查看文章
 
inode 结构的管理
2009-09-08 16:11

inode结构前三个字段就是用来帮助将inode串起来的字段,分别是

struct list_head i_hash;
struct list_head i_list;
struct list_head i_dentry;  

   这跟我们在super block那里所看到的s_list是属于同样的型别,都是struct list_head。list_head这种结构在Kernel里实在用的很多,事实上,它也的确很好用。我们将在这篇文章的最后跟您彻底讨论 list_head结构以及它的用法。现在我们只要知道list_head可以帮我们将一些结构串行在一起就够了。在VFS里,有四个串行是用来管理 inode的,分别是inode_unused用来将目前还没使用的inode串在一起,它就是使用i_list这个字段。第二个是 inode_in_use用来将目前正在使用的inode串在一起,当一个inode被使用时,它会从inode_unused中被取出来,因此,此时 i_list不会被用到,接着它会利用i_list字段放到inode_in_use中。第三个是sb->s_dirty用来将dirty inode串行在一起。这个串行的开头位于super block的s_dirty字段,一样也是使用i_list串接。所有正在使用中的inode都可以经由inode_in_use串行找到,但是,因为系 统的inode太多,所以,串行可能会很长,如果慢慢找,在速度上并不理想,因此,每个使用中的inode都会计算出其hash value,并且放到hash table,但是hash table有时会有collision的情形出现,因此每一个entry是由一个list串接起来,这个list就是利用i_hash字段来串接的。至于 i_dentry是在dcache中使用的,dcache利用这个字段将inode串接起来。
============

Linux inode cache机制实现在fs/inode.c文件中。  
1.1.Inode的slab分配器缓存   
索引节点缓存(inode cache,简称icache)机制的实现是以inode对象的slab分配器缓存为基础的,因此要从物理内存中申请或释放一个inode对象,都必须通 过kmem_cache_alloc()函数和kmem_cache_free()函数来进行。   

Inode对象的slab分配缓存由一个kmem_cache_t类型的指针变量inode_cachep来定义。这个slab分配器缓存是在 inode cache的初始化函数inode_init()中通过kmem_cache_create()函数来创建的。   Linux在inode.c文件中又定义了两个封装函数,来实现从inode_cachep slab分配器缓存中分配一个inode对象或将一个不再使用的inode对象释放给slab分配器,如下所示:   
#define alloc_inode() \   ((strUCt inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))   static void destroy_inode(struct inode *inode)   {   if (!list_empty(&inode->i_dirty_buffers))   BUG();   kmem_cache_free(inode_cachep, (inode));   }     

1.3 icache数据结构   
Linux通过在inode_cachep slab分配器缓存之上定义各种双向链表来实现inode缓存机制,以便有效地管理内存inode对象。这些链表包括:正在使用的inode链表、未使用 的inode链表、inode哈希链表和匿名inode的哈希链表,他们的定义如下:   
static LIST_HEAD(inode_in_use);   
static LIST_HEAD(inode_unused);   
static struct list_head *inode_hashtable;   
static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */   
此外,每个超级块对象super_block中还有一条被修改过的、且正在使用的inode双向链表s_dirty。   每一个inode对象都会存在于两个分离的双向链表中:   
(1)一个就是inode哈希链表inode_hashtable,用来加快inode查找,每个inode对象都通过I_hash指针链入哈希链表 中。   
(2)另一个就是inode的“类型”链表:   
l 如果I _count>0、I_nlink>0且该inode不脏,则这个inode就通过其I_list指针链入系统全局的 inode_in_use双向链表。   
l 如果I _count和I_nlink都大于0,但是这个inode为脏(既I_state域中设置了I_DIRTY标志),则这个inode通过 I_list指针链入他所属的super_block对象的s_dirty链表。   
l 如果I _count=0,则通过其I_list链入inode_unused链表。 对于那些不属于任何超级块对象(即I_sb=NULL)的匿名inode对象,则通过I_hash指针链入系统全局的匿名inode哈希链表 anon_hash_chain。    

1.3.1 对inode缓存链表的锁保护
  
Linux在inode.c中定义了自旋锁inode_lock,来实现对所有inode缓存链表的互斥访问。也即,任何访问任意一条inode缓存 链表的代码段,都必须通过调用spin_lock()函数持有该自旋锁,并在结束访问后通过spin_unlock()释放该自旋锁。 Inode_lock的定义如下:   Spinlock_t inode_lock=SPIN_LOCK_UNLOCKED;   NOTE!如果要改变一个正在使用的inode对象的I_state域,也必须先持有该自旋锁。  

1.3.2 inode缓存的统计信息   全局变量inodes_stat定义了inode cache的统计信息,主要包括cache中的inode对象总数和其中未使用的inode个数,其定义如下:   struct {   int nr_inodes;   int nr_unused;   int dummy[5];   } inodes_stat;     

1.3.3 inode哈希链表   inode哈希链表的主要用途是加快在icache中查找一个特定的inode对象。指针inode_hashtable指向一组哈希链表表头,所有 哈希函数值(记为h)相同的inode对象都通过I_hash指针作为接口组成双向链表,并挂在inode_hashtable[h]这个哈希链表表头之 后。所有哈希链表表头都放在一起组成一个数组,该数组的首地址由指针inode_hashtable所指向。   在Linux中,inode哈希链表表头数组是存放在2order个连续的物理页帧中的,其中,order≥1,且它的值与系统总的物理页帧数 num_physpages的值相关。因此,哈希链表表头的个数为:2order*PAGE_SIZE/sizeof(struct list_head)。由于list_head结构类型的大小是8个字节(2个32位指针),因此:inode哈希链表表头的个数可以表示 为:2(order+12-3)。   1 哈希链表的初始化   inode cache的初始化工作是由inode_init()函数来完成的,它主要完成两项工作:(1)inode哈希链表的初始化,包括为inode哈希链表表 头数组分配物理内存等;(2)创建inode slab分配器缓存。该函数的源代码如下:   /*   * Initialize the hash tables.   */   void __init inode_init(unsigned long mempages)   {   struct list_head *head;   unsigned long order;   unsigned int nr_hash;   int i;     /*计算order的值,但是我不知道为什么要这样计算?:) */   mempages >>= (14 - PAGE_SHIFT);   mempages *= sizeof(struct list_head);

类别:linux_os||添加到搜藏 |分享到i贴吧|浏览(862)|评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu