Restoring a system backup made on another hardware
Backup restore as an interesting alternative to fresh install
I wanted to have the system installed and configured on my new laptop promptly, so I decided not to install the system from fresh, but restore my Debian lenny backup made on another hardware instead. This procedure saved me some time, but it necessitated to reconfigure the restored backups slightly so that the new system was able to boot up correctly. This approach was possible and quick because the original system contained almost no hardware-dependent configuration, most drivers were loaded automatically and their settings were autodetected. The processor architectures weren't surprisingly the same, but they were compatible. Whereas the backup was made on the i386 Debian architecture, the new laptop hardware was a 64-bit Intel processor with the EM64T support and thus designed for a 64-bit operating system as is the amd64 port on Debian. I plan to reinstall the system to the amd64 port in the future, but I wanted to try this interesting approach.
Backing up with tar
The first important question is how the backup was made. I used the GNU version of the traditional Unix/Linux tar archiving tool whose main advantage is that it's so heavily used that it should be part of any Linux distribution or its live version. Even if its name is derived from the phrase tape archiver, it is of course able to perform a backup on another medium such as a usual hard disk drive and the resultant archive is of sufficient quality if proper arguments are given. At least on the standard Linux ext2 based file systems (ext2, ext3, ext4).
GNU/tar is capable of archiving all Linux file
types except unix domain sockets. However, the file of this
type normally exists only if the process that created it is
running unless the process exits abnormally. Hence, this
isn't an issue. All other file types including regular
files, directories, symbolic links, named pipes and
character and block devices are stored. All important
information about these file types is contained in the
archive: filenames, permissions, owner, group, modification
time, symlink target and major and minor device
numbers. Hard links are stored and extracted properly too if
they're put into the same archive. GNU/tar can also
handle sparse files efficiently, but only if
the --sparse option is given. However, the
special lost+found directory in a root directory of
an
ext2 based file system is treated as a usual
directory and should therefore be excluded from the backup
by using the --exclude option.
Furthermore, GNU/tar can create incremental backups
if it is called with the -g switch. It
uses ctime (time of last modification of file
status information) to determine whether the file or its
status has changed. This is a second best choice after using
hashes because if the file contents changes,
the mtime (modification time) and therefore also
the ctime change. However, if the file is only
accessed and atime (access time) is modified,
ctime remains unaltered. If only the file status
changes (permissions, owner, group etc.), ctime is
also updated. The only drawback of this method is that it
is necessary to maintain correct system time. It is not
possible to modify ctime arbitrarily by using some
command, but if the system time changes, later modifications
may occur as older ones and the incremental backup will
unfortunately not contain such files. You should also take
into account that the
-g switch requires an argument denoting the
path to so called snapshot archive. The snapshot archive
contains additional information that is necessary to
determine whether a file should be included into the
incremental archive or not. More precisely, the snapshot
archive contains the list of all files and
their ctimes.
I performed the system backup from a live-CD distribution to ensure the consistency of the data. Otherwise if the system had been running, there could have been a problem with backing up files that were currently undergoing change. This situation might have been avoided by using file systems on top of LVM where a special snapshot volume could have been created that could have held the frozen file system, but my original system wasn't using LVM. I also used an external USB hard disk to store the backups so that a disk failure wouldn't have destroyed them. The backup wasn't made only once for the purpose of moving the system, but it was used long before to protect my data.
Let's now look at the exact commands used to back up the system. I ran my own script from the live-CD and the script called basically the following commands for each file system:
- mount /dev/sdaX /mnt/misc
- df -h | grep '/mnt/misc$' >> df.log
- tar -cvvzf archive.0.tgz -g archive.0.snar -C /mnt/misc --sparse --numeric-owner --exclude=./lost+found
- umount /mnt/misc
I backed up my system incrementally always after a certain
period of time and I therefore created several archives for
each file system. The number 0 before
the tgz or snar suffix in the
example above denotes the current level of the incremental
archive and was increased by one for each backup.
The --numeric-owner tar option is important if
extracting the archive on another system than that which
will be used later. The reason is that GNU/tar
stores both the user names/group names and UIDs/GIDs by
default when creating an archive. But when extracting, it
firstly tries to match the user names and group names and if
the match is found, it assigns the files these user or group
names even if they have different UIDs/GIDs. Only if no
matching names are found, the UIDs and GIDs are used. This
UID/GID renumbering could have been a problem in my case and
I therefore forced
GNU/tar to store and use only UIDs/GIDs
irrespective of names.
The -C argument tells tar to change the
directory to the directory specified before starting the
backup.
Creating partitions and file systems
The backups were already available and I therefore started
with creating partitions and file systems on the new
notebook in order to restore the backups. It's very good to
know the sizes of the file systems on the original machine
so that new file systems of sufficient sizes with enough
free space to operate further may be created. The sizes of
mounted file systems can be obtained by running
the df command, it's advisable to store its
output together with the archives.
Note that all the operations from this point of this subsection
until the subsection
Booting up were performed from a
live-CD. Such a live-CD must contain the essential system
utilities such
as fdisk, mke2fs, lilo,
mount, tar, chroot
etc. I used the
Debian Live Rescue
CD.
I firstly booted from the live-CD and then ran:
- fdisk /dev/sda
Then I switched off the DOS compatibility mode
(command c) and changed display units to
sectors (command u). The default CHS
(cylinder/head/sector) addressing scheme is deprecated for
new hard disks because it doesn't correspond to the real
disk geometry. Constant number of sectors per track isn't
used any more.
I deleted the existing partitions (command d)
and started to create new ones (command n). I
always checked that the start of each partition equals to
such number of sectors that is divisible by 8. The reason is
that my hard disk might use Advanced format according to the
information I received with my laptop which means that the
internal sector size might be larger than 512 bytes. Most
often 4KB. This technology is also called 512e.
Even if my
hard
disk should use 512 bytes per sector according to
the specification I found on the web, I decided to check
the alignment of the partitions to 4K as described in the
7007193 document on the Suse home page referenced by the
documentation I received with my notebook. The partition
types were correctly set to Linux (id 83) and I
therefore didn't have to change them
(command t) except the swap partition type
which I had to change to Linux swap (id 82).
After the partitions were ready to use, I created the file systems by using:
- mkfs.ext3 -b 4096 -L boot /dev/sda1
- mkfs.ext3 -b 4096 -L root /dev/sda2
...
I used the -b argument because in some cases,
the block size was autodetected as only 1024B and I wanted
to optimize the file systems for the potential 4K sector
size.
Finally, I created the swap space by running
- mkswap -L swap /dev/sda3
Restoring the backups
After the file systems were prepared, I was able to start with restoring the backups made on the other machine. This was simply done by calling the following sequence for each file system backup:
- mount /dev/sdaX /mnt/misc
- tar -xvvzf archive.0.tgz -g /dev/null -C /mnt/misc
- tar -xvvzf archive.1.tgz -g /dev/null -C /mnt/misc
... - umount /mnt/misc
There're more tar commands in the example above
because more incremental archives of the same file system
were extracted.
The strange tar argument -g
/dev/null indicates that an incremental archive was
extracted, but the snapshot archive isn't needed for
extracting because each archive contains the list of all
files belonging to it whether they have changed or not. Of
course that the file status information and file contents
are included only for the files that have changed.
Mounting the file systems and running chroot
The next step comprised mounting of all the restored file
systems into the same directory tree into which they were
originally structured. The chroot command could
have been then simply run on the directory where the
directory tree in question was mounted. This wasn't needed
for most of the subsequent operations, but it was necessary
for updating initrd.
I, for instance, called the following command sequence:
- mkdir /mnt/root
- mount /dev/sda2 /mnt/root
- mount /dev/sda1 /mnt/root/boot
... - mount -t proc proc /mnt/root/proc
- mount -t sysfs sysfs /mnt/root/sys
- chroot /mnt/root
Modifications of hardware-dependent information
I decided to restore a backup made on another hardware in spite of the fact that the processor architectures weren't the same but compatible only. The backup was made on the i386 Debian architecture whereas the new processor was designed for a 64-bit operating system such as is Debian on the amd64 port. The original system didn't fortunately contain much of a hardware-dependent configuration. Most of the drivers were loaded automatically as kernel modules or were already built into the stock kernel. Also Xorg was set up in the default way which means that its drivers were autodetected. I had to customize only the following settings.
Firstly the cpufreq kernel modules that were loaded during system startup and were specified in the file /etc/modules. I removed the p4-clockmod cpufreq kernel driver and also the cpufreq-userspace governor, i.e. the lines:
- p4_clockmod
- cpufreq_userspace
The new
processor
cpufreq driver was acpi-cpufreq and I
wanted to use different governor. That's why I edited also
the System V init symbolic links in the /etc/rc?.d
directories for the powernowd daemon which was used
for userspace frequency scaling so that it wasn't run at
system startup. This could have been done by manually
removing the S??powernowd symbolic links from the
/etc/rc?.d directories and replacing them by
K??powernowd symbolic links for the affected
runlevels or by using the update-rc.d
executable with appropriate parameters in
the chroot environment:
- update-rc.d -f powernowd remove
- update-rc.d powernowd stop 20 0 1 2 3 4 5 6 .
The original system used an external USB wireless card as a default network adapter and it was possiblle to plug this card into the USB port of the new laptop easily. Hence, there wasn't a problem with this piece of hardware. But I wasn't sure if the card gets the same name on the new machine because there was another wireless adapter present. I therefore decided to remove the following line from the configuration file /etc/network/interfaces so that this adapter wasn't brought up during system boot.
- auto wlan0
The other devices such as the hard disk, CD-ROM drive, graphics card, sound card and Ethernet adapter didn't use any hardware-specific configuration. I checked the configuration of hdparm in /etc/hdparm.conf and Xorg in /etc/X11/xorg.conf and no updates were necessary.
However, there was a need to reconfigure the file /etc/fstab on my machine because the original computer contained PATA disks whereas the new laptop used the newer SATA disk drives. These drives were accessible by different devices on the 2.6.26 kernel that is the default kernel in Debian lenny (current oldstable release at the time of this writing) and my backed up system was the lenny release. I therefore had to change the hda device strings to sda as in the following example:
- /dev/sda2 / ext3 defaults,errors=remount-ro 0 1
- /dev/sda1 /boot ext3
defaults,errors=remount-ro,nodev,nosuid,noexec 0 1
...
This renaming could have been avoided if the file /etc/fstab used UUIDs instead of device names to identify file systems, but my older system didn't use UUIDs yet.
Because my system was using lilo to boot up, I had to update lilo.conf as well. I had to update two lines only on my system:
- boot=/dev/sda
... - root=/dev/sda2
I was using the uswsusp package for suspend and I therefore modified the device names in the same way in the file /etc/uswsusp.conf, specifically the line:
- resume device = /etc/sda3
And I also had to update the file /etc/initramfs-tools/conf.d/resume so that the system was able to resume after hibernation. The contents of this file after the update was:
- RESUME=/dev/sda3
The last change required updating initrd to take effect. This procedure is described in the next subsection.
Updating initrd
It was necessary to update initrd after the change
of the configuration file
/etc/initramfs-tools/conf.d/resume. This update
could have been done by invoking
the update-initramfs tool, but this executable
had to be used in an environment prepared by
running chroot on a directory into which the
whole directory tree with the restored file systems was
mounted. Otherwise the command in question couldn't have
been able to gather all the necessary information and have
produced a working initrd image. Such a
chroot environment was already prepared in one of
the previous subsections.
One more file had to be edited before generating the initrd image, the configuration file /etc/initramfs-tools/initramfs.conf. I had to change the value of its MODULES variable from dep to most:
- MODULES=most
Without this change, the
command update-initramfs generated a warning
that the system might become unbootable and that
setting MODULES to most should
help. This situation occured only when I
updated initrd in the chroot environment
using the live-CD. The warning disappeared when I
used update-initramfs on the restored system
later.
Finally, the update-initramfs tool was run.
When not updating, but deleting and re-creating
initrd from scratch, lilo wasn't run.
It had to be installed separately anyway. That's why I used
this command sequence.
- update-initramfs -k all -d
- update-initramfs -k 2.6.26-2-686 -c
Installing lilo
To make the system bootable, not only initrd had to be updated, but also a boot loader had to be installed on the newly created system. I was using lilo to boot up my original computer and I therefore set it up again.
Unlike grub, lilo doesn't understand file
systems, it has to store exact offsets of the
initrd and kernel images on the disk so that it is
able to load them using BIOS during the initial phase of the
boot process. That's why lilo has to be updated
everytime when the initrd image file or kernel file
change. It wasn't a problem to run lilo from
the live-CD, but it wasn't possible to run it in
the chroot environment because the udev
daemon wasn't running above these file systems and
the /dev directory didn't contain correct
devices. This meant that it had to be run on the root file
system created by the live-CD where the proper devices
existed. However, the lilo configuration file
/etc/lilo.conf (or /mnt/root/etc/lilo.conf
outside the chroot environment if the restored root
file system was mounted to /mnt/root) couldn't have
been used in the same form which it had on the restored file
system. The reason was that the paths used in the
configuration file didn't point to existing files on the
live-CD directory tree. Because the path strings were not
important, the information used by lilo are the
disk offsets, it was possible to create a temporary
configuration file using the path strings pointing to
correct files. I therefore created such temporary
file /mnt/root/tmp/lilo.conf:
- cp /mnt/root/etc/lilo.conf /mnt/root/tmp
And I changed the following lines in this file:
- map=/mnt/root/boot/map
... - image=/mnt/root/vmlinuz
... - initrd=/mnt/root/initrd
The last step was running lilo. The temporary
configuration file mentioned above should have been passed
to it as an argument to the -C option.
- lilo -C /mnt/root/tmp/lilo.conf
A warning was displayed that initrd was too big to fit between the kernel and the 15M-16M memory hole and that it was assumed that the BIOS supports memory moves above 16M. Naturally, my new BIOS supported this feature.
Booting up
After the initrd image and the boot loader were installed properly, it was possible to restart the system from the disk. So I shutted down the live-CD operating system and removed the CD from the tray. Lilo started, loaded the kernel and the initrd image from the disk, decompressed them, mounted initrd as a temporary root file system and ran the kernel. However, it wasn't able to mount the real root file system and stopped. The problem was that AHCI was set as the SATA mode in the BIOS. This behaviour was unexpected because the ahci kernel module was present in the generated initrd, I checked this by booting from the live-CD again and invoking the following commands:
- mkdir /mnt/boot
- mount /dev/sda1 /mnt/boot
- mkdir /tmp/initrd
- cd /tmp/initrd
- cat /mnt/boot/initrd.img-2.6.26-2-686 | gunzip - | cpio -i
- find . -name 'ahci.ko'
But after I changed the SATA mode settings in the BIOS from AHCI (SATA) to IDE (PATA), the system booted up correctly. So I didn't use the live-CD any more and continued working on the restored system.
I wanted to use the newer AHCI mode, of course. I tried what can be done and I found out that if I set the MODULES settings back to dep in the file /etc/initramfs-tools/initramfs.conf
- MODULES=dep
- ahci
I can change the SATA mode in BIOS back to AHCI and the
system is able to boot. Of course, I had to regenerate
initrd after the changes to the configuration files
by running update-initramfs before I restarted
the system and changed the BIOS settings:
- update-initramfs -k all -u
I didn't have to invoke the lilo command
because it was run automatically
by update-initramfs when using
the -u argument, i.e. the update mode.
The system booted up correctly this time and the AHCI mode was used for accessing hard disk and also DVD-RW drive. It was possible to remove the ahci module from the file /etc/initramfs-tools/modules again, because it will be autodetected next time if it is used. I therefore created the following comment in the file in question.
- # ahci
Kernel upgrade and additional installations
The Debian lenny system backup was already successfully restored on my HP ProBook 4520s laptop as decribed in the preceding subsections. However, not all of its devices were working on this system. The reason was that lenny changed its status from the stable to the oldstable Debian release shortly before the time of this writing and it therefore contained only older drivers. For example, both sound cards and the wireless card weren't detected at all on lenny even if they worked on the lenny successor squeeze. The hardware compatibility of this notebook with Debian squeeze is decribed in the Hardware specification and compatibility with Debian squeeze subsection.
It wasn't necessary to upgrade the whole system from lenny to squeeze to make the devices working, but at least the kernel and its dependencies and also some non-free firmware packages had to be upgraded or installed. I therefore changed the references to lenny to the references to squeeze in the file /etc/apt/sources.list and added the contrib and non-free sections to this file because I don't use them by default:
- deb ftp://ftp.cz.debian.org/debian/ squeeze main contrib non-free
- deb-src ftp://ftp.cz.debian.org/debian/ squeeze main contrib non-free
- deb http://security.debian.org/ squeeze/updates main contrib non-free
- deb-src http://security.debian.org/ squeeze/updates main contrib non-free
I had to update the package index files after that by running:
- apt-get update
First of all, I upgraded the kernel. I chose the kernel package with the bigmem suffix in order to use the whole memory as explained in the Memory subsection of the Hardware specification and compatibility with Debian squeeze subsection. Specifically, I invoked the following command:
- apt-get install linux-image-2.6.32-5-686-bigmem
I updated lilo to use the new kernel and rebooted so that the new kernel was loaded. I also installed the non-free firmware packages required by both network cards, i.e. firmware-realtek and firmware-brcm80211:
- apt-get install firmware-realtek firmware-brcm80211
Because I wanted to use cpufreq to enable the processor frequency and voltage scaling, I installed the package cpufrequtils:
- apt-get install cpufrequtils
This package loads the cpufreq kernel modules automatically during system startup. I changed the default governor as described in the Processor subsection of the Hardware specification and compatibility with Debian squeeze subsection.
After these modifications, all the devices were detected and their drivers loaded as decribed in the Hardware specification and compatibility with Debian squeeze subsection mentioned earlier. However, I ran one more command to reconfigure the uswsusp package and modify its configuration file /etc/uswsusp.conf once again. This was already done in one of the preceding subsections, but I wanted to change not only the resume device, but also adjust the preferred snapshot size to a larger value because my physical memory and swap space were much larger on the new system. Hence, I ran the following command:
- dpkg-reconfigure uswsusp
I could have changed more suspend and resume settings by answering a few questions, but it wasn't necessary.