* [RFC/PATCH 1/2] slub: Break out alloc_kmem_cache_cpus() from kmem_cache_open()
@ 2011-04-25 17:46 Pekka Enberg
2011-04-25 17:46 ` [RFC/PATCH 2/2] slub: Don't share struct kmem_cache for shared caches Pekka Enberg
2011-04-25 19:06 ` [RFC/PATCH 1/2] slub: Break out alloc_kmem_cache_cpus() from kmem_cache_open() Christoph Lameter
0 siblings, 2 replies; 6+ messages in thread
From: Pekka Enberg @ 2011-04-25 17:46 UTC (permalink / raw)
To: linux-kernel
Cc: Pekka Enberg, Christoph Lameter, David Rientjes, Linus Torvalds
In preparation for sharing per-CPU structures between merged caches, break out
alloc_kmem_cache_cpus() from kmem_cache_open() function.
Cc: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
---
mm/slub.c | 37 +++++++++++++++++++++----------------
1 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/mm/slub.c b/mm/slub.c
index 94d2a33..cb61024 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2638,11 +2638,7 @@ static int kmem_cache_open(struct kmem_cache *s,
#endif
if (!init_kmem_cache_nodes(s))
goto error;
-
- if (alloc_kmem_cache_cpus(s))
- return 1;
-
- free_kmem_cache_nodes(s);
+ return 1;
error:
if (flags & SLAB_PANIC)
panic("Cannot create slab %s size=%lu realsize=%u "
@@ -2818,6 +2814,9 @@ static struct kmem_cache *__init create_kmalloc_cache(const char *name,
flags, NULL))
goto panic;
+ if (!alloc_kmem_cache_cpus(s))
+ goto panic;
+
list_add(&s->list, &slab_caches);
return s;
@@ -3239,6 +3238,8 @@ void __init kmem_cache_init(void)
sizeof(struct kmem_cache_node),
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+ alloc_kmem_cache_cpus(kmem_cache_node);
+
hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
/* Able to allocate the per node structures */
@@ -3247,6 +3248,8 @@ void __init kmem_cache_init(void)
temp_kmem_cache = kmem_cache;
kmem_cache_open(kmem_cache, "kmem_cache", kmem_size,
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+ alloc_kmem_cache_cpus(kmem_cache);
+
kmem_cache = kmem_cache_alloc(kmem_cache, GFP_NOWAIT);
memcpy(kmem_cache, temp_kmem_cache, kmem_size);
@@ -3469,18 +3472,20 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
s = kmalloc(kmem_size, GFP_KERNEL);
if (s) {
- if (kmem_cache_open(s, n,
- size, align, flags, ctor)) {
- list_add(&s->list, &slab_caches);
- if (sysfs_slab_add(s)) {
- list_del(&s->list);
- kfree(n);
- kfree(s);
- goto err;
- }
- up_write(&slub_lock);
- return s;
+ if (!kmem_cache_open(s, n, size, align, flags, ctor))
+ goto err_free;
+
+ if (!alloc_kmem_cache_cpus(s))
+ goto err_free;
+
+ list_add(&s->list, &slab_caches);
+ if (sysfs_slab_add(s)) {
+ list_del(&s->list);
+ goto err_free;
}
+ up_write(&slub_lock);
+ return s;
+err_free:
kfree(n);
kfree(s);
}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC/PATCH 2/2] slub: Don't share struct kmem_cache for shared caches
2011-04-25 17:46 [RFC/PATCH 1/2] slub: Break out alloc_kmem_cache_cpus() from kmem_cache_open() Pekka Enberg
@ 2011-04-25 17:46 ` Pekka Enberg
2011-04-25 19:09 ` Christoph Lameter
2011-04-25 19:06 ` [RFC/PATCH 1/2] slub: Break out alloc_kmem_cache_cpus() from kmem_cache_open() Christoph Lameter
1 sibling, 1 reply; 6+ messages in thread
From: Pekka Enberg @ 2011-04-25 17:46 UTC (permalink / raw)
To: linux-kernel
Cc: Pekka Enberg, Christoph Lameter, David Rientjes, Linus Torvalds
This patch changes the slab cache sharing in SLUB to only share 'struct
kmem_cpu_cache' which contains the actual list of slabs and object freelists.
We no longer share 'struct kmem_cache' between merged caches so /proc/slabinfo
statistics work as expected:
Before:
# cat /proc/slabinfo | wc -l
104
After:
# cat /proc/slabinfo | wc -l
185
Cc: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
---
mm/slub.c | 98 +++++++++++++++++++-----------------------------------------
1 files changed, 31 insertions(+), 67 deletions(-)
diff --git a/mm/slub.c b/mm/slub.c
index cb61024..3a8fbca 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2349,6 +2349,11 @@ init_kmem_cache_node(struct kmem_cache_node *n, struct kmem_cache *s)
#endif
}
+static inline void dup_kmem_cache_cpus(struct kmem_cache *src, struct kmem_cache *dst)
+{
+ dst->cpu_slab = src->cpu_slab;
+}
+
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
{
BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
@@ -3441,26 +3446,41 @@ static struct kmem_cache *find_mergeable(size_t size,
struct kmem_cache *kmem_cache_create(const char *name, size_t size,
size_t align, unsigned long flags, void (*ctor)(void *))
{
- struct kmem_cache *s;
+ struct kmem_cache *s, *parent;
char *n;
if (WARN_ON(!name))
return NULL;
down_write(&slub_lock);
- s = find_mergeable(size, align, flags, name, ctor);
- if (s) {
- s->refcount++;
+ parent = find_mergeable(size, align, flags, name, ctor);
+ if (parent) {
+ n = kstrdup(name, GFP_KERNEL);
+ if (!n)
+ goto err;
+
+ s = kmalloc(kmem_size, GFP_KERNEL);
+ if (!s)
+ goto err_free;
+
+ if (!kmem_cache_open(s, n, size, align, flags, ctor))
+ goto err_free;
+
+ dup_kmem_cache_cpus(parent, s);
+
+ parent->refcount++;
/*
* Adjust the object sizes so that we clear
* the complete object on kzalloc.
*/
- s->objsize = max(s->objsize, (int)size);
- s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
+ parent->objsize = max(parent->objsize, (int)size);
+ parent->inuse = max_t(int, parent->inuse, ALIGN(size, sizeof(void *)));
- if (sysfs_slab_alias(s, name)) {
- s->refcount--;
- goto err;
+ list_add(&s->list, &slab_caches);
+ if (sysfs_slab_add(s)) {
+ parent->refcount--;
+ list_del(&s->list);
+ goto err_free;
}
up_write(&slub_lock);
return s;
@@ -4670,68 +4690,17 @@ static const struct kset_uevent_ops slab_uevent_ops = {
static struct kset *slab_kset;
-#define ID_STR_LENGTH 64
-
-/* Create a unique string id for a slab cache:
- *
- * Format :[flags-]size
- */
-static char *create_unique_id(struct kmem_cache *s)
-{
- char *name = kmalloc(ID_STR_LENGTH, GFP_KERNEL);
- char *p = name;
-
- BUG_ON(!name);
-
- *p++ = ':';
- /*
- * First flags affecting slabcache operations. We will only
- * get here for aliasable slabs so we do not need to support
- * too many flags. The flags here must cover all flags that
- * are matched during merging to guarantee that the id is
- * unique.
- */
- if (s->flags & SLAB_CACHE_DMA)
- *p++ = 'd';
- if (s->flags & SLAB_RECLAIM_ACCOUNT)
- *p++ = 'a';
- if (s->flags & SLAB_DEBUG_FREE)
- *p++ = 'F';
- if (!(s->flags & SLAB_NOTRACK))
- *p++ = 't';
- if (p != name + 1)
- *p++ = '-';
- p += sprintf(p, "%07d", s->size);
- BUG_ON(p > name + ID_STR_LENGTH - 1);
- return name;
-}
-
static int sysfs_slab_add(struct kmem_cache *s)
{
int err;
const char *name;
- int unmergeable;
if (slab_state < SYSFS)
/* Defer until later */
return 0;
- unmergeable = slab_unmergeable(s);
- if (unmergeable) {
- /*
- * Slabcache can never be merged so we can use the name proper.
- * This is typically the case for debug situations. In that
- * case we can catch duplicate names easily.
- */
- sysfs_remove_link(&slab_kset->kobj, s->name);
- name = s->name;
- } else {
- /*
- * Create a unique name for the slab as a target
- * for the symlinks.
- */
- name = create_unique_id(s);
- }
+ sysfs_remove_link(&slab_kset->kobj, s->name);
+ name = s->name;
s->kobj.kset = slab_kset;
err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, name);
@@ -4747,11 +4716,6 @@ static int sysfs_slab_add(struct kmem_cache *s)
return err;
}
kobject_uevent(&s->kobj, KOBJ_ADD);
- if (!unmergeable) {
- /* Setup first alias */
- sysfs_slab_alias(s, s->name);
- kfree(name);
- }
return 0;
}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 1/2] slub: Break out alloc_kmem_cache_cpus() from kmem_cache_open()
2011-04-25 17:46 [RFC/PATCH 1/2] slub: Break out alloc_kmem_cache_cpus() from kmem_cache_open() Pekka Enberg
2011-04-25 17:46 ` [RFC/PATCH 2/2] slub: Don't share struct kmem_cache for shared caches Pekka Enberg
@ 2011-04-25 19:06 ` Christoph Lameter
1 sibling, 0 replies; 6+ messages in thread
From: Christoph Lameter @ 2011-04-25 19:06 UTC (permalink / raw)
To: Pekka Enberg; +Cc: linux-kernel, David Rientjes, Linus Torvalds
On Mon, 25 Apr 2011, Pekka Enberg wrote:
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -2638,11 +2638,7 @@ static int kmem_cache_open(struct kmem_cache *s,
> #endif
> if (!init_kmem_cache_nodes(s))
> goto error;
> -
> - if (alloc_kmem_cache_cpus(s))
> - return 1;
> -
> - free_kmem_cache_nodes(s);
free_kmem_cache_nodes() shows up nowhere now. Memory leak?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 2/2] slub: Don't share struct kmem_cache for shared caches
2011-04-25 17:46 ` [RFC/PATCH 2/2] slub: Don't share struct kmem_cache for shared caches Pekka Enberg
@ 2011-04-25 19:09 ` Christoph Lameter
2011-04-25 19:25 ` Pekka Enberg
0 siblings, 1 reply; 6+ messages in thread
From: Christoph Lameter @ 2011-04-25 19:09 UTC (permalink / raw)
To: Pekka Enberg; +Cc: linux-kernel, David Rientjes, Linus Torvalds
On Mon, 25 Apr 2011, Pekka Enberg wrote:
> This patch changes the slab cache sharing in SLUB to only share 'struct
> kmem_cpu_cache' which contains the actual list of slabs and object freelists.
> We no longer share 'struct kmem_cache' between merged caches so /proc/slabinfo
> statistics work as expected:
I am a bit confused. Struct kmem_cache contains per slab
allocation information and all pages have pointers to struct kmem_cache.
So we have pages now on the kmem_cache_cpu list with varying kmem_cache
pointers? How do we figure out which cache a page belongs to? It seems
that a page from one cache can be freed to the freelists of another.
Does this even run right with the debugging enabled?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 2/2] slub: Don't share struct kmem_cache for shared caches
2011-04-25 19:09 ` Christoph Lameter
@ 2011-04-25 19:25 ` Pekka Enberg
2011-04-25 21:08 ` Christoph Lameter
0 siblings, 1 reply; 6+ messages in thread
From: Pekka Enberg @ 2011-04-25 19:25 UTC (permalink / raw)
To: Christoph Lameter; +Cc: linux-kernel, David Rientjes, Linus Torvalds
On Mon, 25 Apr 2011, Pekka Enberg wrote:
>> This patch changes the slab cache sharing in SLUB to only share 'struct
>> kmem_cpu_cache' which contains the actual list of slabs and object freelists.
>> We no longer share 'struct kmem_cache' between merged caches so /proc/slabinfo
>> statistics work as expected:
On Mon, Apr 25, 2011 at 10:09 PM, Christoph Lameter <cl@linux.com> wrote:
> I am a bit confused. Struct kmem_cache contains per slab
> allocation information and all pages have pointers to struct kmem_cache.
>
> So we have pages now on the kmem_cache_cpu list with varying kmem_cache
> pointers? How do we figure out which cache a page belongs to? It seems
> that a page from one cache can be freed to the freelists of another.
We share the freelist so it goes to the same freelist. However, I
completely forgot about page to struct kmem_cache mapping so stats
won't work properly.
On Mon, Apr 25, 2011 at 10:09 PM, Christoph Lameter <cl@linux.com> wrote:
> Does this even run right with the debugging enabled?
It boots OK to minimal userspace under KVM with slub_debug. But no, I
didn't test it properly yet.
Pekka
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC/PATCH 2/2] slub: Don't share struct kmem_cache for shared caches
2011-04-25 19:25 ` Pekka Enberg
@ 2011-04-25 21:08 ` Christoph Lameter
0 siblings, 0 replies; 6+ messages in thread
From: Christoph Lameter @ 2011-04-25 21:08 UTC (permalink / raw)
To: Pekka Enberg; +Cc: linux-kernel, David Rientjes, Linus Torvalds
On Mon, 25 Apr 2011, Pekka Enberg wrote:
> On Mon, 25 Apr 2011, Pekka Enberg wrote:
> >> This patch changes the slab cache sharing in SLUB to only share 'struct
> >> kmem_cpu_cache' which contains the actual list of slabs and object freelists.
> >> We no longer share 'struct kmem_cache' between merged caches so /proc/slabinfo
> >> statistics work as expected:
>
> On Mon, Apr 25, 2011 at 10:09 PM, Christoph Lameter <cl@linux.com> wrote:
> > I am a bit confused. Struct kmem_cache contains per slab
> > allocation information and all pages have pointers to struct kmem_cache.
> >
> > So we have pages now on the kmem_cache_cpu list with varying kmem_cache
> > pointers? How do we figure out which cache a page belongs to? It seems
> > that a page from one cache can be freed to the freelists of another.
>
> We share the freelist so it goes to the same freelist. However, I
> completely forgot about page to struct kmem_cache mapping so stats
> won't work properly.
How are the freelist shared? You would need to share kmem_cache_node too
to make this work but then you dont have counters per slab anymore.
The counters are in kmem_cache_cpu and kmem_cache_node. So why a
kmem_cache structure for separate stats?
> On Mon, Apr 25, 2011 at 10:09 PM, Christoph Lameter <cl@linux.com> wrote:
> > Does this even run right with the debugging enabled?
>
> It boots OK to minimal userspace under KVM with slub_debug. But no, I
> didn't test it properly yet.
Run a validation of all objects please. That should check the slab headers
for correct pointers back.
Also by having multiple kmem_cache * for a single kmem_cache_cpu/node
structure you end up with an elevated cacheline footprint.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-04-25 21:08 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-04-25 17:46 [RFC/PATCH 1/2] slub: Break out alloc_kmem_cache_cpus() from kmem_cache_open() Pekka Enberg
2011-04-25 17:46 ` [RFC/PATCH 2/2] slub: Don't share struct kmem_cache for shared caches Pekka Enberg
2011-04-25 19:09 ` Christoph Lameter
2011-04-25 19:25 ` Pekka Enberg
2011-04-25 21:08 ` Christoph Lameter
2011-04-25 19:06 ` [RFC/PATCH 1/2] slub: Break out alloc_kmem_cache_cpus() from kmem_cache_open() Christoph Lameter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox