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>
This commit is contained in:
parent
b9ec0339d8
commit
fb46f341d9
|
@ -145,7 +145,7 @@ static int finish_unfinished(struct super_block *s)
|
|||
{
|
||||
INITIALIZE_PATH(path);
|
||||
struct cpu_key max_cpu_key, obj_key;
|
||||
struct reiserfs_key save_link_key;
|
||||
struct reiserfs_key save_link_key, last_inode_key;
|
||||
int retval = 0;
|
||||
struct item_head *ih;
|
||||
struct buffer_head *bh;
|
||||
|
@ -166,6 +166,8 @@ static int finish_unfinished(struct super_block *s)
|
|||
set_cpu_key_k_offset(&max_cpu_key, ~0U);
|
||||
max_cpu_key.key_length = 3;
|
||||
|
||||
memset(&last_inode_key, 0, sizeof(last_inode_key));
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
/* Needed for iput() to work correctly and not trash data */
|
||||
if (s->s_flags & MS_ACTIVE) {
|
||||
|
@ -278,8 +280,18 @@ static int finish_unfinished(struct super_block *s)
|
|||
REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
|
||||
/* not completed unlink (rmdir) found */
|
||||
reiserfs_info(s, "Removing %k..", INODE_PKEY(inode));
|
||||
if (memcmp(&last_inode_key, INODE_PKEY(inode),
|
||||
sizeof(last_inode_key))){
|
||||
last_inode_key = *INODE_PKEY(inode);
|
||||
/* removal gets completed in iput */
|
||||
retval = 0;
|
||||
} else {
|
||||
reiserfs_warning(s, "Dead loop in "
|
||||
"finish_unfinished detected, "
|
||||
"just remove save link\n");
|
||||
retval = remove_save_link_only(s,
|
||||
&save_link_key, 0);
|
||||
}
|
||||
}
|
||||
|
||||
iput(inode);
|
||||
|
|
Loading…
Reference in New Issue