The fs Directory

File handling is at the core of any Unix system, and the fs directory in Linux is the fattest of all directories. It includes all the filesystems supported by the current Linux version, each in its own subdirectory, as well as the most important system calls after fork and exit.

The execve system call lives in exec.c and relies on the various available binary formats to actually interpret the binary data found in the executable files. The most important binary format nowadays is ELF, implemented by binfmt_elf.c. binfmt_script.c supports the execution of interpreted files. After detecting the need for an interpreter (usually on the #! or “shebang” line), the file relies on the other binary formats to load the interpreter.

Miscellaneous binary formats (such as the Java executable format) can be defined by the user with a /proc interface defined in binfmt_misc.c. The misc binary format is able to identify an interpreted binary format based on the contents of the executable file, and fire the appropriate interpreter with appropriate arguments. The tool is configured via /proc/sys/fs/binfmt_misc.

The fundamental system calls for file access are defined in open.c and read_write.c. The former also defines close and several other file-access system calls (chown, for instance). select.c implements select and poll. pipe.c and fifo.c implement pipes and named pipes. readdir.c implements the getdents system call, which is how user-space programs read directories (the name stands for “get directory entries”). Other programming interfaces to access directory data (such as the readdir interface) are all implemented in user space as library functions, based on the getdents system call.

Most system calls related to moving files around, such as mkdir, rmdir, rename, link, symlink, and mknod, are implemented in namei.c, which in turn lays its foundations on the directory entry cache that lives in dcache.c.

Mounting and unmounting filesystems, as well as support for the use of a temporary root for initrd, are implemented in super.c.

Of particular interest to device driver writers is devices.c, which implements the char and block driver registries and acts as dispatcher for all devices. It does so by implementing the generic open method that is used before the device-specific file_operations structure is fetched and used. read and write for block devices are implemented in block_dev.c, which in turn delegates to buffer.c everything related to buffer management.

There are several other files in this directory, but they are less interesting. The most important ones are inode.c and file.c, which manage the internal organization of file and inode data structures; ioctl.c, which implements ioctl; and dquot.c, which implements quotas.

As we suggested, most of the subdirectories of fs host individual filesystem implementations. However, fs/partitions is not a filesystem type but rather a container for partition management code. Some files in there are always compiled, regardless of kernel configuration, while other files that implement support for specific partitioning schemes can be individually enabled or disabled.

Get Linux Device Drivers, Second Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.