Using SquashFS to read-only root file system

This HOWTO guide describes the usage of SquashFS.
SquashFS is a compressed read-only file system for Linux on ODROID-XU4 series like HC1,HC2,MC1 and XU3.
RootFS corruption rate after power failures will be significantly reduced because SquashFS is a very robust file system.

Note..
The properly working built-in squashfs is available in the Kernel update 4.14.5-92 or higher.

Prepare a boot device

You need to prepare a bootable uSD or emmc with Ubuntu minimal image.
For instructions on how to write images to a card, see the following page.
https://wiki.odroid.com/troubleshooting/odroid_flashing_tools
This HOWTO guide is using a uSD card.

Installing the squashfs-tools

Now you need to install squashfs-tools on your linux pc- the tool for creating squashed file systems.

ck@ck-desktop:~$ sudo apt install squashfs-tools

Creating squashed root file system image

1. Remove auto-resize script.
2. Eidt /etc/rc.local and remove auto-resize feature.
3. Eidt /etc/fstab and remove root mount option.
4. Use mksquashfs for creating read-only root file systems
ck@ck-desktop:~$ sudo rm /media/ck/rootfs/aafirstboot
ck@ck-desktop:~$ sudo cat /media/ck/rootfs/etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
 
 
if [ -f /aafirstboot ]; then /aafirstboot start ; fi
 
exit 0
 
ck@ck-desktop:~$ sudo nano /media/ck/rootfs/etc/rc.local
ck@ck-desktop:~$ sudo cat /media/ck/rootfs/etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
 
exit 0
ck@ck-desktop:~$ sudo cat /media/ck/rootfs/etc/fstab
UUID=e139ce78-9841-40fe-8823-96a304a09859 / ext4 errors=remount-ro,noatime 0 1
LABEL=boot /media/boot vfat defaults 0 1
 
ck@ck-desktop:~$ sudo nano /media/ck/rootfs/etc/fstab
ck@ck-desktop:~$ sudo cat /media/ck/rootfs/etc/fstab
LABEL=boot /media/boot vfat defaults 0 1
 
ck@ck-desktop:~$ sudo mksquashfs /media/ck/rootfs/ squash.rootfs
Parallel mksquashfs: Using 8 processors
Creating 4.0 filesystem on squash.rootfs, block size 131072.
[=================================================================================-] 36821/36821 100%
 
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072
	compressed data, compressed metadata, compressed fragments, compressed xattrs
	duplicates are removed
Filesystem size 423720.81 Kbytes (413.79 Mbytes)
	42.27% of uncompressed filesystem size (1002435.26 Kbytes)
Inode table size 464688 bytes (453.80 Kbytes)
	28.95% of uncompressed inode table size (1604883 bytes)
Directory table size 433806 bytes (423.64 Kbytes)
	39.67% of uncompressed directory table size (1093654 bytes)
Xattr table size 48 bytes (0.05 Kbytes)
	40.00% of uncompressed xattr table size (120 bytes)
Number of duplicate files found 2340
Number of inodes 45340
Number of files 31162
Number of fragments 1912
Number of symbolic links  10373
Number of device nodes 79
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 3726
Number of ids (unique uids + gids) 22
Number of uids 6
	root (0)
	man (6)
	dnsmasq (104)
	rtkit (107)
	libuuid (100)
	avahi-autoipd (105)
Number of gids 18
	root (0)
	video (44)
	audio (29)
	tty (5)
	kmem (15)
	disk (6)
	dip (30)
	shadow (42)
	utmp (43)
	messagebus (106)
	ssh (111)
	mlocate (110)
	staff (50)
	avahi-autoipd (113)
	netdev (102)
	adm (4)
	scanner (109)
	mail (8)
ck@ck-desktop:~$

Squashed file systems on uSD

If everything went fine, unmount /dev/sdc2 (if needed) and use dd to copy squash.rootfs to /dev/sdc2:

1. Unmount all uSD partition
2. Use dd to copy squash.rootfs file to uSD partition #2.
3. Reconnect the uSD and check the mount
ck@ck-desktop:~$ mount
/dev/sdc2 on /media/ck/rootfs type ext4 (rw,nosuid,nodev,uhelper=udisks2)
/dev/sdc1 on /media/ck/boot type vfat (rw,nosuid,nodev,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,showexec,flush,uhelper=udisks2)
ck@ck-desktop:~$ sudo umount /dev/sdc?
ck@ck-desktop:~$ sudo dd if=./squash.rootfs of=/dev/sdc2
ck@ck-desktop:~$ sync
ck@ck-desktop:~$
ck@ck-desktop:~$ mount
 
