aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2012-02-15 10:23:57 -0500
committerDavid Sterba <dsterba@suse.cz>2012-02-15 10:40:25 -0500
commit87826df0ec36fc28884b4ddbb3f3af41c4c2008f (patch)
tree7d95bf1ff03c82805903330a279a67642be68699 /fs/btrfs/inode.c
parenta7e221e9002306a753d6f78b4060edabce402033 (diff)
btrfs: delalloc for page dirtied out-of-band in fixup worker
We encountered an issue that was easily observable on s/390 systems but could really happen anywhere. The timing just seemed to hit reliably on s/390 with limited memory. The gist is that when an unexpected set_page_dirty() happened, we'd run into the BUG() in btrfs_writepage_fixup_worker since it wasn't properly set up for delalloc. This patch does the following: - Performs the missing delalloc in the fixup worker - Allow the start hook to return -EBUSY which informs __extent_writepage that it should mark the page skipped and not to redirty it. This is required since the fixup worker can fail with -ENOSPC and the page will have already been redirtied. That causes an Oops in drop_outstanding_extents later. Retrying the fixup worker could lead to an infinite loop. Deferring the page redirty also saves us some cycles since the page would be stuck in a resubmit-redirty loop until the fixup worker completes. It's not harmful, just wasteful. - If the fixup worker fails, we mark the page and mapping as errored, and end the writeback, similar to what we would do had the page actually been submitted to writeback. Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 7405753ec5d..bf392e53261 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1555,6 +1555,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
1555 struct inode *inode; 1555 struct inode *inode;
1556 u64 page_start; 1556 u64 page_start;
1557 u64 page_end; 1557 u64 page_end;
1558 int ret;
1558 1559
1559 fixup = container_of(work, struct btrfs_writepage_fixup, work); 1560 fixup = container_of(work, struct btrfs_writepage_fixup, work);
1560 page = fixup->page; 1561 page = fixup->page;
@@ -1582,12 +1583,21 @@ again:
1582 page_end, &cached_state, GFP_NOFS); 1583 page_end, &cached_state, GFP_NOFS);
1583 unlock_page(page); 1584 unlock_page(page);
1584 btrfs_start_ordered_extent(inode, ordered, 1); 1585 btrfs_start_ordered_extent(inode, ordered, 1);
1586 btrfs_put_ordered_extent(ordered);
1585 goto again; 1587 goto again;
1586 } 1588 }
1587 1589
1588 BUG(); 1590 ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
1591 if (ret) {
1592 mapping_set_error(page->mapping, ret);
1593 end_extent_writepage(page, ret, page_start, page_end);
1594 ClearPageChecked(page);
1595 goto out;
1596 }
1597
1589 btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state); 1598 btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state);
1590 ClearPageChecked(page); 1599 ClearPageChecked(page);
1600 set_page_dirty(page);
1591out: 1601out:
1592 unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end, 1602 unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end,
1593 &cached_state, GFP_NOFS); 1603 &cached_state, GFP_NOFS);
@@ -1630,7 +1640,7 @@ static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
1630 fixup->work.func = btrfs_writepage_fixup_worker; 1640 fixup->work.func = btrfs_writepage_fixup_worker;
1631 fixup->page = page; 1641 fixup->page = page;
1632 btrfs_queue_worker(&root->fs_info->fixup_workers, &fixup->work); 1642 btrfs_queue_worker(&root->fs_info->fixup_workers, &fixup->work);
1633 return -EAGAIN; 1643 return -EBUSY;
1634} 1644}
1635 1645
1636static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, 1646static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,