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>

+32 -8
+32 -8
fs/btrfs/extent_io.c
··· 2104 return ret; 2105 } 2106 2107 /* 2108 * the writepage semantics are similar to regular writepage. extent 2109 * records are inserted to lock ranges in the tree, and as dirty areas ··· 2183 delalloc_end = 0; 2184 page_started = 0; 2185 if (!epd->extent_locked) { 2186 while (delalloc_end < page_end) { 2187 nr_delalloc = find_lock_delalloc_range(inode, tree, 2188 page, ··· 2210 */ 2211 if (page_started) { 2212 ret = 0; 2213 - goto update_nr_written; 2214 } 2215 } 2216 lock_extent(tree, start, page_end, GFP_NOFS); ··· 2229 if (ret == -EAGAIN) { 2230 unlock_extent(tree, start, page_end, GFP_NOFS); 2231 redirty_page_for_writepage(wbc, page); 2232 unlock_page(page); 2233 ret = 0; 2234 - goto update_nr_written; 2235 } 2236 } 2237 2238 - nr_written++; 2239 2240 end = page_end; 2241 if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) ··· 2372 unlock_extent(tree, unlock_start, page_end, GFP_NOFS); 2373 unlock_page(page); 2374 2375 - update_nr_written: 2376 - wbc->nr_to_write -= nr_written; 2377 - if (wbc->range_cyclic || (wbc->nr_to_write > 0 && 2378 - wbc->range_start == 0 && wbc->range_end == LLONG_MAX)) 2379 - page->mapping->writeback_index = page->index + nr_written; 2380 return 0; 2381 } 2382
··· 2104 return ret; 2105 } 2106 2107 + static 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 + 2117 /* 2118 * the writepage semantics are similar to regular writepage. extent 2119 * records are inserted to lock ranges in the tree, and as dirty areas ··· 2173 delalloc_end = 0; 2174 page_started = 0; 2175 if (!epd->extent_locked) { 2176 + /* 2177 + * make sure the wbc mapping index is at least updated 2178 + * to this page. 2179 + */ 2180 + update_nr_written(page, wbc, 0); 2181 + 2182 while (delalloc_end < page_end) { 2183 nr_delalloc = find_lock_delalloc_range(inode, tree, 2184 page, ··· 2194 */ 2195 if (page_started) { 2196 ret = 0; 2197 + /* 2198 + * we've unlocked the page, so we can't update 2199 + * the mapping's writeback index, just update 2200 + * nr_to_write. 2201 + */ 2202 + wbc->nr_to_write -= nr_written; 2203 + goto done_unlocked; 2204 } 2205 } 2206 lock_extent(tree, start, page_end, GFP_NOFS); ··· 2207 if (ret == -EAGAIN) { 2208 unlock_extent(tree, start, page_end, GFP_NOFS); 2209 redirty_page_for_writepage(wbc, page); 2210 + update_nr_written(page, wbc, nr_written); 2211 unlock_page(page); 2212 ret = 0; 2213 + goto done_unlocked; 2214 } 2215 } 2216 2217 + /* 2218 + * we don't want to touch the inode after unlocking the page, 2219 + * so we update the mapping writeback index now 2220 + */ 2221 + update_nr_written(page, wbc, nr_written + 1); 2222 2223 end = page_end; 2224 if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) ··· 2345 unlock_extent(tree, unlock_start, page_end, GFP_NOFS); 2346 unlock_page(page); 2347 2348 + done_unlocked: 2349 + 2350 return 0; 2351 } 2352