Skip to content

Improve handling of offline and read-only zones - #1224

Open
blktests-ci-kpd[bot] wants to merge 16 commits into
linus-master_basefrom
series/1144041=>linus-master
Open

Improve handling of offline and read-only zones#1224
blktests-ci-kpd[bot] wants to merge 16 commits into
linus-master_basefrom
series/1144041=>linus-master

Conversation

@blktests-ci-kpd

Copy link
Copy Markdown

Pull request for series with
subject: Improve handling of offline and read-only zones
version: 6
url: https://patchwork.kernel.org/project/linux-block/list/?series=1154085

@blktests-ci-kpd

Copy link
Copy Markdown
Author

Upstream branch: bc35965
series: https://patchwork.kernel.org/project/linux-block/list/?series=1154085
version: 6

@blktests-ci-kpd

Copy link
Copy Markdown
Author

Upstream branch: df29080
series: https://patchwork.kernel.org/project/linux-block/list/?series=1154085
version: 6

@blktests-ci-kpd
blktests-ci-kpd Bot force-pushed the series/1144041=>linus-master branch from 078677d to 544e176 Compare September 7, 2026 04:30
@blktests-ci-kpd blktests-ci-kpd Bot closed this Sep 7, 2026
@blktests-ci-kpd blktests-ci-kpd Bot reopened this Sep 8, 2026
@blktests-ci-kpd

Copy link
Copy Markdown
Author

Upstream branch: 28924df
series: https://patchwork.kernel.org/series/1160295/
version: 7

@blktests-ci-kpd blktests-ci-kpd Bot added V7 and removed V6 labels Sep 8, 2026
@blktests-ci-kpd
blktests-ci-kpd Bot force-pushed the series/1144041=>linus-master branch from 544e176 to 25f5386 Compare September 8, 2026 15:45
@blktests-ci-kpd

Copy link
Copy Markdown
Author

Upstream branch: 893e117
series: https://patchwork.kernel.org/series/1160295/
version: 7

@blktests-ci-kpd
blktests-ci-kpd Bot force-pushed the series/1144041=>linus-master branch from 25f5386 to 2a36d0e Compare September 9, 2026 08:05
@blktests-ci-kpd

Copy link
Copy Markdown
Author

Upstream branch: 893e117
series: https://patchwork.kernel.org/series/1160295/
version: 7

@blktests-ci-kpd
blktests-ci-kpd Bot force-pushed the series/1144041=>linus-master branch from 2a36d0e to 002371c Compare September 9, 2026 09:34
In the rare event when revalidating the zones of a zoned block device
fails, the device capacity will be dropped to 0. In such case, the zoned
block device will either be rescanned and restored or will be dropped
entirely and its gendisk will be destroyed. So calling
disk_free_zone_resources() from blk_revalidate_disk_zones() in case of
an error does not make much sense. We can keep the zone resources in case
the device is rescanned and restored and simply free all resources in
disk_release_zone_resources() when the gendisk is destroyed.

Remove the call to disk_free_zone_resources() from
blk_revalidate_disk_zones() and squash disk_free_zone_resources() inside
disk_release_zone_resources(). With this change, the conditional creation
of the zone write plugs work queue is not necessary anymore as the
workqueue will keep existing together with all other resources until the
disk is released. This simplifies disk_alloc_zone_resources().

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
While executing blk_revalidate_disk_zones(), a disk capacity is looked at
using get_capacity() several times: on entry to
blk_revalidate_disk_zones(), when allocating zone revalidation arguments
in disk_revalidate_zone_resources(), while validating zones in
blk_revalidate_zone_cb() and one last time at the end of
blk_revalidate_disk_zones() to check that all zones have been inspected.

Since this is all done while passthrough commands can be issued, it is
possible that a capacity change operation (e.g. the removal of a storage
element on a SCSI or SATA disk) is concurrently executed, potentially
resulting in an inconsistent or conflicting revalidation with potentially
out-of-bound accesses to the zone condition array.

Prevent issues by using get_capacity() once on entry to
blk_revalidate_disk_zones(), remembering this capacity as a field of
struct blk_revalidate_zone_args and using that field while revalidating
zones. A final second call to get_capacity() is done at the end of
blk_revalidate_disk_zones() to ensure that the disk capacity has not
changed, thus revalidating the capacity (and number of zones) itself.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
The function disk_revalidate_zone_resources() is misnamed as it does not
revalidate anything but rather allocates the revalidation arguments and
then calls disk_alloc_zone_resources() to initialize the disk zone
resources if they are needed and not already allocated.

Make this function less confusing by renaming it
disk_init_revalidate_args() and moving the call to
disk_alloc_zone_resources() into blk_revalidate_disk_zones(). As before,
this function is only called if the zone resources are needed and not yet
allocated. The initialization of the atomic nr_zone_wplugs is also moved
to the function disk_init_zone_resources() so that this is done once and
not on all revalidation.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Since the function disk_update_zone_resources() does a lot of checks
beside updating a zoned disk limits and resources, rename this function
to disk_revalidate_zone_resources().

To keep all the checks together, move the capacity checks (including the
check on the end sector of the last zone of the disk) in
blk_revalidate_disk_zones() to this function.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Currently, bdev_zone_is_seq() identifies a sequential zone by looking at
the zone condition, assuming that any zone that does not have the
condition BLK_ZONE_COND_NOT_WP is a sequential write required zone. That
is correct only as long as the target zoned device does not support
storage element depopulation (aka HDD head depopulation), which is a
feature that can transition conventional zones to the read-only or offline
condition. For such device, we cannot distinguish anymore between
conventional and sequential zones using the zone condition as both zone
types can have the same conditions.

Prepare for fully supporting storage element depopulation and restoration
by caching the type of a zone in addition to its condition. This is
implemented by reformating the zones_cond array using a more compact zone
condition representation with the new enum blk_zstate. This zone condition
representation only uses the lower 4 bits of a byte for the condition
values, thus leaving the high order 4 bits of each byte entry of the
array for flags. The flag BLK_ZFLAG_CONV is defined to indicate
conventional zones.

The helper functions blk_zstate_to_zone_cond() and
blk_zone_cond_to_zstate() are implemented using lookup tables to convert
between enum blk_zone_condition values and enum blk_zstate zone condition
values. The helper blk_zstate_set() can be used to set a zones_state
entry with a zone condition and zone type flags, safely in accordance to
the size of the zone state array being accessed. This helper is used in
disk_zone_set_cond() to update a zone condition.
bdev_zone_is_seq() is modified to use the flags of the zones_state array
entries to identify sequential zones. The zones_state array initialization
and revalidation is unchanged from the former zones_cond array.

Overall, any zone condition that is being considered outside of the
zones_state array always uses the enum blk_zone_condition values as
before, thus minimizing the number of changes.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Define the helper function disk_zone_is_seq() and use it to refactor
bdev_zone_is_seq(). disk_zone_is_seq() is also used in
blk_zone_wplug_handle_write().

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Add a zone state array bound check to ensure that like
disk_zone_get_state(), we never attempt to access the zone state array
beyond its size.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Introduce the helper function disk_for_all_zone_wplugs() to allow
executing an actor function on all hashed zone write plugs. This helper
is used to simplify the implementation of blk_zone_reset_all_bio_endio()
and queue_zone_wplugs_show().

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
The zone related fields of struct gendisk can be modified by
blk_revalidate_disk_zones() either on the first scan of the disk, or
during user triggered scans or device revalidation, if some
characteristics of the disk has changed (e.g. the disk capacity). Changes
to these fields are always done with the disk request queue frozen so that
BIO processing does not see any inconsistent state of the zones. This
implies a contract that reading these zone related fields must always be
done while holding a usage count on the request queue of the disk.

However, increasing the usage count of the disk request queue cannot be
done from the context of blk_revalidate_disk_zones() itself, as that would
prevent freezing the disk queue and result in a deadlock. This prevents
blk_revalidate_disk_zones() from consulting the zone related fields of
struct gendisk to detect, for instance, a change in the number of zones of
the disk. For such case, we want to detect the change, take appropriate
measures and revalidate exclusively revalidate the zones to avoid
concurrent revalidation calls to see the same change while corrections are
already on-going.

A simple solution to avoid this issue is to introduce a mutex to serialize
calls to blk_revalidate_disk_zones() and ensure only a single context at a
time can modify the zone related fields of a gendisk. In preparation for
handling disk capacity revalidation in blk_revalidate_disk_zones(), do so
with the mutex zone_revalidate_mutex. This mutex is initialized in
disk_init_zone_resources(), destroyed in disk_release_zone_resources() and
taken and released only in blk_revalidate_disk_zones() to serialize the
execution of this function.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
If during revalidation, we detect a capacity change for a zoned block
device, e.g. due to a storage element removal on an HDD, we can assume
that the device was reformatted, which implies that all sequential zones
are empty. For such case, we can remove and free all zone write plugs in
the gendisk hash table by marking them as dead, thus avoiding also to
leave zone write plugs for zones that are beyond the new device capacity
in the disk hash table.

Introduce the function disk_revalidate_capacity() to do this and call this
new function at the beginning of blk_revalidate_disk_zones(), so that the
zone revalidation process can re-create, if needed, any zone write plug
for sequential zones that are not empty.

