gsthnz's blog

Read-only root with overlayfs Jul 16, 2020

Read-only filesystems can be really useful for the deployment of devices that are prone to sudden shutdowns or other failure scenarios. It also makes it really easy to upgrade dependending on the method used.

I recently had to create a small buildroot system with a read-only layer and a write enabled layer using overlayfs. I’m using this setup for x86 boards and armv7 boards. Also, one requirement I set for myself was not to depend on any bootloader specific feature, since I have to support multiple architectures.

In this article, I’ll be describing a bit of this setup.

Overlayfs

From the linux summary of overlayfs:

An overlay filesystem combines two filesystems - an ‘upper’ filesystem and a ’lower’ filesystem. When a name exists in both filesystems, the object in the ‘upper’ filesystem is visible while the object in the ’lower’ filesystem is either hidden or, in the case of directories, merged with the ‘upper’ object.

You can find more documentation on the kernel documentation page. 1

This basically means that we can have a readonly (lower) filesystem merged with a writable (upper) filesystem. And every change made on the filesystem will be persisted on the upper filesystem. With this description you can see how this makes system upgrades and factory resets a dream, and it really does. 2

Boot and Overlayfs mounting process

For this article, I’ll be making the following assumptions:

For the boot process, we just need a kernel and a initrd on our boot partition and load that on the bootloader.

All we have to do now is override our /init so that we can mount the new overlayed filesystem before our actual init.

So our new /init will look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/sh

# Mount /proc, /dev/ and /sys as needed.

# You can add a shell here for debugging,
# just calling "exec /bin/sh" should work

# Remount root as readonly to a new location
mount / /rom
mount -o remount,ro /rom

# Mount our writable partition to the overlay location
mount /dev/sda2 /overlay

# Create a upperdir and workdir inside the overlay directory.
mkdir /overlay/{upper,work}
mount -t overlay overlay -o \
    lowerdir=/rom,upperdir=/overlay/upper,workdir=/overlay/work \
    rootfs

# At this point, everything should be OK, we just need to move our mounts
# before the chroot
mount --move /rom /rootfs/rom
mount --move /overlay /rootfs/overlay

# Don't forget to remount /proc, /dev and /sys if needed.

# And lastly, run chroot with our new rootfs and action init.
exec chroot /new_rootfs /sbin/init

After this, you should be on your new merged filesystem.

Upgrades and Resets

From the boot process and mounting, you can see how upgrading and reset will be very simple tasks.

To upgrade, just replacing the kernel and rootfs on the boot partition should do the trick. To reset, just cleaning the /overlay/upper should bring everything to default!

And that’s it. It took me a little time to figure all this stuff out. But it’s a really simple process and I haven’t found any weird behavior with this little setup yet.


  1. Overlayfs docs on the linux kernel ↩︎

  2. A huge inspiration for this was the OpenWrt project, they use a setup similar to the one I describe on their distro, and it works very well! ↩︎


Have questions or comments? Use my public inbox by sending a plain text-email to ~gsthnz/public-inbox@lists.sr.ht