The root filesystem (rootfs)

The root filesystem (rootfs) is the main filesystem for an UNIX-like operative system. It contains the very critical files needed for the whole system to work (for instance, the init process), so if the root filesystem gets corrupted, the system will not work at all!

The root filesystem is the first filesystem the kernel mounts at boot, and it is never unmounted.

A rootfs can be used on several different types of storage devices (disks, flashes, and so on). A filesystem can stay in the RAM or even over the network, and according to the storage device where it's placed on, it can have different formats. This is because it has to take into account some special feature of the underlying storage media. In a typical GNU/Linux system, a rootfs type can be (mostly) EXT3/EXT4 or JFFS2/UBIFS. The first two formats are the standard Linux filesystems used into hard disks, USB storage devices, microSDs, and other block devices, while the JFFS2 and UBIFS are filesystems used on fla devices (nowadays, NAND flashes).

Tip

sh devices (nowadays, NAND flashes). You might be willing to know the differences between these filesystems so that you can start your studies from https://en.wikipedia.org/wiki/File_system#Unix_and_Unix-like_operating_systems .

Apart from the format we're using in our system, we can find the same files and directory set in a root filesystem. Here is the typical listing on both my host PC and one developer kit of this book (see the uname output to distinguish the architecture):

$ uname -a
Linux ubuntu1510 4.2.0-35-generic #40-Ubuntu SMP Tue Mar 15 22:15:45 U TC 2016 x86_64 x86_64 x86_64 GNU/Linux
$ ls /
bin dev initrd.img lib64 mnt root srv usr vmlinuz.old
boot etc initrd.img.old lost+found opt run sys var
cdrom home lib media proc sbin tmp vmlinuz
root@wb:~# uname -a
Linux wb 4.4.7-armv7-x6 #1 SMP Sun Apr 17 18:41:21 CEST 2016 armv7l GN U/Linux
root@wb:~# ls /
bin dev home lost+found mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr

As we can see, they're almost the same (apart some files), and we can write the same directories. I can write a complete chapter on these directories and the files they hold, but this not the scope of this book. However, I can spend some paragraphs to explain the directories we're going to refer to in this book.

Tip

To get a complete listing of these directories and their contents and explanations, refer to https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard .

In particular, we'll see the following directories: /dev that is related to the system's devices or peripherals, /proc and /sys that are related to special virtual filesystem where we can get/set some system's settings, and /run and other directories related to the temporary filesystem.

The /dev directory

This is the directory where all devices (apart from the net devices) are mapped, that is, where the block or character special files (used to address all the relative peripherals into the system) are usually placed.

At very beginning of the UNIX era, this directory was simply a standard directory with several block and character files (one per possible device connected to the system). However, during the evolution of UNIX (and Linux), this solution become very inefficient (due the very large peripheral numbers). So, Linux developers implemented different solutions to address this problem until the current one that uses a special temporary filesystem named devtmpfs.

The devtmpfs filesystem is just like the temporary filesystem, but it lets the kernel create a tmpfs instance very early at kernel initialization, before any driver-core device is registered. This is because each device must be mapped here as soon as it is activated by its relative driver.

We can take a look at this using the findmnt command:

root@wb:~# findmnt /dev
TARGET SOURCE FSTYPE OPTIONS
/dev devtmpfs devtmpfs rw,relatime,size=1016472k,nr_inodes=186701,mo de=7555

The files under /dev in the Wandboard are reported here:

root@wb:~# ls /dev/
apm_bios mapper stdin tty29 tty51 uhid
ashmem mem stdout tty3 tty52 uinput
autofs memory_bandwidth tty tty30 tty53 urandom
binder mmcblk0 tty0 tty31 tty54 vcs
block mmcblk0p1 tty1 tty32 tty55 vcs1
btrfs-control mqueue tty10 tty33 tty56 vcs2
bus net tty11 tty34 tty57 vcs3
char network_latency tty12 tty35 tty58 vcs4
console network_throughput tty13 tty36 tty59 vcs5
cpu_dma_latency null tty14 tty37 tty6 vcs6
cuse port tty15 tty38 tty60 vcsa
disk ppp tty16 tty39 tty61 vcsa1
dri pps0 tty17 tty4 tty62 vcsa2
fb0 psaux tty18 tty40 tty63 vcsa3
fd ptmx tty19 tty41 tty7 vcsa4
full ptp0 tty2 tty42 tty8 vcsa5
fuse pts tty20 tty43 tty9 vcsa6
i2c-0 random tty21 tty44 ttymxc0 vga_arbiter
i2c-1 rfkill tty22 tty45 ttymxc2 watchdog
initctl rtc tty23 tty46 ttyS0 watchdog0
input rtc0 tty24 tty47 ttyS1 xconsole
kmem shm tty25 tty48 ttyS2 zero
kmsg snapshot tty26 tty49 ttyS3
log snd tty27 tty5 ttyS4
loop-control stderr tty28 tty50 ttyS5

We can recognize some known devices such as the serial ports (ttyS0, ttyS1, and so on), the I2C busses (i2c-0 and i2c-1), the real-time clock (rtc), and so on. Other devices are located into sub directories as disks:

root@wb:~# tree /dev/disk/ /dev/disk/ +-- by-id | +-- mmc-SL16G_0x28a39857 -> ../../mmcblk0 | \-- mmc-SL16G_0x28a39857-part1 -> ../../mmcblk0p1 +-- by-label | \-- rootfs -> ../../mmcblk0p1 +-- by-path | +-- platform-2198000.usdhc -> ../../mmcblk0 | +-- platform-2198000.usdhc-part1 -> ../../mmcblk0p1 \-- by-uuid \-- d38a7071-3fbf-4782-b406-ff64478c4266 -> ../../mmcblk0p1 4 directories, 6 files 

Ot the sound devices:

root@wb:~# tree /dev/snd/ /dev/snd/ +-- by-path | +-- platform-120000.hdmi -> ../controlC0 | +-- platform-sound -> ../controlC2 | \-- platform-sound-spdif -> ../controlC1 +-- controlC0 +-- controlC1 +-- controlC2 +-- pcmC0D0p +-- pcmC1D0p +-- pcmC2D0c +-- pcmC2D0p +-- seq \-- timer 1 directory, 12 files 
Tip

You can use your host PC or embedded device to walk around the /dev directory and discover other block or character devices. You can see the device type just using the ls command with the -l option arguments:

 root@wb:~# ls -l /dev/mmcblk0*
 brw-rw---- 1 root disk 179, 0 Jan 1 1970 /dev/mmc
 blk0
 brw-rw---- 1 root disk 179, 1 Jan 1 1970 /dev/mmc
 blk0p1
 root@wb:~# ls -l /dev/ttyS*
 crw-rw---- 1 root dialout 4, 64 Jan 1 1970 /dev/t
 tyS0
 crw-rw---- 1 root dialout 4, 65 Jan 1 1970 /dev/t
 tyS1
 crw-rw---- 1 root dialout 4, 66 Jan 1 1970 /dev/t
 tyS2
 crw-rw---- 1 root dialout 4, 67 Jan 1 1970 /dev/t
 tyS3
 crw-rw---- 1 root dialout 4, 68 Jan 1 1970 /dev/t
 tyS4
 crw-rw---- 1 root dialout 4, 69 Jan 1 1970 /dev/t
 tyS5

The block devices have a b character at the beginning of the first column of the ls output, while the character ones have a c. So, in the preceding output, we can see that /dev/mmcblk0xx are block devices while /dev/ttySx are character ones.

The tmpfs

The temporary filesystem (tmpfs) is a filesystem stored on top of volatile memory instead of a persistent storage device. Due to this fact, on reboot, everything in tmpfs will be lost.

Even if it may look really strange that a vanishing filesystem can be useful, it really is! In fact, it is used where the system needs quick read, write, and delete operations on several files that are to be recreated on every boot. These files are exactly the ones under the /run directory, that is, where (almost) every distribution stores temporary files related to its running services (daemons).

On the Wandboard, we have the following tmpfs filesystems:

root@wb:~# findmnt tmpfs
TARGET SOURCE FSTYPE OPTIONS
/dev/shm tmpfs tmpfs rw,nosuid,nodev
/run tmpfs tmpfs rw,nosuid,nodev,mode=755
/run/lock tmpfs tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k
/sys/fs/cgroup tmpfs tmpfs ro,nosuid,nodev,noexec,mode=755

