[转]浅析/sys/class目录的创建流程

浅析/sys/class目录的创建流程

/sys/class目录创建成功之后,其他的driver就可以调用
struct class *class_create(struct module *owner, const char *name);
int class_register(struct class *cls);
成功向class添加自己的目录和attr文件了.

   因为sysfs是一个内存文件系统,所以文件的物理存储关系就需要使用sd来维护,因此sysfs_dirent即sd就类似于硬盘中的磁道.
   
sysfs文件系统是一个排它式的文件系统,不论被mount多少次都只产生一个sb超级块,
如果尝试再次mount,即尝试再次调用sysfs_get_sb获取另一个sb超级块,那么将执行atomic_inc(old->s_active);增加
已被mount的引用计数,然后如果s已经执行了alloc_super,那么调用destroy_super将其销毁,然后返回这个已被mount了的
super_block超级块old,
这样就实现了sysfs文件系统不论被mount多少次都只产生一个sb超级块的效果,所以取名为get_sb_single[luther.gliethttp]

int __init classes_init(void)
{
    class_kset = kset_create_and_add("class", NULL, NULL);//parent_kobj为NULL,"class"目录将创建到sysfs_root-sysfs的根‘/‘下面.
    if (!class_kset)
        return -ENOMEM;
//到这里/sys/class目录就已经创建成功了,并且当sysfs被mount到/sys目录之后,/sys/class就可以通过ls可见了[luther.gliethttp]
    /* ick, this is ugly, the things we go through to keep from showing up
     * in sysfs... */
    kset_init(&class_obj_subsys);
    kobject_set_name(&class_obj_subsys.kobj, "class_obj");
    if (!class_obj_subsys.kobj.parent)
        class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
    return 0;
}

