Stefan's Blog

debian stretch: upgrade 32-bit to 64-bit

Posted on 2017-06-28

There are various reasons why one would prefer 64-bit over 32-bit (or not); basically it is about improved ABI (passing arguments in registers), bigger register (can be faster) versus higher memory usage (because pointers are twice as big). In some corner cases you want 64-bit to be able to use more memory in your programs (32-bit kernels can often handle more than 4G memory, but 32-bit userspace programs can’t).

So that is why I decided to upgrade some 32-bit (called “i386” in debian) machines to 64-bit (“amd64”); after some trial and error I came to the following set of operations to do this in a “reliable” (for me) and fast way.

Instructions

This one should be obvious: make sure you have backups

If you can’t figure out what one of the commands below does, this is not for you. Expert mode only :)

Don’t blame me if it fails :)

Some programs store data in a platform specific way. So far I had this problem only with postgresql, but other databases are very likely to be affected too. Export the data in a platform independent way before and restore it afterwards.

If you run custom installed stuff like rvm, virtualenv or npm they probably won’t work after the migration.

Remember which packages were installed, so you can later check nothing is missing (and you didn’t install packages you didn’t want). As I use aptitude with “markauto” I also store these states:

If you need dkms modules you also need linux-headers-amd64:amd64. Make sure the dkms modules actually got compiled before rebooting if they are essential.

Reboot and make sure you boot the amd64 kernel - either manipulate your bootloader config before rebooting, select it manually, or remove the 32-bit kernel before.

uname -r
# should show 4.9.0-3-amd64

Now is a good time to remove special 32-bit only packages, like libc6-xen or the 32-bit kernel.

You’ll see a repeating pattern below, so I’ll explain it first. apt-get (and aptitude) are not good at resolving conflicts, and don’t understand they don’t have to remove the :i386 packages to install the corresponding :amd64 package. So they would start with removing the :i386 packages, which essentially breaks your system, instead of just installing the :amd64 package.

So we only download the packages with apt, and install them manually with dpkg. For this we need a clean /var/cache/apt/archives/ directory.

If the download command shows errors, it usually mentions missing dependencies: just repeat the command and add those at the end of the command.

Sometimes dpkg fails:

If a Pre-Depends package is missing, it won’t install it at all. At the end dpkg will show you the *.deb filename - just install those again with dpkg --install ....

If a Depends package is missing it won’t configure the package. Just run dpkg --configure -a afterwards to fix those.

The examples below sometimes anticipate the dpkg failures and show a second command to run.

For whatever fucked up reason the dash preinst script uses bash; and bash of course “Pre-Depends” on dash. There is a good chance this breaks later, and if one of them gets removed you’re in big trouble (xxd -r might help you restoring binaries from another system). So we update these first:

The download command might fail due to missing dependencies (see note above); also packages which are not available on amd64 can’t be installed of course. You could try removing them if they are not strictly needed, or put a | grep -v PKGNAME before sed.

Again you might need to fix the download command like before. Instead of redownloading you can just remove the just installed packages too, or just install them again.

This was basically the big step.

Make sure your stuff is working again. The following steps cleanup the 32-bit packages, and for example installing postgresql-9.6:i386 to recover your database becomes more difficult if all dependecies are already gone.

Now remove the :i386 packages - they shouldn’t be needed anymore. I used aptitude for this (limit package view with l, then enter ~ri386).
Something like this might work too:

You’re done. Reboot if you want to make sure everything is still working :)

Additional notes

Debian multiarch dependency handling

Sometimes the dependency handling is fucked up. E.g. postgresql (architecture independent) depends on postgresql-9.6 - it isn’t multiarch enabled as far as I can tell, and this means it wants postgresql-9.6 with the host architecture (which is completely unreasonable as it is just a meta package pulling components).

A similar problem exists the other way too: postgresql-9.6 (architecture dependent) depends on locales (architecture independent). postgresql-9.6 wants locales to be from the same architecture as itself, and apt and dpkg pretend locales is from the host architecture, which doesn’t match if you try to install postgresql-9.6:i386 and the host architecture is already amd64.

I have no solution for the first problem; in the second case just download the package with wget and install it with dpkg --install. It won’t configure it (because a dependency is missing), but it should be usable.

Useful tools

needrestart is a great tool to find processes which should be restarted after upgrades - or 32-bit to 64-bit migrations.

etckeeper is a great tool to keep track of your /etc/ changes.

Feedback

I received some mails with feedback, thanks Leszek Dubiel and Klemens:

It’s probably a good idea to make sure there are no pending updates before you start.

I pass --no-install-recommends to apt; if you enabled APT::Install-Suggests in your apt config you should add --install-suggests as well in those places, or simply put this into /etc/apt/99-no-auto-install.conf during the procedure:

APT::Install-Recommends "false";
APT::Install-Suggests "false";

You could make sure before starting your packages are in good state, and you don’t have any configured-but-not-installed packages. List the unclean packages with:

dpkg -l | grep -v '^ii'

Purge previously installed and still configured packages with (this should remove all configuration and data of those packages - so don’t do this if you still need those):

apt-get purge $(dpkg -l | grep "^rc" | awk '{print $2}')

Or with aptitude:

aptitude purge '~c'

You can try to make sure before that all the packages you want are available on 64-bit:

If you have packages that only work in a 32-bit environment you might be able to run them in a multiarch setup afterwards; just be careful when removing 32-bit packages above (either don’t remove them, or reinstall them later).

If dpkg --install fails with “too many errors” you might want to try:

dpkg --abort-after=999999 --install ...

Due to my repeated usage of apt-get clean a fast network connection is useful, or a local caching proxy (e.g. squid-deb-proxy; better run it on a second machine though).