linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes
@ 2022-10-04  7:43 Qu Wenruo
  2022-10-04  7:43 ` [PATCH 1/2] btrfs-progs: properly initialized extent generation for __btrfs_record_file_extent() Qu Wenruo
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Qu Wenruo @ 2022-10-04  7:43 UTC (permalink / raw)
  To: linux-btrfs

I don't know if it's recent kernel tmpfs change or something else, but
I'm consistently get ino number smaller than 256 from my /tmp directory.

This behavior change exposed a new problem in mkfs.btrfs --rootdir, that
if some ino number (in the source directory, not in btrfs) is smaller
than 256, it can screw up the backref code.

As backref code is utilizing @owner to determine if a backref is data or
metadata.

And inode number smaller than 256 will make backref code to treat a data
backref as tree backref, and cause corruption.

Thankfully this should not happen that easily, only when --rootdir
points to a newly created fs.

Qu Wenruo (2):
  btrfs-progs: properly initialized extent generation for
    __btrfs_record_file_extent()
  btrfs-progs: avoid fs corruption if rootdir contains ino smaller than
    BTRFS_FIRST_FREE_OBJECTID

 kernel-shared/extent-tree.c | 8 +++++++-
 mkfs/rootdir.c              | 8 +++++++-
 2 files changed, 14 insertions(+), 2 deletions(-)

-- 
2.37.3


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] btrfs-progs: properly initialized extent generation for __btrfs_record_file_extent()
  2022-10-04  7:43 [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes Qu Wenruo
@ 2022-10-04  7:43 ` Qu Wenruo
  2022-10-05  9:39   ` Anand Jain
  2022-10-04  7:43 ` [PATCH 2/2] btrfs-progs: avoid fs corruption if rootdir contains ino smaller than BTRFS_FIRST_FREE_OBJECTID Qu Wenruo
  2022-10-04  9:04 ` [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes David Sterba
  2 siblings, 1 reply; 6+ messages in thread
From: Qu Wenruo @ 2022-10-04  7:43 UTC (permalink / raw)
  To: linux-btrfs

[BUG]
When using mkfs.btrfs --rootdir option, the data extents generated will
has 0 as their generation in extent tree:

  # mkdir /tmp/rootdir
  # xfs_io -f -c "pwrite 0 16k" /tmp/rootdir
  # mkfs.btrfs -f --rootdir /tmp/rootdir $dev
  # btrfs ins dump-tree -t extent $dev
  btrfs-progs v5.19.1
  extent tree key (EXTENT_TREE ROOT_ITEM 0)
  leaf 30474240 items 13 free space 15536 generation 7 owner EXTENT_TREE
  leaf 30474240 flags 0x1(WRITTEN) backref revision 1
  fs uuid c1f05988-49f9-4dd4-8489-b90d60f522ee
  chunk uuid 40f81603-fe75-4f58-aa9e-e74e28df8523
	item 0 key (13631488 EXTENT_ITEM 16384) itemoff 16230 itemsize 53
		refs 1 gen 0 flags DATA <<< Generation is 0
  ...

[CAUSE]
In __btrfs_record_file_extent() we just set the extent generation to 0.

[FIX]
Use trans->transid to properly fill extent generation.

Now after mkfs, the first data extent backref looks like this:

	item 0 key (13631488 EXTENT_ITEM 16384) itemoff 16230 itemsize 53
		refs 1 gen 7 flags DATA
        ...

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 kernel-shared/extent-tree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index 3a058a8698ee..92d5c521abe8 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -3582,7 +3582,7 @@ static int __btrfs_record_file_extent(struct btrfs_trans_handle *trans,
 					    struct btrfs_extent_item);
 
 			btrfs_set_extent_refs(leaf, ei, 0);
-			btrfs_set_extent_generation(leaf, ei, 0);
+			btrfs_set_extent_generation(leaf, ei, trans->transid);
 			btrfs_set_extent_flags(leaf, ei,
 					       BTRFS_EXTENT_FLAG_DATA);
 			btrfs_mark_buffer_dirty(leaf);
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] btrfs-progs: avoid fs corruption if rootdir contains ino smaller than BTRFS_FIRST_FREE_OBJECTID
  2022-10-04  7:43 [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes Qu Wenruo
  2022-10-04  7:43 ` [PATCH 1/2] btrfs-progs: properly initialized extent generation for __btrfs_record_file_extent() Qu Wenruo
