歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux虛擬文件系統(內核初始化<二>)

Linux虛擬文件系統(內核初始化<二>)

日期:2017/2/28 15:57:11   编辑:Linux教程

這部分主要對linux虛擬文件系統內核初始化部分做些補充。

關於shrinker,inode和dentry cache初始化階段都需要注冊自己的shrinker,用於縮減cache。兩個操作原理類似。

shrinker數據結構介紹

[cpp]

  1. /*
  2. * A callback you can register to apply pressure to ageable caches.
  3. *
  4. * 'shrink' is passed a count 'nr_to_scan' and a 'gfpmask'. It should
  5. * look through the least-recently-used 'nr_to_scan' entries and
  6. * attempt to free them up. It should return the number of objects
  7. * which remain in the cache. If it returns -1, it means it cannot do
  8. * any scanning at this time (eg. there is a risk of deadlock).
  9. *
  10. * The 'gfpmask' refers to the allocation we are currently trying to
  11. * fulfil.
  12. *
  13. * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is
  14. * querying the cache size, so a fastpath for that case is appropriate.
  15. */
  16. struct shrinker {
  17. int (*shrink)(int nr_to_scan, gfp_t gfp_mask);
  18. int seeks; /* seeks to recreate an obj */
  19. /* These are for internal use */
  20. struct list_head list;
  21. long nr; /* objs pending delete */
  22. };

1,注冊inode cache shrinker

Start_kernel()->vfs_caches_init()->dcache_init()->register_shrinker(&dcache_shrinker);

[cpp]
  1. /*
  2. * Add a shrinker callback to be called from the vm
  3. */
  4. void register_shrinker(struct shrinker *shrinker)
  5. {
  6. shrinker->nr = 0;
  7. down_write(&shrinker_rwsem);
  8. list_add_tail(&shrinker->list, &shrinker_list);
  9. up_write(&shrinker_rwsem);
  10. }

其中相關的函數在這裡定義。

[cpp]
  1. static struct shrinker dcache_shrinker = {
  2. .shrink = shrink_dcache_memory,
  3. .seeks = DEFAULT_SEEKS,
  4. };
[cpp]
  1. /*
  2. * Scan `nr' dentries and return the number which remain.
  3. *
  4. * We need to avoid reentering the filesystem if the caller is performing a
  5. * GFP_NOFS allocation attempt. One example deadlock is:
  6. *
  7. * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache->
  8. * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->put_inode->
  9. * ext2_discard_prealloc->ext2_free_blocks->lock_super->DEADLOCK.
  10. *
  11. * In this case we return -1 to tell the caller that we baled.
  12. */
  13. static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
  14. {
  15. if (nr) {
  16. if (!(gfp_mask & __GFP_FS))
  17. return -1;
  18. prune_dcache(nr);/*縮減指定大小的cache*/
  19. }
  20. return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
  21. }
[cpp]
  1. /**
  2. * prune_dcache - shrink the dcache
  3. * @count: number of entries to try to free
  4. *
  5. * Shrink the dcache. This is done when we need more memory, or simply when we
  6. * need to unmount something (at which point we need to unuse all dentries).
  7. *
  8. * This function may fail to free any resources if all the dentries are in use.
  9. */
  10. /*縮減dcache,count為釋放的數量*/
  11. static void prune_dcache(int count)
  12. {
  13. struct super_block *sb;
  14. int w_count;
  15. int unused = dentry_stat.nr_unused;
  16. int prune_ratio;
  17. int pruned;
  18. if (unused == 0 || count == 0)
  19. return;
  20. spin_lock(&dcache_lock);
  21. restart:
  22. if (count >= unused)
  23. prune_ratio = 1;/*釋放率*/
  24. else
  25. prune_ratio = unused / count;
  26. spin_lock(&sb_lock);
  27. list_for_each_entry(sb, &super_blocks, s_list) {
  28. if (sb->s_nr_dentry_unused == 0)
  29. continue;
  30. sb->s_count++;
  31. /* Now, we reclaim unused dentrins with fairness.
  32. * We reclaim them same percentage from each superblock.
  33. * We calculate number of dentries to scan on this sb
  34. * as follows, but the implementation is arranged to avoid
  35. * overflows:
  36. * number of dentries to scan on this sb =
  37. * count * (number of dentries on this sb /
  38. * number of dentries in the machine)
  39. */
  40. spin_unlock(&sb_lock);
  41. /*重新利用釋放率計算釋放量*/
  42. if (prune_ratio != 1)
  43. w_count = (sb->s_nr_dentry_unused / prune_ratio) + 1;
  44. else
  45. w_count = sb->s_nr_dentry_unused;
  46. pruned = w_count;
  47. /*
  48. * We need to be sure this filesystem isn't being unmounted,
  49. * otherwise we could race with generic_shutdown_super(), and
  50. * end up holding a reference to an inode while the filesystem
  51. * is unmounted. So we try to get s_umount, and make sure
  52. * s_root isn't NULL.
  53. */
  54. if (down_read_trylock(&sb->s_umount)) {
  55. if ((sb->s_root != NULL) &&
  56. (!list_empty(&sb->s_dentry_lru))) {
  57. spin_unlock(&dcache_lock);
  58. /*實際釋放工作*/
  59. __shrink_dcache_sb(sb, &w_count,
  60. DCACHE_REFERENCED);
  61. pruned -= w_count;
  62. spin_lock(&dcache_lock);
  63. }
  64. up_read(&sb->s_umount);
  65. }
  66. spin_lock(&sb_lock);
  67. count -= pruned;
  68. /*
  69. * restart only when sb is no longer on the list and
  70. * we have more work to do.
  71. */
  72. if (__put_super_and_need_restart(sb) && count > 0) {
  73. spin_unlock(&sb_lock);
  74. goto restart;
  75. }
  76. }
  77. spin_unlock(&sb_lock);
  78. spin_unlock(&dcache_lock);
  79. }
Copyright © Linux教程網 All Rights Reserved