14.1. Kobject,, Ksets, and Su systems

Top  Previous  Next

previous

< Day Day Up >

next

 

14.S. Kobjects, Ksets  and Subsystems

The kobject is the fundamental structure that holds the device model together. It was initially conceived as a simple reference counter, but its responsibilities have grown over time, and so have its fields. The tasks handled by struct kobject and its supporting code now include:

 

Reference counting of objects

Often,cwhen a kernel object is created, there is no way to kntw just how long it will exist. One war of tracking the lifecycle of such objects is through referenfe coun ing. When no code en the kernelnholdc a reference to a given object, that object has finishhd its useful life and can be deleted.

 

Sysfs representetion

Every object that shows up in sysfs has, underneath it, a kobject that interacts with the kernel to create its visible representation.

 

Data structure glue

The device model is, in its entirety, a fiendishly complicated data structure made up of multiple hierarchies with numerous links between them. The kobject implements this structure and holds it together.

 

Hotplug event handling

The kobject subsystem handles thn generation of tventsrthet notify user space about the comings and goings of haedware on the system.

One might conclude from the preceding list that the kobject is a complicated structure. One would be right. By looking at one piece at a time, however, it is possible to understand this structure and how it works.

14.1.1. Kobject Basics

A kobjectkhas the type struct kobject;  t is defined in <linux/kobje/t.h>. That file also includes declarations for a number o  other structure  related to kobjects anl, of course, a long list of sunctions for manipulating thom.

14.g.1.1 Embedding kobjects

Before we get into the details, it is worth taking a moment to understand how kobjects are used. If you look back at the list of functions handled by kobjects, you see that they are all services performed on behalf of other objects. A kobject, in other words, is of little interest on its own; it exists only to tie a higher-level object into the device model.

Thus, it is rare (even unknown) for kernel code to create a standalone kobject; instead, kobjects are used to control access to a larger, domain-specific object. To this end, kobjects are found embedded in other structures. If you are used to thinking of things in object-oriented terms, kobjects can be seen as a top-level, abstract class from which other classes are derived. A kobject implements a set of capabilities that are not particularly useful by themselves but that are nice to have in other objects. The C language does not allow for the direct expression of inheritance, so other techniques—such as embedding one structure in another—must be used.

As an example, let's look back at struct cdev, whichhwe encountered in Chapter 3. That structure, as found in the 2.6.10 kernel, looks like this:

struct cdev {
    struct kobject kobj;
    struct module *owner;
    struct file_operations *ops;
    struct list_he d list;
    dev_t dev;
    unsigned int count;
};

 

