yet somehow managed to overlook writing up how to do so in Linux.
This write up is to rectify just that, how to clone a disk, in this case,
the root disk, in Linux. The following are our setup details:
HOST: tux PROMPT: tux [0] OS: CentOS 5.4 Linux MASTER DISK: sda current root disk grub disk hd0 bios disk 1 ALTERNATE DISK: sdb soon to be clone disk grub disk hd1 bios disk 2Optimally, your clone disk will be the same size and geometry as your
master disk. In the examples that follow, this is not the case, wherein
the clone disk is 1 cylinder (1 MB) larger than the master. This isn't
necessarily an issue. The partition layout created mirrors that of the
master disk. The important thing to note is that to follow the details
below explicitly, your clone disk needs to have at least enough capacity
to account for the partitions on the master disk. An understanding of
disk layout, geometry, and partitioning schemes would be useful.
With the disclaimer out of the way, onto the details. Of note,
'alternate' and 'clone' are used interchangeably in reference to 'sdb',
whereas 'master' references 'sda'. To start, use 'fdisk' to verify the
current partition tables of both 'sda' and 'sdb'. This is basically to
verify our size constraints:
tux [0] /sbin/fdisk -l /dev/sda Disk /dev/sda: 11.0 GB, 11004805120 bytes 255 heads, 63 sectors/track, 1337 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/sda1 * 1 945 7590681 83 Linux /dev/sda2 946 1206 2096482+ 83 Linux /dev/sda3 1207 1337 1052257+ 82 Linux swap / Solaris tux [0] /sbin/fdisk -l /dev/sdb Disk /dev/sdb: 11.0 GB, 11005853696 bytes 255 heads, 63 sectors/track, 1338 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id SystemSince 'sdb' will support the size requirements from 'sda', use 'sfdisk'
to dump the partition table of 'sda' and apply it to 'sdb'. Verify the
new partition table on 'sdb' with another 'fdisk' command:
tux [0] /sbin/sfdisk -d /dev/sda | /sbin/sfdisk /dev/sdb Checking that no-one is using this disk right now ... OK Disk /dev/sdb: 1338 cylinders, 255 heads, 63 sectors/track Old situation: Units = cylinders of 8225280 bytes, blocks of 1024 bytes, counting from 0 Device Boot Start End #cyls #blocks Id System /dev/sdb1 0 - 0 0 0 Empty /dev/sdb2 0 - 0 0 0 Empty /dev/sdb3 0 - 0 0 0 Empty /dev/sdb4 0 - 0 0 0 Empty New situation: Units = sectors of 512 bytes, counting from 0 Device Boot Start End #sectors Id System /dev/sdb1 * 63 15181424 15181362 83 Linux /dev/sdb2 15181425 19374389 4192965 83 Linux /dev/sdb3 19374390 21478904 2104515 82 Linux swap / Solaris /dev/sdb4 0 - 0 0 Empty Successfully wrote the new partition table Re-reading the partition table ... If you created or changed a DOS partition, /dev/foo7, say, then use dd(1) to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1 (See fdisk(8).) tux [0] /sbin/fdisk -l /dev/sdb Disk /dev/sdb: 11.0 GB, 11005853696 bytes 255 heads, 63 sectors/track, 1338 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/sdb1 * 1 945 7590681 83 Linux /dev/sdb2 946 1206 2096482+ 83 Linux /dev/sdb3 1207 1337 1052257+ 82 Linux swap / SolarisWith the new partition table in place on the alternate disk, we can set
up empty filesystems on 'sdb1' and 'sdb2' using 'mkfs':
tux [0] for i in 1 2 ; do echo "*** mkfs -V -t ext3 /dev/sdb${i} ***" ; > /sbin/mkfs -V -t ext3 /dev/sdb${i} ; done *** mkfs -V -t ext3 /dev/sdb1 *** mkfs (util-linux 2.13-pre7) mkfs.ext3 /dev/sdb1 mke2fs 1.39 (29-May-2006) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 950272 inodes, 1897670 blocks 94883 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=1946157056 58 block groups 32768 blocks per group, 32768 fragments per group 16384 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632 Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 25 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. *** mkfs -V -t ext3 /dev/sdb2 *** mkfs (util-linux 2.13-pre7) mkfs.ext3 /dev/sdb2 mke2fs 1.39 (29-May-2006) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 262144 inodes, 524120 blocks 26206 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=536870912 16 block groups 32768 blocks per group, 32768 fragments per group 16384 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912 Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 22 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override.Though unnecessary, rather than using device entries to manage the
clone disk, we can use volume labels instead. Turning to 'tune2fs',
we get the volume labels for 'sda1' and 'sda2' to mirror their format
for our clone disk in a separate set of 'tune2fs' commands:
tux [0] ( /sbin/tune2fs -l /dev/sda1 ; /sbin/tune2fs -l /dev/sda2 ) | /bin/grep name Filesystem volume name: /1 Filesystem volume name: /var1 tux [0] ( /sbin/tune2fs -l /dev/sdb1 ; /sbin/tune2fs -l /dev/sdb2 ) | /bin/grep name Filesystem volume name: <none> Filesystem volume name: <none> tux [0] /sbin/tune2fs -L /2 /dev/sdb1 tune2fs 1.39 (29-May-2006) tux [0] /sbin/tune2fs -L /var2 /dev/sdb2 tune2fs 1.39 (29-May-2006) tux [0] ( /sbin/tune2fs -l /dev/sdb1 ; /sbin/tune2fs -l /dev/sdb2 ) | /bin/grep name Filesystem volume name: /2 Filesystem volume name: /var2Below, we check what the system says about the swap volume on 'sda3'
via 'swapon' and /etc/fstab:
tux [0] /sbin/swapon -s Filename Type Size Used Priority /dev/sda3 partition 1052248 0 -1 tux [0] /bin/grep swap /etc/fstab LABEL=SWAP-sda3 swap swap defaults 0 0Since swap isn't a filesystem, we can't use 'tune2fs' to set a volume
label to 'sdb3'. As we still need to create the swap area on 'sdb3',
we can tell 'mkswap' to apply a label while setting up the swap area:
tux [0] /sbin/mkswap -L SWAP-sdb3 /dev/sdb3 Setting up swapspace version 1, size = 1077506 kB LABEL=SWAP-sdb3, no uuidWe now proceed to actually mirroring the data content of our filesystems
on our master disk (sda). Below, we test for a mount point (/mnt) and if
necessary create it, mount 'sdb1' to '/mnt', and use 'dump' and 'restore'
to copy the data from 'sda1' (/) to 'sdb1' (/mnt). Once the dump /
restore has completed, we remove 'restoresymtable' as it won't be needed:
tux [0] [ ! -d /mnt ] && /bin/mkdir /mnt tux [1] /bin/mount /dev/sdb1 /mnt tux [0] cd /mnt ; /sbin/dump 0uf - / | /sbin/restore rf - DUMP: Date of this level 0 dump: Sun Jan 9 23:08:52 2011 DUMP: Dumping /dev/sda1 (/) to standard output DUMP: Label: /1 DUMP: Writing 10 Kilobyte records DUMP: mapping (Pass I) [regular files] DUMP: mapping (Pass II) [directories] DUMP: estimated 2040405 blocks. DUMP: Volume 1 started with block 1 at: Sun Jan 9 23:08:54 2011 DUMP: dumping (Pass III) [directories] DUMP: dumping (Pass IV) [regular files] /sbin/restore: ./lost+found: File exists ./tmp/rstdir1294632532: (inode 1276706) not found on tape ./tmp/rstmode1294632532: (inode 1276711) not found on tape DUMP: 61.29% done at 4168 kB/s, finished in 0:03 DUMP: Volume 1 completed at: Sun Jan 9 23:18:43 2011 DUMP: Volume 1 2372690 blocks (2317.08MB) DUMP: Volume 1 took 0:09:49 DUMP: Volume 1 transfer rate: 4028 kB/s DUMP: 2372690 blocks (2317.08MB) DUMP: finished in 589 seconds, throughput 4028 kBytes/sec DUMP: Date of this level 0 dump: Sun Jan 9 23:08:52 2011 DUMP: Date this dump completed: Sun Jan 9 23:18:43 2011 DUMP: Average transfer rate: 4028 kB/s DUMP: DUMP IS DONE tux [0] /bin/rm restoresymtableWith 'sdb1' complete, we move on to 'sdb2', using the same procedure as
above to copy from 'sda2' (/var) to 'sdb2' (/mnt/var):
tux [0] [ ! -d /mnt/var ] && /bin/mkdir /mnt/var tux [1] /bin/mount /dev/sdb2 /mnt/var tux [0] cd /mnt/var ; /sbin/dump 0uf - /var | /sbin/restore rf - DUMP: Date of this level 0 dump: Sun Jan 9 23:33:17 2011 DUMP: Dumping /dev/sda2 (/var) to standard output DUMP: Label: /var1 DUMP: Writing 10 Kilobyte records DUMP: mapping (Pass I) [regular files] DUMP: mapping (Pass II) [directories] DUMP: estimated 37035 blocks. DUMP: Volume 1 started with block 1 at: Sun Jan 9 23:33:18 2011 DUMP: dumping (Pass III) [directories] DUMP: dumping (Pass IV) [regular files] /sbin/restore: ./lost+found: File exists DUMP: Volume 1 completed at: Sun Jan 9 23:33:30 2011 DUMP: Volume 1 40990 blocks (40.03MB) DUMP: Volume 1 took 0:00:12 DUMP: Volume 1 transfer rate: 3415 kB/s DUMP: 40990 blocks (40.03MB) DUMP: finished in 12 seconds, throughput 3415 kBytes/sec DUMP: Date of this level 0 dump: Sun Jan 9 23:33:17 2011 DUMP: Date this dump completed: Sun Jan 9 23:33:30 2011 DUMP: Average transfer rate: 3415 kB/s DUMP: DUMP IS DONE tux [0] /bin/rm restoresymtable tux [0] cd /Now that our filesystems have been cloned, we need to update 'fstab',
'grub.conf', and potentially 'device.map' on our clone disk. For 'fstab',
we update from this (the values of our master disk (sda)):
tux [0] /bin/cat /mnt/etc/fstab LABEL=/1 / ext3 defaults 1 1 LABEL=/var1 /var ext3 defaults 1 2 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 LABEL=SWAP-sda3 swap swap defaults 0 0to this (using the values of our clone disk (sdb)):
tux [0] /bin/cat /mnt/etc/fstab LABEL=/2 / ext3 defaults 1 1 LABEL=/var2 /var ext3 defaults 1 2 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 LABEL=SWAP-sdb3 swap swap defaults 0 0You will likely need to update 'device.map' on your clone disk, as
otherwise, 'grub-install' may kick back the following error:
tux [0] /sbin/grub-install --root-directory=/mnt /dev/sdb /dev/sdb does not have any corresponding BIOS drive.So using your favorite editor (vi?), update 'device.map' from this:
tux [0] /bin/cat /mnt/boot/grub/device.map # this device map was generated by anaconda (hd0) /dev/sdato this to account for our alternate disk as well:
tux [0] /bin/cat /mnt/boot/grub/device.map # this device map was generated by anaconda (hd0) /dev/sda (hd1) /dev/sdbA subsequent run of 'grub-install' now completes without issue, writing
the stage1, stage1_5, and stage2 files to '/mnt/boot/grub' and installing
'GRUB' to the master boot record (MBR) on 'sdb':
tux [0] /sbin/grub-install --root-directory=/mnt /dev/sdb Installation finished. No error reported. This is the contents of the device map /mnt/boot/grub/device.map. Check if this is correct or not. If any of the lines is incorrect, fix it and re-run the script `grub-install'. # this device map was generated by anaconda (hd0) /dev/sda (hd1) /dev/sdbThe last file to update is 'grub.conf' on 'sdb' to tell 'GRUB' about our
alternate disk. You should also update 'grub.conf' on 'sda' as well.
On our clone disk (sdb) below, we update from:
tux [0] grep -v ^# /mnt/boot/grub/grub.conf default=0 timeout=5 splashimage=(hd0,0)/boot/grub/splash.xpm.gz title CentOS (2.6.18-164.el5) root (hd0,0) kernel /boot/vmlinuz-2.6.18-164.el5 ro root=LABEL=/1 initrd /boot/initrd-2.6.18-164.el5.imgto the following, setting the default boot entry to our clone disk and
adding an entry to boot into the Linux install now cloned to 'sdb':
tux [0] grep -v ^# /mnt/boot/grub/grub.conf default=1 timeout=5 splashimage=(hd1,0)/boot/grub/splash.xpm.gz title CentOS (2.6.18-164.el5) root (hd0,0) kernel /boot/vmlinuz-2.6.18-164.el5 ro root=LABEL=/1 initrd /boot/initrd-2.6.18-164.el5.img title CentOS Mirror (2.6.18-164.el5) root (hd1,0) kernel /boot/vmlinuz-2.6.18-164.el5 ro root=LABEL=/2 initrd /boot/initrd-2.6.18-164.el5.imgOf note, updating 'grub.conf' on the master disk (sda) would only
include adding an entry for our clone disk, leaving the default entry to
the master disk. With our work complete, the only things left are to
unmount our clone disk filesystems, check for any FS errors via 'fsck',
and reboot:
tux [0] /bin/umount /mnt/var tux [0] /bin/umount /mnt tux [0] /sbin/fsck -n /dev/sdb2 fsck 1.39 (29-May-2006) e2fsck 1.39 (29-May-2006) /var2: clean, 991/262144 files, 26347/524120 blocks tux [0] /sbin/fsck -n /dev/sdb1 fsck 1.39 (29-May-2006) e2fsck 1.39 (29-May-2006) /2: clean, 71367/950272 files, 562330/1897670 blocks tux [0] /sbin/rebootAfter the host has reset, tell the BIOS to boot from disk 2 (sdb).
Once Linux has finished booting, log in and verify that we are indeed
booted from our clone disk:
tux [0] /bin/cat /proc/cmdline ro root=LABEL=/2 tux [0] /bin/df -h Filesystem Size Used Avail Use% Mounted on /dev/sdb1 7.2G 2.1G 4.8G 31% / /dev/sdb2 2.0G 71M 1.8G 4% /var tmpfs 506M 0 506M 0% /dev/shm tux [0] /sbin/swapon -s Filename Type Size Used Priority /dev/sdb3 partition 1052248 0 -1
see also:
Creating an MD Root Mirror in Linux
Disk Cloning in Solaris
Disk Cloning in FreeBSD
Breaking and Syncing an MD Root Mirror