Let us turn our attention to the data structures that represent attributes and the mechanisms used to declare new attributes:

Data Structures

Attributes are defined by the following data structure:


struct attribute {

const char * name;

struct module * owner;

mode_t mode;

name provides a name for the attribute that is used as a filename in sysfs (thus attributes that belong to the same object need to have unique names), while mode specifies the access mode. owner points to the module instance to which the owner of the attribute belongs.

It is also possible to define a group of attributes with the aid of the following data structure: <sysfs.h>

struct attribute_group {

const char * name;

struct attribute ** attrs;

name is a name for the group, and attrs points to an array of attribute instances terminated by a NULL entry.

Note that these data structures only provide a means to represent attributes, but do not specify how to read or modify them. This is covered in Section 10.3.4. The separation of representation and access method was chosen because all attributes belonging to a certain entity (e.g., a driver, a device class, etc.) are modified in a similar way, so it makes sense to transfer this group property to the export/import mechanism. Note, though, that it is customary that the show and store operations of the subsystem rely on attribute-specific show and store methods that are internally connected with the attribute and that differ on a per-attribute basis. The implementation details are left to the respective subsystem; sysfs is unconcerned about this.

For a read/write attribute, two methods denoted as show and store need to be available; the kernel provides the following data structure to keep them together:

struct sysfs_ops {

ssize_t (*show)(struct kobject *, struct attribute *,char *);

ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);

It is the responsibility of the code that declares a new attribute type to provide a suitable set of show and store operations.

The situation is different for binary attributes: Here, the methods used to read and modify the data are usually different for each attribute. This is reflected in the data structure, where methods for reading, writing, and memory mapping are specified explicitly:

struct bin_attribute {

struct attribute attr; size_t size; void *private;

ssize_t (*read)(struct kobject *, struct bin_attribute *, char *, loff_t, size_t); ssize_t (*write)(struct kobject *, struct bin_attribute *, char *, loff_t, size_t); int (*mmap)(struct kobject *, struct bin_attribute *attr, struct vm_area_struct *vma);

size denotes the size of the binary data associated with the attribute, and private is (usually) used to point to the place where the data are actually stored.

Declaring New Attributes

Many possibilities for declaring subsystem-specific attributes are spread around the kernel, but since they all share a basic structure with regard to their implementation, it is sufficient to consider one implementation as an example for the underlying mechanism. Consider, for instance, how the generic hard disk code defines a structure that unites an attribute and the associated methods to read and modify the attribute:

struct disk_attribute {

struct attribute attr;

ssize_t (*store)(struct gendisk *, const char *, size_t);

The attr member is nothing other than an attribute as introduced before; this can be fed to sysfs whenever an instance of attribute is required. But note that the show and store function pointers have a different prototype from that required for sysfs!

How do the subsystem-specific attribute functions get called by the sysfs layer? The connection is made by the following struct:

block/genhd.c static struct sysfs_ops disk_sysfs_ops = { .show = &disk_attr_show, .store = &disk_attr_store,

The show and store methods of sysfs_ops are called when a process wants to read from (or write to) a sysfs file as will be shown below in more detail.

When a sysfs file related to generic hard disk attributes is accessed, the kernel uses the methods disk_attr_show and disk_attr_store to read and modify the attribute values. The disk_attr_show function is called whenever the value of an attribute of this type needs to be read from the kernel; the code acts as the glue between sysfs and the genhd implementation:

Continue reading here: Blockgenhdc

Was this article helpful?

0 0