summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/blk-zoned.c77
1 files changed, 57 insertions, 20 deletions
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 676620ed93de..e7f20b5262c7 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -2246,6 +2246,56 @@ unfreeze:
return ret;
}
+static void disk_drop_zone_wplug(struct blk_zone_wplug *zwplug, void *data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&zwplug->lock, flags);
+ disk_zone_wplug_abort(zwplug);
+ disk_mark_zone_wplug_dead(zwplug);
+ spin_unlock_irqrestore(&zwplug->lock, flags);
+}
+
+static int disk_revalidate_capacity(struct gendisk *disk,
+ struct blk_revalidate_zone_args *args)
+{
+ struct queue_limits *lim = &disk->queue->limits;
+ sector_t zone_sectors = lim->chunk_sectors;
+ unsigned int nr_zones;
+ int ret = -ENODEV;
+
+ /* Checks that the device driver indicated a valid zone size. */
+ if (!zone_sectors || !is_power_of_2(zone_sectors)) {
+ pr_warn("%s: Invalid non power of two zone size (%llu)\n",
+ disk->disk_name, zone_sectors);
+ goto drop_all_zwplugs;
+ }
+
+ args->capacity = get_capacity(disk);
+ nr_zones = disk_get_nr_zones(disk, args->capacity);
+ if (!args->capacity || !nr_zones)
+ goto drop_all_zwplugs;
+
+ /*
+ * Check if the capacity has changed. If it did, assume that the device
+ * was reformatted and that all sequential zones are now empty. So drop
+ * all zone write plug.
+ */
+ if (disk->nr_zones && disk->nr_zones != nr_zones) {
+ pr_warn("%s: Number of zones changed (%u -> %u)\n",
+ disk->disk_name, disk->nr_zones, nr_zones);
+ ret = 0;
+ goto drop_all_zwplugs;
+ }
+
+ return 0;
+
+drop_all_zwplugs:
+ disk_for_all_zone_wplugs(disk, disk_drop_zone_wplug, NULL);
+
+ return ret;
+}
+
static int blk_revalidate_zone_cond(struct blk_zone *zone, unsigned int idx,
struct blk_revalidate_zone_args *args)
{
@@ -2435,40 +2485,27 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx,
*/
int blk_revalidate_disk_zones(struct gendisk *disk)
{
- struct request_queue *q = disk->queue;
- sector_t zone_sectors = q->limits.chunk_sectors;
- struct blk_revalidate_zone_args args = {
- .capacity = get_capacity(disk),
- };
+ struct blk_revalidate_zone_args args = { };
struct blk_report_zones_args rep_args = {
.cb = blk_revalidate_zone_cb,
.data = &args,
};
unsigned int noio_flag;
- int ret = -ENOMEM;
+ int ret;
- if (WARN_ON_ONCE(!blk_queue_is_zoned(q)))
+ if (WARN_ON_ONCE(!blk_queue_is_zoned(disk->queue)))
return -EIO;
- if (!args.capacity)
- return -ENODEV;
-
- /*
- * Checks that the device driver indicated a valid zone size and that
- * the max zone append limit is set.
- */
- if (!zone_sectors || !is_power_of_2(zone_sectors)) {
- pr_warn("%s: Invalid non power of two zone size (%llu)\n",
- disk->disk_name, zone_sectors);
- return -ENODEV;
- }
-
/*
* Serialize calls to this function so that we can safely look at and
* eventually change the disk zone information.
*/
mutex_lock(&disk->zone_revalidate_mutex);
+ ret = disk_revalidate_capacity(disk, &args);
+ if (ret)
+ goto unlock;
+
/*
* Allocate zone resources if they are needed and we have not done
* so yet, and initialize the revalidation arguments passed to report