aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLepton Wu <ytht.net@gmail.com>2007-10-17 02:30:04 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 11:42:58 -0400
commitfb46f341d9868fe993626536c7449c2a1aec62a3 (patch)
tree869b426000d9c4689110e08ff9419901a958ec7c
parentb9ec0339d8e22cadf2d9d1b010b51dc53837dfb0 (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.c18
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);