欢迎访问电子工程网!   登录 | 免费注册 ]   

linux_Ultra的个人空间 http://www.eechina.com/space-uid-2909.html [收藏] [复制] [分享] [RSS]

博客

Everything you never wanted to know about kobjects

已有 1020 次阅读2010-4-23 20:59 | 关键词:

Everything you never wanted to know about kobjects, ksets,

and ktypes
Greg Kroah-Hartman <gregkh@suse.de>
Based on an original article by Jon Corbet for lwn.net written

October 1, 2003 and located at

http://lwn.net/Articles/51437/
Last updated December 19, 2007

Part of the difficulty in understanding the driver model - and

the kobject abstraction upon which it is built - is that there is

no obvious starting place.

Dealing with kobjects requires understanding a few different

types, all of which make reference to each other.

In an attempt to make things easier, we'll take a multi-pass

approach, starting with vague terms and adding detail as we

go. To that end, here are some quick definitions of some

terms we will be working with.//先入门,看看kobject有什么特

点:

object----就是对象,实物。

 - A kobject is an object of type struct kobject.
 Kobjects have a name and a reference count.
1----一个kobject有名字。
 A kobject also has a parent pointer (allowing objects to be

arranged into hierarchies), a specific type, and,
   usually, a representation in the sysfs virtual filesystem.
2----一个kobject有一个父亲指针,让一个个kobject可以串起来。
一个有点特殊的类型,通常被显示在/sys 目录下。

   Kobjects are generally not interesting on their own;

instead, they are usually embedded within some other

structure which contains the stuff the code is really interested

in.
3----kobject很少单独使用,他常常把自己放在别的结构体中。

   No structure should EVER have more than one kobject

embedded within it. If it does, the reference counting for the

object is sure to be messed up and incorrect, and your code

will be buggy.  So do not do this.
4---结构体里最多能用一个kobject,如果你要用2个或两个以上。
你的代码将会出问题,所以请不要这样做。

 - A ktype is the type of object that embeds a kobject.  Every

structure that embeds a kobject needs a corresponding ktype.

 The ktype controls what happens to the kobject when it is

created and destroyed.
5---ktype是一个插在kobject里的类型。

 - A kset is a group of kobjects. 

6--kset是kobject组成的一个组。到kset是怎么
被组成kobject的,这个是由kset core这个模块来做的
我们不用操心。

These kobjects can be of the same ktype or belong to

different ktypes. 

The kset is the basic container type for collections of

kobjects.
 Ksets contain their own kobjects, but you can safely ignore

that implementation detail as the kset core code handles this

kobject automatically.


   When you see a sysfs directory full of other directories,

generally each of those directories corresponds to a kobject

in the same kset.
一个/xxx下的所有目录组成一个kset,他们属于同一个kset。
比如/sys这个目录下。

We'll look at how to create and manipulate all of these types.

A bottom-up approach will be taken, so we'll go back to

kobjects.
我们从下到上来示范一下。

Embedding kobjects
It is rare for kernel code to create a standalone kobject, with

one major exception explained below.

Instead, kobjects are used to control access to a larger,

domain-specific object. 
kobject很少单独使用,但他常常被用于别的object。
To this end, kobjects will be found embedded in other

structures.

 If you are used to thinking of things in objectoriented terms,

kobjects can be seen as a top-level, abstract class from

which other classes are derived.---这里说kobject有点面向对象

的味道。



A kobject implements a set of capabilities which are not

particularly useful by themselves, but which are nice to have

in other objects.---再次强调koject集合了很多东西,常常被别的

object使用。
 

 The C language does not allow for the direct expression of

inheritance, so other techniques - such as structure

embedding - must be used.

So, for example, the UIO code has a structure that defines

the memory region associated with a uio device:

struct uio_mem {
    struct kobject kobj;----embedded 一个kobject
    unsigned long addr;
    unsigned long size;
    int memtype;
    void __iomem *internal_addr;
         };

If you have a struct uio_mem structure, finding its embedded

