direct-io.hg

changeset 12360:5cdd4da17036

[XEN] memory_op hypercall does not use guest_handle_add_offset().

It was causing compatibility issues across architectures as
on x86 the effect would not persist across a continuation. On
x86/64 and powerpc (both of which use xencomm) the effect would
persist. This patch sidesteps the whole issue.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Nov 10 14:22:17 2006 +0000 (2006-11-10)
parents f5b98471d6ff
children 32f7b40ace42
files xen/common/memory.c
line diff
     1.1 --- a/xen/common/memory.c	Fri Nov 10 13:09:01 2006 +0000
     1.2 +++ b/xen/common/memory.c	Fri Nov 10 14:22:17 2006 +0000
     1.3 @@ -29,98 +29,105 @@
     1.4   */
     1.5  #define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */
     1.6  
     1.7 -static long
     1.8 -increase_reservation(
     1.9 -    struct domain *d, 
    1.10 -    XEN_GUEST_HANDLE(xen_pfn_t) extent_list,
    1.11 -    unsigned int   nr_extents,
    1.12 -    unsigned int   extent_order,
    1.13 -    unsigned int   memflags,
    1.14 -    int           *preempted)
    1.15 +struct memop_args {
    1.16 +    /* INPUT */
    1.17 +    struct domain *domain;     /* Domain to be affected. */
    1.18 +    XEN_GUEST_HANDLE(xen_pfn_t) extent_list; /* List of extent base addrs. */
    1.19 +    unsigned int nr_extents;   /* Number of extents to allocate or free. */
    1.20 +    unsigned int extent_order; /* Size of each extent. */
    1.21 +    unsigned int memflags;     /* Allocation flags. */
    1.22 +
    1.23 +    /* INPUT/OUTPUT */
    1.24 +    unsigned int nr_done;    /* Number of extents processed so far. */
    1.25 +    int          preempted;  /* Was the hypercall preempted? */
    1.26 +};
    1.27 +
    1.28 +static unsigned int select_local_cpu(struct domain *d)
    1.29 +{
    1.30 +    struct vcpu *v = d->vcpu[0];
    1.31 +    return (v ? v->processor : 0);
    1.32 +}
    1.33 +
    1.34 +static void increase_reservation(struct memop_args *a)
    1.35  {
    1.36      struct page_info *page;
    1.37      unsigned long i;
    1.38      xen_pfn_t mfn;
    1.39 -    /* use domain's first processor for locality parameter */
    1.40 -    unsigned int cpu = d->vcpu[0]->processor;
    1.41 +    struct domain *d = a->domain;
    1.42 +    unsigned int cpu = select_local_cpu(d);
    1.43  
    1.44 -    if ( !guest_handle_is_null(extent_list) &&
    1.45 -         !guest_handle_okay(extent_list, nr_extents) )
    1.46 -        return 0;
    1.47 +    if ( !guest_handle_is_null(a->extent_list) &&
    1.48 +         !guest_handle_okay(a->extent_list, a->nr_extents) )
    1.49 +        return;
    1.50  
    1.51 -    if ( (extent_order != 0) &&
    1.52 +    if ( (a->extent_order != 0) &&
    1.53           !multipage_allocation_permitted(current->domain) )
    1.54 -        return 0;
    1.55 +        return;
    1.56  
    1.57 -    for ( i = 0; i < nr_extents; i++ )
    1.58 +    for ( i = a->nr_done; i < a->nr_extents; i++ )
    1.59      {
    1.60          if ( hypercall_preempt_check() )
    1.61          {
    1.62 -            *preempted = 1;
    1.63 -            return i;
    1.64 +            a->preempted = 1;
    1.65 +            goto out;
    1.66          }
    1.67  
    1.68 -        if ( unlikely((page = __alloc_domheap_pages( d, cpu, 
    1.69 -            extent_order, memflags )) == NULL) ) 
    1.70 +        page = __alloc_domheap_pages(d, cpu, a->extent_order, a->memflags);
    1.71 +        if ( unlikely(page == NULL) ) 
    1.72          {
    1.73              gdprintk(XENLOG_INFO, "Could not allocate order=%d extent: "
    1.74                      "id=%d memflags=%x (%ld of %d)\n",
    1.75 -                    extent_order, d->domain_id, memflags, i, nr_extents);
    1.76 -            return i;
    1.77 +                     a->extent_order, d->domain_id, a->memflags,
    1.78 +                     i, a->nr_extents);
    1.79 +            goto out;
    1.80          }
    1.81  
    1.82          /* Inform the domain of the new page's machine address. */ 
    1.83 -        if ( !guest_handle_is_null(extent_list) )
    1.84 +        if ( !guest_handle_is_null(a->extent_list) )
    1.85          {
    1.86              mfn = page_to_mfn(page);
    1.87 -            if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) )
    1.88 -                return i;
    1.89 +            if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) )
    1.90 +                goto out;
    1.91          }
    1.92      }
    1.93  
    1.94 -    return nr_extents;
    1.95 + out:
    1.96 +    a->nr_done = i;
    1.97  }
    1.98  
    1.99 -static long
   1.100 -populate_physmap(
   1.101 -    struct domain *d, 
   1.102 -    XEN_GUEST_HANDLE(xen_pfn_t) extent_list,
   1.103 -    unsigned int  nr_extents,
   1.104 -    unsigned int  extent_order,
   1.105 -    unsigned int  memflags,
   1.106 -    int          *preempted)
   1.107 +static void populate_physmap(struct memop_args *a)
   1.108  {
   1.109      struct page_info *page;
   1.110      unsigned long i, j;
   1.111 -    xen_pfn_t gpfn;
   1.112 -    xen_pfn_t mfn;
   1.113 -    /* use domain's first processor for locality parameter */
   1.114 -    unsigned int cpu = d->vcpu[0]->processor;
   1.115 +    xen_pfn_t gpfn, mfn;
   1.116 +    struct domain *d = a->domain;
   1.117 +    unsigned int cpu = select_local_cpu(d);
   1.118  
   1.119 -    if ( !guest_handle_okay(extent_list, nr_extents) )
   1.120 -        return 0;
   1.121 +    if ( !guest_handle_okay(a->extent_list, a->nr_extents) )
   1.122 +        return;
   1.123  
   1.124 -    if ( (extent_order != 0) &&
   1.125 +    if ( (a->extent_order != 0) &&
   1.126           !multipage_allocation_permitted(current->domain) )
   1.127 -        return 0;
   1.128 +        return;
   1.129  
   1.130 -    for ( i = 0; i < nr_extents; i++ )
   1.131 +    for ( i = a->nr_done; i < a->nr_extents; i++ )
   1.132      {
   1.133          if ( hypercall_preempt_check() )
   1.134          {
   1.135 -            *preempted = 1;
   1.136 +            a->preempted = 1;
   1.137              goto out;
   1.138          }
   1.139  
   1.140 -        if ( unlikely(__copy_from_guest_offset(&gpfn, extent_list, i, 1)) )
   1.141 +        if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i, 1)) )
   1.142              goto out;
   1.143  
   1.144 -        if ( unlikely((page = __alloc_domheap_pages( d, cpu, 
   1.145 -            extent_order, memflags )) == NULL) ) 
   1.146 +        page = __alloc_domheap_pages(d, cpu, a->extent_order, a->memflags);
   1.147 +        if ( unlikely(page == NULL) ) 
   1.148          {
   1.149              gdprintk(XENLOG_INFO, "Could not allocate order=%d extent: "
   1.150 -                    "id=%d memflags=%x (%ld of %d)\n",
   1.151 -                    extent_order, d->domain_id, memflags, i, nr_extents);
   1.152 +                     "id=%d memflags=%x (%ld of %d)\n",
   1.153 +                     a->extent_order, d->domain_id, a->memflags,
   1.154 +                     i, a->nr_extents);
   1.155              goto out;
   1.156          }
   1.157  
   1.158 @@ -128,28 +135,25 @@ populate_physmap(
   1.159  
   1.160          if ( unlikely(shadow_mode_translate(d)) )
   1.161          {
   1.162 -            for ( j = 0; j < (1 << extent_order); j++ )
   1.163 +            for ( j = 0; j < (1 << a->extent_order); j++ )
   1.164                  guest_physmap_add_page(d, gpfn + j, mfn + j);
   1.165          }
   1.166          else
   1.167          {
   1.168 -            for ( j = 0; j < (1 << extent_order); j++ )
   1.169 +            for ( j = 0; j < (1 << a->extent_order); j++ )
   1.170                  set_gpfn_from_mfn(mfn + j, gpfn + j);
   1.171  
   1.172              /* Inform the domain of the new page's machine address. */ 
   1.173 -            if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) )
   1.174 +            if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) )
   1.175                  goto out;
   1.176          }
   1.177      }
   1.178  
   1.179   out:
   1.180 -    return i;
   1.181 +    a->nr_done = i;
   1.182  }
   1.183  
   1.184 -int
   1.185 -guest_remove_page(
   1.186 -    struct domain *d,
   1.187 -    unsigned long gmfn)
   1.188 +int guest_remove_page(struct domain *d, unsigned long gmfn)
   1.189  {
   1.190      struct page_info *page;
   1.191      unsigned long mfn;
   1.192 @@ -191,43 +195,35 @@ guest_remove_page(
   1.193      return 1;
   1.194  }
   1.195  
   1.196 -static long
   1.197 -decrease_reservation(
   1.198 -    struct domain *d,
   1.199 -    XEN_GUEST_HANDLE(xen_pfn_t) extent_list,
   1.200 -    unsigned int   nr_extents,
   1.201 -    unsigned int   extent_order,
   1.202 -    int           *preempted)
   1.203 +static void decrease_reservation(struct memop_args *a)
   1.204  {
   1.205      unsigned long i, j;
   1.206      xen_pfn_t gmfn;
   1.207  
   1.208 -    if ( !guest_handle_okay(extent_list, nr_extents) )
   1.209 -        return 0;
   1.210 +    if ( !guest_handle_okay(a->extent_list, a->nr_extents) )
   1.211 +        return;
   1.212  
   1.213 -    for ( i = 0; i < nr_extents; i++ )
   1.214 +    for ( i = a->nr_done; i < a->nr_extents; i++ )
   1.215      {
   1.216          if ( hypercall_preempt_check() )
   1.217          {
   1.218 -            *preempted = 1;
   1.219 -            return i;
   1.220 +            a->preempted = 1;
   1.221 +            goto out;
   1.222          }
   1.223  
   1.224 -        if ( unlikely(__copy_from_guest_offset(&gmfn, extent_list, i, 1)) )
   1.225 -            return i;
   1.226 +        if ( unlikely(__copy_from_guest_offset(&gmfn, a->extent_list, i, 1)) )
   1.227 +            goto out;
   1.228  
   1.229 -        for ( j = 0; j < (1 << extent_order); j++ )
   1.230 -        {
   1.231 -            if ( !guest_remove_page(d, gmfn + j) )
   1.232 -                return i;
   1.233 -        }
   1.234 +        for ( j = 0; j < (1 << a->extent_order); j++ )
   1.235 +            if ( !guest_remove_page(a->domain, gmfn + j) )
   1.236 +                goto out;
   1.237      }
   1.238  
   1.239 -    return nr_extents;
   1.240 + out:
   1.241 +    a->nr_done = i;
   1.242  }
   1.243  
   1.244 -static long
   1.245 -translate_gpfn_list(
   1.246 +static long translate_gpfn_list(
   1.247      XEN_GUEST_HANDLE(xen_translate_gpfn_list_t) uop, unsigned long *progress)
   1.248  {
   1.249      struct xen_translate_gpfn_list op;
   1.250 @@ -289,8 +285,7 @@ translate_gpfn_list(
   1.251      return 0;
   1.252  }
   1.253  
   1.254 -static long
   1.255 -memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
   1.256 +static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg)
   1.257  {
   1.258      struct xen_memory_exchange exch;
   1.259      LIST_HEAD(in_chunk_list);
   1.260 @@ -341,24 +336,15 @@ memory_exchange(XEN_GUEST_HANDLE(xen_mem
   1.261          memflags = MEMF_dma;
   1.262      }
   1.263  
   1.264 -    guest_handle_add_offset(exch.in.extent_start, exch.nr_exchanged);
   1.265 -    exch.in.nr_extents -= exch.nr_exchanged;
   1.266 -
   1.267      if ( exch.in.extent_order <= exch.out.extent_order )
   1.268      {
   1.269          in_chunk_order  = exch.out.extent_order - exch.in.extent_order;
   1.270          out_chunk_order = 0;
   1.271 -        guest_handle_add_offset(
   1.272 -            exch.out.extent_start, exch.nr_exchanged >> in_chunk_order);
   1.273 -        exch.out.nr_extents -= exch.nr_exchanged >> in_chunk_order;
   1.274      }
   1.275      else
   1.276      {
   1.277          in_chunk_order  = 0;
   1.278          out_chunk_order = exch.in.extent_order - exch.out.extent_order;
   1.279 -        guest_handle_add_offset(
   1.280 -            exch.out.extent_start, exch.nr_exchanged << out_chunk_order);
   1.281 -        exch.out.nr_extents -= exch.nr_exchanged << out_chunk_order;
   1.282      }
   1.283  
   1.284      /*
   1.285 @@ -372,14 +358,15 @@ memory_exchange(XEN_GUEST_HANDLE(xen_mem
   1.286      }
   1.287      d = current->domain;
   1.288  
   1.289 -    /* use domain's first processor for locality parameter */
   1.290 -    cpu = d->vcpu[0]->processor;
   1.291 +    cpu = select_local_cpu(d);
   1.292  
   1.293 -    for ( i = 0; i < (exch.in.nr_extents >> in_chunk_order); i++ )
   1.294 +    for ( i = (exch.nr_exchanged >> in_chunk_order);
   1.295 +          i < (exch.in.nr_extents >> in_chunk_order);
   1.296 +          i++ )
   1.297      {
   1.298          if ( hypercall_preempt_check() )
   1.299          {
   1.300 -            exch.nr_exchanged += i << in_chunk_order;
   1.301 +            exch.nr_exchanged = i << in_chunk_order;
   1.302              if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
   1.303                  return -EFAULT;
   1.304              return hypercall_create_continuation(
   1.305 @@ -420,8 +407,8 @@ memory_exchange(XEN_GUEST_HANDLE(xen_mem
   1.306          /* Allocate a chunk's worth of anonymous output pages. */
   1.307          for ( j = 0; j < (1UL << out_chunk_order); j++ )
   1.308          {
   1.309 -            page = __alloc_domheap_pages( NULL, cpu, 
   1.310 -                  exch.out.extent_order, memflags);
   1.311 +            page = __alloc_domheap_pages(
   1.312 +                NULL, cpu, exch.out.extent_order, memflags);
   1.313              if ( unlikely(page == NULL) )
   1.314              {
   1.315                  rc = -ENOMEM;
   1.316 @@ -480,7 +467,7 @@ memory_exchange(XEN_GUEST_HANDLE(xen_mem
   1.317          BUG_ON(j != (1UL << out_chunk_order));
   1.318      }
   1.319  
   1.320 -    exch.nr_exchanged += exch.in.nr_extents;
   1.321 +    exch.nr_exchanged = exch.in.nr_extents;
   1.322      if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
   1.323          rc = -EFAULT;
   1.324      return rc;
   1.325 @@ -507,7 +494,7 @@ memory_exchange(XEN_GUEST_HANDLE(xen_mem
   1.326          free_domheap_pages(page, exch.out.extent_order);
   1.327      }
   1.328  
   1.329 -    exch.nr_exchanged += i << in_chunk_order;
   1.330 +    exch.nr_exchanged = i << in_chunk_order;
   1.331  
   1.332   fail_early:
   1.333      if ( copy_field_to_guest(arg, &exch, nr_exchanged) )
   1.334 @@ -518,10 +505,10 @@ memory_exchange(XEN_GUEST_HANDLE(xen_mem
   1.335  long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg)
   1.336  {
   1.337      struct domain *d;
   1.338 -    int rc, op, preempted = 0;
   1.339 -    unsigned int memflags = 0;
   1.340 +    int rc, op;
   1.341      unsigned long start_extent, progress;
   1.342      struct xen_memory_reservation reservation;
   1.343 +    struct memop_args args;
   1.344      domid_t domid;
   1.345  
   1.346      op = cmd & ((1 << START_EXTENT_SHIFT) - 1);
   1.347 @@ -543,9 +530,12 @@ long do_memory_op(unsigned long cmd, XEN
   1.348          if ( unlikely(start_extent > reservation.nr_extents) )
   1.349              return start_extent;
   1.350  
   1.351 -        if ( !guest_handle_is_null(reservation.extent_start) )
   1.352 -            guest_handle_add_offset(reservation.extent_start, start_extent);
   1.353 -        reservation.nr_extents -= start_extent;
   1.354 +        args.extent_list  = reservation.extent_start;
   1.355 +        args.nr_extents   = reservation.nr_extents;
   1.356 +        args.extent_order = reservation.extent_order;
   1.357 +        args.nr_done      = start_extent;
   1.358 +        args.preempted    = 0;
   1.359 +        args.memflags     = 0;
   1.360  
   1.361          if ( (reservation.address_bits != 0) &&
   1.362               (reservation.address_bits <
   1.363 @@ -553,7 +543,7 @@ long do_memory_op(unsigned long cmd, XEN
   1.364          {
   1.365              if ( reservation.address_bits < 31 )
   1.366                  return start_extent;
   1.367 -            memflags = MEMF_dma;
   1.368 +            args.memflags = MEMF_dma;
   1.369          }
   1.370  
   1.371          if ( likely(reservation.domid == DOMID_SELF) )
   1.372 @@ -561,44 +551,27 @@ long do_memory_op(unsigned long cmd, XEN
   1.373          else if ( !IS_PRIV(current->domain) ||
   1.374                    ((d = find_domain_by_id(reservation.domid)) == NULL) )
   1.375              return start_extent;
   1.376 +        args.domain = d;
   1.377  
   1.378          switch ( op )
   1.379          {
   1.380          case XENMEM_increase_reservation:
   1.381 -            rc = increase_reservation(
   1.382 -                d,
   1.383 -                reservation.extent_start,
   1.384 -                reservation.nr_extents,
   1.385 -                reservation.extent_order,
   1.386 -                memflags,
   1.387 -                &preempted);
   1.388 +            increase_reservation(&args);
   1.389              break;
   1.390          case XENMEM_decrease_reservation:
   1.391 -            rc = decrease_reservation(
   1.392 -                d,
   1.393 -                reservation.extent_start,
   1.394 -                reservation.nr_extents,
   1.395 -                reservation.extent_order,
   1.396 -                &preempted);
   1.397 +            decrease_reservation(&args);
   1.398              break;
   1.399 -        case XENMEM_populate_physmap:
   1.400 -        default:
   1.401 -            rc = populate_physmap(
   1.402 -                d,
   1.403 -                reservation.extent_start,
   1.404 -                reservation.nr_extents,
   1.405 -                reservation.extent_order,
   1.406 -                memflags,
   1.407 -                &preempted);
   1.408 +        default: /* XENMEM_populate_physmap */
   1.409 +            populate_physmap(&args);
   1.410              break;
   1.411          }
   1.412  
   1.413          if ( unlikely(reservation.domid != DOMID_SELF) )
   1.414              put_domain(d);
   1.415  
   1.416 -        rc += start_extent;
   1.417 +        rc = args.nr_done;
   1.418  
   1.419 -        if ( preempted )
   1.420 +        if ( args.preempted )
   1.421              return hypercall_create_continuation(
   1.422                  __HYPERVISOR_memory_op, "lh",
   1.423                  op | (rc << START_EXTENT_SHIFT), arg);