Skip to content

Commit 82eca8d

Browse files
committed
btrfs-progs: check/lowmem: fix INODE_REF repair
[BUG] Although lowmem has the logical to repair one missing INODE_REF/DIR_INDEX/DIR_ITEM, there is a catch in missing INODE_REF. If we're checking an DIR_ITEM (which we normally hits first), and failed to find the INODE_REF, we are in a situation where there is no @index to delete the original DIR_INDEX/DIR_ITEM pair. This can cause further damage to the fs, without really improving anything. [CAUSE] There is a minimal example where there is missing INODE_ITEM: item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160 generation 3 transid 9 size 12 nbytes 16384 block group 0 mode 40755 links 1 uid 0 gid 0 rdev 0 sequence 1 flags 0x0(none) item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12 index 0 namelen 2 name: .. item 2 key (256 DIR_ITEM 496027801) itemoff 16075 itemsize 36 location key (257 INODE_ITEM 0) type FILE transid 9 data_len 0 name_len 6 name: foobar item 3 key (256 DIR_INDEX 2) itemoff 16039 itemsize 36 location key (257 INODE_ITEM 0) type FILE transid 9 data_len 0 name_len 6 name: foobar item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160 generation 9 transid 9 size 0 nbytes 0 block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0 sequence 1 flags 0x0(none) For above case, if we're check the DIR_ITEM, we can find the INODE_ITEM but not the INODE_REF. So we need to repair it, but at this stage we haven't checked DIR_INDEX, this means we have no idea which index we should delete, leaving the default @index as (-1). If we call btrfs_unlink() with that (-1) as index, it will not delete the (256 DIR_INDEX 2) one, then re-add a link using -1 as index, causing more damage. [FIX] Before calling btrfs_unlink(), do an extra check on if we're called from DIR_ITEM checks (aka, @index is -1) and we only detected a missing INODE_REF yet. If so, do find_dir_index() call to determine the DIR_INDEX, if that failed it means we have missing both DIR_INDEX and INODE_REF, thus should remove the lone DIR_ITEM instead. With this enhancement, lowmem mode can properly fix the missing INODE_REF by adding it back. Signed-off-by: Qu Wenruo <wqu@suse.com>
1 parent b9f35a2 commit 82eca8d

File tree

1 file changed

+11
-0
lines changed

1 file changed

+11
-0
lines changed

check/mode-lowmem.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,17 @@ static int repair_ternary_lowmem(struct btrfs_root *root, u64 dir_ino, u64 ino,
10151015
int stage = 0;
10161016
int ret = 0;
10171017

1018+
/*
1019+
* We miss an INODE_REF, and we're checking DIR_ITEM and hasn't yet
1020+
* find the DIR_INDEX, thus there is no reliable index.
1021+
* Try to locate one, this can be slow as we need to locate the DIR_INDEX
1022+
* item from the directory.
1023+
*/
1024+
if (index == (u64)-1 && (err & INODE_REF_MISSING)) {
1025+
ret = find_dir_index(root, dir_ino, ino, &index, name, name_len, filetype);
1026+
if (ret < 0)
1027+
err |= DIR_INDEX_MISSING;
1028+
}
10181029
/*
10191030
* stage shall be one of following valild values:
10201031
* 0: Fine, nothing to do.

0 commit comments

Comments
 (0)