Instances of struct filename come from names_cachep (via __getname()). That is done by getname_flags() and getname_kernel() and these two are the main callers of __getname(). However, there are other callers that simply want to allocate PATH_MAX bytes for uses that have nothing to do with struct filename. We want saner allocation rules for long pathnames, so that struct filename would *always* come from names_cachep, with the out-of-line pathname getting kmalloc'ed. For that we need to be able to change the size of objects allocated by getname_flags()/getname_kernel(). That requires the rest of __getname() users to stop using names_cachep; we could explicitly switch all of those to kmalloc(), but that would cause quite a bit of noise. So the plan is to switch getname_...() to new helpers and turn __getname() into a wrapper for kmalloc(). Remaining __getname() users could be converted to explicit kmalloc() at leisure, hopefully along with figuring out what size do they really want - PATH_MAX is an overkill for some of them, used out of laziness ("we have a convenient helper that does 4K allocations and that's large enough, let's use it"). As a side benefit, names_cachep is no longer used outside of fs/namei.c, so we can move it there and be done with that. Signed-off-by: Al Viro --- fs/dcache.c | 8 +------- fs/internal.h | 2 ++ fs/namei.c | 37 ++++++++++++++++++++++++++++--------- include/linux/fs.h | 6 ++---- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index dc2fff4811d1..cf865c12cdf9 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3290,10 +3290,6 @@ static void __init dcache_init(void) runtime_const_init(ptr, dentry_hashtable); } -/* SLAB cache for __getname() consumers */ -struct kmem_cache *names_cachep __ro_after_init; -EXPORT_SYMBOL(names_cachep); - void __init vfs_caches_init_early(void) { int i; @@ -3307,9 +3303,7 @@ void __init vfs_caches_init_early(void) void __init vfs_caches_init(void) { - names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL); - + filename_init(); dcache_init(); inode_init(); files_init(); diff --git a/fs/internal.h b/fs/internal.h index ab638d41ab81..e44146117a42 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -71,6 +71,8 @@ struct dentry *start_dirop(struct dentry *parent, struct qstr *name, unsigned int lookup_flags); int lookup_noperm_common(struct qstr *qname, struct dentry *base); +void __init filename_init(void); + /* * namespace.c */ diff --git a/fs/namei.c b/fs/namei.c index 471e4db2dbdb..468e3db62f53 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -125,6 +125,25 @@ #define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname)) +/* SLAB cache for struct filename instances */ +static struct kmem_cache *names_cachep __ro_after_init; + +void __init filename_init(void) +{ + names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL); +} + +static inline struct filename *alloc_filename(void) +{ + return kmem_cache_alloc(names_cachep, GFP_KERNEL); +} + +static inline void free_filename(struct filename *p) +{ + kmem_cache_free(names_cachep, p); +} + static inline void initname(struct filename *name) { name->aname = NULL; @@ -164,7 +183,7 @@ getname_flags(const char __user *filename, int flags) char *kname; int len; - result = __getname(); + result = alloc_filename(); if (unlikely(!result)) return ERR_PTR(-ENOMEM); @@ -181,13 +200,13 @@ getname_flags(const char __user *filename, int flags) */ if (unlikely(len <= 0)) { if (unlikely(len < 0)) { - __putname(result); + free_filename(result); return ERR_PTR(len); } /* The empty path is special. */ if (!(flags & LOOKUP_EMPTY)) { - __putname(result); + free_filename(result); return ERR_PTR(-ENOENT); } } @@ -201,7 +220,7 @@ getname_flags(const char __user *filename, int flags) if (unlikely(len == EMBEDDED_NAME_MAX)) { struct filename *p = getname_long(result, filename); if (IS_ERR(p)) { - __putname(result); + free_filename(result); return p; } result = p; @@ -242,7 +261,7 @@ struct filename *getname_kernel(const char * filename) struct filename *result; int len = strlen(filename) + 1; - result = __getname(); + result = alloc_filename(); if (unlikely(!result)) return ERR_PTR(-ENOMEM); @@ -254,13 +273,13 @@ struct filename *getname_kernel(const char * filename) tmp = kmalloc(size, GFP_KERNEL); if (unlikely(!tmp)) { - __putname(result); + free_filename(result); return ERR_PTR(-ENOMEM); } tmp->name = (char *)result; result = tmp; } else { - __putname(result); + free_filename(result); return ERR_PTR(-ENAMETOOLONG); } memcpy((char *)result->name, filename, len); @@ -287,10 +306,10 @@ void putname(struct filename *name) } if (unlikely(name->name != name->iname)) { - __putname(name->name); + free_filename((struct filename *)name->name); kfree(name); } else - __putname(name); + free_filename(name); } EXPORT_SYMBOL(putname); diff --git a/include/linux/fs.h b/include/linux/fs.h index f48149f3c086..c2ce1dc388cb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2533,10 +2533,8 @@ static inline int finish_open_simple(struct file *file, int error) extern void __init vfs_caches_init_early(void); extern void __init vfs_caches_init(void); -extern struct kmem_cache *names_cachep; - -#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL) -#define __putname(name) kmem_cache_free(names_cachep, (void *)(name)) +#define __getname() kmalloc(PATH_MAX, GFP_KERNEL) +#define __putname(name) kfree(name) void emergency_thaw_all(void); extern int sync_filesystem(struct super_block *); -- 2.47.3