Chapter 17. kobjects and sysfs

A significant new feature in the 2.6 Linux kernel is the addition of a unified device model. The device model provides a single mechanism for representing devices and describing their topology in the system. Such a system provides several benefits:

  • Minimization of code duplication

  • A mechanism for providing common facilities, such as reference counting

  • The capability to enumerate all the devices in the system, view their status, and see to what bus they attach

  • The capability to generate a complete and valid tree of the entire device structure of the system, including all buses and interconnections

  • The capability to link devices to their drivers and vice versa

  • The capability to categorize devices by their class, such as input device, without the need to understand the physical device topology

  • The ability to walk the tree of devices from the leaves up to the root, powering down devices in the correct order

The initial motivation for the device model was this final point. To implement intelligent power management in the kernel, you need to be able to build a tree representing the device topology in the system. When powering down devices on a tree that grows down, the kernel must power down the lower (leaf) nodes of the tree before the higher nodes. For example, the kernel needs to turn off a USB mouse before it turns off the USB controller, and the kernel must power down the USB controller before the PCI bus. To do this accurately and efficiently for the entire system, the kernel needs a tree of devices.

kobjects

At the heart of the device model is the kobject, which is represented by struct kobject and defined in <linux/kobject.h>. The kobject is similar to the Object class in object-oriented languages such as C# or Java. It provides basic facilities, such as reference counting, a name, and a parent pointer, allowing the creation of a hierarchy of objects.

Without further ado:

struct kobject {
        char                    *k_name;
        char                    name[KOBJ_NAME_LEN];
        struct kref             kref;
        struct list_head        entry;
        struct kobject          *parent;
        struct kset             *kset;
        struct kobj_type        *ktype;
        struct dentry           *dentry;
};

The k_name pointer points to the name of this kobject. If the name is less than KOBJ_NAME_LEN—currently 20—bytes, the name is stored in name and k_name points there. If the name is larger than KOBJ_NAME_LEN bytes, a buffer sufficient in size to hold the name is dynamically allocated, the name is stored in the buffer, and k_name points there.

The parent pointer points to this kobject's parent. In this manner, kobjects build an object hierarchy in the kernel and allow the expression of the relationship between multiple objects. As you shall see, this is actually all that sysfs is: a user-space filesystem representation of the kobject object hierarchy inside the kernel.

The dentry pointer points to the dentry structure that represents this kobject in sysfs, assuming that this kobject is represented in sysfs.

The kref, ktype, and kset members point to structures used in support of kobjects. The entry member is used in conjunction with kset. Those structures and their use are discussed shortly.

kobjects are usually embedded in other structures and are generally not interesting on their own. Instead, a more important structure, such as struct cdev, has a kobj member:

/* cdev structure - object representing a character device */
struct cdev {
        struct kobject          kobj;
        struct module           *owner;
        struct file_operations  *ops;
        struct list_head        list;
        dev_t                   dev;
        unsigned int            count;
};

When kobjects are embedded inside other structures, the structures receive the standardized functions that a kobject provides. Most importantly, the structure's embedded kobject now allows the structure to become part of an object hierarchy. For example, the cdev structure is presentable in an object hierarchy via the parent pointer cdev->kobj->parent and the list cdev->kobj->entry.

ktypes

kobjects are associated with a specific type, called a ktype. ktypes are represented by struct kobj_type and defined in <linux/kobject.h>:

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

ktypes have the simple job of describing default behavior for a family of kobjects. Instead of each kobject defining its own behavior, the behavior is stored in a ktype, and kobjects of the same “type” share the same behavior.

The release pointer points to the deconstructor called when a kobject's reference count reaches zero. This function is responsible for freeing any memory associated with this kobject and otherwise cleaning up.

The sysfs_ops variable points to a sysfs_ops structure. This structure describes the behavior of sysfs files on read and write. It's covered in more detail in the section “Adding Files to sysfs.”

Finally, default_attrs points to an array of attribute structures. These structures define the default attributes associated with this kobject. Attributes represent properties related to a given object. If this kobject is exported to sysfs, the attributes are exported as files. The last entry in the array must be NULL.

ksets

ksets aggregate collections of kobjects. ksets work as the base container class for a set of objects, collecting related kobjects, such as “all block devices,” together in a single place. ksets may sound very similar to ktypes and beg the question, “Why have both?” Although ksets collect kobjects into a set, ktypes describe properties shared by kobjects of a related type. The distinction is kept to allow kobjects of identical ktypes to be grouped into different ksets.

