btrfs-progs: mkfs: offset inode numbers of the source filesystem
[BUG] When running mkfs tests on a newly rebooted minimal system, it can cause mkfs/009 to fail. The reproduce steps requires /tmp to has minimal files in the first place. # mkdir /tmp/rootdir # xfs_io -f -c "pwrite 0 16k" /tmp/rootdir # mkfs.btrfs --rootdir /tmp/rootdir -f $dev # btrfs check $dev Opening filesystem to check... Checking filesystem on /dev/test/scratch1 UUID: 6821b3db-f056-4c18-b797-32679dcd4272 [1/7] checking root items [2/7] checking extents data backref 13631488 root 5 owner 170 offset 0 num_refs 0 not found in extent tree incorrect local backref count on 13631488 root 5 owner 170 offset 0 found 1 wanted 0 back 0x55ff6cd72260 backref 13631488 root 5 not referenced back 0x55ff6cd4c1f0 incorrect global backref count on 13631488 found 2 wanted 1 backpointer mismatch on [13631488 16384] ERROR: errors found in extent allocation tree or chunk allocation [CAUSE] The extent tree has the following weird item: item 0 key (13631488 EXTENT_ITEM 16384) itemoff 16250 itemsize 33 refs 1 gen 0 flags DATA tree block backref root FS_TREE This is an extent item for data, thus it should not have an inline tree backref. Then checking the fs tree: item 0 key (170 INODE_ITEM 0) itemoff 16123 itemsize 160 generation 7 transid 0 size 16384 nbytes 16384 block group 0 mode 100600 links 1 uid 1000 gid 1000 rdev 0 sequence 0 flags 0x0(none) atime 1664866393.0 (2022-10-04 14:53:13) ctime 1664863510.0 (2022-10-04 14:05:10) mtime 1664863455.0 (2022-10-04 14:04:15) otime 0.0 (1970-01-01 08:00:00) There is an inode item before the root dir inode. And that inode number 170 is causing the problem. In traverse_directory(), we use the inode number reported from stat() directly as btrfs inode number, and pass it to btrfs_record_file_extent(), which finally calls btrfs_inc_extent_ref(), with above 170 passed as @owner parameter. But inside btrfs_inc_extent_ref() we use that @owner value to determine if it's a data backref. Since we got a smaller than BTRFS_FIRST_FREE_OBJECTID, btrfs treats it as tree block, and cause the above problem. [FIX] As a quick fix, always add BTRFS_FIRST_FREE_OBJECTID to all inode number directly grabbed from stat(). And add an ASSERT() in __btrfs_record_file_extent() to catch unexpected objectid. This is not a perfect solution, as the resulted fs will has a huge gap in its inodes: item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160 item 4 key (426 INODE_ITEM 0) itemoff 15883 itemsize 160 For a proper fix, we should allocate new btrfs inode numbers in a sequential order, but that would be another series of patches. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
dad9db45bb
commit
2cdc8dddbf
|
@ -3529,6 +3529,12 @@ static int __btrfs_record_file_extent(struct btrfs_trans_handle *trans,
|
|||
u64 extent_offset;
|
||||
u64 num_bytes = *ret_num_bytes;
|
||||
|
||||
/*
|
||||
* @objectid should be an inode number, thus it must not be smaller
|
||||
* than BTRFS_FIRST_FREE_OBJECTID.
|
||||
*/
|
||||
ASSERT(objectid >= BTRFS_FIRST_FREE_OBJECTID);
|
||||
|
||||
/*
|
||||
* All supported file system should not use its 0 extent.
|
||||
* As it's for hole
|
||||
|
|
|
@ -530,7 +530,13 @@ static int traverse_directory(struct btrfs_trans_handle *trans,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
cur_inum = st.st_ino;
|
||||
/*
|
||||
* We can not directly use the source ino number,
|
||||
* as there is a chance that the ino is smaller than
|
||||
* BTRFS_FIRST_FREE_OBJECTID, which will screw up
|
||||
* backref code.
|
||||
*/
|
||||
cur_inum = st.st_ino + BTRFS_FIRST_FREE_OBJECTID;
|
||||
ret = add_directory_items(trans, root,
|
||||
cur_inum, parent_inum,
|
||||
cur_file->d_name,
|
||||
|
|
Loading…
Reference in New Issue