天天看点

Linux文件系统(四)---三大缓冲区之inode缓冲区 (内存inode映像 )

在文件系统中,有三大缓冲为了提升效率:inode缓冲区、dentry缓冲区、块缓冲。

(内核:2.4.37)

一、inode缓冲区

为了加快对索引节点的索引,引入inode缓冲区,下面我们看Linux/fs/inode.c代码。inode缓冲区代码

1、一些数据结构:

之前已经说过,有多个链表用于管理inode节点:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">59 static LIST_HEAD(inode_in_use);  
  2.  60 static LIST_HEAD(inode_unused);  
  3.  61 static LIST_HEAD(inode_unused_pagecache);  
  4.  62 static struct list_head *inode_hashtable;  
  5.  63 static LIST_HEAD(anon_hash_chain); </span>  

inode_in_use:正在使用的inode,即有效的inode,i_count > 0且i_nlink > 0。

inode_unused:有效的节点,但是还没有使用,处于空闲状态。(数据不在pagecache中)。

inode_unused_pagecache:同上。(数据在pagecache中)。

inode_hashtable:用于inode在hash表中,提高查找效率。

anon_hash_chain:用于超级块是空的的inodes。例如:sock_alloc()函数, 通过调用fs/inode.c中get_empty_inode()创建的套接字是一个匿名索引节点,这个节点就加入到了anon_hash_chain链表。

dirty:用于保存超级块中的所有的已经修改的inodes。

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;"> 76 struct inodes_stat_t inodes_stat;  
  2.  77   
  3.  78 static kmem_cache_t * inode_cachep;</span>  

上面的两个字段:

inodes_stat:记录inodes节点的状态。

inode_cachep:对inodes对象的缓存块。

2、基本初始化:初始化inode哈希表头和slab内存缓存块

索引节点高速缓存的初始化是由inode_init()实现的,现在看看下面代码:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">1296   
  2. 1299 void __init inode_init(unsigned long mempages)     
  3. 1300 {  
  4. 1301         struct list_head *head;  
  5. 1302         unsigned long order;  
  6. 1303         unsigned int nr_hash;  
  7. 1304         int i;  
  8. 1305           
  9. 1306         mempages >>= (14 - PAGE_SHIFT);  
  10. 1307         mempages *= sizeof(struct list_head);  
  11. 1308         for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)  
  12. 1309                 ;  
  13. 1310   
  14. 1311         do {  
  15. 1312                 unsigned long tmp;  
  16. 1313   
  17. 1314                 nr_hash = (1UL << order) * PAGE_SIZE /  
  18. 1315                         sizeof(struct list_head);  
  19. 1316                 i_hash_mask = (nr_hash - 1);  
  20. 1317   
  21. 1318                 tmp = nr_hash;  
  22. 1319                 i_hash_shift = 0;  
  23. 1320                 while ((tmp >>= 1UL) != 0UL)  
  24. 1321                         i_hash_shift++;  
  25. 1322                   
  26. 1323                 inode_hashtable = (struct list_head *)  
  27. 1324                         __get_free_pages(GFP_ATOMIC, order);  
  28. 1325         } while (inode_hashtable == NULL && --order >= 0);  
  29. 1326   
  30. 1327         printk(KERN_INFO "Inode cache hash table entries: %d (order: %ld, %ld bytes)\n",  
  31. 1328                         nr_hash, order, (PAGE_SIZE << order));  
  32. 1329           
  33. 1330         if (!inode_hashtable)  
  34. 1331                 panic("Failed to allocate inode hash table\n");  
  35. 1332           
  36. 1333         head = inode_hashtable;  
  37. 1334         i = nr_hash;  
  38. 1335         do {  
  39. 1336                 INIT_LIST_HEAD(head);  
  40. 1337                 head++;  
  41. 1338                 i--;  
  42. 1339         } while (i);  
  43. 1340   
  44. 1341           
  45. 1342         inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),  
  46. 1343                                          0, SLAB_HWCACHE_ALIGN, init_once,  
  47. 1344                                          NULL);  
  48. 1345         if (!inode_cachep)  
  49. 1346                 panic("cannot create inode slab cache");  
  50. 1347   
  51. 1348         unused_inodes_flush_task.routine = try_to_sync_unused_inodes;  
  52. 1349 }  
  53. 1350</span>  