The kset pointer points at a kobject's associated kset. ksets are represented by the kset structure, which is defined in <linux/kobject.h>:

struct kset {
        struct subsystem         *subsys;
        struct kobj_type         *ktype;
        struct list_head         list;
        struct kobject           kobj;
        struct kset_hotplug_ops  *hotplug_ops;
};

The ktype pointer points to the ktype for the kobjects in this kset, list is a linked list of all kobjects in this kset, kobj is a kobject representing the base class for this set, and hotplug_ops points to a structure that describes the hotplug behavior of kobjects in this kset.

Finally, the subsys pointer points to the struct subsystem associated with this kset.

Subsystems

Subsystems represent high-level concepts in the kernel and are a collection of one or more ksets. Whereas ksets contain kobjects, subsystems contain ksets, but the relationship between ksets in a subsystem is much weaker than the relationship between kobjects in a kset. The ksets in a subsystem may share only some large overarching generalization.

Despite this important role, subsystems are represented by a rather simple object, struct subsystem:

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

Whereas the subsystem structure only points to a single kset, multiple ksets may point to a single subsystem via their subsys pointer. This unidirectional relationship implies that it is not possible to find all ksets in a subsystem given only a subsystem structure.

The kset that is contained in the subsystem is the default kset of that subsystem, used to cement the subsystem's location in the object hierarchy.

The rwsem member of the subsystem structure is a read-write semaphore (see Chapter 9, “Kernel Synchronization Methods”) used to protect against concurrent access of this subsystem and all its ksets. All ksets must belong to a subsystem because they use this read-write semaphore to synchronize access to their internal data.

Structure Confusion

The handful of structures thus far discussed is confusing not because of their sheer number (there are only four) or their complexity (they are all fairly simple), but because they are all very interrelated. In the world of kobjects, it is hard to discuss one structure without involving the others. With the basics of each structure covered, however, you can develop a firm understanding of their relationships.

The important guy here is the kobject, represented by struct kobject. The kobject is used to introduce basic object properties—such as reference counting, parent-child relationship, and object name—to kernel data structures. The kobject can provide these features in a standard unified way. kobjects, in and of themselves, are not overly useful. Instead, kobjects are typically embedded in other data structures.

kobjects are associated with a specific ktype, which is represented by struct kobj_type and pointed at by the ktype variable inside of the kobject. ktypes define some default properties of related kobjects: deconstruction behavior, sysfs behavior, and default attributes.

kobjects are then grouped into sets, called ksets. ksets are represented by struct kset. ksets provide two functions. First, their embedded kobjects act as a base class for a group of kobjects. Second, ksets aggregate together related kobjects. In sysfs, kobjects are the individual directories in the filesystem. Related directories—say, perhaps all subdirectories of a given directory—might be in the same kset.

Subsystems represent large pieces of the kernel and are collections of ksets. They are represented by struct subsystem. The root level directories in sysfs are all subsystems.

Figure 17.1 depicts the relationship between these data structures.

Relationship between kobjects, ksets, and subsystems

Figure 17.1. Relationship between kobjects, ksets, and subsystems

Managing and Manipulating kobjects

With the basic internals of kobjects and friends behind you, it's time to look at the exported interfaces used for managing and manipulating kobjects. Most of the time, driver writers will not have to deal with kobjects directly. Instead, kobjects will be embedded in some class-specific structure (as you saw with the character device structure) and managed “behind the scenes” by the associated driver subsystem. Nonetheless, kobjects are not intended to remain hidden and may seep through into driver code or you may be hacking on the driver subsystem itself.

The first step in using a kobject is declaring and initializing it. kobjects are initialized via the function kobject_init, which is defined in <linux/kobject.h>:

void kobject_init(struct kobject *kobj);

The function's lone parameter is the kobject to initialize. Before calling this function, the kobject must be zeroed. This may normally happen during the initialization of the larger function in which the kobject is embedded. If not, a simple call to memset() does the trick:

memset(kobj, 0, sizeof (*kobj));

It is safe to initialize parent and kset after the zeroing. For example,

kobj = kmalloc(sizeof (*kobj), GFP_KERNEL);
if (!kobj)
        return -ENOMEM; 
memset(kobj, 0, sizeof (*kobj));
kobj->kset = kset;
kobj->parent = parent_kobj;
kobject_init(kobj);

After initialization, you must set the kobject's name via kobject_set_name():

int kobject_set_name(struct kobject * kobj, const char * fmt, ...);

This function uses a variable argument list in the style of printf() and printk() to set the name of the provided kobject. As you saw, k_name points to the kobject's name. If the name is small enough, it is stored in the static array name, so it makes sense to not needlessly provide a huge name.

After allocating a kobject and proving it with a name, you need to set its kset field and optionally its ktype field. You need to set the ktype only if the kset does not provide one. Otherwise, the ktype in the kset takes precedence. If you are wondering why kobjects even have ktype fields, welcome to the club.

Reference Counts

One of the primary features provided by kobjects is a unified reference counting system. After initialization, the kobject's reference count is set to one. So long as the reference count is nonzero, the object continues to exist in memory and is said to be pinned. Any code that holds a reference to the object first elevates the reference count. When the code is finished with the object, the reference count is decremented. Bumping the reference count is called getting a reference to the object, and decrementing the reference count is called putting reference to the object. When the reference count reaches zero, the object may be destroyed and any associated memory freed.

Incrementing the reference count is done via kobject_get():

struct kobject * kobject_get(struct kobject *kobj);

This function returns a pointer to the kobject or NULL on failure.

Decrementing the reference count is done via kobject_put():

void kobject_put(struct kobject *kobj);

If the provided kobject's reference count reaches zero, the release function pointed at by the ktype associated with the kobject is invoked.

krefs

Internally, the kobject reference counting is provided by the kref structure, which is defined in <linux/kref.h>:

struct kref {
        atomic_t refcount;
};

The lone member is an atomic variable used to hold the reference count. A structure is used simply to provide type checking. Before using a kref, you must initialize it via kref_init():

void kref_init(struct kref *kref)
{
        atomic_set(&kref->refcount, 1);
}

As you can see, this function simply initializes the internal atomic_t to one. Consequently, krefs are pinned with a reference count of one as soon as they are initialized; this is the same behavior as kobjects.

To obtain a reference to a kref, use kref_get():

void kref_get(struct kref *kref)
{
        WARN_ON(!atomic_read(&kref->refcount));
        atomic_inc(&kref->refcount);
}

This function bumps the reference count. It has no return value. To drop a reference to a kref, use kref_put():

void kref_put(struct kref *kref, void (*release) (struct kref *kref))
{
        WARN_ON(release == NULL);
        WARN_ON(release == (void (*)(struct kref *))kfree);

        if (atomic_dec_and_test(&kref->refcount))
                release(kref);
}

This function drops the reference count by one and calls the provided release() function if the count is now zero. As noted by the ominous WARN_ON() statement, the provided release() function cannot simply be kfree(), but must be a specialized function that accepts struct kref as its lone argument and has no return value.

Rather than having kernel code implement its own reference counting via atomic_t types and simple “get” and “put” wrapper functions, developers are encouraged to use the kref type and its helpers to provide a common and known-correct reference counting mechanism in the kernel.

All these functions are defined in lib/kref.c and declared in <linux/kref.h>.

sysfs

The sysfs filesystem is an in-memory virtual filesystem that provides a view of the kobject object hierarchy. It enables users to view the device topology of their system as a simple filesystem. Using attributes, kobjects can export files that allow kernel variables to be read from and optionally written to.

Although the intended purpose of the device model was initially to provide a device topology for power management reasons, a quite spectacular offshoot was sysfs. To facilitate debugging, the device model's developer decided to export the tree as a file-system. This quickly proved quite useful, at first as a replacement for device-related files that previously found themselves in /proc, and later as a powerful view into the system's object hierarchy. Indeed, sysfs, originally called driverfs, predated kobjects. Eventually sysfs made it clear that a new object model would be quite beneficial, and kobject was born. Today, every system with a 2.6 kernel has sysfs and nearly all have it mounted.

The magic behind sysfs is simply tying kobjects to directory entries via the dentry variable inside each kobject. Recall from Chapter 12, “The Virtual Filesystem,” that the dentry structure represents directory entries. By linking kobjects to dentries, kobjects trivially map to directories. Exporting the kobjects as a filesystem is now as easy as building a tree of the dentries in memory. But wait! kobjects already form a tree, our beloved device model. With kobjects mapping to dentries and the object hierarchy already forming an in-memory tree, sysfs became trivial.

Figure 17.2 is a partial view of the sysfs filesystem as mounted at /sys.

