perezdecastro.org

Moikka! Here's Adrián. I work for Igalia.

Merging OpenBSD file systems non-destructively

Halloween 2019 had just passed when I installed uptimed to track the uptime of an OpenBSD virtual machine from OpenBSD.amsterdam that I had booked a couple of months before. According to uptimed, the latest release of the system at the time was 6.6, and the longest uptime clocked at 139 days using the 7.3 release. The same install has been updated all the way to 7.8 since then, which means this particular install has gone through twelve updates. Not bad at all!

Data Accumulates

The machine runs a few services using tools included in the base system, plus a few installed by hand or using readily available packages. The heavy lifting for public facing services goes through httpd(8). relayd(8). All quite light.

Nevertheless, it is a well known fact that disks tend to fill up; but contrary to what the reader may expect, in this case not by running a pastebin service (with anonymous uploads disabled) nor an IRC bouncer that has been saving chat history for years (clocking “only” at ~6 GiB). The real culprit has been regular use of an install that has gone through those twelve system updates.

Each release has been getting slightly bigger, and the kernel with them. Which gets re-linked on each boot, a process that started failing on my install a little while back due to /usr/obj being full. Also it did not help having used the ports tree at some point and leaving files behind.

After some poking around doing spring autumn cleaning the issue was gone, but I kept wondering: can we make that partition bigger without losing data? Maybe that would prevent the same from happening again.

Growing Pains

It is not unheard of file systems which may both be resized. Most of them can easily grow, with some like XFS—my go-to file system on Linux—not only allowing to be resized while mounted, but requiring it.

OpenBSD is not precisely known for its ground breaking file system innovations. It still uses the venerable (but quite outdated) Berkeley FFS, a.k.a. Fast File System, where “Fast” stands for “Somewhat Slow”. Not even soft updates are supported anymore. Can it even resize file systems?

Well, yes it can. There is a growfs(8) tool which has been available forever, since OpenBSD 3.4, and I did know nothing about. It does need the file system to have been cleanly unmounted before using growfs, then checked after resizing before mounting it back.

Luckily enough, the folks at OpenBSD.amsterdam allow connecting to the host to manage the virtual machine and connect to its serial console. We can even start the “RAM disk kernel” by hand:

vmctl stop vmNN
vmctl start -c -b /var/vmm/bsd.rd vmNN

At the end of the boot process there will be an option to start a shell, and from there all the tools available to perform disk surgery are readily available.

Making Room

Let’s look how the disk label after the automated install looks like:

# disklabel -h sd0 | tail -n12
#            size       offset  fstype [fsize bsize  cpg]
  a:      1024.0M           64  4.2BSD   2048 16384    1 # /
  b:       752.0M      2097216    swap
  c:     51200.0M            0  unused
  d:      3401.4M      3637312  4.2BSD   2048 16384    1 # /tmp
  e:      5088.0M     10603328  4.2BSD   2048 16384    1 # /var
  f:      2048.0M     21023552  4.2BSD   2048 16384    1 # /usr
  g:      1024.0M     25217856  4.2BSD   2048 16384    1 # /usr/X11R6
  h:      7176.6M     27315008  4.2BSD   2048 16384    1 # /usr/local
  i:      2048.0M     42012640  4.2BSD   2048 16384    1 # /usr/src
  j:      6144.0M     46206944  4.2BSD   2048 16384    1 # /usr/obj
  k:     22493.3M     58789856  4.2BSD   2048 16384    1 # /home

Let’s see what can be reasonably done:

  • Slices sd0f and sd0g contain /usr and /usr/X11R6, and both have the same mount options. We can move the contents of the second into the first, delete sd0g with the disk label editor, then change the size of sd0f and apply growfs onto /dev/sd0f.

  • Slices sd0i and sd0j contain /usr/src and /usr/obj, with the same mount options. We can apply the same idea: delete sd0j and add the space to sd0i. Then to keep things working create a /usr/src/.obj directory and a /usr/obj symlink pointing to it.

This is how the disk label looks like now:

# disklabel -h sd0 | tail -n10     
#                size           offset  fstype [fsize bsize   cpg]
  a:          1024.0M               64  4.2BSD   2048 16384 12958 # /
  b:           752.0M          2097216    swap                    # none
  c:         51200.0M                0  unused                    
  d:          3565.2M          3637312  4.2BSD   2048 16384 12958 # /tmp
  e:          5088.0M         10938880  4.2BSD   2048 16384 12958 # /var
  f:          3072.0M         21359104  4.2BSD   2048 16384 38128 # /usr
  h:          7483.8M         27650560  4.2BSD   2048 16384 12958 # /usr/local
  i:          6842.6M         42977344  4.2BSD   2048 16384 38128 # /usr/src
  k:         23371.7M         56991008  4.2BSD   2048 16384 12958 # /home

While it should be possible to also merge slices sd0d and sd0e, respectively /tmp and /var, I feel more comfortable with /tmp being on its own, so this is it for now.

Was It Worth It?

Time will tell; but I expect less trouble in the future because having /usr/src and /usr/obj in the same place added ~1 GiB of headroom. In practice, the main point of this exercise was to poke around and make an old dog learn a new trick. And that’s always good in my book.