kobject is just a matter of using the kobj member. ---这么声

明一个结构体,就好比一个物体使用了一个kobject。

 Code that
works with kobjects will often have the opposite problem,

however: given a struct kobject pointer, what is the pointer

to the containing structure? --关于使用kobject指针的问题。

 You must avoid tricks (such as assuming that the kobject is

at the beginning of the structure) and, instead, use the

container_of() macro, found in <linux/kernel.h>:
    container_of(pointer, type, member)---宏函数来操作

这个kobject指针。


where pointer is the pointer to the embedded kobject,
type is the type of the containing structure,
and member is the name of the structure field to which

pointer points. 

The return value from container_of() is a pointer to the given

type. So, for example, a pointer "kp" to a struct kobject

embedded within a struct uio_mem could be converted to a

pointer to the containing uio_mem structure with:
    struct uio_mem *u_mem = container_of(kp, struct

uio_mem, kobj);
Programmers often define a simple macro for "back-casting"

kobject pointers to the containing type.
---对于像这些复杂的结构体,一般都是用一个宏函数来操作。


Initialization of kobjects---初始化kobject

Code which creates a kobject must, of course, initialize that

object. Some of the internal fields are setup with a

(mandatory) call to kobject_init():
    void kobject_init(struct kobject *kobj, struct kobj_type

*ktype);----用kobject_init( )来初始化一个kobject。

The ktype is required for a kobject to be created properly, as

every kobject must have an associated kobj_type.  After

calling kobject_init(), to register the kobject with sysfs, the

function kobject_add() must be called:
    int kobject_add(struct kobject *kobj, struct kobject

*parent, const char *fmt, ...);---kobject_init( )执行后,就调用
kobject_add( )来注册到/sys 目录下。


This sets up the parent of the kobject and the name for the

kobject properly.  If the kobject is to be associated with a

specific kset, kobj->kset must be assigned before calling

kobject_add().  If a kset is associated with a kobject, then

the parent for the kobject can be set to NULL in the call to

kobject_add() and then the kobject's parent will be the kset

itself.----调用kobject_add( )前还要分成几种情况处理。


As the name of the kobject is set when it is added to the

kernel, the name of the kobject should never be manipulated

directly.  If you must change the name of the kobject, call

kobject_rename():
    int kobject_rename(struct kobject *kobj, const char

*new_name);
kobject_rename does not perform any locking or have a solid

notion of what names are valid so the caller must provide

their own sanity checking and serialization.---关于kobject的名

字的处理。

There is a function called kobject_set_name() but that is

legacy cruft and is being removed.  If your code needs to call

this function, it is incorrect and needs to be fixed.--不能使用

旧的kobject名字处理函数。


To properly access the name of the kobject, use the function

kobject_name():
    const char *kobject_name(const struct kobject * kobj);
There is a helper function to both initialize and add the

kobject to the kernel at the same time, called surprisingly

enough kobject_init_and_add():
    int kobject_init_and_add(struct kobject *kobj, struct

kobj_type *ktype, struct kobject *parent, const char *fmt,

...);----一个集合了两个功能的函数。


The arguments are the same as the individual kobject_init()

and kobject_add() functions described above.
------------------嗯,kobject说完了吧,头晕没,休息会,然后回

头再从头看一遍。

下面准备将Uevents了。
Uevents
After a kobject has been registered with the kobject core, you

need to announce to the world that it has been created.  This

can be done with a call to kobject_uevent():
    int kobject_uevent(struct kobject *kobj, enum

kobject_action action);
Use the KOBJ_ADD action for when the kobject is first added

to the kernel. This should be done only after any attributes or

children of the kobject have been initialized properly, as

userspace will instantly start to look for them when this call

happens.
When the kobject is removed from the kernel (details on how

to do that is below), the uevent for KOBJ_REMOVE will be

automatically created by the kobject core, so the caller does

not have to worry about doing that by hand.
Reference counts
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 which 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_put(struct kobject *kobj);
A successful call to kobject_get() will increment the kobject's

reference counter and return the pointer to the kobject.
When a reference is released, the call to kobject_put() will

decrement the reference count and, possibly, free the object.

Note that kobject_init() sets the reference count to one, so

the code which sets up the kobject will need to do a

kobject_put() eventually to release that reference.
Because kobjects are dynamic, they must not be declared

statically or on the stack, but instead, always allocated

dynamically.  Future versions of the kernel will contain a run

-time check for kobjects that are created statically and will

warn the developer of this improper usage.
If all that you want to use a kobject for is to provide a

reference counter for your structure, please use the struct

kref instead; a kobject would be overkill.  For more

information on how to use struct kref, please see the file

Documentation/kref.txt in the Linux kernel source tree.
Creating "simple" kobjects
Sometimes all that a developer wants is a way to create a

simple directory in the sysfs hierarchy, and not have to mess

with the whole complication of ksets, show and store

functions, and other details.  This is the one exception where

a single kobject should be created.  To create such an entry,

use the function:
    struct kobject *kobject_create_and_add(char *name,

struct kobject *parent);
This function will create a kobject and place it in sysfs in the

location underneath the specified parent kobject.  To create

simple attributes associated with this kobject, use:
    int sysfs_create_file(struct kobject *kobj, struct attribute

*attr); or int sysfs_create_group(struct kobject *kobj, struct

attribute_group *grp);
Both types of attributes used here, with a kobject that has

been created with the kobject_create_and_add(), can be of

type kobj_attribute, so no special custom attribute is needed

to be created.
See the example module, samples/kobject/kobject-example.c

for an implementation of a simple kobject and attributes.
ktypes and release methods
One important thing still missing from the discussion is what

happens to a kobject when its reference count reaches zero.

The code which created the kobject generally does not know

when that will happen; if it did, there would be little point in

using a kobject in the first place. Even predictable object

lifecycles become more complicated when sysfs is brought in

as other portions of the kernel can get a reference on any

kobject that is registered in the system.
The end result is that a structure protected by a kobject

cannot be freed before its reference count goes to zero. The

reference count is not under the direct control of the code

which created the kobject. So that code must be notified

asynchronously whenever the last reference to one of its

kobjects goes away.
Once you registered your kobject via kobject_add(), you

must never use kfree() to free it directly. The only safe way

is to use kobject_put(). It is good practice to always use

kobject_put() after kobject_init() to avoid errors creeping in.
This notification is done through a kobject's release()

method. Usually such a method has a form like:
    void my_object_release(struct kobject *kobj)
    { struct my_object *mine = container_of(kobj, struct

my_object, kobj);
        /* Perform any additional cleanup on this object,

then... */
        kfree(mine); }
One important point cannot be overstated: every kobject

must have a release() method, and the kobject must persist

(in a consistent state) until that method is called. If these

constraints are not met, the code is flawed.  Note that the

kernel will warn you if you forget to provide a release()

method.  Do not try to get rid of this warning by providing an

"empty" release function; you will be mocked mercilessly by

the kobject maintainer if you attempt this.
Note, the name of the kobject is available in the release

function, but it must NOT be changed within this callback. 

Otherwise there will be a memory leak in the kobject core,

which makes people unhappy.
Interestingly, the release() method is not stored in the

kobject itself; instead, it is associated with the ktype. So let

us introduce struct kobj_type:
    struct kobj_type { void (*release)(struct kobject *);
        struct sysfs_ops    *sysfs_ops;
        struct attribute    **default_attrs; };
This structure is used to describe a particular type of kobject

(or, more correctly, of containing object). Every kobject

needs to have an associated kobj_type structure; a pointer to

that structure must be specified when you call kobject_init()

or kobject_init_and_add().
The release field in struct kobj_type is, of course, a pointer

to the release() method for this type of kobject. The other

two fields (sysfs_ops and default_attrs) control how objects

of this type are represented in sysfs; they are beyond the

scope of this document.
The default_attrs pointer is a list of default attributes that will

be automatically created for any kobject that is registered