/dev/sdc2 on /media/ck/disk type squashfs (ro,nosuid,nodev,uhelper=udisks2)
/dev/sdc1 on /media/ck/boot type vfat (rw,nosuid,nodev,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,showexec,flush,uhelper=udisks2)

Modifying rootfs mount options in the boot.ini file

You can find the UUID of the ext4 partition in the “root=” option in the boot.ini file. (/media/ck/boot/boot.ini)

#------------------------------------------------------------------------------------------------------
# Basic Ubuntu Setup. Don't touch unless you know what you are doing.
# --------------------------------
setenv bootrootfs "console=tty1 console=ttySAC2,115200n8 root=UUID=e139ce78-9841-40fe-8823-96a304a09859 rootwait ro fsck.repair=yes net.ifnames=0"

Find the bootrootfs environment and change the rootfs options as follows:
This HOWTO using uSD. If you are using emmc, you can use root=mmcblk0p2

#------------------------------------------------------------------------------------------------------
# Basic Ubuntu Setup. Don't touch unless you know what you are doing.
# --------------------------------
setenv bootrootfs "console=tty1 console=ttySAC2,115200n8 root=/dev/mmcblk1p2 rootfstype=squashfs rootwait ro net.ifnames=0"
ck@ck-desktop:~$ nano /media/ck/boot/boot.ini
ck@ck-desktop:~$ cat /media/ckkim/boot/boot.ini | grep bootrootfs
setenv bootrootfs "console=tty1 console=ttySAC2,115200n8 root=/dev/mmcblk1p2 rootfstype=squashfs rootwait ro net.ifnames=0"
setenv bootargs "${bootrootfs} ${videoconfig} ${hdmi_phy_control} ${hid_quirks} smsc95xx.macaddr=${macaddr} ${external_watchdog} governor=${governor}"
ck@ck-desktop:~$

Now just ensure that everything works fine
Don't forget to set the boot mode switch to uSD.
odroid login : root, password : odroid

root@odroid:/# mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
udev on /dev type devtmpfs (rw,nosuid,relatime,size=952168k,nr_inodes=186804,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=204240k,mode=755)
/dev/mmcblk1p2 on / type squashfs (ro,relatime)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=27,pgrp=1,timeout=0,minproto=5,maxproto=5,direct)
mqueue on /dev/mqueue type mqueue (rw,relatime)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
configfs on /sys/kernel/config type configfs (rw,relatime)
/dev/mmcblk1p1 on /media/boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,size=204240k,mode=700)

Example : Make the /home writable.

1. Create a new ext4 partition on the uSD.
2. Unpack squashfs-root 
3. make new /media/data directory.
4. Edit /etc/fstab to mount ext4 data partition rw
5. Add/modify as per your taste then recreate squash.rootfs
6. Copy the newly created squash.rootfs over the existing one on uSD
7. Boot using uSD with new image
ck@ck-desktop:~$ sudo umount /dev/sdc?
ck@ck-desktop:~$ sudo fdisk /dev/sdc
ck@ck-desktop:~$ sudo mkfs.ext4 /dev/sdc3 -L data
ck@ck-desktop:~$ sudo unsquashfs squash.rootfs
ck@ck-desktop:~$ sudo mkdir -p squashfs-root/media/data
ck@ck-desktop:~$ sudo nano squashfs-root/etc/fstab
ck@ck-desktop:~$ cat squashfs-root/etc/fstab
LABEL=boot /media/boot vfat defaults 0 1
LABEL=data /media/data ext4 defaults 0 1
ck@ck-desktop:~$ sudo mksquashfs squashfs-root/ squash.rootfs.1
ck@ck-desktop:~$ sudo dd if=./squash.rootfs.1 of=/dev/sdc2

then reboot and using uSD with new image

root@odroid:~# mount | grep mmc
/dev/mmcblk1p2 on / type squashfs (ro,relatime)
/dev/mmcblk1p1 on /media/boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
/dev/mmcblk1p3 on /media/data type ext4 (rw,relatime,data=ordered)
root@odroid:~# 

Simple Squashfs testing

Creation of SquashFS filesystems is performed with the mksquashfs command.

mksquashfs /home/odroid /home/odroid/home.squashfs
 
Parallel mksquashfs: Using 4 processors
Creating 4.0 filesystem on /home/odroid/home.squashfs, block size 131072.
[====================================================================================================================================/] 122/122 100%
 
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072
        compressed data, compressed metadata, compressed fragments, compressed xattrs
        duplicates are removed
Filesystem size 249.07 Kbytes (0.24 Mbytes)
        21.48% of uncompressed filesystem size (1159.79 Kbytes)
Inode table size 1707 bytes (1.67 Kbytes)
        32.35% of uncompressed inode table size (5276 bytes)
