aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_io.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-04-20 15:50:09 -0400
committerChris Mason <chris.mason@oracle.com>2009-04-20 15:53:09 -0400
commit11c8349b4eb68f2b04cd8ece577377e6c0e5dd4b (patch)
treebaeaabbe0a10d903ba3e0d6ff90ae9934912fc21 /fs/btrfs/extent_io.c
parentd313d7a31a752c88f7288692bd98e66d0789779b (diff)
Btrfs: fix oops on page->mapping->host during writepage
The extent_io writepage call updates the writepage index in the inode as it makes progress. But, it was doing the update after unlocking the page, which isn't legal because page->mapping can't be trusted once the page is unlocked. This lead to an oops, especially common with compression turned on. The fix here is to update the writeback index before unlocking the page. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r--fs/btrfs/extent_io.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 5d66cb27e422..05a1c42e25bf 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2104,6 +2104,16 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
2104 return ret; 2104 return ret;
2105} 2105}
2106 2106
2107static noinline void update_nr_written(struct page *page,
2108 struct writeback_control *wbc,
2109 unsigned long nr_written)
2110{
2111 wbc->nr_to_write -= nr_written;
2112 if (wbc->range_cyclic || (wbc->nr_to_write > 0 &&
2113 wbc->range_start == 0 && wbc->range_end == LLONG_MAX))
2114 page->mapping->writeback_index = page->index + nr_written;
2115}
2116
2107/* 2117/*
2108 * the writepage semantics are similar to regular writepage. extent 2118 * the writepage semantics are similar to regular writepage. extent
2109 * records are inserted to lock ranges in the tree, and as dirty areas 2119 * records are inserted to lock ranges in the tree, and as dirty areas
@@ -2173,6 +2183,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
2173 delalloc_end = 0; 2183 delalloc_end = 0;
2174 page_started = 0; 2184 page_started = 0;
2175 if (!epd->extent_locked) { 2185 if (!epd->extent_locked) {
2186 /*
2187 * make sure the wbc mapping index is at least updated
2188 * to this page.
2189 */
2190 update_nr_written(page, wbc, 0);
2191
2176 while (delalloc_end < page_end) { 2192 while (delalloc_end < page_end) {
2177 nr_delalloc = find_lock_delalloc_range(inode, tree, 2193 nr_delalloc = find_lock_delalloc_range(inode, tree,
2178 page, 2194 page,
@@ -2194,7 +2210,13 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
2194 */ 2210 */
2195 if (page_started) { 2211 if (page_started) {
2196 ret = 0; 2212 ret = 0;
2197 goto update_nr_written; 2213 /*
2214 * we've unlocked the page, so we can't update
2215 * the mapping's writeback index, just update
2216 * nr_to_write.
2217 */
2218 wbc->nr_to_write -= nr_written;
2219 goto done_unlocked;
2198 } 2220 }
2199 } 2221 }
2200 lock_extent(tree, start, page_end, GFP_NOFS); 2222 lock_extent(tree, start, page_end, GFP_NOFS);
@@ -2207,13 +2229,18 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
2207 if (ret == -EAGAIN) { 2229 if (ret == -EAGAIN) {
2208 unlock_extent(tree, start, page_end, GFP_NOFS); 2230 unlock_extent(tree, start, page_end, GFP_NOFS);
2209 redirty_page_for_writepage(wbc, page); 2231 redirty_page_for_writepage(wbc, page);
2232 update_nr_written(page, wbc, nr_written);
2210 unlock_page(page); 2233 unlock_page(page);
2211 ret = 0; 2234 ret = 0;
2212 goto update_nr_written; 2235 goto done_unlocked;
2213 } 2236 }
2214 } 2237 }
2215 2238
2216 nr_written++; 2239 /*
2240 * we don't want to touch the inode after unlocking the page,
2241 * so we update the mapping writeback index now
2242 */
2243 update_nr_written(page, wbc, nr_written + 1);
2217 2244
2218 end = page_end; 2245 end = page_end;
2219 if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) 2246 if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0))
@@ -2345,11 +2372,8 @@ done:
2345 unlock_extent(tree, unlock_start, page_end, GFP_NOFS); 2372 unlock_extent(tree, unlock_start, page_end, GFP_NOFS);
2346 unlock_page(page); 2373 unlock_page(page);
2347 2374
2348update_nr_written: 2375done_unlocked:
2349 wbc->nr_to_write -= nr_written; 2376
2350 if (wbc->range_cyclic || (wbc->nr_to_write > 0 &&
2351 wbc->range_start == 0 && wbc->range_end == LLONG_MAX))
2352 page->mapping->writeback_index = page->index + nr_written;
2353 return 0; 2377 return 0;
2354} 2378}
2355 2379