dm: add basic support for using the select or poll function
authorMikulas Patocka <mpatocka@redhat.com>
Mon, 16 Jan 2017 21:05:59 +0000 (16:05 -0500)
committerMike Snitzer <snitzer@redhat.com>
Mon, 19 Jun 2017 15:03:49 +0000 (11:03 -0400)
Add the ability to poll on the /dev/mapper/control device.  The select
or poll function waits until any event happens on any dm device since
opening the /dev/mapper/control device.  When select or poll returns the
device as readable, we must close and reopen the device to wait for new
dm events.

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

The next commit allows to re-arm the polling without closing and
reopening the device.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Andy Grover <agrover@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-core.h
drivers/md/dm-ioctl.c
drivers/md/dm.c

index 52ca8d059e821b125cb1475b9545563f8528cefb..24eddbdf2ab4cb9437674a3783ffbbfaca8a21fd 100644 (file)
@@ -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
index 41852ae287a58c29e675dd4b794f1670f9dc53e8..6b65a538d91d6f670435584ba218ef97849e7b6a 100644 (file)
 #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,
index fbd06b9f946748d34caface2ebbed308051b2ef6..ff22aa2a07b509c626429c48ef063d2ab43baa9f 100644 (file)
@@ -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);
 }
 
 /*