I recently had to replace the system disk in a FreeBSD machine (SMART self-tests failed, better be safe than sorry), this is my recipe for an “online” replacement. I did this in multi-user mode with all services shut down.

ad4 is the disk that is going to be replaced (ie. the old disk) and ad6 is new the new one, the new disk was of identical size so I simply kept the old partition layout.

Be extremely careful when entering your disk names as one command to the wrong disk could make you loose data.

The layout of the old disk looked like this

Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/ad4s1a    496M    351M    105M    77%    /
/dev/ad4s1e    496M    213M    243M    47%    /tmp
/dev/ad4s1f    124G     29G     85G    26%    /usr
/dev/ad4s1d    3.9G    1.5G    2.0G    43%    /var

Make sure the disk is treated as a new one (overwrite old slice information if any, should not be needed if it’s a brand new drive)

> dd if=/dev/zero of=/dev/ad6 bs=512 count=100
100+0 records in
100+0 records out
51200 bytes transferred in 0.038179 secs (1341054 bytes/sec)

Create a slice that covers the whole disk and install MBR on the new disk

> fdisk -v -B -I -a /dev/ad6

I was replacing the disk with one of identical size so I just used the same partitions as before, If your disk is larger you’ll need to adjust your partition sizes.

Read and save the label from the old disk

> bsdlabel /dev/ad4s1 > /tmp/label

Restore the label on the new disk and install boot code

> bsdlabel -R /dev/ad6s1 /tmp/label
> bsdlabel -B /dev/ad6s1

I had a slight problem as the new disk which was “identical” in size actually was 2 MB larger so I had to adjust the c: partition in /tmp/label to cover the whole disk before restoring it onto the new one. fdisk /dev/ad6 reports the actual size.

Make sure the new partitions look OK and that bsdlabel doesn’t emit warning about overlapping partitions etc.

> bsdlabel /dev/ad6s1
# /dev/ad6s1:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
a:  1048576        0    4.2BSD     2048 16384     8
b:  4132160  1048576      swap
c: 293046705        0    unused        0     0         # "raw" part, don't edit
d:  8388608  5180736    4.2BSD     2048 16384 28528
e:  1048576 13569344    4.2BSD     2048 16384     8
f: 278423682 14617920    4.2BSD     2048 16384 14080

As far as partitioning and MBR/boot code the disk should be ready. Now what’s left is formatting the partition and copying the data.

Create a file system on the / partition, no soft updates.

> newfs /dev/ad6s1a

Create file system for /tmp, /var and /usr with soft updates

> newfs -U /dev/ad6s1d
> newfs -U /dev/ad6s1e
> newfs -U /dev/ad6s1f

Mount the NEW root onto /mnt (or any other suitable place)

> mount /dev/ad1s1a /mnt/

Do a live level 0 dump of the original / onto the new /

> dump -L -0 -f- / | (cd /mnt/ && restore -r -v -f-)

Mount the remaining partitions

> mount /dev/ad6s1e /mnt/tmp
> mount /dev/ad6s1d /mnt/var
> mount /dev/ad6s1f /mnt/usr

And do the dump/restore dance for these partitions as well.

> dump -L -0 -f- /tmp | (cd /mnt/tmp && restore -r -v -f-)
> dump -L -0 -f- /var | (cd /mnt/var && restore -r -v -f-)
> dump -L -0 -f- /usr | (cd /mnt/usr && restore -r -v -f-)

Now either adjust /mnt/etc/fstab so that the partitions refer to the new disk name (in my case that would have be to replace ad4 with ad6) or simply reconnect the new disk to the old disks’ (s)ata port (this is what I did). Disconnect the old disk and boot the system, it should now be running on the new disk with all data intact.

Depending on how much data there is to copy, down time can be kept to an hour or so.

If it doesn’t boot? Re-connect the old drive and redo the thing. Installing the boot code is very importat, otherwise it simply won’t boot.

Comments are closed.