感谢支持
我们一直在努力

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

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


关于shrinkerinodedentry 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.   

  20.     /* These are for internal use */  

  21.     struct list_head list;  

  22.     long nr;    /* objs pending delete */  

  23. };  


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.   

  19.     if (unused == 0 || count == 0)  

  20.         return;  

  21.     spin_lock(&dcache_lock);  

  22. restart:  

  23.     if (count >= unused)  

  24.         prune_ratio = 1;/*释放率*/  

  25.     else  

  26.         prune_ratio = unused / count;  

  27.     spin_lock(&sb_lock);  

  28.     list_for_each_entry(sb, &super_blocks, s_list) {  

  29.         if (sb->s_nr_dentry_unused == 0)  

  30.             continue;  

  31.         sb->s_count++;  

  32.         /* Now, we reclaim unused dentrins with fairness. 

  33.          * We reclaim them same percentage from each superblock. 

  34.          * We calculate number of dentries to scan on this sb 

  35.          * as follows, but the implementation is arranged to avoid 

  36.          * overflows: 

  37.          * number of dentries to scan on this sb = 

  38.          * count * (number of dentries on this sb / 

  39.          * number of dentries in the machine) 

  40.          */  

  41.         spin_unlock(&sb_lock);  

  42.         /*重新利用释放率计算释放量*/  

  43.         if (prune_ratio != 1)  

  44.             w_count = (sb->s_nr_dentry_unused / prune_ratio) + 1;  

  45.         else  

  46.             w_count = sb->s_nr_dentry_unused;  

  47.         pruned = w_count;  

  48.         /* 

  49.          * We need to be sure this filesystem isn’t being unmounted, 

  50.          * otherwise we could race with generic_shutdown_super(), and 

  51.          * end up holding a reference to an inode while the filesystem 

  52.          * is unmounted.  So we try to get s_umount, and make sure 

  53.          * s_root isn’t NULL. 

  54.          */  

  55.         if (down_read_trylock(&sb->s_umount)) {  

  56.             if ((sb->s_root != NULL) &&  

  57.                 (!list_empty(&sb->s_dentry_lru))) {  

  58.                 spin_unlock(&dcache_lock);  

  59.                 /*实际释放工作*/  

  60.                 __shrink_dcache_sb(sb, &w_count,  

  61.                         DCACHE_REFERENCED);  

  62.                 pruned -= w_count;  

  63.                 spin_lock(&dcache_lock);  

  64.             }  

  65.             up_read(&sb->s_umount);  

  66.         }  

  67.         spin_lock(&sb_lock);  

  68.         count -= pruned;  

  69.         /* 

  70.          * restart only when sb is no longer on the list and 

  71.          * we have more work to do. 

  72.          */  

  73.         if (__put_super_and_need_restart(sb) && count > 0) {  

  74.             spin_unlock(&sb_lock);  

  75.             goto restart;  

  76.         }  

  77.     }  

  78.     spin_unlock(&sb_lock);  

  79.     spin_unlock(&dcache_lock);  

  80. }  

[cpp]


  1. /* 

  2.  * Shrink the dentry LRU on a given superblock. 

  3.  * @sb   : superblock to shrink dentry LRU. 

  4.  * @count: If count is NULL, we prune all dentries on superblock. 

  5.  * @flags: If flags is non-zero, we need to do special processing based on 

  6.  * which flags are set. This means we don’t need to maintain multiple 

  7.  * similar copies of this loop. 

  8.  */  

  9. static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)  

  10. {  

  11.     LIST_HEAD(referenced);  

  12.     LIST_HEAD(tmp);  

  13.     struct dentry *dentry;  

  14.     int cnt = 0;  

  15.   

  16.     BUG_ON(!sb);  

  17.     BUG_ON((flags & DCACHE_REFERENCED) && count == NULL);  

  18.     spin_lock(&dcache_lock);  

  19.     if (count != NULL)  

  20.         /* called from prune_dcache() and shrink_dcache_parent() */  

  21.         cnt = *count;/*在下面用到*/  

  22. restart:  

  23.     if (count == NULL)  

  24.         list_splice_init(&sb->s_dentry_lru, &tmp);  

  25.     else {  

  26.         while (!list_empty(&sb->s_dentry_lru)) {  

  27.             dentry = list_entry(sb->s_dentry_lru.prev,  

  28.                     struct dentry, d_lru);  

  29.             BUG_ON(dentry->d_sb != sb);  

  30.   

  31.             spin_lock(&dentry->d_lock);  

  32.             /* 

  33.              * If we are honouring the DCACHE_REFERENCED flag and 

  34.              * the dentry has this flag set, don’t free it. Clear 

  35.              * the flag and put it back on the LRU. 

  36.              */  

  37.              /*清flag对应位,将链表元素放LRU尾部*/  

  38.             if ((flags & DCACHE_REFERENCED)  

  39.                 && (dentry->d_flags & DCACHE_REFERENCED)) {  

  40.                 dentry->d_flags &= ~DCACHE_REFERENCED;  

  41.                 list_move(&dentry->d_lru, &referenced);  

  42.                 spin_unlock(&dentry->d_lock);  

  43.             } else {  

  44.                 /*从d_lru链表中删除,加到tmp链表中*/  

  45.                 list_move_tail(&dentry->d_lru, &tmp);  

  46.                 spin_unlock(&dentry->d_lock);  

  47.                 cnt–;/*数量减一*/  

  48.                 if (!cnt)/*减到0跳出循环*/  

  49.                     break;  

  50.             }  

  51.             cond_resched_lock(&dcache_lock);  

  52.         }  

  53.     }  

  54.     /*对tmp中的每个元素,其中tmp中的元素为上面移过来的*/  

  55.     while (!list_empty(&tmp)) {  

  56.         dentry = list_entry(tmp.prev, struct dentry, d_lru);  

  57.         /*从tmp中删除相关链表并做重新初始化和数据统计*/  

  58.         dentry_lru_del_init(dentry);  

  59.         spin_lock(&dentry->d_lock);  

  60.         /* 

  61.          * We found an inuse dentry which was not removed from 

  62.          * the LRU because of laziness during lookup.  Do not free 

  63.          * it – just keep it off the LRU list. 

  64.          */  

  65.         if (atomic_read(&dentry->d_count)) {  

  66.             spin_unlock(&dentry->d_lock);  

  67.             continue;  

  68.         }/*释放dentry和其父dentry*/  

  69.         prune_one_dentry(dentry);  

  70.         /* dentry->d_lock was dropped in prune_one_dentry() */  

  71.         cond_resched_lock(&dcache_lock);  

  72.     }  

  73.     if (count == NULL && !list_empty(&sb->s_dentry_lru))  

  74.         goto restart;  

  75.     if (count != NULL)  

  76.         *count = cnt;  

  77.     if (!list_empty(&referenced))  

  78.         list_splice(&referenced, &sb->s_dentry_lru);  

  79.     spin_unlock(&dcache_lock);  

  80. }  

[cpp]


  1. static void dentry_lru_del_init(struct dentry *dentry)  

  2. {  

  3.     if (likely(!list_empty(&dentry->d_lru))) {  

  4.         list_del_init(&dentry->d_lru);/*从链表中删除并初始化dentry->d_lru*/  

  5.         dentry->d_sb->s_nr_dentry_unused–;/*未用数减一*/  

  6.         dentry_stat.nr_unused–;/*更新统计数据*/  

  7.     }  

  8. }  

[html]


  1. /*  

  2.  * Throw away a dentry – free the inode, dput the parent.  This requires that  

  3.  * the LRU list has already been removed.  

  4.  *  

  5.  * Try to prune ancestors as well.  This is necessary to prevent  

  6.  * quadratic behavior of shrink_dcache_parent(), but is also expected  

  7.  * to be beneficial in reducing dentry cache fragmentation.  

  8.  */  

  9. static void prune_one_dentry(struct dentry * dentry)  

  10.     __releases(dentry->d_lock)  

  11.     __releases(dcache_lock)  

  12.     __acquires(dcache_lock)  

  13. {  

  14.     __d_drop(dentry);  

  15.     dentry = d_kill(dentry);/*释放dentry*/  

  16.   

  17.     /*  

  18.      * Prune ancestors.  Locking is simpler than in dput(),  

  19.      * because dcache_lock needs to be taken anyway.  

  20.      */  

  21.     spin_lock(&dcache_lock);  

  22.     while (dentry) {  

  23.         if (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock))  

  24.             return;  

  25.   

  26.         if (dentry->d_op && dentry->d_op->d_delete)  

  27.             dentry->d_op->d_delete(dentry);  

  28.         dentry_lru_del_init(dentry);  

  29.         __d_drop(dentry);  

  30.         dentry = d_kill(dentry);  

  31.         spin_lock(&dcache_lock);  

  32.     }  

  33. }  

