btrfs: make prepare_pages nowait compatible
authorStefan Roesch <shr@fb.com>
Mon, 12 Sep 2022 19:27:47 +0000 (12:27 -0700)
committerDavid Sterba <dsterba@suse.com>
Thu, 29 Sep 2022 15:08:28 +0000 (17:08 +0200)
Add nowait parameter to the prepare_pages function. In case nowait is
specified for an async buffered write request, do a nowait allocation or
return -EAGAIN.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Stefan Roesch <shr@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/file.c

index c7edac4..2181b54 100644 (file)
@@ -1339,26 +1339,54 @@ static int prepare_uptodate_page(struct inode *inode,
        return 0;
 }
 
+static unsigned int get_prepare_fgp_flags(bool nowait)
+{
+       unsigned int fgp_flags = FGP_LOCK | FGP_ACCESSED | FGP_CREAT;
+
+       if (nowait)
+               fgp_flags |= FGP_NOWAIT;
+
+       return fgp_flags;
+}
+
+static gfp_t get_prepare_gfp_flags(struct inode *inode, bool nowait)
+{
+       gfp_t gfp;
+
+       gfp = btrfs_alloc_write_mask(inode->i_mapping);
+       if (nowait) {
+               gfp &= ~__GFP_DIRECT_RECLAIM;
+               gfp |= GFP_NOWAIT;
+       }
+
+       return gfp;
+}
+
 /*
  * this just gets pages into the page cache and locks them down.
  */
 static noinline int prepare_pages(struct inode *inode, struct page **pages,
                                  size_t num_pages, loff_t pos,
-                                 size_t write_bytes, bool force_uptodate)
+                                 size_t write_bytes, bool force_uptodate,
+                                 bool nowait)
 {
        int i;
        unsigned long index = pos >> PAGE_SHIFT;
-       gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
+       gfp_t mask = get_prepare_gfp_flags(inode, nowait);
+       unsigned int fgp_flags = get_prepare_fgp_flags(nowait);
        int err = 0;
        int faili;
 
        for (i = 0; i < num_pages; i++) {
 again:
-               pages[i] = find_or_create_page(inode->i_mapping, index + i,
-                                              mask | __GFP_WRITE);
+               pages[i] = pagecache_get_page(inode->i_mapping, index + i,
+                                             fgp_flags, mask | __GFP_WRITE);
                if (!pages[i]) {
                        faili = i - 1;
-                       err = -ENOMEM;
+                       if (nowait)
+                               err = -EAGAIN;
+                       else
+                               err = -ENOMEM;
                        goto fail;
                }
 
@@ -1376,7 +1404,7 @@ again:
                                                    pos + write_bytes, false);
                if (err) {
                        put_page(pages[i]);
-                       if (err == -EAGAIN) {
+                       if (!nowait && err == -EAGAIN) {
                                err = 0;
                                goto again;
                        }
@@ -1714,8 +1742,7 @@ again:
                 * contents of pages from loop to loop
                 */
                ret = prepare_pages(inode, pages, num_pages,
-                                   pos, write_bytes,
-                                   force_page_uptodate);
+                                   pos, write_bytes, force_page_uptodate, false);
                if (ret) {
                        btrfs_delalloc_release_extents(BTRFS_I(inode),
                                                       reserve_bytes);