Coder
分类: LINUX
2010-08-09 21:32:26
怎么能够让那些未知的问题一直困扰着我们呢,接着来探讨sysfs文件系统目录inode的创建。一切秘密都在需要时。
在路径名查找的过程中, do_lookup()函数根据传递的父目录路径的信息和所要查找的名字信息来查找路径,它接收三个参数,一为nameidata 结构指针nd,该指针指向的对象的path字段中保存有父目录路径的信息,包括dentry,vfsmount等;二为name,指向所要查找的文件或目录的名字;三为path结构指针,用于存放查找的结构。若在dentry缓存中查找未果的话,则do_lookup()函数将会调用父目录的inode的lookup()方法来进行实际的查找,包括读取父目录文件内容等更加和具体文件系统相关的操作。(参见前面“do_lookup()路径名查找”博文)。对于sysfs来说即是sysfs_lookup()函数。在开始看这个sysfs_lookup()函数之前,还是要先看下do_lookup()函数都为我们的sysfs_lookup()做了什么:它已经根据父目录路径和名字创建了目录项了。
来看sysfs_lookup()函数定义:
---------------------------------------------------------------------
fs/sysfs/dir.c
629
static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
630 struct
nameidata *nd)
631
{
632 struct dentry *ret = NULL;
633 struct sysfs_dirent *parent_sd =
dentry->d_parent->d_fsdata;
634 struct sysfs_dirent *sd;
635 struct inode *inode;
636
637 mutex_lock(&sysfs_mutex);
638
639 sd = sysfs_find_dirent(parent_sd,
dentry->d_name.name);
640
641 /* no such entry */
642 if (!sd) {
643 ret = ERR_PTR(-ENOENT);
644 goto out_unlock;
645 }
646
647 /* attach dentry and inode */
648 inode = sysfs_get_inode(dir->i_sb,
sd);
649 if (!inode) {
650 ret = ERR_PTR(-ENOMEM);
651 goto out_unlock;
652 }
653
654 /* instantiate and hash dentry */
655 ret = d_find_alias(inode);
656 if (!ret) {
657 dentry->d_op = &sysfs_dentry_ops;
658 dentry->d_fsdata =
sysfs_get(sd);
659 d_add(dentry, inode);
660 } else {
661 d_move(ret, dentry);
662 iput(inode);
663 }
664
665 out_unlock:
666 mutex_unlock(&sysfs_mutex);
667 return ret;
668
}
---------------------------------------------------------------------
不知道哪个大傻瓜写的这么个函数,参数名起的,一点提示性都没有。从do_lookup()来看,个参数倒是会清晰一些:dir,即是要在其中查找目录项的目录(父目录)的inode;dentry,是新创建的要保存我们查找的结构的,它的d_parent字段也是经过了适当的设置的了;nd,其path字段中保存了父目录路径的信息。
这个函数主要完成以下操作:
1、获得父目录的sysfs_dirent。在“Sysfs文件系统根目录项的建立”博文中,我们看到在sysfs文件系统中inode的i_private字段和dentry的d_fsdata都是指向对应的sysfs_dirent的,所以可以从dentry->d_parent->d_fsdata中获得父目录的sysfs_dirent对象。
2、调用sysfs_find_dirent(parent_sd,
dentry->d_name.name)来查找sysfs_dirent。这个函数根据父目录的sysfs_dirent和文件或目录的名字来查找sysfs_dirent。sysfs_find_dirent()函数定义如下:
---------------------------------------------------------------------
fs/sysfs/dir.c
522
/**
523 *
sysfs_find_dirent - find sysfs_dirent with the given name
524 *
@parent_sd: sysfs_dirent to search under
525 *
@name: name to look for
526 *
527 *
Look for sysfs_dirent with name @name under @parent_sd.
528 *
529 *
LOCKING:
530 *
mutex_lock(sysfs_mutex)
531 *
532 *
RETURNS:
533 *
Pointer to sysfs_dirent if found, NULL if not.
534 */
535
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
536 const
unsigned char *name)
537
{
538 struct sysfs_dirent *sd;
539
540 for (sd =
parent_sd->s_dir.children; sd; sd = sd->s_sibling)
541 if (!strcmp(sd->s_name,
name))
542 return sd;
543 return NULL;
544
}
---------------------------------------------------------------------
前面添加kobject的过程,我们看到,其实主要就是为对应的kobject创建sysfs_dirent,并将该sysfs_dirent对象添加进父kobject对应的sysfs_dirent的子sysfs_dirent链表中。sysfs_find_dirent()函数完成的主要工作,也就是要根据名字来查出sysfs_dirent对象地址来。
3、如果sysfs_find_dirent()查找失败,则返回-ENOENT。
4、调用sysfs_get_inode(dir->i_sb,
sd)函数来创建inode。我们要找的就是它啊,在需要的时候,它为kobject所对应的目录创建inode。在“inode对象的建立”及“Sysfs文件系统根目录项的建立”博文中有说明,这里就不啰嗦了。
5、调用d_find_alias(inode)函数为inode对象找到一个位于哈希链表中的、且在该索引节点的别名链表i_dentry中的dentry对象。
---------------------------------------------------------------------
fs/dcache.c
335
/**
336 * d_find_alias - grab a hashed alias of inode
337 * @inode: inode in question
338 * @want_discon: flag, used by d_splice_alias, to request
339 *
that only a DISCONNECTED alias be returned.
340 *
341 * If inode has a hashed alias, or is a
directory and has any alias,
342 * acquire the reference to alias and return
it. Otherwise return
343 * NULL.Notice that if inode is a directory
there can be only one alias
344 * and it can be unhashed only if it has no
children, or if it is the
345 * root of a filesystem.
346 *
347 * If the inode has an IS_ROOT,
DCACHE_DISCONNECTED alias, then prefer
348 * any other hashed alias over that one unless
@want_discon is set,
349 * in which case only return an IS_ROOT,
DCACHE_DISCONNECTED alias.
350 */
351
352
static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
353
{
354 struct list_head *head, *next, *tmp;
355 struct dentry *alias, *discon_alias=NULL;
356
357 head = &inode->i_dentry;
358 next = inode->i_dentry.next;
359 while (next != head) {
360 tmp = next;
361 next = tmp->next;
362 prefetch(next);
363 alias = list_entry(tmp, struct dentry,
d_alias);
364 if (S_ISDIR(inode->i_mode)
|| !d_unhashed(alias)) {
365 if (IS_ROOT(alias)
&&
366 (alias->d_flags
& DCACHE_DISCONNECTED))
367 discon_alias = alias;
368 else if (!want_discon)
{
369
__dget_locked(alias);
370 return alias;
371 }
372 }
373 }
374 if (discon_alias)
375 __dget_locked(discon_alias);
376 return discon_alias;
377
}
378
379
struct dentry * d_find_alias(struct inode *inode)
380
{
381 struct dentry *de = NULL;
382
383 if
(!list_empty(&inode->i_dentry)) {
384 spin_lock(&dcache_lock);
385 de = __d_find_alias(inode, 0);
386 spin_unlock(&dcache_lock);
387 }
388 return de;
389
}
390
EXPORT_SYMBOL(d_find_alias);
---------------------------------------------------------------------
6、设置dentry->d_op指向sysfs_dentry_ops,设置dentry->d_fsdata指向对应的sysfs_dirent。
7、调用d_add(dentry,
inode)来向哈希队列添加dentry。d_add()定义为:
---------------------------------------------------------------------
include/linux/dcache.h
267
/**
268 * d_add - add dentry to hash queues
269 * @entry: dentry to add
270 * @inode: The inode to attach to this dentry
271 *
272 * This adds the entry to the hash queues and
initializes @inode.
273 * The entry was actually filled in earlier
during d_alloc().
274 */
275
276
static inline void d_add(struct dentry *entry, struct inode *inode)
277
{
278 d_instantiate(entry, inode);
279 d_rehash(entry);
280
}
---------------------------------------------------------------------
8、返回0