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.