You may notice that there are other places where tmpfs are used!

The procfs

The proc filesystem (procfs) is a virtual filesystem that holds information about the processes (and other system information) in a hierarchical file structure. This allows the user to find the necessary information quickly by looking at a well-defined point of the system where all information is pretty ordinated.

A virtual filesystem is a filesystem that contains virtual files (files stored nowhere filled with information created on the fly when they get accessed) used to export information about various kernel subsystems, hardware devices, and associated device drivers to user space. In addition to providing this information, these exported virtual files are also used for system configuration and device management.

The standard mount point of this filesystem is the /proc directory, as shown here:

root@wb:~# findmnt proc
TARGET SOURCE FSTYPE OPTIONS
/proc proc proc rw,nosuid,nodev,noexec,relatime

Then, in this directory, we can find all process-related information. For instance, if we wish to have some information about the init process, the first process executed into the system (that is, the process with PID 1), we should have a look at the /proc/1 directory as shown here:

root@wb:~# ls /proc/1
attr cpuset limits net root statm
autogroup cwd loginuid ns sched status
auxv environ map_files oom_adj schedstat syscall
cgroup exe maps oom_score sessionid task
clear_refs fd mem oom_score_adj setgroups timers
cmdline fdinfo mountinfo pagemap smaps uid_map
comm gid_map mounts personality stack wchan
coredump_filter io mountstats projid_map stat

Here is located all information regarding the init process. For example, we can find the environment:

root@wb:~# cat /proc/1/environ ; echo
HOME=/TERM=linux
Tip

The echo command has been used to force a newline (\n) character at the end of the preceding cat command's output.

We can retrieve the command line used to execute the process:

/sbin/initroot@wb:~# cat /proc/1/cmdline ; echo
/sbin/init

Or the init's memory usage:

root@wb:~# cat /proc/1/maps
00010000-000cb000 r-xp 00000000 b3:01 655091 /lib/systemd/systemd
000db000-000eb000 r--p 000bb000 b3:01 655091 /lib/systemd/systemd
000eb000-000ec000 rw-p 000cb000 b3:01 655091 /lib/systemd/systemd
01da2000-01e67000 rw-p 00000000 00:00 0 [heap]
b6cc3000-b6d05000 rw-p 00000000 00:00 0
...
Tip

Here we discover that, in reality, the real init process is systemd. Visit https://en.wikipedia.org/wiki/Systemd for further information.

Or the file descriptors used:

root@wb:~# ls -l /proc/1/fd
total 0
lrwx------ 1 root root 64 Jan 1 1970 0 -> /dev/null
lrwx------ 1 root root 64 Jan 1 1970 1 -> /dev/null
lr-x------ 1 root root 64 Apr 2 19:04 10 -> /proc/swaps
lrwx------ 1 root root 64 Apr 2 19:04 11 -> socket:[13056]
lrwx------ 1 root root 64 Apr 2 19:04 12 -> socket:[13058]
lrwx------ 1 root root 64 Apr 2 19:04 13 -> anon_inode:[timerfd]
lr-x------ 1 root root 64 Apr 2 19:04 19 -> anon_inode:inotify
...

This information can be retrieved for every process running into the system. For instance, we can get the information regarding our Bash shell by discovering its PID first:

root@wb:~# pidof bash
588
Tip

My Wandboard is running just one instance of the Bash process, so I am sure that the preceding PID is referred to my shell.

Then, we can look at /proc/588 directory:

root@wb:~# ls /proc/588/
attr cpuset limits net root statm
autogroup cwd loginuid ns sched status
auxv environ map_files oom_adj schedstat syscall
cgroup exe maps oom_score sessionid task
clear_refs fd mem oom_score_adj setgroups timers
cmdline fdinfo mountinfo pagemap smaps uid_map
comm gid_map mounts personality stack wchan
coredump_filter io mountstats projid_map stat

Now, we can check out the shell's environment by looking at the /proc/588/environ file:

root@wb:~# cat /proc/588/environ ; echo
TERM=vt102LANG=en_US.UTF-8HOME=/rootSHELL=/bin/bashUSER=rootLOGNAME=ro otPATH=/ul
ocal/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binMAIL=/ var/mail/rootHUSHLON
=FALSE

