@@ -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
@@ -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