歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

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; 

Copyright © Linux教程網 All Rights Reserved