A view of part of the /sys tree.

Figure 17.2. A view of part of the /sys tree.

The root of the sysfs contains seven directories: block, bus, class, devices, firmware, module, and power. The block directory contains one directory for each of the registered block devices on the system. Each of those directories, in turn, contains any partitions on the block device. The bus directory provides a view of the system buses. The class directory contains a view of the devices on the system organized by high-level function. The devices directory is a view of the device topology of the system. It maps directly to the hierarchy of device structures inside the kernel. The firmware directory contains a system-specific tree of low-level subsystems such as ACPI, EDD, EFI, and so on. The power directory contains system-wide power management data.

The most important directory is devices, which exports the device model to the world. The directory structure is the actual device topology of the system. Much of the data in other directories is simply alternative organizations of the data in the devices directory. For example, /sys/class/net/ organizes devices by the high-level concept of registered network interfaces. Inside this directory might be the subdirectory eth0, which contains the symlink device back to the actual device directory in devices.

Take a look at /sys on any Linux systems that you have access to. Such an accurate view into the system's device is pretty neat, and seeing the interconnection between the high-level concepts in class versus the low-level physical devices in devices and the actual drivers in bus is very informative. The whole experience is even more rewarding when you realize that this data is free, that this is the very representation of the system maintained inside the kernel[1].

Adding and Removing kobjects from sysfs

Initialized kobjects are not automatically exported to sysfs. To represent a kobject to sysfs, you use kobject_add():

int kobject_add(struct kobject *kobj);

The kobject's location in sysfs depends on the kobject's location in the object hierarchy. If the kobject's parent pointer is set, the kobject will map to a subdirectory in sysfs inside its parent. If the parent pointer is not set, the kobject will map to a subdirectory inside kset->kobj. If neither the parent nor the kset fields are set in the given kobject, the kobject is assumed to have no parent and will map to a root-level directory in sysfs. This is almost assuredly what you want, so one or both of parent and kset should be set appropriately before kobject_add() is called. Regardless, the name of the directory representing the kobject in sysfs is given by kobj->k_name.

Rather than call both kobject_init() and kobject_add(), you can call kobject_register():

int kobject_register(struct kobject *kobj)

This function both initializes the given kobject and adds it to the object hierarchy.

Removing a kobject's sysfs representation is done via kobject_del():

void kobject_del(struct kobject *kobj);

The function kobject_unregister() combines both kobject_del() and kobject_put():

void kobject_unregister(struct kobject * kobj)

All four of these functions are defined in lib/kobject.c and declared in <linux/kobject.h>.

Adding Files to sysfs

kobjects map to directories, and the complete object hierarchy maps nicely to the complete sysfs directory structure, but what about files? sysfs is nothing but a pretty tree without files to provide actual data.

Default Attributes

A default set of files is provided via the ktype field in kobjects and ksets. Consequently, all kobjects of the same type have the same default set of files populating their sysfs directories. The kobj_type structure contains a member, default_attrs, that is an array of attribute structures. Attributes map kernel data to files in sysfs.

The attribute structure is defined in <linux/sysfs.h>:

/* attribute structure - attributes map kernel data to a sysfs file */
struct attribute {
        char             *name;    /* attribute's name */
        struct module    *owner;   /* owning module, if any */
        mode_t           mode;     /* permissions */
};

The name member provides the name of this attribute. This will be the filename of the resulting file in sysfs. The owner member points to a module structure representing the owning module, if any. If a module does not own this attribute, this field is NULL. The mode member is a mode_t type that specifies the permissions for the file in sysfs. Read-only attributes probably want to set this to S_IRUGO if they are world readable and S_IRUSR if they are only owner readable. Writable attributes probably want to set mode to S_IRUGO | S_IWUSR. All files and directories in sysfs are owned by uid zero and gid zero.

Although default_attrs lists the default attributes, sysfs_ops describes how to use them. The sysfs_ops member is a pointer to a structure of the same name, which is defined in <linux/sysfs.h>:

struct sysfs_ops {
        /* method invoked on read of a sysfs file */
        ssize_t (*show) (struct kobject *kobj,
                         struct attribute *attr,
                         char *buffer);

        /* method invoked on write of a sysfs file */
        ssize_t (*store) (struct kobject *kobj,
                          struct attribute *attr,
                          const char *buffer,
                          size_t size);
};

