diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-11-26 18:13:40 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-12-01 18:52:36 -0500 |
commit | cab7a7e5b6c5c2638b00c72559ff9fb715583c98 (patch) | |
tree | fdea606d6c8739f33ec3444e69b40a534645caea /mm/zswap.c | |
parent | ad7ed7708db9ff388450935645816d44bf08a56d (diff) |
mm/zswap: Convert pool to hotplug state machine
Install the callbacks via the state machine. Multi state is used to address the
per-pool notifier. Uppon adding of the intance the callback is invoked for all
online CPUs so the manual init can go.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: linux-mm@kvack.org
Cc: Seth Jennings <sjenning@redhat.com>
Cc: rt@linutronix.de
Link: http://lkml.kernel.org/r/20161126231350.10321-13-bigeasy@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'mm/zswap.c')
-rw-r--r-- | mm/zswap.c | 99 |
1 files changed, 34 insertions, 65 deletions
diff --git a/mm/zswap.c b/mm/zswap.c index b13aa5706348..067a0d62f318 100644 --- a/mm/zswap.c +++ b/mm/zswap.c | |||
@@ -118,7 +118,7 @@ struct zswap_pool { | |||
118 | struct kref kref; | 118 | struct kref kref; |
119 | struct list_head list; | 119 | struct list_head list; |
120 | struct work_struct work; | 120 | struct work_struct work; |
121 | struct notifier_block notifier; | 121 | struct hlist_node node; |
122 | char tfm_name[CRYPTO_MAX_ALG_NAME]; | 122 | char tfm_name[CRYPTO_MAX_ALG_NAME]; |
123 | }; | 123 | }; |
124 | 124 | ||
@@ -376,77 +376,34 @@ static int zswap_dstmem_dead(unsigned int cpu) | |||
376 | return 0; | 376 | return 0; |
377 | } | 377 | } |
378 | 378 | ||
379 | static int __zswap_cpu_comp_notifier(struct zswap_pool *pool, | 379 | static int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node) |
380 | unsigned long action, unsigned long cpu) | ||
381 | { | 380 | { |
381 | struct zswap_pool *pool = hlist_entry(node, struct zswap_pool, node); | ||
382 | struct crypto_comp *tfm; | 382 | struct crypto_comp *tfm; |
383 | 383 | ||
384 | switch (action) { | 384 | if (WARN_ON(*per_cpu_ptr(pool->tfm, cpu))) |
385 | case CPU_UP_PREPARE: | 385 | return 0; |
386 | if (WARN_ON(*per_cpu_ptr(pool->tfm, cpu))) | ||
387 | break; | ||
388 | tfm = crypto_alloc_comp(pool->tfm_name, 0, 0); | ||
389 | if (IS_ERR_OR_NULL(tfm)) { | ||
390 | pr_err("could not alloc crypto comp %s : %ld\n", | ||
391 | pool->tfm_name, PTR_ERR(tfm)); | ||
392 | return NOTIFY_BAD; | ||
393 | } | ||
394 | *per_cpu_ptr(pool->tfm, cpu) = tfm; | ||
395 | break; | ||
396 | case CPU_DEAD: | ||
397 | case CPU_UP_CANCELED: | ||
398 | tfm = *per_cpu_ptr(pool->tfm, cpu); | ||
399 | if (!IS_ERR_OR_NULL(tfm)) | ||
400 | crypto_free_comp(tfm); | ||
401 | *per_cpu_ptr(pool->tfm, cpu) = NULL; | ||
402 | break; | ||
403 | default: | ||
404 | break; | ||
405 | } | ||
406 | return NOTIFY_OK; | ||
407 | } | ||
408 | |||
409 | static int zswap_cpu_comp_notifier(struct notifier_block *nb, | ||
410 | unsigned long action, void *pcpu) | ||
411 | { | ||
412 | unsigned long cpu = (unsigned long)pcpu; | ||
413 | struct zswap_pool *pool = container_of(nb, typeof(*pool), notifier); | ||
414 | |||
415 | return __zswap_cpu_comp_notifier(pool, action, cpu); | ||
416 | } | ||
417 | 386 | ||
418 | static int zswap_cpu_comp_init(struct zswap_pool *pool) | 387 | tfm = crypto_alloc_comp(pool->tfm_name, 0, 0); |
419 | { | 388 | if (IS_ERR_OR_NULL(tfm)) { |
420 | unsigned long cpu; | 389 | pr_err("could not alloc crypto comp %s : %ld\n", |
421 | 390 | pool->tfm_name, PTR_ERR(tfm)); | |
422 | memset(&pool->notifier, 0, sizeof(pool->notifier)); | 391 | return -ENOMEM; |
423 | pool->notifier.notifier_call = zswap_cpu_comp_notifier; | 392 | } |
424 | 393 | *per_cpu_ptr(pool->tfm, cpu) = tfm; | |
425 | cpu_notifier_register_begin(); | ||
426 | for_each_online_cpu(cpu) | ||
427 | if (__zswap_cpu_comp_notifier(pool, CPU_UP_PREPARE, cpu) == | ||
428 | NOTIFY_BAD) | ||
429 | goto cleanup; | ||
430 | __register_cpu_notifier(&pool->notifier); | ||
431 | cpu_notifier_register_done(); | ||
432 | return 0; | 394 | return 0; |
433 | |||
434 | cleanup: | ||
435 | for_each_online_cpu(cpu) | ||
436 | __zswap_cpu_comp_notifier(pool, CPU_UP_CANCELED, cpu); | ||
437 | cpu_notifier_register_done(); | ||
438 | return -ENOMEM; | ||
439 | } | 395 | } |
440 | 396 | ||
441 | static void zswap_cpu_comp_destroy(struct zswap_pool *pool) | 397 | static int zswap_cpu_comp_dead(unsigned int cpu, struct hlist_node *node) |
442 | { | 398 | { |
443 | unsigned long cpu; | 399 | struct zswap_pool *pool = hlist_entry(node, struct zswap_pool, node); |
400 | struct crypto_comp *tfm; | ||
444 | 401 | ||
445 | cpu_notifier_register_begin(); | 402 | tfm = *per_cpu_ptr(pool->tfm, cpu); |
446 | for_each_online_cpu(cpu) | 403 | if (!IS_ERR_OR_NULL(tfm)) |
447 | __zswap_cpu_comp_notifier(pool, CPU_UP_CANCELED, cpu); | 404 | crypto_free_comp(tfm); |
448 | __unregister_cpu_notifier(&pool->notifier); | 405 | *per_cpu_ptr(pool->tfm, cpu) = NULL; |
449 | cpu_notifier_register_done(); | 406 | return 0; |
450 | } | 407 | } |
451 | 408 | ||
452 | /********************************* | 409 | /********************************* |
@@ -527,6 +484,7 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor) | |||
527 | struct zswap_pool *pool; | 484 | struct zswap_pool *pool; |
528 | char name[38]; /* 'zswap' + 32 char (max) num + \0 */ | 485 | char name[38]; /* 'zswap' + 32 char (max) num + \0 */ |
529 | gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM; | 486 | gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM; |
487 | int ret; | ||
530 | 488 | ||
531 | pool = kzalloc(sizeof(*pool), GFP_KERNEL); | 489 | pool = kzalloc(sizeof(*pool), GFP_KERNEL); |
532 | if (!pool) { | 490 | if (!pool) { |
@@ -551,7 +509,9 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor) | |||
551 | goto error; | 509 | goto error; |
552 | } | 510 | } |
553 | 511 | ||
554 | if (zswap_cpu_comp_init(pool)) | 512 | ret = cpuhp_state_add_instance(CPUHP_MM_ZSWP_POOL_PREPARE, |
513 | &pool->node); | ||
514 | if (ret) | ||
555 | goto error; | 515 | goto error; |
556 | pr_debug("using %s compressor\n", pool->tfm_name); | 516 | pr_debug("using %s compressor\n", pool->tfm_name); |
557 | 517 | ||
@@ -605,7 +565,7 @@ static void zswap_pool_destroy(struct zswap_pool *pool) | |||
605 | { | 565 | { |
606 | zswap_pool_debug("destroying", pool); | 566 | zswap_pool_debug("destroying", pool); |
607 | 567 | ||
608 | zswap_cpu_comp_destroy(pool); | 568 | cpuhp_state_remove_instance(CPUHP_MM_ZSWP_POOL_PREPARE, &pool->node); |
609 | free_percpu(pool->tfm); | 569 | free_percpu(pool->tfm); |
610 | zpool_destroy_pool(pool->zpool); | 570 | zpool_destroy_pool(pool->zpool); |
611 | kfree(pool); | 571 | kfree(pool); |
@@ -1212,6 +1172,13 @@ static int __init init_zswap(void) | |||
1212 | goto dstmem_fail; | 1172 | goto dstmem_fail; |
1213 | } | 1173 | } |
1214 | 1174 | ||
1175 | ret = cpuhp_setup_state_multi(CPUHP_MM_ZSWP_POOL_PREPARE, | ||
1176 | "mm/zswap_pool:prepare", | ||
1177 | zswap_cpu_comp_prepare, | ||
1178 | zswap_cpu_comp_dead); | ||
1179 | if (ret) | ||
1180 | goto hp_fail; | ||
1181 | |||
1215 | pool = __zswap_pool_create_fallback(); | 1182 | pool = __zswap_pool_create_fallback(); |
1216 | if (!pool) { | 1183 | if (!pool) { |
1217 | pr_err("pool creation failed\n"); | 1184 | pr_err("pool creation failed\n"); |
@@ -1228,6 +1195,8 @@ static int __init init_zswap(void) | |||
1228 | return 0; | 1195 | return 0; |
1229 | 1196 | ||
1230 | pool_fail: | 1197 | pool_fail: |
1198 | cpuhp_remove_state_nocalls(CPUHP_MM_ZSWP_POOL_PREPARE); | ||
1199 | hp_fail: | ||
1231 | cpuhp_remove_state(CPUHP_MM_ZSWP_MEM_PREPARE); | 1200 | cpuhp_remove_state(CPUHP_MM_ZSWP_MEM_PREPARE); |
1232 | dstmem_fail: | 1201 | dstmem_fail: |
1233 | zswap_entry_cache_destroy(); | 1202 | zswap_entry_cache_destroy(); |