[cpp]


  1. /** 

  2.  * d_kill – kill dentry and return parent 

  3.  * @dentry: dentry to kill 

  4.  * 

  5.  * The dentry must already be unhashed and removed from the LRU. 

  6.  * 

  7.  * If this is the root of the dentry tree, return NULL. 

  8.  */  

  9. static struct dentry *d_kill(struct dentry *dentry)  

  10.     __releases(dentry->d_lock)  

  11.     __releases(dcache_lock)  

  12. {  

  13.     struct dentry *parent;  

  14.   

  15.     list_del(&dentry->d_u.d_child);/*删除子目录*/  

  16.     dentry_stat.nr_dentry–;/*更新统计数据*/  /* For d_free, below */  

  17.     /*drops the locks, at that point nobody can reach this dentry */  

  18.     dentry_iput(dentry);/*”释放”inode*/  

  19.     if (IS_ROOT(dentry))  

  20.         parent = NULL;  

  21.     else  

  22.         parent = dentry->d_parent;  

  23.     d_free(dentry);/*释放dentry*/  

  24.     return parent;  

  25. }  

[cpp]


  1. /* 

  2.  * Release the dentry’s inode, using the filesystem 

  3.  * d_iput() operation if defined. 

  4.  */  

  5.  /*释放inode*/  

  6. static void dentry_iput(struct dentry * dentry)  

  7.     __releases(dentry->d_lock)  

  8.     __releases(dcache_lock)  

  9. {  

  10.     struct inode *inode = dentry->d_inode;  

  11.     if (inode) {  

  12.         dentry->d_inode = NULL;  

  13.         list_del_init(&dentry->d_alias);/*从同一索引节点目录链表中删除*/  

  14.         spin_unlock(&dentry->d_lock);  

  15.         spin_unlock(&dcache_lock);  

  16.         if (!inode->i_nlink)/*如果inode没有硬链接*/  

  17.             fsnotify_inoderemove(inode);  

  18.         if (dentry->d_op && dentry->d_op->d_iput)  

  19.             dentry->d_op->d_iput(dentry, inode);  

  20.         else  

  21.             iput(inode);/*释放inode*/  

  22.     } else {  

  23.         spin_unlock(&dentry->d_lock);  

  24.         spin_unlock(&dcache_lock);  

  25.     }  

  26. }  

2.注册inode cache shrinker


Start_kernel()->vfs_caches_init()->inode_init()->register_shrinker(&icache_shrinker);


其中参数为下面定义

[cpp]


  1. static struct shrinker icache_shrinker = {  

  2.     .shrink = shrink_icache_memory,  

  3.     .seeks = DEFAULT_SEEKS,  

  4. };  

[cpp]


  1. static int shrink_icache_memory(int nr, gfp_t gfp_mask)  

  2. {  

  3.     if (nr) {  

  4.         /* 

  5.          * Nasty deadlock avoidance.  We may hold various FS locks, 

  6.          * and we don’t want to recurse into the FS that called us 

  7.          * in clear_inode() and friends.. 

  8.          */  

  9.         if (!(gfp_mask & __GFP_FS))  

  10.             return -1;  

  11.         prune_icache(nr);  

  12.     }  

  13.     return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;  

  14. }  

[cpp]


  1. /* 

  2.  * Scan `goal’ inodes on the unused list for freeable ones. They are moved to 

  3.  * a temporary list and then are freed outside inode_lock by dispose_list(). 

  4.  * 

  5.  * Any inodes which are pinned purely because of attached pagecache have their 

  6.  * pagecache removed.  We expect the final iput() on that inode to add it to 

  7.  * the front of the inode_unused list.  So look for it there and if the 

  8.  * inode is still freeable, proceed.  The right inode is found 99.9% of the 

  9.  * time in testing on a 4-way. 

  10.  * 

  11.  * If the inode has metadata buffers attached to mapping->private_list then 

  12.  * try to remove them. 

  13.  */  

  14. static void prune_icache(int nr_to_scan)  

  15. {  

  16.     LIST_HEAD(freeable);/*初始化freeable,在下面需要用到,作为临时存放可被释放的inode*/  

  17.     int nr_pruned = 0;  

  18.     int nr_scanned;  

  19.     unsigned long reap = 0;  

  20.   

  21.     down_read(&iprune_sem);  

  22.     spin_lock(&inode_lock);  

  23.     for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) {  

  24.         struct inode *inode;  

  25.   

  26.         if (list_empty(&inode_unused))  

  27.             break;  

  28.   

  29.         inode = list_entry(inode_unused.prev, struct inode, i_list);  

  30.   

  31.         if (inode->i_state || atomic_read(&inode->i_count)) {  

  32.             /*将ionde从inode_unused链表中删除,加入inode_unused链表头*/  

  33.             list_move(&inode->i_list, &inode_unused);  

  34.             continue;  

  35.         }  

  36.         if (inode_has_buffers(inode) || inode->i_data.nrpages) {  

  37.             __iget(inode);/*移动到使用链表*/  

  38.             spin_unlock(&inode_lock);  

  39.             if (remove_inode_buffers(inode))/*从buffer链表中删除所有buffer*/  

  40.                 reap += invalidate_mapping_pages(&inode->i_data,  

  41.                                 0, -1);  

  42.             iput(inode);  

  43.             spin_lock(&inode_lock);  

  44.   

  45.             if (inode != list_entry(inode_unused.next,  

  46.                         struct inode, i_list))  

  47.                 continue;   /* wrong inode or list_empty */  

  48.             if (!can_unuse(inode))  

  49.                 continue;  

  50.         }  

  51.         /*移动到freeable链表*/  

  52.         list_move(&inode->i_list, &freeable);  

  53.         WARN_ON(inode->i_state & I_NEW);  

  54.         inode->i_state |= I_FREEING;  

  55.         nr_pruned++;/*统计移动到freeable链表的元素个数*/  

  56.     }  

  57.     inodes_stat.nr_unused -= nr_pruned;/*更新统计数据*/  

  58.     if (current_is_kswapd())  

  59.         __count_vm_events(KSWAPD_INODESTEAL, reap);  

  60.     else  

  61.         __count_vm_events(PGINODESTEAL, reap);  

  62.     spin_unlock(&inode_lock);  

  63.   

  64.     dispose_list(&freeable);/*将freeable链表中的数据处理掉*/  

  65.     up_read(&iprune_sem);  

  66. }  

