The kobject Infrastructure

Patrick Mochel <mochel@osdl.org>

Updated: 3 June 2003


Copyright (c)  2003 Patrick Mochel
Copyright (c)  2003 Open Source Development Labs


0. Introduction

The kobject infrastructure performs basic object management that larger
data structures and subsystems can leverage, rather than reimplement
similar functionality. This functionality 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. 


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 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 they duplicate. 

1.2 Definition

struct kobject {
	const 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 sysfs_dirent	* sd;
	wait_queue_head_t	poll;
};

void kobject_init(struct kobject *);
int kobject_add(struct kobject *);
int kobject_register(struct kobject *);

void kobject_del(struct kobject *);
void kobject_unregister(struct kobject *);

struct kobject * kobject_get(struct kobject *);
void kobject_put(struct kobject *);


1.3 kobject Programming Interface

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.

Alternatively, one may use a kobject without adding it 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.

Note: calling kobject_init() then kobject_add() is functionally
equivalent to calling kobject_register().

When a kobject is unregistered, it is removed from its kset's list,
removed from the sysfs filesystem, and its reference count is 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. 

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
kobj_type::release() (which the kobject's kset points to) is called.
This allows any memory allocated for the object to be freed.


NOTE!!! 

It is _imperative_ that you supply a destructor for dynamically
allocated kobjects to free them if you are using kobject reference
counts. The reference count controls the lifetime of the object.
If it goes to 0, then it is assumed that the object will
be freed and cannot be used. 

More importantly, you must free the object there, and not immediately
after an unregister call. If someone else is referencing the object
(e.g. through a sysfs file), they will obtain a reference to the
object, assume it's valid and operate on it. If the object is
unregistered and freed in the meantime, the operation will then
reference freed memory and go boom. 

This can be prevented, in the simplest case, by defining a release
method and freeing the object from there only. Note that this will not
secure reference count/object management models that use a dual
reference count or do other wacky things with the reference count
(like the networking layer). 


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.



2. ksets

2.1 Description

A kset is a set of kobjects that are embedded in the same type. 


struct kset {
	struct kobj_type	* ktype;
	struct list_head	list;
	struct kobject		kobj;
	struct kset_uevent_ops	* uevent_ops;
};


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.

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 express this properly.

	 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 by disk->kset.kobj.kset. 

- The type of objects on 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. 

There are also some helper functions which names point to the formerly
existing "struct subsystem", whose functions have been taken over by
ksets.


decl_subsys(name,type,uevent_ops)

Declares a kset named '<name>_subsys' of type <type> with
uevent_ops <uevent_ops>. For example,

decl_subsys(devices, &ktype_device, &device_uevent_ops);

is equivalent to doing:

struct kset devices_subsys = {
     .kobj = {
	   .name = "devices",
     },
     .ktype = &ktype_devices,
     .uevent_ops = &device_uevent_ops,
};


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 or ksets. The
following helpers make setting the kset easier:


kobj_set_kset_s(obj,subsys)

- Assumes that obj->kobj exists, and is a struct kobject.
- Sets the kset of that kobject to the kset <subsys>.


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 kset <subsys>.

subsys_set_kset(obj,subsys)

- Assumes obj->subsys exists, and is a struct subsystem.
- Sets obj->subsys.kset.kobj.kset to the subsystem's embedded kset.

void subsystem_init(struct kset *s);
int subsystem_register(struct kset *s);
void subsystem_unregister(struct kset *s);
struct kset *subsys_get(struct kset *s);
void kset_put(struct kset *s);

These are just wrappers around the respective kset_* functions.

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 its 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;
};


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. 

- sysfs_ops: Provides conversion functions for sysfs access. Please
  see the sysfs documentation for more information. 

- default_attrs: Default attributes to be exported via sysfs when the
  object is registered.Note that the last attribute has to be
  initialized to NULL ! You can find a complete implementation
  in block/genhd.c


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 there may be disparate sets of identical objects. 

