aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxc/xc_linux_osdep.c
diff options
context:
space:
mode:
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>2011-10-06 19:28:53 +0100
committerDaniel De Graaf <dgdegra@tycho.nsa.gov>2011-10-06 19:28:53 +0100
commit1f5552006de96f879ea0bcf342dcf4d9b3b06354 (patch)
treeea023d0ddf2f20b6590c98f49c83fa4fdb811064 /tools/libxc/xc_linux_osdep.c
parentb7ee8d2f432f726a1154d172016d3f2b22757fe3 (diff)
downloadxen-1f5552006de96f879ea0bcf342dcf4d9b3b06354.tar.gz
xen-1f5552006de96f879ea0bcf342dcf4d9b3b06354.tar.bz2
xen-1f5552006de96f879ea0bcf342dcf4d9b3b06354.zip
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. This also unifies the 3 very similar grant-mapping osdep interfaces into a single function instead of introducing yet another minor variation. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Committed-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'tools/libxc/xc_linux_osdep.c')
-rw-r--r--tools/libxc/xc_linux_osdep.c112
1 files changed, 51 insertions, 61 deletions
diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c
index dca6718370..f760421f9c 100644
--- a/tools/libxc/xc_linux_osdep.c
+++ b/tools/libxc/xc_linux_osdep.c
@@ -509,56 +509,21 @@ static int linux_gnttab_close(xc_gnttab *xcg, xc_osdep_handle h)
return close(fd);
}
-static void *linux_gnttab_map_grant_ref(xc_gnttab *xch, xc_osdep_handle h,
- uint32_t domid, uint32_t ref, int prot)
-{
- int fd = (int)h;
- struct ioctl_gntdev_map_grant_ref map;
- 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;
- }
-
-mmap_again:
- addr = mmap(NULL, XC_PAGE_SIZE, prot, MAP_SHARED, fd, map.index);
- if ( addr == MAP_FAILED )
- {
- int saved_errno = errno;
- struct ioctl_gntdev_unmap_grant_ref unmap_grant;
-
- if(saved_errno == EAGAIN)
- {
- usleep(1000);
- goto mmap_again;
- }
- /* Unmap the driver slots used to store the grant information. */
- 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;
- }
-
- return addr;
-}
-
-static void *do_gnttab_map_grant_refs(xc_gnttab *xch, xc_osdep_handle h,
- uint32_t count,
- uint32_t *domids, int domids_stride,
- uint32_t *refs, int prot)
+static void *linux_gnttab_grant_map(xc_gnttab *xch, xc_osdep_handle h,
+ uint32_t count, int flags, int prot,
+ uint32_t *domids, uint32_t *refs,
+ uint32_t notify_offset,
+ evtchn_port_t notify_port)
{
int fd = (int)h;
struct ioctl_gntdev_map_grant_ref *map;
void *addr = NULL;
+ int domids_stride = 1;
int i;
+ if (flags & XC_GRANT_MAP_SINGLE_DOMAIN)
+ domids_stride = 0;
+
map = malloc(sizeof(*map) +
(count - 1) * sizeof(struct ioctl_gntdev_map_grant_ref));
if ( map == NULL )
@@ -573,13 +538,52 @@ static void *do_gnttab_map_grant_refs(xc_gnttab *xch, xc_osdep_handle h,
map->count = count;
if ( ioctl(fd, IOCTL_GNTDEV_MAP_GRANT_REF, map) ) {
- PERROR("xc_gnttab_map_grant_refs: ioctl MAP_GRANT_REF failed");
+ PERROR("linux_gnttab_grant_map: ioctl MAP_GRANT_REF failed");
goto out;
}
+ retry:
addr = mmap(NULL, XC_PAGE_SIZE * count, prot, MAP_SHARED, fd,
map->index);
- if ( addr == MAP_FAILED )
+
+ if (addr == MAP_FAILED && errno == EAGAIN)
+ {
+ /*
+ * The grant hypercall can return EAGAIN if the granted page is
+ * swapped out. Since the paging daemon may be in the same domain, the
+ * hypercall cannot block without causing a deadlock.
+ *
+ * Because there are no notificaitons when the page is swapped in, wait
+ * a bit before retrying, and hope that the page will arrive eventually.
+ */
+ usleep(1000);
+ goto retry;
+ }
+
+ if (addr != MAP_FAILED)
+ {
+ int rv = 0;
+ struct ioctl_gntdev_unmap_notify notify;
+ notify.index = map->index;
+ notify.action = 0;
+ if (notify_offset >= 0 && notify_offset < XC_PAGE_SIZE * count) {
+ notify.index += notify_offset;
+ notify.action |= UNMAP_NOTIFY_CLEAR_BYTE;
+ }
+ if (notify_port != -1) {
+ 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_grant_map: ioctl SET_UNMAP_NOTIFY failed");
+ munmap(addr, count * XC_PAGE_SIZE);
+ addr = MAP_FAILED;
+ }
+ }
+
+ if (addr == MAP_FAILED)
{
int saved_errno = errno;
struct ioctl_gntdev_unmap_grant_ref unmap_grant;
@@ -599,19 +603,7 @@ static void *do_gnttab_map_grant_refs(xc_gnttab *xch, xc_osdep_handle h,
return addr;
}
-static void *linux_gnttab_map_grant_refs(xc_gnttab *xcg, xc_osdep_handle h,
- uint32_t count, uint32_t *domids,
- uint32_t *refs, int prot)
-{
- return do_gnttab_map_grant_refs(xcg, h, count, domids, 1, refs, prot);
-}
-static void *linux_gnttab_map_domain_grant_refs(xc_gnttab *xcg, xc_osdep_handle h,
- uint32_t count,
- uint32_t domid, uint32_t *refs, int prot)
-{
- return do_gnttab_map_grant_refs(xcg, h, count, &domid, 0, refs, prot);
-}
static int linux_gnttab_munmap(xc_gnttab *xcg, xc_osdep_handle h,
void *start_address, uint32_t count)
@@ -659,9 +651,7 @@ static struct xc_osdep_ops linux_gnttab_ops = {
.close = &linux_gnttab_close,
.u.gnttab = {
- .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,
+ .grant_map = &linux_gnttab_grant_map,
.munmap = &linux_gnttab_munmap,
},
};