Chinaunix首页 | 论坛 | 博客
  • 博客访问: 520217
  • 博文数量: 174
  • 博客积分: 4177
  • 博客等级: 上校
  • 技术积分: 1827
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-15 14:12
文章分类

全部博文(174)

文章存档

2018年(1)

2017年(1)

2013年(3)

2012年(9)

2010年(12)

2009年(5)

2008年(106)

2007年(37)

我的朋友

分类: LINUX

2008-11-11 17:52:49


// 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,


阅读(869) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~