Chinaunix首页 | 论坛 | 博客
  • 博客访问: 177761
  • 博文数量: 33
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 305
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-07 15:33
文章存档

2015年(23)

2014年(10)

分类: 嵌入式

2015-01-07 11:13:44

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

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

shrinker数据结构介绍


  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);

  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. }  

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

  1. static struct shrinker dcache_shrinker = {  
  2.     .shrink = shrink_dcache_memory,  
  3.     .seeks = DEFAULT_SEEKS,  
  4. };  
  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. }  
  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. }  
  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. }  
  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. }  
  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. }  
  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. }  
  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);

其中参数为下面定义

  1. static struct shrinker icache_shrinker = {  
  2.     .shrink = shrink_icache_memory,  
  3.     .seeks = DEFAULT_SEEKS,  
  4. };  
  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. }  
  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,注册文件描述符表释放函数

  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);

  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()

  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. }  
阅读(1318) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~