
driverfs - The Device Driver Filesystem

Patrick Mochel	<mochel@osdl.org>

3 December 2001


What it is:
~~~~~~~~~~~
driverfs is a unified means for device drivers to export interfaces to
userspace.

Some drivers have a need for exporting interfaces for things like
setting device-specific parameters, or tuning the device performance.
For example, wireless networking cards export a file in procfs to set
their SSID.

Other times, the bus on which a device resides may export other
information about the device. For example, PCI and USB both export
device information via procfs or usbdevfs.

In these cases, the files or directories are in nearly random places
in /proc. One benefit of driverfs is that it can consolidate all of
these interfaces to one standard location.


Why it's better than procfs:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This of course can't happen without changing every single driver that
exports a procfs interface, and having some coordination between all
of them as to what the proper place for their files is. Or can it?


driverfs was developed in conjunction with the new driver model for
the 2.5 kernel. In that model, the system has one unified tree of all
the devices that are present in the system. It follows naturally that
this tree can be exported to userspace in the same order.

So, every bus and every device gets a directory in the filesystem.
This directory is created when the device is registered in the tree;
before the driver actually gets a initialised. The dentry for this
directory is stored in the struct device for this driver, so the
driver has access to it.

Now, every driver has one standard place to export its files.

Granted, the location of the file is not as intuitive as it may have
been under procfs. But, I argue that with the exception of
/proc/bus/pci, none of the files had intuitive locations. I also argue
that the development of userspace tools can help cope with these
changes and inconsistencies in locations.


Why we're not just using procfs:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When developing the new driver model, it was initially implemented
with a procfs tree. In explaining the concept to Linus, he said "Don't
use proc."

I was a little shocked (especially considering I had already
implemented it using procfs). "What do you mean 'don't use proc'?"

His argument was that too many things use proc that shouldn't. And
even more things misuse proc that shouldn't. On top of that, procfs
was written before the VFS layer was written, so it doesn't use the
dcache. It reimplements many of the same features that the dcache
does, and is in general, crufty.

So, he told me to write my own. Soon after, he pointed me at ramfs,
the simplest filesystem known to man.

Consequently, we have a virtual fileystem based heavily on ramfs, and
borrowing some conceptual functionality from procfs.

It may suck, but it does what it was designed to. At least so far.


How it works:
~~~~~~~~~~~~~

Directories are encapsulated like this:

struct driver_dir_entry {
	char                    * name;
	struct dentry           * dentry;
	mode_t                  mode;
	struct list_head        files;
};

name:
	Name of the directory.
dentry:
	Dentry for the directory.
mode:
	Permissions of the directory.
files:
	Linked list of driver_file_entry's that are in the directory.


To create a directory, one first calls

struct driver_dir_entry *
driverfs_create_dir_entry(const char * name, mode_t mode);

which allocates and initialises a struct driver_dir_entry. Then to actually
create the directory:

int driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *);

To remove a directory:

void driverfs_remove_dir(struct driver_dir_entry * entry);


Files are encapsulated like this:

struct driver_file_entry {
	struct driver_dir_entry * parent;
	struct list_head        node;
	char                    * name;
	mode_t                  mode;
	struct dentry           * dentry;
	void                    * data;
	struct driverfs_operations      * ops;
};

struct driverfs_operations {
	ssize_t (*read) (char *, size_t, loff_t, void *);
	ssize_t (*write)(const char *, size_t, loff_t, void*);
};

node:
	Node in its parent directory's list of files.

name:
	The name of the file.

dentry:
	The dentry for the file.

data:
	Caller specific data that is passed to the callbacks when they
	are called.

ops:
	Operations for the file. Currently, this only contains read() and write()
	callbacks for the file.

To create a file, one first calls

struct driver_file_entry *
driverfs_create_entry (const char * name, mode_t mode,
			struct driverfs_operations * ops, void * data);

That allocates and initialises a struct driver_file_entry. Then, to actually
create a file, one calls

int driverfs_create_file(struct driver_file_entry * entry,
			struct driver_dir_entry * parent);


To remove a file, one calls

void driverfs_remove_file(struct driver_dir_entry *, const char * name);


The callback functionality is similar to the way procfs works. When a
user performs a read(2) or write(2) on the file, it first calls a
driverfs function. This function then checks for a non-NULL pointer in
the file->private_data field, which it assumes to be a pointer to a
struct driver_file_entry.

It then checks for the appropriate callback and calls it.


What driverfs is not:
~~~~~~~~~~~~~~~~~~~~~
It is not a replacement for either devfs or procfs.

It does not handle device nodes, like devfs is intended to do. I think
this functionality is possible, but indeed think that integration of
the device nodes and control files should be done. Whether driverfs or
devfs, or something else, is the place to do it, I don't know.

It is not intended to be a replacement for all of the procfs
functionality. I think that many of the driver files should be moved
out of /proc (and maybe a few other things as well ;).



Limitations:
~~~~~~~~~~~~
The driverfs functions assume that at most a page is being either read
or written each time.


Possible bugs:
~~~~~~~~~~~~~~
It may not deal with offsets and/or seeks very well, especially if
they cross a page boundary.

There may be locking issues when dynamically adding/removing files and
directories rapidly (like if you have a hot plug device).

There are some people that believe that filesystems which add
files/directories dynamically based on the presence of devices are
inherently flawed. Though not as technically versed in this area as
some of those people, I like to believe that they can be made to work,
with the right guidance.

