linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Goldwyn Rodrigues <rgoldwyn@suse.de>
To: linux-btrfs@vger.kernel.org
Cc: Goldwyn Rodrigues <rgoldwyn@suse.com>
Subject: [RFC PATCH 6/8] btrfs: read the first/last page of the write
Date: Fri, 17 Nov 2017 11:44:52 -0600	[thread overview]
Message-ID: <20171117174456.13393-7-rgoldwyn@suse.de> (raw)
In-Reply-To: <20171117174456.13393-1-rgoldwyn@suse.de>

From: Goldwyn Rodrigues <rgoldwyn@suse.com>

We cannot perform a readpage in iomap_apply after
iomap_begin() because we have our extents locked. So,
we perform a readpage and make sure we unlock it, but
increase the page count.

Question: How do we deal with -EAGAIN return from
prepare_uptodate_page()? Under what scenario's would this occur?

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
---
 fs/btrfs/file.c  | 116 ++++++++++++++++++++++---------------------------------
 fs/btrfs/iomap.h |   1 +
 2 files changed, 47 insertions(+), 70 deletions(-)

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index b7390214ef3a..b34ec493fe4b 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1252,84 +1252,36 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
 	return 0;
 }
 
-/*
- * on error we return an unlocked page and the error value
- * on success we return a locked page and 0
- */
-static int prepare_uptodate_page(struct inode *inode,
-				 struct page *page, u64 pos,
-				 bool force_uptodate)
+static int prepare_uptodate_page(struct inode *inode, u64 pos, struct page **pagep)
 {
+	struct page *page = NULL;
 	int ret = 0;
+	int index = pos >> PAGE_SHIFT;
+
+	if (!(pos & (PAGE_SIZE - 1)))
+		goto out;
+
+	page = grab_cache_page_write_begin(inode->i_mapping, index,
+			AOP_FLAG_NOFS);
 
-	if (((pos & (PAGE_SIZE - 1)) || force_uptodate) &&
-	    !PageUptodate(page)) {
+	if (!PageUptodate(page)) {
 		ret = btrfs_readpage(NULL, page);
 		if (ret)
-			return ret;
-		lock_page(page);
+			goto out;
 		if (!PageUptodate(page)) {
-			unlock_page(page);
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 		if (page->mapping != inode->i_mapping) {
-			unlock_page(page);
-			return -EAGAIN;
-		}
-	}
-	return 0;
-}
-
-/*
- * 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)
-{
-	int i;
-	unsigned long index = pos >> PAGE_SHIFT;
-	gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
-	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);
-		if (!pages[i]) {
-			faili = i - 1;
-			err = -ENOMEM;
-			goto fail;
-		}
-
-		if (i == 0)
-			err = prepare_uptodate_page(inode, pages[i], pos,
-						    force_uptodate);
-		if (!err && i == num_pages - 1)
-			err = prepare_uptodate_page(inode, pages[i],
-						    pos + write_bytes, false);
-		if (err) {
-			put_page(pages[i]);
-			if (err == -EAGAIN) {
-				err = 0;
-				goto again;
-			}
-			faili = i - 1;
-			goto fail;
+			ret = -EAGAIN;
+			goto out;
 		}
-		wait_on_page_writeback(pages[i]);
 	}
-
-	return 0;
-fail:
-	while (faili >= 0) {
-		unlock_page(pages[faili]);
-		put_page(pages[faili]);
-		faili--;
-	}
-	return err;
-
+out:
+	if (page)
+		unlock_page(page);
+	*pagep = page;
+	return ret;
 }
 
 static int btrfs_find_new_delalloc_bytes(struct btrfs_inode *inode,
@@ -1502,7 +1454,7 @@ int btrfs_file_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
                         fs_info->sectorsize);
         bim->extent_locked = false;
         iomap->type = IOMAP_DELALLOC;
-        iomap->flags = IOMAP_F_NEW;
+        iomap->flags = IOMAP_F_NEW | IOMAP_F_NOBH;
 
 	extent_changeset_release(bim->data_reserved);
         /* Reserve data/quota space */
@@ -1526,7 +1478,7 @@ int btrfs_file_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
                                         sector_offset,
                                         fs_info->sectorsize);
                         iomap->type = IOMAP_UNWRITTEN;
-                        iomap->flags = 0;
+                        iomap->flags &= ~IOMAP_F_NEW;
                 } else {
                         return ret;
                 }
@@ -1543,6 +1495,20 @@ int btrfs_file_iomap_begin(struct inode *inode, loff_t pos, loff_t length,
         }
 
 	bim->extent_locked = 0;
+
+	if (pos < inode->i_size) {
+		ret = prepare_uptodate_page(inode, pos, &bim->first_page);
+		if (ret)
+			goto release;
+	}
+
+	if ((length > PAGE_SIZE) &&
+			(round_down(length + pos, PAGE_SIZE) < inode->i_size)) {
+		ret = prepare_uptodate_page(inode, pos + length, &bim->last_page);
+		if (ret)
+			goto release;
+	}
+
 again:
         bim->extent_locked = lock_and_cleanup_extent(BTRFS_I(inode),
                         pos, write_bytes, &bim->lockstart,
@@ -1597,6 +1563,16 @@ int btrfs_file_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 
 	dirty_sectors = BTRFS_BYTES_TO_BLKS(fs_info, dirty_sectors);
 
+	if (bim->first_page) {
+		put_page(bim->first_page);
+		bim->first_page = NULL;
+	}
+
+	if (bim->last_page) {
+		put_page(bim->last_page);
+		bim->last_page = NULL;
+	}
+
 	if (unlikely(copied == 0))
 		dirty_sectors = 0;
 	else
diff --git a/fs/btrfs/iomap.h b/fs/btrfs/iomap.h
index ac34b3412f64..f62e3ee6d4de 100644
--- a/fs/btrfs/iomap.h
+++ b/fs/btrfs/iomap.h
@@ -14,6 +14,7 @@ struct btrfs_iomap {
 	int extent_locked;
 	struct extent_state *cached_state;
 	struct extent_changeset *data_reserved;
+	struct page *first_page, *last_page;
 };
 
 #endif
-- 
2.14.2


  parent reply	other threads:[~2017-11-17 17:45 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-17 17:44 [RFC PATCH 0/8] btrfs iomap support Goldwyn Rodrigues
2017-11-17 17:44 ` [RFC PATCH 1/8] btrfs: use iocb for __btrfs_buffered_write Goldwyn Rodrigues
2018-04-10 16:19   ` David Sterba
2018-05-22  6:40   ` Misono Tomohiro
2018-05-22 10:03     ` David Sterba
2017-11-17 17:44 ` [RFC PATCH 2/8] fs: Add inode_extend_page() Goldwyn Rodrigues
2017-11-17 17:44 ` [RFC PATCH 3/8] fs: Introduce IOMAP_F_NOBH Goldwyn Rodrigues
2017-11-17 17:44 ` [RFC PATCH 4/8] btrfs: Introduce btrfs_iomap Goldwyn Rodrigues
2017-11-17 17:44 ` [RFC PATCH 5/8] btrfs: use iomap to perform buffered writes Goldwyn Rodrigues
2017-11-17 17:44 ` Goldwyn Rodrigues [this message]
2017-11-17 17:44 ` [RFC PATCH 7/8] fs: iomap->prepare_pages() to set directives specific for the page Goldwyn Rodrigues
2017-11-17 17:44 ` Goldwyn Rodrigues
2017-11-17 17:44 ` [RFC PATCH 8/8] fs: Introduce iomap->dirty_page() Goldwyn Rodrigues
2017-11-17 17:44 ` [RFC PATCH 8/8] iomap: " Goldwyn Rodrigues
2017-11-17 18:45 ` [RFC PATCH 0/8] btrfs iomap support Nikolay Borisov
2017-11-17 23:07   ` Goldwyn Rodrigues

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171117174456.13393-7-rgoldwyn@suse.de \
    --to=rgoldwyn@suse.de \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=rgoldwyn@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).