Archive-only list for patches
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Johannes Thumshirn <johannes.thumshirn@wdc.com>,
	Naohiro Aota <naohiro.aota@wdc.com>,
	Anand Jain <anand.jain@oracle.com>,
	David Sterba <dsterba@suse.com>, Sasha Levin <sashal@kernel.org>,
	clm@fb.com, josef@toxicpanda.com, linux-btrfs@vger.kernel.org
Subject: [PATCH AUTOSEL 6.16-6.12] btrfs: zoned: skip ZONE FINISH of conventional zones
Date: Mon, 25 Aug 2025 08:14:56 -0400	[thread overview]
Message-ID: <20250825121505.2983941-7-sashal@kernel.org> (raw)
In-Reply-To: <20250825121505.2983941-1-sashal@kernel.org>

From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

[ Upstream commit f0ba0e7172a222ea6043b61ecd86723c46d7bcf2 ]

Don't call ZONE FINISH for conventional zones as this will result in I/O
errors. Instead check if the zone that needs finishing is a conventional
zone and if yes skip it.

Also factor out the actual handling of finishing a single zone into a
helper function, as do_zone_finish() is growing ever bigger and the
indentations levels are getting higher.

Reviewed-by: Naohiro Aota <naohiro.aota@wdc.com>
Reviewed-by: Anand Jain <anand.jain@oracle.com>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

**Backport Status: YES**

This commit should be backported to stable kernel trees for the
following reasons:

## Bug Fix Analysis

1. **Critical Bug Fix**: The commit fixes a concrete bug where calling
   `REQ_OP_ZONE_FINISH` on conventional zones results in I/O errors.
   This is a real runtime error that affects users of btrfs on zoned
   storage devices that have conventional zones mixed with sequential
   zones.

2. **Small and Contained Change**: The fix is relatively small and well-
   contained:
   - Adds a new helper function `call_zone_finish()` that encapsulates
     the zone finishing logic
   - Most importantly, adds the critical check: `if
     (btrfs_dev_is_sequential(device, physical))` before issuing the
     `REQ_OP_ZONE_FINISH` operation
   - The refactoring merely moves existing code into the helper function
     without changing the logic

3. **Clear Root Cause**: The bug occurs because the original code
   unconditionally calls `blkdev_zone_mgmt()` with `REQ_OP_ZONE_FINISH`
   on all zones, but this operation is invalid for conventional zones
   (non-sequential zones). The fix properly checks if a zone is
   sequential before attempting to finish it.

4. **No New Features**: This commit doesn't introduce any new
   functionality - it's purely a bug fix that prevents I/O errors.

5. **Minimal Risk**: The change has minimal risk of regression:
   - The check for sequential zones is straightforward
   - The refactoring doesn't change the existing logic flow
   - The fix has been reviewed by multiple developers familiar with the
     zoned code

6. **Affects Real Users**: This bug affects users running btrfs on SMR
   (Shingled Magnetic Recording) drives or ZNS (Zoned Namespace) SSDs
   that have a mix of conventional and sequential zones, which is a
   common configuration.

## Code Analysis

The key fix in `call_zone_finish()` at line 2262:
```c
if (btrfs_dev_is_sequential(device, physical)) {
    // Only call zone finish for sequential zones
    ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH, ...);
}
```

This prevents the invalid operation on conventional zones while
maintaining the correct behavior for sequential zones. The subsequent
operations (updating reserved_active_zones and clearing active zone) are
still performed regardless of zone type, which is the correct behavior.

The commit follows stable kernel rules perfectly: it's a clear bug fix,
has minimal changes, doesn't introduce new features, and addresses a
real user-facing issue that causes I/O errors.

 fs/btrfs/zoned.c | 55 ++++++++++++++++++++++++++++++------------------
 1 file changed, 35 insertions(+), 20 deletions(-)

diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index 5439d8374716..950e72dc537c 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -2246,6 +2246,40 @@ static void wait_eb_writebacks(struct btrfs_block_group *block_group)
 	rcu_read_unlock();
 }
 
