diff options
Diffstat (limited to 'fs/ext3/inode.c')
-rw-r--r-- | fs/ext3/inode.c | 80 |
1 files changed, 43 insertions, 37 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index cc55cecf9fbc..5e0faf4cda79 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -1166,9 +1166,25 @@ static int walk_page_buffers( handle_t *handle, | |||
1166 | static int do_journal_get_write_access(handle_t *handle, | 1166 | static int do_journal_get_write_access(handle_t *handle, |
1167 | struct buffer_head *bh) | 1167 | struct buffer_head *bh) |
1168 | { | 1168 | { |
1169 | int dirty = buffer_dirty(bh); | ||
1170 | int ret; | ||
1171 | |||
1169 | if (!buffer_mapped(bh) || buffer_freed(bh)) | 1172 | if (!buffer_mapped(bh) || buffer_freed(bh)) |
1170 | return 0; | 1173 | return 0; |
1171 | return ext3_journal_get_write_access(handle, bh); | 1174 | /* |
1175 | * __block_prepare_write() could have dirtied some buffers. Clean | ||
1176 | * the dirty bit as jbd2_journal_get_write_access() could complain | ||
1177 | * otherwise about fs integrity issues. Setting of the dirty bit | ||
1178 | * by __block_prepare_write() isn't a real problem here as we clear | ||
1179 | * the bit before releasing a page lock and thus writeback cannot | ||
1180 | * ever write the buffer. | ||
1181 | */ | ||
1182 | if (dirty) | ||
1183 | clear_buffer_dirty(bh); | ||
1184 | ret = ext3_journal_get_write_access(handle, bh); | ||
1185 | if (!ret && dirty) | ||
1186 | ret = ext3_journal_dirty_metadata(handle, bh); | ||
1187 | return ret; | ||
1172 | } | 1188 | } |
1173 | 1189 | ||
1174 | /* | 1190 | /* |
@@ -1641,10 +1657,7 @@ static int ext3_writeback_writepage(struct page *page, | |||
1641 | goto out_fail; | 1657 | goto out_fail; |
1642 | } | 1658 | } |
1643 | 1659 | ||
1644 | if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) | 1660 | ret = block_write_full_page(page, ext3_get_block, wbc); |
1645 | ret = nobh_writepage(page, ext3_get_block, wbc); | ||
1646 | else | ||
1647 | ret = block_write_full_page(page, ext3_get_block, wbc); | ||
1648 | 1661 | ||
1649 | err = ext3_journal_stop(handle); | 1662 | err = ext3_journal_stop(handle); |
1650 | if (!ret) | 1663 | if (!ret) |
@@ -1949,17 +1962,6 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, | |||
1949 | length = blocksize - (offset & (blocksize - 1)); | 1962 | length = blocksize - (offset & (blocksize - 1)); |
1950 | iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); | 1963 | iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); |
1951 | 1964 | ||
1952 | /* | ||
1953 | * For "nobh" option, we can only work if we don't need to | ||
1954 | * read-in the page - otherwise we create buffers to do the IO. | ||
1955 | */ | ||
1956 | if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) && | ||
1957 | ext3_should_writeback_data(inode) && PageUptodate(page)) { | ||
1958 | zero_user(page, offset, length); | ||
1959 | set_page_dirty(page); | ||
1960 | goto unlock; | ||
1961 | } | ||
1962 | |||
1963 | if (!page_has_buffers(page)) | 1965 | if (!page_has_buffers(page)) |
1964 | create_empty_buffers(page, blocksize, 0); | 1966 | create_empty_buffers(page, blocksize, 0); |
1965 | 1967 | ||
@@ -2311,27 +2313,6 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, | |||
2311 | depth); | 2313 | depth); |
2312 | 2314 | ||
2313 | /* | 2315 | /* |
2314 | * We've probably journalled the indirect block several | ||
2315 | * times during the truncate. But it's no longer | ||
2316 | * needed and we now drop it from the transaction via | ||
2317 | * journal_revoke(). | ||
2318 | * | ||
2319 | * That's easy if it's exclusively part of this | ||
2320 | * transaction. But if it's part of the committing | ||
2321 | * transaction then journal_forget() will simply | ||
2322 | * brelse() it. That means that if the underlying | ||
2323 | * block is reallocated in ext3_get_block(), | ||
2324 | * unmap_underlying_metadata() will find this block | ||
2325 | * and will try to get rid of it. damn, damn. | ||
2326 | * | ||
2327 | * If this block has already been committed to the | ||
2328 | * journal, a revoke record will be written. And | ||
2329 | * revoke records must be emitted *before* clearing | ||
2330 | * this block's bit in the bitmaps. | ||
2331 | */ | ||
2332 | ext3_forget(handle, 1, inode, bh, bh->b_blocknr); | ||
2333 | |||
2334 | /* | ||
2335 | * Everything below this this pointer has been | 2316 | * Everything below this this pointer has been |
2336 | * released. Now let this top-of-subtree go. | 2317 | * released. Now let this top-of-subtree go. |
2337 | * | 2318 | * |
@@ -2354,6 +2335,31 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, | |||
2354 | truncate_restart_transaction(handle, inode); | 2335 | truncate_restart_transaction(handle, inode); |
2355 | } | 2336 | } |
2356 | 2337 | ||
2338 | /* | ||
2339 | * We've probably journalled the indirect block several | ||
2340 | * times during the truncate. But it's no longer | ||
2341 | * needed and we now drop it from the transaction via | ||
2342 | * journal_revoke(). | ||
2343 | * | ||
2344 | * That's easy if it's exclusively part of this | ||
2345 | * transaction. But if it's part of the committing | ||
2346 | * transaction then journal_forget() will simply | ||
2347 | * brelse() it. That means that if the underlying | ||
2348 | * block is reallocated in ext3_get_block(), | ||
2349 | * unmap_underlying_metadata() will find this block | ||
2350 | * and will try to get rid of it. damn, damn. Thus | ||
2351 | * we don't allow a block to be reallocated until | ||
2352 | * a transaction freeing it has fully committed. | ||
2353 | * | ||
2354 | * We also have to make sure journal replay after a | ||
2355 | * crash does not overwrite non-journaled data blocks | ||
2356 | * with old metadata when the block got reallocated for | ||
2357 | * data. Thus we have to store a revoke record for a | ||
2358 | * block in the same transaction in which we free the | ||
2359 | * block. | ||
2360 | */ | ||
2361 | ext3_forget(handle, 1, inode, bh, bh->b_blocknr); | ||
2362 | |||
2357 | ext3_free_blocks(handle, inode, nr, 1); | 2363 | ext3_free_blocks(handle, inode, nr, 1); |
2358 | 2364 | ||
2359 | if (parent_bh) { | 2365 | if (parent_bh) { |