All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vladimir Davydov <vdavydov@parallels.com>
To: Michal Hocko <mhocko@suse.cz>
Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org,
	cgroups@vger.kernel.org, devel@openvz.org,
	Johannes Weiner <hannes@cmpxchg.org>,
	Glauber Costa <glommer@gmail.com>,
	Christoph Lameter <cl@linux.com>,
	Pekka Enberg <penberg@kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>
Subject: Re: [PATCH 6/6] memcg, slab: RCU protect memcg_params for root caches
Date: Thu, 19 Dec 2013 13:36:42 +0400	[thread overview]
Message-ID: <52B2BE2A.2080509@parallels.com> (raw)
In-Reply-To: <20131219092836.GH9331@dhcp22.suse.cz>

On 12/19/2013 01:28 PM, Michal Hocko wrote:
> On Wed 18-12-13 17:16:57, Vladimir Davydov wrote:
>> We update root cache's memcg_params whenever we need to grow the
>> memcg_caches array to accommodate all kmem-active memory cgroups.
>> Currently we free the old version immediately then, which can lead to
>> use-after-free, because the memcg_caches array is accessed lock-free.
>> This patch fixes this by making memcg_params RCU-protected.
> yes, I was thinking about something like this when talking about RCU
> usage.

Not exactly (if you mean your replies to this series). We do not protect
kmem_caches, but we do protect the memcg_caches array, which can grow.