3,注册文件描述符表释放函数

[cpp]


  1. /*文件描述符表*/  

  2. struct fdtable {  

  3.     unsigned int max_fds;/*进程能够处理的最大file结构*/  

  4.     struct file ** fd;/*所有打开文件信息*//* current fd array */  

  5.     fd_set *close_on_exec;/*exec系统调用被关闭的所有文件集合*/  

  6.     fd_set *open_fds;/*当前打开的所有文件集合*/  

  7.     struct rcu_head rcu;  

  8.     struct fdtable *next;  

  9. };  

Start_kernel()->vfs_caches_init()->files_init()->files_defer_init()->fdtable_defer_list_init()->INIT_WORK(&fddef->wq, free_fdtable_work);

[cpp]


  1. static void free_fdtable_work(struct work_struct *work)  

  2. {  

  3.     struct fdtable_defer *f =  

  4.         container_of(work, struct fdtable_defer, wq);  

  5.     struct fdtable *fdt;  

  6.   

  7.     spin_lock_bh(&f->lock);  

  8.     fdt = f->next;  

  9.     f->next = NULL;  

  10.     spin_unlock_bh(&f->lock);  

  11.     while(fdt) {/*释放工作*/  

  12.         struct fdtable *next = fdt->next;  

  13.         vfree(fdt->fd);  

  14.         free_fdset(fdt);  

  15.         kfree(fdt);  

  16.         fdt = next;  

  17.     }  

  18. }  

4.sysfs文件系统初始化


Start_kernel()->vfs_caches_init()->mnt_init()->sysfs_init()

[cpp]


  1. int __init sysfs_init(void)  

  2. {  

  3.     int err = -ENOMEM;  

  4.   

  5.     sysfs_dir_cachep = kmem_cache_create(“sysfs_dir_cache”,  

  6.                           sizeof(struct sysfs_dirent),  

  7.                           0, 0, NULL);  

  8.     if (!sysfs_dir_cachep)  

  9.         goto out;  

  10.     /*初始化sysfs的backing_dev_info结构*/  

  11.     err = sysfs_inode_init();  

  12.     if (err)  

  13.         goto out_err;  

  14.     /*注册文件系统*/  

  15.     err = register_filesystem(&sysfs_fs_type);  

  16.     if (!err) {  

  17.         /*创建sysfs mount*/  

  18.         sysfs_mount = kern_mount(&sysfs_fs_type);  

  19.         if (IS_ERR(sysfs_mount)) {  

  20.             printk(KERN_ERR “sysfs: could not mount!\n”);  

  21.             err = PTR_ERR(sysfs_mount);  

  22.             sysfs_mount = NULL;  

  23.             unregister_filesystem(&sysfs_fs_type);  

  24.             goto out_err;  

  25.         }  

  26.     } else  

  27.         goto out_err;  

  28. out:  

  29.     return err;  

  30. out_err:  

  31.     kmem_cache_destroy(sysfs_dir_cachep);  

  32.     sysfs_dir_cachep = NULL;  

  33.     goto out;  

  34. }  

赞(0) 打赏
转载请注明出处:服务器评测 » Linux虚拟文件系统(内核初始化<二>)
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