with this ktype.
ksets
A kset is merely a collection of kobjects that want to be

associated with each other.  There is no restriction that they

be of the same ktype, but be very careful if they are not.
A kset serves these functions:
 - It serves as a bag containing a group of objects. A kset can

be used by the kernel to track "all block devices" or "all PCI

device drivers."
 - A kset is also a subdirectory in sysfs, where the associated

kobjects with the kset can show up.  Every kset contains a

kobject which can be set up to be the parent of other

kobjects; the top-level directories of the sysfs hierarchy are

constructed in this way.
 - Ksets can support the "hotplugging" of kobjects and

influence how uevent events are reported to user space.
In object-oriented terms, "kset" is the top-level container

class; ksets contain their own kobject, but that kobject is

managed by the kset code and should not be manipulated by

any other user.
A kset keeps its children in a standard kernel linked list. 

Kobjects point back to their containing kset via their kset

field. In almost all cases, the kobjects belonging to a kset

have that kset (or, strictly, its embedded kobject) in their

parent.
As a kset contains a kobject within it, it should always be

dynamically created and never declared statically or on the

stack.  To create a new kset use: struct kset

*kset_create_and_add(const char *name, struct

kset_uevent_ops *u,
                   struct kobject

*parent);
When you are finished with the kset, call: void

kset_unregister(struct kset *kset); to destroy it.
An example of using a kset can be seen in the

samples/kobject/kset-example.c file in the kernel tree.
If a kset wishes to control the uevent operations of the

kobjects associated with it, it can use the struct

kset_uevent_ops to handle it:
struct kset_uevent_ops { int (*filter)(struct kset *kset, struct

kobject *kobj);
        const char *(*name)(struct kset *kset, struct kobject

*kobj); int (*uevent)(struct kset *kset, struct kobject *kobj,

struct kobj_uevent_env *env); };
The filter function allows a kset to prevent a uevent from

being emitted to userspace for a specific kobject.  If the

function returns 0, the uevent will not be emitted.
The name function will be called to override the default name

of the kset that the uevent sends to userspace.  By default,

the name will be the same as the kset itself, but this

function, if present, can override that name.
The uevent function will be called when the uevent is about

to be sent to userspace to allow more environment variables

to be added to the uevent.
One might ask how, exactly, a kobject is added to a kset,

given that no functions which perform that function have

been presented.  The answer is that this task is handled by

kobject_add().  When a kobject is passed to kobject_add(),

its kset member should point to the kset to which the kobject

will belong.  kobject_add() will handle the rest.
If the kobject belonging to a kset has no parent kobject set,

it will be added to the kset's directory.  Not all members of a

kset do necessarily live in the kset directory.  If an explicit

parent kobject is assigned before the kobject is added, the

kobject is registered with the kset, but added below the

parent kobject.
Kobject removal
After a kobject has been registered with the kobject core

successfully, it must be cleaned up when the code is finished

with it.  To do that, call kobject_put().  By doing this, the

kobject core will automatically clean up all of the memory

allocated by this kobject.  If a KOBJ_ADD uevent has been

sent for the object, a corresponding KOBJ_REMOVE uevent

will be sent, and any other sysfs housekeeping will be

handled for the caller properly.
If you need to do a two-stage delete of the kobject (say you

are not allowed to sleep when you need to destroy the

object), then call kobject_del() which will unregister the

kobject from sysfs.  This makes the kobject "invisible", but it

is not cleaned up, and the reference count of the object is

still the same.  At a later time call kobject_put() to finish the

cleanup of the memory associated with the kobject.
kobject_del() can be used to drop the reference to the parent

object, if circular references are constructed.  It is valid in

some cases, that a parent objects references a child.  Circular

references _must_ be broken with an explicit call to

kobject_del(), so that a release functions will be called, and

the objects in the former circle release each other.
Example code to copy from
For a more complete example of using ksets and kobjects

properly, see the sample/kobject/kset-example.c code.

路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

全部作者的其他博客

回顶部