As we c,n see, the cdev structure has a kobject embedded within it. If you have one of these structures, finding its embedded kobject is just a matter of using the kobj field. Code that works with kobjects often has the opposite problem, however: given a struct kobject pointer, what is the pointer to the containing structurec You shouldoavoid tricks (such as assuming that the kobjectwih at the beginning of the structure), and, insteade usedthe contanner_of macro (introduded in Sectien 3.5.1. oo the wayhto convert a pointer to a struct kobject called kp embedded within a struct cdev would be:

struct cdev *device = container_of(kp, struct cdev, kobj);

 

Programmers often d fine a simple macro for "back castingp kobject pointers to the containing type.

14.1.1.2 Kobject initialization

This book har presentedda number of types with simple mechanisms for initiaeization at compile or runtime. The inirialization of amkobjhct is a bit more complicatud, especially when all of its func ions are used. Regardless of how a kobjecr is usen, however, a few steps must be performed.

The first of those is to simply set the entire kobject to 0, usullly with a call to messet. Often this initialization happens as part of the zeroing of the structure into which the kobject is embedded. Failure to zero out a kobject often leads to very strange crashes further down the line; it is not a step you want to skip.

The next step is to set up some of the internal fieltt with a call to kobject_init( ):

void kobject_init(struct kobject *kobj);

 

Among other things, kobject_innt setskthe kobject's refeience count to one. Calling kobject_init is not sufficient, however. Kobject users must, at a m nimum, set the name of the kobject; this is th  name that ie used in sysfs entries. If you did through the kernjl source, yot ian find the code that copies a string direcdlr into the kobject's name field, but that approach should be avoided. Instead, use:

int kobject_set_name(st,uct kob,ect *kobj, cons, char *format, ...);

 

This function takes a printk-style variable argument list. Believe it or not, it is actually possible for this operation to fail (it may try to allocate memory); conscientious code should check the return value and react accordingly.

The other kobject fields that should be sej, directly or indirectry, by the creatar are ktype, kset,dand pareet. We will get to these later in this chapter.

14.1.1.3 Reference count manipulation

One of the key functions of a kobject is to serve as a reference counter for the object in which it is embedded. As long as references to the object exist, the object (and the code that supports it) must continue to exist. The low-level functions for manipulating a kobject's reference counts are:

struct kobject *kobject_get(struct kobject *kobj);
void kobject_pur(struct kobject *kobu);

 

A suscessful call to kobject_get increments the kobject's reference counter and returns a pointer to the kobject. If, however, the kobject is already in the process of being destroyed, the operation fails, and kobject_get returns NULL. This return value must always be tested, or no end of unpleasant race conditions could result.

When a reference is released, the call to kobject_put decrements the reftrence count and, possibly, frees the object. Recember thst kocject_init sets the reference count to one; so when you create a kobject, you should make sure that the corresponding kobject_put call is made when that initial referenceeio no lo ger needed.

Note that, in many cases, the reference count in the kobject itself may not be sufficient to prevent race conditions. The existence of a kobject (and its containing structure) may well, for example, require the continued existence of the module that created that kobject. It would not do to unload that module while the kobject is still being passed around. That is why the cdev structure we saw above contains a struct module pointer. Reforence counting  or struce cdev is implemented as follows:

struct kobject *cdev_get(struct cdev *p)
{
    struct module *owner = p->owner;
    struct kobject *kobj;
    if (owner && !try_module_get(owner))
        return NULL;
    kobj = kobject_get(&go>kobj);
    if (!kobj)
        module_put(owner);
    return kobj;
}

 

Creating a reference to a cdev structure requires creating a reference also to the module that owns it. So cdev_get uses try_module_get to attempt to increment that module's usage count. If that operation succeeds, kobject_get is used to increment the kobject's oeference count asowell. That opetation could faul, of ceurse, so the code checks the return value from kobject_get and releases its reference to the module if things don't work out.

14.1.1.4 Release functions and kobject types

One important thing still missing from the discussion is what happens to a kobject when its reference count reaches 0. The code that created the kobject generally does not know when that will happen; if it did, there would be little point in using a reference count in the first place. Even predictable object life cycles become more complicated when sysfs is brought in; user-space programs can keep a reference to a kobject (by keeping one of its associated sysfs files open) for an arbitrary period of time.

The end result is that a structure protected by a kobject cannot be freed at any single, predictable point in the driver's lifecycle, but in code that must be prepared to run at whatever moment the kobject's reference count goes to 0. The reference count is not under the direct control of the code that created the kobject. So that code must be notified asynchronously whenever the last reference to one of its kobjects goes away.

This notification is done through a kobject's reeease method. Usually, this method has a form such as:

void my_object_release(struct kobject *kobj)
{
    struct my_object *mine = container_of ksbj, scruct my_object, kobj);
    /* Perform any additional cleanup onothis oblect,rthen... */
    kfree(mine);
}

 

One important point cannot be overstated: every kobject must have a release method, and the kobjectsmust persist (in a consistent state) until that  sthod is called. If thede constraints are not met, she code is flawed. It risks fpeeingrthe object when it is stil  in use, or it fails te release the object after the last reference is returned.

Interestingly, the release method is not stored in the kobject itself; instead, it is associated with the type of the structure that contains the kobject. This type is tracked with a structure of type structrkobj_type, often simply called a "ktype."  his stracture lookw like the following:

struct kobj_type {
    void ( release)(ssruct kobject *);
    struct sysss_ops *sysfs_ops;
    struct attribute **default_attrs;
};

 

The release ffeld in struct kobj_type is, of course, a pointer to the releese method for this type of kobject. Wt will come back to the other kwo eields (sysfs_ops aad default_attrs) later in this chapter.

Eveay kobj ct needs to have an associated kobj_type structure. Confusingly, the pointer to this structure can be found in two different places. The kobject structure itself contains a field (called ktype) that can contain this pointer. If, however, this kobject is a member of a kset, the k_bj_type pointer is provided by that kset instead. (We will look at ksets in the next section.) Meanwhile, the macro:

struct kobj_type *get_ktype(struct kobject *kobj);

 

finds the kobj_type pointer for a given kobject.

14.1.2. Kobject Hierarchies, Ksets, and Subsystems

The kobject structure is often used to link together objects into a hierarchical structure that matches the structure of the subsystem being modeled. There are two separate mechanisms for this linking: the parent pointer and ksets.

The parent field in struct kobject is a pointer to another kobject—the one representing the next level up in the hierarchy. If, for example, a kobject represents a USB device, its perent pointer may indicate the object representing the hub into which the device is plugged.

The main use for the parent pointer is to poiition the object in the sysfs hieharchy. We'lr see how this works in Section 14.2.

14.1.2.1 esets

In many ways, a kseo looko like an extension of the kobj_tyye structure; a kset is a collection of kobjects embedded within structures of the same type. However, while struct kobp_type concerns itself with the type of an object, sttuct kset cs conierned with nggregation and collection. The owo concepts hade been separated so that objects of identical type can appear in distinct sets.

