Introduce a dedicated cache pool for ovl_entry to optimize memory allocation adn deallocation. Signed-off-by: Chengguang Xu <cgxu519@xxxxxxx> --- fs/overlayfs/export.c | 11 +++++++---- fs/overlayfs/namei.c | 7 +++++-- fs/overlayfs/overlayfs.h | 4 ++++ fs/overlayfs/ovl_entry.h | 9 +++++---- fs/overlayfs/super.c | 38 +++++++++++++++++++++++++++++--------- fs/overlayfs/util.c | 28 ++++++++++++++++++++++++---- 6 files changed, 74 insertions(+), 23 deletions(-) diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c index f2ba5fb..b1047ae 100644 --- a/fs/overlayfs/export.c +++ b/fs/overlayfs/export.c @@ -321,8 +321,8 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb, goto nomem; if (lower) { - oe->lowerstack->dentry = dget(lower); - oe->lowerstack->layer = lowerpath->layer; + oe->lowerstack.dentry = dget(lower); + oe->lowerstack.layer = lowerpath->layer; } dentry->d_fsdata = oe; if (upper_alias) @@ -346,9 +346,12 @@ static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx) if (!idx) return ovl_dentry_upper(dentry); + if (oe->numlower == 1 && oe->lowerstack.layer->idx == idx) + return oe->lowerstack.dentry; + for (i = 0; i < oe->numlower; i++) { - if (oe->lowerstack[i].layer->idx == idx) - return oe->lowerstack[i].dentry; + if (oe->lowerstacks[i].layer->idx == idx) + return oe->lowerstacks[i].dentry; } return NULL; diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index eb3ec6c..51fd914 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -994,7 +994,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, if (!oe) goto out_put; - memcpy(oe->lowerstack, stack, sizeof(struct ovl_path) * ctr); + if (oe->numlower == 1) + memcpy(&oe->lowerstack, stack, sizeof(struct ovl_path)); + else + memcpy(oe->lowerstacks, stack, sizeof(struct ovl_path) * ctr); dentry->d_fsdata = oe; if (upperopaque) @@ -1028,7 +1031,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, out_free_oe: dentry->d_fsdata = NULL; - kfree(oe); + ovl_free_entry(oe); out_put: dput(index); for (i = 0; i < ctr; i++) diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 8039602..a104e02 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -207,6 +207,7 @@ static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode) bool ovl_index_all(struct super_block *sb); bool ovl_verify_lower(struct super_block *sb); struct ovl_entry *ovl_alloc_entry(unsigned int numlower); +void ovl_free_entry(struct ovl_entry *oe); bool ovl_dentry_remote(struct dentry *dentry); bool ovl_dentry_weird(struct dentry *dentry); enum ovl_path_type ovl_path_type(struct dentry *dentry); @@ -378,3 +379,6 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower, /* export.c */ extern const struct export_operations ovl_export_operations; + +/* super.c */ +extern struct kmem_cache *ovl_entry_cachep; diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 41655a7..3ed8ab4 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -71,13 +71,14 @@ struct ovl_fs { /* private information held for every overlayfs dentry */ struct ovl_entry { union { - struct { - unsigned long flags; - }; + unsigned long flags; struct rcu_head rcu; }; unsigned numlower; - struct ovl_path lowerstack[]; + union { + struct ovl_path lowerstack; + struct ovl_path *lowerstacks; + }; }; struct ovl_entry *ovl_alloc_entry(unsigned int numlower); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 38c1dd1..6327497 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -60,8 +60,11 @@ static void ovl_entry_stack_free(struct ovl_entry *oe) { unsigned int i; - for (i = 0; i < oe->numlower; i++) - dput(oe->lowerstack[i].dentry); + if (oe->numlower == 1) + dput(oe->lowerstack.dentry); + else + for (i = 0; i < oe->numlower; i++) + dput(oe->lowerstacks[i].dentry); } static void ovl_dentry_release(struct dentry *dentry) @@ -191,6 +194,7 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags) }; static struct kmem_cache *ovl_inode_cachep; +struct kmem_cache *ovl_entry_cachep; static struct inode *ovl_alloc_inode(struct super_block *sb) { @@ -1332,9 +1336,14 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, if (!oe) goto out_err; - for (i = 0; i < numlower; i++) { - oe->lowerstack[i].dentry = dget(stack[i].dentry); - oe->lowerstack[i].layer = &ofs->lower_layers[i]; + if (numlower == 1) { + oe->lowerstack.dentry = stack[0].dentry; + oe->lowerstack.layer = &ofs->lower_layers[0]; + } else { + for (i = 0; i < numlower; i++) { + oe->lowerstacks[i].dentry = dget(stack[i].dentry); + oe->lowerstacks[i].layer = &ofs->lower_layers[i]; + } } if (remote) @@ -1515,20 +1524,31 @@ static void ovl_inode_init_once(void *foo) static int __init ovl_init(void) { - int err; + int err = -ENOMEM; ovl_inode_cachep = kmem_cache_create("ovl_inode", sizeof(struct ovl_inode), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD|SLAB_ACCOUNT), ovl_inode_init_once); - if (ovl_inode_cachep == NULL) - return -ENOMEM; + if (!ovl_inode_cachep) + return err; + + ovl_entry_cachep = KMEM_CACHE(ovl_entry, + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); + if (!ovl_entry_cachep) + goto bad_entry_cachep; err = register_filesystem(&ovl_fs_type); if (err) - kmem_cache_destroy(ovl_inode_cachep); + goto err_out; + return 0; + +err_out: + kmem_cache_destroy(ovl_entry_cachep); +bad_entry_cachep: + kmem_cache_destroy(ovl_inode_cachep); return err; } diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index a3459e6..7d4ff3e 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -95,13 +95,30 @@ bool ovl_verify_lower(struct super_block *sb) return ofs->config.nfs_export && ofs->config.index; } +void ovl_free_entry(struct ovl_entry *oe) +{ + if (oe->numlower > 1) + kfree(oe->lowerstacks); + + kmem_cache_free(ovl_entry_cachep, oe); +} + struct ovl_entry *ovl_alloc_entry(unsigned int numlower) { - size_t size = offsetof(struct ovl_entry, lowerstack[numlower]); - struct ovl_entry *oe = kzalloc(size, GFP_KERNEL); + size_t size = sizeof(struct ovl_path) * numlower; + struct ovl_entry *oe; - if (oe) + oe = kmem_cache_zalloc(ovl_entry_cachep, GFP_KERNEL); + if (oe) { oe->numlower = numlower; + if (numlower > 1) { + oe->lowerstacks = kzalloc(size, GFP_KERNEL); + if (!oe->lowerstacks) { + kmem_cache_free(ovl_entry_cachep, oe); + oe = NULL; + } + } + } return oe; } @@ -186,7 +203,10 @@ struct ovl_path *__ovl_path_lower(struct ovl_entry *oe, int layer) if (layer > oe->numlower) return NULL; - return &oe->lowerstack[layer - 1]; + if (layer == 1 && oe->numlower == 1) + return &oe->lowerstack; + else + return &oe->lowerstacks[layer - 1]; } struct vfsmount *ovl_mnt_lower(struct dentry *dentry) -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html