memcg-vs-slab related fixes, improvements, cleanups
Subsystems (3)
v2 cover memcg-vs-slab related fixes, improvements, cleanups
Hi,
This patch set mostly cleanups memcg slab caches creation/destruction paths fixing a couple of bugs in the meanwhile. The only serious change it introduces is a rework of the sysfs layout for memcg slub caches (see patch 7).
Changes in v2:
- do not remove cgroup name part from memcg cache names
- do not export memcg cache id to userspace
Comments are appreciated.
Thanks.
Vladimir Davydov (7):
memcg, slab: never try to merge memcg caches
memcg, slab: cleanup memcg cache name creation
memcg, slab: separate memcg vs root cache creation paths memcg, slab: unregister cache from memcg before starting to destroy
it
memcg, slab: do not destroy children caches if parent has aliases
slub: adjust memcg caches when creating cache alias
slub: rework sysfs layout for memcg caches
include/linux/memcontrol.h | 16 ++-- include/linux/slab.h | 9 +-- include/linux/slub_def.h | 3 + mm/memcontrol.c | 104 +++++++++++------------- mm/slab.h | 36 ++++----- mm/slab_common.c | 192 ++++++++++++++++++++++++++++---------------- mm/slub.c | 118 +++++++++++++++++++++------ 7 files changed, 296 insertions(+), 182 deletions(-)
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 1/7 memcg, slab: never try to merge memcg caches
Suppose we are creating memcg cache A that could be merged with cache B of the same memcg. Since any memcg cache has the same parameters as its parent cache, parent caches PA and PB of memcg caches A and B must be mergeable too. That means PA was merged with PB on creation or vice versa, i.e. PA = PB. From that it follows that A = B, and we couldn't even try to create cache B, because it already exists - a contradiction.
So let's remove unused code responsible for merging memcg caches.
--- mm/slab.h | 21 ++++----------------- mm/slab_common.c | 8 +++++--- mm/slub.c | 19 +++++++++---------- 3 files changed, 18 insertions(+), 30 deletions(-)
mm/slab.h +4 -17
@@ -55,12 +55,12 @@ extern void create_boot_cache(struct kmem_cache *, const char *name,struct mem_cgroup ;#ifdef CONFIG_SLUB struct kmem_cache * -__kmem_cache_alias (struct mem_cgroup *memcg,const char *name,size_t size, -size_t align,unsigned long flags,void (*ctor)(void *)); +__kmem_cache_alias (const char *name,size_t size,size_t align, +unsigned long flags,void (*ctor)(void *));#else static inline struct kmem_cache * -__kmem_cache_alias (struct mem_cgroup *memcg,const char *name,size_t size, -size_t align,unsigned long flags,void (*ctor)(void *)) +__kmem_cache_alias (const char *name,size_t size,size_t align, +unsigned long flags,void (*ctor)(void *)) {return NULL ; }#endif
@@ -119,13 +119,6 @@ static inline bool is_root_cache(struct kmem_cache *s)return !s->memcg_params || s->memcg_params->is_root_cache; } -static inline bool cache_match_memcg (struct kmem_cache *cachep, -struct mem_cgroup *memcg) -{ -return (is_root_cache (cachep) && !memcg) || - (cachep->memcg_params->memcg == memcg); -} -static inline void memcg_bind_pages (struct kmem_cache *s,int order) {if (!is_root_cache (s))
@@ -204,12 +197,6 @@ static inline bool is_root_cache(struct kmem_cache *s)return true; } -static inline bool cache_match_memcg (struct kmem_cache *cachep, -struct mem_cgroup *memcg) -{ -return true; -} -static inline void memcg_bind_pages (struct kmem_cache *s,int order) { }
mm/slab_common.c +5 -3
@@ -200,9 +200,11 @@ kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size,*/ flags &=CACHE_CREATE_MASK ; - s =__kmem_cache_alias (memcg, name, size, align, flags, ctor); -if (s) - goto out_unlock; +if (!memcg) { + s =__kmem_cache_alias (name, size, align, flags, ctor); +if (s) + goto out_unlock; + } err = -ENOMEM ; s =kmem_cache_zalloc (kmem_cache,GFP_KERNEL );
mm/slub.c +9 -10
@@ -3692,9 +3692,8 @@ static int slab_unmergeable(struct kmem_cache *s)return 0 ; } -static struct kmem_cache *find_mergeable (struct mem_cgroup *memcg,size_t size, -size_t align,unsigned long flags,const char *name, -void (*ctor)(void *)) +static struct kmem_cache *find_mergeable (size_t size,size_t align, +unsigned long flags,const char *name,void (*ctor)(void *)) {struct kmem_cache *s;
@@ -3713,11 +3712,14 @@ static struct kmem_cache *find_mergeable(struct mem_cgroup *memcg, size_t size,if (slab_unmergeable (s))continue ; +if (!is_root_cache (s)) +continue ; +if (size > s->size)continue ;if ((flags &SLUB_MERGE_SAME ) != (s->flags &SLUB_MERGE_SAME )) -continue ; +continue ;/* * Check if alignment is compatible. * Courtesy of Adrian Drzewiecki
@@ -3728,21 +3730,18 @@ static struct kmem_cache *find_mergeable(struct mem_cgroup *memcg, size_t size,if (s->size - size >=sizeof (void *))continue ; -if (!cache_match_memcg (s, memcg)) -continue ; -return s; }return NULL ; }struct kmem_cache * -__kmem_cache_alias (struct mem_cgroup *memcg,const char *name,size_t size, -size_t align,unsigned long flags,void (*ctor)(void *)) +__kmem_cache_alias (const char *name,size_t size,size_t align, +unsigned long flags,void (*ctor)(void *)) {struct kmem_cache *s; - s =find_mergeable (memcg, size, align, flags, name, ctor); + s =find_mergeable (size, align, flags, name, ctor);if (s) { s->refcount++;/*
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 2/7 memcg, slab: cleanup memcg cache name creation
In reply to Vladimir DavydovThe way memcg_create_kmem_cache() creates the name for a memcg cache looks rather strange: it first formats the name in the static buffer tmp_name protected by a mutex, then passes the pointer to the buffer to kmem_cache_create_memcg(), which finally duplicates it to the cache name.
Let's clean this up by moving memcg cache name creation to a separate function to be called by kmem_cache_create_memcg(), and estimating the length of the name string before copying anything to it so that we won't need a temporary buffer.
--- include/linux/memcontrol.h | 9 +++++ mm/memcontrol.c | 94 ++++++++++++++++++++++---------------------- mm/slab_common.c | 5 ++- 3 files changed, 59 insertions(+), 49 deletions(-)
include/linux/memcontrol.h +9 -0
@@ -497,6 +497,9 @@ void __memcg_kmem_commit_charge(struct page *page,void __memcg_kmem_uncharge_pages (struct page *page,int order);int memcg_cache_id (struct mem_cgroup *memcg); + +char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache);int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache);void memcg_free_cache_params (struct kmem_cache *s);
@@ -641,6 +644,12 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)return -1 ; } +static inline char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache) +{ +return NULL ; +} +static inline int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache) {
mm/memcontrol.c +46 -48
121 lines not on this page · raw message
mm/slab_common.c +4 -1
@@ -215,7 +215,10 @@ kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size, s->align =calculate_alignment (flags, align, size); s->ctor = ctor; - s->name =kstrdup (name,GFP_KERNEL ); +if (memcg) + s->name =memcg_create_cache_name (memcg, parent_cache); +else + s->name =kstrdup (name,GFP_KERNEL );if (!s->name) goto out_free_cache;
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [PATCH v2 2/7] memcg, slab: cleanup memcg cache name creation
Quoted 34 lines · On Mon, 3 Feb 2014 19:54:37 +0400 Vladimir Davydov <[email protected]>…
The way
memcg_create_kmem_cache()creates the name for a memcg cache looks rather strange: it first formats the name in the static buffertmp_nameprotected by a mutex, then passes the pointer to the buffer tokmem_cache_create_memcg(), which finally duplicates it to the cache name.Let's clean this up by moving memcg cache name creation to a separate function to be called by
kmem_cache_create_memcg(), and estimating the length of the name string before copying anything to it so that we won't need a temporary buffer.mm/memcontrol.c +17
-0@@ -3193,6 +3193,37 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)return 0 ; } +static int memcg_print_cache_name (char *buf,size_t size, +struct mem_cgroup *memcg,struct kmem_cache *root_cache) +{ +int ret; + +rcu_read_lock (); + ret =snprintf (buf, size,"%s(%d:%s)" , root_cache->name, +memcg_cache_id (memcg),cgroup_name (memcg->css.cgroup)); +rcu_read_unlock (); +return ret; +} + +char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache) +{ +int len; +char *name;
mm/memcontrol.c int memcg_update_cache_size(struct kmem_cache *s, int num_groups) · line 3222
Quoted 10 lines
mm/memcontrol.c +10
-0+ +/* +* We cannot use kasprintf() here, because cgroup_name() must be called +* under RCU protection. +*/ + len =memcg_print_cache_name (NULL ,0 , memcg, root_cache); + + name =kmalloc (len +1 ,GFP_KERNEL ); +if (name) +memcg_print_cache_name (name, len +1 , memcg, root_cache);
but but but this assumes that cgroup_name(memcg->css.cgroup) did not change between the two calls to memcg_print_cache_name(). If that is the case then the locking was unneeded anyway.
mm/memcontrol.c void mem_cgroup_destroy_cache(struct kmem_cache *cachep) · line 3430
Quoted 10 lines
mm/memcontrol.c +3
-0+return name; +} +int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache) {@@ -3397,44 +3428,6 @@ void mem_cgroup_destroy_cache(struct kmem_cache *cachep)schedule_work (&cachep->memcg_params->destroy); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v2 2/7] memcg, slab: cleanup memcg cache name creation
Quoted 41 lines · Andrew Morton
Quoted 39 lines · On Mon, 3 Feb 2014 19:54:37 +0400 Vladimir Davydov <[email protected]>…
The way
memcg_create_kmem_cache()creates the name for a memcg cache looks rather strange: it first formats the name in the static buffertmp_nameprotected by a mutex, then passes the pointer to the buffer tokmem_cache_create_memcg(), which finally duplicates it to the cache name.Let's clean this up by moving memcg cache name creation to a separate function to be called by
kmem_cache_create_memcg(), and estimating the length of the name string before copying anything to it so that we won't need a temporary buffer.mm/memcontrol.c +22
-0@@ -3193,6 +3193,37 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)return 0 ; } +static int memcg_print_cache_name (char *buf,size_t size, +struct mem_cgroup *memcg,struct kmem_cache *root_cache) +{ +int ret; + +rcu_read_lock (); + ret =snprintf (buf, size,"%s(%d:%s)" , root_cache->name, +memcg_cache_id (memcg),cgroup_name (memcg->css.cgroup)); +rcu_read_unlock (); +return ret; +} + +char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache) +{ +int len; +char *name; + +/* +* We cannot use kasprintf() here, because cgroup_name() must be called +* under RCU protection. +*/
Quoted 8 lines
mm/memcontrol.c int memcg_update_cache_size(struct kmem_cache *s, int num_groups) · line 3222
Quoted 5 lines
mm/memcontrol.c +5
-0+ len =memcg_print_cache_name (NULL ,0 , memcg, root_cache); + + name =kmalloc (len +1 ,GFP_KERNEL ); +if (name) +memcg_print_cache_name (name, len +1 , memcg, root_cache);but but but this assumes that
cgroup_name(memcg->css.cgroup)did not change between the two calls tomemcg_print_cache_name(). If that is the case then the locking was unneeded anyway.
Oops, I missed that. Thank you for pointing me out. It seems the usage of the temporary buffer is inevitable. However, a dedicated mutex protecting it can be removed, because we already hold the slab_mutex while calling this function. Will rework.
Thanks.
Quoted 11 lines
mm/memcontrol.c void mem_cgroup_destroy_cache(struct kmem_cache *cachep) · line 3430
Quoted 11 lines
mm/memcontrol.c +3
-0+return name; +} +int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache) {@@ -3397,44 +3428,6 @@ void mem_cgroup_destroy_cache(struct kmem_cache *cachep)schedule_work (&cachep->memcg_params->destroy); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/1 memcg, slab: cleanup memcg cache creation
This patch cleanups the memcg cache creation path as follows:
- Move memcg cache name creation to a separate function to be called from kmem_cache_create_memcg(). This allows us to get rid of the mutex protecting the temporary buffer used for the name formatting, because the whole cache creation path is protected by the slab_mutex.
- Get rid of memcg_create_kmem_cache(). This function serves as a proxy to kmem_cache_create_memcg(). After separating the cache name creation path, it would be reduced to a function call, so let's inline it.
--- include/linux/memcontrol.h | 9 +++++ mm/memcontrol.c | 89 ++++++++++++++++++++------------------------ mm/slab_common.c | 5 ++- 3 files changed, 54 insertions(+), 49 deletions(-)
include/linux/memcontrol.h +9 -0
@@ -497,6 +497,9 @@ void __memcg_kmem_commit_charge(struct page *page,void __memcg_kmem_uncharge_pages (struct page *page,int order);int memcg_cache_id (struct mem_cgroup *memcg); + +char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache);int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache);void memcg_free_cache_params (struct kmem_cache *s);
@@ -641,6 +644,12 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)return -1 ; } +static inline char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache) +{ +return NULL ; +} +static inline int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache) {
mm/memcontrol.c +41 -48
116 lines not on this page · raw message
mm/slab_common.c +4 -1
@@ -215,7 +215,10 @@ kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size, s->align =calculate_alignment (flags, align, size); s->ctor = ctor; - s->name =kstrdup (name,GFP_KERNEL ); +if (memcg) + s->name =memcg_create_cache_name (memcg, parent_cache); +else + s->name =kstrdup (name,GFP_KERNEL );if (!s->name) goto out_free_cache;
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] memcg, slab: cleanup memcg cache creation
Quoted 9 lines · Vladimir Davydov
This patch cleanups the memcg cache creation path as follows:
- Move memcg cache name creation to a separate function to be called fromkmem_cache_create_memcg(). This allows us to get rid of the mutex protecting the temporary buffer used for the name formatting, because the whole cache creation path is protected by theslab_mutex.
- Get rid ofmemcg_create_kmem_cache(). This function serves as a proxy tokmem_cache_create_memcg(). After separating the cache name creation path, it would be reduced to a function call, so let's inline it.
OK, this looks better but it will still conflict with Tejun's cleanup now? Can we wait until mmotm settles down a bit and sees those changes? Maybe we can get rid of the static buffer altogether?
Quoted 177 lines
Signed-off-by Vladimir Davydov <[email protected]>--- include/linux/memcontrol.h | 9 +++++ mm/memcontrol.c | 89 ++++++++++++++++++++------------------------ mm/slab_common.c | 5 ++- 3 files changed, 54 insertions(+), 49 deletions(-)include/linux/memcontrol.h +9
-0@@ -497,6 +497,9 @@ void __memcg_kmem_commit_charge(struct page *page,void __memcg_kmem_uncharge_pages (struct page *page,int order);int memcg_cache_id (struct mem_cgroup *memcg); + +char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache);int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache);void memcg_free_cache_params (struct kmem_cache *s);@@ -641,6 +644,12 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)return -1 ; } +static inline char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache) +{ +return NULL ; +} +static inline int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache) {mm/memcontrol.c +41
-48@@ -3193,6 +3193,32 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)return 0 ; } +char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache) +{ +static char *buf =NULL ; + +/* +* We need a mutex here to protect the shared buffer. Since this is +* expected to be called only on cache creation, we can employ the +* slab_mutex for that purpose. +*/ +lockdep_assert_held (&slab_mutex); + +if (!buf) { + buf =kmalloc (PATH_MAX ,GFP_KERNEL ); +if (!buf) +return NULL ; + } + +rcu_read_lock (); +snprintf (buf,PATH_MAX ,"%s(%d:%s)" , root_cache->name, +memcg_cache_id (memcg),cgroup_name (memcg->css.cgroup)); +rcu_read_unlock (); + +return kstrdup (buf,GFP_KERNEL ); +} +int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache) {@@ -3397,44 +3423,6 @@ void mem_cgroup_destroy_cache(struct kmem_cache *cachep)schedule_work (&cachep->memcg_params->destroy); } -static struct kmem_cache *memcg_create_kmem_cache (struct mem_cgroup *memcg, -struct kmem_cache *s) -{ -struct kmem_cache *new =NULL ; -static char *tmp_name =NULL ; -static DEFINE_MUTEX (mutex);/* protects tmp_name */ - -BUG_ON (!memcg_can_account_kmem (memcg)); - -mutex_lock (&mutex); -/* -* kmem_cache_create_memcg duplicates the given name and -* cgroup_name for this name requires RCU context. -* This static temporary buffer is used to prevent from -* pointless shortliving allocation. -*/ -if (!tmp_name) { - tmp_name =kmalloc (PATH_MAX ,GFP_KERNEL ); -if (!tmp_name) - goto out; - } - -rcu_read_lock (); -snprintf (tmp_name,PATH_MAX ,"%s(%d:%s)" , s->name, -memcg_cache_id (memcg),cgroup_name (memcg->css.cgroup)); -rcu_read_unlock (); - - new =kmem_cache_create_memcg (memcg, tmp_name, s->object_size, s->align, - (s->flags & ~SLAB_PANIC ), s->ctor, s); -if (new) - new->allocflags |= __GFP_KMEMCG; -else - new = s; -out: -mutex_unlock (&mutex); -return new; -} -void kmem_cache_destroy_memcg_children (struct kmem_cache *s) {struct kmem_cache *c;@@ -3481,12 +3469,6 @@ void kmem_cache_destroy_memcg_children(struct kmem_cache *s)mutex_unlock (&activate_kmem_mutex); } -struct create_work { -struct mem_cgroup *memcg; -struct kmem_cache *cachep; -struct work_struct work; -}; -static void mem_cgroup_destroy_all_caches (struct mem_cgroup *memcg) {struct kmem_cache *cachep;@@ -3504,13 +3486,24 @@ static void mem_cgroup_destroy_all_caches(struct mem_cgroup *memcg)mutex_unlock (&memcg->slab_caches_mutex); } +struct create_work { +struct mem_cgroup *memcg; +struct kmem_cache *cachep; +struct work_struct work; +}; +static void memcg_create_cache_work_func (struct work_struct *w) { -struct create_work *cw; + struct create_work *cw = container_of(w, struct create_work, work); +struct mem_cgroup *memcg = cw->memcg; +struct kmem_cache *s = cw->cachep; +struct kmem_cache *new; - cw = container_of(w, struct create_work, work); -memcg_create_kmem_cache (cw->memcg, cw->cachep); -css_put (&cw->memcg->css); + new =kmem_cache_create_memcg (memcg, s->name, s->object_size, s->align, + (s->flags & ~SLAB_PANIC ), s->ctor, s); +if (new) + new->allocflags |= __GFP_KMEMCG; +css_put (&memcg->css);kfree (cw); }mm/slab_common.c +4
-1@@ -215,7 +215,10 @@ kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size, s->align =calculate_alignment (flags, align, size); s->ctor = ctor; - s->name =kstrdup (name,GFP_KERNEL ); +if (memcg) + s->name =memcg_create_cache_name (memcg, parent_cache); +else + s->name =kstrdup (name,GFP_KERNEL );if (!s->name) goto out_free_cache;Signature · 1 line
1.7.10.4
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] memcg, slab: cleanup memcg cache creation
Quoted 10 lines · Michal Hocko
Quoted 9 lines · Vladimir Davydov
This patch cleanups the memcg cache creation path as follows:
- Move memcg cache name creation to a separate function to be called fromkmem_cache_create_memcg(). This allows us to get rid of the mutex protecting the temporary buffer used for the name formatting, because the whole cache creation path is protected by theslab_mutex.
- Get rid ofmemcg_create_kmem_cache(). This function serves as a proxy tokmem_cache_create_memcg(). After separating the cache name creation path, it would be reduced to a function call, so let's inline it.
Quoted 2 lines
OK, this looks better but it will still conflict with Tejun's cleanup now? Can we wait until mmotm settles down a bit and sees those changes?
The new cgroup_name() has not been committed neither to master, nor for-next branches of
git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
so I guess it will take a while.
Quoted 1 line
Maybe we can get rid of the static buffer altogether?
It seems we can't. The point is that we don't know in advance how much memory we would like to allocate for slab cache name, because we don't know the length of the cgroup name. Note, we can't estimate the length (as I tried in the initial version of this patch), because cgroup name can change any time. So we will have to copy the cgroup name to a buffer large enough to accommodate it first, and only then copy it to slab cache name. The alternative way would be allocation >= NAME_MAX bytes for any memcg cache name, but it will be waste of memory.
Thanks.
Quoted 175 lines
Quoted 175 lines
Signed-off-by Vladimir Davydov <[email protected]>--- include/linux/memcontrol.h | 9 +++++ mm/memcontrol.c | 89 ++++++++++++++++++++------------------------ mm/slab_common.c | 5 ++- 3 files changed, 54 insertions(+), 49 deletions(-)include/linux/memcontrol.h +9
-0@@ -497,6 +497,9 @@ void __memcg_kmem_commit_charge(struct page *page,void __memcg_kmem_uncharge_pages (struct page *page,int order);int memcg_cache_id (struct mem_cgroup *memcg); + +char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache);int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache);void memcg_free_cache_params (struct kmem_cache *s);@@ -641,6 +644,12 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)return -1 ; } +static inline char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache) +{ +return NULL ; +} +static inline int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache) {mm/memcontrol.c +41
-48@@ -3193,6 +3193,32 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)return 0 ; } +char *memcg_create_cache_name (struct mem_cgroup *memcg, +struct kmem_cache *root_cache) +{ +static char *buf =NULL ; + +/* +* We need a mutex here to protect the shared buffer. Since this is +* expected to be called only on cache creation, we can employ the +* slab_mutex for that purpose. +*/ +lockdep_assert_held (&slab_mutex); + +if (!buf) { + buf =kmalloc (PATH_MAX ,GFP_KERNEL ); +if (!buf) +return NULL ; + } + +rcu_read_lock (); +snprintf (buf,PATH_MAX ,"%s(%d:%s)" , root_cache->name, +memcg_cache_id (memcg),cgroup_name (memcg->css.cgroup)); +rcu_read_unlock (); + +return kstrdup (buf,GFP_KERNEL ); +} +int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s,struct kmem_cache *root_cache) {@@ -3397,44 +3423,6 @@ void mem_cgroup_destroy_cache(struct kmem_cache *cachep)schedule_work (&cachep->memcg_params->destroy); } -static struct kmem_cache *memcg_create_kmem_cache (struct mem_cgroup *memcg, -struct kmem_cache *s) -{ -struct kmem_cache *new =NULL ; -static char *tmp_name =NULL ; -static DEFINE_MUTEX (mutex);/* protects tmp_name */ - -BUG_ON (!memcg_can_account_kmem (memcg)); - -mutex_lock (&mutex); -/* -* kmem_cache_create_memcg duplicates the given name and -* cgroup_name for this name requires RCU context. -* This static temporary buffer is used to prevent from -* pointless shortliving allocation. -*/ -if (!tmp_name) { - tmp_name =kmalloc (PATH_MAX ,GFP_KERNEL ); -if (!tmp_name) - goto out; - } - -rcu_read_lock (); -snprintf (tmp_name,PATH_MAX ,"%s(%d:%s)" , s->name, -memcg_cache_id (memcg),cgroup_name (memcg->css.cgroup)); -rcu_read_unlock (); - - new =kmem_cache_create_memcg (memcg, tmp_name, s->object_size, s->align, - (s->flags & ~SLAB_PANIC ), s->ctor, s); -if (new) - new->allocflags |= __GFP_KMEMCG; -else - new = s; -out: -mutex_unlock (&mutex); -return new; -} -void kmem_cache_destroy_memcg_children (struct kmem_cache *s) {struct kmem_cache *c;@@ -3481,12 +3469,6 @@ void kmem_cache_destroy_memcg_children(struct kmem_cache *s)mutex_unlock (&activate_kmem_mutex); } -struct create_work { -struct mem_cgroup *memcg; -struct kmem_cache *cachep; -struct work_struct work; -}; -static void mem_cgroup_destroy_all_caches (struct mem_cgroup *memcg) {struct kmem_cache *cachep;@@ -3504,13 +3486,24 @@ static void mem_cgroup_destroy_all_caches(struct mem_cgroup *memcg)mutex_unlock (&memcg->slab_caches_mutex); } +struct create_work { +struct mem_cgroup *memcg; +struct kmem_cache *cachep; +struct work_struct work; +}; +static void memcg_create_cache_work_func (struct work_struct *w) { -struct create_work *cw; + struct create_work *cw = container_of(w, struct create_work, work); +struct mem_cgroup *memcg = cw->memcg; +struct kmem_cache *s = cw->cachep; +struct kmem_cache *new; - cw = container_of(w, struct create_work, work); -memcg_create_kmem_cache (cw->memcg, cw->cachep); -css_put (&cw->memcg->css); + new =kmem_cache_create_memcg (memcg, s->name, s->object_size, s->align, + (s->flags & ~SLAB_PANIC ), s->ctor, s); +if (new) + new->allocflags |= __GFP_KMEMCG; +css_put (&memcg->css);kfree (cw); }mm/slab_common.c +4
-1@@ -215,7 +215,10 @@ kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size, s->align =calculate_alignment (flags, align, size); s->ctor = ctor; - s->name =kstrdup (name,GFP_KERNEL ); +if (memcg) + s->name =memcg_create_cache_name (memcg, parent_cache); +else + s->name =kstrdup (name,GFP_KERNEL );if (!s->name) goto out_free_cache;
Quoted 3 lines
Quoted 3 lines
Signature · 1 line
1.7.10.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 3/7 memcg, slab: separate memcg vs root cache creation paths
In reply to Vladimir DavydovMemcg-awareness turned kmem_cache_create() into a dirty interweaving of memcg-only and except-for-memcg calls. To clean this up, let's create a separate function handling memcg caches creation. Although this will result in the two functions having several hunks of practically the same code, I guess this is the case when readability fully covers the cost of code duplication.
--- include/linux/memcontrol.h | 14 ++--- include/linux/slab.h | 9 ++- mm/memcontrol.c | 16 ++---- mm/slab_common.c | 130 ++++++++++++++++++++++++++------------------ 4 files changed, 90 insertions(+), 79 deletions(-)
include/linux/memcontrol.h +4 -10
@@ -500,8 +500,8 @@ int memcg_cache_id(struct mem_cgroup *memcg);char *memcg_create_cache_name (struct mem_cgroup *memcg,struct kmem_cache *root_cache); -int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s, -struct kmem_cache *root_cache); +int memcg_alloc_cache_params (struct kmem_cache *s, +struct mem_cgroup *memcg,struct kmem_cache *root_cache);void memcg_free_cache_params (struct kmem_cache *s);void memcg_register_cache (struct kmem_cache *s);void memcg_unregister_cache (struct kmem_cache *s);
@@ -644,14 +644,8 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)return -1 ; } -static inline char *memcg_create_cache_name (struct mem_cgroup *memcg, -struct kmem_cache *root_cache) -{ -return NULL ; -} - -static inline int memcg_alloc_cache_params (struct mem_cgroup *memcg, -struct kmem_cache *s,struct kmem_cache *root_cache) +static inline int memcg_alloc_cache_params (struct kmem_cache *s, +struct mem_cgroup *memcg,struct kmem_cache *root_cache) {return 0 ; }
include/linux/slab.h +4 -5
@@ -113,11 +113,10 @@ void __init kmem_cache_init(void);int slab_is_available (void );struct kmem_cache *kmem_cache_create (const char *,size_t ,size_t , -unsigned long , -void (*)(void *)); -struct kmem_cache * -kmem_cache_create_memcg (struct mem_cgroup *,const char *,size_t ,size_t , -unsigned long ,void (*)(void *),struct kmem_cache *); +unsigned long ,void (*)(void *)); +#ifdef CONFIG_MEMCG_KMEM +int kmem_cache_create_memcg (struct mem_cgroup *,struct kmem_cache *); +#endif void kmem_cache_destroy (struct kmem_cache *);int kmem_cache_shrink (struct kmem_cache *);void kmem_cache_free (struct kmem_cache *,void *);
mm/memcontrol.c +5 -11
@@ -3224,8 +3224,8 @@ char *memcg_create_cache_name(struct mem_cgroup *memcg,return name; } -int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s, -struct kmem_cache *root_cache) +int memcg_alloc_cache_params (struct kmem_cache *s, +struct mem_cgroup *memcg,struct kmem_cache *root_cache) {size_t size;
@@ -3500,15 +3500,9 @@ struct create_work {static void memcg_create_cache_work_func (struct work_struct *w) { struct create_work *cw = container_of(w, struct create_work, work); -struct mem_cgroup *memcg = cw->memcg; -struct kmem_cache *s = cw->cachep; -struct kmem_cache *new; - - new =kmem_cache_create_memcg (memcg, s->name, s->object_size, s->align, - (s->flags & ~SLAB_PANIC ), s->ctor, s); -if (new) - new->allocflags |= __GFP_KMEMCG; -css_put (&memcg->css); + +kmem_cache_create_memcg (cw->memcg, cw->cachep); +css_put (&cw->memcg->css);kfree (cw); }
mm/slab_common.c +77 -53
194 lines not on this page · raw message
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v2 3/7] memcg, slab: separate memcg vs root cache creation paths
Quoted 6 lines · Vladimir Davydov
Memcg-awareness turned
kmem_cache_create()into a dirty interweaving of memcg-only and except-for-memcg calls. To clean this up, let's create a separate function handling memcg caches creation. Although this will result in the two functions having several hunks of practically the same code, I guess this is the case when readability fully covers the cost of code duplication.
I don't know. The code is apparently cleaner because calling a function with NULL memcg just to go via several if (memcg) branches is ugly as hell. But having a duplicated function like this calls for a problem later.
Would it be possible to split kmem_cache_create into memcg independant part and do the rest in a single memcg branch?
Quoted 13 lines
Signed-off-by Vladimir Davydov <[email protected]>--- include/linux/memcontrol.h | 14 ++--- include/linux/slab.h | 9 ++- mm/memcontrol.c | 16 ++---- mm/slab_common.c | 130 ++++++++++++++++++++++++++------------------ 4 files changed, 90 insertions(+), 79 deletions(-)include/linux/memcontrol.h +0
-0
include/linux/memcontrol.h int memcg_cache_id(struct mem_cgroup *memcg); · line 504
Quoted 7 lines
include/linux/memcontrol.h +2
-2@@ -500,8 +500,8 @@ int memcg_cache_id(struct mem_cgroup *memcg);char *memcg_create_cache_name (struct mem_cgroup *memcg,struct kmem_cache *root_cache); -int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s, -struct kmem_cache *root_cache); +int memcg_alloc_cache_params (struct kmem_cache *s, +struct mem_cgroup *memcg,struct kmem_cache *root_cache);
Why is the parameters ordering changed? It really doesn't help review the patch. Also what does `s' stand for and can we use a more descriptive name, please?
[...]
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v2 3/7] memcg, slab: separate memcg vs root cache creation paths
Quoted 7 lines · Michal Hocko
Quoted 6 lines · Vladimir Davydov
Memcg-awareness turned
kmem_cache_create()into a dirty interweaving of memcg-only and except-for-memcg calls. To clean this up, let's create a separate function handling memcg caches creation. Although this will result in the two functions having several hunks of practically the same code, I guess this is the case when readability fully covers the cost of code duplication.
Quoted 7 lines
I don't know. The code is apparently cleaner because calling a function with NULL memcg just to go via several if (memcg) branches is ugly as hell. But having a duplicated function like this calls for a problem later.
Would it be possible to split
kmem_cache_createinto memcg independant part and do the rest in a single memcg branch?
May be, something like the patch attached?
Quoted 15 lines
Quoted 15 lines
Signed-off-by Vladimir Davydov <[email protected]>--- include/linux/memcontrol.h | 14 ++--- include/linux/slab.h | 9 ++- mm/memcontrol.c | 16 ++---- mm/slab_common.c | 130 ++++++++++++++++++++++++++------------------ 4 files changed, 90 insertions(+), 79 deletions(-)include/linux/memcontrol.h +0
-0@@ -500,8 +500,8 @@ int memcg_cache_id(struct mem_cgroup *memcg);
Quoted 8 lines
include/linux/memcontrol.h int memcg_cache_id(struct mem_cgroup *memcg); · line 504
Quoted 6 lines
include/linux/memcontrol.h +2
-2char *memcg_create_cache_name (struct mem_cgroup *memcg,struct kmem_cache *root_cache); -int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s, -struct kmem_cache *root_cache); +int memcg_alloc_cache_params (struct kmem_cache *s, +struct mem_cgroup *memcg,struct kmem_cache *root_cache);Why is the parameters ordering changed? It really doesn't help review the patch.
Oh, this is because seeing something like
memcg_alloc_cache_params(NULL, s, NULL);
hurts my brain :-) I prefer to have NULLs in the end.
Quoted 2 lines
Also what does `s' stand for and can we use a more descriptive name, please?
Yes, we can call it `cachep', but it would be too long :-/
`s' is the common name for a kmem_cache throughout mm/sl[au]b.c so I guess it fits here. However, this function certainly needs a comment - I guess I'll do it along with swapping the function parameters in a separate patch.
Thanks.
Re: [PATCH v2 3/7] memcg, slab: separate memcg vs root cache creation paths
Quoted 42 lines · Vladimir Davydov
Quoted 7 lines · Michal Hocko
Quoted 6 lines · Vladimir Davydov
Memcg-awareness turned
kmem_cache_create()into a dirty interweaving of memcg-only and except-for-memcg calls. To clean this up, let's create a separate function handling memcg caches creation. Although this will result in the two functions having several hunks of practically the same code, I guess this is the case when readability fully covers the cost of code duplication.Quoted 7 lines
I don't know. The code is apparently cleaner because calling a function with NULL memcg just to go via several if (memcg) branches is ugly as hell. But having a duplicated function like this calls for a problem later.
Would it be possible to split
kmem_cache_createinto memcg independant part and do the rest in a single memcg branch?May be, something like the patch attached?
Quoted 15 lines
Quoted 15 lines
Signed-off-by Vladimir Davydov <[email protected]>--- include/linux/memcontrol.h | 14 ++--- include/linux/slab.h | 9 ++- mm/memcontrol.c | 16 ++---- mm/slab_common.c | 130 ++++++++++++++++++++++++++------------------ 4 files changed, 90 insertions(+), 79 deletions(-)include/linux/memcontrol.h +0
-0@@ -500,8 +500,8 @@ int memcg_cache_id(struct mem_cgroup *memcg);Quoted 8 lines
include/linux/memcontrol.h int memcg_cache_id(struct mem_cgroup *memcg); · line 504
Quoted 6 lines
include/linux/memcontrol.h +2
-2char *memcg_create_cache_name (struct mem_cgroup *memcg,struct kmem_cache *root_cache); -int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s, -struct kmem_cache *root_cache); +int memcg_alloc_cache_params (struct kmem_cache *s, +struct mem_cgroup *memcg,struct kmem_cache *root_cache);Why is the parameters ordering changed? It really doesn't help review the patch.
Quoted 5 lines
Oh, this is because seeing something like
memcg_alloc_cache_params(NULL, s, NULL);hurts my brain :-) I prefer to have NULLs in the end.
the function still allocates parameters for the given memcg and cache and needs a reference to root cache so the ordering kind of makes sense to me.
Quoted 9 lines
Quoted 2 lines
Also what does `s' stand for and can we use a more descriptive name, please?
Yes, we can call it `cachep', but it would be too long :-/
`s' is the common name for a
kmem_cachethroughout mm/sl[au]b.c so I guess it fits here. However, this function certainly needs a comment - I guess I'll do it along with swapping the function parameters in a separate patch.
Yes, it seems that self explaining `s' is spread all over the place.
Quoted 5 lines
From
55f0916c794ad25a8bf45566f6d333bea956e0d4Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <[email protected]>
Date: Mon, 3 Feb 2014 19:18:22 +0400
Subject: [PATCH] memcg, slab: separate memcg vs root cache creation paths
Quoted 8 lines
Memcg-awareness turned
kmem_cache_create()into a dirty interweaving of memcg-only and except-for-memcg calls. To clean this up, let's create a separate function handling memcg caches creation. Although this will result in the two functions having several hunks of practically the same code, I guess this is the case when readability fully covers the cost of code duplication.Signed-off-by Vladimir Davydov <[email protected]>
This looks better. The naming could still be little bit better because do_kmem_cache_create suggests that no memcg is involved but it at least reduced all the code duplication and nasty if(memcg) parts.
Few minor comments bellow
Quoted 11 lines
--- include/linux/slab.h | 9 ++- mm/memcontrol.c | 12 +--- mm/slab_common.c | 174 +++++++++++++++++++++++++++----------------------- 3 files changed, 101 insertions(+), 94 deletions(-)include/linux/slab.h +0
-0
include/linux/slab.h void __init kmem_cache_init(void); · line 116
Quoted 9 lines
include/linux/slab.h +1
-5@@ -113,11 +113,10 @@ void __init kmem_cache_init(void);int slab_is_available (void );struct kmem_cache *kmem_cache_create (const char *,size_t ,size_t , -unsigned long , -void (*)(void *)); -struct kmem_cache * -kmem_cache_create_memcg (struct mem_cgroup *,const char *,size_t ,size_t , -unsigned long ,void (*)(void *),struct kmem_cache *); +unsigned long ,void (*)(void *));
It is quite confusing when you mix formatting changes with other ones.
[...]
Quoted 4 lines
mm/slab_common.c +0
-0
[...]
Quoted 5 lines
mm/slab_common.c +3
-1+int kmem_cache_create_memcg (struct mem_cgroup *memcg,struct kmem_cache *cachep) { -return kmem_cache_create_memcg (NULL , name, size, align, flags, ctor,NULL ); +struct kmem_cache *s; +int err;
mm/slab_common.c
Quoted 10 lines
mm/slab_common.c +10
-0+ +get_online_cpus (); +mutex_lock (&slab_mutex); + +/* +* Since per-memcg caches are created asynchronously on first +* allocation (see memcg_kmem_get_cache()), several threads can try to +* create the same cache, but only one of them may succeed. +*/ + err = -EEXIST ;
Does it make any sense to report the error here? If we are racing then at least on part wins and the work is done.
We should probably warn about errors which prevent from accounting but I do not think there is much more we can do so returning an error code from this function seems pointless. memcg_create_cache_work_func ignores the return value anyway.
Quoted 24 lines
mm/slab_common.c +16
-1+if (cache_from_memcg_idx (cachep,memcg_cache_id (memcg))) + goto out_unlock; + + s =do_kmem_cache_create (memcg_create_cache_name (memcg, cachep), + cachep->object_size, cachep->size, cachep->align, + cachep->flags & ~SLAB_PANIC , cachep->ctor, + memcg, cachep); + err =IS_ERR (s) ?PTR_ERR (s) :0 ; +if (!err) + s->allocflags |= __GFP_KMEMCG; + +out_unlock: +mutex_unlock (&slab_mutex); +put_online_cpus (); + return err; } -EXPORT_SYMBOL (kmem_cache_create); +#endif /* CONFIG_MEMCG_KMEM */ void kmem_cache_destroy (struct kmem_cache *s) {Signature · 1 line
1.7.10.4
Signature · 2 lines
Michal Hocko SUSE Labs
Re: [PATCH v2 3/7] memcg, slab: separate memcg vs root cache creation paths
Quoted 41 lines · Michal Hocko
Quoted 40 lines · Vladimir Davydov
Quoted 7 lines · Michal Hocko
Quoted 6 lines · Vladimir Davydov
Memcg-awareness turned
kmem_cache_create()into a dirty interweaving of memcg-only and except-for-memcg calls. To clean this up, let's create a separate function handling memcg caches creation. Although this will result in the two functions having several hunks of practically the same code, I guess this is the case when readability fully covers the cost of code duplication.Quoted 7 lines
I don't know. The code is apparently cleaner because calling a function with NULL memcg just to go via several if (memcg) branches is ugly as hell. But having a duplicated function like this calls for a problem later.
Would it be possible to split
kmem_cache_createinto memcg independant part and do the rest in a single memcg branch?May be, something like the patch attached?
Quoted 23 lines
Quoted 14 lines
Signed-off-by Vladimir Davydov <[email protected]>--- include/linux/memcontrol.h | 14 ++--- include/linux/slab.h | 9 ++- mm/memcontrol.c | 16 ++---- mm/slab_common.c | 130 ++++++++++++++++++++++++++------------------ 4 files changed, 90 insertions(+), 79 deletions(-)include/linux/memcontrol.h +0
-0include/linux/memcontrol.h int memcg_cache_id(struct mem_cgroup *memcg); · line 504
Quoted 7 lines
include/linux/memcontrol.h +2
-2@@ -500,8 +500,8 @@ int memcg_cache_id(struct mem_cgroup *memcg);char *memcg_create_cache_name (struct mem_cgroup *memcg,struct kmem_cache *root_cache); -int memcg_alloc_cache_params (struct mem_cgroup *memcg,struct kmem_cache *s, -struct kmem_cache *root_cache); +int memcg_alloc_cache_params (struct kmem_cache *s, +struct mem_cgroup *memcg,struct kmem_cache *root_cache);Why is the parameters ordering changed? It really doesn't help review the patch.
Quoted 8 lines
Quoted 5 lines
Oh, this is because seeing something like
memcg_alloc_cache_params(NULL, s, NULL);hurts my brain :-) I prefer to have NULLs in the end.
the function still allocates parameters for the given memcg and cache and needs a reference to root cache so the ordering kind of makes sense to me.
All right, I'll leave it as is then - anyway, in this patch this hunk is absent.
Quoted 43 lines
Quoted 9 lines
Quoted 3 lines
Also what does `s' stand for and can we use a more descriptive name, please?
Yes, we can call it `cachep', but it would be too long :-/
`s' is the common name for a
kmem_cachethroughout mm/sl[au]b.c so I guess it fits here. However, this function certainly needs a comment - I guess I'll do it along with swapping the function parameters in a separate patch.Yes, it seems that self explaining `s' is spread all over the place.
Quoted 5 lines
From
55f0916c794ad25a8bf45566f6d333bea956e0d4Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <[email protected]>
Date: Mon, 3 Feb 2014 19:18:22 +0400
Subject: [PATCH] memcg, slab: separate memcg vs root cache creation pathsQuoted 8 lines
Memcg-awareness turned
kmem_cache_create()into a dirty interweaving of memcg-only and except-for-memcg calls. To clean this up, let's create a separate function handling memcg caches creation. Although this will result in the two functions having several hunks of practically the same code, I guess this is the case when readability fully covers the cost of code duplication.Signed-off-by Vladimir Davydov <[email protected]>This looks better. The naming could still be little bit better because
do_kmem_cache_createsuggests that no memcg is involved but it at least reduced all the code duplication and nasty if(memcg) parts.Few minor comments bellow
Quoted 13 lines
--- include/linux/slab.h | 9 ++- mm/memcontrol.c | 12 +--- mm/slab_common.c | 174 +++++++++++++++++++++++++++----------------------- 3 files changed, 101 insertions(+), 94 deletions(-)include/linux/slab.h +0
-0@@ -113,11 +113,10 @@ void __init kmem_cache_init(void);int slab_is_available (void );
Quoted 8 lines
include/linux/slab.h void __init kmem_cache_init(void); · line 116
Quoted 7 lines
include/linux/slab.h +1
-5struct kmem_cache *kmem_cache_create (const char *,size_t ,size_t , -unsigned long , -void (*)(void *)); -struct kmem_cache * -kmem_cache_create_memcg (struct mem_cgroup *,const char *,size_t ,size_t , -unsigned long ,void (*)(void *),struct kmem_cache *); +unsigned long ,void (*)(void *));It is quite confusing when you mix formatting changes with other ones.
Oh, just could not pass this by. I guess I'll do it in a separate patch then.
Quoted 16 lines
[...]
Quoted 4 lines
mm/slab_common.c +0
-0[...]
Quoted 9 lines
mm/slab_common.c +7
-1+int kmem_cache_create_memcg (struct mem_cgroup *memcg,struct kmem_cache *cachep) { -return kmem_cache_create_memcg (NULL , name, size, align, flags, ctor,NULL ); +struct kmem_cache *s; +int err; + +get_online_cpus (); +mutex_lock (&slab_mutex); +
Quoted 8 lines
mm/slab_common.c
Quoted 6 lines
mm/slab_common.c +6
-0+/* +* Since per-memcg caches are created asynchronously on first +* allocation (see memcg_kmem_get_cache()), several threads can try to +* create the same cache, but only one of them may succeed. +*/ + err = -EEXIST ;Does it make any sense to report the error here? If we are racing then at least on part wins and the work is done.
Yeah, you're perfectly right. It's better to return 0 here.
Quoted 4 lines
We should probably warn about errors which prevent from accounting but I do not think there is much more we can do so returning an error code from this function seems pointless.
memcg_create_cache_work_funcignores the return value anyway.
I do not think warnings are appropriate here, because it is not actually an error if we are short on memory and can't do proper memcg accounting due to this. Perhaps, we'd better add fail counters for memcg cache creations and/or accounting to the root cache instead of memcg's one. That would be useful for debugging. I'm not sure though.
Thanks.
Quoted 26 lines
Quoted 25 lines
mm/slab_common.c +16
-1+if (cache_from_memcg_idx (cachep,memcg_cache_id (memcg))) + goto out_unlock; + + s =do_kmem_cache_create (memcg_create_cache_name (memcg, cachep), + cachep->object_size, cachep->size, cachep->align, + cachep->flags & ~SLAB_PANIC , cachep->ctor, + memcg, cachep); + err =IS_ERR (s) ?PTR_ERR (s) :0 ; +if (!err) + s->allocflags |= __GFP_KMEMCG; + +out_unlock: +mutex_unlock (&slab_mutex); +put_online_cpus (); + return err; } -EXPORT_SYMBOL (kmem_cache_create); +#endif /* CONFIG_MEMCG_KMEM */ void kmem_cache_destroy (struct kmem_cache *s) {Signature · 1 line
1.7.10.4
Re: [PATCH v2 3/7] memcg, slab: separate memcg vs root cache creation paths
Quoted 1 line · Vladimir Davydov
On 02/06/2014 08:41 PM, Michal Hocko wrote:
[...]
Quoted 18 lines
Quoted 9 lines
Quoted 9 lines
(quoted diff) +7
-1+int kmem_cache_create_memcg(struct mem_cgroup *memcg, struct kmem_cache *cachep) { - return kmem_cache_create_memcg(NULL, name, size, align, flags, ctor, NULL); + struct kmem_cache *s; + int err; + + get_online_cpus(); + mutex_lock(&slab_mutex); +Quoted 8 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ /* + * Since per-memcg caches are created asynchronously on first + * allocation (see memcg_kmem_get_cache()), several threads can try to + * create the same cache, but only one of them may succeed. + */ + err = -EEXIST;Does it make any sense to report the error here? If we are racing then at least on part wins and the work is done.
Quoted 1 line
Yeah, you're perfectly right. It's better to return 0 here.
Why not void?
Quoted 10 lines
Quoted 4 lines
We should probably warn about errors which prevent from accounting but I do not think there is much more we can do so returning an error code from this function seems pointless.
memcg_create_cache_work_funcignores the return value anyway.I do not think warnings are appropriate here, because it is not actually an error if we are short on memory and can't do proper memcg accounting due to this. Perhaps, we'd better add fail counters for memcg cache creations and/or accounting to the root cache instead of memcg's one. That would be useful for debugging. I'm not sure though.
warn on once per memcg would be probably sufficient but it would still be great if an admin could see that a memcg is not accounted although it is supposed to be. Scanning all the memcgs might be really impractical. We do not fail allocations needed for those object in the real life now but we shouldn't rely on that.
Signature · 2 lines
Michal Hocko SUSE Labs
Re: [PATCH v2 3/7] memcg, slab: separate memcg vs root cache creation paths
Quoted 20 lines · Michal Hocko
Quoted 1 line · Vladimir Davydov
On 02/06/2014 08:41 PM, Michal Hocko wrote:
[...]
Quoted 17 lines
Quoted 17 lines
Quoted 5 lines
(quoted diff) +3
-1+int kmem_cache_create_memcg(struct mem_cgroup *memcg, struct kmem_cache *cachep) { - return kmem_cache_create_memcg(NULL, name, size, align, flags, ctor, NULL); + struct kmem_cache *s; + int err;Review
Quoted 10 lines
(quoted diff) +10
-0+ + get_online_cpus(); + mutex_lock(&slab_mutex); + + /* + * Since per-memcg caches are created asynchronously on first + * allocation (see memcg_kmem_get_cache()), several threads can try to + * create the same cache, but only one of them may succeed. + */ + err = -EEXIST;Does it make any sense to report the error here? If we are racing then at least on part wins and the work is done.
Quoted 2 lines
Quoted 1 line
Yeah, you're perfectly right. It's better to return 0 here.
Why not void?
Yeah, better to make it void for now, just to keep it clean. I guess if one day we need an error code there (for accounting of error reporting), we'll add it then, but currently there is no point in that.
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
We should probably warn about errors which prevent from accounting but I do not think there is much more we can do so returning an error code from this function seems pointless.
memcg_create_cache_work_funcignores the return value anyway.I do not think warnings are appropriate here, because it is not actually an error if we are short on memory and can't do proper memcg accounting due to this. Perhaps, we'd better add fail counters for memcg cache creations and/or accounting to the root cache instead of memcg's one. That would be useful for debugging. I'm not sure though.
Quoted 5 lines
warn on once per memcg would be probably sufficient but it would still be great if an admin could see that a memcg is not accounted although it is supposed to be. Scanning all the memcgs might be really impractical. We do not fail allocations needed for those object in the real life now but we shouldn't rely on that.
Hmm, an alert in dmesg first time kmem_cache_create_memcg() fails for a particular memcg, just to draw attention, plus accounting of total number of failures for each memcg so that admin could check if it's a real problem... Sounds reasonable to me. I guess I'll handle it in a separate patch a bit later.
Thanks.
PATCH v2 4/7 memcg, slab: unregister cache from memcg before starting to destroy it
In reply to Vladimir DavydovCurrently, memcg_unregister_cache(), which deletes the cache being destroyed from the memcg_slab_caches list, is called after __kmem_cache_shutdown() (see kmem_cache_destroy()), which starts to destroy the cache. As a result, one can access a partially destroyed cache while traversing a memcg_slab_caches list, which can have deadly consequences (for instance, cache_show() called for each cache on a memcg_slab_caches list from mem_cgroup_slabinfo_read() will dereference pointers to already freed data).
To fix this, let's move memcg_unregister_cache() before the cache destruction process beginning, issuing memcg_register_cache() on failure.
--- mm/memcontrol.c | 12 ++++++------ mm/slab_common.c | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-)
mm/memcontrol.c +6 -6
@@ -3247,6 +3247,7 @@ int memcg_alloc_cache_params(struct kmem_cache *s, s->memcg_params->root_cache = root_cache;INIT_WORK (&s->memcg_params->destroy, kmem_cache_destroy_work_func); +css_get (&memcg->css); }else s->memcg_params->is_root_cache = true;
@@ -3255,6 +3256,10 @@ int memcg_alloc_cache_params(struct kmem_cache *s,void memcg_free_cache_params (struct kmem_cache *s) { +if (!s->memcg_params) +return ; +if (!s->memcg_params->is_root_cache) +css_put (&s->memcg_params->memcg->css);kfree (s->memcg_params); }
@@ -3277,9 +3282,6 @@ void memcg_register_cache(struct kmem_cache *s) memcg = s->memcg_params->memcg; id =memcg_cache_id (memcg); -css_get (&memcg->css); - -/* * Since readers won't lock (see cache_from_memcg_idx()), we need a * barrier here to ensure nobody will see the kmem_cache partially
@@ -3328,10 +3330,8 @@ void memcg_unregister_cache(struct kmem_cache *s)* after removing it from the memcg_slab_caches list, otherwise we can * fail to convert memcg_params_to_cache() while traversing the list. */ -VM_BUG_ON (!root->memcg_params->memcg_caches[id]); +VM_BUG_ON (root->memcg_params->memcg_caches[id] != s); root->memcg_params->memcg_caches[id] =NULL ; - -css_put (&memcg->css); }/*
mm/slab_common.c +2 -1
@@ -310,9 +310,9 @@ void kmem_cache_destroy(struct kmem_cache *s) s->refcount--;if (!s->refcount) {list_del (&s->list); +memcg_unregister_cache (s);if (!__kmem_cache_shutdown (s)) { -memcg_unregister_cache (s);mutex_unlock (&slab_mutex);if (s->flags &SLAB_DESTROY_BY_RCU )rcu_barrier ();
@@ -322,6 +322,7 @@ void kmem_cache_destroy(struct kmem_cache *s)kmem_cache_free (kmem_cache, s); }else {list_add (&s->list, &slab_caches); +memcg_register_cache (s);mutex_unlock (&slab_mutex);printk (KERN_ERR "kmem_cache_destroy %s: Slab cache still has objects\n" , s->name);
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 5/7 memcg, slab: do not destroy children caches if parent has aliases
In reply to Vladimir DavydovCurrently we destroy children caches at the very beginning of kmem_cache_destroy(). This is wrong, because the root cache will not necessarily be destroyed in the end - if it has aliases (refcount > 0), kmem_cache_destroy() will simply decrement its refcount and return. In this case, at best we will get a bunch of warnings in dmesg, like this one:
kmem_cache_destroy kmalloc-32:0: Slab cache still has objects
CPU: 1 PID: 7139 Comm: modprobe Tainted: G B W 3.13.0+ #117 Hardware name: ffff88007d7a6368 ffff880039b07e48 ffffffff8168cc2e ffff88007d7a6d68 ffff88007d7a6300 ffff880039b07e68 ffffffff81175e9f 0000000000000000 ffff88007d7a6300 ffff880039b07e98 ffffffff811b67c7 ffff88003e803c00 Call Trace: [<ffffffff8168cc2e>] dump_stack+0x49/0x5b [<ffffffff81175e9f>] kmem_cache_destroy+0xdf/0xf0 [<ffffffff811b67c7>] kmem_cache_destroy_memcg_children+0x97/0xc0 [<ffffffff81175dcf>] kmem_cache_destroy+0xf/0xf0 [<ffffffffa0130b21>] xfs_mru_cache_uninit+0x21/0x30 [xfs] [<ffffffffa01893ea>] exit_xfs_fs+0x2e/0xc44 [xfs] [<ffffffff810eeb58>] SyS_delete_module+0x198/0x1f0 [<ffffffff816994f9>] system_call_fastpath+0x16/0x1b
At worst - if kmem_cache_destroy() will race with an allocation from a memcg cache - the kernel will panic.
This patch fixes this by moving children caches destruction after the check if the cache has aliases. Plus, it forbids destroying a root cache if it still has children caches, because each children cache keeps a reference to its parent.
--- include/linux/memcontrol.h | 5 --- mm/memcontrol.c | 2 +- mm/slab.h | 17 ++++++++-- mm/slab_common.c | 74 +++++++++++++++++++++++++++++--------------- 4 files changed, 65 insertions(+), 33 deletions(-)
include/linux/memcontrol.h +0 -5
@@ -513,7 +513,6 @@ struct kmem_cache * __memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp);void mem_cgroup_destroy_cache (struct kmem_cache *cachep); -void kmem_cache_destroy_memcg_children (struct kmem_cache *s);/** * memcg_kmem_newpage_charge: verify if a new kmem allocation is allowed.
@@ -667,10 +666,6 @@ memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp) {return cachep; } - -static inline void kmem_cache_destroy_memcg_children (struct kmem_cache *s) -{ -}#endif /* CONFIG_MEMCG_KMEM */ #endif /* _LINUX_MEMCONTROL_H */
mm/memcontrol.c +1 -1
@@ -3428,7 +3428,7 @@ void mem_cgroup_destroy_cache(struct kmem_cache *cachep)schedule_work (&cachep->memcg_params->destroy); } -void kmem_cache_destroy_memcg_children (struct kmem_cache *s) +void __kmem_cache_destroy_memcg_children (struct kmem_cache *s) {struct kmem_cache *c;int i;
mm/slab.h +15 -2
@@ -191,7 +191,16 @@ static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)return s; return s->memcg_params->root_cache; } -#else + +extern void __kmem_cache_destroy_memcg_children (struct kmem_cache *s); + +static inline void kmem_cache_destroy_memcg_children (struct kmem_cache *s) +{ +mutex_unlock (&slab_mutex); +__kmem_cache_destroy_memcg_children (s); +mutex_lock (&slab_mutex); +} +#else /* !CONFIG_MEMCG_KMEM */ static inline bool is_root_cache (struct kmem_cache *s) {return true;
@@ -226,7 +235,11 @@ static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s) {return s; } -#endif + +static inline void kmem_cache_destroy_memcg_children (struct kmem_cache *s) +{ +} +#endif /* CONFIG_MEMCG_KMEM */ static inline struct kmem_cache *cache_from_obj (struct kmem_cache *s,void *x) {
mm/slab_common.c +49 -25
87 lines not on this page · raw message
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 6/7 slub: adjust memcg caches when creating cache alias
In reply to Vladimir DavydovOtherwise, kzalloc() called from a memcg won't clear the whole object.
--- mm/slub.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
mm/slub.c +14 -0
@@ -3743,7 +3743,11 @@ __kmem_cache_alias(const char *name, size_t size, size_t align, s =find_mergeable (size, align, flags, name, ctor);if (s) { +int i; +struct kmem_cache *c; + s->refcount++; +/* * Adjust the object sizes so that we clear * the complete object on kzalloc.
@@ -3751,6 +3755,16 @@ __kmem_cache_alias(const char *name, size_t size, size_t align, s->object_size =max (s->object_size, (int )size); s->inuse =max_t (int, s->inuse,ALIGN (size,sizeof (void *))); +BUG_ON (!is_root_cache (s)); +for_each_memcg_cache_index (i) { + c =cache_from_memcg_idx (s, i); +if (!c) +continue ; + c->object_size = s->object_size; + c->inuse =max_t (int, c->inuse, +ALIGN (size,sizeof (void *))); + } +if (sysfs_slab_alias (s, name)) { s->refcount--; s =NULL ;
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 7/7 slub: rework sysfs layout for memcg caches
In reply to Vladimir DavydovCurrently, we try to arrange sysfs entries for memcg caches in the same manner as for global caches. Apart from turning /sys/kernel/slab into a mess when there are a lot of kmem-active memcgs created, it actually does not work properly - we won't create more than one link to a memcg cache in case its parent is merged with another cache. For instance, if A is a root cache merged with another root cache B, we will have the following sysfs setup:
X
A -> X
B -> X
where X is some unique id (see create_unique_id()). Now if memcgs M and N start to allocate from cache A (or B, which is the same), we will get:
X
X:M
X:N
A -> X
B -> X
A:M -> X:M
A:N -> X:N
Since B is an alias for A, we won't get entries B:M and B:N, which is confusing.
It is more logical to have entries for memcg caches under the corresponding root cache's sysfs directory. This would allow us to keep sysfs layout clean, and avoid such inconsistencies like one described above.
This patch does the trick. It creates a "cgroup" kset in each root cache kobject to keep its children caches there.
--- include/linux/slub_def.h | 3 ++ mm/slub.c | 85 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 15 deletions(-)
include/linux/slub_def.h +3 -0
@@ -87,6 +87,9 @@ struct kmem_cache {#ifdef CONFIG_MEMCG_KMEM struct memcg_cache_params *memcg_params;int max_attr_size;/* for propagation, maximum size of a stored attr */ +#ifdef CONFIG_SYSFS +struct kset *memcg_kset; +#endif #endif #ifdef CONFIG_NUMA
mm/slub.c +70 -15
130 lines not on this page · raw message
Signature · 7 lines
1.7.10.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>