Commit 351b11ab authored by Patrick Mochel's avatar Patrick Mochel

Update kobject documentation.

parent 33e86005
kobjects - Simple, Generic Kernel Objects
The kobject Infrastructure
Patrick Mochel <mochel@osdl.org>
30 October 2002
7 January 2003
0. Introduction
The kobject infrastructure performs basic object managment that larger
data structures and subsystems can leverage, rather than reimplement
similar functionality. This functionality consists primarily concerns:
- Object reference counting.
- Maintaining lists (sets) of objects.
- Object set locking.
- Userspace representation.
The infrastructure consists of a number of object types to support
this functionality. Their programming interfaces are described below
in detail, and briefly here:
- kobjects a simple object.
- kset a set of objects of a certain type.
- ktype a set of helpers for objects of a common type.
- subsystem a controlling object for a number of ksets.
The kobject infrastructure maintains a close relationship with the
sysfs filesystem. Each kobject that is registered with the kobject
core receives a directory in sysfs. Attributes about the kobject can
then be exported. Please see Documentation/filesystems/sysfs.txt for
more information.
The kobject infrastructure provides a flexible programming interface,
and allows kobjects and ksets to be used without being registered
(i.e. with no sysfs representation). This is also described later.
1. kobjects
1.1 Description
struct kobject introduces a simple, intregral datatype and a simple
set of semantics for operating on the device. kobjects are intended to
be embedded in larger data structures and replace fields it
duplicates. A set of library functions has been developed to assist in
the manipulation of kobjects.
struct kobject is a simple data type that provides a foundation for
more complex object types. It provides a set of basic fields that
almost all complex data types share. kobjects are intended to be
embedded in larger data structures and replace fields it duplicates.
1.2 Defintion
struct kobject {
char name[16];
char name[KOBJ_NAME_LEN];
atomic_t refcount;
struct list_head entry;
struct kobject * parent;
struct subsystem * subsys;
struct kset * kset;
struct kobj_type * ktype;
struct dentry * dentry;
};
......@@ -32,204 +64,276 @@ int kobject_add(struct kobject *);
int kobject_register(struct kobject *);
void kobject_del(struct kobject *);
void kobject_cleanup(struct kobject *);
void kobject_unregister(struct kobject *);
struct kobject * kobject_get(struct kobject *);
void kobject_put(struct kobject *);
1.3 kobject Programming Interface
2. subsystems
kobjects may be dynamically added and removed from the kobject core
using kobject_register() and kobject_unregister(). Registration
includes inserting the kobject in the list of its dominant kset and
creating a directory for it in sysfs.
2.1 Description
Alternatively, one may use a kobject without adding to its kset's list
or exporting it via sysfs, by simply calling kobject_init(). An
initialized kobject may later be added to the object hierarchy by
calling kobject_add(). An initialized kobject may be used for
reference counting.
struct subsystem is introduced to describe a collection of objects of
a certain type. subsystems are kobjects themselves, though they
contain lists of kobjects that belong to that subsystem. Objects of a
subsystem (the embedder objects in which kobjects live) are all of the
same type.
Note: calling kobject_init(), then kobject_add() is functionally
equivalent to calling kobject_register().
2.2 Definition
When a kobject is unregistered, it is removed from its kset's list,
removed from the sysfs filesystem, and its reference decremented. List
and sysfs removal happen in kobject_del(), and may be called
manually. kobject_put() decrements the reference count, and may also
be called manually.
struct subsystem {
struct kobject kobj;
A kobject's reference count may be incremented with kobject_get(),
which returns a valid reference to a kobject; and decremented with
kobject_put(). An object's reference count may only be incremented if
it is already positive.
When a kobject's reference count reaches 0, the method struct
ktype::release() (which the kobject's kset points to) is called. This
allows any memory allocated for the object to be freed.
1.4 sysfs
Each kobject receives a directory in sysfs. This directory is created
under the kobject's parent directory.
If a kobject does not have a parent when it is registered, its parent
becomes its dominant kset.
If a kobject does not have a parent nor a dominant kset, its directory
is created at the top-level of the sysfs partition. This should only
happen for kobjects that are embedded in a struct subsystem.
2. ksets
2.1 Desecription
A kset is a set of kobjects that are embedded in the same type.
struct kset {
struct subsystem * subsys;
struct kobj_type * ktype;
struct list_head list;
struct rw_semaphore rwsem;
struct subsystem * parent;
struct kobject kobj;
};
void kset_init(struct kset * k);
int kset_add(struct kset * k);
int kset_register(struct kset * k);
void kset_unregister(struct kset * k);
struct kset * kset_get(struct kset * k);
void kset_put(struct kset * k);
struct kobject * kset_find_obj(struct kset *, char *);
The type that the kobjects are embedded in is described by the ktype
pointer. The subsystem that the kobject belongs to is pointed to by
subsys pointer.
A kset contains a kobject itself, meaning that it may be registered in
the kobject hierarchy and exported via sysfs. More importantly, the
kset may be embedded in a larger data type, and may be part of another
kset (of that object type).
For example, a block device is an object (struct gendisk) that is
contained in a set of block devices. It may also contain a set of
partitions (struct hd_struct) that have been found on the device. The
following code snippet illustrates how to properly express this.
struct gendisk * disk;
...
disk->kset.kobj.kset = &block_kset;
disk->kset.ktype = &partition_ktype;
kset_register(&disk->kset);
- The kset that the disk's embedded object belongs to is the
block_kset, and is pointed to disk->kset.kobj.kset.
- The type of object of the disk's _subordinate_ list are partitions,
and is set in disk->kset.ktype.
- The kset is then registered, which handles initializing and adding
the embedded kobject to the hierarchy.
2.2 kset Programming Interface
All kset functions, except kset_find_obj(), eventually forward the
calls to their embedded kobjects after performing kset-specific
operations. ksets offer a similar programming model to kobjects: they
may be used after they are initialized, without registering them in
the hierarchy.
kset_find_obj() may be used to locate a kobject with a particular
name. The kobject, if found, is returned.
2.3 sysfs
ksets are represented in sysfs when their embedded kobjects are
registered. They follow the same rules of parenting, with one
exception. If a kset does not have a parent, nor is its embedded
kobject part of another kset, the kset's parent becomes it's dominant
subsystem.
If the kset does not have a parent, its directory is created at the
sysfs root. This should only happen when the kset registered is
embedded in a subsystem itself.
3. struct ktype
3.1. Description
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops;
struct attribute ** default_attrs;
};
void subsystem_init(struct subsystem *);
int subsystem_register(struct subsystem *);
void subsystem_unregister(struct subsystem *);
struct subsystem * subsys_get(struct subsystem * s);
void subsys_put(struct subsystem * s);
Object types require specific functions for converting between the
generic object and the more complex type. struct kobj_type provides
the object-specific fields, which include:
- release: Called when the kobject's reference count reaches 0. This
should convert the object to the more complex type and free it.
3. The Interface
- sysfs_ops: Provides conversion functions for sysfs access. Please
see the sysfs documentation for more information.
The kobject API provides a symmeticral interface that may be used in
one of two ways: by using the default front-end registration
interface, or by directly using the backend helpers the registration
interface uses.
- default_attrs: Default attributes to exported via sysfs when the
object is registered.
3.1 Default Usage
The default usage is to use kobjet_register() to add a device to the
object hierarchy, and kobject_unregister() to remove it.
Instances of struct kobj_type are not registered; only referenced by
the kset. A kobj_type may be referenced by an arbitrary number of
ksets, as their may be disparate sets of identical objects.
kobject_register() will call kobject_init() and kobject_add()
consecutively. kobject_init() will initialize the object and increment
the reference count of the subsystem the object belongs to. It will
leave the reference count of the object at 1.
kobject_add() will insert it into the object hierarchy and create
a sysfs directory for the object. This will increment the reference
count of the object, leaving it at 2.
kobject_unregister() will call kobject_del() and kobject_put()
consecutively. kobject_del() will remove the object from the hierarchy
and the sysfs directory for the object. It will decrement the
reference count for the object. Assuming there are no other users of
the object, it will be left at 1.
4. subsystems
kobject_put() will decrement the reference count of the object, and
when it reaches 0, call kobject_cleanup(). This will happen
immediately if there are no other users of the object.
kobject_cleanup() will call the subsystem's release() method
for the object, and decrement the subsystem's reference count.
4.1 Description
Because kobject_unregister() calls kobject_put(), instead of
kobject_cleanup() directly, when an object is unregistered, the
pointer to the object is guaranteed to remain valid until the last
reference to the object has gone away.
A subsystem represents a significant entity of code that maintains an
arbitrary number of sets of objects of various types. Since the number
of ksets, and the type of objects they contain, are variable, a
generic representation of a subsystem is minimal.
Users of objects should call kobject_get() to obtain a reference to
the object that they are using. If the object passed to it is a valid
object (i.e. still present in the system), it will return a pointer to
the object. Otherwise, it will return NULL.
When users are done using an object, they should call kobject_put() to
decrement the reference count on the object. As explained above, when
the reference count for the object reaches 0, kobject_cleanup() will
be called for the object.
struct subsystem {
struct kset kset;
struct rw_semaphore rwsem;
};
int subsystem_register(struct subsystem *);
void subsystem_unregister(struct subsystem *);
struct subsystem * subsys_get(struct subsystem * s);
void subsys_put(struct subsystem * s);
3.2 Backend Usage
A subsystem contains an embedded kset so:
Users of the kobject infrastructure may use the backend functions
directly. In order to maintain consistency and reduce confusion, users
of the interface should use only the front end registration-oriented
interface, or the backend helpers.
- It can be represented in the object hierarchy via the kset's
embedded kobject.
Using the backend helpers allows code to use the kobjects solely for
the reference counting and garbage collection mechanisms, and
optionally adding them to the object hierarchy or exporting them via
sysfs.
- It can maintain a default list of objects of one type.
To take advantage of this side of the interface, users should call
kobject_init() to initialize the object. As stated above, this will
leave the reference count of the object at 1, and will enable the
subsystem to use the reference count of the object.
Additional ksets may attach to the subsystem simply by referencing the
subsystem before they are registered. (This one-way reference means
that there is no way to determine the ksets that are attached to the
subsystem.)
When the life of the object is ending, the kobject_put() should be
called to decrement the reference count of the object. Just like
above, this will call kobject_cleanup() when the reference count
reaches 0, and release() method of the object's subsystem will be
called.
All ksets that are attached to a subsystem share the subsystem's R/W
semaphore.
During the lifetime of the object, kobject_add() and kobject_del() may
be called to add the object to the hierarchy and export it via
sysfs. kobject_del() must always be called if kobject_add() has
previously been called. Care should be taken to ensure kobject_del()
is called before the final kobject_put() is called, though not doing
so will not cause catastrophe, only confusion when reading the source
code. Fatal results are avoided by having kobject_add() increment the
reference count of the object, for kobject_del() to decrement.
4.2 Programming Interface.
3.3 Summary
The subsystem programming interface is simple and does not offer the
flexibility that the kset and kobject programming interfaces do. They
may be registered and unregistered, as well as reference counted. Each
call forwards the calls to their embedded ksets (which forward the
calls to their embedded kobjects).
Using either interface, users should obtain the same results. The
registration interface does the same actions as the backend interface,
though it guarantees that initialization and addition, and deletion
and cleanup, happen consecutively.
4.3 Helpers
Familial Relations
A number of macros are available to make dealing with subsystems, and
their embedded objects easier.
kobjects and subsystems intersect and intertwine in several ways. Each
is well-defined (though maybe they could be made simpler). Each kobject
belongs to a subsystem. Since subsystems are kobjects themselves, they
also belong to a controlling subsystem. This implies that subsystems
are hierarchial.
Many kobjects are hierarchial in nature, which is represented by
including a pointer to its parent kobject in struct kobject. Many
different types of kobject-embedding objects may all point to the same
parent.
decl_subsys(name,type)
The ancestral hierarchy of kobjects should not be confused with
membership in a subsystem, or the ancestral relationship of
subsystems. A set of kobjects may all belong to a subsystem, but all
have different parents.
Declares a subsystem named '<name>_subsys', with an embedded kset of
type <type>. For example,
kobjects may be orphans and have no explicit parent. In that case, the
subsystem to which the object belongs becomes its parent.
decl_subsys(devices,&ktype_devices);
is equivalent to doing:
struct subsystem device_subsys = {
.kset = {
.kobj = {
.name = "devices",
},
.ktype = &ktype_devices,
}
};
Sysfs
These rules force a complete kobject hierarchy, which Suprise! maps
very well onto a filesystem.
The objects that are registered with a subsystem that use the
subsystem's default list must have their kset ptr set properly. These
objects may have embedded kobjects, ksets, or other subsystems. The
following helpers make setting the kset easier:
driverfs was recently cloned, and there now exists sysfs. All driverfs
operations operate on a separate data type: struct driver_dir_entry,
which all objects that are represented in driverfs must have. driverfs
also allowed rogue directory creation that had no explicit objects
associated with them.
struct kobject is intended to be the common data type which sysfs
operates on. This gives the filesystem the ability to directly access
more fields of the object, including the reference count. This also
forces each directory in the filesystem to be tied directly to a
kobject.
kobj_set_kset_s(obj,subsys)
- Assumes that obj->kobj exists, and is a struct kobject.
- Sets the kset of that kobject to the subsystem's embedded kset.
Directory Placement
Parental relationships are determined in the kobject/subsystem layer,
and the kobject is then passed off to the sysfs layer. kobjects with
no parent have directories created for them in the sysfs root
directory. Per the rules above, the only kobjects that remain orphans
are subsystems without parent subsystems (since leaf objects either
have an explicit parent, or are assigned their controlling subsystem
as their foster parent).
kset_set_kset_s(obj,subsys)
- Assumes that obj->kset exists, and is a struct kset.
- Sets the kset of the embedded kobject to the subsystem's
embedded kset.
File Callbacks
subsys_set_kset(obj,subsys)
Previously, each driverfs directory contained a pointer to a list of file
operations for reading and writing driverfs files. These callbacks
received a struct driver_dir_entry, when they performed a
container_of() transform on to receive the specific object type for
which the call was meant.
- Assumes obj->subsys exists, and is a struct subsystem.
- Sets obj->subsys.kset.kobj.kset to the subsystem's embedded kset.
These callbacks have been converted to accept a struct kobject instead
of struct driver_dir_entry. Since all kobjects belong to a subsystem
that contains kobjects all of the same type, the sysfs operations
have been moved to reside in the subsystem, since they are common for
all kobjects.
4.4 sysfs
Default Attributes
subsystems are represented in sysfs via their embedded kobjects. They
follow the same rules as previously mentioned with no exceptions. They
typically receive a top-level directory in sysfs, except when their
embedded kobject is part of another kset, or the parent of the
embedded kobject is explicitly set.
Most subsystems have a set of default attributes associated with an
object that registers with them. A subsystem definition may contain a
NULL-terminated array of attributes that will be exported when an
object is registered with the subsystem.
Note that the subsystem's embedded kset must be 'attached' to the
subsystem itself in order to use its rwsem. This is done after
kset_add() has been called. (Not before, because kset_add() uses its
subsystem for a default parent if it doesn't already have one).
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment