Matt Mackall wrote:
On Wed, May 09, 2007 at 12:02:29PM +1000, Nick Piggin wrote:
BTW, we _really_ should be doing RCU properly in slob, because you
technically can't noop RCU on UP (even though the current users may be
safe...).
Thanks. Hugh was pretty convinced it was unneeded:
http://marc.info/?l=linux-mm&m=116413907023393&w=2
And since I didn't care much about the SMP case, I didn't pursue it.
Sure the anonvma cache is OK on UP, but I'm just saying that in the
general case, you cannot noop RCU on UP systems.
SLAB_DESTROY_BY_RCU is quite a nice way to mitigate some RCU freeing
overheads for small objects, so I'd expect it may see wider use in
future. Maybe all those users would be fine too, but it's a bit nasty
to have already tricky RCU semantics deviate...
This almost looks reasonable. I think HW_ALIGN | RCU is going to make
it break though:
+ if (unlikely(c->flags & SLAB_DESTROY_BY_RCU))
+ b += sizeof(struct slob_rcu);
+
That could be dealt with by putting the slob_rcu at the end of the
object and having the RCU helper function use ->size to work backward
to the actual pointer.
Sure, OK.
void kmem_cache_free(struct kmem_cache *c, void *b)
{
if (c->dtor)
c->dtor(b, c, 0);
I think if we want RCU to actually work, we want to run ->dtor in
__kmem_cache_free?
Yeah, thinko... thanks.
- if (c->size < PAGE_SIZE)
- slob_free(b, c->size);
- else
- free_pages((unsigned long)b, find_order(c->size));
+ if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) {
+ struct slob_rcu *slob_rcu;
+ b -= sizeof(struct slob_rcu);
+ slob_rcu = b;
+ slob_rcu->size = c->size;
Which means just store c in the header^Wfooter, then we can retrieve the size
and the dtor in the RCU helper.
OK, updated patch (about-to-be-tested) attached.
--
SUSE Labs, Novell Inc.
Index: linux-2.6/mm/slob.c
===================================================================
--- linux-2.6.orig/mm/slob.c 2007-04-12 14:35:11.000000000 +1000
+++ linux-2.6/mm/slob.c 2007-05-09 11:01:09.000000000 +1000
@@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
+#include <linux/rcupdate.h>
struct slob_block {
int units;
@@ -53,6 +54,11 @@
};
typedef struct bigblock bigblock_t;
+struct slob_rcu {
+ struct rcu_head rcu_head;
+ struct kmem_cache *c;
+};
+
static slob_t arena = { .next = &arena, .units = 1 };
static slob_t *slobfree = &arena;
static bigblock_t *bigblocks;
@@ -242,6 +248,7 @@
struct kmem_cache {
unsigned int size, align;
+ unsigned long flags;
const char *name;
void (*ctor)(void *, struct kmem_cache *, unsigned long);
void (*dtor)(void *, struct kmem_cache *, unsigned long);
@@ -259,6 +266,11 @@
if (c) {
c->name = name;
c->size = size;
+ if (flags & SLAB_DESTROY_BY_RCU) {
+ /* leave room for rcu footer at the end of object */
+ c->size += sizeof(struct slob_rcu);
+ }
+ c->flags = flags;
c->ctor = ctor;
c->dtor = dtor;
/* ignore alignment unless it's forced */
@@ -281,9 +293,9 @@
{
void *b;
- if (c->size < PAGE_SIZE)
+ if (c->size < PAGE_SIZE) {
b = slob_alloc(c->size, flags, c->align);
- else
+ } else
b = (void *)__get_free_pages(flags, find_order(c->size));
if (c->ctor)
@@ -303,7 +315,7 @@
}
EXPORT_SYMBOL(kmem_cache_zalloc);
-void kmem_cache_free(struct kmem_cache *c, void *b)
+static void __kmem_cache_free(struct kmem_cache *c, void *b)
{
if (c->dtor)
c->dtor(b, c, 0);
@@ -313,6 +325,25 @@
else
free_pages((unsigned long)b, find_order(c->size));
}
+
+static void kmem_rcu_free(struct rcu_head *head)
+{
+ struct slob_rcu *slob_rcu = (struct slob_rcu *)head;
+ void *b = (void *)slob_rcu - slob_rcu->c->size;
+
+ __kmem_cache_free(b, slob_rcu->c);
+}
+
+void kmem_cache_free(struct kmem_cache *c, void *b)
+{
+ if (unlikely(c->flags & SLAB_DESTROY_BY_RCU)) {
+ struct slob_rcu *slob_rcu;
+ slob_rcu = b + c->size;;
+ slob_rcu->c = c;
+ call_rcu(&slob_rcu->rcu_head, kmem_rcu_free);
+ } else
+ __kmem_cache_free(b, c);
+}
EXPORT_SYMBOL(kmem_cache_free);
unsigned int kmem_cache_size(struct kmem_cache *c)
Index: linux-2.6/init/Kconfig
===================================================================
--- linux-2.6.orig/init/Kconfig 2007-04-12 14:35:11.000000000 +1000
+++ linux-2.6/init/Kconfig 2007-05-09 09:11:14.000000000 +1000
@@ -476,7 +476,7 @@
config SLAB
default y
- bool "Use full SLAB allocator" if (EMBEDDED && !SMP && !SPARSEMEM)
+ bool "Use full SLAB allocator" if (EMBEDDED && !SPARSEMEM)
help
Disabling this replaces the advanced SLAB allocator and
kmalloc support with the drastically simpler SLOB allocator.
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]