btrfs: avoid blocking when allocating context for nowait dio read/write
authorFilipe Manana <fdmanana@suse.com>
Wed, 23 Mar 2022 16:19:29 +0000 (16:19 +0000)
committerDavid Sterba <dsterba@suse.com>
Mon, 16 May 2022 15:03:10 +0000 (17:03 +0200)
When doing a NOWAIT direct IO read/write, we allocate a context object
(struct btrfs_dio_data) with GFP_NOFS, which can result in blocking
waiting for memory allocation (GFP_NOFS is __GFP_RECLAIM | __GFP_IO).
This is undesirable for the NOWAIT semantics, so do the allocation with
GFP_NOWAIT if we are serving a NOWAIT request and if the allocation fails
return -EAGAIN, so that the caller can fallback to a blocking context and
retry with a non-blocking write.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index 1922c70..4254c3c 100644 (file)
@@ -7588,9 +7588,15 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
                }
        }
 
-       dio_data = kzalloc(sizeof(*dio_data), GFP_NOFS);
-       if (!dio_data)
-               return -ENOMEM;
+       if (flags & IOMAP_NOWAIT) {
+               dio_data = kzalloc(sizeof(*dio_data), GFP_NOWAIT);
+               if (!dio_data)
+                       return -EAGAIN;
+       } else {
+               dio_data = kzalloc(sizeof(*dio_data), GFP_NOFS);
+               if (!dio_data)
+                       return -ENOMEM;
+       }
 
        iomap->private = dio_data;