diff options
| -rw-r--r-- | block/blk-zoned.c | 77 |
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 |
