On 2023/12/01 11:03, Damien Le Moal wrote:
> Using dm-linear or dm-error, a user can craft a DM device using
> host-managed SMR disks by mapping only conventional zones. Currently,
> such DM device will be reported also as being host-managed, despite the
> fact that this zoned model mandated sequential-write-required zone are
> not present. This breaks the host-managed model and may confuse some
> applications, potentially resulting in unexpected behavior or bugs.
>
> A simple solution for such case is to expose a DM device built only
> using an SMR host managed disk conventional zones as a regular device.
> This is acceptable and possible because read and write accesses to
> conventional zones do not have any restrictions and can cross zone
> boundaries.
>
> This commit introduces the function dm_validate_zoned_model() to detect
> if a zoned DM device contains only conventional zones. If it does, this
> function calls disk_set_zoned() to change the DM device queue zoned
> model to BLK_ZONED_NONE, clearing in the process also the queue limits
> associated with zoned block devices (e.g. chunk_sectors for the zone
> size, number of zones, etc). dm_validate_zoned_model() is called from
> dm_table_set_restrictions() when the DM device request queue is set up.
>
> With this change, dm-linear and dm-error devices built using
> conventional zones are now exposed as regular block devices.
>
> Signed-off-by: Damien Le Moal <[email protected]>
Mike,
Ping ? I do not see this queued in DM tree for-next branch.
Thanks !
> ---
> drivers/md/dm-table.c | 13 +++++++++
> drivers/md/dm-zone.c | 63 +++++++++++++++++++++++++++++++++++++++++++
> drivers/md/dm.h | 1 +
> 3 files changed, 77 insertions(+)
>
> diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
> index 198d38b53322..9c7547da6171 100644
> --- a/drivers/md/dm-table.c
> +++ b/drivers/md/dm-table.c
> @@ -2034,6 +2034,19 @@ int dm_table_set_restrictions(struct dm_table *t,
> struct request_queue *q,
> dm_table_any_dev_attr(t, device_is_not_random, NULL))
> blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
>
> + /*
> + * A zoned target may contain only conventional zones, in which case
> + * we must set the device queue zoned model to BLK_ZONED_NONE to
> + * expose the target as a regular block device, and thus avoiding
> + * breaking the host-managed zoned model as it mandates the presence
> + * of sequential write required zones.
> + */
> + if (blk_queue_is_zoned(q)) {
> + r = dm_validate_zoned_model(t, q);
> + if (r)
> + return r;
> + }
> +
> /*
> * For a zoned target, setup the zones related queue attributes
> * and resources necessary for zone append emulation if necessary.
> diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c
> index eb9832b22b14..452a59bfdc10 100644
> --- a/drivers/md/dm-zone.c
> +++ b/drivers/md/dm-zone.c
> @@ -174,6 +174,69 @@ static unsigned int dm_get_zone_wp_offset(struct
> blk_zone *zone)
> }
> }
>
> +struct dm_zone_count {
> + unsigned long nr_conv;
> + unsigned long nr_seq;
> +};
> +
> +static int dm_validate_zoned_model_cb(struct blk_zone *zone, unsigned int
> idx,
> + void *data)
> +{
> + struct dm_zone_count *zc = data;
> +
> + switch (zone->type) {
> + case BLK_ZONE_TYPE_CONVENTIONAL:
> + zc->nr_conv++;
> + break;
> + case BLK_ZONE_TYPE_SEQWRITE_REQ:
> + case BLK_ZONE_TYPE_SEQWRITE_PREF:
> + zc->nr_seq++;
> + break;
> + default:
> + DMERR("Invalid zone type 0x%x at sectors %llu",
> + (int)zone->type, zone->start);
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Validate the queue zoned model by counting the conventional and
> + * sequential zones of the target. If no sequential zones are present, modify
> + * the device queue to expose it as a regular block device.
> + */
> +int dm_validate_zoned_model(struct dm_table *t, struct request_queue *q)
> +{
> + struct mapped_device *md = t->md;
> + struct gendisk *disk = md->disk;
> + unsigned int nr_zones = bdev_nr_zones(disk->part0);
> + struct dm_zone_count zc = { };
> + unsigned int noio_flag;
> + int ret;
> +
> + /* Count conventional and sequential zones */
> + noio_flag = memalloc_noio_save();
> + ret = dm_blk_do_report_zones(md, t, 0, nr_zones,
> + dm_validate_zoned_model_cb, &zc);
> + memalloc_noio_restore(noio_flag);
> + if (ret != nr_zones ||
> + zc.nr_conv + zc.nr_seq != nr_zones)
> + ret = -EIO;
> + if (ret < 0)
> + goto err;
> +
> + if (!zc.nr_seq)
> + disk_set_zoned(disk, BLK_ZONED_NONE);
> +
> + return 0;
> +
> +err:
> + DMERR("Validate zoned model failed %d", ret);
> + dm_cleanup_zoned_dev(md);
> + return ret;
> +}
> +
> static int dm_zone_revalidate_cb(struct blk_zone *zone, unsigned int idx,
> void *data)
> {
> diff --git a/drivers/md/dm.h b/drivers/md/dm.h
> index 7f1acbf6bd9e..c3e6afed3910 100644
> --- a/drivers/md/dm.h
> +++ b/drivers/md/dm.h
> @@ -101,6 +101,7 @@ int dm_setup_md_queue(struct mapped_device *md, struct
> dm_table *t);
> /*
> * Zoned targets related functions.
> */
> +int dm_validate_zoned_model(struct dm_table *t, struct request_queue *q);
> int dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q);
> void dm_zone_endio(struct dm_io *io, struct bio *clone);
> #ifdef CONFIG_BLK_DEV_ZONED
--
Damien Le Moal
Western Digital Research