Linux虚拟文件系统(内核初始化<二>)

字体大小: 中小 标准 ->行高大小: 标准

这部分主要对linux虚拟文件系统内核初始化部分做些补充。

关于shrinker,inode和dentry cache初始化阶段都需要注册自己的shrinker,用于缩减cache。两个操作原理类似。

shrinker数据结构介绍

[cpp]

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

1,注册inode cache shrinker

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

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

其中相关的函数在这里定义。

[cpp]
  1. static struct shrinker dcache_shrinker = {       .shrink = shrink_dcache_memory,  
  2.     .seeks = DEFAULT_SEEKS,   };  
[cpp]
  1. /*   * Scan `nr' dentries and return the number which remain. 
  2.  *   * We need to avoid reentering the filesystem if the caller is performing a 
  3.  * GFP_NOFS allocation attempt.  One example deadlock is:   * 
  4.  * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache->   * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->put_inode-> 
  5.  * ext2_discard_prealloc->ext2_free_blocks->lock_super->DEADLOCK.   * 
  6.  * In this case we return -1 to tell the caller that we baled.   */  
  7. static int shrink_dcache_memory(int nr, gfp_t gfp_mask)   {  
  8.     if (nr) {           if (!(gfp_mask & __GFP_FS))  
  9.             return -1;           prune_dcache(nr);/*缩减指定大小的cache*/  
  10.     }       return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;  
  11. }  
[cpp]
  1. /**   * prune_dcache - shrink the dcache 
  2.  * @count: number of entries to try to free   * 
  3.  * Shrink the dcache. This is done when we need more memory, or simply when we   * need to unmount something (at which point we need to unuse all dentries). 
  4.  *   * This function may fail to free any resources if all the dentries are in use. 
  5.  */    /*缩减dcache,count为释放的数量*/  
  6. static void prune_dcache(int count)   {  
  7.     struct super_block *sb;       int w_count;  
  8.     int unused = dentry_stat.nr_unused;       int prune_ratio;  
  9.     int pruned;     
  10.     if (unused == 0 || count == 0)           return;  
  11.     spin_lock(&dcache_lock);   restart:  
  12.     if (count >= unused)           prune_ratio = 1;/*释放率*/  
  13.     else           prune_ratio = unused / count;  
  14.     spin_lock(&sb_lock);       list_for_each_entry(sb, &super_blocks, s_list) {  
  15.         if (sb->s_nr_dentry_unused == 0)               continue;  
  16.         sb->s_count++;           /* Now, we reclaim unused dentrins with fairness. 
  17.          * We reclaim them same percentage from each superblock.           * We calculate number of dentries to scan on this sb 
  18.          * as follows, but the implementation is arranged to avoid           * overflows: 
  19.          * number of dentries to scan on this sb =           * count * (number of dentries on this sb / 
  20.          * number of dentries in the machine)           */  
  21.         spin_unlock(&sb_lock);           /*重新利用释放率计算释放量*/  
  22.         if (prune_ratio != 1)               w_count = (sb->s_nr_dentry_unused / prune_ratio) + 1;  
  23.         else               w_count = sb->s_nr_dentry_unused;  
  24.         pruned = w_count;           /* 
  25.          * We need to be sure this filesystem isn't being unmounted,           * otherwise we could race with generic_shutdown_super(), and 
  26.          * end up holding a reference to an inode while the filesystem           * is unmounted.  So we try to get s_umount, and make sure 
  27.          * s_root isn't NULL.           */  
  28.         if (down_read_trylock(&sb->s_umount)) {               if ((sb->s_root != NULL) &&  
  29.                 (!list_empty(&sb->s_dentry_lru))) {                   spin_unlock(&dcache_lock);  
  30.                 /*实际释放工作*/                   __shrink_dcache_sb(sb, &w_count,  
  31.                         DCACHE_REFERENCED);                   pruned -= w_count;  
  32.                 spin_lock(&dcache_lock);               }  
  33.             up_read(&sb->s_umount);           }  
  34.         spin_lock(&sb_lock);           count -= pruned;  
  35.         /*           * restart only when sb is no longer on the list and 
  36.          * we have more work to do.           */  
  37.         if (__put_super_and_need_restart(sb) && count > 0) {               spin_unlock(&sb_lock);  
  38.             goto restart;           }  
  39.     }       spin_unlock(&sb_lock);  
  40.     spin_unlock(&dcache_lock);   }  

此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/57827.html