// init/main.c
/*
* Ok, the machine is now initialized. None of the devices
* have been touched yet, but the CPU subsystem is up and
* running, and memory and process management works.
*
* Now we can finally start doing some real work..
*/
static void __init do_basic_setup(void)
{
/* drivers will send hotplug events */
init_workqueues(); // kernel/workqueue.c
usermodehelper_init();
driver_init(); //drivers/base/init.c
#ifdef CONFIG_SYSCTL
sysctl_init();
#endif
do_initcalls();
}
//drivers/base/init.c
/**
* driver_init - initialize driver model.
*
* Call the driver model init functions to initialize their
* subsystems. Called early from init/main.c.
*/
void __init driver_init(void)
{
/* These are the core pieces */
devices_init(); //drivers/base/core.c
buses_init();
classes_init();
firmware_init();
/* These are also core pieces, but must come after the
* core core pieces.
*/
platform_bus_init();
system_bus_init();
cpu_dev_init();
memory_dev_init();
attribute_container_init();
}
//drivers/base/core.c
int __init devices_init(void)
{
return subsystem_register(&devices_subsys); //lib/kobject.c
}
这里的devices_subsys定义于 drivers/base/core.c,如下所示:
//devices_subsys - structure to be registered with kobject core.
decl_subsys(devices, &ktype_device, &device_uevent_ops);
其中 decl_subsys是一个宏,定义于 include/linux/kobject.h中,如下所示:
#define decl_subsys(_name,_type,_uevent_ops) \
struct subsystem _name##_subsys = { \
.kset = { \
.kobj = { .name = __stringify(_name) }, \
.ktype = _type, \
.uevent_ops =_uevent_ops, \
} \
}
其中的__stringify()也是一个宏,定义于include/linux/stringify.h,如下所示:
#ifndef __LINUX_STRINGIFY_H
#define __LINUX_STRINGIFY_H
/* Indirect stringification. Doing two levels allows the parameter to be a
* macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
* converts to "bar".
*/
#define __stringify_1(x) #x
#define __stringify(x) __stringify_1(x)
"#"的作用是把宏参数转换成字符串,因此 __stringify(x) <===> "x"
需要注意的是,这里用了两层,原因可以查看博客上面C/C++里面<>
#endif /* !__LINUX_STRINGIFY_H */
把它代入即得到
struct subsystem devices_subsys = {
.kset = {
.kobj = { .name = "devices" },
.ktype = &ktype_device,
.uevent_ops = &device_uevent_ops,
}
}
其中 ktype_device和device_uevent_ops以及对应的dev_sysfs_ops均位于drivers/base/core.c,里面主要是指定了一些回调函数,如下所示:
static struct kobj_type ktype_device = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops,
};
static struct kset_uevent_ops device_uevent_ops = {
.filter = dev_uevent_filter,
.name = dev_uevent_name,
.uevent = dev_uevent,
};
static struct sysfs_ops dev_sysfs_ops = {
.show = dev_attr_show,
.store = dev_attr_store,
};
定义了这个变量之后,但相当于定义了一个子系统,名字就是devices,对应于/sys下面的devices目录。
现在我们可以调用subsystem_register()来对该子系统进行注册,首先来看一下这个注册函数,如下所示:
//lib/kobject.c
/**
* subsystem_register - register a subsystem.
* @s: the subsystem we're registering.
*
* Once we register the subsystem, we want to make sure that
* the kset points back to this subsystem for correct usage of
* the rwsem.
*/
int subsystem_register(struct subsystem * s)
{
int error;
subsystem_init(s);
pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
if (!(error = kset_add(&s->kset))) {
if (!s->kset.subsys)
s->kset.subsys = s;
}
return error;
}
先来看第一句,subsystem_init(),它也定义于lib/kobject.c中,它的参数是一个struct subsystem,定义于include/linux/kobject.h,如下所示:
// include/linux/kobject.h:
struct subsystem {
struct kset kset;
struct rw_semaphore rwsem;
};
// lib/kobject.c
void subsystem_init(struct subsystem * s)
{
init_rwsem(&s->rwsem); //初始化读写信号锁
kset_init(&s->kset); //初始化子系统的kset
}
该函数只有两行,第一行只是对subsystem 内部的读写信号锁进行初始化,然后对kset进行初始化。kset的定义及其初始化函数如下所示:
// include/linux/kobject.h:
struct kset {
struct subsystem * subsys;
struct kobj_type * ktype;
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
struct kset_uevent_ops * uevent_ops;
};
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops;
struct attribute ** default_attrs;
};
struct subsys_attribute {
struct attribute attr;
ssize_t (*show)(struct subsystem *, char *);
ssize_t (*store)(struct subsystem *, const char *, size_t);
};
// include/linux/sysfs.h
struct attribute {
const char * name;
struct module * owner;
mode_t mode;
};
// lib/kobject.c:
/**
* kset_init - initialize a kset for use
* @k: kset
*/
void kset_init(struct kset * k)
{
kobject_init(&k->kobj); //初始化kset内部所包含的kobject
INIT_LIST_HEAD(&k->list); //将kset的list的prev和next指针都指向list
spin_lock_init(&k->list_lock); //初始化kset中的自旋锁
}
kset_init调用kobjct_init来对kset内部的kobj成员进行初始化,并将kset的list的prev和next指针都指向list,最后再初始化kset中的自旋锁list_lock,由于之前在devices_subsys定义的时候已经对ktype和uevent_ops进行了赋值,因此,进行到这一步,实际上kset内部的各个成员实际上只有subsys成员“没有”进行初始化,不过,我们现在还没有仔细分析kobject_init()函数呢。
kobject和kobject_init()定义如下:
// include/linux/kobject.h:
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 dentry * dentry;
};
// lib/kobject.c:
/**
* kobject_init - initialize object.
* @kobj: object in question.
*/
void kobject_init(struct kobject * kobj)
{
kref_init(&kobj->kref); //将kobj的引用计数设置为1
INIT_LIST_HEAD(&kobj->entry); //将kobj的entry的prev和next指针都指向entry
kobj->kset = kset_get(kobj->kset); //将kobj所属的kobject的引用计数加1
}
在devices_subsys定义的时候已经对kobject的.name成员赋值为“devices”,kref_init()将kobj的引用计数设置为1,INIT_LIST_HEAD(&kobj->entry)将kobj的entry的prev和next指针都指向entry,最后来设置kobj的kset成员,首先来看用到的几个函数,如下所示:
// lib/kobject.c:
static inline struct kset * to_kset(struct kobject * kobj)
{
return kobj ? container_of(kobj,struct kset,kobj) : NULL;
}
static inline struct kset * kset_get(struct kset * k)
{
return k ? to_kset(kobject_get(&k->kobj)) : NULL;
}
/**
* kobject_get - increment refcount for object.
* @kobj: object.
*/
struct kobject * kobject_get(struct kobject * kobj)
{
if (kobj)
kref_get(&kobj->kref);
return kobj;
}
由于定义的时候我们并没有对devices_subsys.kset.kobj->kset进行赋值,所以我们假设它为NULL,这样的话,经过kset_get()之后,它的值依然为NULL。至此,对devices_subsys的初始化暂告一段落,目前还有一部分成员未进行初始化,即kobject的k_name、parent、kobj_type和dentry成员。对于k_name,其实它也是用来存放kobject的名字的,不过一般情况下,如果名字长度比较短,能够存放在name[]中的话,就直接存放在name[]中,否则的话,再申请一块内存来存放名字,并用k_name一指向这块内存。
至此,我们总算完成了subsystem_init()函数的分析,我们继续往下分析,再把代码贴出来,如下所示:
int subsystem_register(struct subsystem * s)
{
int error;
subsystem_init(s);
pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
if (!(error = kset_add(&s->kset))) {
if (!s->kset.subsys)
s->kset.subsys = s;
}
return error;
}
首先打印一条高度信息,然后调用kset_add(),它的定义如下:
/**
* kset_add - add a kset object to the hierarchy.
* @k: kset.
*
* Simply, this adds the kset's embedded kobject to the
* hierarchy.
* We also try to make sure that the kset's embedded kobject
* has a parent before it is added. We only care if the embedded
* kobject is not part of a kset itself, since kobject_add()
* assigns a parent in that case.
* If that is the case, and the kset has a controlling subsystem,
* then we set the kset's parent to be said subsystem.
*/
int kset_add(struct kset * k)
{
if (!k->kobj.parent && !k->kobj.kset && k->subsys)
k->kobj.parent = &k->subsys->kset.kobj;
return kobject_add(&k->kobj);
}
由上可知,devices_subsys.kset.kobject的parent和kset都为NULL,devices_subsys.kset的subsys也为NULL,因此,这里直接调用kobject_add(),其定义如下:
/**
* kobject_add - add an object to the hierarchy.
* @kobj: object.
*/
int kobject_add(struct kobject * kobj)
{
int error = 0;
struct kobject * parent;
if (!(kobj = kobject_get(kobj)))
return -ENOENT;
if (!kobj->k_name)
kobj->k_name = kobj->name;
if (!kobj->k_name) {
pr_debug("kobject attempted to be registered with no name!\n");
WARN_ON(1);
return -EINVAL;
}
parent = kobject_get(kobj->parent);
pr_debug("kobject %s: registering. parent: %s, set: %s\n",
kobject_name(kobj), parent ? kobject_name(parent) : "",
kobj->kset ? kobj->kset->kobj.name : "" );
if (kobj->kset) {
spin_lock(&kobj->kset->list_lock);
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
list_add_tail(&kobj->entry,&kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
}
kobj->parent = parent;
error = create_dir(kobj);
if (error) {
/* unlink does the kobject_put() for us */
unlink(kobj);
if (parent)
kobject_put(parent);
}
return error;
}
首先增加kobject的引用计数,然后检查k_name是否为NULL,如果是的话,则将它指向name,然后再检查k_name的合法性,如果它还为空的话报错。然后调用kobject_get()来设置parent,为NULL。由于devices_subsys.kset.kobject.kset为NULL,因此,直接跳过if语句,然后将devices_subsys.kset.kobject.parent设置为之前的parent,然后调用create_dir(kobj)来创建目录。它的定义如下:
// lib/kobject.c:
static int create_dir(struct kobject * kobj)
{
int error = 0;
if (kobject_name(kobj)) {
error = sysfs_create_dir(kobj);
if (!error) {
if ((error = populate_dir(kobj)))
sysfs_remove_dir(kobj);
}
}
return error;
}
// include/linux/kobject.h:
static inline const char * kobject_name(const struct kobject * kobj)
{
return kobj->k_name;
}
kobject_name返回该kobject的名字,然后调用sysfs_create_dir(kobj),定义如下:
// fs/sysfs/dir.c:
/**
* sysfs_create_dir - create a directory for an object.
* @parent: parent parent object.
* @kobj: object we're creating directory for.
*/
int sysfs_create_dir(struct kobject * kobj)
{
struct dentry * dentry = NULL;
struct dentry * parent;
int error = 0;
BUG_ON(!kobj);
if (kobj->parent)
parent = kobj->parent->dentry;
else if (sysfs_mount && sysfs_mount->mnt_sb)
parent = sysfs_mount->mnt_sb->s_root;
else
return -EFAULT;
error = create_dir(kobj,parent,kobject_name(kobj),&dentry);
if (!error)
kobj->dentry = dentry;
return error;
}
BUG_ON的定义位于 include/asm-generic/bug.h,判断kobj是否为NULL;
// include/asm-generic/bug.h:
#ifdef CONFIG_BUG
#ifndef HAVE_ARCH_BUG
#define BUG() do { \
printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
panic("BUG!"); \
} while (0)
#endif
#ifndef HAVE_ARCH_BUG_ON
#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
#endif
如果kobj->parent不为NULL的话,则将kobj的父kobject的对应的dentry赋给parent,由于devices_subsys.kset.kobj.parent为NULL,所以这里不管。sysfs_mount定义于fs/sysfs/mount.c,并在fs/sysfs/sysfs.h中进行了声明,
// fs/sysfs/mount.c:
struct vfsmount *sysfs_mount;
// include/linux/mount.h:
struct vfsmount {
struct list_head mnt_hash;
struct vfsmount *mnt_parent; /* fs we are mounted on */
struct dentry *mnt_mountpoint; /* dentry of mountpoint */
struct dentry *mnt_root; /* root of the mounted tree */
struct super_block *mnt_sb; /* pointer to superblock */
struct list_head mnt_mounts; /* list of children, anchored here */
struct list_head mnt_child; /* and going through their mnt_child */
atomic_t mnt_count;
int mnt_flags;
int mnt_expiry_mark; /* true if marked for expiry */
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
struct list_head mnt_list;
struct list_head mnt_expire; /* link in fs-specific expiry list */
struct list_head mnt_share; /* circular list of shared mounts */
struct list_head mnt_slave_list;/* list of slave mounts */
struct list_head mnt_slave; /* slave list entry */
struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
struct namespace *mnt_namespace; /* containing namespace */
int mnt_pinned;
};
其中的struct super_block定义于include/linux/fs.h,也是一个巨型结构。
实际上就是将sysfs的顶层目录的dentry赋给了parent,然后调用create_dir(kobj,parent,kobject_name(kobj),&dentry)来创建该kobject对应的目录,定义如下所示:
// fs/sysfs/dir.c:
static int create_dir(struct kobject * k, struct dentry * p,
const char * n, struct dentry ** d)
{
int error;
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
mutex_lock(&p->d_inode->i_mutex);
*d = lookup_one_len(n, p, strlen(n));
if (!IS_ERR(*d)) {
error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR);
if (!error) {
error = sysfs_create(*d, mode, init_dir);
if (!error) {
p->d_inode->i_nlink++;
(*d)->d_op = &sysfs_dentry_ops;
d_rehash(*d);
}
}
if (error && (error != -EEXIST)) {
struct sysfs_dirent *sd = (*d)->d_fsdata;
if (sd) {
list_del_init(&sd->s_sibling);
sysfs_put(sd);
}
d_drop(*d);
}
dput(*d);
} else
error = PTR_ERR(*d);
mutex_unlock(&p->d_inode->i_mutex);
return error;
}
刚开始设置了文件创建的模式,这几个宏均定义于include/linux/stat.h,
阅读(903) | 评论(0) | 转发(0) |