* [PATCH v2 0/2] block: two fixes for the zone report ioctls
@ 2026-10-11 15:40 Shashank Mohan Jain
2026-10-11 15:40 ` [PATCH v2 1/2] block: only use the cached zone report if BLK_ZONE_REP_CACHED is set Shashank Mohan Jain
2026-10-11 15:40 ` [PATCH v2 2/2] block: fix the length of a smaller last zone in blkdev_get_zone_info() Shashank Mohan Jain
0 siblings, 2 replies; 3+ messages in thread
From: Shashank Mohan Jain @ 2026-10-11 15:40 UTC (permalink / raw)
To: Jens Axboe, Damien Le Moal
Cc: Christoph Hellwig, Johannes Thumshirn, Hannes Reinecke,
Chaitanya Kulkarni, Martin K. Petersen, linux-block,
linux-kernel
Two problems in the zone report code added in v6.19:
- BLKREPORTZONEV2 does not look at BLK_ZONE_REP_CACHED and returns the
cached report also when the flag is not set (patch 1).
- blkdev_get_zone_info() gives a smaller last zone the length of a
full zone, so the cached report describes a zone that ends behind
the end of the device (patch 2).
Both were found by reading the code and then confirmed with zoned
null_blk devices in qemu (x86_64). The test program opens one zone
explicitly, writes to a second zone and closes it, and compares the
reports of BLKREPORTZONE, BLKREPORTZONEV2 with flags 0 and
BLKREPORTZONEV2 with BLK_ZONE_REP_CACHED. On mainline it finds both
problems. With both patches BLKREPORTZONEV2 with flags 0 returns the
same device report as BLKREPORTZONE, and the cached report describes
the smaller last zone with its real length.
For patch 1 there is a choice between the code and the documentation.
The changelog of b30ffcdc0c15 and the comments in the uapi header both
say that without BLK_ZONE_REP_CACHED the report comes from the device,
and BLKREPORTZONE is marked as deprecated in favour of the new ioctl,
so I changed the code. If the cached report is meant to be the only
mode of BLKREPORTZONEV2, the header needs to say so instead.
Changes since v1:
- patch 1: rewrite the BLKREPORTZONEV2 case to the positive form
suggested by Damien Le Moal: take the cached report only when
BLK_ZONE_REP_CACHED is set and blkdev_has_cached_report_zones() is
true, and call blkdev_report_zones() in every other case. This drops
the redundant blkdev_report_zones_cached() call for the no-cache
case, where it would only fall back to a device report anyway, so
the observable behaviour is unchanged.
- patch 1: blkdev_has_cached_report_zones() is now used from
blkdev_report_zones_ioctl(), so move it, with its comment, above
that function rather than add a forward declaration.
- patch 1: adjust the changelog to describe the new form.
- patch 2 is unchanged; it keeps Damien Le Moal's Reviewed-by from v1.
- retested on zoned null_blk in qemu (see below).
The series is based on mainline (a5ebb76233b7, v7.3-rc6+), where both
patches apply. Patch 1 also applies to linux-next (next-20261009).
Patch 2 needs its context adjusted on linux-next / for-7.4/block,
because blkdev_get_zone_info() there tests the zone type instead of
the zone condition; I can rebase it onto that tree if you prefer to
take the series there.
Shashank Mohan Jain (2):
block: only use the cached zone report if BLK_ZONE_REP_CACHED is set
block: fix the length of a smaller last zone in blkdev_get_zone_info()
block/blk-zoned.c | 41 ++++++++++++++++++++++++-----------------
1 file changed, 24 insertions(+), 17 deletions(-)
base-commit: a5ebb76233b79db01e82e061173cb73c6d2b5c6b
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2 1/2] block: only use the cached zone report if BLK_ZONE_REP_CACHED is set
2026-10-11 15:40 [PATCH v2 0/2] block: two fixes for the zone report ioctls Shashank Mohan Jain
@ 2026-10-11 15:40 ` Shashank Mohan Jain
2026-10-11 15:40 ` [PATCH v2 2/2] block: fix the length of a smaller last zone in blkdev_get_zone_info() Shashank Mohan Jain
1 sibling, 0 replies; 3+ messages in thread
From: Shashank Mohan Jain @ 2026-10-11 15:40 UTC (permalink / raw)
To: Jens Axboe, Damien Le Moal
Cc: Christoph Hellwig, Johannes Thumshirn, Hannes Reinecke,
Chaitanya Kulkarni, Martin K. Petersen, linux-block,
linux-kernel
BLKREPORTZONEV2 takes the flags field of struct blk_zone_report as an
input. With BLK_ZONE_REP_CACHED the report is built from the zone
information cached by the block layer. Without it, BLKREPORTZONEV2 is
documented to behave like BLKREPORTZONE and to get the report from the
device: this is what the changelog of the commit that added the ioctl
and the comments in include/uapi/linux/blkzoned.h say.
blkdev_report_zones_ioctl() only uses the flag to validate the input
and calls blkdev_report_zones_cached() for every BLKREPORTZONEV2
request. A caller that passes flags == 0 gets the cached report, in
which implicitly open, explicitly open and closed zones all have the
condition BLK_ZONE_COND_ACTIVE, and an explicitly opened empty zone is
reported as empty.
Example with a zoned null_blk device (10 MiB, 4 MiB zones) after
BLKOPENZONE on zone 0, and a write of 8 sectors to zone 1 followed by
BLKCLOSEZONE:
BLKREPORTZONE: zone 0 cond 0x3 (EXP_OPEN)
zone 1 cond 0x4 (CLOSED)
BLKREPORTZONEV2, flags 0: zone 0 cond 0x1 (EMPTY)
zone 1 cond 0xff (ACTIVE)
The uapi header marks BLKREPORTZONE as deprecated in favour of
BLKREPORTZONEV2. A program that follows this and does not ask for
cached information can no longer tell open zones from closed ones, and
is handed BLK_ZONE_COND_ACTIVE, which is only defined for the cached
report.
Use the cached report only when BLK_ZONE_REP_CACHED is set and the
device has a cached report; otherwise, and whenever the flag is not
set, get the report from the device with blkdev_report_zones(). Guard
the cached path with blkdev_has_cached_report_zones() so the redundant
call is avoided when there is no cached report: in that case
blkdev_report_zones_cached() already falls back to a device report, so
the observable behaviour is unchanged. blkdev_has_cached_report_zones()
is defined lower in the file, so move it, with its comment, above
blkdev_report_zones_ioctl().
Tested with zoned null_blk devices in qemu: a program that compares
the reports of BLKREPORTZONE and BLKREPORTZONEV2 with flags 0 after
the sequence above finds the differences before this change and none
with it. The report with BLK_ZONE_REP_CACHED is unchanged.
Fixes: b30ffcdc0c15 ("block: introduce BLKREPORTZONESV2 ioctl")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Shashank Mohan Jain <jain.sm@gmail.com>
---
Prepared with Claude Code (Anthropic), model Claude Opus 4.8
(claude-opus-4-8).
block/blk-zoned.c | 37 ++++++++++++++++++++++---------------
1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 475aa16bc..c9b66b8a7 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -361,6 +361,19 @@ static int blkdev_copy_zone_to_user(struct blk_zone *zone, unsigned int idx,
return 0;
}
+/*
+ * For devices that natively support zone append operations, we do not use zone
+ * write plugging for zone append writes, which makes the zone condition
+ * tracking invalid once zone append was used. In that case fall back to a
+ * regular report zones to get correct information.
+ */
+static inline bool blkdev_has_cached_report_zones(struct block_device *bdev)
+{
+ return disk_need_zone_resources(bdev->bd_disk) &&
+ (bdev_emulates_zone_append(bdev) ||
+ !test_bit(GD_ZONE_APPEND_USED, &bdev->bd_disk->state));
+}
+
/*
* Mask of valid input flags for BLKREPORTZONEV2 ioctl.
*/
@@ -400,8 +413,15 @@ int blkdev_report_zones_ioctl(struct block_device *bdev, unsigned int cmd,
case BLKREPORTZONEV2:
if (rep.flags & ~BLK_ZONE_REPV2_INPUT_FLAGS)
return -EINVAL;
- ret = blkdev_report_zones_cached(bdev, rep.sector, rep.nr_zones,
- blkdev_copy_zone_to_user, &args);
+ if ((rep.flags & BLK_ZONE_REP_CACHED) &&
+ blkdev_has_cached_report_zones(bdev))
+ ret = blkdev_report_zones_cached(bdev, rep.sector,
+ rep.nr_zones,
+ blkdev_copy_zone_to_user, &args);
+ else
+ ret = blkdev_report_zones(bdev, rep.sector,
+ rep.nr_zones,
+ blkdev_copy_zone_to_user, &args);
break;
default:
return -EINVAL;
@@ -905,19 +925,6 @@ static int blkdev_report_zone_fallback(struct block_device *bdev,
return 0;
}
-/*
- * For devices that natively support zone append operations, we do not use zone
- * write plugging for zone append writes, which makes the zone condition
- * tracking invalid once zone append was used. In that case fall back to a
- * regular report zones to get correct information.
- */
-static inline bool blkdev_has_cached_report_zones(struct block_device *bdev)
-{
- return disk_need_zone_resources(bdev->bd_disk) &&
- (bdev_emulates_zone_append(bdev) ||
- !test_bit(GD_ZONE_APPEND_USED, &bdev->bd_disk->state));
-}
-
/**
* blkdev_get_zone_info - Get a single zone information from cached data
* @bdev: Target block device
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v2 2/2] block: fix the length of a smaller last zone in blkdev_get_zone_info()
2026-10-11 15:40 [PATCH v2 0/2] block: two fixes for the zone report ioctls Shashank Mohan Jain
2026-10-11 15:40 ` [PATCH v2 1/2] block: only use the cached zone report if BLK_ZONE_REP_CACHED is set Shashank Mohan Jain
@ 2026-10-11 15:40 ` Shashank Mohan Jain
1 sibling, 0 replies; 3+ messages in thread
From: Shashank Mohan Jain @ 2026-10-11 15:40 UTC (permalink / raw)
To: Jens Axboe, Damien Le Moal
Cc: Christoph Hellwig, Johannes Thumshirn, Hannes Reinecke,
Chaitanya Kulkarni, Martin K. Petersen, linux-block,
linux-kernel
blkdev_get_zone_info() sets the length of every zone to the zone size
of the device. The last zone of a zoned block device may be smaller
than the others: blk_revalidate_zone_cb() accepts that and remembers
the capacity of that zone in disk->last_zone_capacity. For such a zone
the length reported from the cached information is too large, and
start + len is beyond the end of the device. A conventional last zone
is also given the capacity of a full zone.
Example with a zoned null_blk device of 10 MiB (20480 sectors) with
4 MiB zones, last zone:
BLKREPORTZONE: start 16384 len 4096 capacity 4096
BLKREPORTZONEV2 with
BLK_ZONE_REP_CACHED: start 16384 len 8192 capacity 4096
Limit the length to what is left of the device. disk_zone_is_last()
still recognises the last zone, as start + len is then equal to the
capacity of the device. The capacity of a conventional zone is equal
to its length, which blk_revalidate_conv_zone() checks, so use the
length there.
Tested with zoned null_blk devices in qemu (all zones sequential, and
two conventional zones followed by sequential ones, both with a smaller
last zone): the start, length and capacity of all zones in the cached
report are the same as in the report from the device with this change.
null_blk cannot create a device with a conventional last zone, so that
case is not tested.
Fixes: f2284eec5053 ("block: introduce blkdev_get_zone_info()")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Shashank Mohan Jain <jain.sm@gmail.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
---
Prepared with Claude Code (Anthropic), model Claude Opus 4.8
(claude-opus-4-8).
block/blk-zoned.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index c9b66b8a7..4ebaba9aa 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -971,7 +971,7 @@ int blkdev_get_zone_info(struct block_device *bdev, sector_t sector,
rcu_read_unlock();
zone->start = sector;
- zone->len = zone_sectors;
+ zone->len = min(zone_sectors, get_capacity(disk) - sector);
/*
* If this is a conventional zone, we do not have a zone write plug and
@@ -979,7 +979,7 @@ int blkdev_get_zone_info(struct block_device *bdev, sector_t sector,
*/
if (zone->cond == BLK_ZONE_COND_NOT_WP) {
zone->type = BLK_ZONE_TYPE_CONVENTIONAL;
- zone->capacity = zone_sectors;
+ zone->capacity = zone->len;
zone->wp = ULLONG_MAX;
return 0;
}
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-11 15:40 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-11 15:40 [PATCH v2 0/2] block: two fixes for the zone report ioctls Shashank Mohan Jain
2026-10-11 15:40 ` [PATCH v2 1/2] block: only use the cached zone report if BLK_ZONE_REP_CACHED is set Shashank Mohan Jain
2026-10-11 15:40 ` [PATCH v2 2/2] block: fix the length of a smaller last zone in blkdev_get_zone_info() Shashank Mohan Jain
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®