linux类似的vlookup函数,do_lookup()路径名查找

do_lookup()根据父目录的路径,及文件名来找到文件的路径,也就是目录项和vfsmount,回忆一下,do_lookup()的调用环境,在link_path_walk()中有:

---------------------------------------------------------------------

fs/namei.c

836nd->flags |=

LOOKUP_CONTINUE;

837err = exec_permission(inode);

838if (err)

839break;

840

841this.name = name;

842c= *(const unsigned char

*)name;

843

844hash = init_name_hash();

845do {

846name++;

847hash =

partial_name_hash(c, hash);

848c= *(const unsigned char

*)name;

849} while (c && (c !=

'/'));

850this.len = name - (const char

*) this.name;

851this.hash =

end_name_hash(hash);

852

853/* remove trailing slashes? */

854if (!c)

855goto last_component;

856while (*++name == '/');

857if (!*name)

858goto

last_with_slashes;

859

878err = do_lookup(nd, &this,

&next);

879if (err)

880break;

---------------------------------------------------------------------

在qstr结构局部变量this中存有路径分量的信息,包括文件名字符串地址及其长度,根据文件名算得的哈希值,nd变量中存有父路径的信息,包括vfsmount对象地址和目录项对象地址。Path结构体类型的next变量用来存放查找的结果。

do_lookup()接受3个参数,nd保存有要查找的分量所在的目录的信息,name要查找的分量的名字信息,path则用于返回查找的结果。do_lookup()定义如下:

---------------------------------------------------------------------

fs/namei.c

698

static int do_lookup(struct nameidata *nd, struct qstr *name,

699struct path *path)

700

{

701struct vfsmount *mnt =

nd->path.mnt;

702struct dentry *dentry, *parent;

703struct inode *dir;

704/*

705* See if the low-level filesystem

might want

706* to use its own hash..

707*/

708if (nd->path.dentry->d_op

&& nd->path.dentry->d_op->d_hash) {

709int err =

nd->path.dentry->d_op->d_hash(nd->path.dentry, name);

710if (err < 0)

711return err;

712}

713

714dentry =

__d_lookup(nd->path.dentry, name);

715if (!dentry)

716goto need_lookup;

717if (dentry->d_op &&

dentry->d_op->d_revalidate)

718goto need_revalidate;

719

done:

720path->mnt = mnt;

721path->dentry = dentry;

722__follow_mount(path);

723return 0;

724

725

need_lookup:

726parent = nd->path.dentry;

727dir = parent->d_inode;

728

729mutex_lock(&dir->i_mutex);

730/*

731* First re-do the cached lookup just

in case it was created

732* while we waited for the directory

semaphore..

733*

734* FIXME! This could use version

numbering or similar to

735* avoid unnecessary cache lookups.

736*

737* The "dcache_lock" is

purely to protect the RCU list walker

738* from concurrent renames at this

point (we mustn't get false

739* negatives from the RCU list walk

here, unlike the optimistic

740* fast walk).

741*

742* so doing d_lookup() (with seqlock),

instead of lockfree __d_lookup

743*/

744dentry = d_lookup(parent, name);

745if (!dentry) {

746struct dentry *new;

747

748/* Don't create child dentry

for a dead directory. */

749dentry = ERR_PTR(-ENOENT);

750if (IS_DEADDIR(dir))

751goto out_unlock;

752

753new = d_alloc(parent, name);

754dentry = ERR_PTR(-ENOMEM);

755if (new) {

756dentry =

dir->i_op->lookup(dir, new, nd);

757if (dentry)

758

dput(new);

759else

760dentry = new;

761}

762

out_unlock:

763mutex_unlock(&dir->i_mutex);

764if (IS_ERR(dentry))

765goto fail;

766goto done;

767}

768

769/*

770* Uhhuh! Nasty case: the cache was

re-populated while

771* we waited on the semaphore. Need to

revalidate.

772*/

773mutex_unlock(&dir->i_mutex);

774if (dentry->d_op &&

dentry->d_op->d_revalidate) {

775dentry = do_revalidate(dentry,

nd);

776if (!dentry)

777dentry =

ERR_PTR(-ENOENT);

778}

779

if (IS_ERR(dentry))

780goto fail;

781goto done;

782

783

need_revalidate:

784dentry = do_revalidate(dentry, nd);

785if (!dentry)

786goto need_lookup;

787if (IS_ERR(dentry))

788goto fail;

789goto done;

790

791

fail:

792return PTR_ERR(dentry);

793

}

---------------------------------------------------------------------

这个函数也有点长,但结构还算清晰。

1、检查底层文件系统是否要使用它自己的哈希方法(nd->path.dentry->d_op->d_hash),若是,则调用该方法来更新已经计算出的分量名的哈希值。

2、调用__d_lookup(nd->path.dentry,

name)来在目录项高速缓存中搜索分量的目录项对象。该函数定义如下:

---------------------------------------------------------------------

fs/dcache.c

1374

struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)

1375

{

1376unsigned int len = name->len;

1377unsigned int hash = name->hash;

1378const unsigned char *str =

name->name;

1379struct hlist_head *head =

d_hash(parent,hash);

1380struct dentry *found = NULL;

1381struct hlist_node *node;

1382struct dentry *dentry;

1383

1384rcu_read_lock();

1385

1386hlist_for_each_entry_rcu(dentry, node,

head, d_hash) {

1387struct qstr *qstr;

1388

1389if (dentry->d_name.hash !=

hash)

1390continue;

1391if (dentry->d_parent !=

parent)

1392continue;

1393

1394spin_lock(&dentry->d_lock);

1395

1396/*

1397* Recheck the dentry after

taking the lock - d_move may have

1398* changed things.Don't bother checking the hash because we're

1399* about to compare the whole

name anyway.

1400*/

1401if (dentry->d_parent !=

parent)

1402goto next;

1403

1404/* non-existing due to RCU? */

1405if (d_unhashed(dentry))

1406goto next;

1407

1408/*

1409* It is safe to compare names

since d_move() cannot

1410* change the qstr (protected

by d_lock).

1411*/

1412qstr = &dentry->d_name;

1413if (parent->d_op &&

parent->d_op->d_compare) {

1414if

(parent->d_op->d_compare(parent, qstr, name))

1415goto next;

1416} else {

1417if (qstr->len !=

len)

1418goto next;

1419if

(memcmp(qstr->name, str, len))

1420goto next;

1421}

1422

1423atomic_inc(&dentry->d_count);

1424found = dentry;

1425spin_unlock(&dentry->d_lock);

1426break;

1427

next:

1428spin_unlock(&dentry->d_lock);

1429}

1430rcu_read_unlock();

1431

1432return found;

1433

}

---------------------------------------------------------------------

a.调用d_hash(parent,hash)来找到目录项可能存在于其中的哈希表项,也就是hlist_head指针,存放在局部变量head中。

---------------------------------------------------------------------

fs/dcache.c

1123

static inline struct hlist_head *d_hash(struct dentry *parent,

1124unsigned long hash)

1125

