Devfs (Device File System) FAQ Linux Devfs (Device File System) FAQRichard Gooch20-AUG-2002 Document languages: ----------------------------------------------------------------------------- NOTE: the master copy of this document is available online at: http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.htmland looks much better than the text version distributed with thekernel sources. A mirror site is available at: http://www.ras.ucalgary.ca/~rgooch/linux/docs/devfs.html There is also an optional daemon that may be used with devfs. You canfind out more about it at: http://www.atnf.csiro.au/~rgooch/linux/ A mailing list is available which you may subscribe to. Sendemailto majordomo@oss.sgi.com with the following line in thebody of the message:subscribe devfsTo unsubscribe, send the message body:unsubscribe devfsinstead. The list is archived at http://oss.sgi.com/projects/devfs/archive/. ----------------------------------------------------------------------------- Contents What is it? Why do it? Who else does it? How it works Operational issues (essential reading) Instructions for the impatientPermissions persistence across rebootsDealing with drivers without devfs supportAll the way with DevfsOther IssuesKernel Naming SchemeDevfsd Naming SchemeOld Compatibility NamesSCSI Host Probing Issues Device drivers currently ported Allocation of Device Numbers Questions and Answers Making things workAlternatives to devfsWhat I don't like about devfsHow to report bugsStrange kernel messagesCompilation problems with devfsd Other resources Translations of this document ----------------------------------------------------------------------------- What is it? Devfs is an alternative to "real" character and block special deviceson your root filesystem. Kernel device drivers can register devices byname rather than major and minor numbers. These devices will appear indevfs automatically, with whatever default ownership andprotection the driver specified. A daemon (devfsd) can be used tooverride these defaults. Devfs has been in the kernel since 2.3.46. NOTE that devfs is entirely optional. If you prefer the olddisc-based device nodes, then simply leave CONFIG_DEVFS_FS=n (thedefault). In this case, nothing will change. ALSO NOTE that if you doenable devfs, the defaults are such that full compatibility ismaintained with the old devices names. There are two aspects to devfs: one is the underlying devicenamespace, which is a namespace just like any mounted filesystem. Theother aspect is the filesystem code which provides a view of thedevice namespace. The reason I make a distinction is because devfscan be mounted many times, with each mount showing the same devicenamespace. Changes made are global to all mounted devfs filesystems.Also, because the devfs namespace exists without any devfs mounts, youcan easily mount the root filesystem by referring to an entry in thedevfs namespace. The cost of devfs is a small increase in kernel code size and memoryusage. About 7 pages of code (some of that in __init sections) and 72bytes for each entry in the namespace. A modest system has only acouple of hundred device entries, so this costs a few morepages. Compare this with the suggestion to put /dev on a <ahref="#why-faq-ramdisc">ramdisc. On a typical machine, the cost is under 0.2 percent. On a modestsystem with 64 MBytes of RAM, the cost is under 0.1 percent. Theaccusations of "bloatware" levelled at devfs are not justified. ----------------------------------------------------------------------------- Why do it? There are several problems that devfs addresses. Some of theseproblems are more serious than others (depending on your point ofview), and some can be solved without devfs. However, the totality ofthese problems really calls out for devfs. The choice is a patchwork of inefficient user space solutions, whichare complex and likely to be fragile, or to use a simple and efficientdevfs which is robust. There have been many counter-proposals to devfs, all seeking toprovide some of the benefits without actually implementing devfs. Sofar there has been an absence of code and no proposed alternative hasbeen able to provide all the features that devfs does. Further,alternative proposals require far more complexity in user-space (andstill deliver less functionality than devfs). Some people have themantra of reducing "kernel bloat", but don't consider the effects onuser-space. A good solution limits the total complexity of kernel-space anduser-space. Major&minor allocation The existing scheme requires the allocation of major and minor devicenumbers for each and every device. This means that a centralco-ordinating authority is required to issue these device numbers(unless you're developing a "private" device driver), in order topreserve uniqueness. Devfs shifts the burden to a namespace. This maynot seem like a huge benefit, but actually it is. Since driver authorswill naturally choose a device name which reflects the functionalityof the device, there is far less potential for namespace conflict.Solving this requires a kernel change. /dev management Because you currently access devices through device nodes, these mustbe created by the system administrator. For standard devices you canusually find a MAKEDEV programme which creates all these (hundreds!)of nodes. This means that changes in the kernel must be reflected bychanges in the MAKEDEV programme, or else the system administratorcreates device nodes by hand. The basic problem is that there are two separate databases ofmajor and minor numbers. One is in the kernel and one is in /dev (orin a MAKEDEV programme, if you want to look at it that way). This isduplication of information, which is not good practice.Solving this requires a kernel change. /dev growth A typical /dev has over 1200 nodes! Most of these devices simply don'texist because the hardware is not available. A huge /dev increases thetime to access devices (I'm just referring to the dentry lookup timesand the time taken to read inodes off disc: the next subsection showssome more horrors). An example of how big /dev can grow is if we consider SCSI devices: host 6 bits (say up to 64 hosts on a really big machine)channel 4 bits (say up to 16 SCSI buses per host)id 4 bitslun 3 bitspartition 6 bitsTOTAL 23 bits This requires 8 Mega (1024*1024) inodes if we want to store allpossible device nodes. Even if we scrap everything but id,partitionand assume a single host adapter with a single SCSI bus and only onelogical unit per SCSI target (id), that's still 10 bits or 1024inodes. Each VFS inode takes around 256 bytes (kernel 2.1.78), sothat's 256 kBytes of inode storage on disc (assuming real inodes takea similar amount of space as VFS inodes). This is actually not so bad,because disc is cheap these days. Embedded systems would care about256 kBytes of /dev inodes, but you could argue that embedded systemswould have hand-tuned /dev directories. I've had to do just that on myembedded systems, but I would rather just leave it to devfs. Another issue is the time taken to lookup an inode when firstreferenced. Not only does this take time in scanning through a list inmemory, but also the seek times to read the inodes off disc.This could be solved in user-space using a clever programme whichscanned the kernel logs and deleted /dev entries which are notavailable and created them when they were available. This programmewould need to be run every time a new module was loaded, which wouldslow things down a lot. There is an existing programme called scsidev which will automaticallycreate device nodes for SCSI devices. It can do this by scanning filesin /proc/scsi. Unfortunately, to extend this idea to other devicenodes would require significant modifications to existing drivers (sothey too would provide information in /proc). This is a non-trivialchange (I should know: devfs has had to do something similar). Onceyou go to this much effort, you may as well use devfs itself (whichalso provides this information). Furthermore, such a system wouldlikely be implemented in an ad-hoc fashion, as different drivers willprovide their information in different ways. Devfs is much cleaner, because it (naturally) has a uniform mechanismto provide this information: the device nodes themselves! Node to driver file_operations translation There is an important difference between the way disc-based characterand block nodes and devfs entries make the connection between an entryin /dev and the actual device driver. With the current 8 bit major and minor numbers the connection betweendisc-based c&b nodes and per-major drivers is done through afixed-length table of 128 entries. The various filesystem types setthe inode operations for c&b nodes to {chr,blk}dev_inode_operations,so when a device is opened a few quick levels of indirection bring usto the driver file_operations. For miscellaneous character devices a second step is required: thereis a scan for the driver entry with the same minor number as the filethat was opened, and the appropriate minor open method is called. Thisscanning is done *every time* you open a device node. Potentially, youmay be searching through dozens of misc. entries before you find youropen method. While not an enormous performance overhead, this doesseem pointless. Linux *must* move beyond the 8 bit major and minor barrier,somehow. If we simply increase each to 16 bits, then the indexingscheme used for major driver lookup becomes untenable, because themajor tables (one each for character and block devices) would need tobe 64 k entries long (512 kBytes on x86, 1 MByte for 64 bitsystems). So we would have to use a scheme like that used formiscellaneous character devices, which means the search time goes uplinearly with the average number of major device drivers on yoursystem. Not all "devices" are hardware, some are higher-level driverslike KGI, so you can get more "devices" without adding hardwareYou can improve this by creating an ordered (balanced:-)binary tree, in which case your search time becomes log(N).Alternatively, you can use hashing to speed up the search.But why do that search at all if you don't have to? Once again, itseems pointless. Note that devfs doesn't use the major&minor system. For devfsentries, the connection is done when you lookup the /dev entry. Whendevfs_register() is called, an internal table is appended which hasthe entry name and the file_operations. If the dentry cache doesn'thave the /dev entry already, this internal table is scanned to get thefile_operations, and an inode is created. If the dentry cache alreadyhas the entry, there is *no lookup time* (other than the dentry scanitself, but we can't avoid that anyway, and besides Linux dentriescream other OS's which don't have them:-). Furthermore, the number ofnode entries in a devfs is only the number of available deviceentries, not the number of *conceivable* entries. Even if you removeunnecessary entries in a disc-based /dev, the number of conceivableentries remains the same: you just limit yourself in order to savespace. Devfs provides a fast connection between a VFS node and the devicedriver, in a scalable way. /dev as a system administration tool Right now /dev contains a list of conceivable devices, most of which Idon't have. Devfs only shows those devices available on mysystem. This means that listing /dev is a handy way of checking whatdevices are available. Major&minor size Existing major and minor numbers are limited to 8 bits each. This isnow a limiting factor for some drivers, particularly the SCSI discdriver, which consumes a single major number. Only 16 discs aresupported, and each disc may have only 15 partitions. Maybe this isn'ta problem for you, but some of us are building huge Linux systems withdisc arrays. With devfs an arbitrary pointer can be associated witheach device entry, which can be used to give an effective 32 bitdevice identifier (i.e. that's like having a 32 bit minornumber). Since this is private to the kernel, there are no C librarycompatibility issues which you would have with increasing major andminor number sizes. See the section on "Allocation of Device Numbers"for details on maintaining compatibility with userspace. Solving this requires a kernel change. Since writing this, the kernel has been modified so that the SCSI discdriver has more major numbers allocated to it and now supports up to128 discs. Since these major numbers are non-contiguous (a result ofunplanned expansion), the implementation is a little more cumbersomethan originally. Just like the changes to IPv4 to fix impending limitations in theaddress space, people find ways around the limitations. In the longrun, however, solutions like IPv6 or devfs can't be put off forever. Read-only root filesystem Having your device nodes on the root filesystem means that you can'toperate properly with a read-only root filesystem. This is because youwant to change ownerships and protections of tty devices. Existingpractice prevents you using a CD-ROM as your root filesystem for a*real* system. Sure, you can boot off a CD-ROM, but you can't changetty ownerships, so it's only good for installing. Also, you can't use a shared NFS root filesystem for a cluster ofdiscless Linux machines (having tty ownerships changed on a common/dev is not good). Nor can you embed your root filesystem in aROM-FS. You can get around this by creating a RAMDISC at boot time, makingan ext2 filesystem in it, mounting it somewhere and copying thecontents of /dev into it, then unmounting it and mounting it over/dev. A devfs is a cleaner way of solving this. Non-Unix root filesystem Non-Unix filesystems (such as NTFS) can't be used for a rootfilesystem because they variously don't support character and blockspecial files or symbolic links. You can't have a separate disc-basedor RAMDISC-based filesystem mounted on /dev because you need devicenodes before you can mount these. Devfs can be mounted without anydevice nodes. Devlinks won't work because symlinks aren't supported.An alternative solution is to use initrd to mount a RAMDISC initialroot filesystem (which is populated with a minimal set of devicenodes), and then construct a new /dev in another RAMDISC, and finallyswitch to your non-Unix root filesystem. This requires clever bootscripts and a fragile and conceptually complex boot procedure. Devfs solves this in a robust and conceptually simple way. PTY security Current pseudo-tty (pty) devices are owned by root and read-writableby everyone. The user of a pty-pair cannot changeownership/protections without being suid-root. This could be solved with a secure user-space daemon which runs asroot and does the actual creation of pty-pairs. Such a daemon wouldrequire modification to *every* programme that wants to use this newmechanism. It also slows down creation of pty-pairs. An alternative is to create a new open_pty() syscall which does muchthe same thing as the user-space daemon. Once again, this requiresmodifications to pty-handling programmes. The devfs solution allows a device driver to "tag" certain devicefiles so that when an unopened device is opened, the ownerships arechanged to the current euid and egid of the opening process, and theprotections are changed to the default registered by the driver. Whenthe device is closed ownership is set back to root and protections areset back to read-write for everybody. No programme need be changed.The devpts filesystem provides this auto-ownership feature for Unix98ptys. It doesn't support old-style pty devices, nor does it have allthe other features of devfs. Intelligent device management Devfs implements a simple yet powerful protocol for communication witha device management daemon (devfsd) which runs in user space. It ispossible to send a message (either synchronously or asynchronously) todevfsd on any event, such as registration/unregistration of deviceentries, opening and closing devices, looking up inodes, scanningdirectories and more. This has many possibilities. Some of these arealready implemented. See: http://www.atnf.csiro.au/~rgooch/linux/ Device entry registration events can be used by devfsd to changepermissions of newly-created device nodes. This is one mechanism tocontrol device permissions. Device entry registration/unregistration events can be used to runprogrammes or scripts. This can be used to provide automatic mountingof filesystems when a new block device media is inserted into thedrive. Asynchronous device open and close events can be used to implementclever permissions management. For example, the default permissions on/dev/dsp do not allow everybody to read from the device. This issensible, as you don't want some remote user recording what you say atyour console. However, the console user is also prevented fromrecording. This behaviour is not desirable. With asynchronous deviceopen and close events, you can have devfsd run a programme or scriptwhen console devices are opened to change the ownerships for *other*device nodes (such as /dev/dsp). On closure, you can run a differentscript to restore permissions. An advantage of this scheme overmodifying the C library tty handling is that this works even if yourprogramme crashes (how many times have you seen the utmp database withlingering entries for non-existent logins?). Synchronous device open events can be used to perform intelligentdevice access protections. Before the device driver open() method iscalled, the daemon must first validate the open attempt, by running anexternal programme or script. This is far more flexible than accesscontrol lists, as access can be determined on the basis of othersystem conditions instead of just the UID and GID. Inode lookup events can be used to authenticate module autoloadrequests. Instead of using kmod directly, the event is sent todevfsd which can implement an arbitrary authentication before loadingthe module itself. Inode lookup events can also be used to construct arbitrarynamespaces, without having to resort to populating devfs with symlinksto devices that don't exist. Speculative Device Scanning Consider an application (like cdparanoia) that wants to find allCD-ROM devices on the system (SCSI, IDE and other types), whether ornot their respective modules are loaded. The application mustspeculatively open certain device nodes (such as /dev/sr0 for the SCSICD-ROMs) in order to make sure the module is loaded. This requiresthat all Linux distributions follow the standard device naming scheme(last time I looked RedHat did things differently). Devfs solves thenaming problem. The same application also wants to see which devices are actuallyavailable on the system. With the existing system it needs to read the/dev directory and speculatively open each /dev/sr* device todetermine if the device exists or not. With a large /dev this is aninefficient operation, especially if there are many /dev/sr* nodes. Asolution like scsidev could reduce the number of /dev/sr* entries (butof course that also requires all that inefficient directory scanning). With devfs, the application can open the /dev/sr directory(which triggers the module autoloading if required), and proceed toread /dev/sr. Since only the available devices will haveentries, there are no inefficencies in directory scanning or deviceopenings. ----------------------------------------------------------------------------- Who else does it? FreeBSD has a devfs implementation. Solaris and AIX each have apseudo-devfs (something akin to scsidev but for all devices, with someunspecified kernel support). BeOS, Plan9 and QNX also have it. SGI'sIRIX 6.4 and above also have a device filesystem. While we shouldn't just automatically do something because others doit, we should not ignore the work of others either. FreeBSD has a lotof competent people working on it, so their opinion should not beblithely ignored. ----------------------------------------------------------------------------- How it works Registering device entries For every entry (device node) in a devfs-based /dev a driver must calldevfs_register(). This adds the name of the device entry, thefile_operations structure pointer and a few other things to aninternal table. Device entries may be added and removed at anytime. When a device entry is registered, it automagically appears inany mounted devfs'. Inode lookup When a lookup operation on an entry is performed and if there is nodriver information for that entry devfs will attempt to calldevfsd. If still no driver information can be found then a negativedentry is yielded and the next stage operation will be called by theVFS (such as create() or mknod() inode methods). If driver informationcan be found, an inode is created (if one does not exist already) andLines 1–500 of 1959. Load more
Devfs (Device File System) FAQ Linux Devfs (Device File System) FAQ Richard Gooch 20-AUG-2002 Document languages: ----------------------------------------------------------------------------- NOTE: the master copy of this document is available online at: http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html and looks much better than the text version distributed with the kernel sources. A mirror site is available at: http://www.ras.ucalgary.ca/~rgooch/linux/docs/devfs.html There is also an optional daemon that may be used with devfs. You can find out more about it at: http://www.atnf.csiro.au/~rgooch/linux/ A mailing list is available which you may subscribe to. Send email to majordomo@oss.sgi.com with the following line in the body of the message: subscribe devfs To unsubscribe, send the message body: unsubscribe devfs instead. The list is archived at http://oss.sgi.com/projects/devfs/archive/. ----------------------------------------------------------------------------- Contents What is it? Why do it? Who else does it? How it works Operational issues (essential reading) Instructions for the impatient Permissions persistence across reboots Dealing with drivers without devfs support All the way with Devfs Other Issues Kernel Naming Scheme Devfsd Naming Scheme Old Compatibility Names SCSI Host Probing Issues Device drivers currently ported Allocation of Device Numbers Questions and Answers Making things work Alternatives to devfs What I don't like about devfs How to report bugs Strange kernel messages Compilation problems with devfsd Other resources Translations of this document ----------------------------------------------------------------------------- What is it? Devfs is an alternative to "real" character and block special devices on your root filesystem. Kernel device drivers can register devices by name rather than major and minor numbers. These devices will appear in devfs automatically, with whatever default ownership and protection the driver specified. A daemon (devfsd) can be used to override these defaults. Devfs has been in the kernel since 2.3.46. NOTE that devfs is entirely optional. If you prefer the old disc-based device nodes, then simply leave CONFIG_DEVFS_FS=n (the default). In this case, nothing will change. ALSO NOTE that if you do enable devfs, the defaults are such that full compatibility is maintained with the old devices names. There are two aspects to devfs: one is the underlying device namespace, which is a namespace just like any mounted filesystem. The other aspect is the filesystem code which provides a view of the device namespace. The reason I make a distinction is because devfs can be mounted many times, with each mount showing the same device namespace. Changes made are global to all mounted devfs filesystems. Also, because the devfs namespace exists without any devfs mounts, you can easily mount the root filesystem by referring to an entry in the devfs namespace. The cost of devfs is a small increase in kernel code size and memory usage. About 7 pages of code (some of that in __init sections) and 72 bytes for each entry in the namespace. A modest system has only a couple of hundred device entries, so this costs a few more pages. Compare this with the suggestion to put /dev on a <a href="#why-faq-ramdisc">ramdisc. On a typical machine, the cost is under 0.2 percent. On a modest system with 64 MBytes of RAM, the cost is under 0.1 percent. The accusations of "bloatware" levelled at devfs are not justified. ----------------------------------------------------------------------------- Why do it? There are several problems that devfs addresses. Some of these problems are more serious than others (depending on your point of view), and some can be solved without devfs. However, the totality of these problems really calls out for devfs. The choice is a patchwork of inefficient user space solutions, which are complex and likely to be fragile, or to use a simple and efficient devfs which is robust. There have been many counter-proposals to devfs, all seeking to provide some of the benefits without actually implementing devfs. So far there has been an absence of code and no proposed alternative has been able to provide all the features that devfs does. Further, alternative proposals require far more complexity in user-space (and still deliver less functionality than devfs). Some people have the mantra of reducing "kernel bloat", but don't consider the effects on user-space. A good solution limits the total complexity of kernel-space and user-space. Major&minor allocation The existing scheme requires the allocation of major and minor device numbers for each and every device. This means that a central co-ordinating authority is required to issue these device numbers (unless you're developing a "private" device driver), in order to preserve uniqueness. Devfs shifts the burden to a namespace. This may not seem like a huge benefit, but actually it is. Since driver authors will naturally choose a device name which reflects the functionality of the device, there is far less potential for namespace conflict. Solving this requires a kernel change. /dev management Because you currently access devices through device nodes, these must be created by the system administrator. For standard devices you can usually find a MAKEDEV programme which creates all these (hundreds!) of nodes. This means that changes in the kernel must be reflected by changes in the MAKEDEV programme, or else the system administrator creates device nodes by hand. The basic problem is that there are two separate databases of major and minor numbers. One is in the kernel and one is in /dev (or in a MAKEDEV programme, if you want to look at it that way). This is duplication of information, which is not good practice. Solving this requires a kernel change. /dev growth A typical /dev has over 1200 nodes! Most of these devices simply don't exist because the hardware is not available. A huge /dev increases the time to access devices (I'm just referring to the dentry lookup times and the time taken to read inodes off disc: the next subsection shows some more horrors). An example of how big /dev can grow is if we consider SCSI devices: host 6 bits (say up to 64 hosts on a really big machine) channel 4 bits (say up to 16 SCSI buses per host) id 4 bits lun 3 bits partition 6 bits TOTAL 23 bits This requires 8 Mega (1024*1024) inodes if we want to store all possible device nodes. Even if we scrap everything but id,partition and assume a single host adapter with a single SCSI bus and only one logical unit per SCSI target (id), that's still 10 bits or 1024 inodes. Each VFS inode takes around 256 bytes (kernel 2.1.78), so that's 256 kBytes of inode storage on disc (assuming real inodes take a similar amount of space as VFS inodes). This is actually not so bad, because disc is cheap these days. Embedded systems would care about 256 kBytes of /dev inodes, but you could argue that embedded systems would have hand-tuned /dev directories. I've had to do just that on my embedded systems, but I would rather just leave it to devfs. Another issue is the time taken to lookup an inode when first referenced. Not only does this take time in scanning through a list in memory, but also the seek times to read the inodes off disc. This could be solved in user-space using a clever programme which scanned the kernel logs and deleted /dev entries which are not available and created them when they were available. This programme would need to be run every time a new module was loaded, which would slow things down a lot. There is an existing programme called scsidev which will automatically create device nodes for SCSI devices. It can do this by scanning files in /proc/scsi. Unfortunately, to extend this idea to other device nodes would require significant modifications to existing drivers (so they too would provide information in /proc). This is a non-trivial change (I should know: devfs has had to do something similar). Once you go to this much effort, you may as well use devfs itself (which also provides this information). Furthermore, such a system would likely be implemented in an ad-hoc fashion, as different drivers will provide their information in different ways. Devfs is much cleaner, because it (naturally) has a uniform mechanism to provide this information: the device nodes themselves! Node to driver file_operations translation There is an important difference between the way disc-based character and block nodes and devfs entries make the connection between an entry in /dev and the actual device driver. With the current 8 bit major and minor numbers the connection between disc-based c&b nodes and per-major drivers is done through a fixed-length table of 128 entries. The various filesystem types set the inode operations for c&b nodes to {chr,blk}dev_inode_operations, so when a device is opened a few quick levels of indirection bring us to the driver file_operations. For miscellaneous character devices a second step is required: there is a scan for the driver entry with the same minor number as the file that was opened, and the appropriate minor open method is called. This scanning is done *every time* you open a device node. Potentially, you may be searching through dozens of misc. entries before you find your open method. While not an enormous performance overhead, this does seem pointless. Linux *must* move beyond the 8 bit major and minor barrier, somehow. If we simply increase each to 16 bits, then the indexing scheme used for major driver lookup becomes untenable, because the major tables (one each for character and block devices) would need to be 64 k entries long (512 kBytes on x86, 1 MByte for 64 bit systems). So we would have to use a scheme like that used for miscellaneous character devices, which means the search time goes up linearly with the average number of major device drivers on your system. Not all "devices" are hardware, some are higher-level drivers like KGI, so you can get more "devices" without adding hardware You can improve this by creating an ordered (balanced:-) binary tree, in which case your search time becomes log(N). Alternatively, you can use hashing to speed up the search. But why do that search at all if you don't have to? Once again, it seems pointless. Note that devfs doesn't use the major&minor system. For devfs entries, the connection is done when you lookup the /dev entry. When devfs_register() is called, an internal table is appended which has the entry name and the file_operations. If the dentry cache doesn't have the /dev entry already, this internal table is scanned to get the file_operations, and an inode is created. If the dentry cache already has the entry, there is *no lookup time* (other than the dentry scan itself, but we can't avoid that anyway, and besides Linux dentries cream other OS's which don't have them:-). Furthermore, the number of node entries in a devfs is only the number of available device entries, not the number of *conceivable* entries. Even if you remove unnecessary entries in a disc-based /dev, the number of conceivable entries remains the same: you just limit yourself in order to save space. Devfs provides a fast connection between a VFS node and the device driver, in a scalable way. /dev as a system administration tool Right now /dev contains a list of conceivable devices, most of which I don't have. Devfs only shows those devices available on my system. This means that listing /dev is a handy way of checking what devices are available. Major&minor size Existing major and minor numbers are limited to 8 bits each. This is now a limiting factor for some drivers, particularly the SCSI disc driver, which consumes a single major number. Only 16 discs are supported, and each disc may have only 15 partitions. Maybe this isn't a problem for you, but some of us are building huge Linux systems with disc arrays. With devfs an arbitrary pointer can be associated with each device entry, which can be used to give an effective 32 bit device identifier (i.e. that's like having a 32 bit minor number). Since this is private to the kernel, there are no C library compatibility issues which you would have with increasing major and minor number sizes. See the section on "Allocation of Device Numbers" for details on maintaining compatibility with userspace. Solving this requires a kernel change. Since writing this, the kernel has been modified so that the SCSI disc driver has more major numbers allocated to it and now supports up to 128 discs. Since these major numbers are non-contiguous (a result of unplanned expansion), the implementation is a little more cumbersome than originally. Just like the changes to IPv4 to fix impending limitations in the address space, people find ways around the limitations. In the long run, however, solutions like IPv6 or devfs can't be put off forever. Read-only root filesystem Having your device nodes on the root filesystem means that you can't operate properly with a read-only root filesystem. This is because you want to change ownerships and protections of tty devices. Existing practice prevents you using a CD-ROM as your root filesystem for a *real* system. Sure, you can boot off a CD-ROM, but you can't change tty ownerships, so it's only good for installing. Also, you can't use a shared NFS root filesystem for a cluster of discless Linux machines (having tty ownerships changed on a common /dev is not good). Nor can you embed your root filesystem in a ROM-FS. You can get around this by creating a RAMDISC at boot time, making an ext2 filesystem in it, mounting it somewhere and copying the contents of /dev into it, then unmounting it and mounting it over /dev. A devfs is a cleaner way of solving this. Non-Unix root filesystem Non-Unix filesystems (such as NTFS) can't be used for a root filesystem because they variously don't support character and block special files or symbolic links. You can't have a separate disc-based or RAMDISC-based filesystem mounted on /dev because you need device nodes before you can mount these. Devfs can be mounted without any device nodes. Devlinks won't work because symlinks aren't supported. An alternative solution is to use initrd to mount a RAMDISC initial root filesystem (which is populated with a minimal set of device nodes), and then construct a new /dev in another RAMDISC, and finally switch to your non-Unix root filesystem. This requires clever boot scripts and a fragile and conceptually complex boot procedure. Devfs solves this in a robust and conceptually simple way. PTY security Current pseudo-tty (pty) devices are owned by root and read-writable by everyone. The user of a pty-pair cannot change ownership/protections without being suid-root. This could be solved with a secure user-space daemon which runs as root and does the actual creation of pty-pairs. Such a daemon would require modification to *every* programme that wants to use this new mechanism. It also slows down creation of pty-pairs. An alternative is to create a new open_pty() syscall which does much the same thing as the user-space daemon. Once again, this requires modifications to pty-handling programmes. The devfs solution allows a device driver to "tag" certain device files so that when an unopened device is opened, the ownerships are changed to the current euid and egid of the opening process, and the protections are changed to the default registered by the driver. When the device is closed ownership is set back to root and protections are set back to read-write for everybody. No programme need be changed. The devpts filesystem provides this auto-ownership feature for Unix98 ptys. It doesn't support old-style pty devices, nor does it have all the other features of devfs. Intelligent device management Devfs implements a simple yet powerful protocol for communication with a device management daemon (devfsd) which runs in user space. It is possible to send a message (either synchronously or asynchronously) to devfsd on any event, such as registration/unregistration of device entries, opening and closing devices, looking up inodes, scanning directories and more. This has many possibilities. Some of these are already implemented. See: http://www.atnf.csiro.au/~rgooch/linux/ Device entry registration events can be used by devfsd to change permissions of newly-created device nodes. This is one mechanism to control device permissions. Device entry registration/unregistration events can be used to run programmes or scripts. This can be used to provide automatic mounting of filesystems when a new block device media is inserted into the drive. Asynchronous device open and close events can be used to implement clever permissions management. For example, the default permissions on /dev/dsp do not allow everybody to read from the device. This is sensible, as you don't want some remote user recording what you say at your console. However, the console user is also prevented from recording. This behaviour is not desirable. With asynchronous device open and close events, you can have devfsd run a programme or script when console devices are opened to change the ownerships for *other* device nodes (such as /dev/dsp). On closure, you can run a different script to restore permissions. An advantage of this scheme over modifying the C library tty handling is that this works even if your programme crashes (how many times have you seen the utmp database with lingering entries for non-existent logins?). Synchronous device open events can be used to perform intelligent device access protections. Before the device driver open() method is called, the daemon must first validate the open attempt, by running an external programme or script. This is far more flexible than access control lists, as access can be determined on the basis of other system conditions instead of just the UID and GID. Inode lookup events can be used to authenticate module autoload requests. Instead of using kmod directly, the event is sent to devfsd which can implement an arbitrary authentication before loading the module itself. Inode lookup events can also be used to construct arbitrary namespaces, without having to resort to populating devfs with symlinks to devices that don't exist. Speculative Device Scanning Consider an application (like cdparanoia) that wants to find all CD-ROM devices on the system (SCSI, IDE and other types), whether or not their respective modules are loaded. The application must speculatively open certain device nodes (such as /dev/sr0 for the SCSI CD-ROMs) in order to make sure the module is loaded. This requires that all Linux distributions follow the standard device naming scheme (last time I looked RedHat did things differently). Devfs solves the naming problem. The same application also wants to see which devices are actually available on the system. With the existing system it needs to read the /dev directory and speculatively open each /dev/sr* device to determine if the device exists or not. With a large /dev this is an inefficient operation, especially if there are many /dev/sr* nodes. A solution like scsidev could reduce the number of /dev/sr* entries (but of course that also requires all that inefficient directory scanning). With devfs, the application can open the /dev/sr directory (which triggers the module autoloading if required), and proceed to read /dev/sr. Since only the available devices will have entries, there are no inefficencies in directory scanning or device openings. ----------------------------------------------------------------------------- Who else does it? FreeBSD has a devfs implementation. Solaris and AIX each have a pseudo-devfs (something akin to scsidev but for all devices, with some unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's IRIX 6.4 and above also have a device filesystem. While we shouldn't just automatically do something because others do it, we should not ignore the work of others either. FreeBSD has a lot of competent people working on it, so their opinion should not be blithely ignored. ----------------------------------------------------------------------------- How it works Registering device entries For every entry (device node) in a devfs-based /dev a driver must call devfs_register(). This adds the name of the device entry, the file_operations structure pointer and a few other things to an internal table. Device entries may be added and removed at any time. When a device entry is registered, it automagically appears in any mounted devfs'. Inode lookup When a lookup operation on an entry is performed and if there is no driver information for that entry devfs will attempt to call devfsd. If still no driver information can be found then a negative dentry is yielded and the next stage operation will be called by the VFS (such as create() or mknod() inode methods). If driver information can be found, an inode is created (if one does not exist already) and