注意上面的逻辑,说明两个问题:

1).  第一初始化inode_hashtable作为链表的头。

2).  初始化inode的slab缓存,也就是说,如果我需要分配一个inode缓存在内存中,那么都从这个inode_cachep中分配一个inode内存节点。然后统一加入到这个inode_hashtable中进行管理!也就是所谓的创建inode slab分配器缓存。

下面看看具体的缓存的分配过程:

先看init_once函数:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">169 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)  
  2. 170 {  
  3. 171         struct inode * inode = (struct inode *) foo;  
  4. 172   
  5. 173         if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==  
  6. 174             SLAB_CTOR_CONSTRUCTOR)  
  7. 175                 inode_init_once(inode);  
  8. 176 }</span>  

注意:在上面的kmem_cache_create函数中,执行的顺序是:

---> kmem_cache_create(里面重要的一步是cachep->ctor = ctor; cachep->dtor = dtor;)

---> kmem_cache_alloc

---> __kmem_cache_alloc

---> kmem_cache_grow(里面一个重要设置是:ctor_flags = SLAB_CTOR_CONSTRUCTOR;)

---> kmem_cache_init_objs:里面会执行cachep->ctor(objp, cachep, ctor_flags);

这样最终就跳转到上面的init_once函数中了!在init函数中执行的是inode_init_once函数:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">141   
  2. 146 void inode_init_once(struct inode *inode)  
  3. 147 {  
  4. 148         memset(inode, 0, sizeof(*inode));  
  5. 149         __inode_init_once(inode);  
  6. 150 }</span>  

再看__inode_init_once函数:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">152 void __inode_init_once(struct inode *inode)  
  2. 153 {  
  3. 154         init_waitqueue_head(&inode->i_wait);  
  4. 155         INIT_LIST_HEAD(&inode->i_hash);  
  5. 156         INIT_LIST_HEAD(&inode->i_data.clean_pages);  
  6. 157         INIT_LIST_HEAD(&inode->i_data.dirty_pages);  
  7. 158         INIT_LIST_HEAD(&inode->i_data.locked_pages);  
  8. 159         INIT_LIST_HEAD(&inode->i_dentry);  
  9. 160         INIT_LIST_HEAD(&inode->i_dirty_buffers);  
  10. 161         INIT_LIST_HEAD(&inode->i_dirty_data_buffers);  
  11. 162         INIT_LIST_HEAD(&inode->i_devices);  
  12. 163         sema_init(&inode->i_sem, 1);  
  13. 164         sema_init(&inode->i_zombie, 1);  
  14. 165         init_rwsem(&inode->i_alloc_sem);  
  15. 166         spin_lock_init(&inode->i_data.i_shared_lock);  
  16. 167 }</span>  

3、注意知道现在我们主要说了上面的两个基本的问题(红字部分),但是这只是一个框架而已,对于具体的一个文件系统来说怎么个流程,下面需要看看!

我们以最常见的ext2作为说明:

现在一个ext2类型的文件系统想要创建一个inode,那么执行:ext2_new_inode函数

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">314 struct inode * ext2_new_inode (const struct inode * dir, int mode)  
  2. 315 {  
  3. 316         struct super_block * sb;  
  4. 317         struct buffer_head * bh;  
  5. 318         struct buffer_head * bh2;  
  6. 319         int group, i;  
  7. 320         ino_t ino;  
  8. 321         struct inode * inode;  
  9. 322         struct ext2_group_desc * desc;  
  10. 323         struct ext2_super_block * es;  
  11. 324         int err;  
  12. 325   
  13. 326         sb = dir->i_sb;  
  14. 327         inode = new_inode(sb);     
  15. 328         if (!inode)  
  16. 329                 return ERR_PTR(-ENOMEM);  
  17. 330   
  18. 331         lock_super (sb);  
  19. 332         es = sb->u.ext2_sb.s_es;  
  20. 333 repeat:  
  21. 334         if (S_ISDIR(mode))  
  22. 335                 group = find_group_dir(sb, dir->u.ext2_i.i_block_group);  
  23. 336         else   
  24. 337                 group = find_group_other(sb, dir->u.ext2_i.i_block_group);  
  25. 338   
  26. 339         err = -ENOSPC;  
  27. 340         if (group == -1)  
  28. 341                 goto fail;  
  29. 342   
  30. 343         err = -EIO;  
  31. 344         bh = load_inode_bitmap (sb, group);  
  32. 345         if (IS_ERR(bh))  
  33. 346                 goto fail2;  
  34. 347   
  35. 348         i = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,  
  36. 349                                       EXT2_INODES_PER_GROUP(sb));  
  37. 350         if (i >= EXT2_INODES_PER_GROUP(sb))  
  38. 351                 goto bad_count;  
  39. 352         ext2_set_bit (i, bh->b_data);  
  40. 353   
  41. 354         mark_buffer_dirty(bh);  
  42. 355         if (sb->s_flags & MS_SYNCHRONOUS) {  
  43. 356                 ll_rw_block (WRITE, 1, &bh);  
  44. 357                 wait_on_buffer (bh);  
  45. 358         }  
  46. 359   
  47. 360         ino = group * EXT2_INODES_PER_GROUP(sb) + i + 1;  
  48. 361         if (ino < EXT2_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {  
  49. 362                 ext2_error (sb, "ext2_new_inode",  
  50. 363                             "reserved inode or inode > inodes count - "  
  51. 364                             "block_group = %d,inode=%ld", group, ino);  
  52. 365                 err = -EIO;  
  53. 366                 goto fail2;  
  54. 367         }  
  55. 368   
  56. 369         es->s_free_inodes_count =  
  57. 370                 cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1);  
  58. 371         mark_buffer_dirty(sb->u.ext2_sb.s_sbh);  
  59. 372         sb->s_dirt = 1;  
  60. 373         inode->i_uid = current->fsuid;  
  61. 374         if (test_opt (sb, GRPID))  
  62. 375                 inode->i_gid = dir->i_gid;  
  63. 376         else if (dir->i_mode & S_ISGID) {  
  64. 377                 inode->i_gid = dir->i_gid;  
  65. 378                 if (S_ISDIR(mode))  
  66. 379                         mode |= S_ISGID;  
  67. 380         } else  
  68. 381                 inode->i_gid = current->fsgid;  
  69. 382         inode->i_mode = mode;  
  70. 383   
  71. 384         inode->i_ino = ino;  
  72. 385         inode->i_blksize = PAGE_SIZE;     
  73. 386         inode->i_blocks = 0;  
  74. 387         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;  
  75. 388         inode->u.ext2_i.i_state = EXT2_STATE_NEW;  
  76. 389         inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags & ~EXT2_BTREE_FL;  
  77. 390         if (S_ISLNK(mode))  
  78. 391                 inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);  
  79. 392         inode->u.ext2_i.i_block_group = group;  
  80. 393         ext2_set_inode_flags(inode);  
  81. 394         insert_inode_hash(inode);             
  82. 395         inode->i_generation = event++;  
  83. 396         mark_inode_dirty(inode);  
  84. 397   
  85. 398         unlock_super (sb);  
  86. 399         if(DQUOT_ALLOC_INODE(inode)) {  
  87. 400                 DQUOT_DROP(inode);  
  88. 401                 inode->i_flags |= S_NOQUOTA;  
  89. 402                 inode->i_nlink = 0;  
  90. 403                 iput(inode);  
  91. 404                 return ERR_PTR(-EDQUOT);  
  92. 405         }  
  93. 406         ext2_debug ("allocating inode %lu\n", inode->i_ino);  
  94. 407         return inode;  
  95. 408   
  96. 409 fail2:  
  97. 410         desc = ext2_get_group_desc (sb, group, &bh2);  
  98. 411         desc->bg_free_inodes_count =  
  99. 412                 cpu_to_le16(le16_to_cpu(desc->bg_free_inodes_count) + 1);  
  100. 413         if (S_ISDIR(mode))  
  101. 414                 desc->bg_used_dirs_count =  
  102. 415                         cpu_to_le16(le16_to_cpu(desc->bg_used_dirs_count) - 1);  
  103. 416         mark_buffer_dirty(bh2);  
  104. 417 fail:  
  105. 418         unlock_super(sb);  
  106. 419         make_bad_inode(inode);  
  107. 420         iput(inode);  
  108. 421         return ERR_PTR(err);  
  109. 422   
  110. 423 bad_count:  
  111. 424         ext2_error (sb, "ext2_new_inode",  
  112. 425                     "Free inodes count corrupted in group %d",  
  113. 426                     group);  
  114. 427           
  115. 428         err = -ENOSPC;  
  116. 429         if (sb->s_flags & MS_RDONLY)  
  117. 430                 goto fail;  
  118. 431   
  119. 432         desc = ext2_get_group_desc (sb, group, &bh2);  
  120. 433         desc->bg_free_inodes_count = 0;  
  121. 434         mark_buffer_dirty(bh2);  
  122. 435         goto repeat;  
  123. 436 }</span>  

这个函数比较复杂,但是我们主要看327行和394行,就是创建一个inode内存节点,然后将这个inode插入inode_hashtable中!

这个函数具体的解释不再看了,现在主要从这两个函数入手:

1). fs/inode.c中的new_inode函数,创建一个inode内存节点:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">964 struct inode * new_inode(struct super_block *sb)  
  2. 965 {  
  3. 966         static unsigned long last_ino;  
  4. 967         struct inode * inode;  
  5. 968   
  6. 969         spin_lock_prefetch(&inode_lock);  
  7. 970           
  8. 971         inode = alloc_inode(sb);  
  9. 972         if (inode) {  
  10. 973                 spin_lock(&inode_lock);  
  11. 974                 inodes_stat.nr_inodes++;    
  12. 975                 list_add(&inode->i_list, &inode_in_use);   
  13. 976                 inode->i_ino = ++last_ino;   
  14. 977                 inode->i_state = 0;  
  15. 978                 spin_unlock(&inode_lock);  
  16. 979         }  
  17. 980         return inode;  
  18. 981 }</span>  

看看这个alloc_inode函数:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;"> 80 static struct inode *alloc_inode(struct super_block *sb)  
  2.  81 {  
  3.  82         static struct address_space_operations empty_aops;  
  4.  83         static struct inode_operations empty_iops;  
  5.  84         static struct file_operations empty_fops;  
  6.  85         struct inode *inode;  
  7.  86   
  8.  87         if (sb->s_op->alloc_inode)     
  9.  88                 inode = sb->s_op->alloc_inode(sb);  
  10.  89         else {  
  11.  90                 inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);  
  12.  91                   
  13.  92                 if (inode)  
  14.  93                         memset(&inode->u, 0, sizeof(inode->u));  
  15.  94         }  
  16.  95           
  17.  96         if (inode) {  
  18.  97                 struct address_space * const mapping = &inode->i_data;  
  19.  98   
  20.  99                 inode->i_sb = sb;  
  21. 100                 inode->i_dev = sb->s_dev;  
  22. 101                 inode->i_blkbits = sb->s_blocksize_bits;  
  23. 102                 inode->i_flags = 0;  
  24. 103                 atomic_set(&inode->i_count, 1);  
  25. 104                 inode->i_sock = 0;  
  26. 105                 inode->i_op = &empty_iops;  
  27. 106                 inode->i_fop = &empty_fops;  
  28. 107                 inode->i_nlink = 1;  
  29. 108                 atomic_set(&inode->i_writecount, 0);  
  30. 109                 inode->i_size = 0;  
  31. 110                 inode->i_blocks = 0;  
  32. 111                 inode->i_bytes = 0;  
  33. 112                 inode->i_generation = 0;  
  34. 113                 memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));  
  35. 114                 inode->i_pipe = NULL;  
  36. 115                 inode->i_bdev = NULL;  
  37. 116                 inode->i_cdev = NULL;  
  38. 117   
  39. 118                 mapping->a_ops = &empty_aops;  
  40. 119                 mapping->host = inode;  
  41. 120                 mapping->gfp_mask = GFP_HIGHUSER;  
  42. 121                 inode->i_mapping = mapping;  
  43. 122         }  
  44. 123         return inode;  
  45. 124 }</span>  

