This is far from perfect, but it seems to work for my purposes. Input & improvements greatly welcomed. Licensed BSD or whatever, since most of it’s just modification & gluing of Ralf S. Engelschall and Christian Laursen code & smarts.
There’s no error checking/handling/trapping, so if things go wrong, you don’t even really get to keep both pieces. I will say it’s worked fine for me, but I’ve only tested this in my staging environment, never on a running machine with actual, real, live, important data.
The next things I’d like to do are:
- add are checking (via mount and swapinfo) that the first stage has worked properly before blindly adding the first drive to the mirror.
- make the whole thing stop cold if something goes wrong (I think this is quite easy but I forget how)
- remove the extraneous logger in stage II, since it doesn’t actually log anything
- figure out what’s up with boot.config and how to not hard-code it (though I know extremely little about FreeBSD’s boot/loader/etc…)
I appreciate input & improvements, please leave them in the comments below!
#!/bin/sh # Full disk mirroring for FreeBSD 9 by Myke # (assuming automatic & stock install, this has not been tested with # more than just boot,root & swap) # # 20120502 - First version # # Based on the directions and scripts from both # http://people.freebsd.org/~rse/mirror/ # and # http://borderworlds.dk/notes/gmirror.html # # Assumes an already installed FreeBSD 9 system living on ada0: # Creates a mirror on ada1 and then migrates # the system onto that, reboots, then adds ada0 to the mirror # (blindly, doesn't check if the first step was successful) # A suggestion for $mir is # echo `hostname -s` `date +%Y` | sed -e "s/ /-/g" ### EDIT THIS ### EDIT THIS ### EDIT THIS ### ### EDIT THIS ### EDIT THIS ### EDIT THIS ### ### EDIT THIS ### EDIT THIS ### EDIT THIS ### d0=ada0; d1=ada1; mir=Mirror0; ### EDIT THIS ### EDIT THIS ### EDIT THIS ### ### EDIT THIS ### EDIT THIS ### EDIT THIS ### ### EDIT THIS ### EDIT THIS ### EDIT THIS ### echo ; echo Creating half-mirror $mir on $d1 from $d0 echo ; echo kldload geom_mirror echo ; echo Labelling drive... gmirror label ${mir} $d1 gmirror status echo ; echo Copying partitions gpart backup $d0 > /tmp/part.txt gpart restore mirror/${mir} < /tmp/part.txt echo ; echo Installing bootcode... gpart bootcode -b /boot/pmbr mirror/${mir} gpart bootcode -p /boot/gptboot -i 1 mirror/${mir} echo ; echo Formatting filesystem... newfs -U /dev/mirror/${mir}p2 echo ; echo Mounting on /mnt mount /dev/mirror/${mir}p2 /mnt echo ; echo Dumping to mirror... dump -L -0 -f- / | (cd /mnt/ && restore -r -v -f-); echo ; echo Updating fstab, loader.conf and boot.config... cp -v /etc/fstab /mnt/etc/fstab.orig sed -e "s/${d0}/mirror/${mir}/" < /etc/fstab > /mnt/etc/fstab echo 'geom_mirror_load="YES"' >> /mnt/boot/loader.conf # I do not like hardcoding this next bit!!! # I do not like hardcoding this next bit!!! # I do not like hardcoding this next bit!!! # Tell the bootloader on the first drive to use the second (now mirrored) drive: # This very well may not work with SCSI drives or something # but the boot.config(5) manpage doesn't explain what this means # nor are is it up to date/unambiguous for ATA_CAM # (ie: 'ad', not 'ada', but '0p2' rather than '1,a' (or b)) # Also, the boot(8) and loader(8) manpages don't help either. echo "1:ad(0p2)/boot/loader" > /boot.config ### That really needs to be smarter. echo ; echo "Creating restart script..." #echo "#!/bin/sh" > /mnt/root/raid-stage-II.sh #echo "d0="$d0 "; d1="$d1 "; mir="$mir >> /mnt/root/raid-stage-II.sh cat << EOT >> /mnt/root/raid-stage-II.sh #!/bin/sh echo "Adding first drive to mirror" | logger gmirror insert ${mir} $d0 cp /etc/rc.local /etc/rc.local.temp grep -v "/root/raid-stage-II.sh > /var/log/RAID-STAGE-II.log #KAZBLAT" < /etc/rc.local.temp > /etc/rc.local && rm /etc/rc.local.temp EOT chmod +x /mnt/root/raid-stage-II.sh echo "/root/raid-stage-II.sh > /var/log/RAID-STAGE-II.log #KAZBLAT" >> /mnt/etc/rc.local umount /mnt shutdown -r now