Directory table size 3289 bytes (3.21 Kbytes)
        53.44% of uncompressed directory table size (6155 bytes)
Number of duplicate files found 5
Number of inodes 163
Number of files 124
Number of fragments 6
Number of symbolic links  1
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 38
Number of ids (unique uids + gids) 2
Number of uids 2
        odroid (1000)
        root (0)
Number of gids 2
        odroid (1000)
        root (0)

Mount SquashFS system

To mount a SquashFS, use the mount command's -o loop option with escalated privileges:

$ mkdir -p ~/tmp
$ sudo mount -o loop ~/home.squashfs ~/tmp
[sudo] password for odroid:
ls -al  ~/tmp/
total 36
drwxr-xr-x 15 odroid odroid   503 Jul 25 09:34 .
drwxr-xr-x 16 odroid odroid  4096 Jul 25 09:39 ..
-rw-------  1 odroid odroid  1264 Jan 28 15:58 .ICEauthority
-rw-------  1 odroid odroid    51 Jan 28 15:58 .Xauthority
-rw-------  1 odroid odroid   180 Jul 25 05:56 .bash_history
-rw-r--r--  1 odroid odroid   220 Jul 19 18:05 .bash_logout
-rw-r--r--  1 odroid odroid  3771 Jul 19 18:05 .bashrc
drwxr-xr-x  6 odroid odroid   267 Jul 25 04:50 .cache
drwx------ 12 odroid odroid   234 Jul 20 11:59 .config
-rw-r--r--  1 odroid odroid    23 Jul 19 18:07 .dmrc
drwx------  3 odroid odroid    40 Jul 19 18:07 .gnupg
drwx------  3 odroid odroid    28 Jul 19 18:07 .local
drwx------  3 odroid odroid    28 Jul 20 11:47 .pki
-rw-r--r--  1 odroid odroid   807 Jul 19 18:05 .profile
-rw-r--r--  1 odroid odroid     0 Jul 19 18:18 .sudo_as_admin_successful
-rw-r--r--  1 odroid odroid 12288 Jul 25 09:27 .sw.sh.swp
-rw-------  1 odroid odroid  1686 Jul 25 09:01 .viminfo
-rw-------  1 odroid odroid  8584 Jul 20 11:55 .xsession-errors
-rw-------  1 odroid odroid     0 Jul 20 11:36 .xsession-errors.old
drwxr-xr-x  2 odroid odroid     3 Jul 19 18:07 Desktop
drwxr-xr-x  2 odroid odroid     3 Jul 19 18:07 Documents
drwxr-xr-x  2 odroid odroid     3 Jul 19 18:07 Downloads
drwxr-xr-x  2 odroid odroid     3 Jul 19 18:07 Music
drwxr-xr-x  2 odroid odroid     3 Jul 19 18:07 Pictures
drwxr-xr-x  2 odroid odroid     3 Jul 19 18:07 Public
drwxr-xr-x  2 odroid odroid     3 Jul 19 18:07 Templates
drwxr-xr-x  2 odroid odroid     3 Jul 19 18:07 Videos
-rw-r--r--  1 odroid odroid     0 Jul 25 09:34 home.squashfs
-rw-r--r--  1 root   root       0 Jan 28 15:58 resize.log

Extract Squashfs file system

SquashFS files can be extracted using unsquashfs. Supposing the ~/tmp directory and the ~/home.squashfs file have been previously created in the steps above.

unsquashfs -d tmp/ -f home.squashfs

Squashfs umount file system

To unmount the filesystem, use the umount command with escalated privileges:

sudo umount ~/tmp

Simple overlayfs testing

For example the overlayfs is used(overlayfs is enabled as a module in the 4.14.y kernel) Use overlayfs to make /home writable.

root@odroid:~# modprobe overlay
root@odroid:~# lsmod
Module                  Size  Used by
overlay                65536  0
joydev                 20480  0
spidev                 20480  0
spi_s3c64xx            20480  0
exynos_gpiomem         16384  0
ipv6                  380928  28
root@odroid:~# 
root@odroid:~# mkdir -p /media/data/home
root@odroid:~# mkdir -p /media/data/home/upper
root@odroid:~# mkdir -p /media/data/home/work
root@odroid:~# mount -t overlay -o lowerdir=/home,upperdir=/media/data/home/upper,workdir=/media/data/home/work overlay /home
root@odroid:~#
root@odroid:~# mount
.
.
.
overlay on /home type overlay (rw,relatime,lowerdir=/home,upperdir=/media/data/home/upper,workdir=/media/data/home/work)
root@odroid:~#
root@odroid:~# cd /home
root@odroid:/home# touch file1
root@odroid:/home# ls
file1
root@odroid:/home#