mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-29 23:53:32 +00:00
dm: refactor ioctl handling
This moves the call to blkdev_ioctl and the argument checking to DM core code, and only leaves a callout to find the block device to operate on in the targets. This simplifies the code and allows us to pass through ioctl-like command using other methods in the next patch. Also split out a helper around calling the prepare_ioctl method that will be reused for persistent reservation handling. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
parent
47796938c4
commit
e56f81e0b0
8 changed files with 94 additions and 75 deletions
|
@ -373,20 +373,20 @@ static void flakey_status(struct dm_target *ti, status_type_t type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg)
|
static int flakey_prepare_ioctl(struct dm_target *ti,
|
||||||
|
struct block_device **bdev, fmode_t *mode)
|
||||||
{
|
{
|
||||||
struct flakey_c *fc = ti->private;
|
struct flakey_c *fc = ti->private;
|
||||||
struct dm_dev *dev = fc->dev;
|
|
||||||
int r = 0;
|
*bdev = fc->dev->bdev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only pass ioctls through if the device sizes match exactly.
|
* Only pass ioctls through if the device sizes match exactly.
|
||||||
*/
|
*/
|
||||||
if (fc->start ||
|
if (fc->start ||
|
||||||
ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
|
ti->len != i_size_read((*bdev)->bd_inode) >> SECTOR_SHIFT)
|
||||||
r = scsi_verify_blk_ioctl(NULL, cmd);
|
return 1;
|
||||||
|
return 0;
|
||||||
return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
|
static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
|
||||||
|
@ -405,7 +405,7 @@ static struct target_type flakey_target = {
|
||||||
.map = flakey_map,
|
.map = flakey_map,
|
||||||
.end_io = flakey_end_io,
|
.end_io = flakey_end_io,
|
||||||
.status = flakey_status,
|
.status = flakey_status,
|
||||||
.ioctl = flakey_ioctl,
|
.prepare_ioctl = flakey_prepare_ioctl,
|
||||||
.iterate_devices = flakey_iterate_devices,
|
.iterate_devices = flakey_iterate_devices,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -116,21 +116,21 @@ static void linear_status(struct dm_target *ti, status_type_t type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int linear_ioctl(struct dm_target *ti, unsigned int cmd,
|
static int linear_prepare_ioctl(struct dm_target *ti,
|
||||||
unsigned long arg)
|
struct block_device **bdev, fmode_t *mode)
|
||||||
{
|
{
|
||||||
struct linear_c *lc = (struct linear_c *) ti->private;
|
struct linear_c *lc = (struct linear_c *) ti->private;
|
||||||
struct dm_dev *dev = lc->dev;
|
struct dm_dev *dev = lc->dev;
|
||||||
int r = 0;
|
|
||||||
|
*bdev = dev->bdev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only pass ioctls through if the device sizes match exactly.
|
* Only pass ioctls through if the device sizes match exactly.
|
||||||
*/
|
*/
|
||||||
if (lc->start ||
|
if (lc->start ||
|
||||||
ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
|
ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
|
||||||
r = scsi_verify_blk_ioctl(NULL, cmd);
|
return 1;
|
||||||
|
return 0;
|
||||||
return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int linear_iterate_devices(struct dm_target *ti,
|
static int linear_iterate_devices(struct dm_target *ti,
|
||||||
|
@ -149,7 +149,7 @@ static struct target_type linear_target = {
|
||||||
.dtr = linear_dtr,
|
.dtr = linear_dtr,
|
||||||
.map = linear_map,
|
.map = linear_map,
|
||||||
.status = linear_status,
|
.status = linear_status,
|
||||||
.ioctl = linear_ioctl,
|
.prepare_ioctl = linear_prepare_ioctl,
|
||||||
.iterate_devices = linear_iterate_devices,
|
.iterate_devices = linear_iterate_devices,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -714,20 +714,19 @@ static void log_writes_status(struct dm_target *ti, status_type_t type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int log_writes_ioctl(struct dm_target *ti, unsigned int cmd,
|
static int log_writes_prepare_ioctl(struct dm_target *ti,
|
||||||
unsigned long arg)
|
struct block_device **bdev, fmode_t *mode)
|
||||||
{
|
{
|
||||||
struct log_writes_c *lc = ti->private;
|
struct log_writes_c *lc = ti->private;
|
||||||
struct dm_dev *dev = lc->dev;
|
struct dm_dev *dev = lc->dev;
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
|
*bdev = dev->bdev;
|
||||||
/*
|
/*
|
||||||
* Only pass ioctls through if the device sizes match exactly.
|
* Only pass ioctls through if the device sizes match exactly.
|
||||||
*/
|
*/
|
||||||
if (ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
|
if (ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
|
||||||
r = scsi_verify_blk_ioctl(NULL, cmd);
|
return 1;
|
||||||
|
return 0;
|
||||||
return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int log_writes_iterate_devices(struct dm_target *ti,
|
static int log_writes_iterate_devices(struct dm_target *ti,
|
||||||
|
@ -782,7 +781,7 @@ static struct target_type log_writes_target = {
|
||||||
.map = log_writes_map,
|
.map = log_writes_map,
|
||||||
.end_io = normal_end_io,
|
.end_io = normal_end_io,
|
||||||
.status = log_writes_status,
|
.status = log_writes_status,
|
||||||
.ioctl = log_writes_ioctl,
|
.prepare_ioctl = log_writes_prepare_ioctl,
|
||||||
.message = log_writes_message,
|
.message = log_writes_message,
|
||||||
.iterate_devices = log_writes_iterate_devices,
|
.iterate_devices = log_writes_iterate_devices,
|
||||||
.io_hints = log_writes_io_hints,
|
.io_hints = log_writes_io_hints,
|
||||||
|
|
|
@ -1533,18 +1533,14 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
|
static int multipath_prepare_ioctl(struct dm_target *ti,
|
||||||
unsigned long arg)
|
struct block_device **bdev, fmode_t *mode)
|
||||||
{
|
{
|
||||||
struct multipath *m = ti->private;
|
struct multipath *m = ti->private;
|
||||||
struct pgpath *pgpath;
|
struct pgpath *pgpath;
|
||||||
struct block_device *bdev;
|
|
||||||
fmode_t mode;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
bdev = NULL;
|
|
||||||
mode = 0;
|
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&m->lock, flags);
|
spin_lock_irqsave(&m->lock, flags);
|
||||||
|
@ -1555,23 +1551,17 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
|
||||||
pgpath = m->current_pgpath;
|
pgpath = m->current_pgpath;
|
||||||
|
|
||||||
if (pgpath) {
|
if (pgpath) {
|
||||||
bdev = pgpath->path.dev->bdev;
|
*bdev = pgpath->path.dev->bdev;
|
||||||
mode = pgpath->path.dev->mode;
|
*mode = pgpath->path.dev->mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
|
if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
|
||||||
r = -ENOTCONN;
|
r = -ENOTCONN;
|
||||||
else if (!bdev)
|
else if (!*bdev)
|
||||||
r = -EIO;
|
r = -EIO;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&m->lock, flags);
|
spin_unlock_irqrestore(&m->lock, flags);
|
||||||
|
|
||||||
/*
|
|
||||||
* Only pass ioctls through if the device sizes match exactly.
|
|
||||||
*/
|
|
||||||
if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
|
|
||||||
r = scsi_verify_blk_ioctl(NULL, cmd);
|
|
||||||
|
|
||||||
if (r == -ENOTCONN && !fatal_signal_pending(current)) {
|
if (r == -ENOTCONN && !fatal_signal_pending(current)) {
|
||||||
spin_lock_irqsave(&m->lock, flags);
|
spin_lock_irqsave(&m->lock, flags);
|
||||||
if (!m->current_pg) {
|
if (!m->current_pg) {
|
||||||
|
@ -1584,7 +1574,12 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
|
||||||
dm_table_run_md_queue_async(m->ti->table);
|
dm_table_run_md_queue_async(m->ti->table);
|
||||||
}
|
}
|
||||||
|
|
||||||
return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
/*
|
||||||
|
* Only pass ioctls through if the device sizes match exactly.
|
||||||
|
*/
|
||||||
|
if (!r && ti->len != i_size_read((*bdev)->bd_inode) >> SECTOR_SHIFT)
|
||||||
|
return 1;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int multipath_iterate_devices(struct dm_target *ti,
|
static int multipath_iterate_devices(struct dm_target *ti,
|
||||||
|
@ -1700,7 +1695,7 @@ static struct target_type multipath_target = {
|
||||||
.resume = multipath_resume,
|
.resume = multipath_resume,
|
||||||
.status = multipath_status,
|
.status = multipath_status,
|
||||||
.message = multipath_message,
|
.message = multipath_message,
|
||||||
.ioctl = multipath_ioctl,
|
.prepare_ioctl = multipath_prepare_ioctl,
|
||||||
.iterate_devices = multipath_iterate_devices,
|
.iterate_devices = multipath_iterate_devices,
|
||||||
.busy = multipath_busy,
|
.busy = multipath_busy,
|
||||||
};
|
};
|
||||||
|
|
|
@ -511,27 +511,24 @@ static void switch_status(struct dm_target *ti, status_type_t type,
|
||||||
*
|
*
|
||||||
* Passthrough all ioctls to the path for sector 0
|
* Passthrough all ioctls to the path for sector 0
|
||||||
*/
|
*/
|
||||||
static int switch_ioctl(struct dm_target *ti, unsigned cmd,
|
static int switch_prepare_ioctl(struct dm_target *ti,
|
||||||
unsigned long arg)
|
struct block_device **bdev, fmode_t *mode)
|
||||||
{
|
{
|
||||||
struct switch_ctx *sctx = ti->private;
|
struct switch_ctx *sctx = ti->private;
|
||||||
struct block_device *bdev;
|
|
||||||
fmode_t mode;
|
|
||||||
unsigned path_nr;
|
unsigned path_nr;
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
path_nr = switch_get_path_nr(sctx, 0);
|
path_nr = switch_get_path_nr(sctx, 0);
|
||||||
|
|
||||||
bdev = sctx->path_list[path_nr].dmdev->bdev;
|
*bdev = sctx->path_list[path_nr].dmdev->bdev;
|
||||||
mode = sctx->path_list[path_nr].dmdev->mode;
|
*mode = sctx->path_list[path_nr].dmdev->mode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only pass ioctls through if the device sizes match exactly.
|
* Only pass ioctls through if the device sizes match exactly.
|
||||||
*/
|
*/
|
||||||
if (ti->len + sctx->path_list[path_nr].start != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
|
if (ti->len + sctx->path_list[path_nr].start !=
|
||||||
r = scsi_verify_blk_ioctl(NULL, cmd);
|
i_size_read((*bdev)->bd_inode) >> SECTOR_SHIFT)
|
||||||
|
return 1;
|
||||||
return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int switch_iterate_devices(struct dm_target *ti,
|
static int switch_iterate_devices(struct dm_target *ti,
|
||||||
|
@ -560,7 +557,7 @@ static struct target_type switch_target = {
|
||||||
.map = switch_map,
|
.map = switch_map,
|
||||||
.message = switch_message,
|
.message = switch_message,
|
||||||
.status = switch_status,
|
.status = switch_status,
|
||||||
.ioctl = switch_ioctl,
|
.prepare_ioctl = switch_prepare_ioctl,
|
||||||
.iterate_devices = switch_iterate_devices,
|
.iterate_devices = switch_iterate_devices,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -631,18 +631,17 @@ static void verity_status(struct dm_target *ti, status_type_t type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verity_ioctl(struct dm_target *ti, unsigned cmd,
|
static int verity_prepare_ioctl(struct dm_target *ti,
|
||||||
unsigned long arg)
|
struct block_device **bdev, fmode_t *mode)
|
||||||
{
|
{
|
||||||
struct dm_verity *v = ti->private;
|
struct dm_verity *v = ti->private;
|
||||||
int r = 0;
|
|
||||||
|
*bdev = v->data_dev->bdev;
|
||||||
|
|
||||||
if (v->data_start ||
|
if (v->data_start ||
|
||||||
ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
|
ti->len != i_size_read(v->data_dev->bdev->bd_inode) >> SECTOR_SHIFT)
|
||||||
r = scsi_verify_blk_ioctl(NULL, cmd);
|
return 1;
|
||||||
|
return 0;
|
||||||
return r ? : __blkdev_driver_ioctl(v->data_dev->bdev, v->data_dev->mode,
|
|
||||||
cmd, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verity_iterate_devices(struct dm_target *ti,
|
static int verity_iterate_devices(struct dm_target *ti,
|
||||||
|
@ -965,7 +964,7 @@ static struct target_type verity_target = {
|
||||||
.dtr = verity_dtr,
|
.dtr = verity_dtr,
|
||||||
.map = verity_map,
|
.map = verity_map,
|
||||||
.status = verity_status,
|
.status = verity_status,
|
||||||
.ioctl = verity_ioctl,
|
.prepare_ioctl = verity_prepare_ioctl,
|
||||||
.iterate_devices = verity_iterate_devices,
|
.iterate_devices = verity_iterate_devices,
|
||||||
.io_hints = verity_io_hints,
|
.io_hints = verity_io_hints,
|
||||||
};
|
};
|
||||||
|
|
|
@ -555,18 +555,16 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
||||||
return dm_get_geometry(md, geo);
|
return dm_get_geometry(md, geo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
|
static int dm_get_live_table_for_ioctl(struct mapped_device *md,
|
||||||
unsigned int cmd, unsigned long arg)
|
struct dm_target **tgt, struct block_device **bdev,
|
||||||
|
fmode_t *mode, int *srcu_idx)
|
||||||
{
|
{
|
||||||
struct mapped_device *md = bdev->bd_disk->private_data;
|
|
||||||
int srcu_idx;
|
|
||||||
struct dm_table *map;
|
struct dm_table *map;
|
||||||
struct dm_target *tgt;
|
int r;
|
||||||
int r = -ENOTTY;
|
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
map = dm_get_live_table(md, &srcu_idx);
|
r = -ENOTTY;
|
||||||
|
map = dm_get_live_table(md, srcu_idx);
|
||||||
if (!map || !dm_table_get_size(map))
|
if (!map || !dm_table_get_size(map))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -574,8 +572,9 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
if (dm_table_get_num_targets(map) != 1)
|
if (dm_table_get_num_targets(map) != 1)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
tgt = dm_table_get_target(map, 0);
|
*tgt = dm_table_get_target(map, 0);
|
||||||
if (!tgt->type->ioctl)
|
|
||||||
|
if (!(*tgt)->type->prepare_ioctl)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (dm_suspended_md(md)) {
|
if (dm_suspended_md(md)) {
|
||||||
|
@ -583,16 +582,46 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = tgt->type->ioctl(tgt, cmd, arg);
|
r = (*tgt)->type->prepare_ioctl(*tgt, bdev, mode);
|
||||||
|
if (r < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
dm_put_live_table(md, srcu_idx);
|
dm_put_live_table(md, *srcu_idx);
|
||||||
|
|
||||||
if (r == -ENOTCONN) {
|
if (r == -ENOTCONN) {
|
||||||
msleep(10);
|
msleep(10);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
struct mapped_device *md = bdev->bd_disk->private_data;
|
||||||
|
struct dm_target *tgt;
|
||||||
|
int srcu_idx, r;
|
||||||
|
|
||||||
|
r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (r > 0) {
|
||||||
|
/*
|
||||||
|
* Target determined this ioctl is being issued against
|
||||||
|
* a logical partition of the parent bdev; so extra
|
||||||
|
* validation is needed.
|
||||||
|
*/
|
||||||
|
r = scsi_verify_blk_ioctl(NULL, cmd);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||||
|
out:
|
||||||
|
dm_put_live_table(md, srcu_idx);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ typedef void (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
|
||||||
|
|
||||||
typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
|
typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
|
||||||
|
|
||||||
typedef int (*dm_ioctl_fn) (struct dm_target *ti, unsigned int cmd,
|
typedef int (*dm_prepare_ioctl_fn) (struct dm_target *ti,
|
||||||
unsigned long arg);
|
struct block_device **bdev, fmode_t *mode);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These iteration functions are typically used to check (and combine)
|
* These iteration functions are typically used to check (and combine)
|
||||||
|
@ -156,7 +156,7 @@ struct target_type {
|
||||||
dm_resume_fn resume;
|
dm_resume_fn resume;
|
||||||
dm_status_fn status;
|
dm_status_fn status;
|
||||||
dm_message_fn message;
|
dm_message_fn message;
|
||||||
dm_ioctl_fn ioctl;
|
dm_prepare_ioctl_fn prepare_ioctl;
|
||||||
dm_busy_fn busy;
|
dm_busy_fn busy;
|
||||||
dm_iterate_devices_fn iterate_devices;
|
dm_iterate_devices_fn iterate_devices;
|
||||||
dm_io_hints_fn io_hints;
|
dm_io_hints_fn io_hints;
|
||||||
|
|
Loading…
Reference in a new issue