WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 1/3] libxc: add xc_gnttab_map_grant_ref_notify

Normally, when a userspace process mapping a grant crashes, the domain
providing the reference receives no indication that its peer has
crashed, possibly leading to unexpected freezes or timeouts. This
function provides a notification of the unmap by signalling an event
channel and/or clearing a specific byte in the page.

Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
---
 tools/include/xen-sys/Linux/gntdev.h |   33 +++++++++++++++++++-
 tools/libxc/xc_gnttab.c              |   23 +++++++++++++
 tools/libxc/xc_linux_osdep.c         |   57 ++++++++++++++++++++++++++++++++++
 tools/libxc/xenctrl.h                |   24 ++++++++++++++
 tools/libxc/xenctrlosdep.h           |    6 +++
 5 files changed, 142 insertions(+), 1 deletions(-)

diff --git a/tools/include/xen-sys/Linux/gntdev.h 
b/tools/include/xen-sys/Linux/gntdev.h
index 8bd1467..5304bd3 100644
--- a/tools/include/xen-sys/Linux/gntdev.h
+++ b/tools/include/xen-sys/Linux/gntdev.h
@@ -66,7 +66,7 @@ struct ioctl_gntdev_map_grant_ref {
  * before this ioctl is called, or an error will result.
  */
 #define IOCTL_GNTDEV_UNMAP_GRANT_REF \
-_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref))       
+_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref))
 struct ioctl_gntdev_unmap_grant_ref {
        /* IN parameters */
        /* The offset was returned by the corresponding map operation. */
@@ -116,4 +116,35 @@ struct ioctl_gntdev_set_max_grants {
        uint32_t count;
 };
 
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTDEV_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntdev_unmap_notify))
+struct ioctl_gntdev_unmap_notify {
+       /* IN parameters */
+       /* Offset in the file descriptor for a byte within the page (same as
+        * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
+        * be cleared. Otherwise, it can be any byte in the page whose
+        * notification we are adjusting.
+        */
+       uint64_t index;
+       /* Action(s) to take on unmap */
+       uint32_t action;
+       /* Event channel to notify */
+       uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
 #endif /* __LINUX_PUBLIC_GNTDEV_H__ */
diff --git a/tools/libxc/xc_gnttab.c b/tools/libxc/xc_gnttab.c
index 4f55fce..3d3c63b 100644
--- a/tools/libxc/xc_gnttab.c
+++ b/tools/libxc/xc_gnttab.c
@@ -18,6 +18,7 @@
  */
 
 #include "xc_private.h"
+#include <errno.h>
 
 int xc_gnttab_op(xc_interface *xch, int cmd, void * op, int op_size, int count)
 {
@@ -174,6 +175,28 @@ void *xc_gnttab_map_domain_grant_refs(xc_gnttab *xcg,
                                                        count, domid, refs, 
prot);
 }
 
+void *xc_gnttab_map_grant_ref_notify(xc_gnttab *xcg,
+                                     uint32_t domid,
+                                     uint32_t ref,
+                                     uint32_t notify_offset,
+                                     evtchn_port_t notify_port,
+                                     int *notify_result)
+{
+       if (xcg->ops->u.gnttab.map_grant_ref_notify)
+               return xcg->ops->u.gnttab.map_grant_ref_notify(xcg, 
xcg->ops_handle,
+                       domid, ref, notify_offset, notify_port, notify_result);
+       else {
+               void* area = xcg->ops->u.gnttab.map_grant_ref(xcg, 
xcg->ops_handle,
+                       domid, ref, PROT_READ|PROT_WRITE);
+               if (area && notify_result) {
+                       *notify_result = -1;
+                       errno = ENOSYS;
+               }
+               return area;
+       }
+}
+
+
 int xc_gnttab_munmap(xc_gnttab *xcg,
                      void *start_address,
                      uint32_t count)
diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c
index dca6718..3040cb6 100644
--- a/tools/libxc/xc_linux_osdep.c
+++ b/tools/libxc/xc_linux_osdep.c
@@ -613,6 +613,62 @@ static void *linux_gnttab_map_domain_grant_refs(xc_gnttab 
*xcg, xc_osdep_handle
     return do_gnttab_map_grant_refs(xcg, h, count, &domid, 0, refs, prot);
 }
 
+static void *linux_gnttab_map_grant_ref_notify(xc_gnttab *xch, xc_osdep_handle 
h,
+                                               uint32_t domid, uint32_t ref,
+                                               uint32_t notify_offset,
+                                               evtchn_port_t notify_port,
+                                               int *notify_result)
+{
+    int fd = (int)h;
+    int rv = 0;
+    struct ioctl_gntdev_map_grant_ref map;
+    struct ioctl_gntdev_unmap_notify notify;
+    void *addr;
+
+    map.count = 1;
+    map.refs[0].domid = domid;
+    map.refs[0].ref = ref;
+
+    if ( ioctl(fd, IOCTL_GNTDEV_MAP_GRANT_REF, &map) ) {
+        PERROR("xc_gnttab_map_grant_ref: ioctl MAP_GRANT_REF failed");
+        return NULL;
+    }
+
+    addr = mmap(NULL, XC_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 
map.index);
+    if ( addr == MAP_FAILED )
+    {
+        int saved_errno = errno;
+        struct ioctl_gntdev_unmap_grant_ref unmap_grant;
+
+        PERROR("xc_gnttab_map_grant_ref: mmap failed");
+        unmap_grant.index = map.index;
+        unmap_grant.count = 1;
+        ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
+        errno = saved_errno;
+        return NULL;
+    }
+
+    notify.index = map.index;
+    notify.action = 0;
+    if (notify_offset >= 0) {
+        notify.index += notify_offset;
+        notify.action |= UNMAP_NOTIFY_CLEAR_BYTE;
+    }
+    if (notify_port >= 0) {
+        notify.event_channel_port = notify_port;
+        notify.action |= UNMAP_NOTIFY_SEND_EVENT;
+    }
+    if (notify.action)
+        rv = ioctl(fd, IOCTL_GNTDEV_SET_UNMAP_NOTIFY, &notify);
+    if (rv)
+        PERROR("linux_gnttab_map_grant_ref_notify: ioctl SET_UNMAP_NOTIFY 
failed");
+    if (notify_result)
+        *notify_result = rv;
+
+    return addr;
+}
+
+
 static int linux_gnttab_munmap(xc_gnttab *xcg, xc_osdep_handle h,
                                void *start_address, uint32_t count)
 {
@@ -662,6 +718,7 @@ static struct xc_osdep_ops linux_gnttab_ops = {
         .map_grant_ref = &linux_gnttab_map_grant_ref,
         .map_grant_refs = &linux_gnttab_map_grant_refs,
         .map_domain_grant_refs = &linux_gnttab_map_domain_grant_refs,
+        .map_grant_ref_notify = &linux_gnttab_map_grant_ref_notify,
         .munmap = &linux_gnttab_munmap,
     },
 };
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 1b82ee0..02c10fa 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -1349,6 +1349,30 @@ void *xc_gnttab_map_domain_grant_refs(xc_gnttab *xcg,
                                       int prot);
 
 /*
+ * Memory maps a grant reference from one domain to a local address range.
+ * Mappings should be unmapped with xc_gnttab_munmap.  This version always maps
+ * writable pages, and will attempt to set up an unmap notification at the 
given
+ * offset and event channel. When the page is unmapped, the byte at the given
+ * offset will be zeroed and a wakeup will be sent to the given event channel.
+ * Logs errors.
+ *
+ * @parm xcg a handle on an open grant table interface
+ * @parm domid the domain to map memory from
+ * @parm ref the grant reference ID to map
+ * @parm notify_offset The byte offset in the page to use for unmap
+ *                     notification; -1 for none.
+ * @parm notify_port The event channel port to use for unmap notify, or -1
+ * @parm notify_result If nonnull, set to 0 if the notify setup succeeded
+ *                     or an errno value if not.
+ */
+void *xc_gnttab_map_grant_ref_notify(xc_gnttab *xcg,
+                                     uint32_t domid,
+                                     uint32_t ref,
+                                     uint32_t notify_offset,
+                                     evtchn_port_t notify_port,
+                                     int *notify_result);
+
+/*
  * Unmaps the @count pages starting at @start_address, which were mapped by a
  * call to xc_gnttab_map_grant_ref or xc_gnttab_map_grant_refs. Never logs.
  */
diff --git a/tools/libxc/xenctrlosdep.h b/tools/libxc/xenctrlosdep.h
index bfe46e0..bf81538 100644
--- a/tools/libxc/xenctrlosdep.h
+++ b/tools/libxc/xenctrlosdep.h
@@ -119,6 +119,12 @@ struct xc_osdep_ops
                                            uint32_t domid,
                                            uint32_t *refs,
                                            int prot);
+            void *(*map_grant_ref_notify)(xc_gnttab *xcg, xc_osdep_handle h,
+                                          uint32_t domid,
+                                          uint32_t ref,
+                                          uint32_t notify_offset,
+                                          evtchn_port_t notify_port,
+                                          int *notify_result);
             int (*munmap)(xc_gnttab *xcg, xc_osdep_handle h,
                           void *start_address,
                           uint32_t count);
-- 
1.7.6.2


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel