/usr Merge in Gentoo

The Linux world is changing! Traditional split between /usr and / directories is given up by several distros, including Fedora and Arch.

There is a comprehensive article that explains the benefits from this merge. I would like to quote Lennart Poettering here:

The separation between minimal boot system in / and full system in
/usr is obsoleted by initrd in a way: the new minimal boot system is
the initrd. Stacking multiple levels of “minimal boot system”, one
after the other is a stupid game. So let’s stick to the one we really
need which is initrd, and forget about the one that we don’t need
anymore, and is broken since ages.

having all static, distro-specific, sharable OS in a single dir
makes snapshots of the OS independetly of its state and configuration
truly atomic. In a btrfs world doing 5 snapshots of /lib, /lib64,
/bin, /sbin and /usr instead of just one is not atomic, and hence
racy, and ugly, and boooh!

An additional argument pro /usr merge in Gentoo is that when upstream has made this merge, it is a bad idea to fight upstream. I have an experience of maintaining a fork of a huge project and I know that such fight can be very expensive: that’s better to convince the upstream to accept your patches than to maintain the fork.

Michał Górny created an overlay for Gentoo introducing wrappers at /bin that catch hardcoded paths in applications. He discovered that a lot of applications call programs by full paths in /bin, so, /bin must be kept in Gentoo.

I tried to make /usr merge on my Gentoo box just as an experiment. And I was really surprised how many tricks are performed just to keep / and /usr separated!

  1. Some files in / are symlinks to their /usr conterparts, e.g., /bin/mail is a symlink to /usr/bin/mail because the upstream installs it to /usr now.
  2. Even more, a lot of files in /usr are symlinks to /, e.g., /usr/bin/touch is a symlink to /bin/touch, and the same for other coreutils. So, Gentoo has to support both the traditional (/bin/touch) and the new (/usr/bin/touch) names.
  3. The trickiest part are special regular .so files in /usr/lib that have counterparts in /lib. This is to resolve a bug in dynamic linking. These files look like this:
    /* GNU ld script
       Because Gentoo have critical dynamic libraries
       in /lib, and the static versions in /usr/lib, we
       need to have a "fake" dynamic lib in /usr/lib,
       otherwise we run into linking problems.
       See bug #4411 on http://bugs.gentoo.org/ for
       more info.  */
    GROUP ( /lib/libxxx )
    

So, it is not enough to just put some symlinks to /: we should handle files that are installed both to / and to /usr.

I have written a Python script that resolves all mentioned conflicts and can be used in a postinstall hook thus making possible to update Gentoo after /usr merge.

When the script is run it as root without parameters, it does merge on the current system. File collisions will be resolved automatically, files moved, and symlinks established. If non-trivial collision are detected, no merge will be performed. The script logs all made changes to stdout:

# /etc/portage/tools/merge-usr
/bin/Mail is a local symlink to mail
/bin/awk is a local symlink to gawk
/usr/bin/basename is a symlink to /bin/basename
...

To make the system updatable, this must be placed at /etc/portage/tools/merge-usr and mentioned in /etc/portage/bashrc:

post_src_install() {
        /etc/portage/tools/merge-usr "$D"
}

This way, it will be called on /var/tmp/pkg/.../image directory after package installation.

As you see, /usr merge can be easily performed in Gentoo.

Leave a comment