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:
committed by
Linus Torvalds
parent
b9ec0339d8
commit
fb46f341d9
@@ -145,7 +145,7 @@ static int finish_unfinished(struct super_block *s)
|
|||||||
{
|
{
|
||||||
INITIALIZE_PATH(path);
|
INITIALIZE_PATH(path);
|
||||||
struct cpu_key max_cpu_key, obj_key;
|
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;
|
int retval = 0;
|
||||||
struct item_head *ih;
|
struct item_head *ih;
|
||||||
struct buffer_head *bh;
|
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);
|
set_cpu_key_k_offset(&max_cpu_key, ~0U);
|
||||||
max_cpu_key.key_length = 3;
|
max_cpu_key.key_length = 3;
|
||||||
|
|
||||||
|
memset(&last_inode_key, 0, sizeof(last_inode_key));
|
||||||
|
|
||||||
#ifdef CONFIG_QUOTA
|
#ifdef CONFIG_QUOTA
|
||||||
/* Needed for iput() to work correctly and not trash data */
|
/* Needed for iput() to work correctly and not trash data */
|
||||||
if (s->s_flags & MS_ACTIVE) {
|
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;
|
REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
|
||||||
/* not completed unlink (rmdir) found */
|
/* not completed unlink (rmdir) found */
|
||||||
reiserfs_info(s, "Removing %k..", INODE_PKEY(inode));
|
reiserfs_info(s, "Removing %k..", INODE_PKEY(inode));
|
||||||
/* removal gets completed in iput */
|
if (memcmp(&last_inode_key, INODE_PKEY(inode),
|
||||||
retval = 0;
|
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);
|
iput(inode);
|
||||||
|
|||||||
Reference in New Issue
Block a user