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
next prev 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).