4.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Dan Streetman <[email protected]>

commit fd5bb66cd934987e49557455b6497fc006521940 upstream.

Change the zpool/compressor param callback function to release the
zswap_pools_lock spinlock before calling param_set_charp, since that
function may sleep when it calls kmalloc with GFP_KERNEL.

While this problem has existed for a while, I wasn't able to trigger it
using a tight loop changing either/both the zpool and compressor params; I
think it's very unlikely to be an issue on the stable kernels, especially
since most zswap users will change the compressor and/or zpool from sysfs
only one time each boot - or zero times, if they add the params to the
kernel boot.

Fixes: c99b42c3529e ("zswap: use charp for zswap param strings")
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Dan Streetman <[email protected]>
Reported-by: Sergey Senozhatsky <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Minchan Kim <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
Signed-off-by: Vlastimil Babka <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 mm/zswap.c |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -752,18 +752,22 @@ static int __zswap_param_set(const char
        pool = zswap_pool_find_get(type, compressor);
        if (pool) {
                zswap_pool_debug("using existing", pool);
+               WARN_ON(pool == zswap_pool_current());
                list_del_rcu(&pool->list);
-       } else {
-               spin_unlock(&zswap_pools_lock);
-               pool = zswap_pool_create(type, compressor);
-               spin_lock(&zswap_pools_lock);
        }
 
+       spin_unlock(&zswap_pools_lock);
+
+       if (!pool)
+               pool = zswap_pool_create(type, compressor);
+
        if (pool)
                ret = param_set_charp(s, kp);
        else
                ret = -EINVAL;
 
+       spin_lock(&zswap_pools_lock);
+
        if (!ret) {
                put_pool = zswap_pool_current();
                list_add_rcu(&pool->list, &zswap_pools);


Reply via email to