This is part of an experiment to improve the L4Re user space.
The operations defined for this kind of filesystem server could be implemented by other servers that have different kinds of storage. For instance, a lightweight "virtual" filesystem might hold nodes in memory and might not even support files of any considerable size.
"Project: A Simple Operating System" covers similar topics. Of particular interest is the "M2: System call interface" milestone which describes the role of musl-libc and how it provides C library functions to programs.
Employing a rom file and accessing it from within a server, exposing operations that are implemented using standard file operations, is the first step:
Subsequently, for more realism, a device server can be introduced to host the filesystem data, even if at first the device server is really only calling the same file operations as before:
Ultimately, the C library calls will be "backed" by the IPC mechanisms:
Various filesystem APIs exist such as those provided by FUSE (defined in fuse.h as fuse_operations).
To avoid unnecessary complication, some essential operations may be defined. In practice, it is desirable to provide operations that support familiar system call primitives such as...
It might also be nice to provide support for memory-mapped files:
This would require some kind of paging support, but perhaps this might be achieved by supporting the appropriate protocol in the filesystem server.
See a description of file operations and their implementation.
One fundamental operation involves looking paths up and determining how the referenced objects are to be accessed. This might occur via the principal capability for filesystem access.
A capability might be provided by creating a resource object, referring to the filesystem object and maintaining relevant state. This capability becomes the point of contact with the filesystem, utilising filesystem code plus object-specific state to manipulate the object.
The process of accessing a file is as follows:
The following client-side pseudocode can be formulated:
# Allocate dataspace and IRQ. ds = alloc_dataspace() irq = alloc_irq() # Write path to buffer. (This is just a memory-writing operation.) ds.write(path) # Obtain a reference to the file object. f = fs.open(ds, irq)
Reading from the file involves sending a message requesting data to the file object. Data is written to the shared buffer and information about the updated buffer is communicated:
It should be possible to wait for updates in files. This can be done by creating an interrupt request (IRQ) object and passing it along with the dataspace to a filesystem server. Updates will then cause the invocation of the IRQ object, and where the client has elected to wait for updates, a notification will be delivered:
A mechanism is required to clean up resource objects once clients are finished with them, regardless of whether this is done explicitly or not. Explicit closure of files can be done using a close operation. Implicit closure of files is done by registering an interrupt request (IRQ) object for the deletion condition on the IPC gate that exposes the resource:
The filesystem object accessed by applications would need to be configured with an identity in order to interpret the layout of the filesystem and the metadata associated with filesystem objects. This user-configured filesystem object, along with the resource objects created by it, would in turn access the underlying storage, most likely something resembling a block device.
A device server will expose an interface that allows clients to access buffers containing raw filesystem data. When communicating with a server, a client provides its own dataspace, into which data is written by the server upon reading from the device. To update the device's data, a write operation is performed after the client has modified the data within the dataspace.
For the most part, devices should behave like normal files.
Filesystems will employ the primitives provided by the device servers to access the raw data. The data is then interpreted as providing the following:
The organisation of such things is one of the tricks to designing a good filesystem, but a simple approach could be employed initially. Eventually, existing filesystem implementations could be considered with ext2-based filesystems being supported using libext2fs.
Basic operations to support on files would be like those supported on devices:
Meanwhile, the means to navigate directory listings would also be needed.
The following packages are currently used to explore this work:
The idl4re tool is also required.