[systemd-devel] libudev: subdirectories in sysfs (what does "available" mean?)

Anne Mulhern amulhern at redhat.com
Wed Nov 25 09:32:27 PST 2015





----- Original Message -----
> From: "Greg KH" <gregkh at linuxfoundation.org>
> To: "Anne Mulhern" <amulhern at redhat.com>
> Cc: "David Herrmann" <dh.herrmann at gmail.com>, "systemd" <systemd-devel at lists.freedesktop.org>
> Sent: Tuesday, November 24, 2015 3:15:21 PM
> Subject: Re: [systemd-devel] libudev: subdirectories in sysfs (what does "available" mean?)
> 
> On Tue, Nov 24, 2015 at 12:37:46PM -0500, Anne Mulhern wrote:
> > 
> > ----- Original Message -----
> > > From: "Greg KH" <gregkh at linuxfoundation.org>
> > > To: "Anne Mulhern" <amulhern at redhat.com>
> > > Cc: "David Herrmann" <dh.herrmann at gmail.com>, "systemd"
> > > <systemd-devel at lists.freedesktop.org>
> > > Sent: Tuesday, November 24, 2015 11:42:21 AM
> > > Subject: Re: [systemd-devel] libudev: subdirectories in sysfs (what does
> > > "available" mean?)
> > > 
> > > On Tue, Nov 24, 2015 at 10:37:08AM -0500, Anne Mulhern wrote:
> > > > 
> > > > 
> > > > 
> > > > 
> > > > ----- Original Message -----
> > > > > From: "David Herrmann" <dh.herrmann at gmail.com>
> > > > > To: "Anne Mulhern" <amulhern at redhat.com>
> > > > > Cc: "systemd" <systemd-devel at lists.freedesktop.org>
> > > > > Sent: Tuesday, November 24, 2015 10:15:05 AM
> > > > > Subject: Re: [systemd-devel] libudev: subdirectories in sysfs (what
> > > > > does
> > > > > "available" mean?)
> > > > > 
> > > > > Hi
> > > > > 
> > > > > On Tue, Nov 24, 2015 at 3:54 PM, Anne Mulhern <amulhern at redhat.com>
> > > > > wrote:
> > > > > >> From: "David Herrmann" <dh.herrmann at gmail.com>
> > > > > >> On Tue, Nov 17, 2015 at 11:57 PM, Anne Mulhern
> > > > > >> <amulhern at redhat.com>
> > > > > >> wrote:
> > > > > >> >> From: "David Herrmann" <dh.herrmann at gmail.com>
> > > > > >> >> On Mon, Nov 16, 2015 at 5:35 PM, Anne Mulhern
> > > > > >> >> <amulhern at redhat.com>
> > > > > >> >> wrote:
> > > > > >> >> > libudev has some cooperating procedures that return the keys
> > > > > >> >> > for
> > > > > >> >> > a
> > > > > >> >> > bunch
> > > > > >> >> > of
> > > > > >> >> > sysfs attributes for a given device.
> > > > > >> >> >
> > > > > >> >> > These attributes all correspond to files that are stored in
> > > > > >> >> > the
> > > > > >> >> > sysfs
> > > > > >> >> > device directory.
> > > > > >> >> >
> > > > > >> >> > In the same directory there are sometimes subdirectories,
> > > > > >> >> > that
> > > > > >> >> > themselves
> > > > > >> >> > contain files
> > > > > >> >> > with information about their corresponding attribute. The dm
> > > > > >> >> > directory
> > > > > >> >> > is
> > > > > >> >> > one obvious
> > > > > >> >> > example.
> > > > > >> >> >
> > > > > >> >> > Are their any plans for libudev to add an ability to get the
> > > > > >> >> > values
> > > > > >> >> > from
> > > > > >> >> > these subdirectories
> > > > > >> >> > as some kind of attributes?
> > > > > >> >> >
> > > > > >> >> > If no, why?
> > > > > >> >>
> > > > > >> >> sd_device_get_sysattr_value(device, "foo/bar/baz", &value);
> > > > > >> >>
> > > > > >> >> This should work fine (or its udev_device_* equivalent).
> > > > > >> >>
> > > > > >> >> Btw., I recommend just using readdir(), open(), read(), and
> > > > > >> >> write().
> > > > > >> >> sysfs is a filesystem, no reason to wrap all those commands.
> > > > > >> >
> > > > > >> > Thanks, I'm asking this more as the pyudev maintainer than as
> > > > > >> > someone
> > > > > >> > who actually wants these values.
> > > > > >> >
> > > > > >> > The funny thing is, I recently found out that the list obtained
> > > > > >> > by
> > > > > >> > udev_device_get_sysattr_list_entry () and friends contains so
> > > > > >> > called "available" keys, but when those get passed to
> > > > > >> > udev_device_get_sysattr_value () the result might be NULL.
> > > > > >> > That makes sense in the sense that they might represent files
> > > > > >> > that are unreadable.
> > > > > >> >
> > > > > >> > Now I find out that I can make up keys not in the results of
> > > > > >> > udev_device_get_sysattr_list_entry () and pass those to
> > > > > >> > udev_device_get_sysattr_value() and get a non-null result.
> > > > > >> >
> > > > > >> > So, what does "available" mean? Do these sysattr_list_entry()
> > > > > >> > methods give any useful information?
> > > > > >>
> > > > > >> "available" probably means attributes which are direct descendants
> > > > > >> of
> > > > > >> the device. That is, sysattr_list_entry() only lists such direct
> > > > > >> descendants, while sysattr_value() allows you to query anything
> > > > > >> (you
> > > > > >> probably can even pass "foo/../../bar/baz").
> > > > > >>
> > > > > >> Thanks
> > > > > >> David
> > > > > >>
> > > > > >
> > > > > > I think it's yet more complicated than that. For example,
> > > > > > 'dm' (for device mapper) is not in the list of available
> > > > > > attributes, but 'dm/name' is certainly an attribute that
> > > > > > can be read by sysattr_value().
> > > > > 
> > > > > 'dm' is not an attribute, so it will never be listed as available
> > > > > attribute. Directories are never treated as attributes.
> > > > > 
> > > > > Thanks
> > > > > David
> > > > > 
> > > > 
> > > > But "bdi" is listed as an attribute, and is a directory.
> > > 
> > > Can you provide a "full" path here that you are looking at (or the
> > > output of 'tree' or 'find' on the device), so that I can try to figure
> > > this out?
> > > 
> > > Odds are, dm is doing something "odd"...
> > > 
> > > thanks,
> > > 
> > > greg k-h
> > > 
> > 
> > It's a bit bare, let me know if you'ld like me to add a few options.
> > 
> > [mulhern-journal at megadeth pyudev]$ find /sys/devices/virtual/block/dm-32
> > /sys/devices/virtual/block/dm-32
> > /sys/devices/virtual/block/dm-32/dm
> > /sys/devices/virtual/block/dm-32/dm/name
> > /sys/devices/virtual/block/dm-32/dm/uuid
> > /sys/devices/virtual/block/dm-32/dm/rq_based_seq_io_merge_deadline
> > /sys/devices/virtual/block/dm-32/dm/use_blk_mq
> > /sys/devices/virtual/block/dm-32/dm/suspended
> 
> The issue here is that the dm core is not using a 'struct device' so
> this isn't a "real" attribute hanging off of the dm-32 block device, but
> rather an "unknown" kobject that userspace knows nothing at all about.
> I thought I had warned the dm developers that this would happen, but it
> looks like no one ever changed the code ;(
> 
> > /sys/devices/virtual/block/dm-32/ro
> > /sys/devices/virtual/block/dm-32/bdi
> 
> That's not a subdir, but an attribute of the dm-32 block device, so yes,
> udev will see it just fine.
> 
> So this is a kernel issue, not a libudev issue, please go pester the dm
> developers to resolve this if you wish to be able to see the attributes
> "properly".  But odds are, this isn't going to be able to be changed due
> to the custom dm tools that are probably expecting this type of
> structure.
> 
> Which goes back to the question, "why do you want to see dm attributes
> in a program?"  Shouldn't the dm tools provide you all of the
> information you need that is exported in these sysfs files?
> 
> thanks,
> 
> greg k-h
> 

Thanks!

I had been quite confident that the issue would be something as complex as
you have described, but it turns out that it is vastly simpler:

libudev just reads the contents of the directory corresponding to the device.
The keys are the names of all files in the directory that are plain files or links.

When libudev looks up values it interprets the "key" as a path relative to the sysfs
directory. If that path is a link, then for the special names in
{'driver', 'subsystem', 'module'} it returns the value of the basename of the path
that is the target of the link. For all other links it returns NULL. For directories
it returns NULL. For regular files, it reads the contents of the file.

This explains why 'dm' is not an 'available' attribute, why 'bdi' is, why the value of
'bdi' is always NULL, and why subsystem is an "available" attribute, with, generally,
a non-NULL value.

My main purpose in pursuing this question has nothing to do with device mapper,
it is to define the classes of pyudev, which is essentially a Python wrapper for libudev,
correctly. The version of pyudev that I inherited from the previous maintainer
implemented attributes as a total mapping from the set of keys returned by libudev
to a set of values, raising an exception if it got a NULL value.
This meant that it could raise an exception for an 'available' key, clearly, which
caused some unfortunate bugs. So, I reimplemented it as a partial mapping from the
set of keys libudev returns to some values or, as is the same a total mapping from
the set of keys libudev returns to any value, including NUll. It only raises an error if the
value returned is NULL _and_ the key is not among libudev's set of keys.
But it turns out that this implementation does not realize the mapping that I thought I had,
because it will return non-NULL values for many items that are not among its keys.
So, the domain is (surprisingly to me), a superset of the 'available' keys.

Given this new info, my new plan is implement this class as a total mapping from the set of all strings
to any value, including NULL. I expect I'll provide some interface to the list of 
available keys that libudev returns, with the remark that the intersection of these
keys with the keys for which lookup will return a non-NULL value is probably a
significant fraction of the total number of keys.

That seems the only sensible thing.

- mulhern


More information about the systemd-devel mailing list