After we have made our kernel works with multiple programs, let them communicate each other, handle access to shared resources and protect the kernel space. Now it is time to start to think about how to store and access files in our kernel, and how we want to support file systems.
As we probably already know there are many different operating system available nowadays, some are proprietary of specific os/architectures, some are open source etc. Using any operating system daily usually we deal with at least 2/3 different file system types, that can grow quickly if we start to add an external device. For example if we are using a linux operating system with an external drive plugged, and a cdrom inserted we are already dealing with three different file system:
How can an operating system manage all these difference file systems and expose them to userspace under the same interface (and directory tree) - and most important of all: how are we going to implement it?
In this part we’re going to look at the subsystem that handles all of this, and how we might implement one.
It will be divided into two main topics:
open, write, opendir
Before proceeding is useful to recap some basic file system concepts.
The main purpose of a file system is to store and organise data, and make it easily accessible to humans and programs. A file system also provides the ability to access, create and update files. More advanced file systems can also provide some kind of recovery mechanism (aka journaling
), permissions, but we are not going to cover them because it’s out of the scope of this guide.
Different filesystems have different advantages: some are simpler to implement, otherwise may be offer extreme redundancy and others may be usable across a network. Each filesystem implementation is typically provided by a separate driver that then interacts with the virtual file system provided by the kernel. The most common filesystem drivers you will want to provide are ext2, FAT(12/16/32 - they are fundamentally all the same) and an ram-based ‘temp fs’. The tempfs may also support loading its contents from a TAR passed by the bootloader. This is the concept of a init ramdisk, and we’ll look at an example of how to implement this.
Each filesystem interally represents file (and directory) data in different ways. Whether they are just a structure laid out before the data, or an entry in a array or list somewhere.
How do we combine the output of all these different filesystems in a uniform way that’s usable by the rest of the OS? We achieve this through a layer of abstraction, which we called the virtual file system, or VFS. It’s responsible for acting as a scaffold that other filesystems can attach themselves to.
How the VFS presents itself is another design decision, but the two common ways to do it are: