Tuesday, November 11, 2014

Beaglebone Debian Read Only Filesystem

Overview

To save the eMMC and to allow for faster bootup/shutdowns, I wanted to mount the root partition as read-only. I spent many days researching and trying to find out what areas of the filesystem needed to have write permissions. It seemed like I was going in circles. Unionfs, aufs, mount -bind, overlayfs, tmpfs.....so many options and so many modules that didn't exist in the default BBB Debian kernel. I finally got so fed up that I decided to just start hacking away at the fstab.

Details

It turns out that the basic read-only filesystem is fairly easy to create, as everything that needs to be configured is contained in /etc/fstab. We need to change the root mount to read-only and add a couple of temporary file systems to handle logs and such. Let's start with an ordinary fstab created by the eMMC flasher script:
# /etc/fstab: static file system information.
#
# Auto generated by: beaglebone-black-eMMC-flasher.sh
#
UUID=716e1ca7-bc61-4958-8c0d-665e48102cfd / ext4 ro,noatime,errors=remount-ro 0 1
UUID=0DFE-E81B /boot/uboot auto defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0

We could then use the following sed command to add the "ro" tag to the root mount line and save it to a temporary fstab file:
> sudo sed s:ext4\ \ noatime:ext4\ \ ro,noatime: /etc/fstab_ro

Next we need to append some tmpfs declarations to our temporary fstab file:
> sudo nano /etc/fstab_ro

and put the following lines at the end:
tmpfs /tmp tmpfs nodev,nosuid,size=32M 0 0
tmpfs /srv tmpfs nodev,size=512K 0 0
tmpfs /var/log tmpfs defaults,noatime,size=1M 0 0
tmpfs /var/tmp tmpfs defaults,noatime,size=512K 0 0
tmpfs /var/run tmpfs defaults,noatime,size=512K 0 0

Replace the real /etc/fstab with your temporary file:
> sudo cp /etc/fstab /etc/fstab.orig
> sudo mv /etc/fstab_ro /etc/fstab

Reboot and you're done!

You may have to experiment with different size limits, depending on your logging needs, but the sizes above should get you started.

Alternate Method

Systemd does the actually mounting, by parsing the fstab. The order in which the mounts are created is not guaranteed. If you need to create mounts in a particular order you need to create a systemd .mount unit for each mount:
> sudo nano /etc/systemd/system/my.mount


with content similar to the following:
[Unit]
Description=Runtime Directory
Before=local-fs.target

[Mount]
What=/mine
Where=/tmp/myfs
Type=bind
Options=bind

Remount RW

If you need to modify the filesystem, you can remount it rw, for a while, with the following command:
> sudo mount -o remount,rw /

To return to read-only mode, either reboot or run this command:
> sudo mount -o remount,ro /

References

https://groups.google.com/forum/#!topic/beagleboard/9J2r8xn3-Os
http://adis.ca/tag/beaglebone/
http://unix.stackexchange.com/questions/27449/mount-a-filesystem-read-only-and-redirect-writes-to-ram
https://help.ubuntu.com/community/aufsRootFileSystemOnUsbFlash
http://unix.stackexchange.com/questions/81959/how-to-mount-aufs-file-system-on-boot-in-archlinux
http://www.thegeekstuff.com/2013/05/linux-aufs/
https://wiki.debian.org/ReadonlyRoot
https://code.google.com/p/rootaufs/wiki/HowToUse

2 comments:

  1. Hello. Thank for the topic, it's quite useful for me. The only problem are the different services that don't want to run. One of them is dnsmasq which is going to write to the file /var/lib/misc/dnsmasq.leases, well, the usb-over-ethernet connection doesn't work after the changes. Is there a way to change location of the file?

    ReplyDelete
  2. Thanks for sharing you knowledge, I tried the option 1. But after the changes system boots to emergency mode also mout /tmp fails.

    ReplyDelete