diff mbox

btrfs-progs: Fix a infinite loop when fixing nlink if file name conflicts twice.

Message ID 1424678404-5493-1-git-send-email-quwenruo@cn.fujitsu.com (mailing list archive)
State Accepted
Headers show

Commit Message

Qu Wenruo Feb. 23, 2015, 8 a.m. UTC
There is a case that can cause nlink fix function.

For example, lost+found dir already has the following files:
---------------------------
|ino	|filename	  |
|-------------------------|
|258	|normal_file	  |
|259	|normal_file.260  |
---------------------------
The next inode to be fixed is the following:
---------------------------
|260	|normail_file	  |
---------------------------

And when trying to move inode to lost+found dir, its file name conflicts
with inode 258, and even add ".INO" suffix, it still conflicts with
inode 259.

Since the move failed, the LINK_COUNT_ERR flag is not cleared, the inode
record will not be freed, btrfsck will try fix it again and again,
causing the infinite loop.

The patch will first change the ".INO" suffix naming to a loop behavior,
and clear the LINK_COUNT_ERR flag anyway to avoid infinite loop.

Reported-by: Naohiro Aota <naota@elisp.net>
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
---
 cmds-check.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

Comments

David Sterba Feb. 24, 2015, 2:22 p.m. UTC | #1
On Mon, Feb 23, 2015 at 04:00:04PM +0800, Qu Wenruo wrote:
> There is a case that can cause nlink fix function.
> 
> For example, lost+found dir already has the following files:
> ---------------------------
> |ino	|filename	  |
> |-------------------------|
> |258	|normal_file	  |
> |259	|normal_file.260  |
> ---------------------------
> The next inode to be fixed is the following:
> ---------------------------
> |260	|normail_file	  |
> ---------------------------
> 
> And when trying to move inode to lost+found dir, its file name conflicts
> with inode 258, and even add ".INO" suffix, it still conflicts with
> inode 259.
> 
> Since the move failed, the LINK_COUNT_ERR flag is not cleared, the inode
> record will not be freed, btrfsck will try fix it again and again,
> causing the infinite loop.
> 
> The patch will first change the ".INO" suffix naming to a loop behavior,
> and clear the LINK_COUNT_ERR flag anyway to avoid infinite loop.
> 
> Reported-by: Naohiro Aota <naota@elisp.net>
> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>

Applied, thanks.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/cmds-check.c b/cmds-check.c
index ce0ac88..62aee83 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -2364,7 +2364,11 @@  static int repair_inode_nlinks(struct btrfs_trans_handle *trans,
 		}
 		ret = btrfs_add_link(trans, root, rec->ino, lost_found_ino,
 				     namebuf, namelen, type, NULL, 1);
-		if (ret == -EEXIST) {
+		/*
+		 * Add ".INO" suffix several times to handle case where
+		 * "FILENAME.INO" is already taken by another file.
+		 */
+		while (ret == -EEXIST) {
 			/*
 			 * Conflicting file name, add ".INO" as suffix * +1 for '.'
 			 */
@@ -2396,9 +2400,14 @@  static int repair_inode_nlinks(struct btrfs_trans_handle *trans,
 		printf("Moving file '%.*s' to '%s' dir since it has no valid backref\n",
 		       namelen, namebuf, dir_name);
 	}
-	rec->errors &= ~I_ERR_LINK_COUNT_WRONG;
 	printf("Fixed the nlink of inode %llu\n", rec->ino);
 out:
+	/*
+	 * Clear the flag anyway, or we will loop forever for the same inode
+	 * as it will not be removed from the bad inode list and the dead loop
+	 * happens.
+	 */
+	rec->errors &= ~I_ERR_LINK_COUNT_WRONG;
 	btrfs_release_path(path);
 	return ret;
 }