[1/3] btrfs: add memalloc_nofs protections around alloc_workspace callback
diff mbox

Message ID b5e9ce7c8b9b1a41adaaac883b15bf63c58dff93.1496245064.git.dsterba@suse.com
State New
Headers show

Commit Message

David Sterba May 31, 2017, 3:41 p.m. UTC
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.

Signed-off-by: David Sterba <dsterba@suse.com>
---
 fs/btrfs/compression.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

Comments

Anand Jain June 1, 2017, 3:36 a.m. UTC | #1
On 05/31/17 23:41, David Sterba wrote:
> 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>

Thanks, Anand

> Signed-off-by: David Sterba <dsterba@suse.com>
> ---
>  fs/btrfs/compression.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
> index ba511dd454d5..39cd164e5a62 100644
> --- a/fs/btrfs/compression.c
> +++ b/fs/btrfs/compression.c
> @@ -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 @@ static struct list_head *find_workspace(int type)
>  	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);
>



--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index ba511dd454d5..39cd164e5a62 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -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 @@  static struct list_head *find_workspace(int type)
 	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);