diff options
author | Jeff Mahoney <jeffm@suse.com> | 2005-12-14 14:38:05 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-12-14 21:56:08 -0500 |
commit | 2499604960fff307fe99ff4d4363c50eaa69235a (patch) | |
tree | 94d329a760e82deb21930c986ca54d479c6c5930 | |
parent | 5d5e815618c4a8b53806845268c951201d14af6e (diff) |
[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>
-rw-r--r-- | fs/reiserfs/inode.c | 26 |
1 files changed, 18 insertions, 8 deletions
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 0a044ad98885..a5e3a0ddbe53 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -32,6 +32,7 @@ void reiserfs_delete_inode(struct inode *inode) | |||
32 | JOURNAL_PER_BALANCE_CNT * 2 + | 32 | JOURNAL_PER_BALANCE_CNT * 2 + |
33 | 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); | 33 | 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); |
34 | struct reiserfs_transaction_handle th; | 34 | struct reiserfs_transaction_handle th; |
35 | int err; | ||
35 | 36 | ||
36 | truncate_inode_pages(&inode->i_data, 0); | 37 | truncate_inode_pages(&inode->i_data, 0); |
37 | 38 | ||
@@ -49,15 +50,13 @@ void reiserfs_delete_inode(struct inode *inode) | |||
49 | } | 50 | } |
50 | reiserfs_update_inode_transaction(inode); | 51 | reiserfs_update_inode_transaction(inode); |
51 | 52 | ||
52 | if (reiserfs_delete_object(&th, inode)) { | 53 | err = reiserfs_delete_object(&th, inode); |
53 | up(&inode->i_sem); | ||
54 | goto out; | ||
55 | } | ||
56 | 54 | ||
57 | /* Do quota update inside a transaction for journaled quotas. We must do that | 55 | /* Do quota update inside a transaction for journaled quotas. We must do that |
58 | * after delete_object so that quota updates go into the same transaction as | 56 | * after delete_object so that quota updates go into the same transaction as |
59 | * stat data deletion */ | 57 | * stat data deletion */ |
60 | DQUOT_FREE_INODE(inode); | 58 | if (!err) |
59 | DQUOT_FREE_INODE(inode); | ||
61 | 60 | ||
62 | if (journal_end(&th, inode->i_sb, jbegin_count)) { | 61 | if (journal_end(&th, inode->i_sb, jbegin_count)) { |
63 | up(&inode->i_sem); | 62 | up(&inode->i_sem); |
@@ -66,6 +65,12 @@ void reiserfs_delete_inode(struct inode *inode) | |||
66 | 65 | ||
67 | up(&inode->i_sem); | 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 | /* all items of file are deleted, so we can remove "save" link */ | 74 | /* all items of file are deleted, so we can remove "save" link */ |
70 | remove_save_link(inode, 0 /* not truncate */ ); /* we can't do anything | 75 | remove_save_link(inode, 0 /* not truncate */ ); /* we can't do anything |
71 | * about an error here */ | 76 | * about an error here */ |
@@ -2099,6 +2104,7 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) | |||
2099 | struct page *page = NULL; | 2104 | struct page *page = NULL; |
2100 | int error; | 2105 | int error; |
2101 | struct buffer_head *bh = NULL; | 2106 | struct buffer_head *bh = NULL; |
2107 | int err2; | ||
2102 | 2108 | ||
2103 | reiserfs_write_lock(p_s_inode->i_sb); | 2109 | reiserfs_write_lock(p_s_inode->i_sb); |
2104 | 2110 | ||
@@ -2136,14 +2142,18 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) | |||
2136 | transaction of truncating gets committed - on reboot the file | 2142 | transaction of truncating gets committed - on reboot the file |
2137 | either appears truncated properly or not truncated at all */ | 2143 | either appears truncated properly or not truncated at all */ |
2138 | add_save_link(&th, p_s_inode, 1); | 2144 | add_save_link(&th, p_s_inode, 1); |
2139 | error = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps); | 2145 | err2 = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps); |
2140 | if (error) | ||
2141 | goto out; | ||
2142 | error = | 2146 | error = |
2143 | journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); | 2147 | journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); |
2144 | if (error) | 2148 | if (error) |
2145 | goto out; | 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 | if (update_timestamps) { | 2157 | if (update_timestamps) { |
2148 | error = remove_save_link(p_s_inode, 1 /* truncate */ ); | 2158 | error = remove_save_link(p_s_inode, 1 /* truncate */ ); |
2149 | if (error) | 2159 | if (error) |