>
>> Signed-off-by: Vladimir Davydov <vdavydov@parallels.com>
>> Cc: Michal Hocko <mhocko@suse.cz>
>> Cc: Johannes Weiner <hannes@cmpxchg.org>
>> Cc: Glauber Costa <glommer@gmail.com>
>> Cc: Christoph Lameter <cl@linux.com>
>> Cc: Pekka Enberg <penberg@kernel.org>
>> Cc: Andrew Morton <akpm@linux-foundation.org>
>> ---
>>  include/linux/slab.h |    5 ++++-
>>  mm/memcontrol.c      |   15 ++++++++-------
>>  mm/slab.h            |    8 +++++++-
>>  3 files changed, 19 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/linux/slab.h b/include/linux/slab.h
>> index 1e2f4fe..f7e5649 100644
>> --- a/include/linux/slab.h
>> +++ b/include/linux/slab.h
>> @@ -528,7 +528,10 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
>>  struct memcg_cache_params {
>>  	bool is_root_cache;
>>  	union {
>> -		struct kmem_cache *memcg_caches[0];
>> +		struct {
>> +			struct rcu_head rcu_head;
>> +			struct kmem_cache *memcg_caches[0];
>> +		};
>>  		struct {
>>  			struct mem_cgroup *memcg;
>>  			struct list_head list;
>> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
>> index ad8de6a..379fc5f 100644
>> --- a/mm/memcontrol.c
>> +++ b/mm/memcontrol.c
>> @@ -3142,18 +3142,17 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
>>  
>>  	if (num_groups > memcg_limited_groups_array_size) {
>>  		int i;
>> +		struct memcg_cache_params *new_params;
>>  		ssize_t size = memcg_caches_array_size(num_groups);
>>  
>>  		size *= sizeof(void *);
>>  		size += offsetof(struct memcg_cache_params, memcg_caches);
>>  
>> -		s->memcg_params = kzalloc(size, GFP_KERNEL);
>> -		if (!s->memcg_params) {
>> -			s->memcg_params = cur_params;
>> +		new_params = kzalloc(size, GFP_KERNEL);
>> +		if (!new_params)
>>  			return -ENOMEM;
>> -		}
>>  
>> -		s->memcg_params->is_root_cache = true;
>> +		new_params->is_root_cache = true;
>>  
>>  		/*
>>  		 * There is the chance it will be bigger than
>> @@ -3167,7 +3166,7 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
>>  		for (i = 0; i < memcg_limited_groups_array_size; i++) {
>>  			if (!cur_params->memcg_caches[i])
>>  				continue;
>> -			s->memcg_params->memcg_caches[i] =
>> +			new_params->memcg_caches[i] =
>>  						cur_params->memcg_caches[i];
>>  		}
>>  
>> @@ -3180,7 +3179,9 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
>>  		 * bigger than the others. And all updates will reset this
>>  		 * anyway.
>>  		 */
>> -		kfree(cur_params);
>> +		rcu_assign_pointer(s->memcg_params, new_params);
>> +		if (cur_params)
>> +			kfree_rcu(cur_params, rcu_head);
>>  	}
>>  	return 0;
>>  }
>> diff --git a/mm/slab.h b/mm/slab.h
>> index 1d8b53f..53b81a9 100644
>> --- a/mm/slab.h
>> +++ b/mm/slab.h
>> @@ -164,10 +164,16 @@ static inline struct kmem_cache *
>>  cache_from_memcg_idx(struct kmem_cache *s, int idx)
>>  {
>>  	struct kmem_cache *cachep;
>> +	struct memcg_cache_params *params;
>>  
>>  	if (!s->memcg_params)
>>  		return NULL;
>> -	cachep = s->memcg_params->memcg_caches[idx];
>> +
>> +	rcu_read_lock();
>> +	params = rcu_dereference(s->memcg_params);
>> +	cachep = params->memcg_caches[idx];
>> +	rcu_read_unlock();
>> +
> Consumer has to be covered by the same rcu section otherwise
> memcg_params might be freed right after rcu unlock here.

No. We protect only accesses to kmem_cache::memcg_params, which can
potentially be relocated for root caches. But as soon as we get the
pointer to a kmem_cache from this array, we can freely dereference it,
because the cache cannot be freed when we use it. This is, because we
access a kmem_cache either under the slab_mutex or
memcg->slab_caches_mutex, or when we allocate/free from it. While doing
the latter, the cache can't go away, it would be a bug. IMO.

Thanks.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

WARNING: multiple messages have this Message-ID (diff)
From: Vladimir Davydov <vdavydov@parallels.com>
To: Michal Hocko <mhocko@suse.cz>
Cc: <linux-kernel@vger.kernel.org>, <linux-mm@kvack.org>,
	<cgroups@vger.kernel.org>, <devel@openvz.org>,
	Johannes Weiner <hannes@cmpxchg.org>,
	Glauber Costa <glommer@gmail.com>,
	Christoph Lameter <cl@linux.com>,
	Pekka Enberg <penberg@kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>
Subject: Re: [PATCH 6/6] memcg, slab: RCU protect memcg_params for root caches
Date: Thu, 19 Dec 2013 13:36:42 +0400	[thread overview]
Message-ID: <52B2BE2A.2080509@parallels.com> (raw)
In-Reply-To: <20131219092836.GH9331@dhcp22.suse.cz>

On 12/19/2013 01:28 PM, Michal Hocko wrote:
> On Wed 18-12-13 17:16:57, Vladimir Davydov wrote:
>> We update root cache's memcg_params whenever we need to grow the
>> memcg_caches array to accommodate all kmem-active memory cgroups.
>> Currently we free the old version immediately then, which can lead to
>> use-after-free, because the memcg_caches array is accessed lock-free.
>> This patch fixes this by making memcg_params RCU-protected.
> yes, I was thinking about something like this when talking about RCU
> usage.

Not exactly (if you mean your replies to this series). We do not protect
kmem_caches, but we do protect the memcg_caches array, which can grow.

>
>> Signed-off-by: Vladimir Davydov <vdavydov@parallels.com>
>> Cc: Michal Hocko <mhocko@suse.cz>
>> Cc: Johannes Weiner <hannes@cmpxchg.org>
>> Cc: Glauber Costa <glommer@gmail.com>
>> Cc: Christoph Lameter <cl@linux.com>
>> Cc: Pekka Enberg <penberg@kernel.org>
>> Cc: Andrew Morton <akpm@linux-foundation.org>
>> ---
>>  include/linux/slab.h |    5 ++++-
>>  mm/memcontrol.c      |   15 ++++++++-------
>>  mm/slab.h            |    8 +++++++-
>>  3 files changed, 19 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/linux/slab.h b/include/linux/slab.h
>> index 1e2f4fe..f7e5649 100644
>> --- a/include/linux/slab.h
>> +++ b/include/linux/slab.h
>> @@ -528,7 +528,10 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
>>  struct memcg_cache_params {
>>  	bool is_root_cache;
>>  	union {
>> -		struct kmem_cache *memcg_caches[0];
>> +		struct {
>> +			struct rcu_head rcu_head;
>> +			struct kmem_cache *memcg_caches[0];
>> +		};
>>  		struct {
>>  			struct mem_cgroup *memcg;
>>  			struct list_head list;
>> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
>> index ad8de6a..379fc5f 100644
>> --- a/mm/memcontrol.c
>> +++ b/mm/memcontrol.c
>> @@ -3142,18 +3142,17 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
>>  
>>  	if (num_groups > memcg_limited_groups_array_size) {
>>  		int i;
>> +		struct memcg_cache_params *new_params;
>>  		ssize_t size = memcg_caches_array_size(num_groups);
>>  
>>  		size *= sizeof(void *);
>>  		size += offsetof(struct memcg_cache_params, memcg_caches);
>>  
>> -		s->memcg_params = kzalloc(size, GFP_KERNEL);
>> -		if (!s->memcg_params) {
>> -			s->memcg_params = cur_params;
>> +		new_params = kzalloc(size, GFP_KERNEL);
>> +		if (!new_params)
>>  			return -ENOMEM;
>> -		}
>>  
>> -		s->memcg_params->is_root_cache = true;
>> +		new_params->is_root_cache = true;
>>  
>>  		/*
>>  		 * There is the chance it will be bigger than
>> @@ -3167,7 +3166,7 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
>>  		for (i = 0; i < memcg_limited_groups_array_size; i++) {
>>  			if (!cur_params->memcg_caches[i])
>>  				continue;
>> -			s->memcg_params->memcg_caches[i] =
>> +			new_params->memcg_caches[i] =
>>  						cur_params->memcg_caches[i];
>>  		}
>>  
>> @@ -3180,7 +3179,9 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
>>  		 * bigger than the others. And all updates will reset this
>>  		 * anyway.
>>  		 */
>> -		kfree(cur_params);
>> +		rcu_assign_pointer(s->memcg_params, new_params);
>> +		if (cur_params)
>> +			kfree_rcu(cur_params, rcu_head);
>>  	}
>>  	return 0;
>>  }
>> diff --git a/mm/slab.h b/mm/slab.h
>> index 1d8b53f..53b81a9 100644
>> --- a/mm/slab.h
>> +++ b/mm/slab.h
>> @@ -164,10 +164,16 @@ static inline struct kmem_cache *
>>  cache_from_memcg_idx(struct kmem_cache *s, int idx)
>>  {
>>  	struct kmem_cache *cachep;
>> +	struct memcg_cache_params *params;
>>  
>>  	if (!s->memcg_params)
>>  		return NULL;
>> -	cachep = s->memcg_params->memcg_caches[idx];
>> +
>> +	rcu_read_lock();
>> +	params = rcu_dereference(s->memcg_params);
>> +	cachep = params->memcg_caches[idx];
>> +	rcu_read_unlock();
>> +
> Consumer has to be covered by the same rcu section otherwise
> memcg_params might be freed right after rcu unlock here.

No. We protect only accesses to kmem_cache::memcg_params, which can
potentially be relocated for root caches. But as soon as we get the
pointer to a kmem_cache from this array, we can freely dereference it,
because the cache cannot be freed when we use it. This is, because we
access a kmem_cache either under the slab_mutex or
memcg->slab_caches_mutex, or when we allocate/free from it. While doing
the latter, the cache can't go away, it would be a bug. IMO.

Thanks.

  reply	other threads:[~2013-12-19  9:36 UTC|newest]

Thread overview: 98+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-18 13:16 [PATCH 1/6] slab: cleanup kmem_cache_create_memcg() Vladimir Davydov
2013-12-18 13:16 ` Vladimir Davydov
2013-12-18 13:16 ` Vladimir Davydov
2013-12-18 13:16 ` [PATCH 2/6] memcg, slab: kmem_cache_create_memcg(): free memcg params on error Vladimir Davydov
2013-12-18 13:16   ` Vladimir Davydov
     [not found]   ` <9420ad797a2cfa14c23ad1ba6db615a2a51ffee0.1387372122.git.vdavydov-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2013-12-18 17:06     ` Michal Hocko
2013-12-18 17:06       ` Michal Hocko
2013-12-18 17:06       ` Michal Hocko
     [not found]       ` <20131218170649.GC31080-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-12-19  6:32         ` Vladimir Davydov
2013-12-19  6:32           ` Vladimir Davydov
2013-12-19  6:32           ` Vladimir Davydov
2013-12-19  8:48           ` Michal Hocko
2013-12-19  8:48             ` Michal Hocko
2013-12-19  9:01             ` Vladimir Davydov
2013-12-19  9:01               ` Vladimir Davydov
2013-12-19  9:19               ` Michal Hocko
2013-12-19  9:19                 ` Michal Hocko
2013-12-18 13:16 ` [PATCH 3/6] memcg, slab: cleanup barrier usage when accessing memcg_caches Vladimir Davydov
2013-12-18 13:16   ` Vladimir Davydov
2013-12-18 17:14   ` Michal Hocko
2013-12-18 17:14     ` Michal Hocko
2013-12-19  6:37     ` Vladimir Davydov
2013-12-19  6:37       ` Vladimir Davydov
2013-12-19  9:10       ` Michal Hocko
2013-12-19  9:10         ` Michal Hocko
2013-12-19  9:16         ` Vladimir Davydov
2013-12-19  9:16           ` Vladimir Davydov
2013-12-19  9:21           ` Michal Hocko
2013-12-19  9:21             ` Michal Hocko
     [not found]             ` <20131219092137.GG9331-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-12-19  9:29               ` Vladimir Davydov
2013-12-19  9:29                 ` Vladimir Davydov
2013-12-19  9:29                 ` Vladimir Davydov
2013-12-19  9:36                 ` Michal Hocko
2013-12-19  9:36                   ` Michal Hocko
     [not found]                   ` <20131219093619.GA10855-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-12-19  9:53                     ` Vladimir Davydov
2013-12-19  9:53                       ` Vladimir Davydov
2013-12-19  9:53                       ` Vladimir Davydov
2013-12-18 13:16 ` [PATCH 4/6] memcg, slab: check and init memcg_cahes under slab_mutex Vladimir Davydov
2013-12-18 13:16   ` Vladimir Davydov
2013-12-18 17:41   ` Michal Hocko
2013-12-18 17:41     ` Michal Hocko
     [not found]     ` <20131218174105.GE31080-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-12-19  7:07       ` Vladimir Davydov
2013-12-19  7:07         ` Vladimir Davydov
2013-12-19  7:07         ` Vladimir Davydov
     [not found]         ` <52B29B2F.7050909-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2013-12-19  8:00           ` Glauber Costa
2013-12-19  8:00             ` Glauber Costa
2013-12-19  8:00             ` Glauber Costa
2013-12-19  9:12             ` Michal Hocko
2013-12-19  9:12               ` Michal Hocko
2013-12-19  9:17               ` Vladimir Davydov
2013-12-19  9:17                 ` Vladimir Davydov
2013-12-19  9:21             ` Vladimir Davydov
2013-12-19  9:21               ` Vladimir Davydov
2013-12-18 13:16 ` [PATCH 5/6] memcg: clear memcg_params after removing cache from memcg_slab_caches list Vladimir Davydov
2013-12-18 13:16   ` Vladimir Davydov
2013-12-18 13:16 ` [PATCH 6/6] memcg, slab: RCU protect memcg_params for root caches Vladimir Davydov
2013-12-18 13:16   ` Vladimir Davydov
2013-12-19  9:28   ` Michal Hocko
2013-12-19  9:28     ` Michal Hocko
2013-12-19  9:36     ` Vladimir Davydov [this message]
2013-12-19  9:36       ` Vladimir Davydov
     [not found]       ` <52B2BE2A.2080509-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2013-12-19  9:43         ` Michal Hocko
2013-12-19  9:43           ` Michal Hocko
2013-12-19  9:43           ` Michal Hocko
     [not found]           ` <20131219094333.GB10855-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-12-19  9:47             ` Vladimir Davydov
2013-12-19  9:47               ` Vladimir Davydov
2013-12-19  9:47               ` Vladimir Davydov
2013-12-19 10:06               ` Michal Hocko
2013-12-19 10:06                 ` Michal Hocko
2013-12-18 16:56 ` [PATCH 1/6] slab: cleanup kmem_cache_create_memcg() Michal Hocko
2013-12-18 16:56   ` Michal Hocko
     [not found]   ` <20131218165603.GB31080-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-12-19  6:31     ` Vladimir Davydov
2013-12-19  6:31       ` Vladimir Davydov
2013-12-19  6:31       ` Vladimir Davydov
2013-12-19  8:44       ` Michal Hocko
2013-12-19  8:44         ` Michal Hocko
     [not found]         ` <20131219084447.GA9331-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2013-12-19  8:51           ` Vladimir Davydov
2013-12-19  8:51             ` Vladimir Davydov
2013-12-19  8:51             ` Vladimir Davydov
2013-12-19  9:16             ` Michal Hocko
2013-12-19  9:16               ` Michal Hocko
     [not found] ` <6f02b2d079ffd0990ae335339c803337b13ecd8c.1387372122.git.vdavydov-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2013-12-19  7:27   ` Pekka Enberg
2013-12-19  7:27     ` Pekka Enberg
2013-12-19  7:27     ` Pekka Enberg
2013-12-19  8:17 ` [Devel] " Vasily Averin
2013-12-19  8:17   ` Vasily Averin
     [not found]   ` <52B2AB7C.1010803-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2013-12-19  8:39     ` Vladimir Davydov
2013-12-19  8:39       ` Vladimir Davydov
2013-12-19  8:39       ` Vladimir Davydov
     [not found]       ` <52B2B0A4.8050009-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2013-12-19  9:26         ` Vasily Averin
2013-12-19  9:26           ` Vasily Averin
2013-12-19  9:26           ` Vasily Averin
2013-12-19  9:42           ` Vladimir Davydov
2013-12-19  9:42             ` Vladimir Davydov
2013-12-19  9:45           ` Michal Hocko
2013-12-19  9:45             ` Michal Hocko
2013-12-19 10:23           ` Pekka Enberg
2013-12-19 10:23             ` Pekka Enberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=52B2BE2A.2080509@parallels.com \
    --to=vdavydov@parallels.com \
    --cc=akpm@linux-foundation.org \
    --cc=cgroups@vger.kernel.org \
    --cc=cl@linux.com \
    --cc=devel@openvz.org \
    --cc=glommer@gmail.com \
    --cc=hannes@cmpxchg.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mhocko@suse.cz \
    --cc=penberg@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.