All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.