User Tools

Site Tools


linux:raspberry_pi_read-only_root

Read-only root for Raspberry Pi

https://github.com/wokis/raspberrypi

Debian is a good choice to run on Raspberry Pi. To create a read-only rootfs for our Debian system we need to:

  • Compile a kernel with overlayfs support
  • Create an initramfs that will setup our read-only root
  • Create some helper scripts to remount root as read-write and to sync any changes back to the disk

With the help of overlayfs we can mount the disk read-only and run the rootfs from RAM. We can then pull the plug on the device without worrying of filesystem corruption. We can also mount the disk read-write to sync any changes back to the drive.

For this to work we are going to use a couple of directorys on the disk.

  • /mnt/root-ro, mountpoint of our disk
  • /mnt/root-rw, overlayfs mountpoint running in RAM (tmpfs)
  • /mnt/persistent, here we will store any changes to files and directories

Overlayfs will merge /mnt/root-ro with /mnt/root-rw into root (/).

Kernel compilation with overlayfs support

Complete instructions for kernel compilation can be found at http://elinux.org/RPi_Kernel_Compilation.

# Clone the raspberry kernel
# -b switch is used to select branch
cd /home/me/raspberry/kernel
git clone -b rpi-4.9.y --depth 1 https://github.com/raspberrypi/linux.git ./
 
# Tell where we can find the kernel
KERNEL_SRC=/home/me/raspberry/kernel/
 
# Get the raspberry toolchain
cd /home/me/raspberry/tools
git clone --depth 1 https://github.com/raspberrypi/tools ./
 
# Tell where we can find the raspberry toolchain
CCPREFIX=/home/me/raspberry/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
 
# Let us build the kernel
# latest kernel already has support for overlayfs built in, the default is to build it as a module
ARCH=arm CROSS_COMPILE=${CCPREFIX} make bcm2709_defconfig
 
# Build our kernel
ARCH=arm CROSS_COMPILE=${CCPREFIX} make
 
# Tell where we should put the kernel modules
MODULES_TEMP=/home/me/raspberry/kernel-modules
 
# Copy our kernel modules to our module directory
ARCH=arm CROSS_COMPILE=${CCPREFIX} INSTALL_MOD_PATH=${MODULES_TEMP} make modules_install

Prepare initramfs

# Clone the raspberry busybox initramfs
cd /home/me/raspberry/initramfs
git clone --depth 1 https://github.com/raspberrypi/target_fs.git ./

New init file.

cat > init << EOF
#!/bin/busybox sh
 
# Mount the /proc and /sys filesystems.
mount -t proc none /proc
mount -t sysfs none /sys
 
# Populate /dev
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
 
# Do overlayfs magic
mount -o ro /dev/mmcblk0p2 /mnt/root-ro
mount -t tmpfs tmpfs /mnt/root-rw
cp -a /mnt/root-ro/mnt/persistent/. /mnt/root-rw
mount -t overlayfs overlayfs -o lowerdir=/mnt/root-ro,upperdir=/mnt/root-rw /rootfs
 
# Move mounts
mount --move /mnt/root-ro /rootfs/mnt/root-ro
mount --move /mnt/root-rw /rootfs/mnt/root-rw
 
# Clean up.
umount /proc
umount /sys
 
exec switch_root /rootfs /bin/systemd
EOF
 
# give init exec privileges
chmod +x init
 
mkdir -p mnt/root-ro
mkdir -p mnt/root-rw
mkdir rootfs
 
mkdir proc
mkdir sys
mkdir dev
 
# you might also want to disable some mdev rules
echo > etc/mdev.conf

When we're finished modifying our initramfs we create it by running:

cd /home/me/raspberry/initramfs
# skip .git dir by find
find . -name .git -a -type d -prune -o -print | cpio -o -H newc > ../initramfs.cpio
cd ..
gzip -c initramfs.cpio > initramfs.img

Create rootfs with debootstrap

I wrote a little script that will deboostrap a minimal raspberry rootfs. Run as ./rpi-debootstrap.sh [directory to debootstrap to]. Download at https://github.com/wokis/raspberrypi/blob/master/rpi-debootstrap.sh

mkdir /home/me/raspberry/rootfs
./rpi-debootstrap.sh /home/me/raspberry/rootfs
 
cd /home/me/raspberry/rootfs
mkdir -p mnt/root-ro
mkdir -p mnt/root-rw
mkdir -p mnt/persistent

Helper scripts for rootfs

cat > /bin/remountro << EOF
#!/bin/bash
 
echo -e "Remounting rootfs as read-only..."
mount -o remount,ro /mnt/root-ro
echo "DONE."
EOF
 
cat > /bin/remountrw << EOF
#!/bin/bash
 
echo -e "Remounting rootfs as read-write..."
mount -o remount,rw /mnt/root-ro
echo "DONE."
EOF
 
cat > /bin/syncroot << EOF
#!/bin/bash
 
echo -e "Syncing rootfs...\n"
rsync -a -H -A -X --delete /mnt/root-rw/. /mnt/root-ro/mnt/persistent
echo "DONE."
EOF
 
chmod +x /bin/remountro
chmod +x /bin/remountrw
chmod +x /bin/syncroot
linux/raspberry_pi_read-only_root.txt · Last modified: 2017/11/29 18:51 by kacper