我们主要看87行和90行!看了注释也就明白了!第一种是文件系统也就是这个超级快提供了分配函数,那么就这个文件系统按照自己的意愿去分配,如果没有,那么就是要用这个通用的分配函数inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);这个函数其实很简单,其实就是在我们已经初始化好的这个inode_cache中分配一个inode内存块出来。

2). fs/inode.c中的insert_inode_hash函数,将新的分配的inode插入到inode_hashtable中:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">1166 void insert_inode_hash(struct inode *inode)  
  2. 1167 {  
  3. 1168         struct list_head *head = &anon_hash_chain;    
  4. 1169         if (inode->i_sb)  
  5. 1170                 head = inode_hashtable + hash(inode->i_sb, inode->i_ino);   
  6. 1171         spin_lock(&inode_lock);  
  7. 1172         list_add(&inode->i_hash, head);  
  8. 1173         spin_unlock(&inode_lock);  
  9. 1174 }</span>  

注意这个hash表其实就可以看做是一个数组链表组合体,如图所示:

Linux文件系统(四)---三大缓冲区之inode缓冲区 (内存inode映像 )

head = inode_hashtable + hash(inode->i_sb, inode->i_ino);这一行就是通过这个hash函数算出hash值,找到这个inode应该放在哪一列。譬如定位到第三列,那么第三列中的都是hash值相同的inode。然后所有的这列inode都是构成双向链表的。注意inode中的i_hash字段就做这个事的!!list_add(&inode->i_hash, head);函数就是将hash值相同的inode构成双向链表。

看一下这个具体的hash函数(inode.c中):

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">1043 static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)  
  2. 1044 {  
  3. 1045         unsigned long tmp = i_ino + ((unsigned long) sb / L1_CACHE_BYTES);  
  4. 1046         tmp = tmp + (tmp >> I_HASHBITS);  
  5. 1047         return tmp & I_HASHMASK;  
  6. 1048 }</span>  

OK,上面的具体的inode创建和加入的流程基本清楚了。具体创建的过程是涉及到内存这一块的,不多说了。

4. 下面看看给一个怎么去找到一个inode,涉及ilookup函数:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">1102 struct inode *ilookup(struct super_block *sb, unsigned long ino)  
  2. 1103 {  
  3. 1104         struct list_head * head = inode_hashtable + hash(sb,ino);  
  4. 1105         struct inode * inode;  
  5. 1106   
  6. 1107         spin_lock(&inode_lock);  
  7. 1108         inode = find_inode(sb, ino, head, NULL, NULL);    
  8. 1109         if (inode) {  
  9. 1110                 __iget(inode);  
  10. 1111                 spin_unlock(&inode_lock);  
  11. 1112                 wait_on_inode(inode);  
  12. 1113                 return inode;  
  13. 1114         }  
  14. 1115         spin_unlock(&inode_lock);  
  15. 1116   
  16. 1117         return inode;  
  17. 1118 }</span>  

这个函数其实比较简单了,首先还是获得这个inode的hash值定位,然后开始finde_inode:

[cpp]  view plain copy print ?

  1. <span style="font-size:14px;">929 static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)  
  2. 930 {  
  3. 931         struct list_head *tmp;  
  4. 932         struct inode * inode;  
  5. 933   
  6. 934 repeat:  
  7. 935         tmp = head;  
  8. 936         for (;;) {  
  9. 937                 tmp = tmp->next;  
  10. 938                 inode = NULL;  
  11. 939                 if (tmp == head)     
  12. 940                         break;  
  13. 941                 inode = list_entry(tmp, struct inode, i_hash);   
  14. 942                 if (inode->i_ino != ino)   
  15. 943                         continue;  
  16. 944                 if (inode->i_sb != sb)   
  17. 945                         continue;  
  18. 946                 if (find_actor && !find_actor(inode, ino, opaque))   
  19. 947                         continue;  
  20. 948                 if (inode->i_state & (I_FREEING|I_CLEAR)) {   
  21. 949                         __wait_on_freeing_inode(inode);  
  22. 950                         goto repeat;  
  23. 951                 }  
  24. 952                 break;  
  25. 953         }  
  26. 954         return inode;   
  27. 955 }</span>  

上面函数最核心的本质不就是双向链表的查找么,OK。

最后:关于inode怎么工作的,将会在后面的分析ext2代码中在详细研究。

继续阅读