首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

Linux虚拟文件系统-资料路径名的解析(3)-普通文件名

2012-11-26 
Linux虚拟文件系统--文件路径名的解析(3)--普通文件名对于一个文件路径的分量,如果其不为.和..则属于

Linux虚拟文件系统--文件路径名的解析(3)--普通文件名

      对于一个文件路径的分量,如果其不为'.'和'..'则属于普通文件名,普通文件名的解析由do_lookup()函数来处理

static int do_lookup(struct nameidata *nd, struct qstr *name,     struct path *path){struct vfsmount *mnt = nd->path.mnt;struct dentry *dentry = __d_lookup(nd->path.dentry, name);//查找name对应的dentryif (!dentry)//dentry不存在,跳转至need_lookupgoto need_lookup;/*如果底层文件系统中定义了d_revalidate函数,则要判断目录项是否有效,以保证一致性,  该函数是针对于网络文件系统存在的*/if (dentry->d_op && dentry->d_op->d_revalidate)goto need_revalidate;done:path->mnt = mnt;path->dentry = dentry;/*这里由于path往下走了一层,因此要调用__follow_mount()判断dentry对应的目录下是否挂载了其他的文件系统,以保证对应的mnt是正确的*/__follow_mount(path);return 0;need_lookup:/*没有找到name对应的dentry,则要创建新的dentry并从磁盘中读取数据保存在dentry中*/dentry = real_lookup(nd->path.dentry, name, nd);if (IS_ERR(dentry))goto fail;goto done;need_revalidate:dentry = do_revalidate(dentry, nd);if (!dentry)goto need_lookup;if (IS_ERR(dentry))goto fail;goto done;fail:return PTR_ERR(dentry);}

 

可以想象,搜索一个文件(目录)时,首先肯定要在dentry缓存中查找,当缓存中查找不到对应的dentry时,才需要从磁盘中查找,并新建一个dentry,将磁盘中的数据保存到其中。找到了目标dentry后,就将相应的信息保存到path中,这里因为路径向下进了一层,因此要判断下层目录是否有新的文件系统挂载的问题,和上文讨论的类似,因此要通过__follow_mount()函数判断是否有文件系统挂载在该目录下,另外,对于网络文件系统,还要通过文件系统中定义的d_revalidate()函数来判断该dentry是否有效以保证一致性。

先来看看在dentry缓存中查找的过程

struct dentry * __d_lookup(struct dentry * parent, struct qstr * name){unsigned int len = name->len;unsigned int hash = name->hash;const unsigned char *str = name->name;struct hlist_head *head = d_hash(parent,hash);//通过parent的地址和hash(hash是name的哈希值)进行定位struct dentry *found = NULL;struct hlist_node *node;struct dentry *dentry;rcu_read_lock();hlist_for_each_entry_rcu(dentry, node, head, d_hash) {//扫描head对应的碰撞溢出表struct qstr *qstr;if (dentry->d_name.hash != hash)//name的hash值不相符,则放弃该dentrycontinue;if (dentry->d_parent != parent)//父目录不一样,则放弃该dentrycontinue;spin_lock(&dentry->d_lock);/* * Recheck the dentry after taking the lock - d_move may have * changed things.  Don't bother checking the hash because we're * about to compare the whole name anyway. */if (dentry->d_parent != parent)goto next;/* non-existing due to RCU? */if (d_unhashed(dentry))goto next;/* * It is safe to compare names since d_move() cannot * change the qstr (protected by d_lock). */ /*当确保了父目录和文件名的哈希值与目标dentry的一致性后,接下来就只用匹配文件名了*/qstr = &dentry->d_name;//取当前dentry的文件名/*如果父目录文件系统定义了比较文件名的方法,则调用之*/if (parent->d_op && parent->d_op->d_compare) {if (parent->d_op->d_compare(parent, qstr, name))goto next;} else {//如果没定义if (qstr->len != len)//先确定长度是否相等goto next;if (memcmp(qstr->name, str, len))//再比较内存goto next;}atomic_inc(&dentry->d_count);found = dentry; //这里表明找到了目标dentryspin_unlock(&dentry->d_lock);break;next:spin_unlock(&dentry->d_lock); } rcu_read_unlock(); return found;}


 

d_hash()函数将父目录dentry的地址和所要查找的文件名的哈希值组合起来,重新构建一个哈希值,并根据其定位到
dentry_hashtable哈希表中,dentry_hashtable是dentry缓存的一部分,所有的dentry都会保存在dentry_hashtable中,这样一来,就得到了一个哈希表的溢出链表的表头,即代码中的head变量。下面的工作就是扫描这个链表,并从中查找真正的目标。

 

如果在dentry_hashtable中没能找到目标dentry,则通过real_lookup()函数从磁盘中查找

static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd){struct dentry * result;struct inode *dir = parent->d_inode;mutex_lock(&dir->i_mutex);/* * First re-do the cached lookup just in case it was created * while we waited for the directory semaphore.. * * FIXME! This could use version numbering or similar to * avoid unnecessary cache lookups. * * The "dcache_lock" is purely to protect the RCU list walker * from concurrent renames at this point (we mustn't get false * negatives from the RCU list walk here, unlike the optimistic * fast walk). * * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup */ //再从磁盘读取前再进行一次d_lookup尝试,因为之前等待互斥锁时有可能已经创建了相应的dentryresult = d_lookup(parent, name);/*下面进行dentry的创建*/if (!result) {struct dentry *dentry;/* Don't create child dentry for a dead directory. */result = ERR_PTR(-ENOENT);if (IS_DEADDIR(dir))goto out_unlock;/*分配一个dentry并进行相应的初始化*/dentry = d_alloc(parent, name);result = ERR_PTR(-ENOMEM);if (dentry) {/*调用特定于文件系统的lookup函数从磁盘中读取数据并将dentry添入散列表*/result = dir->i_op->lookup(dir, dentry, nd);if (result)dput(dentry);elseresult = dentry;}out_unlock:mutex_unlock(&dir->i_mutex);return result;}/* * Uhhuh! Nasty case: the cache was re-populated while * we waited on the semaphore. Need to revalidate. */mutex_unlock(&dir->i_mutex);if (result->d_op && result->d_op->d_revalidate) {result = do_revalidate(result, nd);if (!result)result = ERR_PTR(-ENOENT);}return result;}


 

1楼zi77642475昨天 21:00
加油哦!争取早日成为专家!呵呵!沙发依然在!

热点排行