[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Introduce a grant_entry_v2 structure.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1254897996 -3600
# Node ID 95ea2052b41b209fa913d6861143915140be4171
# Parent  7d4f05a65d5a840eca5fdf1319c696d5583f100d
Introduce a grant_entry_v2 structure.

Signed-off-by: Steven Smith <steven.smith@xxxxxxxxxx>
---
 tools/libxc/xc_linux.c            |   32 +
 tools/libxc/xc_offline_page.c     |   51 ++
 tools/libxc/xenctrl.h             |    4 
 xen/arch/x86/hvm/hvm.c            |   33 +
 xen/arch/x86/mm.c                 |   25 +
 xen/common/compat/grant_table.c   |   81 ++++
 xen/common/grant_table.c          |  713 ++++++++++++++++++++++++++++++--------
 xen/include/Makefile              |    2 
 xen/include/asm-x86/grant_table.h |   19 -
 xen/include/public/grant_table.h  |  111 +++++
 xen/include/public/memory.h       |    2 
 xen/include/public/xen.h          |    1 
 xen/include/xen/grant_table.h     |   28 +
 xen/include/xlat.lst              |    5 
 14 files changed, 921 insertions(+), 186 deletions(-)

diff -r 7d4f05a65d5a -r 95ea2052b41b tools/libxc/xc_linux.c
--- a/tools/libxc/xc_linux.c    Wed Oct 07 07:46:14 2009 +0100
+++ b/tools/libxc/xc_linux.c    Wed Oct 07 07:46:36 2009 +0100
@@ -558,7 +558,21 @@ int xc_gnttab_op(int xc_handle, int cmd,
     return ret;
 }
 
-struct grant_entry_v1 *xc_gnttab_map_table(int xc_handle, int domid, int 
*gnt_num)
+int xc_gnttab_get_version(int xc_handle, int domid)
+{
+    struct gnttab_get_version query;
+    int rc;
+
+    query.dom = domid;
+    rc = xc_gnttab_op(xc_handle, GNTTABOP_get_version,
+                      &query, sizeof(query), 1);
+    if (rc < 0)
+        return rc;
+    else
+        return query.version;
+}
+
+static void *_gnttab_map_table(int xc_handle, int domid, int *gnt_num)
 {
     int rc, i;
     struct gnttab_query_size query;
@@ -636,6 +650,22 @@ err:
         free(pfn_list);
 
     return gnt;
+}
+
+struct grant_entry_v1 *xc_gnttab_map_table_v1(int xc_handle, int domid,
+                                              int *gnt_num)
+{
+    if (xc_gnttab_get_version(xc_handle, domid) == 2)
+        return NULL;
+    return _gnttab_map_table(xc_handle, domid, gnt_num);
+}
+
+struct grant_entry_v2 *xc_gnttab_map_table_v2(int xc_handle, int domid,
+                                              int *gnt_num)
+{
+    if (xc_gnttab_get_version(xc_handle, domid) != 2)
+        return NULL;
+    return _gnttab_map_table(xc_handle, domid, gnt_num);
 }
 
 /*
diff -r 7d4f05a65d5a -r 95ea2052b41b tools/libxc/xc_offline_page.c
--- a/tools/libxc/xc_offline_page.c     Wed Oct 07 07:46:14 2009 +0100
+++ b/tools/libxc/xc_offline_page.c     Wed Oct 07 07:46:36 2009 +0100
@@ -132,8 +132,8 @@ int xc_query_page_offline_status(int xc,
  /*
   * There should no update to the grant when domain paused
   */
-static int xc_is_page_granted(int xc_handle, xen_pfn_t gpfn,
-                              struct grant_entry_v1 *gnttab, int gnt_num)
+static int xc_is_page_granted_v1(int xc_handle, xen_pfn_t gpfn,
+                                 struct grant_entry_v1 *gnttab, int gnt_num)
 {
     int i = 0;
 
@@ -142,6 +142,22 @@ static int xc_is_page_granted(int xc_han
 
     for (i = 0; i < gnt_num; i++)
         if ( ((gnttab[i].flags & GTF_type_mask) !=  GTF_invalid) &&
+             (gnttab[i].frame == gpfn) )
+             break;
+
+   return (i != gnt_num);
+}
+
+static int xc_is_page_granted_v2(int xc_handle, xen_pfn_t gpfn,
+                                 struct grant_entry_v2 *gnttab, int gnt_num)
+{
+    int i = 0;
+
+    if (!gnttab)
+        return 0;
+
+    for (i = 0; i < gnt_num; i++)
+        if ( ((gnttab[i].hdr.flags & GTF_type_mask) !=  GTF_invalid) &&
              (gnttab[i].frame == gpfn) )
              break;
 
@@ -549,7 +565,8 @@ int xc_exchange_page(int xc_handle, int 
     struct domain_mem_info minfo;
     struct xc_mmu *mmu = NULL;
     struct pte_backup old_ptes = {NULL, 0, 0};
-    struct grant_entry_v1 *gnttab = NULL;
+    struct grant_entry_v1 *gnttab_v1 = NULL;
+    struct grant_entry_v2 *gnttab_v2 = NULL;
     struct mmuext_op mops;
     int gnt_num, unpined = 0;
     void *old_p, *backup = NULL;
@@ -588,14 +605,20 @@ int xc_exchange_page(int xc_handle, int 
             goto failed;
     }
 
-    gnttab = xc_gnttab_map_table(xc_handle, domid, &gnt_num);
-    if (!gnttab)
-    {
-        ERROR("Failed to map grant table\n");
-        goto failed;
-    }
-
-    if (xc_is_page_granted(xc_handle, mfn, gnttab, gnt_num))
+    gnttab_v2 = xc_gnttab_map_table_v2(xc_handle, domid, &gnt_num);
+    if (!gnttab_v2)
+    {
+        gnttab_v1 = xc_gnttab_map_table_v1(xc_handle, domid, &gnt_num);
+        if (!gnttab_v1)
+        {
+            ERROR("Failed to map grant table\n");
+            goto failed;
+        }
+    }
+
+    if (gnttab_v1
+        ? xc_is_page_granted_v1(xc_handle, mfn, gnttab_v1, gnt_num)
+        : xc_is_page_granted_v2(xc_handle, mfn, gnttab_v2, gnt_num))
     {
         ERROR("Page %lx is granted now\n", mfn);
         goto failed;
@@ -755,8 +778,10 @@ failed:
     if (backup)
         free(backup);
 
-    if (gnttab)
-        munmap(gnttab, gnt_num / (PAGE_SIZE/sizeof(struct grant_entry_v1)));
+    if (gnttab_v1)
+        munmap(gnttab_v1, gnt_num / (PAGE_SIZE/sizeof(struct grant_entry_v1)));
+    if (gnttab_v2)
+        munmap(gnttab_v2, gnt_num / (PAGE_SIZE/sizeof(struct grant_entry_v2)));
 
     close_mem_info(xc_handle, &minfo);
 
diff -r 7d4f05a65d5a -r 95ea2052b41b tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Wed Oct 07 07:46:14 2009 +0100
+++ b/tools/libxc/xenctrl.h     Wed Oct 07 07:46:36 2009 +0100
@@ -943,7 +943,9 @@ int xc_gnttab_op(int xc_handle, int cmd,
 int xc_gnttab_op(int xc_handle, int cmd,
                  void * op, int op_size, int count);
 
-struct grant_entry_v1 *xc_gnttab_map_table(int xc_handle, int domid, int 
*gnt_num);
+int xc_gnttab_get_version(int xc_handle, int domid);
+struct grant_entry_v1 *xc_gnttab_map_table_v1(int xc_handle, int domid, int 
*gnt_num);
+struct grant_entry_v2 *xc_gnttab_map_table_v2(int xc_handle, int domid, int 
*gnt_num);
 
 int xc_physdev_map_pirq(int xc_handle,
                         int domid,
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Wed Oct 07 07:46:36 2009 +0100
@@ -2087,12 +2087,26 @@ enum hvm_intblk hvm_interrupt_blocked(st
     return hvm_intblk_none;
 }
 
+static int grant_table_op_is_allowed(unsigned int cmd)
+{
+    switch (cmd) {
+    case GNTTABOP_query_size:
+    case GNTTABOP_setup_table:
+    case GNTTABOP_set_version:
+    case GNTTABOP_copy:
+    case GNTTABOP_map_grant_ref:
+    case GNTTABOP_unmap_grant_ref:
+        return 1;
+    default:
+        /* all other commands need auditing */
+        return 0;
+    }
+}
+
 static long hvm_grant_table_op(
     unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
 {
-    if ( (cmd != GNTTABOP_query_size) && (cmd != GNTTABOP_setup_table) &&
-         (cmd != GNTTABOP_map_grant_ref) && (cmd != GNTTABOP_unmap_grant_ref) 
&&
-         (cmd != GNTTABOP_copy))
+    if ( !grant_table_op_is_allowed(cmd) )
         return -ENOSYS; /* all other commands need auditing */
     return do_grant_table_op(cmd, uop, count);
 }
@@ -2144,13 +2158,12 @@ static hvm_hypercall_t *hvm_hypercall32_
 
 #else /* defined(__x86_64__) */
 
-static long hvm_grant_table_op_compat32(
-    unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
-{
-    if ( (cmd != GNTTABOP_query_size) && (cmd != GNTTABOP_setup_table) &&
-         (cmd != GNTTABOP_map_grant_ref) && (cmd != GNTTABOP_unmap_grant_ref) 
&&
-         (cmd != GNTTABOP_copy))
-        return -ENOSYS; /* all other commands need auditing */
+static long hvm_grant_table_op_compat32(unsigned int cmd,
+                                        XEN_GUEST_HANDLE(void) uop,
+                                        unsigned int count)
+{
+    if ( !grant_table_op_is_allowed(cmd) )
+        return -ENOSYS;
     return compat_grant_table_op(cmd, uop, count);
 }
 
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/arch/x86/mm.c Wed Oct 07 07:46:36 2009 +0100
@@ -4000,12 +4000,25 @@ long arch_memory_op(int op, XEN_GUEST_HA
         case XENMAPSPACE_grant_table:
             spin_lock(&d->grant_table->lock);
 
-            if ( (xatp.idx >= nr_grant_frames(d->grant_table)) &&
-                 (xatp.idx < max_nr_grant_frames) )
-                gnttab_grow_table(d, xatp.idx + 1);
-
-            if ( xatp.idx < nr_grant_frames(d->grant_table) )
-                mfn = virt_to_mfn(d->grant_table->shared[xatp.idx]);
+            if ( d->grant_table->gt_version == 0 )
+                d->grant_table->gt_version = 1;
+
+            if ( d->grant_table->gt_version == 2 &&
+                 (xatp.idx & XENMAPIDX_grant_table_status) )
+            {
+                xatp.idx &= ~XENMAPIDX_grant_table_status;
+                if ( xatp.idx < nr_status_frames(d->grant_table) )
+                    mfn = virt_to_mfn(d->grant_table->status[xatp.idx]);
+            }
+            else
+            {
+                if ( (xatp.idx >= nr_grant_frames(d->grant_table)) &&
+                     (xatp.idx < max_nr_grant_frames) )
+                    gnttab_grow_table(d, xatp.idx + 1);
+
+                if ( xatp.idx < nr_grant_frames(d->grant_table) )
+                    mfn = virt_to_mfn(d->grant_table->shared_raw[xatp.idx]);
+            }
 
             spin_unlock(&d->grant_table->lock);
             break;
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/common/compat/grant_table.c
--- a/xen/common/compat/grant_table.c   Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/common/compat/grant_table.c   Wed Oct 07 07:46:36 2009 +0100
@@ -9,6 +9,14 @@ CHECK_grant_entry_v1;
 CHECK_grant_entry_v1;
 #undef xen_grant_entry_v1
 
+#define xen_grant_entry_header grant_entry_header
+CHECK_grant_entry_header;
+#undef xen_grant_entry_header
+
+#define xen_grant_entry_v2 grant_entry_v2
+CHECK_grant_entry_v2;
+#undef xen_grant_entry_v2
+
 #define xen_gnttab_map_grant_ref gnttab_map_grant_ref
 CHECK_gnttab_map_grant_ref;
 #undef xen_gnttab_map_grant_ref
@@ -28,6 +36,16 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_copy_comp
 #define xen_gnttab_dump_table gnttab_dump_table
 CHECK_gnttab_dump_table;
 #undef xen_gnttab_dump_table
+
+#define xen_gnttab_set_version gnttab_set_version
+CHECK_gnttab_set_version;
+#undef xen_gnttab_set_version
+
+DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_compat_t);
+
+#define xen_gnttab_get_version gnttab_get_version
+CHECK_gnttab_get_version;
+#undef xen_gnttab_get_version
 
 int compat_grant_table_op(unsigned int cmd,
                           XEN_GUEST_HANDLE(void) cmp_uop,
@@ -76,6 +94,10 @@ int compat_grant_table_op(unsigned int c
     CASE(dump_table);
 #endif
 
+#ifndef CHECK_gnttab_get_status_frames
+    CASE(get_status_frames);
+#endif
+
 #undef CASE
     default:
         return do_grant_table_op(cmd, cmp_uop, count);
@@ -92,11 +114,13 @@ int compat_grant_table_op(unsigned int c
             struct gnttab_setup_table *setup;
             struct gnttab_transfer *xfer;
             struct gnttab_copy *copy;
+            struct gnttab_get_status_frames *get_status;
         } nat;
         union {
             struct compat_gnttab_setup_table setup;
             struct compat_gnttab_transfer xfer;
             struct compat_gnttab_copy copy;
+            struct compat_gnttab_get_status_frames get_status;
         } cmp;
 
         set_xen_guest_handle(nat.uop, COMPAT_ARG_XLAT_VIRT_BASE);
@@ -233,6 +257,63 @@ int compat_grant_table_op(unsigned int c
             }
             break;
 
+        case GNTTABOP_get_status_frames: {
+            unsigned int max_frame_list_size_in_pages =
+                (COMPAT_ARG_XLAT_SIZE - sizeof(*nat.get_status)) /
+                sizeof(*nat.get_status->frame_list.p);
+            if ( count != 1)
+            {
+                rc = -EINVAL;
+                break;
+            }
+            if ( unlikely(__copy_from_guest(&cmp.get_status, cmp_uop, 1) ||
+                          !compat_handle_okay(cmp.get_status.frame_list,
+                                              cmp.get_status.nr_frames)) )
+            {
+                rc = -EFAULT;
+                break;
+            }
+            if ( max_frame_list_size_in_pages <
+                 grant_to_status_frames(max_nr_grant_frames) )
+            {
+                gdprintk(XENLOG_WARNING,
+                         "grant_to_status_frames(max_nr_grant_frames) is too 
large (%u,%u)\n",
+                         grant_to_status_frames(max_nr_grant_frames),
+                         max_frame_list_size_in_pages);
+                rc = -EINVAL;
+                break;
+            }
+
+#define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \
+            set_xen_guest_handle((_d_)->frame_list, (uint64_t 
*)(nat.get_status + 1))
+            XLAT_gnttab_get_status_frames(nat.get_status, &cmp.get_status);
+#undef XLAT_gnttab_get_status_frames_HNDL_frame_list
+
+            rc = gnttab_get_status_frames(
+                guest_handle_cast(nat.uop, gnttab_get_status_frames_t),
+                count);
+            if ( rc >= 0 )
+            {
+#define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \
+                do \
+                { \
+                    if ( (_s_)->status == GNTST_okay ) \
+                    { \
+                        for ( i = 0; i < (_s_)->nr_frames; ++i ) \
+                        { \
+                            uint64_t frame = (_s_)->frame_list.p[i]; \
+                            (void)__copy_to_compat_offset((_d_)->frame_list, 
i, &frame, 1); \
+                        } \
+                    } \
+                } while (0)
+                XLAT_gnttab_get_status_frames(&cmp.get_status, nat.get_status);
+#undef XLAT_gnttab_get_status_frames_HNDL_frame_list
+                if ( unlikely(__copy_to_guest(cmp_uop, &cmp.get_status, 1)) )
+                    rc = -EFAULT;
+            }
+            break;
+        }
+
         default:
             domain_crash(current->domain);
             break;
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/common/grant_table.c
--- a/xen/common/grant_table.c  Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/common/grant_table.c  Wed Oct 07 07:46:36 2009 +0100
@@ -105,9 +105,24 @@ static unsigned inline int max_nr_maptra
 }
 
 
-#define SHGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v1_t))
-#define shared_entry(t, e) \
-    ((t)->shared[(e)/SHGNT_PER_PAGE][(e)%SHGNT_PER_PAGE])
+#define SHGNT_PER_PAGE_V1 (PAGE_SIZE / sizeof(grant_entry_v1_t))
+#define shared_entry_v1(t, e) \
+    ((t)->shared_v1[(e)/SHGNT_PER_PAGE_V1][(e)%SHGNT_PER_PAGE_V1])
+#define SHGNT_PER_PAGE_V2 (PAGE_SIZE / sizeof(grant_entry_v2_t))
+#define shared_entry_v2(t, e) \
+    ((t)->shared_v2[(e)/SHGNT_PER_PAGE_V2][(e)%SHGNT_PER_PAGE_V2])
+#define STGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t))
+#define status_entry(t, e) \
+    ((t)->status[(e)/STGNT_PER_PAGE][(e)%STGNT_PER_PAGE])
+static grant_entry_header_t *
+shared_entry_header(struct grant_table *t, grant_ref_t ref)
+{
+    ASSERT(t->gt_version != 0);
+    if (t->gt_version == 1)
+        return (grant_entry_header_t*)&shared_entry_v1(t, ref);
+    else
+        return &shared_entry_v2(t, ref).hdr;
+}
 #define ACGNT_PER_PAGE (PAGE_SIZE / sizeof(struct active_grant_entry))
 #define active_entry(t, e) \
     ((t)->active[(e)/ACGNT_PER_PAGE][(e)%ACGNT_PER_PAGE])
@@ -181,6 +196,174 @@ get_maptrack_handle(
         spin_unlock(&lgt->lock);
     }
     return handle;
+}
+
+/* Number of grant table entries. Caller must hold d's grant table lock. */
+static unsigned int nr_grant_entries(struct grant_table *gt)
+{
+    ASSERT(gt->gt_version != 0);
+    if (gt->gt_version == 1)
+        return (nr_grant_frames(gt) << PAGE_SHIFT) / sizeof(grant_entry_v1_t);
+    else
+        return (nr_grant_frames(gt) << PAGE_SHIFT) / sizeof(grant_entry_v2_t);
+}
+
+static int _set_status_v1(domid_t  domid,
+                          int readonly,
+                          grant_entry_header_t *shah, 
+                          struct active_grant_entry *act)
+{
+    int rc = GNTST_okay;
+    union grant_combo scombo, prev_scombo, new_scombo;
+    uint16_t mask = GTF_type_mask;
+
+    /*
+     * We bound the number of times we retry CMPXCHG on memory locations that
+     * we share with a guest OS. The reason is that the guest can modify that
+     * location at a higher rate than we can read-modify-CMPXCHG, so the guest
+     * could cause us to livelock. There are a few cases where it is valid for
+     * the guest to race our updates (e.g., to change the GTF_readonly flag),
+     * so we allow a few retries before failing.
+     */
+    int retries = 0;
+
+    scombo.word = *(u32 *)shah;
+
+    /*
+     * This loop attempts to set the access (reading/writing) flags
+     * in the grant table entry.  It tries a cmpxchg on the field
+     * up to five times, and then fails under the assumption that 
+     * the guest is misbehaving.
+     */
+    for ( ; ; )
+    {
+        /* If not already pinned, check the grant domid and type. */
+        if ( !act->pin &&
+             (((scombo.shorts.flags & mask) !=
+               GTF_permit_access) ||
+              (scombo.shorts.domid != domid)) )
+            PIN_FAIL(done, GNTST_general_error,
+                     "Bad flags (%x) or dom (%d). (expected dom %d)\n",
+                     scombo.shorts.flags, scombo.shorts.domid,
+                     domid);
+
+        new_scombo = scombo;
+        new_scombo.shorts.flags |= GTF_reading;
+
+        if ( !readonly )
+        {
+            new_scombo.shorts.flags |= GTF_writing;
+            if ( unlikely(scombo.shorts.flags & GTF_readonly) )
+                PIN_FAIL(done, GNTST_general_error,
+                         "Attempt to write-pin a r/o grant entry.\n");
+        }
+
+        prev_scombo.word = cmpxchg((u32 *)shah,
+                                   scombo.word, new_scombo.word);
+        if ( likely(prev_scombo.word == scombo.word) )
+            break;
+
+        if ( retries++ == 4 )
+            PIN_FAIL(done, GNTST_general_error,
+                     "Shared grant entry is unstable.\n");
+
+        scombo = prev_scombo;
+    }
+
+done:
+    return rc;
+}
+
+static int _set_status_v2(domid_t  domid,
+                          int readonly,
+                          grant_entry_header_t *shah, 
+                          struct active_grant_entry *act,
+                          grant_status_t *status)
+{
+    int      rc    = GNTST_okay;
+    union grant_combo scombo;
+    uint16_t flags = shah->flags;
+    domid_t  id    = shah->domid;
+    uint16_t mask  = GTF_type_mask;
+
+    /* we read flags and domid in a single memory access.
+       this avoids the need for another memory barrier to
+       ensure access to these fields are not reordered */
+    scombo.word = *(u32 *)shah;
+    barrier(); /* but we still need to stop the compiler from turning
+                  it back into two reads */
+    flags = scombo.shorts.flags;
+    id = scombo.shorts.domid;
+
+    /* If not already pinned, check the grant domid and type. */
+    if ( !act->pin &&
+         (((flags & mask) != GTF_permit_access) ||
+          (id != domid)) )
+        PIN_FAIL(done, GNTST_general_error,
+                 "Bad flags (%x) or dom (%d). (expected dom %d)\n",
+                 flags, id, domid);
+
+    if ( readonly )
+    {
+        *status |= GTF_reading;
+    }
+    else
+    {
+        if ( unlikely(flags & GTF_readonly) )
+            PIN_FAIL(done, GNTST_general_error,
+                     "Attempt to write-pin a r/o grant entry.\n");
+        *status |= GTF_reading | GTF_writing;
+    }
+
+    /* Make sure guest sees status update before checking if flags are
+       still valid */
+    mb();
+
+    scombo.word = *(u32 *)shah;
+    barrier();
+    flags = scombo.shorts.flags;
+    id = scombo.shorts.domid;
+
+    if ( !act->pin )
+    {
+        if ( ((flags & mask) != GTF_permit_access) ||
+             (id != domid) ||
+             (!readonly && (flags & GTF_readonly)) )
+        {
+            gnttab_clear_flag(_GTF_reading | _GTF_writing, status);
+            PIN_FAIL(done, GNTST_general_error,
+                     "Unstable flags (%x) or dom (%d). (expected dom %d) "
+                     "(r/w: %d)\n",
+                     flags, id, domid, !readonly);
+        }
+    }
+    else
+    {
+        if ( unlikely(flags & GTF_readonly) )
+        {
+            gnttab_clear_flag(_GTF_writing, status);
+            PIN_FAIL(done, GNTST_general_error,
+                     "Unstable grant readonly flag\n");
+        }
+    }
+
+done:
+    return rc;
+}
+
+
+static int _set_status(unsigned gt_version,
+                       domid_t  domid,
+                       int readonly,
+                       grant_entry_header_t *shah,
+                       struct active_grant_entry *act,
+                       grant_status_t *status)
+{
+
+    if (gt_version == 1)
+        return _set_status_v1(domid, readonly, shah, act);
+    else
+        return _set_status_v2(domid, readonly, shah, act, status);
 }
 
 /*
@@ -205,18 +388,10 @@ __gnttab_map_grant_ref(
     unsigned int   cache_flags;
     struct active_grant_entry *act;
     struct grant_mapping *mt;
-    grant_entry_v1_t *sha;
-    union grant_combo scombo, prev_scombo, new_scombo;
-
-    /*
-     * We bound the number of times we retry CMPXCHG on memory locations that
-     * we share with a guest OS. The reason is that the guest can modify that
-     * location at a higher rate than we can read-modify-CMPXCHG, so the guest
-     * could cause us to livelock. There are a few cases where it is valid for
-     * the guest to race our updates (e.g., to change the GTF_readonly flag),
-     * so we allow a few retries before failing.
-     */
-    int retries = 0;
+    grant_entry_v1_t *sha1;
+    grant_entry_v2_t *sha2;
+    grant_entry_header_t *shah;
+    uint16_t *status;
 
     led = current;
     ld = led->domain;
@@ -262,12 +437,25 @@ __gnttab_map_grant_ref(
 
     spin_lock(&rd->grant_table->lock);
 
+    if ( rd->grant_table->gt_version == 0 )
+        PIN_FAIL(unlock_out, GNTST_general_error,
+                 "remote grant table not yet set up");
+
     /* Bounds check on the grant ref */
     if ( unlikely(op->ref >= nr_grant_entries(rd->grant_table)))
         PIN_FAIL(unlock_out, GNTST_bad_gntref, "Bad ref (%d).\n", op->ref);
 
     act = &active_entry(rd->grant_table, op->ref);
-    sha = &shared_entry(rd->grant_table, op->ref);
+    shah = shared_entry_header(rd->grant_table, op->ref);
+    if (rd->grant_table->gt_version == 1) {
+        sha1 = &shared_entry_v1(rd->grant_table, op->ref);
+        sha2 = NULL;
+        status = &shah->flags;
+    } else {
+        sha2 = &shared_entry_v2(rd->grant_table, op->ref);
+        sha1 = NULL;
+        status = &status_entry(rd->grant_table, op->ref);
+    }
 
     /* If already pinned, check the active domid and avoid refcnt overflow. */
     if ( act->pin &&
@@ -281,54 +469,19 @@ __gnttab_map_grant_ref(
          (!(op->flags & GNTMAP_readonly) &&
           !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
     {
-        scombo.word = *(u32 *)&sha->flags;
-
-        /*
-         * This loop attempts to set the access (reading/writing) flags
-         * in the grant table entry.  It tries a cmpxchg on the field
-         * up to five times, and then fails under the assumption that 
-         * the guest is misbehaving.
-         */
-        for ( ; ; )
-        {
-            /* If not already pinned, check the grant domid and type. */
-            if ( !act->pin &&
-                 (((scombo.shorts.flags & GTF_type_mask) !=
-                   GTF_permit_access) ||
-                  (scombo.shorts.domid != ld->domain_id)) )
-                 PIN_FAIL(unlock_out, GNTST_general_error,
-                          "Bad flags (%x) or dom (%d). (expected dom %d)\n",
-                          scombo.shorts.flags, scombo.shorts.domid,
-                          ld->domain_id);
-
-            new_scombo = scombo;
-            new_scombo.shorts.flags |= GTF_reading;
-
-            if ( !(op->flags & GNTMAP_readonly) )
-            {
-                new_scombo.shorts.flags |= GTF_writing;
-                if ( unlikely(scombo.shorts.flags & GTF_readonly) )
-                    PIN_FAIL(unlock_out, GNTST_general_error,
-                             "Attempt to write-pin a r/o grant entry.\n");
-            }
-
-            prev_scombo.word = cmpxchg((u32 *)&sha->flags,
-                                       scombo.word, new_scombo.word);
-            if ( likely(prev_scombo.word == scombo.word) )
-                break;
-
-            if ( retries++ == 4 )
-                PIN_FAIL(unlock_out, GNTST_general_error,
-                         "Shared grant entry is unstable.\n");
-
-            scombo = prev_scombo;
-        }
+        if ( (rc = _set_status(rd->grant_table->gt_version,
+                               ld->domain_id, op->flags & GNTMAP_readonly,
+                               shah, act, status) ) != GNTST_okay )
+             goto unlock_out;
 
         if ( !act->pin )
         {
-            act->domid = scombo.shorts.domid;
-            act->gfn = sha->frame;
-            act->frame = gmfn_to_mfn(rd, sha->frame);
+            act->domid = ld->domain_id;
+            if ( sha1 )
+                act->gfn = sha1->frame;
+            else
+                act->gfn = sha2->full_page.frame;
+            act->frame = gmfn_to_mfn(rd, act->gfn);
         }
     }
 
@@ -343,7 +496,7 @@ __gnttab_map_grant_ref(
     frame = act->frame;
     act_pin = act->pin;
 
-    cache_flags = (sha->flags & (GTF_PAT | GTF_PWT | GTF_PCD) );
+    cache_flags = (shah->flags & (GTF_PAT | GTF_PWT | GTF_PCD) );
 
     spin_unlock(&rd->grant_table->lock);
 
@@ -457,7 +610,7 @@ __gnttab_map_grant_ref(
     spin_lock(&rd->grant_table->lock);
 
     act = &active_entry(rd->grant_table, op->ref);
-    sha = &shared_entry(rd->grant_table, op->ref);
+    shah = shared_entry_header(rd->grant_table, op->ref);
 
     if ( op->flags & GNTMAP_device_map )
         act->pin -= (op->flags & GNTMAP_readonly) ?
@@ -468,10 +621,10 @@ __gnttab_map_grant_ref(
 
     if ( !(op->flags & GNTMAP_readonly) &&
          !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
-        gnttab_clear_flag(_GTF_writing, &sha->flags);
+        gnttab_clear_flag(_GTF_writing, status);
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, &sha->flags);
+        gnttab_clear_flag(_GTF_reading, status);
 
  unlock_out:
     spin_unlock(&rd->grant_table->lock);
@@ -508,7 +661,6 @@ __gnttab_unmap_common(
     domid_t          dom;
     struct domain   *ld, *rd;
     struct active_grant_entry *act;
-    grant_entry_v1_t *sha;
     s16              rc = 0;
     u32              old_pin;
 
@@ -556,7 +708,6 @@ __gnttab_unmap_common(
     spin_lock(&rd->grant_table->lock);
 
     act = &active_entry(rd->grant_table, op->map->ref);
-    sha = &shared_entry(rd->grant_table, op->map->ref);
     old_pin = act->pin;
 
     if ( op->frame == 0 )
@@ -622,8 +773,9 @@ __gnttab_unmap_common_complete(struct gn
 {
     struct domain   *ld, *rd;
     struct active_grant_entry *act;
-    grant_entry_v1_t *sha;
+    grant_entry_header_t *sha;
     struct page_info *pg;
+    uint16_t *status;
 
     rd = op->rd;
 
@@ -642,8 +794,16 @@ __gnttab_unmap_common_complete(struct gn
     rcu_lock_domain(rd);
     spin_lock(&rd->grant_table->lock);
 
+    if ( rd->grant_table->gt_version == 0 )
+        goto unmap_out;
+
     act = &active_entry(rd->grant_table, op->map->ref);
-    sha = &shared_entry(rd->grant_table, op->map->ref);
+    sha = shared_entry_header(rd->grant_table, op->map->ref);
+
+    if ( rd->grant_table->gt_version == 1 )
+        status = &sha->flags;
+    else
+        status = &status_entry(rd->grant_table, op->map->ref);
 
     if ( unlikely(op->frame != act->frame) ) 
     {
@@ -694,10 +854,10 @@ __gnttab_unmap_common_complete(struct gn
 
     if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
          !(op->flags & GNTMAP_readonly) )
-        gnttab_clear_flag(_GTF_writing, &sha->flags);
+        gnttab_clear_flag(_GTF_writing, status);
 
     if ( act->pin == 0 )
-        gnttab_clear_flag(_GTF_reading, &sha->flags);
+        gnttab_clear_flag(_GTF_reading, status);
 
  unmap_out:
     spin_unlock(&rd->grant_table->lock);
@@ -829,6 +989,50 @@ fault:
     return -EFAULT;    
 }
 
+static int
+gnttab_populate_status_frames(struct domain *d, struct grant_table *gt)
+{
+    unsigned i;
+    unsigned req_status_frames;
+
+    req_status_frames = grant_to_status_frames(gt->nr_grant_frames);
+    for ( i = nr_status_frames(gt); i < req_status_frames; i++ )
+    {
+        if ( (gt->status[i] = alloc_xenheap_page()) == NULL )
+            goto status_alloc_failed;
+        clear_page(gt->status[i]);
+    }
+    /* Share the new status frames with the recipient domain */
+    for ( i = nr_status_frames(gt); i < req_status_frames; i++ )
+        gnttab_create_status_page(d, gt, i);
+
+    gt->nr_status_frames = req_status_frames;
+
+    return 0;
+
+status_alloc_failed:
+    for ( i = nr_status_frames(gt); i < req_status_frames; i++ )
+    {
+        free_xenheap_page(gt->status[i]);
+        gt->status[i] = NULL;
+    }
+    return -ENOMEM;
+}
+
+static void
+gnttab_unpopulate_status_frames(struct domain *d, struct grant_table *gt)
+{
+    int i;
+
+    for ( i = 0; i < nr_status_frames(gt); i++ )
+    {
+        page_set_owner(virt_to_page(gt->status[i]), dom_xen);
+        free_xenheap_page(gt->status[i]);
+        gt->status[i] = NULL;
+    }
+    gt->nr_status_frames = 0;
+}
+
 int
 gnttab_grow_table(struct domain *d, unsigned int req_nr_frames)
 {
@@ -855,9 +1059,9 @@ gnttab_grow_table(struct domain *d, unsi
     /* Shared */
     for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
     {
-        if ( (gt->shared[i] = alloc_xenheap_page()) == NULL )
+        if ( (gt->shared_raw[i] = alloc_xenheap_page()) == NULL )
             goto shared_alloc_failed;
-        clear_page(gt->shared[i]);
+        clear_page(gt->shared_raw[i]);
     }
 
     /* Share the new shared frames with the recipient domain */
@@ -866,13 +1070,20 @@ gnttab_grow_table(struct domain *d, unsi
 
     gt->nr_grant_frames = req_nr_frames;
 
+    /* Status pages - version 2 */
+    if (gt->gt_version > 1)
+    {
+        if ( gnttab_populate_status_frames(d, gt) )
+            goto shared_alloc_failed;
+    }
+
     return 1;
 
 shared_alloc_failed:
     for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
     {
-        free_xenheap_page(gt->shared[i]);
-        gt->shared[i] = NULL;
+        free_xenheap_page(gt->shared_raw[i]);
+        gt->shared_raw[i] = NULL;
     }
 active_alloc_failed:
     for ( i = nr_active_grant_frames(gt);
@@ -942,7 +1153,13 @@ gnttab_setup_table(
 
     spin_lock(&d->grant_table->lock);
 
-    if ( (op.nr_frames > nr_grant_frames(d->grant_table)) &&
+    if ( d->grant_table->gt_version == 0 )
+        d->grant_table->gt_version = 1;
+
+    if ( (op.nr_frames > nr_grant_frames(d->grant_table) ||
+          ( (d->grant_table->gt_version > 1 ) &&
+            (grant_to_status_frames(op.nr_frames) >
+             nr_status_frames(d->grant_table))  )  ) &&
          !gnttab_grow_table(d, op.nr_frames) )
     {
         gdprintk(XENLOG_INFO,
@@ -1046,7 +1263,7 @@ gnttab_prepare_for_transfer(
     struct domain *rd, struct domain *ld, grant_ref_t ref)
 {
     struct grant_table *rgt;
-    struct grant_entry_v1 *sha;
+    grant_entry_header_t *sha;
     union grant_combo   scombo, prev_scombo, new_scombo;
     int                 retries = 0;
 
@@ -1057,6 +1274,14 @@ gnttab_prepare_for_transfer(
     }
 
     spin_lock(&rgt->lock);
+
+    if ( rgt->gt_version == 0 )
+    {
+        gdprintk(XENLOG_INFO,
+                 "Grant table not ready for transfer to domain(%d).\n",
+                 rd->domain_id);
+        goto fail;
+    }
 
     if ( unlikely(ref >= nr_grant_entries(rd->grant_table)) )
     {
@@ -1066,7 +1291,7 @@ gnttab_prepare_for_transfer(
         goto fail;
     }
 
-    sha = &shared_entry(rgt, ref);
+    sha = shared_entry_header(rgt, ref);
     
     scombo.word = *(u32 *)&sha->flags;
 
@@ -1115,7 +1340,6 @@ gnttab_transfer(
     struct domain *e;
     struct page_info *page;
     int i;
-    grant_entry_v1_t *sha;
     struct gnttab_transfer gop;
     unsigned long mfn;
     unsigned int max_bitsize;
@@ -1248,11 +1472,21 @@ gnttab_transfer(
         /* Tell the guest about its new page frame. */
         spin_lock(&e->grant_table->lock);
 
-        sha = &shared_entry(e->grant_table, gop.ref);
-        guest_physmap_add_page(e, sha->frame, mfn, 0);
-        sha->frame = mfn;
+        if ( e->grant_table->gt_version == 1 )
+        {
+            grant_entry_v1_t *sha = &shared_entry_v1(e->grant_table, gop.ref);
+            guest_physmap_add_page(e, sha->frame, mfn, 0);
+            sha->frame = mfn;
+        }
+        else
+        {
+            grant_entry_v2_t *sha = &shared_entry_v2(e->grant_table, gop.ref);
+            guest_physmap_add_page(e, sha->full_page.frame, mfn, 0);
+            sha->full_page.frame = mfn;
+        }
         wmb();
-        sha->flags |= GTF_transfer_completed;
+        shared_entry_header(e->grant_table, gop.ref)->flags |=
+            GTF_transfer_completed;
 
         spin_unlock(&e->grant_table->lock);
 
@@ -1278,15 +1512,21 @@ __release_grant_for_copy(
 __release_grant_for_copy(
     struct domain *rd, unsigned long gref, int readonly)
 {
-    grant_entry_v1_t *sha;
+    grant_entry_header_t *sha;
     struct active_grant_entry *act;
     unsigned long r_frame;
+    uint16_t *status;
 
     spin_lock(&rd->grant_table->lock);
 
     act = &active_entry(rd->grant_table, gref);
-    sha = &shared_entry(rd->grant_table, gref);
+    sha = shared_entry_header(rd->grant_table, gref);
     r_frame = act->frame;
+
+    if (rd->grant_table->gt_version == 1)
+        status = &sha->flags;
+    else
+        status = &status_entry(rd->grant_table, gref);
 
     if ( readonly )
     {
@@ -1298,11 +1538,11 @@ __release_grant_for_copy(
 
         act->pin -= GNTPIN_hstw_inc;
         if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
-            gnttab_clear_flag(_GTF_writing, &sha->flags);
+            gnttab_clear_flag(_GTF_writing, status);
     }
 
     if ( !act->pin )
-        gnttab_clear_flag(_GTF_reading, &sha->flags);
+        gnttab_clear_flag(_GTF_reading, status);
 
     spin_unlock(&rd->grant_table->lock);
 }
@@ -1316,21 +1556,38 @@ __acquire_grant_for_copy(
     struct domain *rd, unsigned long gref, int readonly,
     unsigned long *frame)
 {
-    grant_entry_v1_t *sha;
+    grant_entry_v1_t *sha1;
+    grant_entry_v2_t *sha2;
+    grant_entry_header_t *shah;
     struct active_grant_entry *act;
+    grant_status_t *status;
     s16 rc = GNTST_okay;
-    int retries = 0;
-    union grant_combo scombo, prev_scombo, new_scombo;
 
     spin_lock(&rd->grant_table->lock);
+
+    if ( rd->grant_table->gt_version == 0 )
+        PIN_FAIL(unlock_out, GNTST_general_error,
+                 "remote grant table not ready\n");
 
     if ( unlikely(gref >= nr_grant_entries(rd->grant_table)) )
         PIN_FAIL(unlock_out, GNTST_bad_gntref,
                  "Bad grant reference %ld\n", gref);
 
     act = &active_entry(rd->grant_table, gref);
-    sha = &shared_entry(rd->grant_table, gref);
-    
+    shah = shared_entry_header(rd->grant_table, gref);
+    if ( rd->grant_table->gt_version == 1 )
+    {
+        sha1 = &shared_entry_v1(rd->grant_table, gref);
+        sha2 = NULL;
+        status = &shah->flags;
+    }
+    else
+    {
+        sha1 = NULL;
+        sha2 = &shared_entry_v2(rd->grant_table, gref);
+        status = &status_entry(rd->grant_table, gref);
+    }
+
     /* If already pinned, check the active domid and avoid refcnt overflow. */
     if ( act->pin &&
          ((act->domid != current->domain->domain_id) ||
@@ -1342,48 +1599,18 @@ __acquire_grant_for_copy(
     if ( !act->pin ||
          (!readonly && !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
     {
-        scombo.word = *(u32 *)&sha->flags;
-
-        for ( ; ; )
-        {
-            /* If not already pinned, check the grant domid and type. */
-            if ( !act->pin &&
-                 (((scombo.shorts.flags & GTF_type_mask) !=
-                   GTF_permit_access) ||
-                  (scombo.shorts.domid != current->domain->domain_id)) )
-                 PIN_FAIL(unlock_out, GNTST_general_error,
-                          "Bad flags (%x) or dom (%d). (expected dom %d)\n",
-                          scombo.shorts.flags, scombo.shorts.domid,
-                          current->domain->domain_id);
-
-            new_scombo = scombo;
-            new_scombo.shorts.flags |= GTF_reading;
-
-            if ( !readonly )
-            {
-                new_scombo.shorts.flags |= GTF_writing;
-                if ( unlikely(scombo.shorts.flags & GTF_readonly) )
-                    PIN_FAIL(unlock_out, GNTST_general_error,
-                             "Attempt to write-pin a r/o grant entry.\n");
-            }
-
-            prev_scombo.word = cmpxchg((u32 *)&sha->flags,
-                                       scombo.word, new_scombo.word);
-            if ( likely(prev_scombo.word == scombo.word) )
-                break;
-
-            if ( retries++ == 4 )
-                PIN_FAIL(unlock_out, GNTST_general_error,
-                         "Shared grant entry is unstable.\n");
-
-            scombo = prev_scombo;
-        }
-
+        if ( (rc = _set_status(rd->grant_table->gt_version,
+                               current->domain->domain_id, 
+                               readonly, shah, act, status) ) != GNTST_okay )
+             goto unlock_out;
         if ( !act->pin )
         {
-            act->domid = scombo.shorts.domid;
-            act->gfn = sha->frame;
-            act->frame = gmfn_to_mfn(rd, sha->frame);
+            act->domid = current->domain->domain_id;
+            if ( sha1 )
+                act->gfn = sha1->frame;
+            else
+                act->gfn = sha2->full_page.frame;
+            act->frame = gmfn_to_mfn(rd, act->gfn);
         }
     }
 
@@ -1528,6 +1755,165 @@ gnttab_copy(
     return 0;
 }
 
+static long
+gnttab_set_version(XEN_GUEST_HANDLE(gnttab_set_version_t uop))
+{
+    gnttab_set_version_t op;
+    struct domain *d = current->domain;
+    struct grant_table *gt = d->grant_table;
+    struct active_grant_entry *act;
+    long res = 0;
+    int i;
+
+    if (copy_from_guest(&op, uop, 1))
+        return -EFAULT;
+
+    if (op.version != 1 && op.version != 2)
+        return -EINVAL;
+
+    spin_lock(&gt->lock);
+    /* Make sure that the grant table isn't currently in use when we
+       change the version number. */
+    /* (You need to change the version number for e.g. kexec.) */
+    if ( gt->gt_version != 0 )
+    {
+        for ( i = 0; i < nr_grant_entries(gt); i++ )
+        {
+            act = &active_entry(gt, i);
+            if ( act->pin != 0 )
+            {
+                gdprintk(XENLOG_WARNING,
+                         "tried to change grant table version from %d to %d, 
but some grant entries still in use\n",
+                         gt->gt_version,
+                         op.version);
+                res = -EBUSY;
+                goto out;
+            }
+        }
+    }
+
+    /* XXX: If we're going to version 2, we could maybe shrink the
+       active grant table here. */
+
+    if ( op.version == 2 && gt->gt_version < 2 )
+    {
+        res = gnttab_populate_status_frames(d, gt);
+        if ( res < 0)
+            goto out;
+    }
+
+    if ( op.version < 2 && gt->gt_version == 2 )
+        gnttab_unpopulate_status_frames(d, gt);
+
+    if ( op.version != gt->gt_version )
+    {
+        /* Make sure there's no crud left over in the table from the
+           old version. */
+        for ( i = 0; i < nr_grant_frames(gt); i++ )
+            memset(gt->shared_raw[i], 0, PAGE_SIZE);
+    }
+
+    gt->gt_version = op.version;
+
+out:
+    spin_unlock(&gt->lock);
+
+    return res;
+}
+
+static long
+gnttab_get_status_frames(XEN_GUEST_HANDLE(gnttab_get_status_frames_t) uop,
+                         int count)
+{
+    gnttab_get_status_frames_t op;
+    struct domain *d;
+    struct grant_table *gt;
+    uint64_t       gmfn;
+    int i;
+    int rc;
+
+    if ( count != 1 )
+        return -EINVAL;
+
+    if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
+    {
+        gdprintk(XENLOG_INFO,
+                 "Fault while reading gnttab_get_status_frames_t.\n");
+        return -EFAULT;
+    }
+
+    rc = rcu_lock_target_domain_by_id(op.dom, &d);
+    if ( rc < 0 )
+    {
+        if ( rc == -ESRCH )
+            op.status = GNTST_bad_domain;
+        else if ( rc == -EPERM )
+            op.status = GNTST_permission_denied;
+        else
+            op.status = GNTST_general_error;
+        goto out1;
+    }
+
+    gt = d->grant_table;
+
+    if ( unlikely(op.nr_frames > nr_status_frames(gt)) ) {
+        gdprintk(XENLOG_INFO, "Guest requested addresses for %d grant status "
+                 "frames, but only %d are available.\n",
+                 op.nr_frames, nr_status_frames(gt));
+        op.status = GNTST_general_error;
+        goto out2;
+    }
+
+    op.status = GNTST_okay;
+
+    spin_lock(&gt->lock);
+
+    for ( i = 0; i < op.nr_frames; i++ )
+    {
+        gmfn = gnttab_status_gmfn(d, d->grant_table, i);
+        if (copy_to_guest_offset(op.frame_list,
+                                 i,
+                                 &gmfn,
+                                 1))
+            op.status = GNTST_bad_virt_addr;
+    }
+
+    spin_unlock(&gt->lock);
+out2:
+    rcu_unlock_domain(d);
+out1:
+    if ( unlikely(copy_to_guest(uop, &op, 1)) )
+        return -EFAULT;
+
+    return 0;
+}
+
+static long
+gnttab_get_version(XEN_GUEST_HANDLE(gnttab_get_version_t uop))
+{
+    gnttab_get_version_t op;
+    struct domain *d;
+
+    if ( copy_from_guest(&op, uop, 1) )
+        return -EFAULT;
+    d = rcu_lock_domain_by_id(op.dom);
+    if ( d == NULL )
+        return -ESRCH;
+    if ( !IS_PRIV_FOR(current->domain, d) )
+    {
+        rcu_unlock_domain(d);
+        return -EPERM;
+    }
+    spin_lock(&d->grant_table->lock);
+    op.version = d->grant_table->gt_version;
+    spin_unlock(&d->grant_table->lock);
+
+    if ( copy_to_guest(uop, &op, 1) )
+        return -EFAULT;
+    else
+        return 0;
+}
+
 long
 do_grant_table_op(
     unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
@@ -1630,6 +2016,22 @@ do_grant_table_op(
         ASSERT(rc <= 0);
         break;
     }
+    case GNTTABOP_set_version:
+    {
+        rc = gnttab_set_version(guest_handle_cast(uop, gnttab_set_version_t));
+        break;
+    }
+    case GNTTABOP_get_status_frames:
+    {
+        rc = gnttab_get_status_frames(
+            guest_handle_cast(uop, gnttab_get_status_frames_t), count);
+        break;
+    }
+    case GNTTABOP_get_version:
+    {
+        rc = gnttab_get_version(guest_handle_cast(uop, gnttab_get_version_t));
+        break;
+    }
     default:
         rc = -ENOSYS;
         break;
@@ -1665,9 +2067,6 @@ grant_table_create(
 {
     struct grant_table *t;
     int                 i;
-
-    /* If this sizeof assertion fails, fix the function: shared_index */
-    ASSERT(sizeof(grant_entry_v1_t) == 8);
 
     if ( (t = xmalloc(struct grant_table)) == NULL )
         goto no_mem_0;
@@ -1703,19 +2102,27 @@ grant_table_create(
         t->maptrack[0][i].ref = i+1;
 
     /* Shared grant table. */
-    if ( (t->shared = xmalloc_array(struct grant_entry_v1 *,
-                                    max_nr_grant_frames)) == NULL )
+    if ( (t->shared_raw = xmalloc_array(void *, max_nr_grant_frames)) == NULL )
         goto no_mem_3;
-    memset(t->shared, 0, max_nr_grant_frames * sizeof(t->shared[0]));
+    memset(t->shared_raw, 0, max_nr_grant_frames * sizeof(t->shared_raw[0]));
     for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
     {
-        if ( (t->shared[i] = alloc_xenheap_page()) == NULL )
+        if ( (t->shared_raw[i] = alloc_xenheap_page()) == NULL )
             goto no_mem_4;
-        clear_page(t->shared[i]);
+        clear_page(t->shared_raw[i]);
     }
 
     for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
         gnttab_create_shared_page(d, t, i);
+
+    /* Status pages for grant table - for version 2 */
+    t->status = xmalloc_array(grant_status_t *,
+                              grant_to_status_frames(max_nr_grant_frames));
+    if ( t->status == NULL )
+        goto no_mem_4;
+    memset(t->status, 0,
+           grant_to_status_frames(max_nr_grant_frames) * sizeof(t->status[0]));
+    t->nr_status_frames = 0;
 
     /* Okay, install the structure. */
     d->grant_table = t;
@@ -1723,8 +2130,8 @@ grant_table_create(
 
  no_mem_4:
     for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
-        free_xenheap_page(t->shared[i]);
-    xfree(t->shared);
+        free_xenheap_page(t->shared_raw[i]);
+    xfree(t->shared_raw);
  no_mem_3:
     free_xenheap_page(t->maptrack[0]);
     xfree(t->maptrack);
@@ -1749,7 +2156,8 @@ gnttab_release_mappings(
     grant_handle_t        handle;
     struct domain        *rd;
     struct active_grant_entry *act;
-    struct grant_entry_v1*sha;
+    grant_entry_header_t *sha;
+    uint16_t             *status;
     struct page_info     *pg;
 
     BUG_ON(!d->is_dying);
@@ -1777,7 +2185,12 @@ gnttab_release_mappings(
         spin_lock(&rd->grant_table->lock);
 
         act = &active_entry(rd->grant_table, ref);
-        sha = &shared_entry(rd->grant_table, ref);
+        sha = shared_entry_header(rd->grant_table, ref);
+        if (rd->grant_table->gt_version == 1)
+            status = &sha->flags;
+        else
+            status = &status_entry(rd->grant_table, ref);
+
         pg = mfn_to_page(act->frame);
 
         if ( map->flags & GNTMAP_readonly )
@@ -1823,11 +2236,11 @@ gnttab_release_mappings(
             }
 
             if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
-                gnttab_clear_flag(_GTF_writing, &sha->flags);
+                gnttab_clear_flag(_GTF_writing, status);
         }
 
         if ( act->pin == 0 )
-            gnttab_clear_flag(_GTF_reading, &sha->flags);
+            gnttab_clear_flag(_GTF_reading, status);
 
         spin_unlock(&rd->grant_table->lock);
 
@@ -1849,8 +2262,8 @@ grant_table_destroy(
         return;
     
     for ( i = 0; i < nr_grant_frames(t); i++ )
-        free_xenheap_page(t->shared[i]);
-    xfree(t->shared);
+        free_xenheap_page(t->shared_raw[i]);
+    xfree(t->shared_raw);
 
     for ( i = 0; i < nr_maptrack_frames(t); i++ )
         free_xenheap_page(t->maptrack[i]);
@@ -1859,6 +2272,10 @@ grant_table_destroy(
     for ( i = 0; i < nr_active_grant_frames(t); i++ )
         free_xenheap_page(t->active[i]);
     xfree(t->active);
+
+    for ( i = 0; i < nr_status_frames(t); i++ )
+        free_xenheap_page(t->status[i]);
+    xfree(t->status);
 
     xfree(t);
     d->grant_table = NULL;
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/include/Makefile
--- a/xen/include/Makefile      Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/include/Makefile      Wed Oct 07 07:46:36 2009 +0100
@@ -58,7 +58,7 @@ compat/%.h: compat/%.i Makefile $(BASEDI
        mv -f $@.new $@
 
 compat/%.i: compat/%.c Makefile
-       $(CPP) $(filter-out -M% .%.d,$(CFLAGS)) $(cppflags-y) -o $@ $<
+       $(CPP) -include public/xen-compat.h $(filter-out -M% .%.d,$(CFLAGS)) 
$(cppflags-y) -o $@ $<
 
 compat/%.c: public/%.h xlat.lst Makefile 
$(BASEDIR)/tools/compat-build-source.py
        mkdir -p $(@D)
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/include/asm-x86/grant_table.h
--- a/xen/include/asm-x86/grant_table.h Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/include/asm-x86/grant_table.h Wed Oct 07 07:46:36 2009 +0100
@@ -21,15 +21,30 @@ int replace_grant_host_mapping(
 #define gnttab_create_shared_page(d, t, i)                               \
     do {                                                                 \
         share_xen_page_with_guest(                                       \
-            virt_to_page((char *)(t)->shared[i]),                        \
+            virt_to_page((char *)(t)->shared_raw[i]),                    \
             (d), XENSHARE_writable);                                     \
     } while ( 0 )
 
+#define gnttab_create_status_page(d, t, i)                               \
+    do {                                                                 \
+        share_xen_page_with_guest(                                       \
+           virt_to_page((char *)(t)->status[i]),                         \
+            (d), XENSHARE_writable);                                     \
+    } while ( 0 )
+
+
 #define gnttab_shared_mfn(d, t, i)                      \
-    ((virt_to_maddr((t)->shared[i]) >> PAGE_SHIFT))
+    ((virt_to_maddr((t)->shared_raw[i]) >> PAGE_SHIFT))
 
 #define gnttab_shared_gmfn(d, t, i)                     \
     (mfn_to_gmfn(d, gnttab_shared_mfn(d, t, i)))
+
+
+#define gnttab_status_mfn(d, t, i)                      \
+    ((virt_to_maddr((t)->status[i]) >> PAGE_SHIFT))
+
+#define gnttab_status_gmfn(d, t, i)                     \
+    (mfn_to_gmfn(d, gnttab_status_mfn(d, t, i)))
 
 #define gnttab_mark_dirty(d, f) paging_mark_dirty((d), (f))
 
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/include/public/grant_table.h
--- a/xen/include/public/grant_table.h  Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/include/public/grant_table.h  Wed Oct 07 07:46:36 2009 +0100
@@ -89,6 +89,11 @@
  * page frames shared between Xen and a guest.
  * [XEN]: This field is written by Xen and read by the sharing guest.
  * [GST]: This field is written by the guest and read by Xen.
+ */
+
+/*
+ * Version 1 of the grant table entry structure is maintained purely
+ * for backwards compatibility.  New guests should use version 2.
  */
 #if __XEN_INTERFACE_VERSION__ < 0x0003020a
 #define grant_entry_v1 grant_entry
@@ -154,6 +159,55 @@ typedef struct grant_entry_v1 grant_entr
 #define _GTF_transfer_completed (3)
 #define GTF_transfer_completed  (1U<<_GTF_transfer_completed)
 
+/*
+ * Version 2 grant table entries.  These fulfil the same role as
+ * version 1 entries, but can represent more complicated operations.
+ * Any given domain will have either a version 1 or a version 2 table,
+ * and every entry in the table will be the same version.
+ *
+ * The interface by which domains use grant references does not depend
+ * on the grant table version in use by the other domain.
+ */
+#if __XEN_INTERFACE_VERSION__ >= 0x0003020a
+/*
+ * Version 1 and version 2 grant entries share a common prefix.  The
+ * fields of the prefix are documented as part of struct
+ * grant_entry_v1.
+ */
+struct grant_entry_header {
+    uint16_t flags;
+    domid_t  domid;
+};
+typedef struct grant_entry_header grant_entry_header_t;
+
+/*
+ * Version 2 of the grant entry structure.
+ */
+union grant_entry_v2 {
+    grant_entry_header_t hdr;
+
+    /*
+     * This member is used for V1-style full page grants, where either:
+     *
+     * -- hdr.type is GTF_accept_transfer, or
+     * -- hdr.type is GTF_permit_access and GTF_sub_page is not set.
+     *
+     * In that case, the frame field has the same semantics as the
+     * field of the same name in the V1 entry structure.
+     */
+    struct {
+        grant_entry_header_t hdr;
+        uint32_t pad0;
+        uint64_t frame;
+    } full_page;
+
+    uint32_t __spacer[4]; /* Pad to a power of two */
+};
+typedef union grant_entry_v2 grant_entry_v2_t;
+
+typedef uint16_t grant_status_t;
+
+#endif /* __XEN_INTERFACE_VERSION__ */
 
 /***********************************
  * GRANT TABLE QUERIES AND USES
@@ -363,6 +417,63 @@ typedef struct gnttab_unmap_and_replace 
 typedef struct gnttab_unmap_and_replace gnttab_unmap_and_replace_t;
 DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t);
 
+#if __XEN_INTERFACE_VERSION__ >= 0x0003020a
+/*
+ * GNTTABOP_set_version: Request a particular version of the grant
+ * table shared table structure.  This operation can only be performed
+ * once in any given domain.  It must be performed before any grants
+ * are activated; otherwise, the domain will be stuck with version 1.
+ * The only defined versions are 1 and 2.
+ */
+#define GNTTABOP_set_version          8
+struct gnttab_set_version {
+    /* IN parameters */
+    uint32_t version;
+};
+typedef struct gnttab_set_version gnttab_set_version_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_set_version_t);
+
+
+/*
+ * GNTTABOP_get_status_frames: Get the list of frames used to store grant
+ * status for <dom>. In grant format version 2, the status is separated
+ * from the other shared grant fields to allow more efficient synchronization
+ * using barriers instead of atomic cmpexch operations.
+ * <nr_frames> specify the size of vector <frame_list>.
+ * The frame addresses are returned in the <frame_list>.
+ * Only <nr_frames> addresses are returned, even if the table is larger.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ */
+#define GNTTABOP_get_status_frames     9
+struct gnttab_get_status_frames {
+    /* IN parameters. */
+    uint32_t nr_frames;
+    domid_t  dom;
+    /* OUT parameters. */
+    int16_t  status;              /* GNTST_* */
+    XEN_GUEST_HANDLE(uint64_t) frame_list;
+};
+typedef struct gnttab_get_status_frames gnttab_get_status_frames_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_t);
+
+/*
+ * GNTTABOP_get_version: Get the grant table version which is in
+ * effect for domain <dom>.
+ */
+#define GNTTABOP_get_version          10
+struct gnttab_get_version {
+    /* IN parameters */
+    domid_t dom;
+    uint16_t pad;
+    /* OUT parameters */
+    uint32_t version;
+};
+typedef struct gnttab_get_version gnttab_get_version_t;
+DEFINE_XEN_GUEST_HANDLE(gnttab_get_version_t);
+
+#endif /* __XEN_INTERFACE_VERSION__ */
 
 /*
  * Bitfield values for gnttab_map_grant_ref.flags.
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/include/public/memory.h
--- a/xen/include/public/memory.h       Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/include/public/memory.h       Wed Oct 07 07:46:36 2009 +0100
@@ -211,6 +211,8 @@ struct xen_add_to_physmap {
 #define XENMAPSPACE_gmfn        2 /* GMFN */
     unsigned int space;
 
+#define XENMAPIDX_grant_table_status 0x80000000
+
     /* Index into source mapping space. */
     xen_ulong_t idx;
 
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/include/public/xen.h
--- a/xen/include/public/xen.h  Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/include/public/xen.h  Wed Oct 07 07:46:36 2009 +0100
@@ -47,6 +47,7 @@ __DEFINE_XEN_GUEST_HANDLE(ulong, unsigne
 __DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
 DEFINE_XEN_GUEST_HANDLE(void);
 
+DEFINE_XEN_GUEST_HANDLE(uint64_t);
 DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
 #endif
 
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/include/xen/grant_table.h
--- a/xen/include/xen/grant_table.h     Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/include/xen/grant_table.h     Wed Oct 07 07:46:36 2009 +0100
@@ -80,7 +80,15 @@ struct grant_table {
     /* Table size. Number of frames shared with guest */
     unsigned int          nr_grant_frames;
     /* Shared grant table (see include/public/grant_table.h). */
-    struct grant_entry_v1 **shared;
+    union {
+        void **shared_raw;
+        struct grant_entry_v1 **shared_v1;
+        union grant_entry_v2 **shared_v2;
+    };
+    /* Number of grant status frames shared with guest (for version 2) */
+    unsigned int          nr_status_frames;
+    /* State grant table (see include/public/grant_table.h). */
+    grant_status_t       **status;
     /* Active grant table. */
     struct active_grant_entry **active;
     /* Mapping tracking table. */
@@ -89,6 +97,9 @@ struct grant_table {
     unsigned int          maptrack_limit;
     /* Lock protecting updates to active and shared grant tables. */
     spinlock_t            lock;
+    /* The defined versions are 1 and 2.  Set to 0 if we don't know
+       what version to use yet. */
+    unsigned              gt_version;
 };
 
 /* Create/destroy per-domain grant table context. */
@@ -114,10 +125,19 @@ static inline unsigned int nr_grant_fram
     return gt->nr_grant_frames;
 }
 
-/* Number of grant table entries. Caller must hold d's grant table lock. */
-static inline unsigned int nr_grant_entries(struct grant_table *gt)
+/* Number of status grant table frames. Caller must hold d's gr. table lock.*/
+static inline unsigned int nr_status_frames(struct grant_table *gt)
 {
-    return (nr_grant_frames(gt) << PAGE_SHIFT) / sizeof(grant_entry_v1_t);
+    return gt->nr_status_frames;
+}
+
+#define GRANT_STATUS_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t))
+#define GRANT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v2_t))
+/* Number of grant table status entries. Caller must hold d's gr. table lock.*/
+static inline unsigned int grant_to_status_frames(int grant_frames)
+{
+    return (grant_frames * GRANT_PER_PAGE + GRANT_STATUS_PER_PAGE - 1) /
+        GRANT_STATUS_PER_PAGE;
 }
 
 static inline unsigned int
diff -r 7d4f05a65d5a -r 95ea2052b41b xen/include/xlat.lst
--- a/xen/include/xlat.lst      Wed Oct 07 07:46:14 2009 +0100
+++ b/xen/include/xlat.lst      Wed Oct 07 07:46:36 2009 +0100
@@ -44,7 +44,12 @@
 !      gnttab_transfer                 grant_table.h
 ?      gnttab_unmap_grant_ref          grant_table.h
 ?      gnttab_unmap_and_replace        grant_table.h
+?      gnttab_set_version              grant_table.h
+?      gnttab_get_version              grant_table.h
+!      gnttab_get_status_frames        grant_table.h
 ?      grant_entry_v1                  grant_table.h
+?       grant_entry_header              grant_table.h
+?      grant_entry_v2                  grant_table.h
 ?      kexec_exec                      kexec.h
 !      kexec_image                     kexec.h
 !      kexec_range                     kexec.h

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.