The checks on the capacity and zone size that were in
blk_revalidate_disk_zones() are moved to disk_revalidate_capacity() and
if true, also trigger dropping all zone write plugs.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
When disk_revalidate_zone_resources() detects a capacity change, -ENODEV
is returned, failing the disk revalidation. However, since a capacity
change may happen due to a storage element removal being executed
concurrently to blk_revalidate_disk_zones(), we can simply retry the
revalidation to capture the new zone state with the new capacity without
failing the revalidation.

Retrying the revalidation is driven by disk_revalidate_zone_resources()
returning -EAGAIN when a new valid capacity is detected. And to avoid
getting stuck in an infinite loop revalidating zones, retries are limited
to 2.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
When revalidating the zones of a zoned block device, or when handling a
zone which has a zone write plug flagged with
BLK_ZONE_WPLUG_NEED_WP_UPDATE, the function
disk_zone_wplug_sync_wp_offset() is used to update the write pointer
offset of a zone write plug. However, this does not take into account the
condition of the zone, which may have changed to readonly or offline,
which in itself will always cause errors.

In order to catch such errors, rename disk_zone_wplug_sync_wp_offset() to
disk_zone_wplug_sync_state() and in addition to the zone write pointer,
also update the zone write plug condition if the zone is readonly or
offline.

This change also requires changes to how a reset all zones operation
(REQ_OP_ZONE_RESET_ALL) is handled so that the offline or read-only
condition of zone write plugs is not overwritten with an erroneous empty
condition. To do so, introduce the helper function
disk_zone_is_offline_or_readonly() to skip updating the condition of zones
that are read-only or offline and that do not have a zone write plug.
For zones that have a zone write plug, the helper function
disk_zone_wplug_is_offline_or_readonly() is used in
disk_zone_wplug_set_wp_offset() to not update a zone write plug write
pointer and condition for read-only and offline zones.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Since any write BIO targeting an offline or a read-only zone will fail,
there is no point in keeping zone write plugs for these zones.
So for any offline or read-only zone, the zone write plug should always
be treated as dead.

Do this by modifying disk_check_zone_wplug_dead() to always mark read-only
and offline zones as dead to force a removal of the zone write plug from
the disk hash table on BIO submission. blk_zone_wplug_prepare_bio() is
also modified to have the same checks to immediately fail a write BIO
targeting a read-only or offline zone. With these two changes, any newly
issued or unplugged write BIO targeting a read-only or offline zone is
immediately failed.

Finally, disk_zone_wplug_sync_state() is modified to add a call to
disk_mark_zone_wplug_dead() for the zone write plug of any read-only or
offline zone found during zone revalidation or a report zones.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
@blktests-ci-kpd

Copy link
Copy Markdown
Author

Upstream branch: 893e117
series: https://patchwork.kernel.org/series/1160295/
version: 7

Any zone management operation targeting a zone that is in the read-only
or offline condition will fail. So there is no point in issuing such
BIO. Modify the check in submit_bio_noacct() to use the new helper
function bdev_zone_mgmt_allowed() to check that a zone is sequential (as
was checked before) and also that the zone is not offline nor read-only.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
With SCSI and ATA SMR HDDs, the storage element depopulation feature can
change the condition of conventional zones to read-only (if a write head
is depopulated) or to offline (if a read head is depopulated).
However, the function blk_revalidate_zone_cond() currently does not allow
these conditions for conventional zones, causing a zone revalidation
failure.

Remove blk_revalidate_zone_cond() and move the zone condition checks for
conventional zones to blk_revalidate_conv_zone(), allowing the regular
BLK_ZONE_COND_NOT_WP condition as well as the BLK_ZONE_COND_OFFLINE and
BLK_ZONE_COND_READONLY conditions to match the conditions that can be
seen from a zoned device with depopulated storage elements.

The zone condition checks for sequential write required zones are moved
to blk_revalidate_seq_zone() without any change to the conditions allowed.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
disk_zone_set_cond() is used to set a zone condition afer a reset, a
finish or a reset all operation. For a single zone reset or finish, we are
guaranteed that the target zone is a sequential one that is not offline
nor read-only (otherwise, the operation would have failed). For a reset
all operation, there is no point in calling this function for offline and
read-only zones since the condition checks in disk_zone_set_cond() will
result in nothing being done.

Simplify all this using disk_zone_is_offline_or_readonly() in
blk_zone_reset_all_bio_endio() to skip zones that are offline or
read-only. This change allows simplifying disk_zone_set_cond() by removing
the zone condition checks. This change is also consistent with the fact
that conventional zones can now have the offline or read-only condition.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
@blktests-ci-kpd
blktests-ci-kpd Bot force-pushed the series/1144041=>linus-master branch from 002371c to 1947c96 Compare September 10, 2026 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant