ia64/xen-unstable

changeset 15783:c93e2a822d6f

[xen, xencomm] xencomm multiple page support
Current implementation doesn't allow struct xencomm_desc::address
array to be more than single page. On IA64 it causes 64GB+ domain
creation failure. This patch generalizes xencomm to allow multipage

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author kfraser@localhost.localdomain
date Tue Aug 28 15:32:27 2007 +0100 (2007-08-28)
parents b1c3b9df7d9a
children f4a0804d18f9
files xen/common/xencomm.c
line diff
     1.1 --- a/xen/common/xencomm.c	Tue Aug 28 15:31:56 2007 +0100
     1.2 +++ b/xen/common/xencomm.c	Tue Aug 28 15:32:27 2007 +0100
     1.3 @@ -17,6 +17,7 @@
     1.4   *
     1.5   * Authors: Hollis Blanchard <hollisb@us.ibm.com>
     1.6   *          Tristan Gingold <tristan.gingold@bull.net>
     1.7 + *          Isaku Yamahata <yamahata@valinux.co.jp> multiple page support
     1.8   */
     1.9  
    1.10  #include <xen/config.h>
    1.11 @@ -82,10 +83,11 @@ xencomm_desc_cross_page_boundary(unsigne
    1.12  }
    1.13  
    1.14  struct xencomm_ctxt {
    1.15 -    struct xencomm_desc *desc;
    1.16 +    struct xencomm_desc __user *desc_in_paddr;
    1.17 +    uint32_t nr_addrs;
    1.18  
    1.19 -    uint32_t nr_addrs;
    1.20      struct page_info *page;
    1.21 +    unsigned long *address;
    1.22  };
    1.23  
    1.24  static uint32_t
    1.25 @@ -95,21 +97,9 @@ xencomm_ctxt_nr_addrs(const struct xenco
    1.26  }
    1.27  
    1.28  static unsigned long*
    1.29 -xencomm_ctxt_address(struct xencomm_ctxt *ctxt, int i)
    1.30 +xencomm_ctxt_address(struct xencomm_ctxt *ctxt)
    1.31  {
    1.32 -    return &ctxt->desc->address[i];
    1.33 -}
    1.34 -
    1.35 -/* check if struct xencomm_desc and address array cross page boundary */
    1.36 -static int
    1.37 -xencomm_ctxt_cross_page_boundary(struct xencomm_ctxt *ctxt)
    1.38 -{
    1.39 -    unsigned long saddr = (unsigned long)ctxt->desc;
    1.40 -    unsigned long eaddr =
    1.41 -        (unsigned long)&ctxt->desc->address[ctxt->nr_addrs] - 1;
    1.42 -    if ( (saddr >> PAGE_SHIFT) != (eaddr >> PAGE_SHIFT) )
    1.43 -        return 1;
    1.44 -    return 0;
    1.45 +    return ctxt->address;
    1.46  }
    1.47  
    1.48  static int
    1.49 @@ -138,16 +128,40 @@ xencomm_ctxt_init(const void* handle, st
    1.50          return -EINVAL;
    1.51      }
    1.52  
    1.53 -    ctxt->desc = desc;
    1.54      ctxt->nr_addrs = desc->nr_addrs; /* copy before use.
    1.55                                        * It is possible for a guest domain to
    1.56                                        * modify concurrently.
    1.57                                        */
    1.58 +    ctxt->desc_in_paddr = (struct xencomm_desc*)handle;
    1.59      ctxt->page = page;
    1.60 -    if ( xencomm_ctxt_cross_page_boundary(ctxt) )
    1.61 +    ctxt->address = &desc->address[0];
    1.62 +    return 0;
    1.63 +}
    1.64 +
    1.65 +static int
    1.66 +xencomm_ctxt_next(struct xencomm_ctxt *ctxt, int i)
    1.67 +{
    1.68 +    BUG_ON(i >= ctxt->nr_addrs);
    1.69 +    /* in i == 0 case, we already calculated in xecomm_addr_init() */
    1.70 +    if ( i != 0 )
    1.71 +        ctxt->address++;
    1.72 +    
    1.73 +    /* When crossing page boundary, machine address must be calculated. */
    1.74 +    if ( ((unsigned long)ctxt->address & ~PAGE_MASK) == 0 )
    1.75      {
    1.76 -        put_page(page);
    1.77 -        return -EINVAL;
    1.78 +        unsigned long paddr =
    1.79 +            (unsigned long)&(ctxt->desc_in_paddr->address[i]);
    1.80 +        struct page_info *page;
    1.81 +        int ret;
    1.82 +
    1.83 +        ret = xencomm_get_page(paddr, &page);
    1.84 +        if ( ret == 0 )
    1.85 +        {
    1.86 +            put_page(ctxt->page);
    1.87 +            ctxt->page = page;
    1.88 +            ctxt->address = xencomm_vaddr(paddr, page);
    1.89 +        }
    1.90 +        return ret;
    1.91      }
    1.92      return 0;
    1.93  }
    1.94 @@ -238,9 +252,12 @@ xencomm_copy_from_guest(
    1.95      /* Iterate through the descriptor, copying up to a page at a time */
    1.96      while ( (to_pos < n) && (i < xencomm_ctxt_nr_addrs(&ctxt)) )
    1.97      {
    1.98 -        unsigned long src_paddr = *xencomm_ctxt_address(&ctxt, i);
    1.99 +        unsigned long src_paddr;
   1.100          unsigned int pgoffset, chunksz, chunk_skip;
   1.101  
   1.102 +        if ( xencomm_ctxt_next(&ctxt, i) )
   1.103 +            goto out;
   1.104 +        src_paddr = *xencomm_ctxt_address(&ctxt);
   1.105          if ( src_paddr == XENCOMM_INVALID )
   1.106          {
   1.107              i++;
   1.108 @@ -354,9 +371,12 @@ xencomm_copy_to_guest(
   1.109      /* Iterate through the descriptor, copying up to a page at a time */
   1.110      while ( (from_pos < n) && (i < xencomm_ctxt_nr_addrs(&ctxt)) )
   1.111      {
   1.112 -        unsigned long dest_paddr = *xencomm_ctxt_address(&ctxt, i);
   1.113 +        unsigned long dest_paddr;
   1.114          unsigned int pgoffset, chunksz, chunk_skip;
   1.115  
   1.116 +        if ( xencomm_ctxt_next(&ctxt, i) )
   1.117 +            goto out;
   1.118 +        dest_paddr = *xencomm_ctxt_address(&ctxt);
   1.119          if ( dest_paddr == XENCOMM_INVALID )
   1.120          {
   1.121              i++;
   1.122 @@ -402,22 +422,27 @@ int xencomm_add_offset(void **handle, un
   1.123  {
   1.124      struct xencomm_ctxt ctxt;
   1.125      int i = 0;
   1.126 +    int res = 0;
   1.127  
   1.128      if ( xencomm_is_inline(*handle) )
   1.129          return xencomm_inline_add_offset(handle, bytes);
   1.130  
   1.131 -    if ( xencomm_ctxt_init(handle, &ctxt) )
   1.132 -        return -1;
   1.133 +    res = xencomm_ctxt_init(handle, &ctxt);
   1.134 +    if ( res != 0 )
   1.135 +        return res;
   1.136  
   1.137      /* Iterate through the descriptor incrementing addresses */
   1.138      while ( (bytes > 0) && (i < xencomm_ctxt_nr_addrs(&ctxt)) )
   1.139      {
   1.140 -        unsigned long *address = xencomm_ctxt_address(&ctxt, i);
   1.141 -        unsigned long dest_paddr = *address;
   1.142 -        unsigned int pgoffset;
   1.143 -        unsigned int chunksz;
   1.144 -        unsigned int chunk_skip;
   1.145 +        unsigned long *address;
   1.146 +        unsigned long dest_paddr;
   1.147 +        unsigned int pgoffset, chunksz, chunk_skip;
   1.148  
   1.149 +        res = xencomm_ctxt_next(&ctxt, i);
   1.150 +        if ( res )
   1.151 +            goto out;
   1.152 +        address = xencomm_ctxt_address(&ctxt);
   1.153 +        dest_paddr = *address;
   1.154          if ( dest_paddr == XENCOMM_INVALID )
   1.155          {
   1.156              i++;
   1.157 @@ -436,8 +461,10 @@ int xencomm_add_offset(void **handle, un
   1.158  
   1.159          i++;
   1.160      }
   1.161 +
   1.162 +out:
   1.163      xencomm_ctxt_done(&ctxt);
   1.164 -    return 0;
   1.165 +    return res;
   1.166  }
   1.167  
   1.168  int xencomm_handle_is_null(void *handle)
   1.169 @@ -454,7 +481,9 @@ int xencomm_handle_is_null(void *handle)
   1.170  
   1.171      for ( i = 0; i < xencomm_ctxt_nr_addrs(&ctxt); i++ )
   1.172      {
   1.173 -        if ( *xencomm_ctxt_address(&ctxt, i) != XENCOMM_INVALID )
   1.174 +        if ( xencomm_ctxt_next(&ctxt, i) )
   1.175 +            goto out;
   1.176 +        if ( *xencomm_ctxt_address(&ctxt) != XENCOMM_INVALID )
   1.177          {
   1.178              res = 0;
   1.179              goto out;