Object Management and Reference Counting

All over the kernel, the need to keep track of instances of C structures arises. Despite the fact that these objects will be used in the most varying forms, some operations are very similar across subsystems — just consider reference counting. This leads to code duplication. Since this is a bad thing, the kernel has adopted generic methods to manage kernel objects during the development of 2.5. The framework is, however, not just required to prevent code duplication. It also allows for providing a coherent view on objects managed by different parts of the kernel, and this information can be brought to good use in many parts of the kernel, for instance, for power management.

The generic kernel object mechanism can be used to perform the following operations on objects:

□ Reference counting

□ Management of lists (sets) of objects

□ Locking of sets

□ Exporting object properties into userspace (via the sysfs filesystem)

Generic Kernel Objects

The following data structure that is embedded in other data structures is used as a basis.

<kobject.h>

struct kobject {

const char struct kref struct list_head struct kobject struct kset struct kobj_type struct sysfs_dirent

* parent;

4Even if there is only one list element in the structure, this entry is used to find the correct start address of the instance by means of pointer arithmetic; the address is translated into the required data type by means of type conversion. I deal with this in more detail in the appendix on C programming.

It is essential that kobjects are not linked with other data structures by means of pointers but are directly embedded. Managing the kernel object itself amounts to managing the whole containing object this way. Since struct kobject is embedded into many data structures of the kernel, the developers take care to keep it small. Adding a single new element to this data structure results in a size increase of many other data structures. Embedded kernel objects look as follows:

struct sample {

struct kobject kobj;

The meanings of the individual elements of struct kobject are as follows:

□ k_name is a text name exported to userspace using sysfs. Sysfs is a virtual filesystem that allows for exporting various properties of the system into userspace. Likewise sd supports this connection, and I will come back to this in Chapter 10.

□ kref holds the general type struct kref designed to simplify reference management. I discuss this below.

□ entry is a standard list element used to group several kobjects in a list (known as a set in this case).

□ kset is required when an object is grouped with other objects in a set.

□ parent is a pointer to the parent element and enables a hierarchical structure to be established between kobjects.

□ ktype provides more detailed information on the data structure in which a kobject is embedded. Of greatest importance is the destructor function that returns the resources of the embedding data structure.

The similarity between the name kobject and the object concept of, well, object-oriented languages like C++ or Java is by no means coincidental: The kobject abstraction indeed allows for using object-oriented techniques in the kernel, but without requiring all the extra mechanics (and bloat, and overhead) of C++.

Table 1-1 lists the standard operations provided by the kernel to manipulate kobject instances, and therefore effectively act on the embedding structure.

The layout of the kref structure used to manage references is as follows:

struct kref {

atomic_t refcount;

refcount is an atomic data type to specify the number of positions in the kernel at which an object is currently being used. When the counter reaches 0, the object is no longer needed and can therefore be removed from memory.

Table 1-1: Standard Methods for Processing kobjects

Function

Meaning

kobject_

_get, kobject_put

Increments or decrements the reference counter of a kobj ect

kobject_

_(un)register

Registers or removes obj from a hierarchy (the object is added to the existing set (if any) of the parent element; a corresponding entry is created in the sysfs filesystem).

kobject_

init

Initializes a kobject; that is, it sets the reference counter to its initial value and initializes the list elements of the object.

kobect_add

Initializes a kernel object and makes it visible in sysfs

kobject_

_cleanup

Releases the allocated resources when a kobject (and therefore the embedding object) is no longer needed

Encapsulation of the single value in a structure was chosen to prevent direct manipulation of the value. kref_init must always be used for initialization. If an object is in use, kref_get must be invoked beforehand to increment the reference counter. kref_put decrements the counter when the object is no longer used.

Sets of Objects

In many cases, it is necessary to group different kernel objects into a set — for instance, the set of all character devices or the set of all PCI-based devices. The data structure provided for this purpose is defined as follows:

<kobject.h>

struct kset { struct struct struct struct

Interestingly, the kset serves as the first example for the use of kernel objects. Since the management structure for sets is nothing other than a kernel object, it can be managed via the previously discussed struct kobj. Indeed, an instance is embedded via kobj. It has nothing to do with the kobjects collected in the set, but only serves to manage the properties of the kset object itself.

The other members have the following meaning:

□ ktype points to a further object that generalizes the behavior of the kset.

□ list is used to build a list of all kernel objects that are a member of the set.

□ uevent_ops provides several function pointers to methods that relay information about the state of the set to userland. This mechanism is used by the core of the driver model, for instance, to format messages that inform about the addition of new devices.

kobj_type list head

kobject kobj;

kset_uevent_ops * uevent_ops;

Another structure is provided to group common features of kernel objects. It is defined as follows:

<kobject.h>

struct kobj_type {

struct sysfs_ops * sysfs_ops;

struct attribute ** default_attrs;

Note that a kobj_type is not used to collect various kernel objects — this is already managed by ksets. Instead, it provides an interface to the sysfs filesystem (discussed in Section 10.3). If multiple objects export similar information via the filesystem, then this can be simplified by using a single ktype to provide the required methods.

Reference Counting

Reference counting is used to detect from how many places in the kernel an object is used. Whenever one part of the kernel needs information contained in one object, it increments the reference count, and when it does not need the information anymore, the count is decremented. Once the count has dropped to 0, the kernel knows that the object is not required anymore, and that it is safe to release it from memory. The kernel provides the following data structure to handle reference counting:

struct kref {

atomic_t refcount;

The data structure is really simple in that it only provides a generic, atomic reference count. ''Atomic'' means in this context that incrementing and decrementing the variable is also safe on multiprocessor systems, where more than one code path can access an object at the same time. Chapter 5 discusses the need for this in more detail.

The auxiliary methods kref_init, kref_get, and kref_put are provided to initialize, increment, or decrement the reference counter. This might seem trivial at a first glance. Nevertheless, it helps to avoid excessive code duplication because such reference counts together with the aforementioned operations are used all over the kernel.

Although manipulating the reference counter this way is safe against concurrency issues, this does not imply that the surrounding data structure is safe against concurrent access! Kernel code needs to employ further means to ensure that access to data structures does not cause any problems when this can happen from multiple processors simultaneously, and I discuss these issues in Chapter 5.

Finally, notice that the kernel contains some documentation related to kernel objects in Documentation/ kobject.txt.

Continue reading here: Data Types

Was this article helpful?

0 0