diff options
author | Aravindh Puthiyaparambil <aravindh@virtuata.com> | 2012-04-24 14:31:36 +0100 |
---|---|---|
committer | Aravindh Puthiyaparambil <aravindh@virtuata.com> | 2012-04-24 14:31:36 +0100 |
commit | 8a2a58e21e8f6f85841b6d8b85acb782f1c39e0b (patch) | |
tree | 4f013c979bb16f5788f5fbf553e77865967682e1 /tools/libxc/xc_linux_osdep.c | |
parent | c9cca66b8db632792f062f5ff50b1ca301dbeae4 (diff) | |
download | xen-8a2a58e21e8f6f85841b6d8b85acb782f1c39e0b.tar.gz xen-8a2a58e21e8f6f85841b6d8b85acb782f1c39e0b.tar.bz2 xen-8a2a58e21e8f6f85841b6d8b85acb782f1c39e0b.zip |
libxc: Replace alloca() with mmap() for large array sizes
Replace alloca() with mmap() for array sizes greater than a page in
xc_linux_osdep.c.
When mapping in large amounts of pages (in the GB range) from a guest
in to Dom0 using xc_map_foreign_bulk(), a segfault occurs in the libxc
client application. This is because the pfn array in
linux_privcmd_map_foreign_bulk() is being allocated using alloca() and
the subsequent memcpy causes the stack to blow. This patch replaces
the alloca() with mmap() for pfn array sizes greater than a page.
Fix an error print with the correct function name.
Do the same for the map array in linux_gnttab_grant_map()
Signed-off-by: Aravindh Puthiyaparambil <aravindh@virtuata.com>
Acked-by: Andres Lagar-Cavilla <andres@lagarcavilla.org>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
Diffstat (limited to 'tools/libxc/xc_linux_osdep.c')
-rw-r--r-- | tools/libxc/xc_linux_osdep.c | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c index 744dfea80d..b2c5449918 100644 --- a/tools/libxc/xc_linux_osdep.c +++ b/tools/libxc/xc_linux_osdep.c @@ -39,6 +39,7 @@ #include "xenctrl.h" #include "xenctrlosdep.h" +#define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1)) #define ERROR(_m, _a...) xc_osdep_log(xch,XTL_ERROR,XC_INTERNAL_ERROR,_m , ## _a ) #define PERROR(_m, _a...) xc_osdep_log(xch,XTL_ERROR,XC_INTERNAL_ERROR,_m \ " (%d = %s)", ## _a , errno, xc_strerror(xch, errno)) @@ -258,7 +259,7 @@ static void *linux_privcmd_map_foreign_bulk(xc_interface *xch, xc_osdep_handle h fd, 0); if ( addr == MAP_FAILED ) { - PERROR("xc_map_foreign_batch: mmap failed"); + PERROR("xc_map_foreign_bulk: mmap failed"); return NULL; } @@ -286,7 +287,21 @@ static void *linux_privcmd_map_foreign_bulk(xc_interface *xch, xc_osdep_handle h * IOCTL_PRIVCMD_MMAPBATCH. */ privcmd_mmapbatch_t ioctlx; - xen_pfn_t *pfn = alloca(num * sizeof(*pfn)); + xen_pfn_t *pfn; + unsigned int pfn_arr_size = ROUNDUP((num * sizeof(*pfn)), XC_PAGE_SHIFT); + + if ( pfn_arr_size <= XC_PAGE_SIZE ) + pfn = alloca(num * sizeof(*pfn)); + else + { + pfn = mmap(NULL, pfn_arr_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_POPULATE, -1, 0); + if ( pfn == MAP_FAILED ) + { + PERROR("xc_map_foreign_bulk: mmap of pfn array failed"); + return NULL; + } + } memcpy(pfn, arr, num * sizeof(*arr)); @@ -328,6 +343,9 @@ static void *linux_privcmd_map_foreign_bulk(xc_interface *xch, xc_osdep_handle h break; } + if ( pfn_arr_size > XC_PAGE_SIZE ) + munmap(pfn, pfn_arr_size); + if ( rc == -ENOENT && i == num ) rc = 0; else if ( rc ) @@ -549,6 +567,9 @@ static void *linux_gnttab_grant_map(xc_gnttab *xch, xc_osdep_handle h, { int fd = (int)h; struct ioctl_gntdev_map_grant_ref *map; + unsigned int map_size = ROUNDUP((sizeof(*map) + (count - 1) * + sizeof(struct ioctl_gntdev_map_grant_ref)), + XC_PAGE_SHIFT); void *addr = NULL; int domids_stride = 1; int i; @@ -556,8 +577,19 @@ static void *linux_gnttab_grant_map(xc_gnttab *xch, xc_osdep_handle h, if (flags & XC_GRANT_MAP_SINGLE_DOMAIN) domids_stride = 0; - map = alloca(sizeof(*map) + - (count - 1) * sizeof(struct ioctl_gntdev_map_grant_ref)); + if ( map_size <= XC_PAGE_SIZE ) + map = alloca(sizeof(*map) + + (count - 1) * sizeof(struct ioctl_gntdev_map_grant_ref)); + else + { + map = mmap(NULL, map_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_POPULATE, -1, 0); + if ( map == MAP_FAILED ) + { + PERROR("linux_gnttab_grant_map: mmap of map failed"); + return NULL; + } + } for ( i = 0; i < count; i++ ) { @@ -628,6 +660,8 @@ static void *linux_gnttab_grant_map(xc_gnttab *xch, xc_osdep_handle h, } out: + if ( map_size > XC_PAGE_SIZE ) + munmap(map, map_size); return addr; } |