[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC PATCH v2 8/9] hyper_dmabuf: event-polling mechanism for detecting a new hyper_DMABUF



New method based on polling for a importing VM to know about a new
hyper_DMABUF exported to it.

For this, the userspace now can poll the device node to check if
there a new event, which is created if there's a new hyper_DMABUF
available in importing VM (just exported).

A poll function call was added to the device driver interface for this
new functionality. Event-generation functionalitywas also implemented in
all other relavant parts of driver.

This "event-polling" mechanism is optional feature and can be enabled
by setting a Kernel config option, "HYPER_DMABUF_EVENT_GEN".

Signed-off-by: Dongwon Kim <dongwon.kim@xxxxxxxxx>
Signed-off-by: Mateusz Polrola <mateuszx.potrola@xxxxxxxxx>
---
 drivers/dma-buf/hyper_dmabuf/Kconfig              |  20 +++
 drivers/dma-buf/hyper_dmabuf/Makefile             |   1 +
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c   | 146 ++++++++++++++++++++++
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.h   |  11 ++
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.c | 122 ++++++++++++++++++
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.h |  38 ++++++
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_list.c  |   1 +
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c   |  11 ++
 include/uapi/linux/hyper_dmabuf.h                 |  11 ++
 9 files changed, 361 insertions(+)
 create mode 100644 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.c
 create mode 100644 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.h

diff --git a/drivers/dma-buf/hyper_dmabuf/Kconfig 
b/drivers/dma-buf/hyper_dmabuf/Kconfig
index 68f3d6ce2c1f..92510731af25 100644
--- a/drivers/dma-buf/hyper_dmabuf/Kconfig
+++ b/drivers/dma-buf/hyper_dmabuf/Kconfig
@@ -20,6 +20,16 @@ config HYPER_DMABUF_SYSFS
 
          The location of sysfs is under "...."
 
+config HYPER_DMABUF_EVENT_GEN
+        bool "Enable event-generation and polling operation"
+        default n
+        depends on HYPER_DMABUF
+        help
+          With this config enabled, hyper_dmabuf driver on the importer side
+          generates events and queue those up in the event list whenever a new
+          shared DMA-BUF is available. Events in the list can be retrieved by
+          read operation.
+
 config HYPER_DMABUF_XEN
         bool "Configure hyper_dmabuf for XEN hypervisor"
         default y
@@ -27,4 +37,14 @@ config HYPER_DMABUF_XEN
         help
           Enabling Hyper_DMABUF Backend for XEN hypervisor
 
+config HYPER_DMABUF_XEN_AUTO_RX_CH_ADD
+        bool "Enable automatic rx-ch add with 10 secs interval"
+        default y
+        depends on HYPER_DMABUF && HYPER_DMABUF_XEN
+        help
+          If enabled, driver reads a node in xenstore every 10 seconds
+          to check whether there is any tx comm ch configured by another
+          domain then initialize matched rx comm ch automatically for any
+          existing tx comm chs.
+
 endmenu
diff --git a/drivers/dma-buf/hyper_dmabuf/Makefile 
b/drivers/dma-buf/hyper_dmabuf/Makefile
index 578a669a0d3e..f573dd5c4054 100644
--- a/drivers/dma-buf/hyper_dmabuf/Makefile
+++ b/drivers/dma-buf/hyper_dmabuf/Makefile
@@ -11,6 +11,7 @@ ifneq ($(KERNELRELEASE),)
                                 hyper_dmabuf_id.o \
                                 hyper_dmabuf_remote_sync.o \
                                 hyper_dmabuf_query.o \
+                                hyper_dmabuf_event.o \
 
 ifeq ($(CONFIG_HYPER_DMABUF_XEN), y)
        $(TARGET_MODULE)-objs += backends/xen/hyper_dmabuf_xen_comm.o \
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c 
b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c
index 3320f9dcc769..087f091ccae9 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c
@@ -41,6 +41,7 @@
 #include "hyper_dmabuf_ioctl.h"
 #include "hyper_dmabuf_list.h"
 #include "hyper_dmabuf_id.h"
+#include "hyper_dmabuf_event.h"
 
 #ifdef CONFIG_HYPER_DMABUF_XEN
 #include "backends/xen/hyper_dmabuf_xen_drv.h"
@@ -91,10 +92,138 @@ static int hyper_dmabuf_release(struct inode *inode, 
struct file *filp)
        return 0;
 }
 
