|
@@ -2161,6 +2161,38 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
|
|
|
|
|
|
/* lots and lots of room for performance fixes in the end_bio funcs */
|
|
|
|
|
|
+int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
|
|
|
+{
|
|
|
+ int uptodate = (err == 0);
|
|
|
+ struct extent_io_tree *tree;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ tree = &BTRFS_I(page->mapping->host)->io_tree;
|
|
|
+
|
|
|
+ if (tree->ops && tree->ops->writepage_end_io_hook) {
|
|
|
+ ret = tree->ops->writepage_end_io_hook(page, start,
|
|
|
+ end, NULL, uptodate);
|
|
|
+ if (ret)
|
|
|
+ uptodate = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!uptodate && tree->ops &&
|
|
|
+ tree->ops->writepage_io_failed_hook) {
|
|
|
+ ret = tree->ops->writepage_io_failed_hook(NULL, page,
|
|
|
+ start, end, NULL);
|
|
|
+ /* Writeback already completed */
|
|
|
+ if (ret == 0)
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!uptodate) {
|
|
|
+ clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS);
|
|
|
+ ClearPageUptodate(page);
|
|
|
+ SetPageError(page);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* after a writepage IO is done, we need to:
|
|
|
* clear the uptodate bits on error
|
|
@@ -2172,13 +2204,11 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
|
|
|
*/
|
|
|
static void end_bio_extent_writepage(struct bio *bio, int err)
|
|
|
{
|
|
|
- int uptodate = err == 0;
|
|
|
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
|
|
|
struct extent_io_tree *tree;
|
|
|
u64 start;
|
|
|
u64 end;
|
|
|
int whole_page;
|
|
|
- int ret;
|
|
|
|
|
|
do {
|
|
|
struct page *page = bvec->bv_page;
|
|
@@ -2195,28 +2225,9 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
|
|
|
|
|
|
if (--bvec >= bio->bi_io_vec)
|
|
|
prefetchw(&bvec->bv_page->flags);
|
|
|
- if (tree->ops && tree->ops->writepage_end_io_hook) {
|
|
|
- ret = tree->ops->writepage_end_io_hook(page, start,
|
|
|
- end, NULL, uptodate);
|
|
|
- if (ret)
|
|
|
- uptodate = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (!uptodate && tree->ops &&
|
|
|
- tree->ops->writepage_io_failed_hook) {
|
|
|
- ret = tree->ops->writepage_io_failed_hook(bio, page,
|
|
|
- start, end, NULL);
|
|
|
- if (ret == 0) {
|
|
|
- uptodate = (err == 0);
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- if (!uptodate) {
|
|
|
- clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS);
|
|
|
- ClearPageUptodate(page);
|
|
|
- SetPageError(page);
|
|
|
- }
|
|
|
+ if (end_extent_writepage(page, err, start, end))
|
|
|
+ continue;
|
|
|
|
|
|
if (whole_page)
|
|
|
end_page_writeback(page);
|
|
@@ -2818,8 +2829,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
|
|
|
if (tree->ops && tree->ops->writepage_start_hook) {
|
|
|
ret = tree->ops->writepage_start_hook(page, start,
|
|
|
page_end);
|
|
|
- if (ret == -EAGAIN) {
|
|
|
- redirty_page_for_writepage(wbc, page);
|
|
|
+ if (ret) {
|
|
|
+ /* Fixup worker will requeue */
|
|
|
+ if (ret == -EBUSY)
|
|
|
+ wbc->pages_skipped++;
|
|
|
+ else
|
|
|
+ redirty_page_for_writepage(wbc, page);
|
|
|
update_nr_written(page, wbc, nr_written);
|
|
|
unlock_page(page);
|
|
|
ret = 0;
|