+static int call_zone_finish(struct btrfs_block_group *block_group,
+			    struct btrfs_io_stripe *stripe)
+{
+	struct btrfs_device *device = stripe->dev;
+	const u64 physical = stripe->physical;
+	struct btrfs_zoned_device_info *zinfo = device->zone_info;
+	int ret;
+
+	if (!device->bdev)
+		return 0;
+
+	if (zinfo->max_active_zones == 0)
+		return 0;
+
+	if (btrfs_dev_is_sequential(device, physical)) {
+		unsigned int nofs_flags;
+
+		nofs_flags = memalloc_nofs_save();
+		ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
+				       physical >> SECTOR_SHIFT,
+				       zinfo->zone_size >> SECTOR_SHIFT);
+		memalloc_nofs_restore(nofs_flags);
+
+		if (ret)
+			return ret;
+	}
+
+	if (!(block_group->flags & BTRFS_BLOCK_GROUP_DATA))
+		zinfo->reserved_active_zones++;
+	btrfs_dev_clear_active_zone(device, physical);
+
+	return 0;
+}
+
 static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_written)
 {
 	struct btrfs_fs_info *fs_info = block_group->fs_info;
@@ -2330,31 +2364,12 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
 	down_read(&dev_replace->rwsem);
 	map = block_group->physical_map;
 	for (i = 0; i < map->num_stripes; i++) {
-		struct btrfs_device *device = map->stripes[i].dev;
-		const u64 physical = map->stripes[i].physical;
-		struct btrfs_zoned_device_info *zinfo = device->zone_info;
-		unsigned int nofs_flags;
-
-		if (!device->bdev)
-			continue;
-
-		if (zinfo->max_active_zones == 0)
-			continue;
-
-		nofs_flags = memalloc_nofs_save();
-		ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
-				       physical >> SECTOR_SHIFT,
-				       zinfo->zone_size >> SECTOR_SHIFT);
-		memalloc_nofs_restore(nofs_flags);
 
+		ret = call_zone_finish(block_group, &map->stripes[i]);
 		if (ret) {
 			up_read(&dev_replace->rwsem);
 			return ret;
 		}
-
-		if (!(block_group->flags & BTRFS_BLOCK_GROUP_DATA))
-			zinfo->reserved_active_zones++;
-		btrfs_dev_clear_active_zone(device, physical);
 	}
 	up_read(&dev_replace->rwsem);
 
-- 
2.50.1


  parent reply	other threads:[~2025-08-25 12:15 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-25 12:14 [PATCH AUTOSEL 6.16-5.15] fs: writeback: fix use-after-free in __mark_inode_dirty() Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.1] cdc_ncm: Flag Intel OEM version of Fibocom L850-GL as WWAN Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.6] LoongArch: Save LBT before FPU in setup_sigcontext() Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16] btrfs: clear block dirty if submit_one_sector() failed Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16] platform/x86/amd: pmc: Drop SMU F/W match for Cezanne Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16] LoongArch: Add cpuhotplug hooks to fix high cpu usage of vCPU threads Sasha Levin
2025-08-25 12:14 ` Sasha Levin [this message]
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-5.10] drm/amd/display: Don't warn when missing DCE encoder caps Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.1] Bluetooth: hci_sync: Avoid adding default advertising on startup Sasha Levin
2025-08-25 12:14 ` [PATCH AUTOSEL 6.16-6.6] cpupower: Fix a bug where the -t option of the set subcommand was not working Sasha Levin
2025-08-25 12:15 ` [PATCH AUTOSEL 6.16-6.12] drm/rockchip: vop2: make vp registers nonvolatile Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250825121505.2983941-7-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=anand.jain@oracle.com \
    --cc=clm@fb.com \
    --cc=dsterba@suse.com \
    --cc=johannes.thumshirn@wdc.com \
    --cc=josef@toxicpanda.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=naohiro.aota@wdc.com \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox