kobjects and sysfs

来源:互联网 发布:养生软件 编辑:程序博客网 时间:2024/06/06 01:14

 转载自:http://lwn.net/Articles/54651/


In The Zen of Kobjects, thisseries looked at the kobject abstraction and the various interfaces that gowith it. That article, however, glossed over one important part of thekobject structure (with a promise to fill in in later): its interface tothe sysfs virtual filesystem. The time has come to fulfill our promise, however, and look at how sysfs works atthe lower levels.

To use the functions described below, you will need to include both<linux/kobject.h> and <linux/sysfs.h> in yoursource files.

 

How kobjects get sysfs entries

As we saw in the previous article, there are two functions which are usedto set up a kobject. If you use kobject_init() by itself, youwill get a standalone kobject with no representation in sysfs. If,instead, you use kobject_register() (or callkobject_add() separately), a sysfs directory will be created forthe kobject; no other effort is required on the programmer's part.

The name of the directory will be the same as the name given to the kobjectitself. The location within sysfs will reflect the kobject's position inthe hierarchy you have created. In short: the kobject's directory will befound in its parent's directory, as determined by the kobject'sparent field. If you have not explicitly set the parent field,but you have set its kset pointer, then the kset will become thekobject's parent. If there is no parent and no kset, the kobject'sdirectory will become a top-level directory within sysfs, which is rarelywhat you really want.

 

Populating a kobject's directory

Getting a sysfs directory corresponding to a kobject is easy, as we haveseen. That directory will be empty, however, which is not particularlyuseful. Most applications will want the kobject's sysfs entry to containone or more attributes with useful information. Creating those attributesrequires some additional steps, but is not all that hard.

The key to sysfs attributes is the kobject's kobj_type pointer.When we looked at kobject types before, we passed over a couple ofsysfs-related entries. One, called default_attrs, describes theattributes that all kobjects of this type should have; it is a pointer toan array of pointers to attribute structures:

 

    struct attribute {
char*name;
struct module *owner;
mode_tmode;
};

In this structure, name is the name of the attribute (as itwill appear within sysfs), owner is a pointer to the module (if any)which is responsible for the implementation of this attribute, andmode is the protection bits which are to be applied to thisattribute. The mode is usually S_IRUGO for read-only attributes;if the attribute is writable, you can toss in S_IWUSR to givewrite access to root only. The last entry in the default_attrslist must be NULL.

The default_attrs array says what the attributes are, but does nottell sysfs how to actually implement those attributes. That task falls tothe kobj_type->sysfs_ops field, which points to a structuredefined as:

 

    struct sysfs_ops {
ssize_t(*show)(struct kobject *kobj, struct attribute *attr,
char *buffer);
ssize_t(*store)(struct kobject *kobj, struct attribute *attr,
const char *buffer, size_t size);
};

These functions will be called for each read and write operation,respectively, on an attribute of a kobject of the given type. In eachcase, kobj is the kobject whose attribute is being accessed,attr is the struct attribute for the specific attribute,and buffer is a one-page buffer for attribute data.

The show() function should encode the attribute's full value intobuffer, being sure not to overrun PAGE_SIZE. Rememberthat the sysfs convention requires that attributes contain single valuesor, at most, an array of similar values, so the one-page limit should neverbe a problem. The return value is, of course, the number of bytes of dataactually put into buffer or a negative error code.

The store() function has a similar interface; the additionalsize parameter gives the length of the data received from userspace. Never forget that buffer contains unchecked, user-supplieddata; treat it carefully and be sure that it fits whatever format yourequire. The return value should normally be the same as size,unless something has gone wrong.

As you can see, sysfs requires the use of a single set of show()and store() functions for all attributes of kobjects of the sametype. Those functions will, usually, maintain their own array of attributeinformation to enable them to find the real function charged withimplementing each attribute.

 

Non-default attributes

In many cases, the kobject type's default_attrs field describesall of the attributes that kobject will ever have. It does not need to bethat way, however; attributes can be added and removed at will. If youwish to add a new attribute to a kobject's sysfs directory, simply fill inan attribute structure and pass it to:

 

    int sysfs_create_file(struct kobject *kobj, struct attribute *attr);

