aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Streetman <ddstreet@ieee.org>2017-02-03 16:13:09 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-03 17:13:19 -0500
commitd7b028f56a971a2e4d8d7887540a144eeefcd4ab (patch)
tree511bb3eb86b7589ec0b96ec678df7e978f04766f
parent79c9089f97d37ffac88c3ddb6d359b2cf75058b7 (diff)
zswap: disable changing params if init fails
Add zswap_init_failed bool that prevents changing any of the module params, if init_zswap() fails, and set zswap_enabled to false. Change 'enabled' param to a callback, and check zswap_init_failed before allowing any change to 'enabled', 'zpool', or 'compressor' params. Any driver that is built-in to the kernel will not be unloaded if its init function returns error, and its module params remain accessible for users to change via sysfs. Since zswap uses param callbacks, which assume that zswap has been initialized, changing the zswap params after a failed initialization will result in WARNING due to the param callbacks expecting a pool to already exist. This prevents that by immediately exiting any of the param callbacks if initialization failed. This was reported here: https://marc.info/?l=linux-mm&m=147004228125528&w=4 And fixes this WARNING: [ 429.723476] WARNING: CPU: 0 PID: 5140 at mm/zswap.c:503 __zswap_pool_current+0x56/0x60 The warning is just noise, and not serious. However, when init fails, zswap frees all its percpu dstmem pages and its kmem cache. The kmem cache might be serious, if kmem_cache_alloc(NULL, gfp) has problems; but the percpu dstmem pages are definitely a problem, as they're used as temporary buffer for compressed pages before copying into place in the zpool. If the user does get zswap enabled after an init failure, then zswap will likely Oops on the first page it tries to compress (or worse, start corrupting memory). Fixes: 90b0fc26d5db ("zswap: change zpool/compressor at runtime") Link: http://lkml.kernel.org/r/20170124200259.16191-2-ddstreet@ieee.org Signed-off-by: Dan Streetman <dan.streetman@canonical.com> Reported-by: Marcin Miroslaw <marcin@mejor.pl> 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> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/zswap.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/mm/zswap.c b/mm/zswap.c
index 067a0d62f318..cabf09e0128b 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -78,7 +78,13 @@ static u64 zswap_duplicate_entry;
78 78
79/* Enable/disable zswap (disabled by default) */ 79/* Enable/disable zswap (disabled by default) */
80static bool zswap_enabled; 80static bool zswap_enabled;
81module_param_named(enabled, zswap_enabled, bool, 0644); 81static int zswap_enabled_param_set(const char *,
82 const struct kernel_param *);
83static struct kernel_param_ops zswap_enabled_param_ops = {
84 .set = zswap_enabled_param_set,
85 .get = param_get_bool,
86};
87module_param_cb(enabled, &zswap_enabled_param_ops, &zswap_enabled, 0644);
82 88
83/* Crypto compressor to use */ 89/* Crypto compressor to use */
84#define ZSWAP_COMPRESSOR_DEFAULT "lzo" 90#define ZSWAP_COMPRESSOR_DEFAULT "lzo"
@@ -176,6 +182,9 @@ static atomic_t zswap_pools_count = ATOMIC_INIT(0);
176/* used by param callback function */ 182/* used by param callback function */
177static bool zswap_init_started; 183static bool zswap_init_started;
178 184
185/* fatal error during init */
186static bool zswap_init_failed;
187
179/********************************* 188/*********************************
180* helpers and fwd declarations 189* helpers and fwd declarations
181**********************************/ 190**********************************/
@@ -624,6 +633,11 @@ static int __zswap_param_set(const char *val, const struct kernel_param *kp,
624 char *s = strstrip((char *)val); 633 char *s = strstrip((char *)val);
625 int ret; 634 int ret;
626 635
636 if (zswap_init_failed) {
637 pr_err("can't set param, initialization failed\n");
638 return -ENODEV;
639 }
640
627 /* no change required */ 641 /* no change required */
628 if (!strcmp(s, *(char **)kp->arg)) 642 if (!strcmp(s, *(char **)kp->arg))
629 return 0; 643 return 0;
@@ -703,6 +717,17 @@ static int zswap_zpool_param_set(const char *val,
703 return __zswap_param_set(val, kp, NULL, zswap_compressor); 717 return __zswap_param_set(val, kp, NULL, zswap_compressor);
704} 718}
705 719
720static int zswap_enabled_param_set(const char *val,
721 const struct kernel_param *kp)
722{
723 if (zswap_init_failed) {
724 pr_err("can't enable, initialization failed\n");
725 return -ENODEV;
726 }
727
728 return param_set_bool(val, kp);
729}
730
706/********************************* 731/*********************************
707* writeback code 732* writeback code
708**********************************/ 733**********************************/
@@ -1201,6 +1226,9 @@ hp_fail:
1201dstmem_fail: 1226dstmem_fail:
1202 zswap_entry_cache_destroy(); 1227 zswap_entry_cache_destroy();
1203cache_fail: 1228cache_fail:
1229 /* if built-in, we aren't unloaded on failure; don't allow use */
1230 zswap_init_failed = true;
1231 zswap_enabled = false;
1204 return -ENOMEM; 1232 return -ENOMEM;
1205} 1233}
1206/* must be late so crypto has time to come up */ 1234/* must be late so crypto has time to come up */