mirror of https://github.com/torvalds/linux.git
dm: Allow .prepare_ioctl to handle ioctls directly
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>
This commit is contained in:
parent
13e79076c8
commit
4862c8861d
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue