Some ideas about File System


posted by Pype at 7.11.01

Files support in microKernel

It would be fine (or at least i think it should be fine) if the microkernel was not dependent on a complete file system, allowing us, for instance, to run Clicker on a diskless system (just having some infos in SOS' diskimage). However, even if everything is in main memory, it's convenient to think it as files that can be called by their names, etc.

So i purpose we introduce a file service for the kernel before having a complete file system. This service only provide a very reduced set of operations on files like mapping a whole file in memory or re-writing its content in the persistent memory area.

Natively, the microkernel will have a server that implement this service by using SOS_map() ugly function (and thus being read-only), but later (by loading a module), we could upgrade this service - for instance by replacing the disk image by a /boot directory of the complete filesystem.

A first attemp for file interface.

I suggest we use the "services.sys.file" kds-string for that /boot filesystem. We don't plan the kernel to call complex operations like allocating space for new files or so. Instead, we have a fixed allocation of storage-area (defined by the content of the disk image, for instance) that we can modify by some external way (re-making the boot datas of a floppy, re-constructing the DISK.IMG file for SOS or simply modifying files in the appropriate directory of the complete file system) and that the kernel will use to read or write file contents.

The smallest possible interface is "services.sys.file:map" which will just have an "open" function (returning a sfsFileImage structure from a filename string), a "close" function (that will destroy that structure) and a "map" function that forces loading all the file in memory (we will give a kmemProp describing what kind of memory should be used) and return the pointer to that memory.
A fourth function list should return a cursor object to browse the available names in the system directory.

So in KDS2, it will gives something like

server("slashboot","sys.file")
implements("map")
method(open, char* filename, out: struct sfsFileImage *fi);
method(close, struct sfsFileImage *fi);
method(map, char* filename, out: void* addr);
method(list, out: vsetcursor_object *cur);
end
end
an optionnal "commit" method might be used to save the file modification to permanent storage.

Note that a specific vsetcursor_class  will have to be defined in order to support conversion between SOS "." file and the cursor paradigm. Also note that we should define a structure for directory entries (returned by the cursor - for instance, including the file name as a C string, the class of the file (also a string ?) and its size).



A framework for device drivers


This is the next step: having a service for accessing raw devices. Each of such "block device" is a server registered on "services.file.device" and it implements "block". The "block" interface is provided for upper-layered parts of the file system like volumes that will deal with block allocation and blocks grouping into logical arrays / sets / sequences, etc. (i.e. files without a name)

Mainly, the methods we will find in "block" are dealing only with block reading / writing and synchronisation (forcing the process to wait until the queue is flushed). Another interface - "info" - might be used to get generic informations about the device, like its hardware type, etc.

Because there should be same infos about every block device, it would be silly to implement it as a "pure" KDS set (having the very same structure and keys for every device, just having the values that change). Something better has to be found.

server("my-block","file.device")
implements("block")
method(read,long int blockid, void* buffer);
method(write, long int blockid, void* buffer);
method(read_n,long int blockid, int n, void *buffer);
method(write_n, long int blockid, int n, void *buffer);
method(sync);
end
implements("info")
method(info,out:char* kds-name-to-info-object);
method(info_by_blockid, long int blockid, char* kds-name-to-info-object);
end
_open_ my_block_init()
{
    // register the info object in the proper set
}
end

One possible solution to that info problems (size of blocks, amount of available blocks, vendor string, etc.) is - if we have kds-objects extension - to define a object recogniser for such stuffes, that is a method registered into "path.to.objects?" that will receive calls when you try to access "members" of an object in "path.to.object.*". For instance, if you have registered "system.devices.block?" as a recognizer for block devices, you'll only have to declare your structure as a "system.devices.block.hdd1" as a KDS_OBJECT to let the recognizer be used for infos retreival. (looking up "system.devices.block.hdd1.vendor" will call lookup(<hdd1_object>, "vendor") at the recognizer.

Well, it seems that i'll have to implement KDS2 before we can really work with block devices that way ...

Note that another stuff that would be very interresting would be to support adding of new informations into the objects representation (that is, derivating recognizers). Also, it would be interresting if we might have an automatic constructor for such objects.

Some KDS2 issues we should discuss :