@@ -14,6 +14,8 @@
*/
#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
#include "private.h"
@@ -64,7 +66,36 @@ void *xenforeignmemory_map(xenforeignmemory_handle *fmem,
uint32_t dom, int prot,
const xen_pfn_t *arr, int *err, size_t num)
{
- return osdep_xenforeignmemory_map(fmem, dom, prot, arr, err, num);
+ void *ret;
+ int *err_to_free = NULL;
+
+ if ( err == NULL )
+ err = err_to_free = malloc(num * sizeof(int));
+
+ if ( err == NULL )
+ return NULL;
+
+ ret = osdep_xenforeignmemory_map(fmem, dom, prot, arr, err, num);
+
+ if ( ret == 0 && err_to_free )
+ {
+ int i;
+
+ for ( i = 0 ; i < num ; i++ )
+ {
+ if ( err[i] )
+ {
+ errno = -err[i];
+ (void)osdep_xenforeignmemory_unmap(fmem, ret, num);
+ ret = NULL;
+ break;
+ }
+ }
+ }
+
+ free(err_to_free);
+
+ return ret;
}
int xenforeignmemory_unmap(xenforeignmemory_handle *fmem,
@@ -80,10 +80,28 @@ int xenforeignmemory_close(xenforeignmemory_handle *fmem);
*
* prot is as for mmap(2).
*
- * Can partially succeed. When a page cannot be mapped, its respective
- * field in @err is set to the corresponding errno value.
+ * @arr is an array of @pages gfns to be mapped linearly in the local
+ * address range. @err is an (optional) output array used to report
+ * per-page errors, as errno values.
*
- * Returns NULL if no pages can be mapped.
+ * If @err is given (is non-NULL) then the mapping may partially
+ * succeed and return a valid pointer while also using @err to
+ * indicate the success (0) or failure (errno value) of the individual
+ * pages. The global errno thread local variable is not valid in this
+ * case.
+ *
+ * If @err is not given (is NULL) then on failure to map any page any
+ * successful mappings will be undone and NULL will be returned. errno
+ * will be set to correspond to the first failure (which may not be
+ * the most critical).
+ *
+ * It is also possible to return NULL due to a complete failure,
+ * i.e. failure to even attempt the mapping, in this case the global
+ * errno will have been set and the contents of @err (if given) is
+ * invalid.
+ *
+ * Note that it is also possible to return non-NULL with the contents
+ * of @err indicating failure to map every page.
*/
void *xenforeignmemory_map(xenforeignmemory_handle *fmem, uint32_t dom,
int prot, const xen_pfn_t *arr, int *err,
@@ -23,32 +23,12 @@
void *xc_map_foreign_pages(xc_interface *xch, uint32_t dom, int prot,
const xen_pfn_t *arr, int num)
{
- void *res;
- int i, *err;
-
if (num < 0) {
errno = EINVAL;
return NULL;
}
- err = malloc(num * sizeof(*err));
- if (!err)
- return NULL;
-
- res = xenforeignmemory_map(xch->fmem, dom, prot, arr, err, num);
- if (res) {
- for (i = 0; i < num; i++) {
- if (err[i]) {
- errno = -err[i];
- munmap(res, num * PAGE_SIZE);
- res = NULL;
- break;
- }
- }
- }
-
- free(err);
- return res;
+ return xenforeignmemory_map(xch->fmem, dom, prot, arr, NULL, num);
}
void *xc_map_foreign_range(xc_interface *xch,