diff options
author | Dan Streetman <ddstreet@ieee.org> | 2017-02-27 17:26:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-27 21:43:45 -0500 |
commit | ae3d89a7e0871bc7b57ef8d3c4dd7fdda43c285c (patch) | |
tree | 21453fc7be1d56cc7c4386ed1f3ffd60af504139 /mm/zswap.c | |
parent | 01cddfe99008da87dd4f6b8fbfa31e09257b9133 (diff) |
zswap: allow initialization at boot without pool
Allow zswap to initialize at boot even if it can't create its pool due
to a failure to create a zpool and/or compressor. Allow those to be
created later, from the sysfs module param interface.
Link: http://lkml.kernel.org/r/20170124200259.16191-3-ddstreet@ieee.org
Signed-off-by: Dan Streetman <dan.streetman@canonical.com>
Cc: Seth Jennings <sjenning@redhat.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: Minchan Kim <minchan@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/zswap.c')
-rw-r--r-- | mm/zswap.c | 46 |
1 files changed, 34 insertions, 12 deletions
diff --git a/mm/zswap.c b/mm/zswap.c index cabf09e0128b..77cb847938e1 100644 --- a/mm/zswap.c +++ b/mm/zswap.c | |||
@@ -185,6 +185,9 @@ static bool zswap_init_started; | |||
185 | /* fatal error during init */ | 185 | /* fatal error during init */ |
186 | static bool zswap_init_failed; | 186 | static bool zswap_init_failed; |
187 | 187 | ||
188 | /* init completed, but couldn't create the initial pool */ | ||
189 | static bool zswap_has_pool; | ||
190 | |||
188 | /********************************* | 191 | /********************************* |
189 | * helpers and fwd declarations | 192 | * helpers and fwd declarations |
190 | **********************************/ | 193 | **********************************/ |
@@ -424,7 +427,8 @@ static struct zswap_pool *__zswap_pool_current(void) | |||
424 | struct zswap_pool *pool; | 427 | struct zswap_pool *pool; |
425 | 428 | ||
426 | pool = list_first_or_null_rcu(&zswap_pools, typeof(*pool), list); | 429 | pool = list_first_or_null_rcu(&zswap_pools, typeof(*pool), list); |
427 | WARN_ON(!pool); | 430 | WARN_ONCE(!pool && zswap_has_pool, |
431 | "%s: no page storage pool!\n", __func__); | ||
428 | 432 | ||
429 | return pool; | 433 | return pool; |
430 | } | 434 | } |
@@ -443,7 +447,7 @@ static struct zswap_pool *zswap_pool_current_get(void) | |||
443 | rcu_read_lock(); | 447 | rcu_read_lock(); |
444 | 448 | ||
445 | pool = __zswap_pool_current(); | 449 | pool = __zswap_pool_current(); |
446 | if (!pool || !zswap_pool_get(pool)) | 450 | if (!zswap_pool_get(pool)) |
447 | pool = NULL; | 451 | pool = NULL; |
448 | 452 | ||
449 | rcu_read_unlock(); | 453 | rcu_read_unlock(); |
@@ -459,7 +463,9 @@ static struct zswap_pool *zswap_pool_last_get(void) | |||
459 | 463 | ||
460 | list_for_each_entry_rcu(pool, &zswap_pools, list) | 464 | list_for_each_entry_rcu(pool, &zswap_pools, list) |
461 | last = pool; | 465 | last = pool; |
462 | if (!WARN_ON(!last) && !zswap_pool_get(last)) | 466 | WARN_ONCE(!last && zswap_has_pool, |
467 | "%s: no page storage pool!\n", __func__); | ||
468 | if (!zswap_pool_get(last)) | ||
463 | last = NULL; | 469 | last = NULL; |
464 | 470 | ||
465 | rcu_read_unlock(); | 471 | rcu_read_unlock(); |
@@ -582,6 +588,9 @@ static void zswap_pool_destroy(struct zswap_pool *pool) | |||
582 | 588 | ||
583 | static int __must_check zswap_pool_get(struct zswap_pool *pool) | 589 | static int __must_check zswap_pool_get(struct zswap_pool *pool) |
584 | { | 590 | { |
591 | if (!pool) | ||
592 | return 0; | ||
593 | |||
585 | return kref_get_unless_zero(&pool->kref); | 594 | return kref_get_unless_zero(&pool->kref); |
586 | } | 595 | } |
587 | 596 | ||
@@ -639,7 +648,7 @@ static int __zswap_param_set(const char *val, const struct kernel_param *kp, | |||
639 | } | 648 | } |
640 | 649 | ||
641 | /* no change required */ | 650 | /* no change required */ |
642 | if (!strcmp(s, *(char **)kp->arg)) | 651 | if (!strcmp(s, *(char **)kp->arg) && zswap_has_pool) |
643 | return 0; | 652 | return 0; |
644 | 653 | ||
645 | /* if this is load-time (pre-init) param setting, | 654 | /* if this is load-time (pre-init) param setting, |
@@ -685,6 +694,7 @@ static int __zswap_param_set(const char *val, const struct kernel_param *kp, | |||
685 | if (!ret) { | 694 | if (!ret) { |
686 | put_pool = zswap_pool_current(); | 695 | put_pool = zswap_pool_current(); |
687 | list_add_rcu(&pool->list, &zswap_pools); | 696 | list_add_rcu(&pool->list, &zswap_pools); |
697 | zswap_has_pool = true; | ||
688 | } else if (pool) { | 698 | } else if (pool) { |
689 | /* add the possibly pre-existing pool to the end of the pools | 699 | /* add the possibly pre-existing pool to the end of the pools |
690 | * list; if it's new (and empty) then it'll be removed and | 700 | * list; if it's new (and empty) then it'll be removed and |
@@ -692,6 +702,15 @@ static int __zswap_param_set(const char *val, const struct kernel_param *kp, | |||
692 | */ | 702 | */ |
693 | list_add_tail_rcu(&pool->list, &zswap_pools); | 703 | list_add_tail_rcu(&pool->list, &zswap_pools); |
694 | put_pool = pool; | 704 | put_pool = pool; |
705 | } else if (!zswap_has_pool) { | ||
706 | /* if initial pool creation failed, and this pool creation also | ||
707 | * failed, maybe both compressor and zpool params were bad. | ||
708 | * Allow changing this param, so pool creation will succeed | ||
709 | * when the other param is changed. We already verified this | ||
710 | * param is ok in the zpool_has_pool() or crypto_has_comp() | ||
711 | * checks above. | ||
712 | */ | ||
713 | ret = param_set_charp(s, kp); | ||
695 | } | 714 | } |
696 | 715 | ||
697 | spin_unlock(&zswap_pools_lock); | 716 | spin_unlock(&zswap_pools_lock); |
@@ -724,6 +743,10 @@ static int zswap_enabled_param_set(const char *val, | |||
724 | pr_err("can't enable, initialization failed\n"); | 743 | pr_err("can't enable, initialization failed\n"); |
725 | return -ENODEV; | 744 | return -ENODEV; |
726 | } | 745 | } |
746 | if (!zswap_has_pool && zswap_init_started) { | ||
747 | pr_err("can't enable, no pool configured\n"); | ||
748 | return -ENODEV; | ||
749 | } | ||
727 | 750 | ||
728 | return param_set_bool(val, kp); | 751 | return param_set_bool(val, kp); |
729 | } | 752 | } |
@@ -1205,22 +1228,21 @@ static int __init init_zswap(void) | |||
1205 | goto hp_fail; | 1228 | goto hp_fail; |
1206 | 1229 | ||
1207 | pool = __zswap_pool_create_fallback(); | 1230 | pool = __zswap_pool_create_fallback(); |
1208 | if (!pool) { | 1231 | if (pool) { |
1232 | pr_info("loaded using pool %s/%s\n", pool->tfm_name, | ||
1233 | zpool_get_type(pool->zpool)); | ||
1234 | list_add(&pool->list, &zswap_pools); | ||
1235 | zswap_has_pool = true; | ||
1236 | } else { | ||
1209 | pr_err("pool creation failed\n"); | 1237 | pr_err("pool creation failed\n"); |
1210 | goto pool_fail; | 1238 | zswap_enabled = false; |
1211 | } | 1239 | } |
1212 | pr_info("loaded using pool %s/%s\n", pool->tfm_name, | ||
1213 | zpool_get_type(pool->zpool)); | ||
1214 | |||
1215 | list_add(&pool->list, &zswap_pools); | ||
1216 | 1240 | ||
1217 | frontswap_register_ops(&zswap_frontswap_ops); | 1241 | frontswap_register_ops(&zswap_frontswap_ops); |
1218 | if (zswap_debugfs_init()) | 1242 | if (zswap_debugfs_init()) |
1219 | pr_warn("debugfs initialization failed\n"); | 1243 | pr_warn("debugfs initialization failed\n"); |
1220 | return 0; | 1244 | return 0; |
1221 | 1245 | ||
1222 | pool_fail: | ||
1223 | cpuhp_remove_state_nocalls(CPUHP_MM_ZSWP_POOL_PREPARE); | ||
1224 | hp_fail: | 1246 | hp_fail: |
1225 | cpuhp_remove_state(CPUHP_MM_ZSWP_MEM_PREPARE); | 1247 | cpuhp_remove_state(CPUHP_MM_ZSWP_MEM_PREPARE); |
1226 | dstmem_fail: | 1248 | dstmem_fail: |