Skip to content

Commit

Permalink
dm ioctl: add a new DM_DEV_ARM_POLL ioctl
Browse files Browse the repository at this point in the history
This ioctl will record the current global event number in the structure
dm_file, so that next select or poll call will wait until new events
arrived since this ioctl.

The DM_DEV_ARM_POLL ioctl has the same effect as closing and reopening
the handle.

Using the DM_DEV_ARM_POLL ioctl is optional - if the userspace is OK
with closing and reopening the /dev/mapper/control handle after select
or poll, there is no need to re-arm via ioctl.

Usage:
1. open the /dev/mapper/control device
2. send the DM_DEV_ARM_POLL ioctl
3. scan the event numbers of all devices we are interested in and process
   them
4. call select, poll or epoll on the handle (it waits until some new event
   happens since the DM_DEV_ARM_POLL ioctl)
5. go to step 2

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Andy Grover <agrover@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
  • Loading branch information
Mikulas Patocka authored and Mike Snitzer committed Jun 19, 2017
1 parent 93e6442 commit fc1841e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 22 deletions.
56 changes: 35 additions & 21 deletions drivers/md/dm-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct dm_file {
* poll will wait until the global event number is greater than
* this value.
*/
unsigned global_event_nr;
volatile unsigned global_event_nr;
};

/*-----------------------------------------------------------------
Expand Down Expand Up @@ -464,9 +464,9 @@ void dm_deferred_remove(void)
* All the ioctl commands get dispatched to functions with this
* prototype.
*/
typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
typedef int (*ioctl_fn)(struct file *filp, struct dm_ioctl *param, size_t param_size);

static int remove_all(struct dm_ioctl *param, size_t param_size)
static int remove_all(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
dm_hash_remove_all(true, !!(param->flags & DM_DEFERRED_REMOVE), false);
param->data_size = 0;
Expand Down Expand Up @@ -499,7 +499,7 @@ static void *get_result_buffer(struct dm_ioctl *param, size_t param_size,
return ((void *) param) + param->data_start;
}

static int list_devices(struct dm_ioctl *param, size_t param_size)
static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
unsigned int i;
struct hash_cell *hc;
Expand Down Expand Up @@ -590,7 +590,7 @@ static void list_version_get_info(struct target_type *tt, void *param)
info->vers = align_ptr(((void *) ++info->vers) + strlen(tt->name) + 1);
}

static int list_versions(struct dm_ioctl *param, size_t param_size)
static int list_versions(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
size_t len, needed = 0;
struct dm_target_versions *vers;
Expand Down Expand Up @@ -732,7 +732,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
}
}

static int dev_create(struct dm_ioctl *param, size_t param_size)
static int dev_create(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
int r, m = DM_ANY_MINOR;
struct mapped_device *md;
Expand Down Expand Up @@ -824,7 +824,7 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
return md;
}

static int dev_remove(struct dm_ioctl *param, size_t param_size)
static int dev_remove(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
struct hash_cell *hc;
struct mapped_device *md;
Expand Down Expand Up @@ -889,7 +889,7 @@ static int invalid_str(char *str, void *end)
return -EINVAL;
}

static int dev_rename(struct dm_ioctl *param, size_t param_size)
static int dev_rename(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
int r;
char *new_data = (char *) param + param->data_start;
Expand Down Expand Up @@ -919,7 +919,7 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
return 0;
}

static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
static int dev_set_geometry(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
int r = -EINVAL, x;
struct mapped_device *md;
Expand Down Expand Up @@ -1068,7 +1068,7 @@ static int do_resume(struct dm_ioctl *param)
* Set or unset the suspension state of a device.
* If the device already is in the requested state we just return its status.
*/
static int dev_suspend(struct dm_ioctl *param, size_t param_size)
static int dev_suspend(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
if (param->flags & DM_SUSPEND_FLAG)
return do_suspend(param);
Expand All @@ -1080,7 +1080,7 @@ static int dev_suspend(struct dm_ioctl *param, size_t param_size)
* Copies device info back to user space, used by
* the create and info ioctls.
*/
static int dev_status(struct dm_ioctl *param, size_t param_size)
static int dev_status(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
struct mapped_device *md;

Expand Down Expand Up @@ -1171,7 +1171,7 @@ static void retrieve_status(struct dm_table *table,
/*
* Wait for a device to report an event
*/
static int dev_wait(struct dm_ioctl *param, size_t param_size)
static int dev_wait(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
int r = 0;
struct mapped_device *md;
Expand Down Expand Up @@ -1208,6 +1208,19 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
return r;
}

/*
* Remember the global event number and make it possible to poll
* for further events.
*/
static int dev_arm_poll(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
struct dm_file *priv = filp->private_data;

priv->global_event_nr = atomic_read(&dm_global_event_nr);

return 0;
}

static inline fmode_t get_mode(struct dm_ioctl *param)
{
fmode_t mode = FMODE_READ | FMODE_WRITE;
Expand Down Expand Up @@ -1277,7 +1290,7 @@ static bool is_valid_type(enum dm_queue_mode cur, enum dm_queue_mode new)
return false;
}

static int table_load(struct dm_ioctl *param, size_t param_size)
static int table_load(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
int r;
struct hash_cell *hc;
Expand Down Expand Up @@ -1364,7 +1377,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
return r;
}

static int table_clear(struct dm_ioctl *param, size_t param_size)
static int table_clear(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
struct hash_cell *hc;
struct mapped_device *md;
Expand Down Expand Up @@ -1438,7 +1451,7 @@ static void retrieve_deps(struct dm_table *table,
param->data_size = param->data_start + needed;
}

static int table_deps(struct dm_ioctl *param, size_t param_size)
static int table_deps(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
struct mapped_device *md;
struct dm_table *table;
Expand All @@ -1464,7 +1477,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
* Return the status of a device as a text string for each
* target.
*/
static int table_status(struct dm_ioctl *param, size_t param_size)
static int table_status(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
struct mapped_device *md;
struct dm_table *table;
Expand Down Expand Up @@ -1519,7 +1532,7 @@ static int message_for_md(struct mapped_device *md, unsigned argc, char **argv,
/*
* Pass a message to the target that's at the supplied device offset.
*/
static int target_message(struct dm_ioctl *param, size_t param_size)
static int target_message(struct file *filp, struct dm_ioctl *param, size_t param_size)
{
int r, argc;
char **argv;
Expand Down Expand Up @@ -1636,7 +1649,8 @@ static ioctl_fn lookup_ioctl(unsigned int cmd, int *ioctl_flags)
{DM_LIST_VERSIONS_CMD, 0, list_versions},

{DM_TARGET_MSG_CMD, 0, target_message},
{DM_DEV_SET_GEOMETRY_CMD, 0, dev_set_geometry}
{DM_DEV_SET_GEOMETRY_CMD, 0, dev_set_geometry},
{DM_DEV_ARM_POLL, IOCTL_FLAGS_NO_PARAMS, dev_arm_poll},
};

if (unlikely(cmd >= ARRAY_SIZE(_ioctls)))
Expand Down Expand Up @@ -1791,7 +1805,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param)
return 0;
}

static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
static int ctl_ioctl(struct file *file, uint command, struct dm_ioctl __user *user)
{
int r = 0;
int ioctl_flags;
Expand Down Expand Up @@ -1845,7 +1859,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
goto out;

param->data_size = offsetof(struct dm_ioctl, data);
r = fn(param, input_param_size);
r = fn(file, param, input_param_size);

if (unlikely(param->flags & DM_BUFFER_FULL_FLAG) &&
unlikely(ioctl_flags & IOCTL_FLAGS_NO_PARAMS))
Expand All @@ -1864,7 +1878,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user)

static long dm_ctl_ioctl(struct file *file, uint command, ulong u)
{
return (long)ctl_ioctl(command, (struct dm_ioctl __user *)u);
return (long)ctl_ioctl(file, command, (struct dm_ioctl __user *)u);
}

#ifdef CONFIG_COMPAT
Expand Down
4 changes: 3 additions & 1 deletion include/uapi/linux/dm-ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ enum {
/* Added later */
DM_LIST_VERSIONS_CMD,
DM_TARGET_MSG_CMD,
DM_DEV_SET_GEOMETRY_CMD
DM_DEV_SET_GEOMETRY_CMD,
DM_DEV_ARM_POLL_CMD,
};

#define DM_IOCTL 0xfd
Expand All @@ -255,6 +256,7 @@ enum {
#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
#define DM_DEV_ARM_POLL _IOWR(DM_IOCTL, DM_DEV_ARM_POLL_CMD, struct dm_ioctl)

#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
Expand Down

0 comments on commit fc1841e

Please sign in to comment.