| From 3a9b0aea089a6b0df0dc16f2040c1719571929db Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Mon, 23 Nov 2009 07:17:34 -0500 |
| Subject: [PATCH 63/85] ext4: make sure directory and symlink blocks are revoked |
| |
| (cherry picked from commit 50689696867d95b38d9c7be640a311494a04fb86) |
| |
| When an inode gets unlinked, the functions ext4_clear_blocks() and |
| ext4_remove_blocks() call ext4_forget() for all the buffer heads |
| corresponding to the deleted inode's data blocks. If the inode is a |
| directory or a symlink, the is_metadata parameter must be non-zero so |
| ext4_forget() will revoke them via jbd2_journal_revoke(). Otherwise, |
| if these blocks are reused for a data file, and the system crashes |
| before a journal checkpoint, the journal replay could end up |
| corrupting these data blocks. |
| |
| Thanks to Curt Wohlgemuth for pointing out potential problems in this |
| area. |
| |
| Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| fs/ext4/extents.c | 2 +- |
| fs/ext4/inode.c | 6 ++++-- |
| 2 files changed, 5 insertions(+), 3 deletions(-) |
| |
| --- a/fs/ext4/extents.c |
| +++ b/fs/ext4/extents.c |
| @@ -2055,7 +2055,7 @@ static int ext4_remove_blocks(handle_t * |
| ext_debug("free last %u blocks starting %llu\n", num, start); |
| for (i = 0; i < num; i++) { |
| bh = sb_find_get_block(inode->i_sb, start + i); |
| - ext4_forget(handle, 0, inode, bh, start + i); |
| + ext4_forget(handle, metadata, inode, bh, start + i); |
| } |
| ext4_free_blocks(handle, inode, start, num, metadata); |
| } else if (from == le32_to_cpu(ex->ee_block) |
| --- a/fs/ext4/inode.c |
| +++ b/fs/ext4/inode.c |
| @@ -4110,6 +4110,8 @@ static void ext4_clear_blocks(handle_t * |
| __le32 *last) |
| { |
| __le32 *p; |
| + int is_metadata = S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode); |
| + |
| if (try_to_extend_transaction(handle, inode)) { |
| if (bh) { |
| BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
| @@ -4140,11 +4142,11 @@ static void ext4_clear_blocks(handle_t * |
| |
| *p = 0; |
| tbh = sb_find_get_block(inode->i_sb, nr); |
| - ext4_forget(handle, 0, inode, tbh, nr); |
| + ext4_forget(handle, is_metadata, inode, tbh, nr); |
| } |
| } |
| |
| - ext4_free_blocks(handle, inode, block_to_free, count, 0); |
| + ext4_free_blocks(handle, inode, block_to_free, count, is_metadata); |
| } |
| |
| /** |