Skip to content

Commit 9198ffb

Browse files
Chen Juntehcaster
authored andcommitted
mm/slub: Reduce memory consumption in extreme scenarios
When kmalloc_node() is called without __GFP_THISNODE and the target node lacks sufficient memory, SLUB allocates a folio from a different node other than the requested node, instead of taking a partial slab from it. However, since the allocated folio does not belong to the requested node, on the following allocation it is deactivated and added to the partial slab list of the node it belongs to. This behavior can result in excessive memory usage when the requested node has insufficient memory, as SLUB will repeatedly allocate folios from other nodes without reusing the previously allocated ones. To prevent memory wastage, when a preferred node is indicated (not NUMA_NO_NODE) but without a prior __GFP_THISNODE constraint: 1) try to get a partial slab from target node only by having __GFP_THISNODE in pc.flags for get_partial() 2) if 1) failed, try to allocate a new slab from target node with GFP_NOWAIT | __GFP_THISNODE opportunistically. 3) if 2) failed, retry with original gfpflags which will allow get_partial() try partial lists of other nodes before potentially allocating new page from other nodes Without a preferred node, or with __GFP_THISNODE constraint, the behavior remains unchanged. On qemu with 4 numa nodes and each numa has 1G memory. Write a test ko to call kmalloc_node(196, GFP_KERNEL, 3) for (4 * 1024 + 4) * 1024 times. cat /proc/slabinfo shows: kmalloc-256 4200530 13519712 256 32 2 : tunables.. after this patch, cat /proc/slabinfo shows: kmalloc-256 4200558 4200768 256 32 2 : tunables.. Signed-off-by: Chen Jun <chenjun102@huawei.com> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
1 parent 87654cf commit 9198ffb

1 file changed

Lines changed: 23 additions & 2 deletions

File tree

mm/slub.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,7 +2699,7 @@ static struct slab *get_partial(struct kmem_cache *s, int node,
26992699
searchnode = numa_mem_id();
27002700

27012701
slab = get_partial_node(s, get_node(s, searchnode), pc);
2702-
if (slab || node != NUMA_NO_NODE)
2702+
if (slab || (node != NUMA_NO_NODE && (pc->flags & __GFP_THISNODE)))
27032703
return slab;
27042704

27052705
return get_any_partial(s, pc);
@@ -3375,6 +3375,7 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
33753375
struct slab *slab;
33763376
unsigned long flags;
33773377
struct partial_context pc;
3378+
bool try_thisnode = true;
33783379

33793380
stat(s, ALLOC_SLOWPATH);
33803381

@@ -3501,6 +3502,21 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
35013502
new_objects:
35023503

35033504
pc.flags = gfpflags;
3505+
/*
3506+
* When a preferred node is indicated but no __GFP_THISNODE
3507+
*
3508+
* 1) try to get a partial slab from target node only by having
3509+
* __GFP_THISNODE in pc.flags for get_partial()
3510+
* 2) if 1) failed, try to allocate a new slab from target node with
3511+
* GPF_NOWAIT | __GFP_THISNODE opportunistically
3512+
* 3) if 2) failed, retry with original gfpflags which will allow
3513+
* get_partial() try partial lists of other nodes before potentially
3514+
* allocating new page from other nodes
3515+
*/
3516+
if (unlikely(node != NUMA_NO_NODE && !(gfpflags & __GFP_THISNODE)
3517+
&& try_thisnode))
3518+
pc.flags = GFP_NOWAIT | __GFP_THISNODE;
3519+
35043520
pc.orig_size = orig_size;
35053521
slab = get_partial(s, node, &pc);
35063522
if (slab) {
@@ -3522,10 +3538,15 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
35223538
}
35233539

35243540
slub_put_cpu_ptr(s->cpu_slab);
3525-
slab = new_slab(s, gfpflags, node);
3541+
slab = new_slab(s, pc.flags, node);
35263542
c = slub_get_cpu_ptr(s->cpu_slab);
35273543

35283544
if (unlikely(!slab)) {
3545+
if (node != NUMA_NO_NODE && !(gfpflags & __GFP_THISNODE)
3546+
&& try_thisnode) {
3547+
try_thisnode = false;
3548+
goto new_objects;
3549+
}
35293550
slab_out_of_memory(s, gfpflags, node);
35303551
return NULL;
35313552
}

0 commit comments

Comments
 (0)