@@ -1293,6 +1293,20 @@ int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end,
cached_state, mask);
}
+static int set_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end,
+ struct extent_state **cached_state, gfp_t mask)
+{
+ return set_extent_bit(tree, start, end, EXTENT_WRITEBACK, NULL,
+ cached_state, mask);
+}
+
+static int clear_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end,
+ struct extent_state **cached_state, gfp_t mask)
+{
+ return clear_extent_bit(tree, start, end, EXTENT_WRITEBACK, 1, 0,
+ cached_state, mask);
+}
+
/*
* either insert or lock state struct between start and end use mask to tell
* us if waiting is desired.
@@ -1399,6 +1413,7 @@ static int set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end)
page_cache_release(page);
index++;
}
+ set_extent_writeback(tree, start, end, NULL, GFP_NOFS);
return 0;
}
@@ -1966,6 +1981,16 @@ static void check_page_locked(struct extent_io_tree *tree, struct page *page)
}
}
+static void check_page_writeback(struct extent_io_tree *tree, struct page *page)
+{
+ u64 start = page_offset(page);
+ u64 end = start + PAGE_CACHE_SIZE - 1;
+
+ if (!test_range_bit(tree, start, end, EXTENT_WRITEBACK, 0, NULL))
+ end_page_writeback(page);
+}
+
+/*
* When IO fails, either with EIO or csum verification fails, we
* try other mirrors that might have a good copy of the data. This
* io_failure_record is used to record state as we go through all the
@@ -2378,6 +2403,32 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
return 0;
}
+static void clear_extent_and_page_writeback(struct address_space *mapping,
+ struct extent_io_tree *tree,
+ struct btrfs_io_bio *io_bio)
+{
+ struct page *page;
+ pgoff_t index;
+ u64 offset, len;
+
+ offset = io_bio->start_offset;
+ len = io_bio->len;
+
+ clear_extent_writeback(tree, offset, offset + len - 1, NULL,
+ GFP_ATOMIC);
+
+ index = offset >> PAGE_CACHE_SHIFT;
+ while (offset < io_bio->start_offset + len) {
+ page = find_get_page(mapping, index);
+ check_page_writeback(tree, page);
+ page_cache_release(page);
+ index++;
+ offset += page_offset(page) + PAGE_CACHE_SIZE - offset;
+ }
+
+ unlock_extent(tree, io_bio->start_offset, io_bio->start_offset + len - 1);
+}
+
/*
* after a writepage IO is done, we need to:
* clear the uptodate bits on error
@@ -2389,6 +2440,9 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
*/
static void end_bio_extent_writepage(struct bio *bio, int err)
{
+ struct address_space *mapping = bio->bi_io_vec->bv_page->mapping;
+ struct extent_io_tree *tree = &BTRFS_I(mapping->host)->io_tree;
+ struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
u64 start;
u64 end;
@@ -2413,8 +2467,8 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
bvec->bv_offset, bvec->bv_len);
}
- start = page_offset(page);
- end = start + bvec->bv_offset + bvec->bv_len - 1;
+ start = page_offset(page) + bvec->bv_offset;
+ end = start + bvec->bv_len - 1;
if (--bvec >= bio->bi_io_vec)
prefetchw(&bvec->bv_page->flags);
@@ -2422,9 +2476,10 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
if (end_extent_writepage(page, err, start, end))
continue;
- end_page_writeback(page);
} while (bvec >= bio->bi_io_vec);
+ clear_extent_and_page_writeback(mapping, tree, io_bio);
+
bio_put(bio);
}
@@ -3151,6 +3206,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
u64 last_byte = i_size_read(inode);
u64 block_start;
u64 iosize;
+ u64 unlock_start = start;
sector_t sector;
struct extent_state *cached_state = NULL;
struct extent_map *em;
@@ -3233,6 +3289,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
/* File system has been set read-only */
if (ret) {
SetPageError(page);
+ unlock_start = page_end + 1;
goto done;
}
/*
@@ -3268,10 +3325,14 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
goto done_unlocked;
}
}
+
+ lock_extent(tree, start, page_end);
+
if (tree->ops && tree->ops->writepage_start_hook) {
ret = tree->ops->writepage_start_hook(page, start,
page_end);
if (ret) {
+ unlock_extent(tree, start, page_end);
/* Fixup worker will requeue */
if (ret == -EBUSY)
wbc->pages_skipped++;
@@ -3292,9 +3353,11 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
end = page_end;
if (last_byte <= start) {
+ unlock_extent(tree, start, page_end);
if (tree->ops && tree->ops->writepage_end_io_hook)
tree->ops->writepage_end_io_hook(page, start,
page_end, NULL, 1);
+ unlock_start = page_end + 1;
goto done;
}
@@ -3302,9 +3365,11 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
while (cur <= end) {
if (cur >= last_byte) {
+ unlock_extent(tree, unlock_start, page_end);
if (tree->ops && tree->ops->writepage_end_io_hook)
tree->ops->writepage_end_io_hook(page, cur,
page_end, NULL, 1);
+ unlock_start = page_end + 1;
break;
}
em = epd->get_extent(inode, page, pg_offset, cur,
@@ -3332,6 +3397,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
*/
if (compressed || block_start == EXTENT_MAP_HOLE ||
block_start == EXTENT_MAP_INLINE) {
+ unlock_extent(tree, unlock_start, cur + iosize - 1);
/*
* end_io notification does not happen here for
* compressed extents
@@ -3351,6 +3417,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
cur += iosize;
pg_offset += iosize;
+ unlock_start = cur;
continue;
}
/* leave this out until we have a page_mkwrite call */
@@ -3397,6 +3464,9 @@ done:
set_page_writeback(page);
end_page_writeback(page);
}
+ if (unlock_start <= page_end)
+ unlock_extent(tree, unlock_start, page_end);
+
unlock_page(page);
done_unlocked:
This commit brings back functions that set/clear EXTENT_WRITEBACK bits. These are required to reliably clear PG_writeback page flag. Signed-off-by: Chandan Rajendra <chandan@linux.vnet.ibm.com> --- fs/btrfs/extent_io.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 3 deletions(-)