The dentry mobs are the sets of dentries, that * belong to one subtree growing from some dentry * are limited in size per-mob * have the unused dentries stored in the mob's LRU list At this point all this patch does it moves the nr_dentry, the nr_dentry_max and the dentry_lru on the static init_dentry_mob structure. The ability to create more mobs will be introduced in the next patches. Signed-off-by: Pavel Emelyanov <xemul@xxxxxxxxxx> --- fs/dcache.c | 46 ++++++++++++++++++++++++++-------------------- include/linux/dcache.h | 7 +++++++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index c5179c3..bfe047d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -123,14 +123,14 @@ struct dentry_stat_t dentry_stat = { .age_limit = 45, }; -static struct percpu_counter nr_dentry __cacheline_aligned_in_smp; -static unsigned long nr_dentry_max; +static struct dentry_mob init_dentry_mob; #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) int proc_nr_dentry(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - dentry_stat.nr_dentry = percpu_counter_sum_positive(&nr_dentry); + dentry_stat.nr_dentry = + percpu_counter_sum_positive(&init_dentry_mob.nr_dentry); return proc_dointvec(table, write, buffer, lenp, ppos); } #endif @@ -151,7 +151,7 @@ static void __d_free(struct rcu_head *head) static void d_free(struct dentry *dentry) { BUG_ON(dentry->d_count); - percpu_counter_dec(&nr_dentry); + percpu_counter_dec(&dentry->d_mob->nr_dentry); if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); @@ -224,7 +224,6 @@ static void dentry_unlink_inode(struct dentry * dentry) iput(inode); } -static LIST_HEAD(dentry_lru); /* * dentry_lru_(add|del|move_tail) must be called with d_lock held. */ @@ -232,7 +231,7 @@ static void dentry_lru_add(struct dentry *dentry) { if (list_empty(&dentry->d_lru)) { spin_lock(&dcache_lru_lock); - list_add(&dentry->d_lru, &dentry_lru); + list_add(&dentry->d_lru, &dentry->d_mob->dentry_lru); dentry_stat.nr_unused++; spin_unlock(&dcache_lru_lock); } @@ -844,7 +843,7 @@ static int shrink_dentry_list(struct list_head *list) * This function may fail to free any resources if all the dentries are in use. */ -static int prune_dcache(int count) +static int prune_dcache(struct dentry_mob *mob, int count) { /* called from prune_dcache() and shrink_dcache_parent() */ struct dentry *dentry; @@ -853,8 +852,8 @@ static int prune_dcache(int count) relock: spin_lock(&dcache_lru_lock); - while (!list_empty(&dentry_lru)) { - dentry = list_entry(dentry_lru.prev, struct dentry, d_lru); + while (!list_empty(&mob->dentry_lru)) { + dentry = list_entry(mob->dentry_lru.prev, struct dentry, d_lru); if (!spin_trylock(&dentry->d_lock)) { spin_unlock(&dcache_lru_lock); @@ -880,7 +879,7 @@ relock: cond_resched_lock(&dcache_lru_lock); } if (!list_empty(&referenced)) - list_splice(&referenced, &dentry_lru); + list_splice(&referenced, &mob->dentry_lru); spin_unlock(&dcache_lru_lock); return shrink_dentry_list(&tmp); @@ -1060,7 +1059,7 @@ static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask) if (nr) { if (!(gfp_mask & __GFP_FS)) return -1; - prune_dcache(nr); + prune_dcache(&init_dentry_mob, nr); } return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; @@ -1071,15 +1070,17 @@ static struct shrinker dcache_shrinker = { .seeks = DEFAULT_SEEKS, }; -static int dcache_mem_check(void) +static int dcache_mem_check(struct dentry_mob *dmob) { - if (percpu_counter_read_positive(&nr_dentry) <= nr_dentry_max) + if (percpu_counter_read_positive(&dmob->nr_dentry) <= + dmob->nr_dentry_max) return 0; do { - if (percpu_counter_sum_positive(&nr_dentry) <= nr_dentry_max) + if (percpu_counter_sum_positive(&dmob->nr_dentry) <= + dmob->nr_dentry_max) return 0; - } while (prune_dcache(nr_dentry_max >> 6) > 0); + } while (prune_dcache(dmob, dmob->nr_dentry_max >> 6) > 0); return -ENOMEM; } @@ -1098,8 +1099,10 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) { struct dentry *dentry; char *dname; + struct dentry_mob *dmob; - if (dcache_mem_check()) + dmob = &init_dentry_mob; + if (dcache_mem_check(dmob)) return NULL; dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); @@ -1136,6 +1139,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) INIT_LIST_HEAD(&dentry->d_subdirs); INIT_LIST_HEAD(&dentry->d_alias); INIT_LIST_HEAD(&dentry->d_u.d_child); + dentry->d_mob = dmob; if (parent) { spin_lock(&parent->d_lock); @@ -1151,7 +1155,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) spin_unlock(&parent->d_lock); } - percpu_counter_inc(&nr_dentry); + percpu_counter_inc(&dmob->nr_dentry); return dentry; } @@ -2860,9 +2864,11 @@ static void __init dcache_init(void) { int loop; - percpu_counter_init(&nr_dentry, 0); - nr_dentry_max = 80 * 1024 * 1024 / sizeof(struct dentry); - printk("nr_dentry_max = %lu\n", nr_dentry_max); + percpu_counter_init(&init_dentry_mob.nr_dentry, 0); + init_dentry_mob.nr_dentry_max = 80 * 1024 * 1024 / sizeof(struct dentry); + INIT_LIST_HEAD(&init_dentry_mob.dentry_lru); + + printk("nr_dentry_max = %lu\n", init_dentry_mob.nr_dentry_max); /* * A constructor could be added for stable state like the lists, diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 64848dd..80bb9e4 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -48,6 +48,12 @@ struct dentry_stat_t { }; extern struct dentry_stat_t dentry_stat; +struct dentry_mob { + struct percpu_counter nr_dentry; + unsigned long nr_dentry_max; + struct list_head dentry_lru; +}; + /* * Compare 2 name strings, return 0 if they match, otherwise non-zero. * The strings are both count bytes long, and count is non-zero. @@ -143,6 +149,7 @@ struct dentry { } d_u; struct list_head d_subdirs; /* our children */ struct list_head d_alias; /* inode alias list */ + struct dentry_mob *d_mob; }; /* -- 1.5.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html