diff mbox series

btrfs: zoned: calculate max_zone_append_size properly on non-zoned setup

Message ID 9c00c066e9529f1a6439c1c8895a8f0d010a07e5.1733887702.git.naohiro.aota@wdc.com (mailing list archive)
State New
Headers show
Series btrfs: zoned: calculate max_zone_append_size properly on non-zoned setup | expand

Commit Message

Naohiro Aota Dec. 11, 2024, 3:36 a.m. UTC
Since commit 559218d43ec9 ("block: pre-calculate max_zone_append_sectors"),
queue_limits's max_zone_append_sectors is default to be 0 and it is only
updated when there is a zoned device. So, we have
lim->max_zone_append_sectors = 0 when there is no zoned device in the
filesystem.

That leads to fs_info->max_zone_append_size and fs_info->max_extent_size to
be 0, which causes several errors. One example is the divide error as
below. Running simple test as btrfs/001 on a non-zoned device with the
zoned mode (zoned emulation) leads to this error because we have
fs_info->max_extent_size = 0 in count_max_extents().

   Oops: divide error: 0000 [#1] PREEMPT SMP KASAN NOPTI
   CPU: 21 UID: 0 PID: 2378822 Comm: dd Tainted: G        W          6.13.0-rc2-kts #1
   Tainted: [W]=WARN
   Hardware name: Supermicro SYS-520P-WTR/X12SPW-TF, BIOS 1.2 02/14/2022
   RIP: 0010:btrfs_delalloc_reserve_metadata+0x161/0x790 [btrfs]

The block layer logic, having max_zone_append_sectors = 0 by stacking
non-zoned devices, seems reasonable to me. So, let's deal with that in
btrfs side by ignoring max_zone_append_sectors if it is non-zoned setup.

Reported-by: Shinichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Fixes: 559218d43ec9 ("block: pre-calculate max_zone_append_sectors")
CC: Christoph Hellwig <hch@lst.de>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
---
 fs/btrfs/zoned.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

Comments

Christoph Hellwig Dec. 11, 2024, 6:20 a.m. UTC | #1
On Wed, Dec 11, 2024 at 12:36:00PM +0900, Naohiro Aota wrote:
> Since commit 559218d43ec9 ("block: pre-calculate max_zone_append_sectors"),
> queue_limits's max_zone_append_sectors is default to be 0 and it is only
> updated when there is a zoned device. So, we have
> lim->max_zone_append_sectors = 0 when there is no zoned device in the
> filesystem.

Which makes sense as zoned append isn't used on conventional devices.

> 
> That leads to fs_info->max_zone_append_size and fs_info->max_extent_size to
> be 0, which causes several errors. One example is the divide error as

But max_extent_size == 0 is a real problem.  Can you try the patch below?

diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index 11ed523e528e..27f4472fb559 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -748,8 +748,9 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
 		     (u64)lim->max_segments << PAGE_SHIFT),
 		fs_info->sectorsize);
 	fs_info->fs_devices->chunk_alloc_policy = BTRFS_CHUNK_ALLOC_ZONED;
-	if (fs_info->max_zone_append_size < fs_info->max_extent_size)
-		fs_info->max_extent_size = fs_info->max_zone_append_size;
+
+	fs_info->max_extent_size = min_not_zero(fs_info->max_extent_size,
+			fs_info->max_zone_append_size);
 
 	/*
 	 * Check mount options here, because we might change fs_info->zoned
Shinichiro Kawasaki Dec. 12, 2024, 4:59 a.m. UTC | #2
On Dec 11, 2024 / 07:20, Christoph Hellwig wrote:
> On Wed, Dec 11, 2024 at 12:36:00PM +0900, Naohiro Aota wrote:
> > Since commit 559218d43ec9 ("block: pre-calculate max_zone_append_sectors"),
> > queue_limits's max_zone_append_sectors is default to be 0 and it is only
> > updated when there is a zoned device. So, we have
> > lim->max_zone_append_sectors = 0 when there is no zoned device in the
> > filesystem.
> 
> Which makes sense as zoned append isn't used on conventional devices.
> 
> > 
> > That leads to fs_info->max_zone_append_size and fs_info->max_extent_size to
> > be 0, which causes several errors. One example is the divide error as
> 
> But max_extent_size == 0 is a real problem.  Can you try the patch below?
> 
> diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
> index 11ed523e528e..27f4472fb559 100644
> --- a/fs/btrfs/zoned.c
> +++ b/fs/btrfs/zoned.c
> @@ -748,8 +748,9 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
>  		     (u64)lim->max_segments << PAGE_SHIFT),
>  		fs_info->sectorsize);
>  	fs_info->fs_devices->chunk_alloc_policy = BTRFS_CHUNK_ALLOC_ZONED;
> -	if (fs_info->max_zone_append_size < fs_info->max_extent_size)
> -		fs_info->max_extent_size = fs_info->max_zone_append_size;
> +
> +	fs_info->max_extent_size = min_not_zero(fs_info->max_extent_size,
> +			fs_info->max_zone_append_size);
>  
>  	/*
>  	 * Check mount options here, because we might change fs_info->zoned

I tried this change instead of Naohiro's fix patch, and observed the btrfs/001
failure goes away. This change also looks good from problem fix point of view.
diff mbox series

Patch

diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index abea8f2f497e..12ad6fcc2513 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -741,12 +741,23 @@  int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info)
 	 * we add the pages one by one to a bio, and cannot increase the
 	 * metadata reservation even if it increases the number of extents, it
 	 * is safe to stick with the limit.
+	 *
+	 * If there is no zoned device in the filesystem, we have
+	 * max_zone_append_sectors = 0. That will cause
+	 * fs_info->max_zone_append_size and fs_info->max_extent_size to be
+	 * 0 in the following lines. Set the maximum value to avoid that.
 	 */
-	fs_info->max_zone_append_size = ALIGN_DOWN(
-		min3((u64)lim->max_zone_append_sectors << SECTOR_SHIFT,
-		     (u64)lim->max_sectors << SECTOR_SHIFT,
-		     (u64)lim->max_segments << PAGE_SHIFT),
-		fs_info->sectorsize);
+	if (lim->features & BLK_FEAT_ZONED)
+		fs_info->max_zone_append_size = ALIGN_DOWN(
+			min3((u64)lim->max_zone_append_sectors << SECTOR_SHIFT,
+			     (u64)lim->max_sectors << SECTOR_SHIFT,
+			     (u64)lim->max_segments << PAGE_SHIFT),
+			fs_info->sectorsize);
+	else
+		fs_info->max_zone_append_size = ALIGN_DOWN(
+			min((u64)lim->max_sectors << SECTOR_SHIFT,
+			    (u64)lim->max_segments << PAGE_SHIFT),
+			fs_info->sectorsize);
 	fs_info->fs_devices->chunk_alloc_policy = BTRFS_CHUNK_ALLOC_ZONED;
 	if (fs_info->max_zone_append_size < fs_info->max_extent_size)
 		fs_info->max_extent_size = fs_info->max_zone_append_size;