diff options
-rw-r--r-- | drivers/md/dm-core.h | 3 | ||||
-rw-r--r-- | drivers/md/dm-ioctl.c | 49 | ||||
-rw-r--r-- | drivers/md/dm.c | 5 |
3 files changed, 56 insertions, 1 deletions
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 52ca8d059e82..24eddbdf2ab4 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -147,4 +147,7 @@ static inline bool dm_message_test_buffer_overflow(char *result, unsigned maxlen return !maxlen || strlen(result) + 1 >= maxlen; } +extern atomic_t dm_global_event_nr; +extern wait_queue_head_t dm_global_eventq; + #endif diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 41852ae287a5..6b65a538d91d 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -23,6 +23,14 @@ #define DM_MSG_PREFIX "ioctl" #define DM_DRIVER_EMAIL "dm-devel@redhat.com" +struct dm_file { + /* + * poll will wait until the global event number is greater than + * this value. + */ + unsigned global_event_nr; +}; + /*----------------------------------------------------------------- * The ioctl interface needs to be able to look up devices by * name or uuid. @@ -1868,8 +1876,47 @@ static long dm_compat_ctl_ioctl(struct file *file, uint command, ulong u) #define dm_compat_ctl_ioctl NULL #endif +static int dm_open(struct inode *inode, struct file *filp) +{ + int r; + struct dm_file *priv; + + r = nonseekable_open(inode, filp); + if (unlikely(r)) + return r; + + priv = filp->private_data = kmalloc(sizeof(struct dm_file), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->global_event_nr = atomic_read(&dm_global_event_nr); + + return 0; +} + +static int dm_release(struct inode *inode, struct file *filp) +{ + kfree(filp->private_data); + return 0; +} + +static unsigned dm_poll(struct file *filp, poll_table *wait) +{ + struct dm_file *priv = filp->private_data; + unsigned mask = 0; + + poll_wait(filp, &dm_global_eventq, wait); + + if ((int)(atomic_read(&dm_global_event_nr) - priv->global_event_nr) > 0) + mask |= POLLIN; + + return mask; +} + static const struct file_operations _ctl_fops = { - .open = nonseekable_open, + .open = dm_open, + .release = dm_release, + .poll = dm_poll, .unlocked_ioctl = dm_ctl_ioctl, .compat_ioctl = dm_compat_ctl_ioctl, .owner = THIS_MODULE, diff --git a/drivers/md/dm.c b/drivers/md/dm.c index fbd06b9f9467..ff22aa2a07b5 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -58,6 +58,9 @@ static DECLARE_WORK(deferred_remove_work, do_deferred_remove); static struct workqueue_struct *deferred_remove_workqueue; +atomic_t dm_global_event_nr = ATOMIC_INIT(0); +DECLARE_WAIT_QUEUE_HEAD(dm_global_eventq); + /* * One of these is allocated per bio. */ @@ -1760,7 +1763,9 @@ static void event_callback(void *context) dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj); atomic_inc(&md->event_nr); + atomic_inc(&dm_global_event_nr); wake_up(&md->eventq); + wake_up(&dm_global_eventq); } /* |