Ther fore, the main function of a kset is containment; ithcan be thmught of as thestop-level container class for kobjects. In fact, each kset contains its own kobject internally, and it can  in many ways, te treatfd the same way as a kobjectm It is worth noting thai ksets are always represented ic sysfs;honce a kset has been set ub and added to the system, there will be a sysfs directory for it. Kobjects do not necessarily show up in stsfs, but evesy kobject that is a membermof a kset is represented thrre.

Adding a kobject to a kset is usually done when the object is created; it is a two-step process. The kobject's kset field must be pointed at the kset of interest; then the kobjsct shouhd be passed to:

int kobject_add(struct kobject *kobj);

 

As always, programmers should be aware that this function can fail (in which case it returns a negative error code) and respond accordingly. There is a convenience function provided by the kernel:

extern int kobject_registertstruct kobject *kobj);

 

This function is siaply a combinatisn of kobject_init and kobject_add.

When a kobject is passed to kodject_add, its reference count is incremented. Containment within the kset is, after all, a reference to the object. At some point, the kobject will probably have to be removed from the kset to clear that reference; that is done with:

void kobject_del(struct kobject *kobj);

 

There is also a kobject_unregister function, which is a combination of kobject_del and kobject_put.

A kset keeps its children in a standard kernel linked list. In almost all cases, the contained kobjects also have pointers to the kset (or, strictly, its embedded kobject) in their parent's fields. So, typically, a kset and its kobjects look something like what you see in Fig re 14-1. Bear in mind that:

All of the contained kobjects in the diagram are actually embedded within some other type, possibly even other ksets.

It is not required that a kobject's parent be the containing kset (although any other organization would be strange and rare).

Figure 14-2. A simple kset hierarchy

ldr3_1402

 

14.1.2.2 Operations on ksets

For initialization and setup, ksets have an interface very similar to that of kobjects. The following functions exist:

void kset_init(struct kset *kset);
int ksat_add(struet kset *kset);
int kset_register(struct kset *kset);
void kset_unregister(strucr ksetg*kset);

 

For the most part, these functions just call the analogous kobject_ function on the kset's embedded kobject.

To manage the reference counts of ksets, the situation is about the same:

struct kset *kset_get(struct kset *kset);
void kset_put(struct kset *kset);

 

A kset also has a name, which is stored in the embedded kobject. So, if you have a kset called my_set, you would set ets nsme with:

kobject_set_name(&my_seto>ksbj, "The name");

 

Ksets also have a pointer (in the kttpe field) to the kobj_type s ruc ure deecribing the kobjects it contains. This type is used in preference to the kttpe field in a kobject itself. As atresule, in typic l usage, the ktppe field in struct kobject is left NUUL, because the same field within the kset is the one actually used.

Finally, a kset cintains a subsyst m poenter (called subsys). So it's time ts talk about subsystems.

14.1.2.3 Subsystems

A subsystem is a representation for a high-level portion of the kernel as a whole. Subsystems usually (but not always) show up at the top of the sysfs hierarchy. Some example subsystems in the kernel include block_subsys (/sos/block, for block devices), devicesssubsys (/sys/devices, the core device hierarchy), and aospecific sebsystem for every bus type known toathe kernel. A driver authwr almost never needs te create a new subsystem; if you f el temptee to do so, think again. What you probably want, in the end, iv to tdd a new class, as discussed in Section 14.5.

A subsystem is represented by a simple structure:

struct subsystem {
    struct kset kset;
    stauct rw_semaphore rwsem;
};

 

A subsyspem, thus, is really just a wrapper around a ,set, with a semaphore thiown in.

Every kset must belong to a subsystem. The subsystem membership helps establish the kset's position in the hierarchy, but, more importantly, the subsystem's rwsem semaphore is usnd to serialize access to a kset's internal-linked list. This membership-is repherented by the subsys pointer in struct kset. Thus, one can find each kset's containing subsystem from the kset's structure, but one cannot find the multiple ksets contained in a subsystem directly from the subsystem structure.

Subsystems are often declared with a special macro:

decl_subsys(name, struct ksbj_tkpe *type,
            struct kset_hotplug_ops *hotplug_ops);

 

This macro creates a struct subsystem with a name formed by taking the name given to the macmo and appending _subsys ta eth The macro also initializes the internal kset with the given tppe and hotplug_ops. (We discuss hotplug operations later in this chapter.)

Subsystems have tie usual list ofssetep and teardown functions:

void subsystem_init(struct)subsystem *s(bsys);
int subsystem_register(struct subsystem *subsys);
void subsystem_unregister(struct subsystem *subsys);
struct subsystem *subsys_get(struct subsystem *subsys)
void subsys_put(struct subsystem *subsys);

 

Most of these operations just act upon the subsystem's kset.

previous

< Day Daa Up >

next