debuggers.hg

changeset 20838:0447c5532e9f

x86: add and use XEN_DOMCTL_getpageframeinfo3

To support wider than 28-bit MFNs, add XEN_DOMCTL_getpageframeinfo3
(with the type replacing the passed in MFN rather than getting or-ed
into it) to properly back xc_get_pfn_type_batch().

With xc_get_pfn_type_batch() only used internally to libxc, move its
prototype from xenctrl.h to xc_private.h.

This also fixes a couple of bugs in pre-existing code:
- the failure path for init_mem_info() leaked minfo->pfn_type,
- one error path of the XEN_DOMCTL_getpageframeinfo2 handler used
put_domain() where rcu_unlock_domain() was meant, and
- the XEN_DOMCTL_getpageframeinfo2 handler could call
xsm_getpageframeinfo() with an invalid struct page_info pointer.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jan 13 08:14:01 2010 +0000 (2010-01-13)
parents 0b138a019292
children 4573383ec3dd
files tools/libxc/xc_domain_save.c tools/libxc/xc_offline_page.c tools/libxc/xc_private.c tools/libxc/xc_private.h tools/libxc/xenctrl.h xen/arch/x86/domctl.c xen/include/public/domctl.h
line diff
     1.1 --- a/tools/libxc/xc_domain_save.c	Wed Jan 13 08:12:56 2010 +0000
     1.2 +++ b/tools/libxc/xc_domain_save.c	Wed Jan 13 08:14:01 2010 +0000
     1.3 @@ -959,6 +959,12 @@ int xc_domain_save(int xc_handle, int io
     1.4      /* Get the size of the P2M table */
     1.5      dinfo->p2m_size = xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &dom) + 1;
     1.6  
     1.7 +    if ( dinfo->p2m_size > ~XEN_DOMCTL_PFINFO_LTAB_MASK )
     1.8 +    {
     1.9 +        ERROR("Cannot save this big a guest");
    1.10 +        goto out;
    1.11 +    }
    1.12 +
    1.13      /* Domain is still running at this point */
    1.14      if ( live )
    1.15      {
    1.16 @@ -1296,17 +1302,11 @@ int xc_domain_save(int xc_handle, int io
    1.17              else
    1.18              {
    1.19                  /* Get page types */
    1.20 -                for ( j = 0; j < batch; j++ )
    1.21 -                    ((uint32_t *)pfn_type)[j] = pfn_type[j];
    1.22 -                if ( xc_get_pfn_type_batch(xc_handle, dom, batch,
    1.23 -                                           (uint32_t *)pfn_type) )
    1.24 +                if ( xc_get_pfn_type_batch(xc_handle, dom, batch, pfn_type) )
    1.25                  {
    1.26                      ERROR("get_pfn_type_batch failed");
    1.27                      goto out;
    1.28                  }
    1.29 -                for ( j = batch-1; j >= 0; j-- )
    1.30 -                    pfn_type[j] = ((uint32_t *)pfn_type)[j] &
    1.31 -                                  XEN_DOMCTL_PFINFO_LTAB_MASK;
    1.32  
    1.33                  for ( j = 0; j < batch; j++ )
    1.34                  {
     2.1 --- a/tools/libxc/xc_offline_page.c	Wed Jan 13 08:12:56 2010 +0000
     2.2 +++ b/tools/libxc/xc_offline_page.c	Wed Jan 13 08:14:01 2010 +0000
     2.3 @@ -24,7 +24,7 @@ struct domain_mem_info{
     2.4      int domid;
     2.5      unsigned int pt_level;
     2.6      unsigned int guest_width;
     2.7 -    uint32_t *pfn_type;
     2.8 +    xen_pfn_t *pfn_type;
     2.9      xen_pfn_t *p2m_table;
    2.10      unsigned long p2m_size;
    2.11      xen_pfn_t *m2p_table;
    2.12 @@ -266,19 +266,18 @@ static int init_mem_info(int xc_handle, 
    2.13      }
    2.14  
    2.15      /* Get pfn type */
    2.16 -    minfo->pfn_type = malloc(sizeof(uint32_t) * minfo->p2m_size);
    2.17 +    minfo->pfn_type = calloc(sizeof(*minfo->pfn_type), minfo->p2m_size);
    2.18      if (!minfo->pfn_type)
    2.19      {
    2.20          ERROR("Failed to malloc pfn_type\n");
    2.21          goto failed;
    2.22      }
    2.23 -    memset(minfo->pfn_type, 0, sizeof(uint32_t) * minfo->p2m_size);
    2.24  
    2.25      for (i = 0; i < minfo->p2m_size; i++)
    2.26          minfo->pfn_type[i] = pfn_to_mfn(i, minfo->p2m_table,
    2.27                                          minfo->guest_width);
    2.28  
    2.29 -    if ( lock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(uint32_t)) )
    2.30 +    if ( lock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(*minfo->pfn_type)) )
    2.31      {
    2.32          ERROR("Unable to lock pfn_type array");
    2.33          goto failed;
    2.34 @@ -297,12 +296,12 @@ static int init_mem_info(int xc_handle, 
    2.35      return 0;
    2.36  
    2.37  unlock:
    2.38 -    unlock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(uint32_t));
    2.39 +    unlock_pages(minfo->pfn_type, minfo->p2m_size * sizeof(*minfo->pfn_type));
    2.40  failed:
    2.41      if (minfo->pfn_type)
    2.42      {
    2.43 +        free(minfo->pfn_type);
    2.44          minfo->pfn_type = NULL;
    2.45 -        free(minfo->pfn_type);
    2.46      }
    2.47      if (live_shinfo)
    2.48          munmap(live_shinfo, PAGE_SIZE);
    2.49 @@ -418,7 +417,9 @@ static int change_pte(int xc_handle, int
    2.50          uint64_t pte, new_pte;
    2.51          int j;
    2.52  
    2.53 -        if ( table_mfn == INVALID_P2M_ENTRY )
    2.54 +        if ( (table_mfn == INVALID_P2M_ENTRY) ||
    2.55 +             ((minfo->pfn_type[i] & XEN_DOMCTL_PFINFO_LTAB_MASK) ==
    2.56 +              XEN_DOMCTL_PFINFO_XTAB) )
    2.57              continue;
    2.58  
    2.59          if ( minfo->pfn_type[i] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK )
     3.1 --- a/tools/libxc/xc_private.c	Wed Jan 13 08:12:56 2010 +0000
     3.2 +++ b/tools/libxc/xc_private.c	Wed Jan 13 08:14:01 2010 +0000
     3.3 @@ -149,14 +149,14 @@ void unlock_pages(void *addr, size_t len
     3.4  }
     3.5  
     3.6  /* NB: arr must be locked */
     3.7 -int xc_get_pfn_type_batch(int xc_handle,
     3.8 -                          uint32_t dom, int num, uint32_t *arr)
     3.9 +int xc_get_pfn_type_batch(int xc_handle, uint32_t dom,
    3.10 +                          unsigned int num, xen_pfn_t *arr)
    3.11  {
    3.12      DECLARE_DOMCTL;
    3.13 -    domctl.cmd = XEN_DOMCTL_getpageframeinfo2;
    3.14 +    domctl.cmd = XEN_DOMCTL_getpageframeinfo3;
    3.15      domctl.domain = (domid_t)dom;
    3.16 -    domctl.u.getpageframeinfo2.num    = num;
    3.17 -    set_xen_guest_handle(domctl.u.getpageframeinfo2.array, arr);
    3.18 +    domctl.u.getpageframeinfo3.num = num;
    3.19 +    set_xen_guest_handle(domctl.u.getpageframeinfo3.array, arr);
    3.20      return do_domctl(xc_handle, &domctl);
    3.21  }
    3.22  
     4.1 --- a/tools/libxc/xc_private.h	Wed Jan 13 08:12:56 2010 +0000
     4.2 +++ b/tools/libxc/xc_private.h	Wed Jan 13 08:14:01 2010 +0000
     4.3 @@ -191,6 +191,9 @@ void *xc_map_foreign_ranges(int xc_handl
     4.4                              size_t size, int prot, size_t chunksize,
     4.5                              privcmd_mmap_entry_t entries[], int nentries);
     4.6  
     4.7 +int xc_get_pfn_type_batch(int xc_handle, uint32_t dom,
     4.8 +                          unsigned int num, xen_pfn_t *);
     4.9 +
    4.10  void bitmap_64_to_byte(uint8_t *bp, const uint64_t *lp, int nbits);
    4.11  void bitmap_byte_to_64(uint64_t *lp, const uint8_t *bp, int nbits);
    4.12  
     5.1 --- a/tools/libxc/xenctrl.h	Wed Jan 13 08:12:56 2010 +0000
     5.2 +++ b/tools/libxc/xenctrl.h	Wed Jan 13 08:14:01 2010 +0000
     5.3 @@ -802,9 +802,6 @@ int xc_mmuext_op(int xc_handle, struct m
     5.4  
     5.5  int xc_memory_op(int xc_handle, int cmd, void *arg);
     5.6  
     5.7 -int xc_get_pfn_type_batch(int xc_handle, uint32_t dom,
     5.8 -                          int num, uint32_t *arr);
     5.9 -
    5.10  
    5.11  /* Get current total pages allocated to a domain. */
    5.12  long xc_get_tot_pages(int xc_handle, uint32_t domid);
     6.1 --- a/xen/arch/x86/domctl.c	Wed Jan 13 08:12:56 2010 +0000
     6.2 +++ b/xen/arch/x86/domctl.c	Wed Jan 13 08:14:01 2010 +0000
     6.3 @@ -160,6 +160,106 @@ long arch_do_domctl(
     6.4      }
     6.5      break;
     6.6  
     6.7 +    case XEN_DOMCTL_getpageframeinfo3:
     6.8 +#ifdef __x86_64__
     6.9 +        if (!has_32bit_shinfo(current->domain))
    6.10 +        {
    6.11 +            unsigned int n, j;
    6.12 +            unsigned int num = domctl->u.getpageframeinfo3.num;
    6.13 +            domid_t dom = domctl->domain;
    6.14 +            struct domain *d;
    6.15 +            struct page_info *page;
    6.16 +            xen_pfn_t *arr;
    6.17 +
    6.18 +            ret = -ESRCH;
    6.19 +            if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) )
    6.20 +                break;
    6.21 +
    6.22 +            if ( unlikely(num > 1024) ||
    6.23 +                 unlikely(num != domctl->u.getpageframeinfo3.num) )
    6.24 +            {
    6.25 +                ret = -E2BIG;
    6.26 +                rcu_unlock_domain(d);
    6.27 +                break;
    6.28 +            }
    6.29 +
    6.30 +            page = alloc_domheap_page(NULL, 0);
    6.31 +            if ( !page )
    6.32 +            {
    6.33 +                ret = -ENOMEM;
    6.34 +                rcu_unlock_domain(d);
    6.35 +                break;
    6.36 +            }
    6.37 +            arr = page_to_virt(page);
    6.38 +
    6.39 +            for ( n = ret = 0; n < num; )
    6.40 +            {
    6.41 +                unsigned int k = min_t(unsigned int, num - n, PAGE_SIZE / 4);
    6.42 +
    6.43 +                if ( copy_from_guest_offset(arr,
    6.44 +                                            domctl->u.getpageframeinfo3.array,
    6.45 +                                            n, k) )
    6.46 +                {
    6.47 +                    ret = -EFAULT;
    6.48 +                    break;
    6.49 +                }
    6.50 +
    6.51 +                for ( j = 0; j < k; j++ )
    6.52 +                {
    6.53 +                    unsigned long type = 0, mfn = arr[j];
    6.54 +
    6.55 +                    page = mfn_to_page(mfn);
    6.56 +
    6.57 +                    if ( unlikely(!mfn_valid(mfn)) )
    6.58 +                        type = XEN_DOMCTL_PFINFO_XTAB;
    6.59 +                    else if ( xsm_getpageframeinfo(page) != 0 )
    6.60 +                        ;
    6.61 +                    else if ( likely(get_page(page, d)) )
    6.62 +                    {
    6.63 +                        switch( page->u.inuse.type_info & PGT_type_mask )
    6.64 +                        {
    6.65 +                        case PGT_l1_page_table:
    6.66 +                            type = XEN_DOMCTL_PFINFO_L1TAB;
    6.67 +                            break;
    6.68 +                        case PGT_l2_page_table:
    6.69 +                            type = XEN_DOMCTL_PFINFO_L2TAB;
    6.70 +                            break;
    6.71 +                        case PGT_l3_page_table:
    6.72 +                            type = XEN_DOMCTL_PFINFO_L3TAB;
    6.73 +                            break;
    6.74 +                        case PGT_l4_page_table:
    6.75 +                            type = XEN_DOMCTL_PFINFO_L4TAB;
    6.76 +                            break;
    6.77 +                        }
    6.78 +
    6.79 +                        if ( page->u.inuse.type_info & PGT_pinned )
    6.80 +                            type |= XEN_DOMCTL_PFINFO_LPINTAB;
    6.81 +
    6.82 +                        put_page(page);
    6.83 +                    }
    6.84 +                    else
    6.85 +                        type = XEN_DOMCTL_PFINFO_XTAB;
    6.86 +
    6.87 +                    arr[j] = type;
    6.88 +                }
    6.89 +
    6.90 +                if ( copy_to_guest_offset(domctl->u.getpageframeinfo3.array,
    6.91 +                                          n, arr, k) )
    6.92 +                {
    6.93 +                    ret = -EFAULT;
    6.94 +                    break;
    6.95 +                }
    6.96 +
    6.97 +                n += k;
    6.98 +            }
    6.99 +
   6.100 +            free_domheap_page(virt_to_page(arr));
   6.101 +
   6.102 +            rcu_unlock_domain(d);
   6.103 +            break;
   6.104 +        }
   6.105 +#endif
   6.106 +        /* fall thru */
   6.107      case XEN_DOMCTL_getpageframeinfo2:
   6.108      {
   6.109          int n,j;
   6.110 @@ -183,7 +283,7 @@ long arch_do_domctl(
   6.111          if ( !arr32 )
   6.112          {
   6.113              ret = -ENOMEM;
   6.114 -            put_domain(d);
   6.115 +            rcu_unlock_domain(d);
   6.116              break;
   6.117          }
   6.118   
   6.119 @@ -209,11 +309,14 @@ long arch_do_domctl(
   6.120  
   6.121                  page = mfn_to_page(mfn);
   6.122  
   6.123 -                ret = xsm_getpageframeinfo(page);
   6.124 -                if ( ret )
   6.125 +                if ( domctl->cmd == XEN_DOMCTL_getpageframeinfo3)
   6.126 +                    arr32[j] = 0;
   6.127 +
   6.128 +                if ( unlikely(!mfn_valid(mfn)) )
   6.129 +                    arr32[j] |= XEN_DOMCTL_PFINFO_XTAB;
   6.130 +                else if ( xsm_getpageframeinfo(page) != 0 )
   6.131                      continue;
   6.132 -
   6.133 -                if ( likely(mfn_valid(mfn) && get_page(page, d)) ) 
   6.134 +                else if ( likely(get_page(page, d)) )
   6.135                  {
   6.136                      unsigned long type = 0;
   6.137  
     7.1 --- a/xen/include/public/domctl.h	Wed Jan 13 08:12:56 2010 +0000
     7.2 +++ b/xen/include/public/domctl.h	Wed Jan 13 08:14:01 2010 +0000
     7.3 @@ -161,6 +161,14 @@ struct xen_domctl_getpageframeinfo2 {
     7.4  typedef struct xen_domctl_getpageframeinfo2 xen_domctl_getpageframeinfo2_t;
     7.5  DEFINE_XEN_GUEST_HANDLE(xen_domctl_getpageframeinfo2_t);
     7.6  
     7.7 +/* XEN_DOMCTL_getpageframeinfo3 */
     7.8 +struct xen_domctl_getpageframeinfo3 {
     7.9 +    /* IN variables. */
    7.10 +    uint64_aligned_t num;
    7.11 +    /* IN/OUT variables. */
    7.12 +    XEN_GUEST_HANDLE_64(xen_pfn_t) array;
    7.13 +};
    7.14 +
    7.15  
    7.16  /*
    7.17   * Control shadow pagetables operation
    7.18 @@ -832,6 +840,7 @@ struct xen_domctl {
    7.19  #define XEN_DOMCTL_disable_migrate               58
    7.20  #define XEN_DOMCTL_gettscinfo                    59
    7.21  #define XEN_DOMCTL_settscinfo                    60
    7.22 +#define XEN_DOMCTL_getpageframeinfo3             61
    7.23  #define XEN_DOMCTL_gdbsx_guestmemio            1000
    7.24  #define XEN_DOMCTL_gdbsx_pausevcpu             1001
    7.25  #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
    7.26 @@ -844,6 +853,7 @@ struct xen_domctl {
    7.27          struct xen_domctl_getmemlist        getmemlist;
    7.28          struct xen_domctl_getpageframeinfo  getpageframeinfo;
    7.29          struct xen_domctl_getpageframeinfo2 getpageframeinfo2;
    7.30 +        struct xen_domctl_getpageframeinfo3 getpageframeinfo3;
    7.31          struct xen_domctl_vcpuaffinity      vcpuaffinity;
    7.32          struct xen_domctl_shadow_op         shadow_op;
    7.33          struct xen_domctl_max_mem           max_mem;