However, the procfs, as already shown in Managing the kernel messages section Chapter 2 , Managing the System Console, where we used it to set the kernel console logging level, can be used to get/set other information regarding the system settings in general. For instance, we can get the listing of the currently loaded modules into the kernel by reading the file /proc/modules:

root@wb:~# cat /proc/modules
brcmfmac 254455 0 - Live 0xbf4d0000el
brcmutil 9092 1 brcmfmac, Live 0xbf4c2000
cfg80211 536448 1 brcmfmac, Live 0xbf3e0000
caam_jr 17297 0 - Live 0xbf34a000
snd_soc_fsl_ssi 15476 2 - Live 0xbf342000
...

Alternatively, we can read how many interrupts we have got per CPU since the boot from the /proc/interrupts file:

root@wb:~# cat /proc/interrupts
 CPU0 CPU1 CPU2 CPU3 
16: 1589 2441 3120 1370 GIC 29 Edge twd
17: 0 0 0 0 GPC 55 Level i.MX Tk
19: 0 0 0 0 GPC 115 Level 120000i
20: 0 0 0 0 GPC 9 Level 130000u
21: 0 0 0 0 GPC 10 Level 134000u
24: 0 0 0 0 GPC 52 Level 200400f
25: 661 0 0 0 GPC 26 Level 202000l
26: 0 0 0 0 GPC 46 Level 202800i
28: 0 0 0 0 GPC 12 Level 204000u
...
303: 0 0 0 0 IPU 23 Edge imx_drm
304: 0 0 0 0 IPU 28 Edge imx_drm
305: 0 0 0 0 IPU 23 Edge imx_drm
306: 0 0 0 0 IPU 28 Edge imx_drm
307: 0 0 0 0 GIC 137 Level 2101000
308: 0 0 0 0 GIC 138 Level 2102001
IPI0: 0 0 0 0 CPU wakeup interrupts
IPI1: 0 0 0 0 Timer broadcast interrupts
IPI2: 1370 4505 5119 9684 Rescheduling interrupts
IPI3: 92 69 55 96 Function call interrupts
IPI4: 0 2 2 0 Single function call interr.
IPI5: 0 0 0 0 CPU stop interrupts
IPI6: 0 0 0 0 IRQ work interrupts
IPI7: 0 0 0 0 completion interrupts
Err: 0

This file is really important when we work with the hardware since we can have an idea whether our device is generating interrupts or not. Also, we can have information regarding the correct interrupt handlers' configurations (we'll see these features in the upcoming chapters when we talk about the peripherals).

Also, we can get the actual device tree configuration by reading the contents of the /proc/device-tree directory as follows:

root@wb:~# ls /proc/device-tree
#address-cells cpus memory #size-cells
aliases display-subsystem model soc
chosen gpu-subsystem name sound
clocks interrupt-controller@00a01000 regulators sound-spdif
compatible __local_fixups__ rfkill __symbols__

Referring to our preceding sample driver, we can retrieve the pulse device's tree settings by reading into the /proc/device-tree/pulses/ directory as shown here (note that this time, we switch back to the SAMA5D3 Xplained):

root@a5d3:~# tree /proc/device-tree/pulses/ /proc/device-tree/pulses/ +-- compatible +-- name +-- oil | +-- gpios | +-- label | +-- name | \-- trigger \-- water +-- gpios +-- label +-- name \-- trigger 2 directories, 10 files 

Then, we can check the data by reading the several files. Here are the trigger settings:

root@a5d3:~# cat /proc/device-tree/pulses/oil/trigger ; echo both root@a5d3:~# cat /proc/device-tree/pulses/water/trigger ; echo rising

Here are the GPIO settings (the GPIO number is the eighth byte):

root@a5d3:~# cat /proc/device-tree/pulses/oil/gpios | \ hexdump -e '16/1 " %3i"' -e '"\n"' 0 0 0 121 0 0 0 17 0 0 0 0 root@a5d3:~# cat /proc/device-tree/pulses/water/gpios | \ hexdump -e '16/1 " %3i"' -e '"\n"' 0 0 0 121 0 0 0 19 0 0 0 0 