+#ifdef CONFIG_HYPER_DMABUF_EVENT_GEN
+
+static unsigned int hyper_dmabuf_event_poll(struct file *filp,
+                                    struct poll_table_struct *wait)
+{
+       poll_wait(filp, &hy_drv_priv->event_wait, wait);
+
+       if (!list_empty(&hy_drv_priv->event_list))
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+static ssize_t hyper_dmabuf_event_read(struct file *filp, char __user *buffer,
+               size_t count, loff_t *offset)
+{
+       int ret;
+
+       /* only root can read events */
+       if (!capable(CAP_DAC_OVERRIDE)) {
+               dev_err(hy_drv_priv->dev,
+                       "Only root can read events\n");
+               return -EPERM;
+       }
+
+       /* make sure user buffer can be written */
+       if (!access_ok(VERIFY_WRITE, buffer, count)) {
+               dev_err(hy_drv_priv->dev,
+                       "User buffer can't be written.\n");
+               return -EINVAL;
+       }
+
+       ret = mutex_lock_interruptible(&hy_drv_priv->event_read_lock);
+       if (ret)
+               return ret;
+
+       while (1) {
+               struct hyper_dmabuf_event *e = NULL;
+
+               spin_lock_irq(&hy_drv_priv->event_lock);
+               if (!list_empty(&hy_drv_priv->event_list)) {
+                       e = list_first_entry(&hy_drv_priv->event_list,
+                                       struct hyper_dmabuf_event, link);
+                       list_del(&e->link);
+               }
+               spin_unlock_irq(&hy_drv_priv->event_lock);
+
+               if (!e) {
+                       if (ret)
+                               break;
+
+                       if (filp->f_flags & O_NONBLOCK) {
+                               ret = -EAGAIN;
+                               break;
+                       }
+
+                       mutex_unlock(&hy_drv_priv->event_read_lock);
+                       ret = wait_event_interruptible(hy_drv_priv->event_wait,
+                                 !list_empty(&hy_drv_priv->event_list));
+
+                       if (ret == 0)
+                               ret = mutex_lock_interruptible(
+                                       &hy_drv_priv->event_read_lock);
+
+                       if (ret)
+                               return ret;
+               } else {
+                       unsigned int length = (sizeof(e->event_data.hdr) +
+                                                     e->event_data.hdr.size);
+
+                       if (length > count - ret) {
+put_back_event:
+                               spin_lock_irq(&hy_drv_priv->event_lock);
+                               list_add(&e->link, &hy_drv_priv->event_list);
+                               spin_unlock_irq(&hy_drv_priv->event_lock);
+                               break;
+                       }
+
+                       if (copy_to_user(buffer + ret, &e->event_data.hdr,
+                                        sizeof(e->event_data.hdr))) {
+                               if (ret == 0)
+                                       ret = -EFAULT;
+
+                               goto put_back_event;
+                       }
+
+                       ret += sizeof(e->event_data.hdr);
+
+                       if (copy_to_user(buffer + ret, e->event_data.data,
+                                        e->event_data.hdr.size)) {
+                               /* error while copying void *data */
+
+                               struct hyper_dmabuf_event_hdr dummy_hdr = {0};
+
+                               ret -= sizeof(e->event_data.hdr);
+
+                               /* nullifying hdr of the event in user buffer */
+                               if (copy_to_user(buffer + ret, &dummy_hdr,
+                                                sizeof(dummy_hdr))) {
+                                       dev_err(hy_drv_priv->dev,
+                                               "failed to nullify invalid hdr 
already in userspace\n");
+                               }
+
+                               ret = -EFAULT;
+
+                               goto put_back_event;
+                       }
+
+                       ret += e->event_data.hdr.size;
+                       hy_drv_priv->pending--;
+                       kfree(e);
+               }
+       }
+
+       mutex_unlock(&hy_drv_priv->event_read_lock);
+
+       return ret;
+}
+
+#endif
+
 static const struct file_operations hyper_dmabuf_driver_fops = {
        .owner = THIS_MODULE,
        .open = hyper_dmabuf_open,
        .release = hyper_dmabuf_release,
+
+/* poll and read interfaces are needed only for event-polling */
+#ifdef CONFIG_HYPER_DMABUF_EVENT_GEN
+       .read = hyper_dmabuf_event_read,
+       .poll = hyper_dmabuf_event_poll,
+#endif
+
        .unlocked_ioctl = hyper_dmabuf_ioctl,
 };
 
@@ -194,6 +323,18 @@ static int __init hyper_dmabuf_drv_init(void)
        }
 #endif
 
+#ifdef CONFIG_HYPER_DMABUF_EVENT_GEN
+       mutex_init(&hy_drv_priv->event_read_lock);
+       spin_lock_init(&hy_drv_priv->event_lock);
+
+       /* Initialize event queue */
+       INIT_LIST_HEAD(&hy_drv_priv->event_list);
+       init_waitqueue_head(&hy_drv_priv->event_wait);
+
+       /* resetting number of pending events */
+       hy_drv_priv->pending = 0;
+#endif
+
        if (hy_drv_priv->bknd_ops->init) {
                ret = hy_drv_priv->bknd_ops->init();
 
@@ -250,6 +391,11 @@ static void hyper_dmabuf_drv_exit(void)
        if (hy_drv_priv->id_queue)
                hyper_dmabuf_free_hid_list();
 
+#ifdef CONFIG_HYPER_DMABUF_EVENT_GEN
+       /* clean up event queue */
+       hyper_dmabuf_events_release();
+#endif
+
        mutex_unlock(&hy_drv_priv->lock);
 
        dev_info(hy_drv_priv->dev,
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.h 
b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.h
index 46119d762430..282a507b33bc 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.h
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.h
@@ -32,6 +32,11 @@
 
 struct hyper_dmabuf_req;
 
+struct hyper_dmabuf_event {
+       struct hyper_dmabuf_event_data event_data;
+       struct list_head link;
+};
+
 struct hyper_dmabuf_private {
        struct device *dev;
 
@@ -54,6 +59,12 @@ struct hyper_dmabuf_private {
        /* flag that shows whether backend is initialized */
        bool initialized;
 
+       wait_queue_head_t event_wait;
+       struct list_head event_list;
+
+       spinlock_t event_lock;
+       struct mutex event_read_lock;
+
        /* # of pending events */
        int pending;
 };
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.c 
b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.c
new file mode 100644
index 000000000000..942a1bb78755
--- /dev/null
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2018 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Dongwon Kim <dongwon.kim@xxxxxxxxx>
+ *    Mateusz Polrola <mateuszx.potrola@xxxxxxxxx>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "hyper_dmabuf_drv.h"
+#include "hyper_dmabuf_struct.h"
+#include "hyper_dmabuf_list.h"
+#include "hyper_dmabuf_event.h"
+
+static void send_event(struct hyper_dmabuf_event *e)
+{
+       struct hyper_dmabuf_event *oldest;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&hy_drv_priv->event_lock, irqflags);
+
+       /* check current number of event then if it hits the max num allowed
+        * then remove the oldest event in the list
+        */
+       if (hy_drv_priv->pending > MAX_DEPTH_EVENT_QUEUE - 1) {
+               oldest = list_first_entry(&hy_drv_priv->event_list,
+                               struct hyper_dmabuf_event, link);
+               list_del(&oldest->link);
+               hy_drv_priv->pending--;
+               kfree(oldest);
+       }
+
+       list_add_tail(&e->link,
+                     &hy_drv_priv->event_list);
+
+       hy_drv_priv->pending++;
+
+       wake_up_interruptible(&hy_drv_priv->event_wait);
+
+       spin_unlock_irqrestore(&hy_drv_priv->event_lock, irqflags);
+}
+
+void hyper_dmabuf_events_release(void)
+{
+       struct hyper_dmabuf_event *e, *et;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&hy_drv_priv->event_lock, irqflags);
+
+       list_for_each_entry_safe(e, et, &hy_drv_priv->event_list,
+                                link) {
+               list_del(&e->link);
+               kfree(e);
+               hy_drv_priv->pending--;
+       }
+
+       if (hy_drv_priv->pending) {
+               dev_err(hy_drv_priv->dev,
+                       "possible leak on event_list\n");
+       }
+
+       spin_unlock_irqrestore(&hy_drv_priv->event_lock, irqflags);
+}
+
+int hyper_dmabuf_import_event(hyper_dmabuf_id_t hid)
+{
+       struct hyper_dmabuf_event *e;
+       struct imported_sgt_info *imported;
+
+       imported = hyper_dmabuf_find_imported(hid);
+
+       if (!imported) {
+               dev_err(hy_drv_priv->dev,
+                       "can't find imported_sgt_info in the list\n");
+               return -EINVAL;
+       }
+
+       e = kzalloc(sizeof(*e), GFP_KERNEL);
+
+       if (!e)
+               return -ENOMEM;
+
+       e->event_data.hdr.event_type = HYPER_DMABUF_NEW_IMPORT;
+       e->event_data.hdr.hid = hid;
+       e->event_data.data = (void *)imported->priv;
+       e->event_data.hdr.size = imported->sz_priv;
+
+       send_event(e);
+
+       dev_dbg(hy_drv_priv->dev,
+               "event number = %d :", hy_drv_priv->pending);
+
+       dev_dbg(hy_drv_priv->dev,
+               "generating events for {%d, %d, %d, %d}\n",
+               imported->hid.id, imported->hid.rng_key[0],
+               imported->hid.rng_key[1], imported->hid.rng_key[2]);
+
+       return 0;
+}
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.h 
b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.h
new file mode 100644
index 000000000000..8f61198e623c
--- /dev/null
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_event.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2018 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __HYPER_DMABUF_EVENT_H__
+#define __HYPER_DMABUF_EVENT_H__
+
+#define MAX_DEPTH_EVENT_QUEUE 32
+
+enum hyper_dmabuf_event_type {
+       HYPER_DMABUF_NEW_IMPORT = 0x10000,
+};
+
+void hyper_dmabuf_events_release(void);
+
+int hyper_dmabuf_import_event(hyper_dmabuf_id_t hid);
+
+#endif /* __HYPER_DMABUF_EVENT_H__ */
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_list.c 
b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_list.c
index f2f65a8ec47f..30c3af65fcde 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_list.c
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_list.c
@@ -36,6 +36,7 @@
 #include "hyper_dmabuf_drv.h"
 #include "hyper_dmabuf_list.h"
 #include "hyper_dmabuf_id.h"
+#include "hyper_dmabuf_event.h"
 
 DECLARE_HASHTABLE(hyper_dmabuf_hash_imported, MAX_ENTRY_IMPORTED);
 DECLARE_HASHTABLE(hyper_dmabuf_hash_exported, MAX_ENTRY_EXPORTED);
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c 
b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
index 1592d5cfaa52..8f2cf7ea827d 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
@@ -35,6 +35,7 @@
 #include "hyper_dmabuf_drv.h"
 #include "hyper_dmabuf_msg.h"
 #include "hyper_dmabuf_remote_sync.h"
+#include "hyper_dmabuf_event.h"
 #include "hyper_dmabuf_list.h"
 
 struct cmd_process {
@@ -179,6 +180,11 @@ static void cmd_process_work(struct work_struct *work)
                        /* updating priv data */
                        memcpy(imported->priv, &req->op[9], req->op[8]);
 
+#ifdef CONFIG_HYPER_DMABUF_EVENT_GEN
+                       /* generating import event */
+                       hyper_dmabuf_import_event(imported->hid);
+#endif
+
                        break;
                }
 
@@ -219,6 +225,11 @@ static void cmd_process_work(struct work_struct *work)
                imported->valid = true;
                hyper_dmabuf_register_imported(imported);
 
+#ifdef CONFIG_HYPER_DMABUF_EVENT_GEN
+               /* generating import event */
+               hyper_dmabuf_import_event(imported->hid);
+#endif
+
                break;
 
        case HYPER_DMABUF_OPS_TO_REMOTE:
diff --git a/include/uapi/linux/hyper_dmabuf.h 
b/include/uapi/linux/hyper_dmabuf.h
index 4f8e8ac0375b..dd73db9bf37d 100644
--- a/include/uapi/linux/hyper_dmabuf.h
+++ b/include/uapi/linux/hyper_dmabuf.h
@@ -32,6 +32,17 @@ typedef struct {
        int rng_key[3]; /* 12bytes long random number */
 } hyper_dmabuf_id_t;
 
+struct hyper_dmabuf_event_hdr {
+       int event_type; /* one type only for now - new import */
+       hyper_dmabuf_id_t hid; /* hyper_dmabuf_id of specific hyper_dmabuf */
+       int size; /* size of data */
+};
+
+struct hyper_dmabuf_event_data {
+       struct hyper_dmabuf_event_hdr hdr;
+       void *data; /* private data */
+};
+
 #define IOCTL_HYPER_DMABUF_TX_CH_SETUP \
 _IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_hyper_dmabuf_tx_ch_setup))
 struct ioctl_hyper_dmabuf_tx_ch_setup {
-- 
2.16.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.