A target type may be implementing a zoned model different from that of the table devices. This means that the compatibility of the table devices zoned models and zone sizes should not be checked against the zoned model and zone size indicated by the stacked limits. Fix validate_hardware_zoned_model() so that compatibility of zoned models and zone sizes is done only between the table devices, ignoring the stacked limits values. Signed-off-by: Damien Le Moal <damien.lemoal@xxxxxxx> --- drivers/md/dm-table.c | 99 +++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 9ba58d3..9849042 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1381,83 +1381,82 @@ bool dm_table_has_no_data_devices(struct dm_table *table) return true; } -static int device_is_zoned_model(struct dm_target *ti, struct dm_dev *dev, - sector_t start, sector_t len, void *data) +static int device_matches_zoned_model(struct dm_target *ti, struct dm_dev *dev, + sector_t start, sector_t len, void *data) { - struct request_queue *q = bdev_get_queue(dev->bdev); + struct block_device *bdev = dev->bdev; enum blk_zoned_model *zoned_model = data; - return q && blk_queue_zoned_model(q) == *zoned_model; -} - -static bool dm_table_supports_zoned_model(struct dm_table *t, - enum blk_zoned_model zoned_model) -{ - struct dm_target *ti; - unsigned i; - - for (i = 0; i < dm_table_get_num_targets(t); i++) { - ti = dm_table_get_target(t, i); - - if (zoned_model == BLK_ZONED_HM && - !dm_target_supports_zoned_hm(ti->type)) - return false; + if (bdev_zoned_model(bdev) == BLK_ZONED_HM && + !dm_target_supports_zoned_hm(ti->type)) + return 0; - if (!ti->type->iterate_devices || - !ti->type->iterate_devices(ti, device_is_zoned_model, &zoned_model)) - return false; - } + if (*zoned_model == -1) { + *zoned_model = bdev_zoned_model(bdev); + return 1; + } - return true; + return bdev_zoned_model(bdev) == *zoned_model; } static int device_matches_zone_sectors(struct dm_target *ti, struct dm_dev *dev, sector_t start, sector_t len, void *data) { - struct request_queue *q = bdev_get_queue(dev->bdev); + struct block_device *bdev = dev->bdev; unsigned int *zone_sectors = data; - return q && blk_queue_zone_sectors(q) == *zone_sectors; -} - -static bool dm_table_matches_zone_sectors(struct dm_table *t, - unsigned int zone_sectors) -{ - struct dm_target *ti; - unsigned i; - - for (i = 0; i < dm_table_get_num_targets(t); i++) { - ti = dm_table_get_target(t, i); - - if (!ti->type->iterate_devices || - !ti->type->iterate_devices(ti, device_matches_zone_sectors, &zone_sectors)) - return false; + if (*zone_sectors == -1) { + *zone_sectors = bdev_zone_sectors(bdev); + return 1; } - return true; + return bdev_zone_sectors(bdev) == *zone_sectors; } static int validate_hardware_zoned_model(struct dm_table *table, struct queue_limits *limits) { - if (!dm_table_supports_zoned_model(table, limits->zoned)) { - DMERR("%s: zoned model is inconsistent across all devices", - dm_device_name(table->md)); - return -EINVAL; - } + enum blk_zoned_model zoned_model = -1; + sector_t zone_sectors = -1; + struct dm_target *ti; + unsigned i; if (limits->zoned != BLK_ZONED_NONE) { - unsigned int zone_sectors = limits->chunk_sectors; - - /* Check zone size validity and compatibility */ + /* Check stacked limits zone size validity */ + zone_sectors = limits->chunk_sectors; if (!zone_sectors || !is_power_of_2(zone_sectors)) return -EINVAL; + } - if (!dm_table_matches_zone_sectors(table, zone_sectors)) { - DMERR("%s: zone sectors is inconsistent across all devices", + /* + * Check table devices zoned model and zone size compatibility. + * This is done for any type of stacked limits zoned model since the + * table targets may have overriden the zoned model of the devices + * (e.g. the target type is doing emulation of a different zoned model). + */ + for (i = 0; i < dm_table_get_num_targets(table); i++) { + ti = dm_table_get_target(table, i); + + if (limits->zoned != BLK_ZONED_NONE && + !ti->type->iterate_devices) + /* Cannot check */ + return -EINVAL; + + /* Check device zoned model compatibility */ + if (!ti->type->iterate_devices(ti, device_matches_zoned_model, + &zoned_model)) { + DMERR("%s: zoned model is inconsistent across all devices", dm_device_name(table->md)); return -EINVAL; } + + /* Check device zone size compatibility */ + if (!ti->type->iterate_devices(ti, device_matches_zone_sectors, + &zone_sectors)) { + DMERR("%s: zone sectors is inconsistent across all devices", + dm_device_name(table->md)); + return -EINVAL; + } } return 0; -- 2.9.4 Western Digital Corporation (and its subsidiaries) E-mail Confidentiality Notice & Disclaimer: This e-mail and any files transmitted with it may contain confidential or legally privileged information of WDC and/or its affiliates, and are intended solely for the use of the individual or entity to which they are addressed. If you are not the intended recipient, any disclosure, copying, distribution or any action taken or omitted to be taken in reliance on it, is prohibited. If you have received this e-mail in error, please notify the sender immediately and delete the e-mail in its entirety from your system. -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel