Skip to contentSkip to conversation

fix RCU-callback-after-kmem_cache_destroy problem in sl[aou]b

RFC PATCH In review Paul E. McKenney 5 participants 14 messages Jun 25, 2009 – Jun 30, 2009

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 fix RCU-callback-after-kmem_cache_destroy problem in sl[aou]b

Hello!

Jesper noted that kmem_cache_destroy() invokes synchronize_rcu() rather than rcu_barrier() in the SLAB_DESTROY_BY_RCU case, which could result in RCU callbacks accessing a kmem_cache after it had been destroyed.

The following untested (might not even compile) patch proposes a fix.

---

 slab.c |    2 +-
 slob.c |    2 ++
 slub.c |    2 ++
 3 files changed, 5 insertions(+), 1 deletion(-)
mm/slab.c +1 -1
index e74a16e..5241b65 100644
@@ -2547,7 +2547,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
 	}
 
 	if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
-		synchronize_rcu();
+		rcu_barrier();
 
 	__kmem_cache_destroy(cachep);
 	mutex_unlock(&cache_chain_mutex);
mm/slob.c +2 -0
index c78742d..9641da3 100644
@@ -595,6 +595,8 @@ EXPORT_SYMBOL(kmem_cache_create);
 void kmem_cache_destroy(struct kmem_cache *c)
 {
 	kmemleak_free(c);
+	if (c->flags & SLAB_DESTROY_BY_RCU)
+		rcu_barrier();
 	slob_free(c, sizeof(struct kmem_cache));
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
mm/slub.c +2 -0
index 819f056..a9201d8 100644
@@ -2595,6 +2595,8 @@ static inline int kmem_cache_close(struct kmem_cache *s)
  */
 void kmem_cache_destroy(struct kmem_cache *s)
 {
+	if (s->flags & SLAB_DESTROY_BY_RCU)
+		rcu_barrier();
 	down_write(&slub_lock);
 	s->refcount--;
 	if (!s->refcount) {

--
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>

Acked-by on v1 1/1
#1 lore raw
Quoted 7 lines · Paul E. McKenney

Hello!

Jesper noted that kmem_cache_destroy() invokes synchronize_rcu() rather than rcu_barrier() in the SLAB_DESTROY_BY_RCU case, which could result in RCU callbacks accessing a kmem_cache after it had been destroyed.

The following untested (might not even compile) patch proposes a fix.

Nick, you'll want to make sure you get this in SLQB.

Quoted 48 lines

---

 slab.c |    2 +-
 slob.c |    2 ++
 slub.c |    2 ++
 3 files changed, 5 insertions(+), 1 deletion(-)
mm/slab.c +1 -1
index e74a16e..5241b65 100644
@@ -2547,7 +2547,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
 	}
 
 	if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
-		synchronize_rcu();
+		rcu_barrier();
 
 	__kmem_cache_destroy(cachep);
 	mutex_unlock(&cache_chain_mutex);
mm/slob.c +2 -0
index c78742d..9641da3 100644
@@ -595,6 +595,8 @@ EXPORT_SYMBOL(kmem_cache_create);
 void kmem_cache_destroy(struct kmem_cache *c)
 {
 	kmemleak_free(c);
+	if (c->flags & SLAB_DESTROY_BY_RCU)
+		rcu_barrier();
 	slob_free(c, sizeof(struct kmem_cache));
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
mm/slub.c +2 -0
index 819f056..a9201d8 100644
@@ -2595,6 +2595,8 @@ static inline int kmem_cache_close(struct kmem_cache *s)
  */
 void kmem_cache_destroy(struct kmem_cache *s)
 {
+	if (s->flags & SLAB_DESTROY_BY_RCU)
+		rcu_barrier();
 	down_write(&slub_lock);
 	s->refcount--;
 	if (!s->refcount) {
Signature · 8 lines
http://selenic.com : development and support for Mercurial and Linux


--
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>
#2 lore raw
Quoted 7 lines · Matt Mackall
Quoted 6 lines · Paul E. McKenney

Hello!

Jesper noted that kmem_cache_destroy() invokes synchronize_rcu() rather than rcu_barrier() in the SLAB_DESTROY_BY_RCU case, which could result in RCU callbacks accessing a kmem_cache after it had been destroyed.

Quoted 7 lines
Quoted 1 line

The following untested (might not even compile) patch proposes a fix.

Nick, you'll want to make sure you get this in SLQB.

Quoted 1 line

And I seem to have blown Jesper's email address (apologies, Jesper!), so:

Quoted 39 lines
Quoted 39 lines

---

 slab.c |    2 +-
 slob.c |    2 ++
 slub.c |    2 ++
 3 files changed, 5 insertions(+), 1 deletion(-)
mm/slab.c +1 -1
index e74a16e..5241b65 100644
@@ -2547,7 +2547,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
 	}
 
 	if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
-		synchronize_rcu();
+		rcu_barrier();
 
 	__kmem_cache_destroy(cachep);
 	mutex_unlock(&cache_chain_mutex);
mm/slob.c +2 -0
index c78742d..9641da3 100644
@@ -595,6 +595,8 @@ EXPORT_SYMBOL(kmem_cache_create);
 void kmem_cache_destroy(struct kmem_cache *c)
 {
 	kmemleak_free(c);
+	if (c->flags & SLAB_DESTROY_BY_RCU)
+		rcu_barrier();
 	slob_free(c, sizeof(struct kmem_cache));
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
mm/slub.c +0 -0
index 819f056..a9201d8 100644
@@ -2595,6 +2595,8 @@ static inline int kmem_cache_close(struct kmem_cache *s)
Quoted 13 lines
Quoted 8 lines
mm/slub.c +2 -0
  */
 void kmem_cache_destroy(struct kmem_cache *s)
 {
+	if (s->flags & SLAB_DESTROY_BY_RCU)
+		rcu_barrier();
 	down_write(&slub_lock);
 	s->refcount--;
 	if (!s->refcount) {
Signature · 1 line
http://selenic.com : development and support for Mercurial and Linux

--
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>

#3 lore raw
Quoted 12 lines · Paul E. McKenney
Quoted 11 lines · Matt Mackall
Quoted 7 lines · Paul E. McKenney

Hello!

Jesper noted that kmem_cache_destroy() invokes synchronize_rcu() rather than rcu_barrier() in the SLAB_DESTROY_BY_RCU case, which could result in RCU callbacks accessing a kmem_cache after it had been destroyed.

The following untested (might not even compile) patch proposes a fix.

Quoted 7 lines
Quoted 3 lines

Nick, you'll want to make sure you get this in SLQB.

Quoted 1 line

And I seem to have blown Jesper's email address (apologies, Jesper!), so:

Compiles and boots here so I went ahead and applied the patch. ;) Thanks a lot Paul!

Pekka

--
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>

#4 lore raw
In reply to Matt Mackall
Quoted 7 lines · Matt Mackall
Quoted 6 lines · Paul E. McKenney

Hello!

Jesper noted that kmem_cache_destroy() invokes synchronize_rcu() rather than rcu_barrier() in the SLAB_DESTROY_BY_RCU case, which could result in RCU callbacks accessing a kmem_cache after it had been destroyed.

Quoted 5 lines
Quoted 1 line

The following untested (might not even compile) patch proposes a fix.

Nick, you'll want to make sure you get this in SLQB.

Thanks Matt. Paul, I think this should be appropriate for [email protected] too?

Quoted 41 lines
Quoted 41 lines

---

 slab.c |    2 +-
 slob.c |    2 ++
 slub.c |    2 ++
 3 files changed, 5 insertions(+), 1 deletion(-)
mm/slab.c +1 -1
index e74a16e..5241b65 100644
@@ -2547,7 +2547,7 @@ void kmem_cache_destroy(struct kmem_cache *cachep)
 	}
 
 	if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
-		synchronize_rcu();
+		rcu_barrier();
 
 	__kmem_cache_destroy(cachep);
 	mutex_unlock(&cache_chain_mutex);
mm/slob.c +2 -0
index c78742d..9641da3 100644
@@ -595,6 +595,8 @@ EXPORT_SYMBOL(kmem_cache_create);
 void kmem_cache_destroy(struct kmem_cache *c)
 {
 	kmemleak_free(c);
+	if (c->flags & SLAB_DESTROY_BY_RCU)
+		rcu_barrier();
 	slob_free(c, sizeof(struct kmem_cache));
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
mm/slub.c +0 -0
index 819f056..a9201d8 100644
@@ -2595,6 +2595,8 @@ static inline int kmem_cache_close(struct kmem_cache *s)
Quoted 12 lines
Quoted 8 lines
mm/slub.c +2 -0
  */
 void kmem_cache_destroy(struct kmem_cache *s)
 {
+	if (s->flags & SLAB_DESTROY_BY_RCU)
+		rcu_barrier();
 	down_write(&slub_lock);
 	s->refcount--;
 	if (!s->refcount) {
Signature · 1 line
http://selenic.com : development and support for Mercurial and Linux

--
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>

#5 lore raw
Quoted 8 lines · Nick Piggin
Quoted 7 lines · Matt Mackall
Quoted 6 lines · Paul E. McKenney

Hello!

Jesper noted that kmem_cache_destroy() invokes synchronize_rcu() rather than rcu_barrier() in the SLAB_DESTROY_BY_RCU case, which could result in RCU callbacks accessing a kmem_cache after it had been destroyed.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

The following untested (might not even compile) patch proposes a fix.

Nick, you'll want to make sure you get this in SLQB.

Thanks Matt. Paul, I think this should be appropriate for [email protected] too?

Yup, I added cc to the patch. Thanks!

Pekka

--
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>

#6 lore raw
In reply to Paul E. McKenney
Quoted 5 lines · Paul E. McKenney

Jesper noted that kmem_cache_destroy() invokes synchronize_rcu() rather than rcu_barrier() in the SLAB_DESTROY_BY_RCU case, which could result in RCU callbacks accessing a kmem_cache after it had been destroyed.

The following untested (might not even compile) patch proposes a fix.

It could be seen to be the responsibility of the caller of kmem_cache_destroy to insure that no accesses are pending.

If the caller specified destroy by rcu on cache creation then he also needs to be aware of not destroying the cache itself until all rcu actions are complete. This is similar to the caution that has to be execised then accessing cache data itself.

--
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>

#7 lore raw
Quoted 8 lines · Christoph Lameter
Quoted 5 lines · Paul E. McKenney

Jesper noted that kmem_cache_destroy() invokes synchronize_rcu() rather than rcu_barrier() in the SLAB_DESTROY_BY_RCU case, which could result in RCU callbacks accessing a kmem_cache after it had been destroyed.

The following untested (might not even compile) patch proposes a fix.

Quoted 7 lines

It could be seen to be the responsibility of the caller of kmem_cache_destroy to insure that no accesses are pending.

If the caller specified destroy by rcu on cache creation then he also needs to be aware of not destroying the cache itself until all rcu actions are complete. This is similar to the caution that has to be execised then accessing cache data itself.

This is a reasonable point, and in keeping with the design principle 'callers should handle their own special cases'. However, I think it would be more than a little surprising for kmem_cache_free() to do the right thing, but not kmem_cache_destroy().

Signature · 8 lines
http://selenic.com : development and support for Mercurial and Linux


--
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>
#8 lore raw
Quoted 4 lines · Matt Mackall

This is a reasonable point, and in keeping with the design principle 'callers should handle their own special cases'. However, I think it would be more than a little surprising for kmem_cache_free() to do the right thing, but not kmem_cache_destroy().

kmem_cache_free() must be used carefully when using SLAB_DESTROY_BY_RCU. The freed object can be accessed after free until the rcu interval expires (well sortof, it may even be reallocated within the interval).

There are special RCU considerations coming already with the use of kmem_cache_free().

Adding RCU operations to the kmem_cache_destroy() logic may result in unnecessary RCU actions for slabs where the coder is ensuring that the RCU interval has passed by other means.

--
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>

#9 lore raw
Quoted 11 lines · Christoph Lameter
Quoted 4 lines · Matt Mackall

This is a reasonable point, and in keeping with the design principle 'callers should handle their own special cases'. However, I think it would be more than a little surprising for kmem_cache_free() to do the right thing, but not kmem_cache_destroy().

kmem_cache_free() must be used carefully when using SLAB_DESTROY_BY_RCU. The freed object can be accessed after free until the rcu interval expires (well sortof, it may even be reallocated within the interval).

Quoted 6 lines

There are special RCU considerations coming already with the use of kmem_cache_free().

Adding RCU operations to the kmem_cache_destroy() logic may result in unnecessary RCU actions for slabs where the coder is ensuring that the RCU interval has passed by other means.

Do we care? Cache destruction shouldn't be in anyone's fast path. Correctness is more important and users are more liable to be correct with this patch.

Signature · 8 lines
http://selenic.com : development and support for Mercurial and Linux


--
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>
#10 lore raw
Quoted 15 lines · Matt Mackall
Quoted 14 lines · Christoph Lameter
Quoted 4 lines · Matt Mackall

This is a reasonable point, and in keeping with the design principle 'callers should handle their own special cases'. However, I think it would be more than a little surprising for kmem_cache_free() to do the right thing, but not kmem_cache_destroy().

kmem_cache_free() must be used carefully when using SLAB_DESTROY_BY_RCU. The freed object can be accessed after free until the rcu interval expires (well sortof, it may even be reallocated within the interval).

There are special RCU considerations coming already with the use of kmem_cache_free().

Quoted 7 lines
Quoted 3 lines

Adding RCU operations to the kmem_cache_destroy() logic may result in unnecessary RCU actions for slabs where the coder is ensuring that the RCU interval has passed by other means.

Do we care? Cache destruction shouldn't be in anyone's fast path. Correctness is more important and users are more liable to be correct with this patch.

I am with Matt on this one -- if we are going to hand the users of SLAB_DESTROY_BY_RCU a hand grenade, let's at least leave the pin in.

Thanx, Paul

--
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>

#11 lore raw
Quoted 20 lines · Paul E. McKenney
Quoted 19 lines · Matt Mackall
Quoted 17 lines · Christoph Lameter
Quoted 4 lines · Matt Mackall

This is a reasonable point, and in keeping with the design principle 'callers should handle their own special cases'. However, I think it would be more than a little surprising for kmem_cache_free() to do the right thing, but not kmem_cache_destroy().

kmem_cache_free() must be used carefully when using SLAB_DESTROY_BY_RCU. The freed object can be accessed after free until the rcu interval expires (well sortof, it may even be reallocated within the interval).

There are special RCU considerations coming already with the use of kmem_cache_free().

Adding RCU operations to the kmem_cache_destroy() logic may result in unnecessary RCU actions for slabs where the coder is ensuring that the RCU interval has passed by other means.

Quoted 6 lines
Quoted 3 lines

Do we care? Cache destruction shouldn't be in anyone's fast path. Correctness is more important and users are more liable to be correct with this patch.

I am with Matt on this one -- if we are going to hand the users of SLAB_DESTROY_BY_RCU a hand grenade, let's at least leave the pin in.

I don't even claim to understand all the RCU details here but I don't see why we should care about _kmem_cache_destroy()_ performance at this level. Christoph, hmmm?

Pekka

--
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>

#12 lore raw
Quoted 3 lines · Pekka Enberg

I don't even claim to understand all the RCU details here but I don't see why we should care about _kmem_cache_destroy()_ performance at this level. Christoph, hmmm?

Well it was surprising to me that kmem_cache_destroy() would perform rcu actions in the first place. RCU is usually handled externally and not within the slab allocator. The only reason that SLAB_DESTROY_BY_RCU exists is because the user cannot otherwise control the final release of memory to the page allocator.

--
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>

#13 lore raw

Hi Christoph,

Quoted 3 lines · Pekka Enberg
Quoted 3 lines

I don't even claim to understand all the RCU details here but I don't see why we should care about _kmem_cache_destroy()_ performance at this level. Christoph, hmmm?

Quoted 5 lines · Christoph Lameter

Well it was surprising to me that kmem_cache_destroy() would perform rcu actions in the first place. RCU is usually handled externally and not within the slab allocator. The only reason that SLAB_DESTROY_BY_RCU exists is because the user cannot otherwise control the final release of memory to the page allocator.

Right. A quick grep for git logs reveals that it's been like that in mm/slab.c at least since 2.6.12-rc2 so I think we should consider it as part of the slab API and Paul's patch is an obvious bugfix to it.

Pekka

--
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>