diff options
author | Lepton Wu <ytht.net@gmail.com> | 2007-10-17 02:30:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:58 -0400 |
commit | fb46f341d9868fe993626536c7449c2a1aec62a3 (patch) | |
tree | 869b426000d9c4689110e08ff9419901a958ec7c | |
parent | b9ec0339d8e22cadf2d9d1b010b51dc53837dfb0 (diff) |
reiserfs: workaround for dead loop in finish_unfinished
There is possible dead loop in finish_unfinished function.
In most situation, the call chain iput -> ... -> reiserfs_delete_inode ->
remove_save_link will success. But for some reason such as data
corruption, reiserfs_delete_inode fails on reiserfs_do_truncate ->
search_for_position_by_key.
Then remove_save_link won't be called. We always get the same
"save_link_key" in the while loop in finish_unfinished function. The
following patch adds a check for the possible dead loop and just remove
save link when deap loop.
[akpm@linux-foundation.org: cleanups]
Signed-off-by: Lepton Wu <ytht.net@gmail.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: "Vladimir V. Saveliev" <vs@namesys.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/reiserfs/super.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index edfd74f9f7e4..b82897ae090b 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -145,7 +145,7 @@ static int finish_unfinished(struct super_block *s) | |||
145 | { | 145 | { |
146 | INITIALIZE_PATH(path); | 146 | INITIALIZE_PATH(path); |
147 | struct cpu_key max_cpu_key, obj_key; | 147 | struct cpu_key max_cpu_key, obj_key; |
148 | struct reiserfs_key save_link_key; | 148 | struct reiserfs_key save_link_key, last_inode_key; |
149 | int retval = 0; | 149 | int retval = 0; |
150 | struct item_head *ih; | 150 | struct item_head *ih; |
151 | struct buffer_head *bh; | 151 | struct buffer_head *bh; |
@@ -166,6 +166,8 @@ static int finish_unfinished(struct super_block *s) | |||
166 | set_cpu_key_k_offset(&max_cpu_key, ~0U); | 166 | set_cpu_key_k_offset(&max_cpu_key, ~0U); |
167 | max_cpu_key.key_length = 3; | 167 | max_cpu_key.key_length = 3; |
168 | 168 | ||
169 | memset(&last_inode_key, 0, sizeof(last_inode_key)); | ||
170 | |||
169 | #ifdef CONFIG_QUOTA | 171 | #ifdef CONFIG_QUOTA |
170 | /* Needed for iput() to work correctly and not trash data */ | 172 | /* Needed for iput() to work correctly and not trash data */ |
171 | if (s->s_flags & MS_ACTIVE) { | 173 | if (s->s_flags & MS_ACTIVE) { |
@@ -278,8 +280,18 @@ static int finish_unfinished(struct super_block *s) | |||
278 | REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask; | 280 | REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask; |
279 | /* not completed unlink (rmdir) found */ | 281 | /* not completed unlink (rmdir) found */ |
280 | reiserfs_info(s, "Removing %k..", INODE_PKEY(inode)); | 282 | reiserfs_info(s, "Removing %k..", INODE_PKEY(inode)); |
281 | /* removal gets completed in iput */ | 283 | if (memcmp(&last_inode_key, INODE_PKEY(inode), |
282 | retval = 0; | 284 | sizeof(last_inode_key))){ |
285 | last_inode_key = *INODE_PKEY(inode); | ||
286 | /* removal gets completed in iput */ | ||
287 | retval = 0; | ||
288 | } else { | ||
289 | reiserfs_warning(s, "Dead loop in " | ||
290 | "finish_unfinished detected, " | ||
291 | "just remove save link\n"); | ||
292 | retval = remove_save_link_only(s, | ||
293 | &save_link_key, 0); | ||
294 | } | ||
283 | } | 295 | } |
284 | 296 | ||
285 | iput(inode); | 297 | iput(inode); |