@ 2022-10-04  7:43 ` Qu Wenruo
  2022-10-04  9:04 ` [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes David Sterba
  2 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2022-10-04  7:43 UTC (permalink / raw)
  To: linux-btrfs

[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 grap
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>
---
 kernel-shared/extent-tree.c | 6 ++++++
 mkfs/rootdir.c              | 8 +++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
index 92d5c521abe8..670eb66b9929 100644
--- a/kernel-shared/extent-tree.c
+++ b/kernel-shared/extent-tree.c
@@ -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 should 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
diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c
index e6a32e8bd3ba..6c2cc414d36c 100644
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -533,7 +533,13 @@ static int traverse_directory(struct btrfs_trans_handle *trans,
 				goto fail;
 			}
 
-			cur_inum = st.st_ino;
+			/*
+			 * We can not directly use the reported 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,
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes
  2022-10-04  7:43 [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes Qu Wenruo
  2022-10-04  7:43 ` [PATCH 1/2] btrfs-progs: properly initialized extent generation for __btrfs_record_file_extent() Qu Wenruo
  2022-10-04  7:43 ` [PATCH 2/2] btrfs-progs: avoid fs corruption if rootdir contains ino smaller than BTRFS_FIRST_FREE_OBJECTID Qu Wenruo
@ 2022-10-04  9:04 ` David Sterba
  2 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2022-10-04  9:04 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs

On Tue, Oct 04, 2022 at 03:43:37PM +0800, Qu Wenruo wrote:
> I don't know if it's recent kernel tmpfs change or something else, but
> I'm consistently get ino number smaller than 256 from my /tmp directory.
> 
> This behavior change exposed a new problem in mkfs.btrfs --rootdir, that
> if some ino number (in the source directory, not in btrfs) is smaller
> than 256, it can screw up the backref code.
> 
> As backref code is utilizing @owner to determine if a backref is data or
> metadata.
> 
> And inode number smaller than 256 will make backref code to treat a data
> backref as tree backref, and cause corruption.
> 
> Thankfully this should not happen that easily, only when --rootdir
> points to a newly created fs.
> 
> Qu Wenruo (2):
>   btrfs-progs: properly initialized extent generation for
>     __btrfs_record_file_extent()
>   btrfs-progs: avoid fs corruption if rootdir contains ino smaller than
>     BTRFS_FIRST_FREE_OBJECTID

Added to devel, thanks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] btrfs-progs: properly initialized extent generation for __btrfs_record_file_extent()
  2022-10-04  7:43 ` [PATCH 1/2] btrfs-progs: properly initialized extent generation for __btrfs_record_file_extent() Qu Wenruo
@ 2022-10-05  9:39   ` Anand Jain
  2022-10-05 14:31     ` David Sterba
  0 siblings, 1 reply; 6+ messages in thread
From: Anand Jain @ 2022-10-05  9:39 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs

On 04/10/2022 15:43, Qu Wenruo wrote:
> [BUG]
> When using mkfs.btrfs --rootdir option, the data extents generated will
> has 0 as their generation in extent tree:
> 
>    # mkdir /tmp/rootdir
>    # xfs_io -f -c "pwrite 0 16k" /tmp/rootdir

This should be:

  # xfs_io -f -c "pwrite 0 16k" /tmp/rootdir/foobar


>    # mkfs.btrfs -f --rootdir /tmp/rootdir $dev
>    # btrfs ins dump-tree -t extent $dev
>    btrfs-progs v5.19.1
>    extent tree key (EXTENT_TREE ROOT_ITEM 0)
>    leaf 30474240 items 13 free space 15536 generation 7 owner EXTENT_TREE
>    leaf 30474240 flags 0x1(WRITTEN) backref revision 1
>    fs uuid c1f05988-49f9-4dd4-8489-b90d60f522ee
>    chunk uuid 40f81603-fe75-4f58-aa9e-e74e28df8523
> 	item 0 key (13631488 EXTENT_ITEM 16384) itemoff 16230 itemsize 53
> 		refs 1 gen 0 flags DATA <<< Generation is 0
>    ...
> 
> [CAUSE]
> In __btrfs_record_file_extent() we just set the extent generation to 0.
> 
> [FIX]
> Use trans->transid to properly fill extent generation.
> 
> Now after mkfs, the first data extent backref looks like this:
> 
> 	item 0 key (13631488 EXTENT_ITEM 16384) itemoff 16230 itemsize 53
> 		refs 1 gen 7 flags DATA
>          ...
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>

Reviewed-by: Anand Jain <anand.jain@oracle.com>


> ---
>   kernel-shared/extent-tree.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c
> index 3a058a8698ee..92d5c521abe8 100644
> --- a/kernel-shared/extent-tree.c
> +++ b/kernel-shared/extent-tree.c
> @@ -3582,7 +3582,7 @@ static int __btrfs_record_file_extent(struct btrfs_trans_handle *trans,
>   					    struct btrfs_extent_item);
>   
>   			btrfs_set_extent_refs(leaf, ei, 0);
> -			btrfs_set_extent_generation(leaf, ei, 0);
> +			btrfs_set_extent_generation(leaf, ei, trans->transid);
>   			btrfs_set_extent_flags(leaf, ei,
>   					       BTRFS_EXTENT_FLAG_DATA);
>   			btrfs_mark_buffer_dirty(leaf);


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] btrfs-progs: properly initialized extent generation for __btrfs_record_file_extent()
  2022-10-05  9:39   ` Anand Jain
@ 2022-10-05 14:31     ` David Sterba
  0 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2022-10-05 14:31 UTC (permalink / raw)
  To: Anand Jain; +Cc: Qu Wenruo, linux-btrfs

On Wed, Oct 05, 2022 at 05:39:24PM +0800, Anand Jain wrote:
> On 04/10/2022 15:43, Qu Wenruo wrote:
> > [BUG]
> > When using mkfs.btrfs --rootdir option, the data extents generated will
> > has 0 as their generation in extent tree:
> > 
> >    # mkdir /tmp/rootdir
> >    # xfs_io -f -c "pwrite 0 16k" /tmp/rootdir
> 
> This should be:
> 
>   # xfs_io -f -c "pwrite 0 16k" /tmp/rootdir/foobar

Updated, thanks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-10-05 14:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-04  7:43 [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes Qu Wenruo
2022-10-04  7:43 ` [PATCH 1/2] btrfs-progs: properly initialized extent generation for __btrfs_record_file_extent() Qu Wenruo
2022-10-05  9:39   ` Anand Jain
2022-10-05 14:31     ` David Sterba
2022-10-04  7:43 ` [PATCH 2/2] btrfs-progs: avoid fs corruption if rootdir contains ino smaller than BTRFS_FIRST_FREE_OBJECTID Qu Wenruo
2022-10-04  9:04 ` [PATCH 0/2] btrfs-progs: mkfs: --rootdir related fixes David Sterba

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).