debuggers.hg

changeset 20837:0b138a019292

libxc: use new (replacement) mmap-batch ioctl

Replace all calls to xc_map_foreign_batch() where the caller doesn't
look at the passed in array to check for errors by calls to
xc_map_foreign_pages(). Replace all remaining calls by such to the
newly introduced xc_map_foreign_bulk().

As a sideband modification (needed while writing the patch to ensure
they're unused) eliminate unused parameters to
uncanonicalize_pagetable() and xc_map_foreign_batch_single(). Also
unmap live_p2m_frame_list earlier in map_and_save_p2m_table(),
reducing the peak amount of virtual address space required.

All supported OSes other than Linux continue to use the old ioctl for
the time being.

Also change libxc's MAJOR to 4.0 to reflect the API change.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jan 13 08:12:56 2010 +0000 (2010-01-13)
parents 0e3910f1de64
children 0447c5532e9f
files tools/include/xen-sys/Linux/privcmd.h tools/libxc/Makefile tools/libxc/xc_domain_restore.c tools/libxc/xc_domain_save.c tools/libxc/xc_linux.c tools/libxc/xc_misc.c tools/libxc/xc_resume.c tools/libxc/xenctrl.h tools/xenpaging/xenpaging.c
line diff
     1.1 --- a/tools/include/xen-sys/Linux/privcmd.h	Tue Jan 12 07:17:40 2010 +0000
     1.2 +++ b/tools/include/xen-sys/Linux/privcmd.h	Wed Jan 13 08:12:56 2010 +0000
     1.3 @@ -64,6 +64,14 @@ typedef struct privcmd_mmapbatch {
     1.4  	xen_pfn_t __user *arr; /* array of mfns - top nibble set on err */
     1.5  } privcmd_mmapbatch_t; 
     1.6  
     1.7 +typedef struct privcmd_mmapbatch_v2 {
     1.8 +	unsigned int num; /* number of pages to populate */
     1.9 +	domid_t dom;      /* target domain */
    1.10 +	__u64 addr;       /* virtual address */
    1.11 +	const xen_pfn_t __user *arr; /* array of mfns */
    1.12 +	int __user *err;  /* array of error codes */
    1.13 +} privcmd_mmapbatch_v2_t;
    1.14 +
    1.15  /*
    1.16   * @cmd: IOCTL_PRIVCMD_HYPERCALL
    1.17   * @arg: &privcmd_hypercall_t
    1.18 @@ -75,5 +83,7 @@ typedef struct privcmd_mmapbatch {
    1.19  	_IOC(_IOC_NONE, 'P', 2, sizeof(privcmd_mmap_t))
    1.20  #define IOCTL_PRIVCMD_MMAPBATCH					\
    1.21  	_IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t))
    1.22 +#define IOCTL_PRIVCMD_MMAPBATCH_V2				\
    1.23 +	_IOC(_IOC_NONE, 'P', 4, sizeof(privcmd_mmapbatch_v2_t))
    1.24  
    1.25  #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
     2.1 --- a/tools/libxc/Makefile	Tue Jan 12 07:17:40 2010 +0000
     2.2 +++ b/tools/libxc/Makefile	Wed Jan 13 08:12:56 2010 +0000
     2.3 @@ -1,7 +1,7 @@
     2.4  XEN_ROOT = ../..
     2.5  include $(XEN_ROOT)/tools/Rules.mk
     2.6  
     2.7 -MAJOR    = 3.4
     2.8 +MAJOR    = 4.0
     2.9  MINOR    = 0
    2.10  
    2.11  CTRL_SRCS-y       :=
     3.1 --- a/tools/libxc/xc_domain_restore.c	Tue Jan 12 07:17:40 2010 +0000
     3.2 +++ b/tools/libxc/xc_domain_restore.c	Wed Jan 13 08:12:56 2010 +0000
     3.3 @@ -118,7 +118,7 @@ static int break_super_page(int xc_handl
     3.4          page_array[i] = start_pfn + i;
     3.5      }
     3.6  
     3.7 -    ram_base = xc_map_foreign_batch(xc_handle, dom, PROT_READ,
     3.8 +    ram_base = xc_map_foreign_pages(xc_handle, dom, PROT_READ,
     3.9                                      page_array, tot_pfns);
    3.10  
    3.11      if ( ram_base == NULL )
    3.12 @@ -166,7 +166,7 @@ static int break_super_page(int xc_handl
    3.13          page_array[i] = start_pfn + i;
    3.14      }
    3.15  
    3.16 -    ram_base = xc_map_foreign_batch(xc_handle, dom, PROT_WRITE,
    3.17 +    ram_base = xc_map_foreign_pages(xc_handle, dom, PROT_WRITE,
    3.18                                      page_array, tot_pfns);
    3.19      if ( ram_base == NULL )
    3.20      {
    3.21 @@ -494,7 +494,7 @@ static ssize_t read_exact_timed(int fd, 
    3.22  ** the (now known) appropriate mfn values.
    3.23  */
    3.24  static int uncanonicalize_pagetable(int xc_handle, uint32_t dom, struct restore_ctx *ctx,
    3.25 -                                    unsigned long type, void *page, int superpages)
    3.26 +                                    void *page, int superpages)
    3.27  {
    3.28      int i, pte_last;
    3.29      unsigned long pfn;
    3.30 @@ -1186,7 +1186,7 @@ static int apply_batch(int xc_handle, ui
    3.31      }
    3.32  
    3.33      /* Map relevant mfns */
    3.34 -    region_base = xc_map_foreign_batch(
    3.35 +    region_base = xc_map_foreign_pages(
    3.36          xc_handle, dom, PROT_WRITE, region_mfn, j);
    3.37  
    3.38      if ( region_base == NULL )
    3.39 @@ -1240,7 +1240,7 @@ static int apply_batch(int xc_handle, ui
    3.40                  (pagetype != XEN_DOMCTL_PFINFO_L1TAB)) {
    3.41  
    3.42                  if (!uncanonicalize_pagetable(xc_handle, dom, ctx,
    3.43 -                                              pagetype, page, superpages)) {
    3.44 +                                              page, superpages)) {
    3.45                      /*
    3.46                      ** Failing to uncanonicalize a page table can be ok
    3.47                      ** under live migration since the pages type may have
    3.48 @@ -1655,7 +1655,7 @@ int xc_domain_restore(int xc_handle, int
    3.49  
    3.50              if ( (i == (dinfo->p2m_size-1)) || (j == MAX_BATCH_SIZE) )
    3.51              {
    3.52 -                region_base = xc_map_foreign_batch(
    3.53 +                region_base = xc_map_foreign_pages(
    3.54                      xc_handle, dom, PROT_READ | PROT_WRITE, region_mfn, j);
    3.55                  if ( region_base == NULL )
    3.56                  {
    3.57 @@ -1666,7 +1666,7 @@ int xc_domain_restore(int xc_handle, int
    3.58                  for ( k = 0; k < j; k++ )
    3.59                  {
    3.60                      if ( !uncanonicalize_pagetable(
    3.61 -                        xc_handle, dom, ctx, XEN_DOMCTL_PFINFO_L1TAB,
    3.62 +                        xc_handle, dom, ctx,
    3.63                          region_base + k*PAGE_SIZE, superpages) )
    3.64                      {
    3.65                          ERROR("failed uncanonicalize pt!");
    3.66 @@ -1949,7 +1949,7 @@ int xc_domain_restore(int xc_handle, int
    3.67      }
    3.68  
    3.69      /* Copy the P2M we've constructed to the 'live' P2M */
    3.70 -    if ( !(ctx->live_p2m = xc_map_foreign_batch(xc_handle, dom, PROT_WRITE,
    3.71 +    if ( !(ctx->live_p2m = xc_map_foreign_pages(xc_handle, dom, PROT_WRITE,
    3.72                                             p2m_frame_list, P2M_FL_ENTRIES)) )
    3.73      {
    3.74          ERROR("Couldn't map p2m table");
     4.1 --- a/tools/libxc/xc_domain_save.c	Tue Jan 12 07:17:40 2010 +0000
     4.2 +++ b/tools/libxc/xc_domain_save.c	Wed Jan 13 08:12:56 2010 +0000
     4.3 @@ -709,7 +709,7 @@ static xen_pfn_t *map_and_save_p2m_table
     4.4              p2m_frame_list_list[i] = ((uint32_t *)p2m_frame_list_list)[i];
     4.5  
     4.6      live_p2m_frame_list =
     4.7 -        xc_map_foreign_batch(xc_handle, dom, PROT_READ,
     4.8 +        xc_map_foreign_pages(xc_handle, dom, PROT_READ,
     4.9                               p2m_frame_list_list,
    4.10                               P2M_FLL_ENTRIES);
    4.11      if ( !live_p2m_frame_list )
    4.12 @@ -727,6 +727,9 @@ static xen_pfn_t *map_and_save_p2m_table
    4.13      memset(p2m_frame_list, 0, P2M_TOOLS_FL_SIZE);
    4.14      memcpy(p2m_frame_list, live_p2m_frame_list, P2M_GUEST_FL_SIZE);
    4.15  
    4.16 +    munmap(live_p2m_frame_list, P2M_FLL_ENTRIES * PAGE_SIZE);
    4.17 +    live_p2m_frame_list = NULL;
    4.18 +
    4.19      /* Canonicalize guest's unsigned long vs ours */
    4.20      if ( dinfo->guest_width > sizeof(unsigned long) )
    4.21          for ( i = 0; i < P2M_FL_ENTRIES; i++ )
    4.22 @@ -741,7 +744,7 @@ static xen_pfn_t *map_and_save_p2m_table
    4.23         (its not clear why it would want to change them, and we'll be OK
    4.24         from a safety POV anyhow. */
    4.25  
    4.26 -    p2m = xc_map_foreign_batch(xc_handle, dom, PROT_READ,
    4.27 +    p2m = xc_map_foreign_pages(xc_handle, dom, PROT_READ,
    4.28                                 p2m_frame_list,
    4.29                                 P2M_FL_ENTRIES);
    4.30      if ( !p2m )
    4.31 @@ -873,8 +876,9 @@ int xc_domain_save(int xc_handle, int io
    4.32      vcpu_guest_context_any_t ctxt;
    4.33  
    4.34      /* A table containing the type of each PFN (/not/ MFN!). */
    4.35 -    unsigned long *pfn_type = NULL;
    4.36 +    xen_pfn_t *pfn_type = NULL;
    4.37      unsigned long *pfn_batch = NULL;
    4.38 +    int *pfn_err = NULL;
    4.39  
    4.40      /* A copy of one frame of guest memory. */
    4.41      char page[PAGE_SIZE];
    4.42 @@ -1263,8 +1267,8 @@ int xc_domain_save(int xc_handle, int io
    4.43              if ( batch == 0 )
    4.44                  goto skip; /* vanishingly unlikely... */
    4.45  
    4.46 -            region_base = xc_map_foreign_batch(
    4.47 -                xc_handle, dom, PROT_READ, pfn_type, batch);
    4.48 +            region_base = xc_map_foreign_bulk(
    4.49 +                xc_handle, dom, PROT_READ, pfn_type, pfn_err, batch);
    4.50              if ( region_base == NULL )
    4.51              {
    4.52                  ERROR("map batch failed");
    4.53 @@ -1275,14 +1279,19 @@ int xc_domain_save(int xc_handle, int io
    4.54              {
    4.55                  /* Look for and skip completely empty batches. */
    4.56                  for ( j = 0; j < batch; j++ )
    4.57 -                    if ( (pfn_type[j] & XEN_DOMCTL_PFINFO_LTAB_MASK) !=
    4.58 -                         XEN_DOMCTL_PFINFO_XTAB )
    4.59 +                {
    4.60 +                    if ( !pfn_err[j] )
    4.61                          break;
    4.62 +                    pfn_type[j] |= XEN_DOMCTL_PFINFO_XTAB;
    4.63 +                }
    4.64                  if ( j == batch )
    4.65                  {
    4.66                      munmap(region_base, batch*PAGE_SIZE);
    4.67                      continue; /* bail on this batch: no valid pages */
    4.68                  }
    4.69 +                for ( ; j < batch; j++ )
    4.70 +                    if ( pfn_err[j] )
    4.71 +                        pfn_type[j] |= XEN_DOMCTL_PFINFO_XTAB;
    4.72              }
    4.73              else
    4.74              {
    4.75 @@ -1296,16 +1305,17 @@ int xc_domain_save(int xc_handle, int io
    4.76                      goto out;
    4.77                  }
    4.78                  for ( j = batch-1; j >= 0; j-- )
    4.79 -                    pfn_type[j] = ((uint32_t *)pfn_type)[j];
    4.80 +                    pfn_type[j] = ((uint32_t *)pfn_type)[j] &
    4.81 +                                  XEN_DOMCTL_PFINFO_LTAB_MASK;
    4.82  
    4.83                  for ( j = 0; j < batch; j++ )
    4.84                  {
    4.85 +                    unsigned long mfn = pfn_to_mfn(pfn_batch[j]);
    4.86                      
    4.87 -                    if ( (pfn_type[j] & XEN_DOMCTL_PFINFO_LTAB_MASK) ==
    4.88 -                         XEN_DOMCTL_PFINFO_XTAB )
    4.89 +                    if ( pfn_type[j] == XEN_DOMCTL_PFINFO_XTAB )
    4.90                      {
    4.91                          DPRINTF("type fail: page %i mfn %08lx\n", 
    4.92 -                                j, pfn_type[j]);
    4.93 +                                j, mfn);
    4.94                          continue;
    4.95                      }
    4.96                      
    4.97 @@ -1313,16 +1323,13 @@ int xc_domain_save(int xc_handle, int io
    4.98                          DPRINTF("%d pfn= %08lx mfn= %08lx [mfn]= %08lx"
    4.99                                  " sum= %08lx\n",
   4.100                                  iter,
   4.101 -                                (pfn_type[j] & XEN_DOMCTL_PFINFO_LTAB_MASK) |
   4.102 -                                pfn_batch[j],
   4.103 -                                pfn_type[j],
   4.104 -                                mfn_to_pfn(pfn_type[j] &
   4.105 -                                           ~XEN_DOMCTL_PFINFO_LTAB_MASK),
   4.106 +                                pfn_type[j] | pfn_batch[j],
   4.107 +                                mfn,
   4.108 +                                mfn_to_pfn(mfn),
   4.109                                  csum_page(region_base + (PAGE_SIZE*j)));
   4.110                      
   4.111                      /* canonicalise mfn->pfn */
   4.112 -                    pfn_type[j] = (pfn_type[j] & XEN_DOMCTL_PFINFO_LTAB_MASK) |
   4.113 -                        pfn_batch[j];
   4.114 +                    pfn_type[j] |= pfn_batch[j];
   4.115                  }
   4.116              }
   4.117  
   4.118 @@ -1332,11 +1339,17 @@ int xc_domain_save(int xc_handle, int io
   4.119                  goto out;
   4.120              }
   4.121  
   4.122 +            if ( sizeof(unsigned long) < sizeof(*pfn_type) )
   4.123 +                for ( j = 0; j < batch; j++ )
   4.124 +                    ((unsigned long *)pfn_type)[j] = pfn_type[j];
   4.125              if ( write_exact(io_fd, pfn_type, sizeof(unsigned long)*batch) )
   4.126              {
   4.127                  PERROR("Error when writing to state file (3)");
   4.128                  goto out;
   4.129              }
   4.130 +            if ( sizeof(unsigned long) < sizeof(*pfn_type) )
   4.131 +                while ( --j >= 0 )
   4.132 +                    pfn_type[j] = ((unsigned long *)pfn_type)[j];
   4.133  
   4.134              /* entering this loop, pfn_type is now in pfns (Not mfns) */
   4.135              run = 0;
     5.1 --- a/tools/libxc/xc_linux.c	Tue Jan 12 07:17:40 2010 +0000
     5.2 +++ b/tools/libxc/xc_linux.c	Wed Jan 13 08:12:56 2010 +0000
     5.3 @@ -64,7 +64,7 @@ int xc_interface_close(int xc_handle)
     5.4      return close(xc_handle);
     5.5  }
     5.6  
     5.7 -static int xc_map_foreign_batch_single(int xc_handle, uint32_t dom, int prot,
     5.8 +static int xc_map_foreign_batch_single(int xc_handle, uint32_t dom,
     5.9                                         xen_pfn_t *mfn, unsigned long addr)
    5.10  {
    5.11      privcmd_mmapbatch_t ioctlx;
    5.12 @@ -116,7 +116,7 @@ void *xc_map_foreign_batch(int xc_handle
    5.13                   XEN_DOMCTL_PFINFO_PAGEDTAB )
    5.14              {
    5.15                  unsigned long paged_addr = (unsigned long)addr + (i << PAGE_SHIFT);
    5.16 -                rc = xc_map_foreign_batch_single(xc_handle, dom, prot, &arr[i],
    5.17 +                rc = xc_map_foreign_batch_single(xc_handle, dom, &arr[i],
    5.18                                                   paged_addr);
    5.19                  if ( rc < 0 )
    5.20                      goto out;
    5.21 @@ -137,6 +137,131 @@ void *xc_map_foreign_batch(int xc_handle
    5.22      return addr;
    5.23  }
    5.24  
    5.25 +void *xc_map_foreign_bulk(int xc_handle, uint32_t dom, int prot,
    5.26 +                          const xen_pfn_t *arr, int *err, unsigned int num)
    5.27 +{
    5.28 +    privcmd_mmapbatch_v2_t ioctlx;
    5.29 +    void *addr;
    5.30 +    unsigned int i;
    5.31 +    int rc;
    5.32 +
    5.33 +    addr = mmap(NULL, (unsigned long)num << PAGE_SHIFT, prot, MAP_SHARED,
    5.34 +                xc_handle, 0);
    5.35 +    if ( addr == MAP_FAILED )
    5.36 +    {
    5.37 +        perror("xc_map_foreign_batch: mmap failed");
    5.38 +        return NULL;
    5.39 +    }
    5.40 +
    5.41 +    ioctlx.num = num;
    5.42 +    ioctlx.dom = dom;
    5.43 +    ioctlx.addr = (unsigned long)addr;
    5.44 +    ioctlx.arr = arr;
    5.45 +    ioctlx.err = err;
    5.46 +
    5.47 +    rc = ioctl(xc_handle, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
    5.48 +
    5.49 +    if ( rc < 0 && errno == ENOENT )
    5.50 +    {
    5.51 +        for ( i = rc = 0; rc == 0 && i < num; i++ )
    5.52 +        {
    5.53 +            if ( err[i] != -ENOENT )
    5.54 +                continue;
    5.55 +
    5.56 +            ioctlx.num = 1;
    5.57 +            ioctlx.dom = dom;
    5.58 +            ioctlx.addr = (unsigned long)addr + ((unsigned long)i<<PAGE_SHIFT);
    5.59 +            ioctlx.arr = arr + i;
    5.60 +            ioctlx.err = err + i;
    5.61 +            do {
    5.62 +                usleep(100);
    5.63 +                rc = ioctl(xc_handle, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
    5.64 +            } while ( rc < 0 && err[i] == -ENOENT );
    5.65 +        }
    5.66 +    }
    5.67 +
    5.68 +    if ( rc < 0 && errno == ENOTTY && (int)num > 0 )
    5.69 +    {
    5.70 +        /*
    5.71 +         * IOCTL_PRIVCMD_MMAPBATCH_V2 is not supported - fall back to
    5.72 +         * IOCTL_PRIVCMD_MMAPBATCH.
    5.73 +         */
    5.74 +        xen_pfn_t *pfn = calloc(num, sizeof(*pfn));
    5.75 +
    5.76 +        if ( pfn )
    5.77 +        {
    5.78 +            privcmd_mmapbatch_t ioctlx;
    5.79 +
    5.80 +            memcpy(pfn, arr, num * sizeof(*arr));
    5.81 +
    5.82 +            ioctlx.num = num;
    5.83 +            ioctlx.dom = dom;
    5.84 +            ioctlx.addr = (unsigned long)addr;
    5.85 +            ioctlx.arr = pfn;
    5.86 +
    5.87 +            rc = ioctl(xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
    5.88 +
    5.89 +            rc = rc < 0 ? -errno : 0;
    5.90 +
    5.91 +            for ( i = 0; i < num; ++i )
    5.92 +            {
    5.93 +                switch ( pfn[i] ^ arr[i] )
    5.94 +                {
    5.95 +                case 0:
    5.96 +                    err[i] = rc != -ENOENT ? rc : 0;
    5.97 +                    continue;
    5.98 +                default:
    5.99 +                    err[i] = -EINVAL;
   5.100 +                    continue;
   5.101 +                case XEN_DOMCTL_PFINFO_PAGEDTAB:
   5.102 +                    if ( rc != -ENOENT )
   5.103 +                    {
   5.104 +                        err[i] = rc ?: -EINVAL;
   5.105 +                        continue;
   5.106 +                    }
   5.107 +                    rc = xc_map_foreign_batch_single(xc_handle, dom, pfn + i,
   5.108 +                        (unsigned long)addr + ((unsigned long)i<<PAGE_SHIFT));
   5.109 +                    if ( rc < 0 )
   5.110 +                    {
   5.111 +                        rc = -errno;
   5.112 +                        break;
   5.113 +                    }
   5.114 +                    rc = -ENOENT;
   5.115 +                    continue;
   5.116 +                }
   5.117 +                break;
   5.118 +            }
   5.119 +
   5.120 +            free(pfn);
   5.121 +
   5.122 +            if ( rc == -ENOENT && i == num )
   5.123 +                rc = 0;
   5.124 +            else if ( rc )
   5.125 +            {
   5.126 +                errno = -rc;
   5.127 +                rc = -1;
   5.128 +            }
   5.129 +        }
   5.130 +        else
   5.131 +        {
   5.132 +            errno = -ENOMEM;
   5.133 +            rc = -1;
   5.134 +        }
   5.135 +    }
   5.136 +
   5.137 +    if ( rc < 0 )
   5.138 +    {
   5.139 +        int saved_errno = errno;
   5.140 +
   5.141 +        perror("xc_map_foreign_bulk: ioctl failed");
   5.142 +        (void)munmap(addr, (unsigned long)num << PAGE_SHIFT);
   5.143 +        errno = saved_errno;
   5.144 +        return NULL;
   5.145 +    }
   5.146 +
   5.147 +    return addr;
   5.148 +}
   5.149 +
   5.150  void *xc_map_foreign_range(int xc_handle, uint32_t dom, int size, int prot,
   5.151                             unsigned long mfn)
   5.152  {
   5.153 @@ -151,7 +276,7 @@ void *xc_map_foreign_range(int xc_handle
   5.154      for ( i = 0; i < num; i++ )
   5.155          arr[i] = mfn + i;
   5.156  
   5.157 -    ret = xc_map_foreign_batch(xc_handle, dom, prot, arr, num);
   5.158 +    ret = xc_map_foreign_pages(xc_handle, dom, prot, arr, num);
   5.159      free(arr);
   5.160      return ret;
   5.161  }
   5.162 @@ -175,7 +300,7 @@ void *xc_map_foreign_ranges(int xc_handl
   5.163          for ( j = 0; j < num_per_entry; j++ )
   5.164              arr[i * num_per_entry + j] = entries[i].mfn + j;
   5.165  
   5.166 -    ret = xc_map_foreign_batch(xc_handle, dom, prot, arr, num);
   5.167 +    ret = xc_map_foreign_pages(xc_handle, dom, prot, arr, num);
   5.168      free(arr);
   5.169      return ret;
   5.170  }
     6.1 --- a/tools/libxc/xc_misc.c	Tue Jan 12 07:17:40 2010 +0000
     6.2 +++ b/tools/libxc/xc_misc.c	Wed Jan 13 08:12:56 2010 +0000
     6.3 @@ -352,25 +352,23 @@ int xc_hvm_set_mem_type(
     6.4  void *xc_map_foreign_pages(int xc_handle, uint32_t dom, int prot,
     6.5                             const xen_pfn_t *arr, int num)
     6.6  {
     6.7 -    xen_pfn_t *pfn;
     6.8      void *res;
     6.9 -    int i;
    6.10 +    int i, *err;
    6.11  
    6.12 -    pfn = malloc(num * sizeof(*pfn));
    6.13 -    if (!pfn)
    6.14 +    if (num < 0) {
    6.15 +        errno = -EINVAL;
    6.16          return NULL;
    6.17 -    memcpy(pfn, arr, num * sizeof(*pfn));
    6.18 +    }
    6.19  
    6.20 -    res = xc_map_foreign_batch(xc_handle, dom, prot, pfn, num);
    6.21 +    err = calloc(num, sizeof(*err));
    6.22 +    if (!err)
    6.23 +        return NULL;
    6.24 +
    6.25 +    res = xc_map_foreign_bulk(xc_handle, dom, prot, arr, err, num);
    6.26      if (res) {
    6.27          for (i = 0; i < num; i++) {
    6.28 -            if ((pfn[i] & 0xF0000000UL) == 0xF0000000UL) {
    6.29 -                /*
    6.30 -                 * xc_map_foreign_batch() doesn't give us an error
    6.31 -                 * code, so we have to make one up.  May not be the
    6.32 -                 * appropriate one.
    6.33 -                 */
    6.34 -                errno = EINVAL;
    6.35 +            if (err[i]) {
    6.36 +                errno = -err[i];
    6.37                  munmap(res, num * PAGE_SIZE);
    6.38                  res = NULL;
    6.39                  break;
    6.40 @@ -378,8 +376,51 @@ void *xc_map_foreign_pages(int xc_handle
    6.41          }
    6.42      }
    6.43  
    6.44 +    free(err);
    6.45 +    return res;
    6.46 +}
    6.47 +
    6.48 +/* stub for all not yet converted OSes */
    6.49 +void *
    6.50 +#ifdef __GNUC__
    6.51 +__attribute__((__weak__))
    6.52 +#endif
    6.53 +xc_map_foreign_bulk(int xc_handle, uint32_t dom, int prot,
    6.54 +                    const xen_pfn_t *arr, int *err, unsigned int num)
    6.55 +{
    6.56 +    xen_pfn_t *pfn;
    6.57 +    unsigned int i;
    6.58 +    void *ret;
    6.59 +
    6.60 +    if ((int)num <= 0) {
    6.61 +        errno = EINVAL;
    6.62 +        return NULL;
    6.63 +    }
    6.64 +
    6.65 +    pfn = calloc(num, sizeof(*pfn));
    6.66 +    if (!pfn) {
    6.67 +        errno = ENOMEM;
    6.68 +        return NULL;
    6.69 +    }
    6.70 +
    6.71 +    memcpy(pfn, arr, num * sizeof(*arr));
    6.72 +    ret = xc_map_foreign_batch(xc_handle, dom, prot, pfn, num);
    6.73 +
    6.74 +    if (ret) {
    6.75 +        for (i = 0; i < num; ++i)
    6.76 +            switch (pfn[i] ^ arr[i]) {
    6.77 +            case 0:
    6.78 +                err[i] = 0;
    6.79 +                break;
    6.80 +            default:
    6.81 +                err[i] = -EINVAL;
    6.82 +                break;
    6.83 +            }
    6.84 +    }
    6.85 +
    6.86      free(pfn);
    6.87 -    return res;
    6.88 +
    6.89 +    return ret;
    6.90  }
    6.91  
    6.92  /*
     7.1 --- a/tools/libxc/xc_resume.c	Tue Jan 12 07:17:40 2010 +0000
     7.2 +++ b/tools/libxc/xc_resume.c	Wed Jan 13 08:12:56 2010 +0000
     7.3 @@ -158,7 +158,7 @@ static int xc_domain_resume_any(int xc_h
     7.4          goto out;
     7.5      }
     7.6  
     7.7 -    p2m_frame_list = xc_map_foreign_batch(xc_handle, domid, PROT_READ,
     7.8 +    p2m_frame_list = xc_map_foreign_pages(xc_handle, domid, PROT_READ,
     7.9                                            p2m_frame_list_list,
    7.10                                            P2M_FLL_ENTRIES);
    7.11      if ( p2m_frame_list == NULL )
    7.12 @@ -171,7 +171,7 @@ static int xc_domain_resume_any(int xc_h
    7.13         the guest must not change which frames are used for this purpose.
    7.14         (its not clear why it would want to change them, and we'll be OK
    7.15         from a safety POV anyhow. */
    7.16 -    p2m = xc_map_foreign_batch(xc_handle, domid, PROT_READ,
    7.17 +    p2m = xc_map_foreign_pages(xc_handle, domid, PROT_READ,
    7.18                                 p2m_frame_list,
    7.19                                 P2M_FL_ENTRIES);
    7.20      if ( p2m == NULL )
     8.1 --- a/tools/libxc/xenctrl.h	Tue Jan 12 07:17:40 2010 +0000
     8.2 +++ b/tools/libxc/xenctrl.h	Wed Jan 13 08:12:56 2010 +0000
     8.3 @@ -749,6 +749,8 @@ void *xc_map_foreign_pages(int xc_handle
     8.4                             const xen_pfn_t *arr, int num );
     8.5  
     8.6  /**
     8.7 + * DEPRECATED - use xc_map_foreign_bulk() instead.
     8.8 + *
     8.9   * Like xc_map_foreign_pages(), except it can succeeed partially.
    8.10   * When a page cannot be mapped, its PFN in @arr is or'ed with
    8.11   * 0xF0000000 to indicate the error.
    8.12 @@ -757,6 +759,14 @@ void *xc_map_foreign_batch(int xc_handle
    8.13                             xen_pfn_t *arr, int num );
    8.14  
    8.15  /**
    8.16 + * Like xc_map_foreign_pages(), except it can succeed partially.
    8.17 + * When a page cannot be mapped, its respective field in @err is
    8.18 + * set to the corresponding errno value.
    8.19 + */
    8.20 +void *xc_map_foreign_bulk(int xc_handle, uint32_t dom, int prot,
    8.21 +                          const xen_pfn_t *arr, int *err, unsigned int num);
    8.22 +
    8.23 +/**
    8.24   * Translates a virtual address in the context of a given domain and
    8.25   * vcpu returning the GFN containing the address (that is, an MFN for 
    8.26   * PV guests, a PFN for HVM guests).  Returns 0 for failure.
     9.1 --- a/tools/xenpaging/xenpaging.c	Tue Jan 12 07:17:40 2010 +0000
     9.2 +++ b/tools/xenpaging/xenpaging.c	Wed Jan 13 08:12:56 2010 +0000
     9.3 @@ -310,9 +310,9 @@ int xenpaging_evict_page(xenpaging_t *pa
     9.4      /* Map page */
     9.5      gfn = victim->gfn;
     9.6      ret = -EFAULT;
     9.7 -    page = xc_map_foreign_batch(paging->xc_handle, victim->domain_id,
     9.8 +    page = xc_map_foreign_pages(paging->xc_handle, victim->domain_id,
     9.9                                  PROT_READ | PROT_WRITE, &gfn, 1);
    9.10 -    if ( (gfn & XEN_DOMCTL_PFINFO_LTAB_MASK) == XEN_DOMCTL_PFINFO_XTAB )
    9.11 +    if ( page == NULL )
    9.12      {
    9.13          ERROR("Error mapping page");
    9.14          goto out;
    9.15 @@ -386,7 +386,7 @@ int xenpaging_populate_page(xenpaging_t 
    9.16  
    9.17      /* Map page */
    9.18      ret = -EFAULT;
    9.19 -    page = xc_map_foreign_batch(paging->xc_handle, paging->mem_event.domain_id,
    9.20 +    page = xc_map_foreign_pages(paging->xc_handle, paging->mem_event.domain_id,
    9.21                                  PROT_READ | PROT_WRITE, gfn, 1);
    9.22      if ( page == NULL )
    9.23      {
    9.24 @@ -394,13 +394,6 @@ int xenpaging_populate_page(xenpaging_t 
    9.25          goto out_map;
    9.26      }
    9.27  
    9.28 -    /* Check that the page exists */
    9.29 -    if ( (*gfn & XEN_DOMCTL_PFINFO_LTAB_MASK) == XEN_DOMCTL_PFINFO_XTAB )
    9.30 -    {
    9.31 -        ERROR("Error mapping page: gfn is invalid");
    9.32 -        goto out;
    9.33 -    }
    9.34 -
    9.35      /* Read page */
    9.36      ret = read_page(fd, page, i);
    9.37      if ( ret != 0 )