{

1126hash += ((unsigned long) parent ^

GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES;

1127hash = hash ^ ((hash ^

GOLDEN_RATIO_PRIME) >> D_HASHBITS);

1128return dentry_hashtable + (hash &

D_HASHMASK);

1129

}

---------------------------------------------------------------------

b.执行循环hlist_for_each_entry_rcu(dentry,

node, head, d_hash),在链表中查找

c.返回查找结果。若没找到,则返回NULL,若找到则返回目录项。

3、如果没有找到这样的目录项对象,则执行如下操作:

a.首先,获得要父目录的inode的i_mutex锁。

b.调用d_lookup(parent,

name)来在目录项缓存中查找,以防在上一步等待信号量的时候已经有进程创建了我们要查找的目录项。

c.如果d_lookup(parent,

name)返回非NULL值,则首先解对父目录的inode的i_mutex锁,然后检查dentry->d_op->d_revalidate方法是否有效,若是对查找结果dentry调用它,该方法成功返回时do_lookup(),设置path->mnt为nd->path.mnt,path->dentry为查找到的目录项dentry。然后在path上调用__follow_mount(path)并返回0。该方法失败时,则返回错误码。

d.如果d_lookup(parent,

name)依然返回NULL值,即说明目录项缓存中依然没有我们要查找的目录项。则

(1)、首先检查提供的父目录路径是不是真的是一个目录文件,若不是对对父目录的inode解锁并返回-ENOENT。

(2)、父目录路径是一个目录文件。则调用d_alloc(parent,

name)来分配并填充一个目录项。其定义为:

---------------------------------------------------------------------

fs/dcache.c

925

struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)

926

{

927struct dentry *dentry;

928char *dname;

929

930dentry =

kmem_cache_alloc(dentry_cache, GFP_KERNEL);

931if (!dentry)

932return NULL;

933

934if (name->len >

DNAME_INLINE_LEN-1) {

935dname = kmalloc(name->len +

1, GFP_KERNEL);

936if (!dname) {

937kmem_cache_free(dentry_cache, dentry);

938return NULL;

939}

940} else{

941dname = dentry->d_iname;

942}

943dentry->d_name.name = dname;

944

945dentry->d_name.len = name->len;

946dentry->d_name.hash = name->hash;

947memcpy(dname, name->name,

name->len);

948dname[name->len] = 0;

949

950atomic_set(&dentry->d_count,

1);

951dentry->d_flags = DCACHE_UNHASHED;

952spin_lock_init(&dentry->d_lock);

953dentry->d_inode = NULL;

954dentry->d_parent = NULL;

955dentry->d_sb = NULL;

956dentry->d_op = NULL;

957dentry->d_fsdata = NULL;

958dentry->d_mounted = 0;

959INIT_HLIST_NODE(&dentry->d_hash);

960INIT_LIST_HEAD(&dentry->d_lru);

961INIT_LIST_HEAD(&dentry->d_subdirs);

962INIT_LIST_HEAD(&dentry->d_alias);

963

964if (parent) {

965dentry->d_parent =

dget(parent);

966dentry->d_sb =

parent->d_sb;

967} else {

968INIT_LIST_HEAD(&dentry->d_u.d_child);

969}

970

971spin_lock(&dcache_lock);

972if (parent)

973list_add(&dentry->d_u.d_child, &parent->d_subdirs);

974dentry_stat.nr_dentry++;

975spin_unlock(&dcache_lock);

976

977return dentry;

978

}

---------------------------------------------------------------------

(3)、若分配失败则返回-ENOMEM。

(4)、成功分配目录项,则执行父目录索引节点的lookup方法从磁盘读取该目录,创建一个新的目录项对象并把它插入到目录项高速缓存中,然后创建一个新的索引节点对象并把它插入到索引节点高速缓存中。解除对父目录的inode的i_mutex锁,然后检查返回值的类型,若是错误码,则返回错误码。若是有效地目录项,则设置path->mnt为nd->path.mnt,path->dentry为查找到的目录项dentry。然后在path上调用__follow_mount(path)并返回0。

4、非常幸运的直接在目录项缓存中找到了要查找的目录项对象,则

a.调用do_revalidate(dentry,

nd)检查其有效性,若返回NULL,则执行同第3不完全相同的操作。

b.若返回非NULL,检查返回值的类型,若是错误码,则返回错误码。若是有效地目录项,则设置path->mnt为nd->path.mnt,path->dentry为查找到的目录项dentry。然后在path上调用__follow_mount(path)并返回0。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值