VFS目录项读取和缓存

来源:互联网 发布:淘宝上好看的男鞋店 编辑:程序博客网 时间:2024/05/16 14:00

 

VFS中,文件的inode是通过dentry索引的,只有知道一个文件名(比如:/usr/src/perl)所对应的dentry对象,才能找到inode并最终读取文件在磁盘中的数据页。典型文件系统ext2/txt3中目录项内容存储在普通文件中,为了减少磁盘IO次数,内核构建了一个dentrycache用来存放读取过的目录项,并且通过hash表加速文件名->dentry对象的过程。下面从内核初始化dentrycachehash表来表述内核对目录项读取的优化方法。

dentry_cachedentry_hashtable是目录项缓存的两个重要数据结构。

 

  1. Dentrycache:内核需要申请一块内存作为dentry对象的缓存。/init/main.c中的vfs_caches_init_earlyvfs_caches_init执行了VFS数据结构(inode等)的初始化过程,当然包括了dentry的初始化过程dcache_init。在dcache_init中,dentry_cache=KMEM_CACHE,这是一个初始化dentryslab分配器过程(内存管理中的slab分配,参考:http://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/http://www.ibm.com/developerworks/cn/linux/l-cn-slub/)。以后的dentry对象所使用的内存都是通过这个slab分配器分配的。通过/proc/slabinfo可以看到内核当前的内存使用情况:一个典型值dentry7630 9512 132 29 1 : tunables 120 60 0 : slabdata 328 328 0(意思参考:http://elinux.org/Slab_allocator)。

  2. Dentryhashtable,这也个是一个在内核启动过程中初始化的一个数据,这个hash表的具体大小1,可以通过内核参数传递见/Documentation/kernel-parameters.txtdhash_entries= [KNL]2,如果不设置默认内核分配(1/16当前ram大小),见:

dentry_hashtable=

alloc_large_system_hash("Dentrycache",

sizeof(structhlist_head),

dhash_entries,

13,

0,

&d_hash_shift,

&d_hash_mask,

0);

for(loop= 0; loop< (1 << d_hash_shift);loop++)

INIT_HLIST_HEAD(&dentry_hashtable[loop]);

,其中alloc_large_system_hash为内核在初始化阶段(alloc_bootmem_nopanic)分配hash表的典型方法,这个方法中,dhash_entries如果设置则为设置大小(2pow),否则内核根据scale(第四个参数13,表示没2^13bytes有一个hashbucket),以及最后一个参数(limit0表示1/16ram,根据scale设置的大小不超过limit的值)。D_hash_shift为返回的创建的hash包含元素的个数,利用最后一个for循环初始化。

  1. hash表查找:link_path_look方法调用do_lookup进行查找,进一步调用dentry= __d_lookup(nd->path.dentry,name);,在__d_lookup方法中对hash表进行查找具体方法为:hlist_for_each_entry_rcu,这里面设计一个rcu机制(参考:http://www.ibm.com/developerworks/cn/linux/l-rcu/http://blog.chinaunix.net/u3/101219/showart_2183663.html),当然,如果在dentrycache中查找到则发挥dentry,否则就要调用具体文件系统的查找方法dentry= dir->i_op->lookup(dir,new,nd);

4,具体文件系统的查找视不同文件系统而不同,但都是利用外键在磁盘上查找(B-TREE等)