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 2104 return ret; 2105 2105 } 2106 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 + 2107 2117 /* 2108 2118 * the writepage semantics are similar to regular writepage. extent 2109 2119 * records are inserted to lock ranges in the tree, and as dirty areas ··· 2183 2173 delalloc_end = 0; 2184 2174 page_started = 0; 2185 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 + 2186 2182 while (delalloc_end < page_end) { 2187 2183 nr_delalloc = find_lock_delalloc_range(inode, tree, 2188 2184 page, ··· 2210 2194 */ 2211 2195 if (page_started) { 2212 2196 ret = 0; 2213 - goto update_nr_written; 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; 2214 2204 } 2215 2205 } 2216 2206 lock_extent(tree, start, page_end, GFP_NOFS); ··· 2229 2207 if (ret == -EAGAIN) { 2230 2208 unlock_extent(tree, start, page_end, GFP_NOFS); 2231 2209 redirty_page_for_writepage(wbc, page); 2210 + update_nr_written(page, wbc, nr_written); 2232 2211 unlock_page(page); 2233 2212 ret = 0; 2234 - goto update_nr_written; 2213 + goto done_unlocked; 2235 2214 } 2236 2215 } 2237 2216 2238 - nr_written++; 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); 2239 2222 2240 2223 end = page_end; 2241 2224 if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) ··· 2372 2345 unlock_extent(tree, unlock_start, page_end, GFP_NOFS); 2373 2346 unlock_page(page); 2374 2347 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; 2348 + done_unlocked: 2349 + 2380 2350 return 0; 2381 2351 } 2382 2352