why only some sysfs attribute callbacks use attribute pointers?

Robert P. J. Day rpjday at crashcourse.ca
Thu Oct 11 06:33:39 EDT 2012


  first time poking around in the sysfs attributes code and i'm a bit
puzzled by something i found, i'm sure someone here (mulyadi? :-) will
know the answer.

  the header file <linux/device.h> declares a number of show/store
routines for various attribute types.  for instance, here's for class:

  ssize_t (*show)(struct class *class, struct class_attribute *attr,
                        char *buf);
  ssize_t (*store)(struct class *class, struct class_attribute *attr,
                        const char *buf, size_t count);

the above suggests that, since the show() and store() routines for
class attributes take both a pointer to a class struct *AND* a pointer
to an attribute itself, the same pair of routines can be used
generally for a number of distinct class attributes, as long as the
callback routine can distinguish among them.  after all, the
attributes being passed can be checked for their name field, and the
show() and store() routines can then act accordingly.

  the same thing can be said for device attributes in that same header
file:

  ssize_t (*show)(struct device *dev, struct device_attribute *attr,
                        char *buf);
  ssize_t (*store)(struct device *dev, struct device_attribute *attr,
                         const char *buf, size_t count);


once again, the show and store routines are passed an attribute
pointer so they can examine the name field of the attribute in
question and act accordingly.  but the same is *not* true for the bus
class:

  ssize_t (*show)(struct bus_type *bus, char *buf);
  ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);

note that these show and store routines *don't* incorporate an
attribute pointer in the argument list, so you can't possibly define a
pair of these routines that will properly process a number of
attributes since those routines will have no idea how to distinguish
between them, correct?

  here's an example from drivers/pci/pci.c:

===== start =====

static ssize_t pci_resource_alignment_show(struct bus_type *bus, char
*buf)
{
        return pci_get_resource_alignment_param(buf, PAGE_SIZE);
}

static ssize_t pci_resource_alignment_store(struct bus_type *bus,
                                        const char *buf, size_t count)
{
        return pci_set_resource_alignment_param(buf, count);
}

BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show,
                                        pci_resource_alignment_store);

static int __init pci_resource_alignment_sysfs_init(void)
{
        return bus_create_file(&pci_bus_type,
                                        &bus_attr_resource_alignment);
}

===== end =====

  in the code above, a single attribute file, "resource_alignment", is
created under /sys/bus/pci and, sure enough, it exists on my ubuntu
system.  but as you can see, the show() and store() routines
associated with that file are absolutely hard-coded for that attribute
only, and can't possible be used for any other attribute.

  is there a reason for this difference in design?  if you look
through <linux/device.h>, some of the attribute types (bus, driver)
have show/store routines that don't take attribute pointers, while
others (class, device) have show/store routines that *do*, allowing
them to be more general.  is this deliberate?  and why?

rday

p.s.  even when show()/store() routines take an attribute pointer and
can switch among them, for the most part, the code doesn't seem to do
that much, anyway.  here's a perfect example from block/genhd.c,
starting around line 922:

static ssize_t disk_range_show(struct device *dev,
                               struct device_attribute *attr, char *buf)
{
        struct gendisk *disk = dev_to_disk(dev);

        return sprintf(buf, "%d\n", disk->minors);
}

static ssize_t disk_ext_range_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
{
        struct gendisk *disk = dev_to_disk(dev);

        return sprintf(buf, "%d\n", disk_max_parts(disk));
}

static ssize_t disk_removable_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
{
        struct gendisk *disk = dev_to_disk(dev);

        return sprintf(buf, "%d\n",
                       (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0));
}

... etc etc ...

  note how those callback routines, given a pointer to the underlying
attribute, ignore it completely, even when they're all related to an
underlying "struct gendisk" and could have been written as a pair of
large callbacks with a "switch" statement based on the attribute name.

  anyway, you get the idea.  is there a reason for this difference?  i
may have more questions about this shortly as i read further.

rday

-- 

========================================================================
Robert P. J. Day                                 Ottawa, Ontario, CANADA
                        http://crashcourse.ca

Twitter:                                       http://twitter.com/rpjday
LinkedIn:                               http://ca.linkedin.com/in/rpjday
========================================================================




More information about the Kernelnewbies mailing list