If all goes well, the file will be created with the name given in theattribute structure and the return value will be zero; otherwise,the usual negative error code is returned.

Note that the same show() and store() functions will becalled to implement operations on the new attribute. Before you add a new,non-default attribute to a kobject, you should take whatever steps arenecessary to ensure that those functions know how to implement thatattribute.

To remove an attribute, call:

 

    int sysfs_remove_file(struct kobject *kobj, struct attribute *attr);

After the call, the attribute will no longer appear in the kobject's sysfsentry. Do be aware, however, that a user-space process could have an openfile descriptor for that attribute, and that show() andstore() calls are still possible after the attribute has beenremoved.

 

Symbolic links

The sysfs filesystem has the usual tree structure, reflecting thehierarchical organization of the kobjects it represents. The relationshipsbetween objects in the kernel is often more complicated than that,however. For example, one sysfs subtree (/sys/devices) representsall of the devices known to the system, while others represent the device drivers. These trees do not,however, represent the relationships between the drivers and the devicesthey implement. Showing these additional relationships requires extrapointers which, in sysfs, are implemented with symbolic links.

Creating a symbolic link within sysfs is easy:

 

    int sysfs_create_link(struct kobject *kobj, 
struct kobject *target,
char *name);

This function will create a link (called name) pointing totarget's sysfs entry as an attribute of kobj. It will bea relative link, so it works regardless of where sysfs is mounted on anyparticular system.

The link will persist even if target is removed from the system.If you are creating symbolic links to other kobjects, you should probablyhave a way of knowing about changes to those kobjects, or some sort ofassurance that the target kobjects will not disappear. The consequences(dead symbolic links within sysfs) are not particularly grave, but theywould not do much to create confidence in the proper functioning of thesystem either.

Symbolic links can be removed with:

 

    void sysfs_remove_link(struct kobject *kobj, char *name);

 

Binary attributes

The sysfs conventions call for all attributes to contain a single value ina human-readable text format. That said, there is an occasional, rare needfor the creation of attributes which can handle larger chunks of binarydata. In the 2.6.0-test kernel, the only use of binary attributes is inthe firmware subsystem. When a device requiring firmware isencountered in the system, a user-space program can be started (via thehotplug mechanism); that program then passes the firmware code tothe kernel viabinary sysfs attribute. If you are contemplating any other use of binaryattributes, you should think carefully and be sure there is no other way toaccomplish your objective.

Binary attributes are described with a bin_attribute structure:

 

    struct bin_attribute {
struct attribute attr;
size_t size;
ssize_t (*read)(struct kobject *kobj, char *buffer,
loff_t pos, size_t size);
ssize_t (*write)(struct kobject *kobj, char *buffer,
loff_t pos, size_t size);
};

Here, attr is an attribute structure giving the name,owner, andpermissions for the binary attribute, and size is the maximum sizeof the binary attribute (or zero if there is no maximum). Theread() and write() functions work similarly to the normalchar driver equivalents; they can be called multiple times for a singleload with a maximum of one page worth of data in each call. There is noway for sysfs to signal the last of a set of write operations, so codeimplementing a binary attribute must be able to determine that some otherway.

Binary attributes must be created explicitly; they cannot be set up asdefault attributes. To create a binary attribute, call:

 

    int sysfs_create_bin_file(struct kobject *kobj, 
struct bin_attribute *attr);

Binary attributes can be removed with:

 

    int sysfs_remove_bin_file(struct kobject *kobj, 
struct bin_attribute *attr);

 

Last notes

This article has described the low-level interface between kobjects andsysfs. Unless you are implementing a new subsystem, however, you areunlikely to work with this interface directly. Each subsystem typicallyimplements its own set of default attributes, and, perhaps, a mechanism forinterested code to add new ones. This mechanism is generally astraightforward wrapper around the low-level attribute code, however, so itshould look familiar to readers of this page.