struct kset *kset_create_and_add(const char *name,
                 struct kset_uevent_ops *uevent_ops,
                 struct kobject *parent_kobj)
{
    struct kset *kset;
    int error;

kset = kset_create(name, uevent_ops, parent_kobj);//创建kset
    if (!kset)
        return NULL;
    error = kset_register(kset);
    if (error) {
        kfree(kset);
        return NULL;
    }
    return kset;
}
static struct kset *kset_create(const char *name,
                struct kset_uevent_ops *uevent_ops,
                struct kobject *parent_kobj)
{
    struct kset *kset;

kset = kzalloc(sizeof(*kset), GFP_KERNEL);//申请内存空间
    if (!kset)
        return NULL;
    kobject_set_name(&kset->kobj, name);//kmalloc内存,然后拷贝name,最后kobj->name = name;
    kset->uevent_ops = uevent_ops;//uevent处理函数
    kset->kobj.parent = parent_kobj;//

/*
     * The kobject of this kset will have a type of kset_ktype and belong to
     * no kset itself. That way we can properly free it when it is
     * finished being used.
     */
    kset->kobj.ktype = &kset_ktype;//包含该kset管理的所有属性文件的read和write通用实现函数,show和store
    kset->kobj.kset = NULL;//该kset就是父,不再有其他kset来管理本kset

return kset;
}
========================================
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
{
    va_list args;
    int retval;

va_start(args, fmt);
    retval = kobject_set_name_vargs(kobj, fmt, args);
    va_end(args);

return retval;
}
static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
                 va_list vargs)
{
    va_list aq;
    char *name;

va_copy(aq, vargs);
    name = kvasprintf(GFP_KERNEL, fmt, vargs);//kmalloc之后赋值,返回到name指针
    va_end(aq);

if (!name)
        return -ENOMEM;

/* Free the old name, if necessary. */
    kfree(kobj->name);//释放原有的name,如果有

/* Now, set the new name */
    kobj->name = name;//设置name

return 0;
}
char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
{
    unsigned int len;
    char *p;
    va_list aq;

va_copy(aq, ap);
    len = vsnprintf(NULL, 0, fmt, aq);
    va_end(aq);

p = kmalloc(len+1, gfp);//申请内存空间
    if (!p)
        return NULL;

vsnprintf(p, len+1, fmt, ap);//拷贝数据

return p;//返回拷贝完数据之后的内存空间
}
========================================
//定义属性文件的read和write实现函数,show和store
static struct kobj_type kset_ktype = {
    .sysfs_ops    = &kobj_sysfs_ops,
    .release = kset_release,
};
struct sysfs_ops kobj_sysfs_ops = {
    .show    = kobj_attr_show,
    .store    = kobj_attr_store,
};
========================================
int kset_register(struct kset *k)//注册本kset到其父目录下
{
    int err;

if (!k)
        return -EINVAL;

kset_init(k);//初始化内部结构
    err = kobject_add_internal(&k->kobj);
    if (err)
        return err;
    kobject_uevent(&k->kobj, KOBJ_ADD);
    return 0;
}
void kset_init(struct kset *k)
{
    kobject_init_internal(&k->kobj);
    INIT_LIST_HEAD(&k->list);
    spin_lock_init(&k->list_lock);
}
static int kobject_add_internal(struct kobject *kobj)
{
    int error = 0;
    struct kobject *parent;

if (!kobj)//必须存在
        return -ENOENT;

if (!kobj->name || !kobj->name[0]) {//kobj必须有名字,因为他要作为目录或者文件显示在sysfs中
        pr_debug("kobject: (%p): attempted to be registered with empty "
             "name!\n", kobj);
        WARN_ON(1);
        return -EINVAL;
    }

parent = kobject_get(kobj->parent);//获取其父kobj结构体,我们的class_kset它的parent为NULL

/* join kset if set, use it as parent if we do not already have one */
    if (kobj->kset) {//我们的class_kset它的kset为NULL
        if (!parent)
            parent = kobject_get(&kobj->kset->kobj);//如果没有为该kobj指定parent,那么kobj所在的kset将作为
//本kobj的父目录
        kobj_kset_join(kobj);//将kobj链接到管理kobj的kset上去
        kobj->parent = parent;
    }

pr_debug("kobject: ‘%s‘ (%p): %s: parent: ‘%s‘, set: ‘%s‘\n",
         kobject_name(kobj), kobj, __FUNCTION__,
         parent ? kobject_name(parent) : "",
         kobj->kset ? kobject_name(&kobj->kset->kobj) : "");

error = create_dir(kobj);//在sysfs中为该kobj创建目录
    if (error) {
        kobj_kset_leave(kobj);
        kobject_put(parent);
        kobj->parent = NULL;

/* be noisy on error issues */
        if (error == -EEXIST)
            printk(KERN_ERR "%s failed for %s with "
             "-EEXIST, don‘t try to register things with "
             "the same name in the same directory.\n",
             __FUNCTION__, kobject_name(kobj));
        else
            printk(KERN_ERR "%s failed for %s (%d)\n",
             __FUNCTION__, kobject_name(kobj), error);
        dump_stack();
    } else
        kobj->state_in_sysfs = 1;

return error;
}
static void kobj_kset_join(struct kobject *kobj)
{
    if (!kobj->kset)
        return;

kset_get(kobj->kset);
    spin_lock(&kobj->kset->list_lock);
    list_add_tail(&kobj->entry, &kobj->kset->list);//将该kobj添加到所属kset的链表上
    spin_unlock(&kobj->kset->list_lock);
}
static int create_dir(struct kobject *kobj)
{
    int error = 0;
    if (kobject_name(kobj)) {//返回kobj的name指针
        error = sysfs_create_dir(kobj);//在sysfs文件系统上创建目录
        if (!error) {
            error = populate_dir(kobj);//向创建的目录添加该kobj需要创建的文件
            if (error)
                sysfs_remove_dir(kobj);
        }
    }
    return error;
}
static inline const char *kobject_name(const struct kobject *kobj)
{
    return kobj->name;
}
int sysfs_create_dir(struct kobject * kobj)
{
    struct sysfs_dirent *parent_sd, *sd;
    int error = 0;

BUG_ON(!kobj);

if (kobj->parent)//如果该kobj有parent,那么在parent下面创建目录
        parent_sd = kobj->parent->sd;
    else
        parent_sd = &sysfs_root;//那么从sysfs的根‘/‘下面创建该kobj对应的目录[luther.gliethttp]

error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);//ok,&sd现在包含了kobj在sysfs文件系统中的文件描述信息
    if (!error)
        kobj->sd = sd;//ok,现在该kobj已经在sysfs中,在parent目录下给自己建立了一个可见的目录,sd包含描述该目录的inode信息,因为sysfs是一个内存文件系统,所以文件的物理存储关系就需要使用sd来维护,因此sysfs_dirent即sd就类似于硬盘中的磁道.
    return error;
}
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
         const char *name, struct sysfs_dirent **p_sd)
{
    umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;//目录属性标识
    struct sysfs_addrm_cxt acxt;
    struct sysfs_dirent *sd;
    int rc;

/* allocate */
    sd = sysfs_new_dirent(name, mode, SYSFS_DIR);//申请sysfs_dirent结构体内存
    if (!sd)
        return -ENOMEM;
    sd->s_dir.kobj = kobj;

/* link in */
    sysfs_addrm_start(&acxt, parent_sd);//准备acxt结构体中需要使用到的信息对象
    rc = sysfs_add_one(&acxt, sd);
    sysfs_addrm_finish(&acxt);//收尾工作,刷新parent目录时间

if (rc == 0)
        *p_sd = sd;
    else
        sysfs_put(sd);

return rc;
}
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
{
    char *dup_name = NULL;
    struct sysfs_dirent *sd;

if (type & SYSFS_COPY_NAME) {
        name = dup_name = kstrdup(name, GFP_KERNEL);
        if (!name)
            return NULL;
    }

sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);//从sysfs_dir_cachep申请一个slab对象内存空间
    if (!sd)
        goto err_out1;

