lkml.org 
[lkml]   [1998]   [Jan]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: disk naming proposal & devfs
Larry McVoy writes:
> [...]
> : OK, well, I think this is not a problem for devfs. Once you have your
> : fs_mountpoint() you can simply call devfs_register(). So, submit a
> : patch and wait for it to be accepted (or shot down:-).
>
> OK, perhaps I misunderstood the point of devfs. Can you please tell me
> (perhaps again) what is the problem that devfs is solving?

It's solving not one but many problems. Perhaps none are fatal in
themselves, but in totality the old scheme is inadequate, IMHO. I've
attached the README which tells you why.

Regards,

Richard....
===============================================================================
Device File System (devfs) Overview

Richard Gooch <rgooch@atnf.csiro.au>

12-JAN-1998


Conventions used in this document <section>
=================================

Each section in this document will have the string "<section>" at the
right-hand side of the section title. Each subsection will have
"<subsection>" at the right-hand side. These strings are meant to make
it easier to search through the document.


What is it? <section>
===========

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
the devfs automatically, with whatever default ownership and
protection the driver specified.


Why do it? <section>
==========

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.

Major&minor allocation <subsection>
----------------------
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 <subsection>
---------------
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).
Solving this requires a kernel change.

/dev growth <subsection>
-----------
I maintain a subset of the common /dev nodes, and I have nearly 600!
Others have twice this number. 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 section 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. Devfs is much cleaner.

Node to driver file_operations translation <subsection>
------------------------------------------
There is an important difference between the way disc-based c&b nodes
and devfs 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.

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.

Note that the devfs doesn't use the major&minor system. For devfs
entries, the connection is done when you lookup the /dev entry. When
dev_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'es 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.
Devfs provides a fast connection between a VFS node and the device
driver, in a scalable way.

/dev as a system administration tool <subsection>
------------------------------------
Right now /dev contains a list of conceivable devices, most of which I
don't have. A devfs would only show those devices available on my
system. This means that listing /dev would be a handy way of checking
what devices were available.

Major&minor size <subsection>
----------------
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.
Solving this requires a kernel change.

Readonly root filesystem <subsection>
------------------------
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 <subsection>
------------------------
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.
Solving this requires devfs.

PTY security <subsection>
------------
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 would allow 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.


How it works <section>
============

Registering device entries <subsection>
--------------------------
For every entry (device node) in a devfs-based /dev a driver must call
dev_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 <subsection>
------------
When a lookup operation on an entry is performed and if there is no
driver information for that entry devfs will attempt to call
kerneld. 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
all is well.

Manually creating device nodes <subsection>
------------------------------
The mknod() method allows you to create an ordinary named pipe in the
devfs, or you can create a character or block special inode if one
does not already exist. You may wish to create a character or block
special inode so that you can set permissions and ownership. Later, if
a device driver registers an entry with the same name, the
permissions, ownership and times are retained. This is how you can set
the protections on a device even before the driver is loaded. Once you
create an inode it appears in the directory listing.

Unregistering device entries <subsection>
----------------------------
A device driver calls dev_unregister() to unregister an entry. This
does not remove the inode. Once an inode is created it remains until
the devfs is unmounted.

Chroot() gaols <subsection>
--------------
The semantics of inode creation are different when the devfs is
mounted with the "explicit" option. Now, when a device entry is
registered, it will not appear until you use mknod() to create the
device. It doesn't matter if you mknod() before or after the device is
registered with dev_register(). The purpose of this behaviour is to
support chroot(2) gaols, where you want to mount a minimal devfs
inside the gaol. Only the devices you specifically want to be
available (through your mknod() setup) will be accessible.


Persistence of ownership/permissions across reboots <section>
===================================================

If you don't use mknod(2) to create a device file, nor use chmod(2) or
chown(2) to change the ownerships/permissions, the inode ctime will
remain at 0 (the epoch, 1-JAN-1970). Anything with a ctime later than
this has had it's ownership/permissions changed. Hence, a simple
script or programme may be used to tar up all changed inodes, prior to
shutdown.

Upon bootup, simply untar the previously created tarfile, and all your
ownerships/permissions will be retained. For the paranoid, you can
save your permissions periodically using a cron job.

I've provided a script called "rc.devfs" in this directory which you
can use to save and restore permissions.


Installation during the transition phase <section>
========================================

Currently, not all device drivers in the kernel have been modified to
use devfs. To allow booting of kernels with and without devfs support,
you will want to copy the contents of /dev to /devfs. Then, remove
entries in /dev which are now available in devfs and make them
symbolic links to the entries in /devfs.
Finally, edit your /etc/fstab or boot scripts so that devfs is mounted
over /devfs on bootup. If devfs is supported, accessing devices
supported by devfs will follow the symlinks to devfs. If devfs is not
supported, accessing those same devices will follow the symlinks to
/devfs which contains only old-style device nodes.
Devices not supported by devfs will be found directly on /dev.
Simple! You can also follow this principle for chroot gaols.

I've provided a script called "mk-sdlinks" in this directory which you
can use to create symlinks in /dev and /devfs for SCSI discs.


Device drivers currently ported <section>
===============================

- All miscellaneous character devices support devfs (this is done
transparently through misc_register()).

- SCSI discs and generic hard discs
Note that CONFIG_DEVFS_ONLY is ignored, otherwise you couldn't boot.
This is because the current root-mounting code only supports a
major:minor format

\
 
 \ /
  Last update: 2005-03-22 13:41    [W:0.059 / U:0.288 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site