Linux是如何解析文件路径名的????

来源:互联网 发布:江苏微盛网络 怎么样 编辑:程序博客网 时间:2024/06/05 03:59

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


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

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

 

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

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

[cpp] view plaincopy
  1. <span style="font-size:12px;">struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)  
  2. {  
  3.     unsigned int len = name->len;  
  4.     unsigned int hash = name->hash;  
  5.     const unsigned char *str = name->name;  
  6.     struct hlist_head *head = d_hash(parent,hash);//通过parent的地址和hash(hash是name的哈希值)进行定位  
  7.     struct dentry *found = NULL;  
  8.     struct hlist_node *node;  
  9.     struct dentry *dentry;  
  10.   
  11.     rcu_read_lock();  
  12.       
  13.     hlist_for_each_entry_rcu(dentry, node, head, d_hash) {//扫描head对应的碰撞溢出表  
  14.         struct qstr *qstr;  
  15.   
  16.         if (dentry->d_name.hash != hash)//name的hash值不相符,则放弃该dentry  
  17.             continue;  
  18.         if (dentry->d_parent != parent)//父目录不一样,则放弃该dentry  
  19.             continue;  
  20.   
  21.         spin_lock(&dentry->d_lock);  
  22.   
  23.         /* 
  24.          * Recheck the dentry after taking the lock - d_move may have 
  25.          * changed things.  Don't bother checking the hash because we're 
  26.          * about to compare the whole name anyway. 
  27.          */  
  28.         if (dentry->d_parent != parent)  
  29.             goto next;  
  30.   
  31.         /* non-existing due to RCU? */  
  32.         if (d_unhashed(dentry))  
  33.             goto next;  
  34.   
  35.         /* 
  36.          * It is safe to compare names since d_move() cannot 
  37.          * change the qstr (protected by d_lock). 
  38.          */  
  39.          /*当确保了父目录和文件名的哈希值与目标dentry的一致性后,接下来就只用匹配文件名了*/  
  40.         qstr = &dentry->d_name;//取当前dentry的文件名  
  41.         /*如果父目录文件系统定义了比较文件名的方法,则调用之*/  
  42.         if (parent->d_op && parent->d_op->d_compare) {  
  43.             if (parent->d_op->d_compare(parent, qstr, name))  
  44.                 goto next;  
  45.         } else {//如果没定义  
  46.             if (qstr->len != len)//先确定长度是否相等  
  47.                 goto next;  
  48.             if (memcmp(qstr->name, str, len))//再比较内存  
  49.                 goto next;  
  50.         }  
  51.   
  52.         atomic_inc(&dentry->d_count);  
  53.         found = dentry; //这里表明找到了目标dentry  
  54.         spin_unlock(&dentry->d_lock);  
  55.         break;  
  56. next:  
  57.         spin_unlock(&dentry->d_lock);  
  58.     }  
  59.     rcu_read_unlock();  
  60.   
  61.     return found;  
  62. }  
  63. </span>  


 

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

 

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

[cpp] view plaincopy
  1. static struct 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.   
  6.     mutex_lock(&dir->i_mutex);  
  7.     /* 
  8.      * First re-do the cached lookup just in case it was created 
  9.      * while we waited for the directory semaphore.. 
  10.      * 
  11.      * FIXME! This could use version numbering or similar to 
  12.      * avoid unnecessary cache lookups. 
  13.      * 
  14.      * The "dcache_lock" is purely to protect the RCU list walker 
  15.      * from concurrent renames at this point (we mustn't get false 
  16.      * negatives from the RCU list walk here, unlike the optimistic 
  17.      * fast walk). 
  18.      * 
  19.      * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup 
  20.      */  
  21.      //再从磁盘读取前再进行一次d_lookup尝试,因为之前等待互斥锁时有可能已经创建了相应的dentry  
  22.     result = d_lookup(parent, name);  
  23.   
  24.     /*下面进行dentry的创建*/  
  25.     if (!result) {  
  26.         struct dentry *dentry;  
  27.   
  28.         /* Don't create child dentry for a dead directory. */  
  29.         result = ERR_PTR(-ENOENT);  
  30.         if (IS_DEADDIR(dir))  
  31.             goto out_unlock;  
  32.   
  33.         /*分配一个dentry并进行相应的初始化*/  
  34.         dentry = d_alloc(parent, name);  
  35.         result = ERR_PTR(-ENOMEM);  
  36.         if (dentry) {  
  37.             /*调用特定于文件系统的lookup函数从磁盘中读取数据并将dentry添入散列表*/  
  38.             result = dir->i_op->lookup(dir, dentry, nd);  
  39.             if (result)  
  40.                 dput(dentry);  
  41.             else  
  42.                 result = dentry;  
  43.         }  
  44. out_unlock:  
  45.         mutex_unlock(&dir->i_mutex);  
  46.         return result;  
  47.     }  
  48.   
  49.     /* 
  50.      * Uhhuh! Nasty case: the cache was re-populated while 
  51.      * we waited on the semaphore. Need to revalidate. 
  52.      */  
  53.     mutex_unlock(&dir->i_mutex);  
  54.     if (result->d_op && result->d_op->d_revalidate) {  
  55.         result = do_revalidate(result, nd);  
  56.         if (!result)  
  57.             result = ERR_PTR(-ENOENT);  
  58.     }  
  59.     return result;  
  60. }  
0 0
原创粉丝点击