This is a nice feature to have in a system, but not all kernel developers agree that this information should be stored in the procfs because a proc filesystem should report processes' information only. That's why, the sysfs shown in the next paragraph was born (in reality, this is not the only reason).

Tip

You may get further information by surfing the Internet or just reading the file Documentation/filesystems/procfs.txt from Linux's source tree.

The sysfs

The system filesystem (sysfs) is a virtual filesystem that exports information about all kernel subsystems, system's buses, and the hardware devices with their relative device drivers. This filesystem is deeply related to the device tree concept (as shown here) and the power system management, and it mainly resolves the problem to have a unified method of representing driver-device relationships and how to correctly put them in the power-saver mode.

From our point of view, the sysfs is really important since by using it, we can get/set most peripherals settings and we can get access to the peripherals data too.

The default mount point of this filesystem is the /sys directory as shown below:

root@wb:~# findmnt sysfs
TARGET SOURCE FSTYPE OPTIONS
/sys sysfs sysfs rw,nosuid,nodev,noexec,relatime

Just by listing its contents, we can have an idea about its organization:

root@wb:~# ls /sys/
block bus class dev devices firmware fs kernel module power

These directory names are quite self-explanatory. However, some words should be spent talking about the directories we're going to use into this book.

Tip

You may get further information by surfing the Internet or just by reading the file Documentation/filesystems/sysfs.txt from Linux's source tree.

The first directory is /sys/class:

root@wb:~# ls /sys/class/
ata_device drm ieee80211 net rtc udc
ata_link dvb input pci_bus scsi_device uio
ata_port extcon iommu phy scsi_disk vc
backlight firmware leds power_supply scsi_host video4linux
bdi gpio mbox pps sound vtconsole
block graphics mdio_bus ptp spi_master watchdog
bsg hidraw mem pwm switch
devcoredump hwmon misc rc thermal
devfreq i2c-adapter mmc_host regulator timed_output
dma i2c-dev mtd rfkill tty

It stores all devices' information grouped by the device class, that is, a logical set of devices that perform a common task in the system: graphics devices, sound devices, hardware monitor (hwmon) devices, and so on.

Referring to our preceding sample driver, we can retrieve the pulse class settings by reading into the /sys/class/pulse/ directory as shown here (note that we switch back to the SAMA5D3 Xplained again):

root@a5d3:~# tree -L 2 -l /sys/class/pulse/ /sys/class/pulse/ +-- oil -> ../../devices/soc0/pulses/pulse/oil | +-- counter | +-- counter_and_reset | +-- device -> ../../../pulses | +-- power | +-- set_to | +-- subsystem -> ../../../../../class/pulse [recursive, not followed] | \-- uevent \-- water -> ../../devices/soc0/pulses/pulse/water +-- counter +-- counter_and_reset +-- device -> ../../../pulses [recursive, not followed] +-- power +-- set_to +-- subsystem -> ../../../../../class/pulse [recursive, not followed] \-- uevent 8 directories, 8 files 

For instance, we can get information regarding the framebuffer (these devices will not be presented in this book, however they refer to a graphic hardware-independent abstraction layer to show graphical data on a computer display) by taking a look at the /sys/class/graphics/fb0/ directory:

root@wb:~# ls /sys/class/graphics/fb0/
bits_per_pixel console device name rotate subsystem
blank cursor mode pan state uevent
bl_curve dev modes power stride virtual_size

Then, we can get the valid graphic modes using the command here:

root@wb:~# cat /sys/class/graphics/fb0/modes
U:1024x768p-0

Alternatively, we can get some information about a hwmon device (these devices will not be presented in this book, however they are used to monitoring some environment data, such as temperatures, and so on. of the system or external peripheral ones) on the Wandboard in the directory here:

root@wb:~# ls /sys/class/hwmon/hwmon0/
name power subsystem temp1_crit temp1_input uevent

Then, by looking at the hwmon device, we can get the name, the critical temperature, and the current system's temperature using the command here:

root@wb:~# cat /sys/class/hwmon/hwmon0/{name,temp1_crit,temp1_input}
imx_thermal_zone
95000
28318
Tip

Returned data are in m°C, that is they are, respectively, 95°C and 28.318°C.

In the upcoming chapters, when we present the several devices a developer can find in its embedded board and how they can get access to them, we will use this filesystem often.