|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH XEN v6 30/32] tools/libs/call: linux: avoid forking between mmap and madvise
Use pthread_atfork to prevent the application from forking before the
madvisoe(), which would result in CoW mappings getting passed to
hypercalls.
(largely cribbed from libxl_fork.c)
Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
v6: New
---
tools/libs/call/buffer.c | 2 +-
tools/libs/call/linux.c | 66 +++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 64 insertions(+), 4 deletions(-)
diff --git a/tools/libs/call/buffer.c b/tools/libs/call/buffer.c
index 2d8fc29..d2acdd4 100644
--- a/tools/libs/call/buffer.c
+++ b/tools/libs/call/buffer.c
@@ -24,7 +24,7 @@
#define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
-pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER;
static void cache_lock(xencall_handle *xcall)
{
diff --git a/tools/libs/call/linux.c b/tools/libs/call/linux.c
index 1485424..64b7be8 100644
--- a/tools/libs/call/linux.c
+++ b/tools/libs/call/linux.c
@@ -20,13 +20,57 @@
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
+#include <pthread.h>
+#include <assert.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "private.h"
-static int set_cloexec(int fd)
+static pthread_mutex_t fork_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int atfork_registered = 0;
+
+static void atfork_lock(void)
+{
+ int r = pthread_mutex_lock(&fork_mutex);
+ assert(!r);
+}
+
+static void atfork_unlock(void)
+{
+ int r = pthread_mutex_unlock(&fork_mutex);
+ assert(!r);
+}
+
+static int atfork_init(void)
+{
+ int rc;
+
+ atfork_lock();
+
+ if ( atfork_registered )
+ {
+ rc = 0;
+ goto out;
+ }
+
+ rc = pthread_atfork(atfork_lock, atfork_unlock, atfork_unlock);
+ if ( rc )
+ {
+ rc = -1;
+ goto out;
+ }
+
+ atfork_registered = 1;
+ rc = 0;
+
+ out:
+ atfork_unlock();
+ return rc;
+}
+
+static int set_cloexec(xencall_handle *xcall, int fd)
{
int flags;
@@ -68,7 +112,7 @@ int osdep_xencall_open(xencall_handle *xcall)
{
/* Fallback to /proc/xen/privcmd */
fd = open("/proc/xen/privcmd", O_RDWR);
- if ( fd > -1 && set_cloexec(fd) < 0 )
+ if ( fd > -1 && set_cloexec(xcall, fd) < 0 )
goto error;
}
@@ -78,6 +122,12 @@ int osdep_xencall_open(xencall_handle *xcall)
return -1;
}
+ if ( atfork_init() < 0 )
+ {
+ PERROR("Failed to setup atfork");
+ goto error;
+ }
+
xcall->fd = fd;
return 0;
@@ -107,12 +157,14 @@ void *osdep_alloc_pages(xencall_handle *xcall, size_t
npages)
void *p;
int rc, saved_errno;
+ atfork_lock(); /* Avoid forking between mmap and madvise */
+
/* Address returned by mmap is page aligned. */
p = mmap(NULL, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED, -1, 0);
if ( p == MAP_FAILED )
{
PERROR("alloc_pages: mmap failed");
- return NULL;
+ goto out_nomap;
}
/* Do not copy the VMA to child process on fork. Avoid the page being COW
@@ -124,24 +176,32 @@ void *osdep_alloc_pages(xencall_handle *xcall, size_t
npages)
goto out;
}
+ atfork_unlock();
return p;
out:
saved_errno = errno;
(void)munmap(p, size);
errno = saved_errno;
+out_nomap:
+ atfork_unlock();
return NULL;
}
void osdep_free_pages(xencall_handle *xcall, void *ptr, size_t npages)
{
int saved_errno = errno;
+
+ atfork_lock();
+
/* Recover the VMA flags. Maybe it's not necessary */
madvise(ptr, npages * PAGE_SIZE, MADV_DOFORK);
munmap(ptr, npages * PAGE_SIZE);
/* We MUST propagate the hypercall errno, not unmap call's. */
errno = saved_errno;
+
+ atfork_unlock();
}
/*
--
2.1.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |