這部分主要對linux虛擬文件系統(tǒng)內(nèi)核初始化部分做些補充。
關(guān)于shrinker,inode和dentry cache初始化階段都需要注冊自己的shrinker,用于縮減cache。兩個操作原理類似。
shrinker數(shù)據(jù)結(jié)構(gòu)介紹
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- struct shrinker {
- int (*shrink)(int nr_to_scan, gfp_t gfp_mask);
- int seeks;
-
-
- struct list_head list;
- long nr;
- };
1,注冊inode cache shrinker
Start_kernel()->vfs_caches_init()->dcache_init()->register_shrinker(&dcache_shrinker);
-
-
-
- void register_shrinker(struct shrinker *shrinker)
- {
- shrinker->nr = 0;
- down_write(&shrinker_rwsem);
- list_add_tail(&shrinker->list, &shrinker_list);
- up_write(&shrinker_rwsem);
- }
其中相關(guān)的函數(shù)在這里定義。
- static struct shrinker dcache_shrinker = {
- .shrink = shrink_dcache_memory,
- .seeks = DEFAULT_SEEKS,
- };
-
-
-
-
-
-
-
-
-
-
-
-
- static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
- {
- if (nr) {
- if (!(gfp_mask & __GFP_FS))
- return -1;
- prune_dcache(nr);
- }
- return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
- }
-
-
-
-
-
-
-
-
-
-
- static void prune_dcache(int count)
- {
- struct super_block *sb;
- int w_count;
- int unused = dentry_stat.nr_unused;
- int prune_ratio;
- int pruned;
-
- if (unused == 0 || count == 0)
- return;
- spin_lock(&dcache_lock);
- restart:
- if (count >= unused)
- prune_ratio = 1;
- else
- prune_ratio = unused / count;
- spin_lock(&sb_lock);
- list_for_each_entry(sb, &super_blocks, s_list) {
- if (sb->s_nr_dentry_unused == 0)
- continue;
- sb->s_count++;
-
-
-
-
-
-
-
-
-
- spin_unlock(&sb_lock);
-
- if (prune_ratio != 1)
- w_count = (sb->s_nr_dentry_unused / prune_ratio) + 1;
- else
- w_count = sb->s_nr_dentry_unused;
- pruned = w_count;
-
-
-
-
-
-
-
- if (down_read_trylock(&sb->s_umount)) {
- if ((sb->s_root != NULL) &&
- (!list_empty(&sb->s_dentry_lru))) {
- spin_unlock(&dcache_lock);
-
- __shrink_dcache_sb(sb, &w_count,
- DCACHE_REFERENCED);
- pruned -= w_count;
- spin_lock(&dcache_lock);
- }
- up_read(&sb->s_umount);
- }
- spin_lock(&sb_lock);
- count -= pruned;
-
-
-
-
- if (__put_super_and_need_restart(sb) && count > 0) {
- spin_unlock(&sb_lock);
- goto restart;
- }
- }
- spin_unlock(&sb_lock);
- spin_unlock(&dcache_lock);
- }
-
-
-
-
-
-
-
-
- static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
- {
- LIST_HEAD(referenced);
- LIST_HEAD(tmp);
- struct dentry *dentry;
- int cnt = 0;
-
- BUG_ON(!sb);
- BUG_ON((flags & DCACHE_REFERENCED) && count == NULL);
- spin_lock(&dcache_lock);
- if (count != NULL)
-
- cnt = *count;
- restart:
- if (count == NULL)
- list_splice_init(&sb->s_dentry_lru, &tmp);
- else {
- while (!list_empty(&sb->s_dentry_lru)) {
- dentry = list_entry(sb->s_dentry_lru.prev,
- struct dentry, d_lru);
- BUG_ON(dentry->d_sb != sb);
-
- spin_lock(&dentry->d_lock);
-
-
-
-
-
-
- if ((flags & DCACHE_REFERENCED)
- && (dentry->d_flags & DCACHE_REFERENCED)) {
- dentry->d_flags &= ~DCACHE_REFERENCED;
- list_move(&dentry->d_lru, &referenced);
- spin_unlock(&dentry->d_lock);
- } else {
-
- list_move_tail(&dentry->d_lru, &tmp);
- spin_unlock(&dentry->d_lock);
- cnt--;
- if (!cnt)
- break;
- }
- cond_resched_lock(&dcache_lock);
- }
- }
-
- while (!list_empty(&tmp)) {
- dentry = list_entry(tmp.prev, struct dentry, d_lru);
-
- dentry_lru_del_init(dentry);
- spin_lock(&dentry->d_lock);
-
-
-
-
-
- if (atomic_read(&dentry->d_count)) {
- spin_unlock(&dentry->d_lock);
- continue;
- }
- prune_one_dentry(dentry);
-
- cond_resched_lock(&dcache_lock);
- }
- if (count == NULL && !list_empty(&sb->s_dentry_lru))
- goto restart;
- if (count != NULL)
- *count = cnt;
- if (!list_empty(&referenced))
- list_splice(&referenced, &sb->s_dentry_lru);
- spin_unlock(&dcache_lock);
- }
- static void dentry_lru_del_init(struct dentry *dentry)
- {
- if (likely(!list_empty(&dentry->d_lru))) {
- list_del_init(&dentry->d_lru);
- dentry->d_sb->s_nr_dentry_unused--;
- dentry_stat.nr_unused--;
- }
- }
- /*
- * Throw away a dentry - free the inode, dput the parent. This requires that
- * the LRU list has already been removed.
- *
- * Try to prune ancestors as well. This is necessary to prevent
- * quadratic behavior of shrink_dcache_parent(), but is also expected
- * to be beneficial in reducing dentry cache fragmentation.
- */
- static void prune_one_dentry(struct dentry * dentry)
- __releases(dentry->d_lock)
- __releases(dcache_lock)
- __acquires(dcache_lock)
- {
- __d_drop(dentry);
- dentry = d_kill(dentry);/*釋放dentry*/
-
- /*
- * Prune ancestors. Locking is simpler than in dput(),
- * because dcache_lock needs to be taken anyway.
- */
- spin_lock(&dcache_lock);
- while (dentry) {
- if (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock))
- return;
-
- if (dentry->d_op && dentry->d_op->d_delete)
- dentry->d_op->d_delete(dentry);
- dentry_lru_del_init(dentry);
- __d_drop(dentry);
- dentry = d_kill(dentry);
- spin_lock(&dcache_lock);
- }
- }
-
-
-
-
-
-
-
-
- static struct dentry *d_kill(struct dentry *dentry)
- __releases(dentry->d_lock)
- __releases(dcache_lock)
- {
- struct dentry *parent;
-
- list_del(&dentry->d_u.d_child);
- dentry_stat.nr_dentry--;
-
- dentry_iput(dentry);
- if (IS_ROOT(dentry))
- parent = NULL;
- else
- parent = dentry->d_parent;
- d_free(dentry);
- return parent;
- }
-
-
-
-
-
- static void dentry_iput(struct dentry * dentry)
- __releases(dentry->d_lock)
- __releases(dcache_lock)
- {
- struct inode *inode = dentry->d_inode;
- if (inode) {
- dentry->d_inode = NULL;
- list_del_init(&dentry->d_alias);
- spin_unlock(&dentry->d_lock);
- spin_unlock(&dcache_lock);
- if (!inode->i_nlink)
- fsnotify_inoderemove(inode);
- if (dentry->d_op && dentry->d_op->d_iput)
- dentry->d_op->d_iput(dentry, inode);
- else
- iput(inode);
- } else {
- spin_unlock(&dentry->d_lock);
- spin_unlock(&dcache_lock);
- }
- }
2.注冊inode cache shrinker Start_kernel()->vfs_caches_init()->inode_init()->register_shrinker(&icache_shrinker); 其中參數(shù)為下面定義 - static struct shrinker icache_shrinker = {
- .shrink = shrink_icache_memory,
- .seeks = DEFAULT_SEEKS,
- };
- static int shrink_icache_memory(int nr, gfp_t gfp_mask)
- {
- if (nr) {
-
-
-
-
-
- if (!(gfp_mask & __GFP_FS))
- return -1;
- prune_icache(nr);
- }
- return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- static void prune_icache(int nr_to_scan)
- {
- LIST_HEAD(freeable);
- int nr_pruned = 0;
- int nr_scanned;
- unsigned long reap = 0;
-
- down_read(&iprune_sem);
- spin_lock(&inode_lock);
- for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) {
- struct inode *inode;
-
- if (list_empty(&inode_unused))
- break;
-
- inode = list_entry(inode_unused.prev, struct inode, i_list);
-
- if (inode->i_state || atomic_read(&inode->i_count)) {
-
- list_move(&inode->i_list, &inode_unused);
- continue;
- }
- if (inode_has_buffers(inode) || inode->i_data.nrpages) {
- __iget(inode);
- spin_unlock(&inode_lock);
- if (remove_inode_buffers(inode))
- reap += invalidate_mapping_pages(&inode->i_data,
- 0, -1);
- iput(inode);
- spin_lock(&inode_lock);
-
- if (inode != list_entry(inode_unused.next,
- struct inode, i_list))
- continue;
- if (!can_unuse(inode))
- continue;
- }
-
- list_move(&inode->i_list, &freeable);
- WARN_ON(inode->i_state & I_NEW);
- inode->i_state |= I_FREEING;
- nr_pruned++;
- }
- inodes_stat.nr_unused -= nr_pruned;
- if (current_is_kswapd())
- __count_vm_events(KSWAPD_INODESTEAL, reap);
- else
- __count_vm_events(PGINODESTEAL, reap);
- spin_unlock(&inode_lock);
-
- dispose_list(&freeable);
- up_read(&iprune_sem);
- }
3,注冊文件描述符表釋放函數(shù) -
- struct fdtable {
- unsigned int max_fds;
- struct file ** fd;
- fd_set *close_on_exec;
- fd_set *open_fds;
- struct rcu_head rcu;
- struct fdtable *next;
- };
Start_kernel()->vfs_caches_init()->files_init()->files_defer_init()->fdtable_defer_list_init()->INIT_WORK(&fddef->wq, free_fdtable_work); - static void free_fdtable_work(struct work_struct *work)
- {
- struct fdtable_defer *f =
- container_of(work, struct fdtable_defer, wq);
- struct fdtable *fdt;
-
- spin_lock_bh(&f->lock);
- fdt = f->next;
- f->next = NULL;
- spin_unlock_bh(&f->lock);
- while(fdt) {
- struct fdtable *next = fdt->next;
- vfree(fdt->fd);
- free_fdset(fdt);
- kfree(fdt);
- fdt = next;
- }
- }
4.sysfs文件系統(tǒng)初始化 Start_kernel()->vfs_caches_init()->mnt_init()->sysfs_init() - int __init sysfs_init(void)
- {
- int err = -ENOMEM;
-
- sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
- sizeof(struct sysfs_dirent),
- 0, 0, NULL);
- if (!sysfs_dir_cachep)
- goto out;
-
- err = sysfs_inode_init();
- if (err)
- goto out_err;
-
- err = register_filesystem(&sysfs_fs_type);
- if (!err) {
-
- sysfs_mount = kern_mount(&sysfs_fs_type);
- if (IS_ERR(sysfs_mount)) {
- printk(KERN_ERR "sysfs: could not mount!\n");
- err = PTR_ERR(sysfs_mount);
- sysfs_mount = NULL;
- unregister_filesystem(&sysfs_fs_type);
- goto out_err;
- }
- } else
- goto out_err;
- out:
- return err;
- out_err:
- kmem_cache_destroy(sysfs_dir_cachep);
- sysfs_dir_cachep = NULL;
- goto out;
- }
|