RAID-1 (mirroring) is a popular approach to protect the system from a harddisk failure. It is either done in hardware or software. The usual hardware solution is to buy a RAID disk controller like the popular 3ware ATA RAID controllers and then not having to deal with any software incompatibilities because the system just sees one large physical disk.
The software solution is less expensive and more flexible, but usually makes more trouble during booting. Because an important point in establishing a software RAID-1 for the system disk partitions is whether one can directly boot from the resulting mirror setup without ugly BIOS and/or boot loader tricks. Additionally IMHO it is also important that in case of a major problem with the RAID-1 software driver, one is still able to easily rescue boot from the mirror setup by treating it like a plain disk setup again.
I currently prefer GEOM mirror for establishing such a RAID-1 solution for the system disk partitions because it both provides the possibility to directly boot from the mirror without tricks and is a really clean and modern solution. Additionally, GEOM based solutions can be stacked in an arbitrary way, i.e., the resulting GEOM mirror is just another GEOM "provider" on which one can base any other GEOM "consumers", including GEOM striping (gstripe) or GEOM based disk encryption (gbde).
The FreeBSD 5 geom(4) framework is an excellent abstraction layer for disk I/O. The GEOM mirror class is a software RAID-1 implementation which can be used even for establishing a mirror for the system disk partitions. GEOM mirror is very flexible and actually can be established for any GEOM "providers", including whole disks or just particular slices on a disk. Unfortunately each approach has again pros and cons and hence should be carefully understood before using one of them:
# make sure the second disk is treated as a really fresh one
# (not really necessary, but makes procedure more deterministically ;-)
dd if=/dev/zero of=/dev/ad1 bs=512 count=79
# place a GEOM mirror label onto second disk
# (actually on the last block of the disk)
gmirror label -v -n -b round-robin gm0 /dev/ad1
# activate GEOM mirror kernel layer
# (makes the /dev/mirror/gm0 device available)
gmirror load
# place a PC MBR onto the second disk
# (with a single FreeBSD slice /dev/mirror/gm0s1 covering the whole disk)
fdisk -v -B -I /dev/mirror/gm0
# place a BSD disklabel onto /dev/mirror/gm0s1
# (ATTENTION: in FreeBSD 5-STABLE before 14-Jan-2005 the
# /dev/mirror/gm0s1 device has to be specified as just "mirror/gm0s1" or
# the bsdlabel(8) will use the incorrect GEOM name "gm0s1" instead!)
# (NOTICE: figure out what partitions you want with "bsdlabel /dev/ad0" before)
# (NOTICE: start "a" partition at offset 16, "c" partition at offset 0)
bsdlabel -w -B /dev/mirror/gm0s1 # initialize
bsdlabel -e /dev/mirror/gm0s1 # create custom partitions
# manually copy filesystem data from first to to second disk
# (same procedure for partitions "g", etc)
newfs -U /dev/mirror/gm0s1a
mount /dev/mirror/gm0s1a /mnt
dump -L -0 -f- / | (cd /mnt; restore -r -v -f-)
newfs -U /dev/mirror/gm0s1d
mount /dev/mirror/gm0s1d /mnt/var
dump -L -0 -f- /var | (cd /mnt/var; restore -r -v -f-)
newfs -U /dev/mirror/gm0s1e
mount /dev/mirror/gm0s1e /mnt/usr
dump -L -0 -f- /usr | (cd /mnt/usr; restore -r -v -f-)
# adjust new system configuration for GEOM mirror based setup
cp -p /mnt/etc/fstab /mnt/etc/fstab.orig
sed -e 's/dev\/ad0/dev\/mirror\/gm0/g' </mnt/etc/fstab.orig >/mnt/etc/fstab
echo 'swapoff="YES"' >>/mnt/etc/rc.conf # for 5.3-RELEASE only
echo 'geom_mirror_load="YES"' >>/mnt/boot/loader.conf
# instruct boot stage 2 loader on first disk to boot
# with the boot stage 3 loader from the second disk
# (mainly because BIOS might not allow easy booting from second ATA disk
# or at least requires manual intervention on the console)
echo "1:ad(1,a)/boot/loader" >/boot.config
# reboot system
# (for running system with GEOM mirror on second disk)
shutdown -r now
# make sure the first disk is treated as a really fresh one
# (also not really necessary, but makes procedure more deterministically ;-)
dd if=/dev/zero of=/dev/ad0 bs=512 count=79
# switch GEOM mirror to auto-synchronization and add first disk
# (first disk is now immediately synchronized with the second disk content)
gmirror configure -a gm0
gmirror insert gm0 /dev/ad0
# wait for the GEOM mirror synchronization to complete
sh -c 'while [ ".`gmirror list | grep SYNCHRONIZING`" != . ]; do sleep 1; done'
# reboot into the final two-disk GEOM mirror setup
# (now actually boots with the MBR and boot stages on first disk
# as it was synchronized from second disk)
shutdown -r now
# make sure the second disk is treated as a really fresh one
# (not really necessary, but makes procedure more deterministically ;-)
dd if=/dev/zero of=/dev/ad1 bs=512 count=79
# place a PC MBR onto the second disk
# (with a single FreeBSD slice /dev/mirror/gm0s1 as large as the /dev/ad0s1)
# either automatically if sizes fit...
fdisk -v -B -I /dev/ad1
# ...or manually to make sure the sizes fit:
size=`fdisk ad0 | grep ', size ' | head -1 | sed -e 's;^.*size \([0-9]*\).*$;\1;'`
# ...and reduce the size by one block because ad0 and ad0s1 else would
# share the same last sector which could lead to ad0 be recognized as
# the GEOM provider instead of ad0s1. Alternatively, you can keep ad0
# and ad0s1 of the same size and hard-code the ad0s1 GEOM provider by
# adding the -h option to the "gmirror label" command below.
size=`expr $size - 1`
(echo "p 1 165 63 $size"; echo "a 1") | fdisk -v -B -f- -i /dev/ad1
# place a GEOM mirror label onto first slice of second disk
# (actually on the last block of the disk slice)
gmirror label -v -n -b round-robin gm0s1 /dev/ad1s1
# activate GEOM mirror kernel layer
# (makes the /dev/mirror/gm0s1 device available)
gmirror load
# place a BSD disklabel onto /dev/mirror/gm0s1
# (ATTENTION: in FreeBSD 5-STABLE before 14-Jan-2005 the
# /dev/mirror/gm0s1 device has to be specified as just "mirror/gm0s1" or
# the bsdlabel(8) will use the incorrect GEOM name "gm0s1" instead!)
# (NOTICE: figure out what partitions you want with "bsdlabel /dev/ad0" before)
# (NOTICE: start "a" partition at offset 16, "c" partition at offset 0)
bsdlabel -w -B /dev/mirror/gm0s1 # initialize
bsdlabel -e /dev/mirror/gm0s1 # create custom partitions
# manually copy filesystem data from first to to second disk
# (same procedure for partitions "g", etc)
newfs -U /dev/mirror/gm0s1a
mount /dev/mirror/gm0s1a /mnt
dump -L -0 -f- / | (cd /mnt; restore -r -v -f-)
newfs -U /dev/mirror/gm0s1d
mount /dev/mirror/gm0s1d /mnt/var
dump -L -0 -f- /var | (cd /mnt/var; restore -r -v -f-)
newfs -U /dev/mirror/gm0s1e
mount /dev/mirror/gm0s1e /mnt/usr
dump -L -0 -f- /usr | (cd /mnt/usr; restore -r -v -f-)
# adjust new system configuration for GEOM mirror based setup
cp -p /mnt/etc/fstab /mnt/etc/fstab.orig
sed -e 's/dev\/ad0s1/dev\/mirror\/gm0s1/g' </mnt/etc/fstab.orig >/mnt/etc/fstab
echo 'swapoff="YES"' >>/mnt/etc/rc.conf # for 5.3-RELEASE only
echo 'geom_mirror_load="YES"' >>/mnt/boot/loader.conf
# instruct boot stage 2 loader on first disk to boot
# with the boot stage 3 loader from the second disk
# (mainly because BIOS might not allow easy booting from second ATA disk
# or at least requires manual intervention on the console)
echo "1:ad(1,a)/boot/loader" >/boot.config
# reboot system
# (for running system with GEOM mirror on second disk)
shutdown -r now
# make sure the first disk is treated as a really fresh one
# (also not really necessary, but makes procedure more deterministically ;-)
dd if=/dev/zero of=/dev/ad0 bs=512 count=79
# place a new PC MBR onto the first disk
# (with a single FreeBSD slice /dev/ad0s1 _exactly_ as large as the /dev/ad1s1)
size=`fdisk ad1 | grep ', size ' | head -1 | sed -e 's;^.*size \([0-9]*\).*$;\1;'`
(echo "p 1 165 63 $size"; echo "a 1") | fdisk -v -B -f- -i /dev/ad0
# switch GEOM mirror to auto-synchronization and add first disk
# (first disk is now immediately synchronized with the second disk content)
gmirror configure -a gm0s1
gmirror insert gm0s1 /dev/ad0s1
# wait for the GEOM mirror synchronization to complete
sh -c 'while [ ".`gmirror list | grep SYNCHRONIZING`" != . ]; do sleep 1; done'
# reboot into the final two-disk GEOM mirror setup
# (now actually boots with the MBR and boot stages on first disk
# as it was synchronized from second disk)
shutdown -r now