Calling things by the same name

In response to my blog post “Whatever you do, don’t fix the kernel!“, David Zeuthen (prominent plumber, the maintainer of HAL and author of DeviceKit) wrote:

Scott, here’s why you’re wrong. It’s very simple and comes down to two points

- you obviously agree we can’t break huge amounts of userspace by changing DEVPATH

- having two names emitted from the kernel (_just_ because lots of user space is
broken) is just wrong and confusing
=> much better to fix up things in user space

Besides, what’s in a freaking name _anyway_? Apps should be using stable symlinks or, gosh, a device enumeration framework like HAL or the upcoming DeviceKit.

He makes, I think, an interesting point.

Why do we have two names for devices?

The kernel maintains its own namespace for devices which is based on its tree of internal objects and exported via the sysfs virtual filesystem.  My mouse’s object path is /devices/pci0000:00/0000:00:02.0/usb2/2-4/2-4:1.0/input/input2/mouse1 (convention is to omit the /sys prefix), and a class device link also exists as /class/input/mouse1 for easy access.

Properties of the device object are exported into user space via the sysfs filesystem, at that path under its mount point, and announcements of new objects, and significant changes to or removal of existing objects are made through the uevent system.  One of those properties is details about the device node that needs to be created; the dev file contains the major and minor number, and these are also present in the MAJOR and MINOR keys of the uevent.

The udev daemon listens out for these uevents and creates device nodes under the /dev path for userspace to use. These device nodes have a naming scheme that is mostly flat, with some sub-directories used for grouping. It records both the kernel object name and device path in its database so that lookups can be performed on device removal, and queries by applications using DeviceKit.

It also passes on the uevent to HAL, which stores the mapping in its own database and performs its own actions.

Applications can then use DeviceKit or HAL to enumerate devices by type, or walk the tree of devices, and lookup the actual device node path from that. They may also use them to lookup the object information for a given device node path.

That’s quite a lot of work going on behind the scenes already to map between two different names for a single device, all my proposal tried to do was reduce a little bit of the user-space side of that work by harmonising the names.

But maybe David has a point, the real problem is that we have two names in the first place!

Obviously the /dev paths are necessary for the vast number of userspace applications that still require them. But why do applications that use DeviceKit or HAL need them?

If the kernel placed a device node inside the sysfs filesystem, we wouldn’t need to do any path lookup, we’d just append the fixed name of the node to the object name.

udev would only need to make symlinks to those devices in /dev for legacy applications.

8 Comments

  1. oliver says:

    Hm, so what’s the advantage of your idea? Udev will still be running, there will still be two names, and also there will be two device files then, no?

  2. regala says:

    And it would just mean put “devfs feature set” into sysfs, wouldn’t it ? I think kernel hackers already redeemed themselves from using devfs, and they stated quite strongly devfs feature set in kernel space (actually creating device nodes in kernel space for example) is racy, messy and hacky.

  3. Rui says:

    @oliver
    AFAIU no, there wouldn’t be 2 device files since the ones in /dev are *symlinks* created by udev for the benefit of legacy apps.

  4. Havoc says:

    As I put it on http://ometer.com/hardware.html 5 years ago,

    2. Creating and maintaining /dev files – As long as this is suitably buried beneath the hardware abstraction library, it’s fairly irrelevant to desktop application developers how it works. Anything that works is great.

  5. James says:

    Oliver: one device file, and a symlink to a device file. It seems a lot like the way Solaris devices work, although device names are a lot more persistent under Solaris. Don’t make /dev/null a symlink to /devices/pseudo/mm@0:null though.

  6. Zack says:

    Doesn’t this bring back the permissions problems that were (AFAIR) one of the biggest nails in devfs’ coffin? The kernel doesn’t (and can’t) know the correct permissions to apply to a new device node, and allowing them to exist for any time with the wrong permissions is a security hole?

  7. davidz says:

    A couple of points

    – what apps really really *want* are stable device names,
    like /dev/disk/by-label/David-Zeuthens-iPod. They want
    to e.g. save this name in their config files etc. Or you
    want stable names in /etc/fstab or whatever.

    – stable names are somewhat expensive to compute (probing
    an fs for the fstype and fslabel; sending commands to a
    serial device to figure out what kind of modem it is etc.)
    and rely on both per-os, per-site and and per-machine policy.
    Also, user space driver frameworks wants to participate here,
    for example if I’m libgphoto2 or libmtp I want to somehow
    create /dev/mtp/Sansa_e200 -> /dev/bus/usb/002/003

    Hence why it’s good to put it in user space like we do now.

    – Permissions. Figuring out the permission of a device node
    may require pretty sophisticated user space components (like
    PolicyKit) and you really want to ensure the permissions are
    set before the device is announced to user space.

    – The raw device file name (e.g. /dev/sda) are simply not
    interesting; in fact it’s a bug that so many people store
    it in config files etc. And that’s all you’d get from having device
    nodes in sysfs.

    While devfs-ish schemes can be cute and all, there’s just no
    reason to do it in kernel space. And, FWIW, remember the last
    time someone tried this in Linux? It was pretty much FAIL FAIL
    FAIL all over the map.

    [my personal opinion is that a minimal devfs would probably
    work and even make things a bit simpler. But you'd need
    stable names even in the initramfs anyway.]

    – also, sysfs expresses the physical by-connection hierarchy,
    it’s most often don’t what you want

    – note that some devices don’t have file files; apps poke
    them via sysfs files already so at least parts of what
    you’re proposing is working like this (e.g. PCI devices,
    I think libpciaccess mmaps files from sysfs)

    – also, for some devices you may need to send commands / firmware
    to them (for initialization) before you announce the device to
    the rest of the OS. Some usb devices (I think ezusb but maybe
    I got the name wrong) actually requires this; initially such
    devices pop up as a vendor-specific usb devices; then you load
    firmware onto them and then the device reboots (e.g. the usb
    device disappears from the host’s POV) and then come back as a
    different usb device. So e.g. you need some way of expressing
    this and with udev it works just fine.

    I hope this clarifies why udev is very useful as it does all this
    today; I’m not exactly sure what part of the current udev you’re
    unhappy with and how you propose to solve all the problems above
    by switching to a pure devfs (as you are suggesting) solution?

  8. Alexander E. Patrakov says:

    The “device in sysfs” thingy has been already considered before and rejected on the following basis. What should be the permissions and ownership of the device node?

    I.e., udev combines major+minor+name information from the kernel with the permissions policy (i.e., the thing that should not be in the kernel) expressed in its rules. In yet other words, the kernel doesn’t have enough information to create a device node in sysfs.

Leave a Reply