[Devel] [PATCH rh7 4/5] slab: ignore memcg limits during marked SLAB allocations

Konstantin Khorenko khorenko at virtuozzo.com
Fri Sep 6 20:34:09 MSK 2024


Pretend marked SLABs are always allocated by a PF_MEMALLOC process to
bypass memory cgroup limits.

Added per-SLAB "pf_memalloc" attribute to disable/enable the logic on
the fly.

https://virtuozzo.atlassian.net/browse/PSBM-155867

Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 include/linux/slab.h |  1 +
 mm/slub.c            | 59 ++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/include/linux/slab.h b/include/linux/slab.h
index 8722dc8864be..263f10a436f6 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -24,6 +24,7 @@
 #define SLAB_CONSISTENCY_CHECKS	0x00000100UL	/* DEBUG: Perform (expensive) checks on alloc/free */
 #define SLAB_RED_ZONE		0x00000400UL	/* DEBUG: Red zone objs in a cache */
 #define SLAB_POISON		0x00000800UL	/* DEBUG: Poison objects */
+#define SLAB_PF_MEMALLOC	0x00001000UL	/* DEBUG: Ignore memcg limits */
 #define SLAB_HWCACHE_ALIGN	0x00002000UL	/* Align objs on cache lines */
 #define SLAB_CACHE_DMA		0x00004000UL	/* Use GFP_DMA memory */
 #define SLAB_STORE_USER		0x00010000UL	/* DEBUG: Store the last owner for bug hunting */
diff --git a/mm/slub.c b/mm/slub.c
index 630d39a0d63f..ea3e20e73fe6 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1296,6 +1296,9 @@ static int __init setup_slub_debug(char *str)
 		case 'a':
 			slub_debug |= SLAB_FAILSLAB;
 			break;
+		case 'm':
+			slub_debug |= SLAB_PF_MEMALLOC;
+			break;
 		default:
 			printk(KERN_ERR "slub_debug option '%c' "
 				"unknown. skipped\n", *str);
@@ -2482,8 +2485,8 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page)
  * Version of __slab_alloc to use when we know that interrupts are
  * already disabled (which is the case for bulk allocation).
  */
-static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
-			  unsigned long addr, struct kmem_cache_cpu *c)
+static void *___slab_alloc_limited(struct kmem_cache *s, gfp_t gfpflags, int node,
+				   unsigned long addr, struct kmem_cache_cpu *c)
 {
 	void *freelist;
 	struct page *page;
@@ -2584,6 +2587,41 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
 	return freelist;
 }
 
+/*
+ * "unlimited" function honors SLAB_PF_MEMALLOC flag on the SLAB and if set,
+ * ignores the memcg limits during the SLAB object allocation.
+ */
+static void *___slab_alloc_unlimited(struct kmem_cache *s, gfp_t gfpflags, int node,
+				     unsigned long addr, struct kmem_cache_cpu *c)
+{
+	/*
+	 * A big crutch: we suspect some SLAB allocation failure leads
+	 * to a memory corruption, so for now we want to make marked SLABs
+	 * to always succeed allocation.
+	 */
+	if (s->flags & SLAB_PF_MEMALLOC) {
+		void *freelist;
+		unsigned long pflags = current->flags;
+
+		current->flags |= PF_MEMALLOC;
+
+		freelist = ___slab_alloc_limited(s, gfpflags, node, addr, c);
+
+		tsk_restore_flags(current, pflags, PF_MEMALLOC);
+		return freelist;
+	} else
+		return ___slab_alloc_limited(s, gfpflags, node, addr, c);
+}
+
+/*
+ * A wrapper to keep the original function name.
+ */
+static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
+			   unsigned long addr, struct kmem_cache_cpu *c)
+{
+	return ___slab_alloc_unlimited(s, gfpflags, node, addr, c);
+}
+
 /*
  * Another one that disabled interrupt and compensates for possible
  * cpu changes by refetching the per cpu area pointer.
@@ -5253,6 +5291,22 @@ static ssize_t poison_store(struct kmem_cache *s,
 }
 SLAB_ATTR(poison);
 
+static ssize_t pf_memalloc_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_PF_MEMALLOC));
+}
+
+static ssize_t pf_memalloc_store(struct kmem_cache *s,
+				 const char *buf, size_t length)
+{
+	s->flags &= ~SLAB_PF_MEMALLOC;
+	if (buf[0] == '1') {
+		s->flags |= SLAB_PF_MEMALLOC;
+	}
+	return length;
+}
+SLAB_ATTR(pf_memalloc);
+
 static ssize_t store_user_show(struct kmem_cache *s, char *buf)
 {
 	return sprintf(buf, "%d\n", !!(s->flags & SLAB_STORE_USER));
@@ -5475,6 +5529,7 @@ static struct attribute *slab_attrs[] = {
 	&trace_attr.attr,
 	&red_zone_attr.attr,
 	&poison_attr.attr,
+	&pf_memalloc_attr.attr,
 	&store_user_attr.attr,
 	&validate_attr.attr,
 	&alloc_calls_attr.attr,
-- 
2.24.3



More information about the Devel mailing list