The show() method is invoked on read. It must copy the value of the attribute given by attr into the buffer provided by buffer. The buffer is PAGE_SIZE bytes in length; on x86, PAGE_SIZE is 4096 bytes. The function should return the size in bytes of data actually written into buffer on success or a negative error code on failure.

The store() method is invoked on write. It must read the size bytes from buffer into the variable represented by the attribute attr. The size of the buffer is always PAGE_SIZE or smaller. The function should return the size in bytes of data read from buffer on success or a negative error code on failure.

Because this single set of functions must handle file I/O requests on all attributes, they typically need to maintain some sort of generic mapping to invoke a handler specific to each attribute.

Creating New Attributes

Generally, the default attributes provided by the ktype associated with a kobject are sufficient. Indeed, because all the kobjects of the same ktype are supposed to be related—if not identical in nature as in, say, all partitions—the same set of attributes should satisfy all kobjects. This not only simplifies life, but also provides code consolidation and a uniform look and feel to sysfs directories of related objects.

Nonetheless, often some specific instance of a kobject is somehow special. It wants or even needs its own attributes—perhaps to provide data or functionality not shared by the more general ktype. To this end, the kernel provides the sysfs_create_file() interface for adding new attributes on top of the default set:

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

This badboy will associate the attribute structure pointed at by attr with the kobject pointed at by kobj. Before it is invoked, the given attribute should be filled out. This function returns zero on success and a negative error code otherwise.

Note that the sysfs_ops specified in the kobject's ktype is invoked to handle this new attribute. The existing default show() and store() methods must be capable of handling the newly created attribute.

In addition to creating actual files, it is possible to create symbolic links. Creating a symlink in sysfs is very easy:

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

This function creates a link named name in the directory mapped from kobj to the directory mapped from target. This function returns zero on success and a negative error code otherwise.

Destroying New Attributes

Removing an attribute is handled via sysfs_remove_file():

void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);

Upon call return, the given attribute will no longer appear in the given kobject's directory.

Symbolic links created with sysfs_create_link() may be removed with sysfs_remove_link():

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

Upon return, the symbolic link name in the directory mapped from kobj is removed.

All four of these functions are declared in <linux/kobject.h>. The sysfs_create_file() and sysfs_remove_file() functions are defined in fs/sysfs/file.c. The sysfs_create_link() and sysfs_remove_link() functions are defined in fs/sysfs/symlink.c.

sysfs Conventions

The sysfs filesystem is currently the place for implementing functionality previously reserved for ioctl() calls on device nodes or the procfs filesystem. These days, the chic thing to do is implement such functionality as sysfs attributes in the appropriate directory. For example, instead of a new ioctl() on a device node, add a sysfs attribute in the driver's sysfs directory. Such an approach avoids the type-unsafe use of obscure ioctl() arguments and the haphazard mess of /proc.

To keep sysfs clean and intuitive, however, developers must follow certain conventions.

First, sysfs attributes should export one value per file. Values should be text-based and map to simple C types. The goal is to avoid the highly structured or highly messy representation of data we have today in /proc. Providing one value per file makes reading and writing trivial from the command line and enables C programs to easily slurp the kernel's data from sysfs into their own variables. In situations where the one-value-per-file rule results in an inefficient representation of data, it is acceptable to place multiple values of the same type in one file. Delineate them as appropriate; a simple space probably makes the most sense. Ultimately, think of sysfs attributes as mapping to individual kernel variables (as they usually do) and keep in mind ease of manipulation from user-space, particularly from the shell.

Second, organize data in sysfs in a clean hierarchy. Correctly parent kobjects so that they map intuitively into the sysfs tree. Associate attributes with the correct kobject and keep in mind that the kobject hierarchy exists not only in the kernel but also as an exported tree to user-space. Keep the sysfs tree sane!

Finally, keep in mind that sysfs provides a kernel-to-user service and is thus some sort of user-space ABI. User programs may come to rely on the existence, location, value, and behavior of sysfs directories and files. Changing existing files in any way is discouraged, and modifying the behavior of a given attribute but keeping its name and location is surely begging for trouble.

These simple conventions should allow sysfs to provide a rich and intuitive interface to user-space. Use sysfs correctly and user-space developers will not curse your existence but praise your beautiful code.

The Kernel Events Layer

