Skip to contentSkip to conversation

slub: add missing kmem cgroup support to kmem_cache_free_bulk

PATCH In review Jesper Dangaard Brouer 3 participants 4 messages Oct 29, 2015 – Nov 5, 2015

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

PATCH 1/1 slub: add missing kmem cgroup support to kmem_cache_free_bulk

Initial implementation missed support for kmem cgroup support in kmem_cache_free_bulk() call, add this.

If CONFIG_MEMCG_KMEM is not enabled, the compiler should be smart enough to not add any asm code.

---
 mm/slub.c |    3 +++
 1 file changed, 3 insertions(+)
mm/slub.c +3 -0
index 9be12ffae9fc..9875864ad7b8 100644
@@ -2845,6 +2845,9 @@ static int build_detached_freelist(struct kmem_cache *s, size_t size,
 	if (!object)
 		return 0;
 
+	/* Support for kmemcg */
+	s = cache_from_obj(s, object);
+
 	/* Start new detached freelist */
 	set_freepointer(s, object, NULL);
 	df->page = virt_to_head_page(object);

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

#1 lore raw
Quoted 16 lines · Jesper Dangaard Brouer

Initial implementation missed support for kmem cgroup support in kmem_cache_free_bulk() call, add this.

If CONFIG_MEMCG_KMEM is not enabled, the compiler should be smart enough to not add any asm code.

---
 mm/slub.c |    3 +++
 1 file changed, 3 insertions(+)
mm/slub.c +0 -0
index 9be12ffae9fc..9875864ad7b8 100644

mm/slub.c static int build_detached_freelist(struct kmem_cache *s, size_t size, · line 2853

Quoted 9 lines
mm/slub.c +3 -0
@@ -2845,6 +2845,9 @@ static int build_detached_freelist(struct kmem_cache *s, size_t size,
 	if (!object)
 		return 0;
 
+	/* Support for kmemcg */
+	s = cache_from_obj(s, object);
+
 	/* Start new detached freelist */
 	set_freepointer(s, object, NULL);
 	df->page = virt_to_head_page(object);

Hello,

It'd better to add this 's = cache_from_obj()' on kmem_cache_free_bulk(). Not only build_detached_freelist() but also slab_free() need proper cache.

Thanks

--
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 29 lines · Joonsoo Kim
Quoted 16 lines · Jesper Dangaard Brouer

Initial implementation missed support for kmem cgroup support in kmem_cache_free_bulk() call, add this.

If CONFIG_MEMCG_KMEM is not enabled, the compiler should be smart enough to not add any asm code.

---
 mm/slub.c |    3 +++
 1 file changed, 3 insertions(+)
mm/slub.c +0 -0
index 9be12ffae9fc..9875864ad7b8 100644

mm/slub.c static int build_detached_freelist(struct kmem_cache *s, size_t size, · line 2853

Quoted 9 lines
mm/slub.c +3 -0
@@ -2845,6 +2845,9 @@ static int build_detached_freelist(struct kmem_cache *s, size_t size,
 	if (!object)
 		return 0;
 
+	/* Support for kmemcg */
+	s = cache_from_obj(s, object);
+
 	/* Start new detached freelist */
 	set_freepointer(s, object, NULL);
 	df->page = virt_to_head_page(object);

Hello,

Quoted 3 lines

It'd better to add this 's = cache_from_obj()' on kmem_cache_free_bulk(). Not only build_detached_freelist() but also slab_free() need proper cache.

Yeah, Joonsoo is right. Besides, there's a bug in kmem_cache_alloc_bulk:

Quoted 26 lines

/* Note that interrupts must be enabled when calling this function. */ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,

			   void **p)
{
	struct kmem_cache_cpu *c;
	int i;

	/*
	 * Drain objects in the per cpu slab, while disabling local
	 * IRQs, which protects against PREEMPT and interrupts
	 * handlers invoking normal fastpath.
	 */
	local_irq_disable();
	c = this_cpu_ptr(s->cpu_slab);

	for (i = 0; i < size; i++) {
		void *object = c->freelist;

		if (unlikely(!object)) {
			/*
			 * Invoking slow path likely have side-effect
			 * of re-populating per CPU c->freelist
			 */
			p[i] = ___slab_alloc(s, flags, NUMA_NO_NODE,
					    _RET_IP_, c);
			if (unlikely(!p[i]))
Quoted 8 lines
				goto error;

			c = this_cpu_ptr(s->cpu_slab);
			continue; /* goto for-loop */
		}

		/* kmem_cache debug support */
		s = slab_pre_alloc_hook(s, flags);

slab_pre_alloc_hook expects a global cache and returns per memcg one, so calling this function from inside a kmemcg will result in hitting the VM_BUG_ON in __memcg_kmem_get_cache, not saying about mis-accounting of __slab_alloc.

memcg_kmem_get_cache should be called once, in the very beginning of kmem_cache_alloc_bulk, and it should be matched by memcg_kmem_put_cache when we are done.

Thanks,
Vladimir

Quoted 22 lines
		if (unlikely(!s))
			goto error;

		c->freelist = get_freepointer(s, object);
		p[i] = object;

		/* kmem_cache debug support */
		slab_post_alloc_hook(s, flags, object);
	}
	c->tid = next_tid(c->tid);
	local_irq_enable();

	/* Clear memory outside IRQ disabled fastpath loop */
	if (unlikely(flags & __GFP_ZERO)) {
		int j;

		for (j = 0; j < i; j++)
			memset(p[j], 0, s->object_size);
	}

	return true;
Quoted 5 lines

error:

	__kmem_cache_free_bulk(s, i, p);
	local_irq_enable();
	return false;
}

--
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 30 lines · On Thu, 5 Nov 2015 11:38:43 +0300 Vladimir Davydov <[email protected]>…
Quoted 29 lines · Joonsoo Kim
Quoted 16 lines · Jesper Dangaard Brouer

Initial implementation missed support for kmem cgroup support in kmem_cache_free_bulk() call, add this.

If CONFIG_MEMCG_KMEM is not enabled, the compiler should be smart enough to not add any asm code.

---
 mm/slub.c |    3 +++
 1 file changed, 3 insertions(+)
mm/slub.c +0 -0
index 9be12ffae9fc..9875864ad7b8 100644

mm/slub.c static int build_detached_freelist(struct kmem_cache *s, size_t size, · line 2853

Quoted 9 lines
mm/slub.c +3 -0
@@ -2845,6 +2845,9 @@ static int build_detached_freelist(struct kmem_cache *s, size_t size,
 	if (!object)
 		return 0;
 
+	/* Support for kmemcg */
+	s = cache_from_obj(s, object);
+
 	/* Start new detached freelist */
 	set_freepointer(s, object, NULL);
 	df->page = virt_to_head_page(object);

Hello,

Quoted 5 lines
Quoted 3 lines

It'd better to add this 's = cache_from_obj()' on kmem_cache_free_bulk(). Not only build_detached_freelist() but also slab_free() need proper cache.

Yeah, Joonsoo is right.

But cache_from_obj() takes an object as input and in kmem_cache_free_bulk() that object is not directly available... Could send "s" as a reference (to build_detached_freelist) to allow re-assignment of "s" so slab_free() gets the correct "s". But it will not look pretty...

Else we can get the object via: p[size -1] which also look a little funny... but it might not be correct in-case NULL pointers in the input p-array.

Quoted 1 line

Besides, there's a bug in kmem_cache_alloc_bulk:

Thanks for spotting this!!!

Quoted 35 lines
Quoted 26 lines

/* Note that interrupts must be enabled when calling this function. */ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,

			   void **p)
{
	struct kmem_cache_cpu *c;
	int i;

	/*
	 * Drain objects in the per cpu slab, while disabling local
	 * IRQs, which protects against PREEMPT and interrupts
	 * handlers invoking normal fastpath.
	 */
	local_irq_disable();
	c = this_cpu_ptr(s->cpu_slab);

	for (i = 0; i < size; i++) {
		void *object = c->freelist;

		if (unlikely(!object)) {
			/*
			 * Invoking slow path likely have side-effect
			 * of re-populating per CPU c->freelist
			 */
			p[i] = ___slab_alloc(s, flags, NUMA_NO_NODE,
					    _RET_IP_, c);
			if (unlikely(!p[i]))
Quoted 8 lines
				goto error;

			c = this_cpu_ptr(s->cpu_slab);
			continue; /* goto for-loop */
		}

		/* kmem_cache debug support */
		s = slab_pre_alloc_hook(s, flags);
Quoted 8 lines

slab_pre_alloc_hook expects a global cache and returns per memcg one, so calling this function from inside a kmemcg will result in hitting the VM_BUG_ON in __memcg_kmem_get_cache, not saying about mis-accounting of __slab_alloc.

memcg_kmem_get_cache should be called once, in the very beginning of kmem_cache_alloc_bulk, and it should be matched by memcg_kmem_put_cache when we are done.

To solve this correctly it looks like I need to pull out memcg_kmem_put_cache(s) call in the slab_post_alloc_hook() call.

Quoted 28 lines
Quoted 28 lines
		if (unlikely(!s))
			goto error;

		c->freelist = get_freepointer(s, object);
		p[i] = object;

		/* kmem_cache debug support */
		slab_post_alloc_hook(s, flags, object);
	}
	c->tid = next_tid(c->tid);
	local_irq_enable();

	/* Clear memory outside IRQ disabled fastpath loop */
	if (unlikely(flags & __GFP_ZERO)) {
		int j;

		for (j = 0; j < i; j++)
			memset(p[j], 0, s->object_size);
	}

	return true;

error:

	__kmem_cache_free_bulk(s, i, p);
	local_irq_enable();
	return false;
}
Signature · 11 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  Author of http://www.iptv-analyzer.org
  LinkedIn: http://www.linkedin.com/in/brouer

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