Skip to content

Commit 03afc0e

Browse files
Vladimir Davydovtorvalds
authored andcommitted
slab: get_online_mems for kmem_cache_{create,destroy,shrink}
When we create a sl[au]b cache, we allocate kmem_cache_node structures for each online NUMA node. To handle nodes taken online/offline, we register memory hotplug notifier and allocate/free kmem_cache_node corresponding to the node that changes its state for each kmem cache. To synchronize between the two paths we hold the slab_mutex during both the cache creationg/destruction path and while tuning per-node parts of kmem caches in memory hotplug handler, but that's not quite right, because it does not guarantee that a newly created cache will have all kmem_cache_nodes initialized in case it races with memory hotplug. For instance, in case of slub: CPU0 CPU1 ---- ---- kmem_cache_create: online_pages: __kmem_cache_create: slab_memory_callback: slab_mem_going_online_callback: lock slab_mutex for each slab_caches list entry allocate kmem_cache node unlock slab_mutex lock slab_mutex init_kmem_cache_nodes: for_each_node_state(node, N_NORMAL_MEMORY) allocate kmem_cache node add kmem_cache to slab_caches list unlock slab_mutex online_pages (continued): node_states_set_node As a result we'll get a kmem cache with not all kmem_cache_nodes allocated. To avoid issues like that we should hold get/put_online_mems() during the whole kmem cache creation/destruction/shrink paths, just like we deal with cpu hotplug. This patch does the trick. Note, that after it's applied, there is no need in taking the slab_mutex for kmem_cache_shrink any more, so it is removed from there. Signed-off-by: Vladimir Davydov <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Pekka Enberg <[email protected]> Cc: Tang Chen <[email protected]> Cc: Zhang Yanfei <[email protected]> Cc: Toshi Kani <[email protected]> Cc: Xishi Qiu <[email protected]> Cc: Jiang Liu <[email protected]> Cc: Rafael J. Wysocki <[email protected]> Cc: David Rientjes <[email protected]> Cc: Wen Congyang <[email protected]> Cc: Yasuaki Ishimatsu <[email protected]> Cc: Lai Jiangshan <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent bfc8c90 commit 03afc0e

File tree

5 files changed

+39
-31
lines changed

5 files changed

+39
-31
lines changed

mm/slab.c

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2480,8 +2480,7 @@ static int drain_freelist(struct kmem_cache *cache,
24802480
return nr_freed;
24812481
}
24822482

2483-
/* Called with slab_mutex held to protect against cpu hotplug */
2484-
static int __cache_shrink(struct kmem_cache *cachep)
2483+
int __kmem_cache_shrink(struct kmem_cache *cachep)
24852484
{
24862485
int ret = 0, i = 0;
24872486
struct kmem_cache_node *n;
@@ -2502,32 +2501,11 @@ static int __cache_shrink(struct kmem_cache *cachep)
25022501
return (ret ? 1 : 0);
25032502
}
25042503

2505-
/**
2506-
* kmem_cache_shrink - Shrink a cache.
2507-
* @cachep: The cache to shrink.
2508-
*
2509-
* Releases as many slabs as possible for a cache.
2510-
* To help debugging, a zero exit status indicates all slabs were released.
2511-
*/
2512-
int kmem_cache_shrink(struct kmem_cache *cachep)
2513-
{
2514-
int ret;
2515-
BUG_ON(!cachep || in_interrupt());
2516-
2517-
get_online_cpus();
2518-
mutex_lock(&slab_mutex);
2519-
ret = __cache_shrink(cachep);
2520-
mutex_unlock(&slab_mutex);
2521-
put_online_cpus();
2522-
return ret;
2523-
}
2524-
EXPORT_SYMBOL(kmem_cache_shrink);
2525-
25262504
int __kmem_cache_shutdown(struct kmem_cache *cachep)
25272505
{
25282506
int i;
25292507
struct kmem_cache_node *n;
2530-
int rc = __cache_shrink(cachep);
2508+
int rc = __kmem_cache_shrink(cachep);
25312509

25322510
if (rc)
25332511
return rc;

mm/slab.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ __kmem_cache_alias(const char *name, size_t size, size_t align,
9191
#define CACHE_CREATE_MASK (SLAB_CORE_FLAGS | SLAB_DEBUG_FLAGS | SLAB_CACHE_FLAGS)
9292

9393
int __kmem_cache_shutdown(struct kmem_cache *);
94+
int __kmem_cache_shrink(struct kmem_cache *);
9495
void slab_kmem_cache_release(struct kmem_cache *);
9596

9697
struct seq_file;

mm/slab_common.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ kmem_cache_create(const char *name, size_t size, size_t align,
205205
int err;
206206

207207
get_online_cpus();
208+
get_online_mems();
209+
208210
mutex_lock(&slab_mutex);
209211

210212
err = kmem_cache_sanity_check(name, size);
@@ -239,6 +241,8 @@ kmem_cache_create(const char *name, size_t size, size_t align,
239241

240242
out_unlock:
241243
mutex_unlock(&slab_mutex);
244+
245+
put_online_mems();
242246
put_online_cpus();
243247

244248
if (err) {
@@ -272,6 +276,8 @@ void kmem_cache_create_memcg(struct mem_cgroup *memcg, struct kmem_cache *root_c
272276
char *cache_name;
273277

274278
get_online_cpus();
279+
get_online_mems();
280+
275281
mutex_lock(&slab_mutex);
276282

277283
/*
@@ -295,6 +301,8 @@ void kmem_cache_create_memcg(struct mem_cgroup *memcg, struct kmem_cache *root_c
295301

296302
out_unlock:
297303
mutex_unlock(&slab_mutex);
304+
305+
put_online_mems();
298306
put_online_cpus();
299307
}
300308

@@ -328,6 +336,8 @@ void slab_kmem_cache_release(struct kmem_cache *s)
328336
void kmem_cache_destroy(struct kmem_cache *s)
329337
{
330338
get_online_cpus();
339+
get_online_mems();
340+
331341
mutex_lock(&slab_mutex);
332342

333343
s->refcount--;
@@ -359,15 +369,36 @@ void kmem_cache_destroy(struct kmem_cache *s)
359369
#else
360370
slab_kmem_cache_release(s);
361371
#endif
362-
goto out_put_cpus;
372+
goto out;
363373

364374
out_unlock:
365375
mutex_unlock(&slab_mutex);
366-
out_put_cpus:
376+
out:
377+
put_online_mems();
367378
put_online_cpus();
368379
}
369380
EXPORT_SYMBOL(kmem_cache_destroy);
370381

382+
/**
383+
* kmem_cache_shrink - Shrink a cache.
384+
* @cachep: The cache to shrink.
385+
*
386+
* Releases as many slabs as possible for a cache.
387+
* To help debugging, a zero exit status indicates all slabs were released.
388+
*/
389+
int kmem_cache_shrink(struct kmem_cache *cachep)
390+
{
391+
int ret;
392+
393+
get_online_cpus();
394+
get_online_mems();
395+
ret = __kmem_cache_shrink(cachep);
396+
put_online_mems();
397+
put_online_cpus();
398+
return ret;
399+
}
400+
EXPORT_SYMBOL(kmem_cache_shrink);
401+
371402
int slab_is_available(void)
372403
{
373404
return slab_state >= UP;

mm/slob.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,11 +620,10 @@ int __kmem_cache_shutdown(struct kmem_cache *c)
620620
return 0;
621621
}
622622

623-
int kmem_cache_shrink(struct kmem_cache *d)
623+
int __kmem_cache_shrink(struct kmem_cache *d)
624624
{
625625
return 0;
626626
}
627-
EXPORT_SYMBOL(kmem_cache_shrink);
628627

629628
struct kmem_cache kmem_cache_boot = {
630629
.name = "kmem_cache",

mm/slub.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3398,7 +3398,7 @@ EXPORT_SYMBOL(kfree);
33983398
* being allocated from last increasing the chance that the last objects
33993399
* are freed in them.
34003400
*/
3401-
int kmem_cache_shrink(struct kmem_cache *s)
3401+
int __kmem_cache_shrink(struct kmem_cache *s)
34023402
{
34033403
int node;
34043404
int i;
@@ -3454,15 +3454,14 @@ int kmem_cache_shrink(struct kmem_cache *s)
34543454
kfree(slabs_by_inuse);
34553455
return 0;
34563456
}
3457-
EXPORT_SYMBOL(kmem_cache_shrink);
34583457

34593458
static int slab_mem_going_offline_callback(void *arg)
34603459
{
34613460
struct kmem_cache *s;
34623461

34633462
mutex_lock(&slab_mutex);
34643463
list_for_each_entry(s, &slab_caches, list)
3465-
kmem_cache_shrink(s);
3464+
__kmem_cache_shrink(s);
34663465
mutex_unlock(&slab_mutex);
34673466

34683467
return 0;

0 commit comments

Comments
 (0)