On 10/26/23 08:50, Mike Snitzer wrote: > On Wed, Oct 25 2023 at 5:34P -0400, > Damien Le Moal <dlemoal@xxxxxxxxxx> wrote: > >> On 10/26/23 00:03, Mike Snitzer wrote: >>> On Wed, Oct 25 2023 at 3:23P -0400, >>> Damien Le Moal <dlemoal@xxxxxxxxxx> wrote: >>> >>>> dm-error is used in several test cases in the xfstests test suite to >>>> check the handling of IO errors in file systems. However, with several >>>> file systems getting native support for zoned block devices (e.g. btrfs >>>> and f2fs), dm-error lack of zoned block device support creates problems >>>> as the file system attempt executing zone commands (e.g. a zone append >>>> operation) against a dm-error non-zoned block device, which causes >>>> various issues in the block layer (e.g. WARN_ON triggers). >>>> >>>> This patch adds supports for zoned block devices to dm-error, allowing >>>> an error table to be exposed as a zoned block device. This is done by >>>> relying on the first argument passed to dmsetup when creating the device >>>> table: if that first argument is a path to a backing block device, the >>>> dm-error device is created by copying the limits of the backing device, >>>> thus also copying its zone model. This is consistent with how xfstests >>>> creates dm-error devices (always passing the path to the backing device >>>> as the first argument). >>>> >>>> The zone support for dm-error requires the definition of the >>>> report_zones target type method, which is done by introducing the >>>> function io_err_report_zones(). Given that this function fails report >>>> zones operations (similarly to any other command issued to the dm-error >>>> device), dm_set_zones_restrictions() is tweaked to do nothing for a >>>> wildcard target to avoid failing zone revalidation. As the dm-error >>>> target does not implement the iterate_devices method, >>>> dm_table_supports_zoned_model() is also changed to return true. >>>> >>>> Signed-off-by: Damien Le Moal <dlemoal@xxxxxxxxxx> >>>> Reviewed-by: Christoph Hellwig <hch@xxxxxx> >>>> Tested-by: Christoph Hellwig <hch@xxxxxx> >>>> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@xxxxxxx> >>>> --- >>>> Changes from v1: >>>> - Improved comment in io_err_ctr() about error from dm_get_device() >>>> being ignored >>>> - Fixed typos in the commit message >>>> - Added review and tested-by tags >>> >>> Thanks for the improvements. But likely a v3 is worthwhile. >>> >>> Comment inlined below. >>> >>>> >>>> drivers/md/dm-table.c | 3 +++ >>>> drivers/md/dm-target.c | 45 ++++++++++++++++++++++++++++++++++++++++-- >>>> drivers/md/dm-zone.c | 9 +++++++++ >>>> 3 files changed, 55 insertions(+), 2 deletions(-) >>>> >>>> diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c >>>> index 37b48f63ae6a..5e4d887063d3 100644 >>>> --- a/drivers/md/dm-table.c >>>> +++ b/drivers/md/dm-table.c >>>> @@ -1600,6 +1600,9 @@ static bool dm_table_supports_zoned_model(struct dm_table *t, >>>> for (unsigned int i = 0; i < t->num_targets; i++) { >>>> struct dm_target *ti = dm_table_get_target(t, i); >>>> >>>> + if (dm_target_is_wildcard(ti->type)) >>>> + continue; >>>> + >>>> if (dm_target_supports_zoned_hm(ti->type)) { >>>> if (!ti->type->iterate_devices || >>>> ti->type->iterate_devices(ti, device_not_zoned_model, >>>> diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c >>>> index 27e2992ff249..fcb2ba2bffa2 100644 >>>> --- a/drivers/md/dm-target.c >>>> +++ b/drivers/md/dm-target.c >>>> @@ -118,6 +118,24 @@ EXPORT_SYMBOL(dm_unregister_target); >>>> */ >>>> static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args) >>>> { >>>> + struct dm_dev *ddev; >>>> + int ret; >>>> + >>>> + /* >>>> + * If we have an argument, assume it is the path to the backing >>>> + * block device that we are replacing. In this case, get the device >>>> + * so that we can copy its limits in io_err_io_hints(). If getting the >>>> + * device fails (e.g. because the user did not specify a device file >>>> + * path), ignore the error to be compatible with the normal use case >>>> + * without any argument specified. >>>> + */ >>>> + if (argc) { >>>> + ret = dm_get_device(tt, args[0], dm_table_get_mode(tt->table), >>>> + &ddev); >>>> + if (ret == 0) >>>> + tt->private = ddev; >>>> + } >>>> + >>>> /* >>>> * Return error for discards instead of -EOPNOTSUPP >>>> */ >>>> >>>> @@ -129,7 +147,10 @@ static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args) >>>> >>>> static void io_err_dtr(struct dm_target *tt) >>>> { >>>> - /* empty */ >>>> + struct dm_dev *ddev = tt->private; >>>> + >>>> + if (ddev) >>>> + dm_put_device(tt, ddev); >>>> } >>>> >>>> static int io_err_map(struct dm_target *tt, struct bio *bio) >>>> @@ -149,8 +170,27 @@ static void io_err_release_clone_rq(struct request *clone, >>>> { >>>> } >>>> >>>> +#ifdef CONFIG_BLK_DEV_ZONED >>>> +static int io_err_report_zones(struct dm_target *ti, >>>> + struct dm_report_zones_args *args, unsigned int nr_zones) >>>> +{ >>>> + return -EIO; >>>> +} >>>> +#else >>>> +#define io_err_report_zones NULL >>>> +#endif >>>> + >>>> static void io_err_io_hints(struct dm_target *ti, struct queue_limits *limits) >>>> { >>>> + struct dm_dev *ddev = ti->private; >>>> + >>>> + /* If we have a target device, copy its limits */ >>>> + if (ddev) { >>>> + struct request_queue *q = bdev_get_queue(ddev->bdev); >>>> + >>>> + memcpy(limits, &q->limits, sizeof(*limits)); >>>> + } >>>> + >>>> limits->max_discard_sectors = UINT_MAX; >>>> limits->max_hw_discard_sectors = UINT_MAX; >>>> limits->discard_granularity = 512; >>> >>> >>> You don't need to explicitly copy the queue_limits, DM core >>> (dm-table.c:dm_calculate_queue_limits) will stack up the underlying >>> device's queue_limits as long as you implement io_err_iterate_devices >>> (like dm-linear.c:linear_iterate_devices). >>> >>> With io_err_iterate_devices you shouldn't need to change >>> io_err_io_hints -- but actually I could see there being a need to wrap >>> setting the above no-device defaults only if (!ddev).. or: >>> if (ddev) >>> return; >> >> Works for me, but I do not see how iterate_devices would work if there is no >> backing device specified (current default). Am I missing something ? > > You don't call 'fn' if the ddev (ti->private) is NULL. > >> Also, >> doesn't adding the iterate_devices method allow combining dm-error with other dm >> targets in the same table, something that is not possible currently ? So that >> would change dm-error usage. OK with me, but I want to make sure. > > No, iterate_devices is purely for iterating within a given target's > devices to call the provide 'fn'. > > What I suggested doesn't change combining dm-error with other targets > in the same table. But we do allow that, think of a table with > multiple linear targets and a subset that is the error target. I was confused about that because my test script had a problem and was failing to setup a dm-linear+dm-error combination. I now have that working and I can check the combination. So adding the iterate device now makes sense for the zone stuff. Will do that. Thanks for the details. Sending a v3. > >> But it may be that I am missing something because of the wildcard flag. Is do >> not fully understand how that one impacts anything. Is that flag responsible for >> preventing dm-error to be combined with other targets ? > > /* > * Indicates that a target may replace any target; even immutable targets. > * .map, .map_rq, .clone_and_map_rq and .release_clone_rq are all defined. > */ > #define DM_TARGET_WILDCARD 0x00000008 > > Just means that the error target can replace all types of DM targets > (its the only DM target that sets the DM_TARGET_WILDCARD flag). > > Mike > -- Damien Le Moal Western Digital Research