Chinaunix首页 | 论坛 | 博客
  • 博客访问: 819807
  • 博文数量: 117
  • 博客积分: 2583
  • 博客等级: 少校
  • 技术积分: 1953
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-06 22:58
个人简介

Coder

文章分类
文章存档

2013年(1)

2012年(10)

2011年(12)

2010年(77)

2009年(13)

2008年(4)

分类: LINUX

2010-08-09 00:22:23

sysfs文件系统中创建目录

文接上回,来讨论在sysfs文件系统中创建目录的问题。话说,一个kobjectsysfs层次体系中对应于一个目录。在kset_register()kobject_add_varg()中会调用kobject_add_internal(struct kobject *kobj)函数来完成最终在sysfs文件系统中添加目录的工作。回想一些,之前的工作都对kobject做了些什么:kobjectktype字段肯定是经过了适当的设置了,还有parent字段和name字段也一样。接着,没多久就见到了kobject_add_internal()的出场。这个函数的定义为:

---------------------------------------------------------------------

lib/kobject.c

158 static int kobject_add_internal(struct kobject *kobj)

159 {

160         int error = 0;

161         struct kobject *parent;

162

163         if (!kobj)

164                 return -ENOENT;

165

166         if (!kobj->name || !kobj->name[0]) {

167     WARN(1, "kobject: (%p): attempted to be registered with empty "

168                          "name!\n", kobj);

169                 return -EINVAL;

170         }

171

172         parent = kobject_get(kobj->parent);

173

174         /* join kset if set, use it as parent if we do not already have one */

175         if (kobj->kset) {

176                 if (!parent)

177                         parent = kobject_get(&kobj->kset->kobj);

178                 kobj_kset_join(kobj);

179                 kobj->parent = parent;

180         }

181

182         pr_debug("kobject: '%s' (%p): %s: parent: '%s', set:

183           '%s'\n", kobject_name(kobj), kobj, __func__,

184           parent ? kobject_name(parent) : "",

185           kobj->kset ? kobject_name(&kobj->kset->kobj) : "");

186

187         error = create_dir(kobj);

188         if (error) {

189                 kobj_kset_leave(kobj);

190                 kobject_put(parent);

191                 kobj->parent = NULL;

192

193                 /* be noisy on error issues */

194                 if (error == -EEXIST)

195                         printk(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));

199                 else

200                         printk(KERN_ERR "%s failed for %s (%d)\n",

201                              __func__, kobject_name(kobj), error);

202                 dump_stack();

203         } else

204                 kobj->state_in_sysfs = 1;

205

206         return error;

207 }

---------------------------------------------------------------------

这个函数完成如下操作:

1、检查传递的kobject的有效性,若为NULL,则返回-ENOENT

 

2、检查kobject名称的有效性,若名称无效,则返回-EINVAL

 

3、若kobject是属于某一个kset的,则检查kobjectparent字段是否指向有效的kobject,若没有,则将kobject加入到它的kset的链表里,并使kobjectparent字段指向它所属的kset的内嵌kobject。若kobjectparent指向有效的kobject,则仅仅将kobject加入到它的kset的链表里。

 

4、调用create_dir(kobj)函数来在sysfs文件系统层次结构中为kobject创建目录。create_dir()函数定义如下:

---------------------------------------------------------------------

lib/kobject.c

47 static int create_dir(struct kobject *kobj)

 48 {

 49         int error = 0;

 50         if (kobject_name(kobj)) {

 51                 error = sysfs_create_dir(kobj);

 52                 if (!error) {

 53                         error = populate_dir(kobj);

 54                         if (error)

 55                                 sysfs_remove_dir(kobj);

 56                 }

 57         }

 58         return 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 {

613         struct sysfs_dirent *parent_sd, *sd;

614         int error = 0;

615

616         BUG_ON(!kobj);

617

618         if (kobj->parent)

619                 parent_sd = kobj->parent->sd;

620         else

621                 parent_sd = &sysfs_root;

622

623         error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);

624         if (!error)

625                 kobj->sd = sd;

626         return error;

627 }

---------------------------------------------------------------------

这个函数首先会找到要为其创建目录的kobjectsysfs_dirent对象的父sysfs_dirent,通常是由父kobjectsd字段所指向。若父kobjectNULL,则设为sysfs跟目录的sysfs_dirent

 

然后调用create_dir(kobj, parent_sd, kobject_name(kobj) , &sd)来创建目录。随后详细来看创建目录的过程。

 

