在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
今日推荐
周排行