if (sysfs_alloc_ino(&sd->s_ino))//从radix树上,顺序申请下一个空闲的唯一整数,作为sysfs文件系统上文件的inode唯一节点索引号[luther.gliethttp]
        goto err_out2;

atomic_set(&sd->s_count, 1);
    atomic_set(&sd->s_active, 0);

sd->s_name = name;
    sd->s_mode = mode;
    sd->s_flags = type;

return sd;

err_out2:
    kmem_cache_free(sysfs_dir_cachep, sd);
 err_out1:
    kfree(dup_name);
    return NULL;
}
static int sysfs_alloc_ino(ino_t *pino)
{
    int ino, rc;

retry:
    spin_lock(&sysfs_ino_lock);
    rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino);//从radix树上,顺序申请下一个空闲的唯一整数
    spin_unlock(&sysfs_ino_lock);

if (rc == -EAGAIN) {
        if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL))
            goto retry;
        rc = -ENOMEM;
    }

*pino = ino;
    return rc;
}
//准备acxt结构体中需要使用到的信息对象
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
         struct sysfs_dirent *parent_sd)
{
    struct inode *inode;

memset(acxt, 0, sizeof(*acxt));//先清0所有数据
    acxt->parent_sd = parent_sd;//填入parent_sd

/* Lookup parent inode. inode initialization and I_NEW
     * clearing are protected by sysfs_mutex. By grabbing it and
     * looking up with _nowait variant, inode state can be
     * determined reliably.
     */
    mutex_lock(&sysfs_mutex);

inode = ilookup5_nowait(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
                parent_sd);
//从存储着所有文件系统yaffs2,ext3,fat和sysfs等文件系统中被读入内存之后建立的内存inode节点映像的
//hash表inode_hashtable中查找parent_sd->s_ino节点号对应的inode节点指针[luther.gliethttp].
    if (inode && !(inode->i_state & I_NEW)) {
//ok,该inode确实已经存在,并且不是正在创建中.
        /* parent inode available */
        acxt->parent_inode = inode;//填入该parent的inode映像指针.

/* sysfs_mutex is below i_mutex in lock hierarchy.
         * First, trylock i_mutex. If fails, unlock
         * sysfs_mutex and lock them in order.
         */
        if (!mutex_trylock(&inode->i_mutex)) {
            mutex_unlock(&sysfs_mutex);
            mutex_lock(&inode->i_mutex);
            mutex_lock(&sysfs_mutex);
        }
    } else
        iput(inode);//释放NEW的inode索引
}
//从存储着所有文件系统yaffs2,ext3,fat和sysfs等文件系统中被读入内存之后建立的内存inode节点映像的
//hash表inode_hashtable中查找parent_sd->s_ino节点号对应的inode节点指针[luther.gliethttp].
struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval,
        int (*test)(struct inode *, void *), void *data)
{
    struct hlist_head *head = inode_hashtable + hash(sb, hashval);

return ifind(sb, head, test, data, 0);
}
ifind
=>find_inode
=>if (inode->i_sb != sb) continue;//比较该inode是否属于该sb超级块,所以这样就可以区分不同超级块管理的相同节点号[luther.gliethttp]
=>if (!test(inode, data)) continue;//如果在hash短链上的inode属于指定的sb超级块,那么调用test函数进一步定位inode的正确性,对于sysfs文件系统,使用了sysfs_ilookup_test来进一步判断
static int sysfs_ilookup_test(struct inode *inode, void *arg)
{
    struct sysfs_dirent *sd = arg;
    return inode->i_ino == sd->s_ino;//只需要保证该sd的s_ino和inode->i_ino相同即说明s_ino号对应的节点已经在sysfs文件系统创建了[luther.gliethttp]
}
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{
    if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) {//检查欲填入的sd是否已经在parent目录下存在了
        printk(KERN_WARNING "sysfs: duplicate filename ‘%s‘ "
         "can not be created\n", sd->s_name);
        WARN_ON(1);
        return -EEXIST;
    }

sd->s_parent = sysfs_get(acxt->parent_sd);//为新建的sd指定有效的parent目录结构体

if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
        inc_nlink(acxt->parent_inode);

acxt->cnt++;

sysfs_link_sibling(sd);//sibling们,按inode节点号,从小到大顺序链接在一起

return 0;
}
//因为sysfs是一种内存文件系统,所以所有文件数据信息都在内存中,文件的级联关系是使用单向链表来完成的,
//所以遍历parent目录结构体挂载的所有文件孩子和目录孩子的目录结构逐一比较name即可[luther.gliethttp].
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
                 const unsigned char *name)
{
    struct sysfs_dirent *sd;

for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
        if (!strcmp(sd->s_name, name))
            return sd;
    return NULL;
}
//sibling们,按inode节点号,从小到大顺序链接在一起[luther.gliethttp]
static void sysfs_link_sibling(struct sysfs_dirent *sd)
{
    struct sysfs_dirent *parent_sd = sd->s_parent;
    struct sysfs_dirent **pos;

BUG_ON(sd->s_sibling);

/* Store directory entries in order by ino. This allows
     * readdir to properly restart without having to add a
     * cursor into the s_dir.children list.
     */
    for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
        if (sd->s_ino < (*pos)->s_ino)//如果新加入的sd的节点号小于该pos节点号,那么break.
            break;
    }
    sd->s_sibling = *pos;//将自己插入到pos前面
    *pos = sd;
}
//在classes_init
//=>kset_create_and_add
//=>kset_create
//=>kset->kobj.ktype = &kset_ktype;
static int populate_dir(struct kobject *kobj)
{
    struct kobj_type *t = get_ktype(kobj);
    struct attribute *attr;
    int error = 0;
    int i;

if (t && t->default_attrs) {//在classes_init中对应的kset_ktype没有属性文件要创建,所以该执行将直接返回
        for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {
            error = sysfs_create_file(kobj, attr);
            if (error)
                break;
        }
    }
    return error;
}
//向sysfs文件系统kobj所在目录添加文件
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
{
    BUG_ON(!kobj || !kobj->sd || !attr);

return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);

}
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
         int type)
{
    umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;//普通文件属性标识
    struct sysfs_addrm_cxt acxt;
    struct sysfs_dirent *sd;
    int rc;

sd = sysfs_new_dirent(attr->name, mode, type);//同create_dir
    if (!sd)
        return -ENOMEM;
    sd->s_attr.attr = (void *)attr;

sysfs_addrm_start(&acxt, dir_sd);//同create_dir
    rc = sysfs_add_one(&acxt, sd);//同create_dir
    sysfs_addrm_finish(&acxt);

if (rc)
        sysfs_put(sd);

return rc;
}

