WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

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

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Introduce a grant_entry_v2 structure.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Tue, 06 Oct 2009 23:55:16 -0700
Delivery-date: Tue, 06 Oct 2009 23:57:26 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Introduce a grant_entry_v2 structure., Xen patchbot-unstable <=