Commit 2499604960fff307fe99ff4d4363c50eaa69235a
Committed by
Linus Torvalds
1 parent
5d5e815618
[PATCH] reiserfs: close open transactions on error path
The following patch fixes a bug where if the journal is aborted, it can leave a transaction open. The result will be a BUG when another code path attempts to start a transaction and will get a "nesting into different fs" error, since current->journal_info will be left non-NULL. Original fix against SUSE kernel by Chris Mason <mason@suse.com> Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 1 changed file with 18 additions and 8 deletions Side-by-side Diff
fs/reiserfs/inode.c
... | ... | @@ -32,6 +32,7 @@ |
32 | 32 | JOURNAL_PER_BALANCE_CNT * 2 + |
33 | 33 | 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); |
34 | 34 | struct reiserfs_transaction_handle th; |
35 | + int err; | |
35 | 36 | |
36 | 37 | truncate_inode_pages(&inode->i_data, 0); |
37 | 38 | |
38 | 39 | |
... | ... | @@ -49,15 +50,13 @@ |
49 | 50 | } |
50 | 51 | reiserfs_update_inode_transaction(inode); |
51 | 52 | |
52 | - if (reiserfs_delete_object(&th, inode)) { | |
53 | - up(&inode->i_sem); | |
54 | - goto out; | |
55 | - } | |
53 | + err = reiserfs_delete_object(&th, inode); | |
56 | 54 | |
57 | 55 | /* Do quota update inside a transaction for journaled quotas. We must do that |
58 | 56 | * after delete_object so that quota updates go into the same transaction as |
59 | 57 | * stat data deletion */ |
60 | - DQUOT_FREE_INODE(inode); | |
58 | + if (!err) | |
59 | + DQUOT_FREE_INODE(inode); | |
61 | 60 | |
62 | 61 | if (journal_end(&th, inode->i_sb, jbegin_count)) { |
63 | 62 | up(&inode->i_sem); |
... | ... | @@ -66,6 +65,12 @@ |
66 | 65 | |
67 | 66 | up(&inode->i_sem); |
68 | 67 | |
68 | + /* check return value from reiserfs_delete_object after | |
69 | + * ending the transaction | |
70 | + */ | |
71 | + if (err) | |
72 | + goto out; | |
73 | + | |
69 | 74 | /* all items of file are deleted, so we can remove "save" link */ |
70 | 75 | remove_save_link(inode, 0 /* not truncate */ ); /* we can't do anything |
71 | 76 | * about an error here */ |
... | ... | @@ -2099,6 +2104,7 @@ |
2099 | 2104 | struct page *page = NULL; |
2100 | 2105 | int error; |
2101 | 2106 | struct buffer_head *bh = NULL; |
2107 | + int err2; | |
2102 | 2108 | |
2103 | 2109 | reiserfs_write_lock(p_s_inode->i_sb); |
2104 | 2110 | |
2105 | 2111 | |
... | ... | @@ -2136,14 +2142,18 @@ |
2136 | 2142 | transaction of truncating gets committed - on reboot the file |
2137 | 2143 | either appears truncated properly or not truncated at all */ |
2138 | 2144 | add_save_link(&th, p_s_inode, 1); |
2139 | - error = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps); | |
2140 | - if (error) | |
2141 | - goto out; | |
2145 | + err2 = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps); | |
2142 | 2146 | error = |
2143 | 2147 | journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); |
2144 | 2148 | if (error) |
2145 | 2149 | goto out; |
2146 | 2150 | |
2151 | + /* check reiserfs_do_truncate after ending the transaction */ | |
2152 | + if (err2) { | |
2153 | + error = err2; | |
2154 | + goto out; | |
2155 | + } | |
2156 | + | |
2147 | 2157 | if (update_timestamps) { |
2148 | 2158 | error = remove_save_link(p_s_inode, 1 /* truncate */ ); |
2149 | 2159 | if (error) |