时间: 2024-12-04 13:27:27

[转]浅析/sys/class目录的创建流程的相关文章

cocos2dx基础篇(4)——浅析cocos2dx引擎目录

通过前面几节的学习,相信大家都已经配置好了VS+cocos2dx2.2.3的环境,并且成功运行了官方的案例HelloWorld. 一.窥探文件目录 要想学好cocos2dx,首先就需要对引擎目录下的各个文件有所了解.接下来,就让我们先来分析一下cocos2dx2.2.3引擎的文件目录吧. 从目录中我们主要了解一下一下几个文件: cocos2dx:cocos2d-x引擎的核心部分,存放了引擎的大部分源文件. CocosDenshion:声音模块相关源文件. Debug.win32:在Windows

openstack之虚拟机的创建流程

这篇博文静静的呆在草稿箱大半年了,如果不是因为某些原因被问到,以及因为忽略它而导致的损失,否则我也不知道什么时候会将它完成.感谢这段时间经历的挫折,让我知道不足,希望你能给我更大的决心! 本文试图详细地描述openstack创建虚拟机的完整过程,从用户发起请求到虚拟机成功运行,包括客户端请求的发出.keystone身份验证.nova-api接收请求.nova-scheduler调度.nova-computer创建.nova-network分配网络.对于每一个模块在创建虚拟机的过程中所负责的功能和

Android 4.4 Kitkat Phone工作流程浅析(十)__&quot;通话显示&quot;查询流程

本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. 前置文章: <Android 4.4 Kitkat Phone工作流程浅析(一)__概要和学习计划> <Android 4.4 Kitkat Phone工作流程浅析(二)__UI结构分析> <Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程

浅析设计模式(六)——创建型模式之Abstract-Factory(抽象工厂模式)

抽象工厂模式Abstract-Factory 本文的套路: 抽象工厂模式的定义 抽象工厂模式的参与者及其角色 抽象工厂模式的类图 抽象工厂模式的示例 参考 抽象工厂模式的定义 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类. 前面[浅析设计模式(四)--创建型模式之Simple-Factory(简单工厂方法,非设计模式)]中介绍的简单工厂方法,虽然已经对变化的部分进行了封装,但是这里只由一个对象负责所有的具体类的实例化,因此每次有新增对象类型时,都需要改变工厂的源码进行扩展.

DJANGO 学生管理系统项目创建流程 -- 单表管理

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 17.0px ".PingFang SC"; color: #454545 } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Helvetica Neue"; color: #454545; min-height: 14.0px } p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; f

eclipse maven工程中src/main/resources目录下创建的文件夹是包图标的解决方法

如图:在src/main/resources目录下创建的文件夹却以包的图标显示  修改方法: 入下图,按顺序1 ,2,3,4操作,把3处remove,在4处添加**  修改后如下:  然后点击完成后,文件夹图标显示正常了 

【Java基础】Java类的加载和对象创建流程的详细分析

相信我们在面试Java的时候总会有一些公司要做笔试题目的,而Java类的加载和对象创建流程的知识点也是常见的题目之一.接下来通过实例详细的分析一下. 实例问题 实例代码 Parent类 1 package mytest.javaBase; 2 3 public class Parent { 4 int a = 10; 5 static int b = 11; 6 // 静态代码块 7 static { 8 System.out.println("Parent静态代码块:b=" + b)

在linux 系统中利用 facl 实现目录下创建文件继承父目录的权限的所属组

在linux 系统中,可以通过setfacl 来实现目录下创建文件或子目录,并继承父目录的权限. 下面以 root 用普通用户 user1 .在目录/mnt下 [[email protected] mnt]# setfacl -m u:user1:rwx share        //为目录添加ower = user1 ,并赋予rwx 的权根. [[email protected] mnt]# setfacl -d -m  u:user1:rwx share    //为目录添加默认的acl权限

IOS在Document目录下创建文件夹、保存、读取、以及删除文件

1 // 在Documents目录下创建一个名为LaunchImage的文件夹 2 NSString *path = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"LaunchImage"]; 3 NSLog(@"%@",path); 4 5 NSFileManager *fileManager =