The Kernel Event Layer implements a kernel-to-user notification system on top of—you guessed it—kobjects. After the release of 2.6.0, it became clear that a mechanism for pushing events out of the kernel and up into user-space was needed, particularly for desktop systems that yearned for a more integrated and asynchronous system. The idea was to have the kernel push events up the stack: Hard drive full! Processor is overheating! Partition mounted! Pirate ship on the horizon!

Just kidding about the last one.

Early revisions of the event layer came and went, and it was not long before the whole thing was tied intimately to kobjects and sysfs. The result, it turns out, is pretty neat. The Kernel Event Layer models events as signals emitting from objects—specifically, kobjects. Because kobjects map to sysfs paths, the source of each event is a sysfs path. If the event in question has to do with your first hard drive, then /sys/block/hda is the source address. Internally, inside the kernel, we model the event as originating from the backing kobject.

Each event is given a verb or action string representing the signal. The strings are terms such as modified or unmounted that describe what happened.

Finally, each event has an optional payload. Rather than pass an arbitrary string to user-space that provides the payload, the kernel event layer represents payloads as sysfs attributes.

Internally, the kernel events go from kernel-space out to user-space via netlink. Netlink is a high-speed multicast socket used to transmit networking information. Using netlink means that obtaining kernel events from user-space is as simple as blocking on a socket. The intention is for user-space to implement a system daemon that listens on the socket, processes any read events, and transmits the events up the system stack. One possible proposal for such a user-space daemon is to tie the events into D-BUS[2], which already implements a system-wide messaging bus. In this manner, the kernel can emit signals just as any other component in the system.

To send events out to user-space from your kernel code, use kobject_uevent():

int kobject_uevent(struct kobject *kobj,
                   enum kobject_action action,
                   struct attribute *attr);

The first parameter specifies the kobject that is emitting this signal. The actual kernel event will contain the sysfs path to which this kobject maps.

The second parameter specifies the action or verb describing this signal. The actual kernel event will contain a string that maps to the provided enum kobject_action value. Rather than directly provide the string, the function uses an enumeration to encourage value reuse, provide type safety, and prevent typos and other mistakes. The enumerations are defined in <linux/kobject_uevent.c> and have the form KOBJ_foo. Current values include KOBJ_MOUNT, KOBJ_UNMOUNT, KOBJ_ADD, KOBJ_REMOVE, and KOBJ_CHANGE. These values map to the strings “mount”, “unmount”, “add”, “remove”, and “change”, respectively. Adding new action values is acceptable, so long as an existing value is insufficient.

The final parameter is an optional pointer to an attribute structure. This can be seen as the “payload” of the event. If the action value is insufficient in describing the event, the event can point at a specific file in sysfs that provides more information.

This function allocates memory and thus can sleep. An atomic version is provided that is identical to the non-atomic variant, except that it allocates memory via GFP_ATOMIC:

int kobject_uevent_atomic(struct kobject *kobj,
                          enum kobject_action action,
                          struct attribute *attr);

Using the standard non-atomic interface is encouraged if possible. The parameters and behavior are otherwise the same between both functions.

Using kobjects and attributes not only encourages events that fit nicely in a sysfs-based world, but also encourages the creation of new kobjects and attributes to represent objects and data not yet exposed through sysfs.

Both these functions are defined in lib/kobject_uevent.c and declared in <linux/kobject_uevent.h>.

kobjects and sysfs in a Nutshell

This chapter looked at the device model, sysfs, kobjects, and the kernel event layer. But a discussion on these topics drags in a plethora of their friends: We had to touch also on ksets, subsystems, attributes, ktypes, and krefs, to name a few. These structures are of different uses to different people. Driver writers need only a peripheral view of these topics. Most driver subsystems nicely hide the internals of kobjects and their friends. Understanding the basics and perhaps interfaces such as sysfs_create_file() is enough for a driver writer. Developers working on the core kernel, however, may need a more in-depth understanding of kobjects. kobjects are becoming sufficiently important that many of their users may not be working on drivers or driver subsystems at all!

This chapter discussed the last subsystem in the kernel that we will cover. The following chapters cover general but important topics that every kernel developer need know. First off, debugging!

 



[1] If you find sysfs interesting, you might be interested in HAL, a hardware abstraction layer, which can be found at http://hal.freedesktop.org/. HAL builds an in-memory database based on the data in sysfs, linking together the concepts of class, device, and driver. On top of this data, HAL provides a rich API allowing for smarter, more aware applications.

[2] More information on D-BUS is available at http://dbus.freedesktop.org/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset