On Tue, 2025-04-29 at 18:50 +0200, Kevin Wolf wrote: > This adds a 'bool *forward' parameter to .prepare_ioctl, which allows > device mapper targets to accept ioctls to themselves instead of the > underlying device. If the target already fully handled the ioctl, it > sets *forward to false and device mapper won't forward it to the > underlying device any more. > > In order for targets to actually know what the ioctl is about and how > to > handle it, pass also cmd and arg. > > As long as targets restrict themselves to interpreting ioctls of type > DM_IOCTL, this is a backwards compatible change because previously, > any > such ioctl would have been passed down through all device mapper > layers > until it reached a device that can't understand the ioctl and would > return an error. > > Signed-off-by: Kevin Wolf <kwolf@xxxxxxxxxx> > --- > include/linux/device-mapper.h | 9 ++++++++- > drivers/md/dm-dust.c | 4 +++- > drivers/md/dm-ebs-target.c | 3 ++- > drivers/md/dm-flakey.c | 4 +++- > drivers/md/dm-linear.c | 4 +++- > drivers/md/dm-log-writes.c | 4 +++- > drivers/md/dm-mpath.c | 4 +++- > drivers/md/dm-switch.c | 4 +++- > drivers/md/dm-verity-target.c | 4 +++- > drivers/md/dm-zoned-target.c | 3 ++- > drivers/md/dm.c | 17 +++++++++++------ > 11 files changed, 44 insertions(+), 16 deletions(-) > > diff --git a/include/linux/device-mapper.h b/include/linux/device- > mapper.h > index bcc6d7b69470..cb95951547ab 100644 > --- a/include/linux/device-mapper.h > +++ b/include/linux/device-mapper.h > @@ -93,7 +93,14 @@ typedef void (*dm_status_fn) (struct dm_target > *ti, status_type_t status_type, > typedef int (*dm_message_fn) (struct dm_target *ti, unsigned int > argc, char **argv, > char *result, unsigned int maxlen); > > -typedef int (*dm_prepare_ioctl_fn) (struct dm_target *ti, struct > block_device **bdev); > +/* > + * Called with *forward == true. If it remains true, the ioctl > should be > + * forwarded to bdev. If it is reset to false, the target already > fully handled > + * the ioctl and the return value is the return value for the whole > ioctl. > + */ > +typedef int (*dm_prepare_ioctl_fn) (struct dm_target *ti, struct > block_device **bdev, > + unsigned int cmd, unsigned long arg, > + bool *forward); > > #ifdef CONFIG_BLK_DEV_ZONED > typedef int (*dm_report_zones_fn) (struct dm_target *ti, > diff --git a/drivers/md/dm-dust.c b/drivers/md/dm-dust.c > index 1a33820c9f46..e75310232bbf 100644 > --- a/drivers/md/dm-dust.c > +++ b/drivers/md/dm-dust.c > @@ -534,7 +534,9 @@ static void dust_status(struct dm_target *ti, > status_type_t type, > } > } > > -static int dust_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev) > +static int dust_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev, > + unsigned int cmd, unsigned long arg, > + bool *forward) > { > struct dust_device *dd = ti->private; > struct dm_dev *dev = dd->dev; > diff --git a/drivers/md/dm-ebs-target.c b/drivers/md/dm-ebs-target.c > index b19b0142a690..6abb31ca9662 100644 > --- a/drivers/md/dm-ebs-target.c > +++ b/drivers/md/dm-ebs-target.c > @@ -415,7 +415,8 @@ static void ebs_status(struct dm_target *ti, > status_type_t type, > } > } > > -static int ebs_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev) > +static int ebs_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev, > + unsigned int cmd, unsigned long arg, bool *forward) > { > struct ebs_c *ec = ti->private; > struct dm_dev *dev = ec->dev; > diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c > index b690905ab89f..0fceb08f4622 100644 > --- a/drivers/md/dm-flakey.c > +++ b/drivers/md/dm-flakey.c > @@ -638,7 +638,9 @@ static void flakey_status(struct dm_target *ti, > status_type_t type, > } > } > > -static int flakey_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev) > +static int flakey_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev, > + unsigned int cmd, unsigned long arg, > + bool *forward) > { > struct flakey_c *fc = ti->private; > > diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c > index 66318aba4bdb..15538ec58f8e 100644 > --- a/drivers/md/dm-linear.c > +++ b/drivers/md/dm-linear.c > @@ -119,7 +119,9 @@ static void linear_status(struct dm_target *ti, > status_type_t type, > } > } > > -static int linear_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev) > +static int linear_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev, > + unsigned int cmd, unsigned long arg, > + bool *forward) > { > struct linear_c *lc = ti->private; > struct dm_dev *dev = lc->dev; > diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c > index 8d7df8303d0a..d484e8e1d48a 100644 > --- a/drivers/md/dm-log-writes.c > +++ b/drivers/md/dm-log-writes.c > @@ -818,7 +818,9 @@ static void log_writes_status(struct dm_target > *ti, status_type_t type, > } > > static int log_writes_prepare_ioctl(struct dm_target *ti, > - struct block_device **bdev) > + struct block_device **bdev, > + unsigned int cmd, unsigned long arg, > + bool *forward) > { > struct log_writes_c *lc = ti->private; > struct dm_dev *dev = lc->dev; > diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c > index 6c98f4ae5ea9..909ed6890ba5 100644 > --- a/drivers/md/dm-mpath.c > +++ b/drivers/md/dm-mpath.c > @@ -2022,7 +2022,9 @@ static int multipath_message(struct dm_target > *ti, unsigned int argc, char **arg > } > > static int multipath_prepare_ioctl(struct dm_target *ti, > - struct block_device **bdev) > + struct block_device **bdev, > + unsigned int cmd, unsigned long arg, > + bool *forward) > { > struct multipath *m = ti->private; > struct pgpath *pgpath; > diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c > index dfd9fb52a6f3..bb1a70b5a215 100644 > --- a/drivers/md/dm-switch.c > +++ b/drivers/md/dm-switch.c > @@ -517,7 +517,9 @@ static void switch_status(struct dm_target *ti, > status_type_t type, > * > * Passthrough all ioctls to the path for sector 0 > */ > -static int switch_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev) > +static int switch_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev, > + unsigned int cmd, unsigned long arg, > + bool *forward) > { > struct switch_ctx *sctx = ti->private; > unsigned int path_nr; > diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity- > target.c > index 4de2c226ac9d..34a9f9fbd0d1 100644 > --- a/drivers/md/dm-verity-target.c > +++ b/drivers/md/dm-verity-target.c > @@ -994,7 +994,9 @@ static void verity_status(struct dm_target *ti, > status_type_t type, > } > } > > -static int verity_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev) > +static int verity_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev, > + unsigned int cmd, unsigned long arg, > + bool *forward) > { > struct dm_verity *v = ti->private; > > diff --git a/drivers/md/dm-zoned-target.c b/drivers/md/dm-zoned- > target.c > index 6141fc25d842..5da3db06da10 100644 > --- a/drivers/md/dm-zoned-target.c > +++ b/drivers/md/dm-zoned-target.c > @@ -1015,7 +1015,8 @@ static void dmz_io_hints(struct dm_target *ti, > struct queue_limits *limits) > /* > * Pass on ioctl to the backend device. > */ > -static int dmz_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev) > +static int dmz_prepare_ioctl(struct dm_target *ti, struct > block_device **bdev, > + unsigned int cmd, unsigned long arg, bool *forward) > { > struct dmz_target *dmz = ti->private; > struct dmz_dev *dev = &dmz->dev[0]; > diff --git a/drivers/md/dm.c b/drivers/md/dm.c > index ccccc098b30e..1726f0f828cc 100644 > --- a/drivers/md/dm.c > +++ b/drivers/md/dm.c > @@ -411,7 +411,8 @@ static int dm_blk_getgeo(struct block_device > *bdev, struct hd_geometry *geo) > } > > static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx, > - struct block_device **bdev) > + struct block_device **bdev, unsigned int cmd, > + unsigned long arg, bool *forward) > { > struct dm_target *ti; > struct dm_table *map; > @@ -434,8 +435,8 @@ static int dm_prepare_ioctl(struct mapped_device > *md, int *srcu_idx, > if (dm_suspended_md(md)) > return -EAGAIN; > > - r = ti->type->prepare_ioctl(ti, bdev); > - if (r == -ENOTCONN && !fatal_signal_pending(current)) { > + r = ti->type->prepare_ioctl(ti, bdev, cmd, arg, forward); > + if (r == -ENOTCONN && *forward && !fatal_signal_pending(current)) { > dm_put_live_table(md, *srcu_idx); > fsleep(10000); > goto retry; > @@ -454,9 +455,10 @@ static int dm_blk_ioctl(struct block_device > *bdev, blk_mode_t mode, > { > struct mapped_device *md = bdev->bd_disk->private_data; > int r, srcu_idx; > + bool forward = true; > > - r = dm_prepare_ioctl(md, &srcu_idx, &bdev); > - if (r < 0) > + r = dm_prepare_ioctl(md, &srcu_idx, &bdev, cmd, arg, &forward); > + if (!forward || r < 0) > goto out; > > if (r > 0) { > @@ -3630,10 +3632,13 @@ static int dm_pr_clear(struct block_device > *bdev, u64 key) > struct mapped_device *md = bdev->bd_disk->private_data; > const struct pr_ops *ops; > int r, srcu_idx; > + bool forward = true; > > - r = dm_prepare_ioctl(md, &srcu_idx, &bdev); > + /* Not a real ioctl, but targets must not interpret non-DM ioctls > */ > + r = dm_prepare_ioctl(md, &srcu_idx, &bdev, 0, 0, &forward); > if (r < 0) > goto out; > + WARN_ON_ONCE(!forward); > > ops = bdev->bd_disk->fops->pr_ops; > if (ops && ops->pr_clear)