]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
btrfs: add memalloc_nofs protections around alloc_workspace callback
authorDavid Sterba <dsterba@suse.com>
Wed, 31 May 2017 15:14:56 +0000 (17:14 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 19 Jun 2017 16:26:02 +0000 (18:26 +0200)
The workspaces are preallocated at the beginning where we can safely use
GFP_KERNEL, but in some cases the find_workspace might reach the
allocation again, now in a more restricted context when the bios or
pages are being compressed.

To avoid potential lockup when alloc_workspace -> vmalloc would silently
use the GFP_KERNEL, add the memalloc_nofs helpers around the critical
call site.

Reviewed-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/compression.c

index ba511dd454d573553a21e5274551daeeef7c9249..39cd164e5a62cba55c9a6ddcf434d80f0c3a9f27 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/writeback.h>
 #include <linux/bit_spinlock.h>
 #include <linux/slab.h>
+#include <linux/sched/mm.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -757,6 +758,7 @@ static struct list_head *find_workspace(int type)
        struct list_head *workspace;
        int cpus = num_online_cpus();
        int idx = type - 1;
+       unsigned nofs_flag;
 
        struct list_head *idle_ws       = &btrfs_comp_ws[idx].idle_ws;
        spinlock_t *ws_lock             = &btrfs_comp_ws[idx].ws_lock;
@@ -786,7 +788,15 @@ again:
        atomic_inc(total_ws);
        spin_unlock(ws_lock);
 
+       /*
+        * Allocation helpers call vmalloc that can't use GFP_NOFS, so we have
+        * to turn it off here because we might get called from the restricted
+        * context of btrfs_compress_bio/btrfs_compress_pages
+        */
+       nofs_flag = memalloc_nofs_save();
        workspace = btrfs_compress_op[idx]->alloc_workspace();
+       memalloc_nofs_restore(nofs_flag);
+
        if (IS_ERR(workspace)) {
                atomic_dec(total_ws);
                wake_up(ws_wait);