感谢支持
我们一直在努力

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

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

  1. staticint do_lookup(struct nameidata *nd, struct qstr *name,
  2. struct path *path)
  3. {
  4. struct vfsmount *mnt = nd->path.mnt;
  5. struct dentry *dentry = __d_lookup(nd->path.dentry, name);//查找name对应的dentry
  6. if (!dentry)//dentry不存在,跳转至need_lookup
  7. goto need_lookup;
  8. /*如果底层文件系统中定义了d_revalidate函数,则要判断目录项是否有效,以保证一致性,
  9. 该函数是针对于网络文件系统存在的*/
  10. if (dentry->d_op && dentry->d_op->d_revalidate)
  11. goto need_revalidate;
  12. done:
  13. path->mnt = mnt;
  14. path->dentry = dentry;
  15. /*这里由于path往下走了一层,因此要调用__follow_mount()判断dentry对应的目录下是否挂载了其他的文件系统,
  16. 以保证对应的mnt是正确的*/
  17. __follow_mount(path);
  18. return 0;
  19. need_lookup:
  20. /*没有找到name对应的dentry,则要创建新的dentry并从磁盘中读取数据保存在dentry中*/
  21. dentry = real_lookup(nd->path.dentry, name, nd);
  22. if (IS_ERR(dentry))
  23. goto fail;
  24. goto done;
  25. need_revalidate:
  26. dentry = do_revalidate(dentry, nd);
  27. if (!dentry)
  28. goto need_lookup;
  29. if (IS_ERR(dentry))
  30. goto fail;
  31. goto done;
  32. fail:
  33. return PTR_ERR(dentry);
  34. }

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

相关阅读: http://www.linuxidc.com/search.aspx?where=nkey&keyword=3305

先来看看在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值不相符,则放弃该dentry 
            continue; 
        if (dentry->d_parent != parent)//父目录不一样,则放弃该dentry 
            continue; 
 
        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; //这里表明找到了目标dentry 
        spin_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()函数从磁盘中查找

  1. staticstruct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd)
  2. {
  3. struct dentry * result;
  4. struct inode *dir = parent->d_inode;
  5. mutex_lock(&dir->i_mutex);
  6. /*
  7. * First re-do the cached lookup just in case it was created
  8. * while we waited for the directory semaphore..
  9. *
  10. * FIXME! This could use version numbering or similar to
  11. * avoid unnecessary cache lookups.
  12. *
  13. * The “dcache_lock” is purely to protect the RCU list walker
  14. * from concurrent renames at this point (we mustn’t get false
  15. * negatives from the RCU list walk here, unlike the optimistic
  16. * fast walk).
  17. *
  18. * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup
  19. */
  20. //再从磁盘读取前再进行一次d_lookup尝试,因为之前等待互斥锁时有可能已经创建了相应的dentry
  21. result = d_lookup(parent, name);
  22. /*下面进行dentry的创建*/
  23. if (!result) {
  24. struct dentry *dentry;
  25. /* Don’t create child dentry for a dead directory. */
  26. result = ERR_PTR(-ENOENT);
  27. if (IS_DEADDIR(dir))
  28. goto out_unlock;
  29. /*分配一个dentry并进行相应的初始化*/
  30. dentry = d_alloc(parent, name);
  31. result = ERR_PTR(-ENOMEM);
  32. if (dentry) {
  33. /*调用特定于文件系统的lookup函数从磁盘中读取数据并将dentry添入散列表*/
  34. result = dir->i_op->lookup(dir, dentry, nd);
  35. if (result)
  36. dput(dentry);
  37. else
  38. result = dentry;
  39. }
  40. out_unlock:
  41. mutex_unlock(&dir->i_mutex);
  42. return result;
  43. }
  44. /*
  45. * Uhhuh! Nasty case: the cache was re-populated while
  46. * we waited on the semaphore. Need to revalidate.
  47. */
  48. mutex_unlock(&dir->i_mutex);
  49. if (result->d_op && result->d_op->d_revalidate) {
  50. result = do_revalidate(result, nd);
  51. if (!result)
  52. result = ERR_PTR(-ENOENT);
  53. }
  54. return result;
  55. }
赞(0) 打赏
转载请注明出处:服务器评测 » Linux虚拟文件系统–文件路径名的解析(3)–普通文件名
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