]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
dm: Allow .prepare_ioctl to handle ioctls directly
authorKevin Wolf <kwolf@redhat.com>
Tue, 29 Apr 2025 16:50:17 +0000 (18:50 +0200)
committerMikulas Patocka <mpatocka@redhat.com>
Sun, 4 May 2025 09:35:05 +0000 (11:35 +0200)
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@redhat.com>
Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
drivers/md/dm-dust.c
drivers/md/dm-ebs-target.c
drivers/md/dm-flakey.c
drivers/md/dm-linear.c
drivers/md/dm-log-writes.c
drivers/md/dm-mpath.c
drivers/md/dm-switch.c
drivers/md/dm-verity-target.c
drivers/md/dm-zoned-target.c
drivers/md/dm.c
include/linux/device-mapper.h

index 1a33820c9f46a717b7ce67ae371b1151b6a7814c..e75310232bbfcd5e9f5f81eeed350fa5844b25d0 100644 (file)
@@ -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;
index b19b0142a690a34e39d323f38411a02b5da01416..6abb31ca966231ee25027535c7aeb7923c905203 100644 (file)
@@ -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;
index a8ee3df32d5f5f34289d25d3c82a77aa38d02c69..c711db6f8f5ca39e68b4ab43919be04607df9127 100644 (file)
@@ -648,7 +648,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;
 
index 66318aba4bdbadf717c046e9dab52d3fa4a96c1d..15538ec58f8e4dbc2780ffbb2202883a598dfcd6 100644 (file)
@@ -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;
index 8d7df8303d0a18198d06c9081368834d8bb5f41e..d484e8e1d48a93dc67f24f7504acb20530815b86 100644 (file)
@@ -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;
index 6c98f4ae5ea99b2b06172c6422b6813ef1571bde..909ed6890ba5805740daac0b414607e5f76ad02f 100644 (file)
@@ -2022,7 +2022,9 @@ out:
 }
 
 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;
index dfd9fb52a6f333f3003f7f51af3e38f902725c4a..bb1a70b5a2152b054004008ea6ac2744101d3664 100644 (file)
@@ -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;
index 4de2c226ac9db7805ade7c894d087ac419445f50..34a9f9fbd0d189ee1045d0945217a54512d0df0d 100644 (file)
@@ -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;
 
index 6141fc25d8421a4f3689eaa27b5c16aea25ef9e1..5da3db06da10300843fc72e894c1a0c4a99588da 100644 (file)
@@ -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];
index ccccc098b30e79a176697d1825106a38b9842e65..1726f0f828cc948e5698645273c3b83f0381bb0d 100644 (file)
@@ -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 @@ retry:
        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)
index bcc6d7b6947010d10f67300b9efe958c222e1e45..cb95951547abe7653ab3dff9020ad0b7d5242870 100644 (file)
@@ -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,