最后,若成功,设置kobjectsd字段指向为其新创建的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 {

577         umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;

578         struct sysfs_addrm_cxt acxt;

579         struct sysfs_dirent *sd;

580         int rc;

581

582         /* allocate */

583         sd = sysfs_new_dirent(name, mode, SYSFS_DIR);

584         if (!sd)

585                 return -ENOMEM;

586         sd->s_dir.kobj = kobj;

587

588         /* link in */

589         sysfs_addrm_start(&acxt, parent_sd);

590         rc = sysfs_add_one(&acxt, sd);

591         sysfs_addrm_finish(&acxt);

592

593         if (rc == 0)

594                 *p_sd = sd;

595         else

596                 sysfs_put(sd);

597

598         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 {

304         char *dup_name = NULL;

305         struct sysfs_dirent *sd;

306

307         if (type & SYSFS_COPY_NAME) {

308                 name = dup_name = kstrdup(name, GFP_KERNEL);

309                 if (!name)

310                         return NULL;

311         }

312

313         sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);

314         if (!sd)

315                 goto err_out1;

316

317         if (sysfs_alloc_ino(&sd->s_ino))

318                 goto err_out2;

319

320         atomic_set(&sd->s_count, 1);

321         atomic_set(&sd->s_active, 0);

322

323         sd->s_name = name;

324         sd->s_mode = mode;

325         sd->s_flags = type;

326

327         return sd;

328

329  err_out2:

330         kmem_cache_free(sysfs_dir_cachep, sd);

331  err_out1:

332         kfree(dup_name);

333         return 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 = namesd->s_mode = modesd->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,

351                        struct sysfs_dirent *parent_sd)

352 {

353         memset(acxt, 0, sizeof(*acxt));

354         acxt->parent_sd = parent_sd;

355

356         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 {

381         struct sysfs_inode_attrs *ps_iattr;

382

383         if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))

384                 return -EEXIST;

385

386         sd->s_parent = sysfs_get(acxt->parent_sd);

387

388         sysfs_link_sibling(sd);

389

390         /* Update timestamps on the parent */

391         ps_iattr = acxt->parent_sd->s_iattr;

392         if (ps_iattr) {

393                 struct iattr *ps_iattrs = &ps_iattr->ia_iattr;

394                 ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;

395         }

396

397         return 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 {

412         if (sd->s_parent) {

413                 sysfs_pathname(sd->s_parent, path);

414                 strcat(path, "/");

415         }

416         strcat(path, sd->s_name);

417         return path;

418 }

419

420 /**

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 {

442         int ret;

443

444         ret = __sysfs_add_one(acxt, sd);

445         if (ret == -EEXIST) {

446                 char *path = kzalloc(PATH_MAX, GFP_KERNEL);

447                 WARN(1, KERN_WARNING

448                      "sysfs: cannot create duplicate filename

449                     '%s'\n", (path == NULL) ? sd->s_name :

450                     strcat(strcat(sysfs_pathname(acxt->parent_sd,

451                           path), "/"),  sd->s_name));

452                 kfree(path);

453         }

454

455         return ret;

456 }

---------------------------------------------------------------------

我们看到,上面这个函数主要是设置sysfs_dirents_parent指向其父sysfs_dirent,并用sysfs_dirents_sibling字段把它连接到其父sysfs_direns_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() */

507         mutex_unlock(&sysfs_mutex);

508

509         /* kill removed sysfs_dirents */

510         while (acxt->removed) {

511                 struct sysfs_dirent *sd = acxt->removed;

512

513                 acxt->removed = sd->s_sibling;

514                 sd->s_sibling = NULL;

515

516                 sysfs_deactivate(sd);

517                 unmap_bin_file(sd);

518                 sysfs_put(sd);

519         }

520 }

---------------------------------------------------------------------

这个函数的主要工作就是释放锁。另外就是在移除sysfs_dirent时会完成一些工作。

 

(6).使用sysfs_dirent的二级指针p_sd来将创建的sysfs_dirent对象的地址返回给调用者。

 

5、设置kobjectstate_in_sysfs字段为1,以此说明该kobject已经被添加进了sysfs文件系统。

 

这整个过程主要是为kobject创建并初始化sysfs_dirent,将它和它的父sysfs_dirent及兄弟sysfs_dirent连接起来。

 

未明了的问题:对于一个目录来说的inode对象的创建。

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