在sysfs文件系统中创建目录


在sysfs文件系统中创建目录
2011年11月30日
  在sysfs文件系统中创建目录
  文接上回,来讨论在sysfs文件系统中创建目录的问题。话说,一个kobject在sysfs层次体系中对应于一个目录。在kset_register()和kobject_add_varg()中会调用kobject_add_internal(struct kobject *kobj)函数来完成最终在sysfs文件系统中添加目录的工作。回想一些,之前的工作都对kobject做了些什么:kobject的ktype字段肯定是经过了适当的设置了,还有parent字段和name字段也一样。接着,没多久就见到了kobject_add_internal()的出场。这个函数的定义为:
  -------------------------------------------------- -------------------
  lib/kobject.c
  158 static int kobject_add_internal(struct kobject *kobj)
  159 {
  160int error = 0;
  161struct kobject *parent;
  162
  163if (!kobj)
  164return -ENOENT;
  165
  166if (!kobj->name || !kobj->name[0]) {
  167WARN(1, "kobject: (%p): attempted to be registered with empty "
  168"name!\n", kobj);
  169return -EINVAL;
  170}
  171
  172parent = kobject_get(kobj->parent);
  173
  174/* join kset if set, use it as parent if we do not already have one */
  175if (kobj->kset) {
  176if (!parent)
  177parent = kobject_get(&kobj->kset->kobj);
  178kobj_kset_join(kobj);
  179kobj->parent = parent;
  180}
  181
  182pr_debug("kobject: '%s' (%p): %s: parent: '%s', set:
  183'%s'\n", kobject_name(kobj), kobj, __func__,
  184parent ? kobject_name(parent) : "",
  185kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
  186
  187error = create_dir(kobj);
  188if (error) {
  189kobj_kset_leave(kobj);
  190kobject_put(parent);
  191kobj->parent = NULL;
  192
  193/* be noisy on error issues */
  194if (error == -EEXIST)
  195printk(KERN_ERR "%s failed for %s with "
  196"-EEXIST, don't try to register things with "
  197"the same name in the same directory.\n",
  198__func__, kobject_name(kobj));
  199else
  200printk(KERN_ERR "%s failed for %s (%d)\n",
  201__func__, kobject_name(kobj), error);
  202dump_stack();
  203} else
  204kobj->state_in_sysfs = 1;
  205
  206return error;
  207 }
  -------------------------------------------------- -------------------
  这个函数完成如下操作:
  1、检查传递的kobject的有效性,若为NULL,则返回-ENOENT。
  2、检查kobject名称的有效性,若名称无效,则返回-EINVAL。
  3、若kobject是属于某一个kset的,则检查kobject的parent字段是否指向有效的kobject,若没有,则将kobject加入到它的kset的链表里,并使kobject的parent字段指向它所属的kset的内嵌kobject。若kobject的parent指向有效的kobject,则仅仅将kobject加入到它的kset的链表里。4、调用create_dir(kobj)函数来在sysfs文件系统层次结构中为kobject创建目录。create_dir()函数定义如下:
  -------------------------------------------------- -------------------
  lib/kobject.c 47 static int create_dir(struct kobject *kobj) 48 { 49int error = 0; 50if (kobject_name(kobj)) { 51error = sysfs_create_dir(kobj); 52if (!error) { 53error = populate_dir(kobj); 54if (error) 55sysfs_remove_dir(kobj); 56} 57} 58return error; 59 } -------------------------------------------------- ------------------- 这个函数接受唯一的一个参数,也就是要为其创建目录的kobject的地址。这个函数的实现也是多么的简洁啊。它完成的操作如下:
  a.检查传递进来kobject对象的name的有效性,若无效,则返回0。
  b.若有效,则调用sysfs_create_dir(kobj)来在sysfs中创建目录。sysfs_create_dir()的定义如下:
  -------------------------------------------------- -------------------
  fs/sysfs/dir.c
  611 int sysfs_create_dir(struct kobject * kobj)
  612 {
  613struct sysfs_dirent *parent_sd, *sd;
  614int error = 0;
  615
  616BUG_ON(!kobj);
  617
  618if (kobj->parent)
  619parent_sd = kobj->parent->sd;
  620else
  621parent_sd = &sysfs_root;
  622
  623error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
  624if (!error)
  625kobj->sd = sd;
  626return error;
  627 }
  -------------------------------------------------- -------------------
  这个函数首先会找到要为其创建目录的kobject的sysfs_dirent对象的父sysfs_dirent,通常是由父kobject的sd字段所指向。若父kobject为NULL,则设为sysfs跟目录的sysfs_dirent。
  然后调用create_dir(kobj, parent_sd, kobject_name(kobj) , &sd)来创建目录。随后详细来看创建目录的过程。
  最后,若成功,设置kobject的sd字段指向为其新创建的sysfs_dirent,并返回0。若失败则返回错误码。
  创建目录的这个函数和前面的那个函数同名,不过此create_dir()非彼create_dir()。所定义的位置自是不同,所需要的参数也迥异。这个create_dir()的定义为:
  -------------------------------------------------- -------------------
  fs/sysfs/dir.c
  574 static int create_dir(struct kobject *kobj, struct sysfs_dirent
  575*parent_sd, const char *name, struct sysfs_dirent **p_sd)
  576 {
  577umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
  578struct sysfs_addrm_cxt acxt;
  579struct sysfs_dirent *sd;
  580int rc;
  581
  582/* allocate */
  583sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
  584if (!sd) 585return -ENOMEM; 586sd->s_dir.kobj = kobj; /* link in */ 589sysfs_addrm_start(&acxt, parent_sd); 590rc = sysfs_add_one(&acxt, sd); 591sysfs_addrm_finish(&acxt); if (rc == 0) 594*p_sd = sd; 595else 596sysfs_put(sd); return rc; 599 } -------------------------------------------------- ------------------- 先来对这个函数的几个参数做一些说明,kobj为要为其创建目录的kobject的地址,parent_sd为父sysfs_dirent的地址,name为名字,还有一个sysfs_dirent的二级指针p_sd,它主要用于保存创建的sysfs_dirent对象的地址。这个函数完成如下操作:
  (1).调用sysfs_new_dirent(name, mode, SYSFS_DIR)来为kobject创建sysfs_dirent对象。并由局部变量sd指向它。sysfs_new_dirent()函数的定义为:
  -------------------------------------------------- -------------------
  fs/sysfs/dir.c
  302 struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
  303 {
  304char *dup_name = NULL;
  305struct sysfs_dirent *sd;
  306
  307if (type & SYSFS_COPY_NAME) {
  308name = dup_name = kstrdup(name, GFP_KERNEL);
  309if (!name)
  310return NULL;
  311}
  312
  313sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
  314if (!sd)
  315goto err_out1;
  316
  317if (sysfs_alloc_ino(&sd->s_ino))
  318goto err_out2;
  319 320atomic_set(&sd->s_count, 1); 321atomic_set(&sd->s_active, 0); 322 323sd->s_name = name; 324sd->s_mode = mode; 325sd->s_flags = type; 326 327return sd; 328 329err_out2: 330kmem_cache_free(sysfs_dir_cachep, sd); 331err_out1: 332kfree(dup_name); 333return NULL; 334 } -------------------------------------------------- ------------------- 这个sysfs_new_dirent()函数完成的工作还算清晰。调用kstrdup(name, GFP_KERNEL)为sysfs_dirent的名字分配内核缓冲区,并将传递进来的kobject名字复制到该缓冲区,由局部变量dup_name和参数name指向这个缓冲区。调用kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL)来在sysfs_dirent的缓存区sysfs_dir_cachep中分配sysfs_dirent对象,由局部变量sd指向它。调用sysfs_alloc_ino(&sd->s_ino)来为sysfs_dirent分配索引节点号。设置sd->s_name = name、sd->s_mode = mode及sd->s_flags = type。最后返回sysfs_dirent对象地址。
  这个地方,分配inode节点号的sysfs_alloc_ino()也是颇有意思的,回头再好好看下这个函数。
  (2).设置新分配的sysfs_dirent对象的sd->s_dir.kobj字段指向kobject。
  (3).调用sysfs_addrm_start(&acxt, parent_sd)来为sysfs_dirent的添加做准备。这个函数定义为:
  -------------------------------------------------- -------------------
  fs/sysfs/dir.c
  336 /**
  337*sysfs_addrm_start - prepare for sysfs_dirent add/remove
  338*@acxt: pointer to sysfs_addrm_cxt to be used
  339*@parent_sd: parent sysfs_dirent
  340*
  341*This function is called when the caller is about to add or
  342*remove sysfs_dirent under @parent_sd.This function
  343*acquires sysfs_mutex.@acxt is used to keep and pass context
  344*to other addrm functions.
  345*
  346*LOCKING:
  347*Kernel thread context (may sleep).sysfs_mutex is locked on
  348*return.
  349*/
  350 void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, 351struct sysfs_dirent *parent_sd) 352 { 353memset(acxt, 0, sizeof(*acxt)); 354acxt->parent_sd = parent_sd; mutex_lock(&sysfs_mutex); 357 } -------------------------------------------------- ------------------- 它完成的工作主要就是设置传递进来的sysfs_addrm_cxt指针所指向的对象的parent_sd字段指向sysfs_dirent,并获得sysfs_mutex锁。
  (4).调用sysfs_add_one(&acxt, sd)来向父sysfs_dirent添加sysfs_dirent。这个函数定义为:
  -------------------------------------------------- -------------------
  fs/sysfs/dir.c
  359 /**
  360*__sysfs_add_one - add sysfs_dirent to parent without warning
  361*@acxt: addrm context to use
  362*@sd: sysfs_dirent to be added
  363*
  364*Get @acxt->parent_sd and set sd->s_parent to it and increment
  365*nlink of parent inode if @sd is a directory and link into the
  366*children list of the parent.
  367*
  368*This function should be called between calls to
  369*sysfs_addrm_start() and sysfs_addrm_finish() and should be
  370*passed the same @acxt as passed to sysfs_addrm_start().
  371*
  372*LOCKING:
  373*Determined by sysfs_addrm_start().
  374*
  375*RETURNS:
  376*0 on success, -EEXIST if entry with the given name already
  377*exists.
  378*/
  379 int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
  380 {
  381struct sysfs_inode_attrs *ps_iattr;
  382
  383if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
  384return -EEXIST;
  385
  386sd->s_parent = sysfs_get(acxt->parent_sd);
  387
  388sysfs_link_sibling(sd);
  389
  390/* Update timestamps on the parent */
  391ps_iattr = acxt->parent_sd->s_iattr;
  392if (ps_iattr) {
  393struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
  394ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
  395} 396 397return 0; 398 } 399 400 /** 401*sysfs_pathname - return full path to sysfs dirent 402*@sd: sysfs_dirent whose path we want 403*@path: caller allocated buffer 404* 405*Gives the name "/" to the sysfs_root entry; any path returned 406*is relative to wherever sysfs is mounted. 407* 408*XXX: does no error checking on @path size 409*/ 410 static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) 411 { 412if (sd->s_parent) { 413sysfs_pathname(sd->s_parent, path); 414strcat(path, "/"); 415} 416strcat(path, sd->s_name); 417return path; 418 } /** 421*sysfs_add_one - add sysfs_dirent to parent 422*@acxt: addrm context to use 423*@sd: sysfs_dirent to be added 424* 425*Get @acxt->parent_sd and set sd->s_parent to it and increment 426*nlink of parent inode if @sd is a directory and link into the 427*children list of the parent. 428* 429*This function should be called between calls to 430*sysfs_addrm_start() and sysfs_addrm_finish() and should be 431*passed the same @acxt as passed to sysfs_addrm_start(). 432* 433*LOCKING: 434*Determined by sysfs_addrm_start(). 435* 436*RETURNS: 437*0 on success, -EEXIST if entry with the given name already 438*exists. 439*/ 440 int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) 441 { 442int ret; ret = __sysfs_add_one(acxt, sd); 445if (ret == -EEXIST) { 446char *path = kzalloc(PATH_MAX, GFP_KERNEL); 447WARN(1, KERN_WARNING 448"sysfs: cannot create duplicate filename449'%s'\n", (path == NULL) ? sd->s_name : 450strcat(strcat(sysfs_pathname(acxt->parent_sd,451 path), "/"),sd->s_name)); 452kfree(path); 453} return ret; 456 } -------------------------------------------------- ------------------- 我们看到,上面这个函数主要是设置sysfs_dirent的s_parent指向其父sysfs_dirent,并用sysfs_dirent的s_sibling字段把它连接到其父sysfs_diren的s_dir.children链表中。
  (5).调用sysfs_addrm_finish(&acxt)来结束sysfs_dirent的添加。这个函数定义为:
  -------------------------------------------------- -------------------
  fs/sysfs/dir.c
  493 /**
  494*sysfs_addrm_finish - finish up sysfs_dirent add/remove
  495*@acxt: addrm context to finish up
  496*
  497*Finish up sysfs_dirent add/remove.Resources acquired by
  498*sysfs_addrm_start() are released and removed sysfs_dirents are
  499*cleaned up.
  500*
  501*LOCKING:
  502*sysfs_mutex is released.
  503*/
  504 void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
  505 {
  506/* release resources acquired by sysfs_addrm_start() */
  507mutex_unlock(&sysfs_mutex);
  508
  509/* kill removed sysfs_dirents */
  510while (acxt->removed) {
  511struct sysfs_dirent *sd = acxt->removed;
  512
  513acxt->removed = sd->s_sibling;
  514sd->s_sibling = NULL;
  515
  516sysfs_deactivate(sd);
  517unmap_bin_file(sd);
  518sysfs_put(sd);
  519}
  520 }
  -------------------------------------------------- -------------------
  这个函数的主要工作就是释放锁。另外就是在移除sysfs_dirent时会完成一些工作。
  (6).使用sysfs_dirent的二级指针p_sd来将创建的sysfs_dirent对象的地址返回给调用者。
  5、设置kobject的state_in_sysfs字段为1,以此说明该kobject已经被添加进了sysfs文件系统。
  这整个过程主要是为kobject创建并初始化sysfs_dirent,将它和它的父sysfs_dirent及兄弟sysfs_dirent连接起来。
  未明了的问题:对于一个目录来说的inode对象的创建。发表于: 2010-08-09,修改于: 2010-08-09 19:17 已浏览29次,有评论0条 推荐 投诉
  loadPreviewComment('','http://blog.chinaunix.net/u 2/87729/showart_.html',1,1,'main',2);

猜你喜欢

转载自ioo226ux.iteye.com/blog/1359498
今日推荐