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-devel

[Xen-devel] [PATCH 05 of 10] Introduce a grant_entry_v2 structure

To: <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 05 of 10] Introduce a grant_entry_v2 structure
From: <steven.smith@xxxxxxxxxx>
Date: Sun, 4 Oct 2009 16:00:35 +0100
Cc: keir.fraser@xxxxxxxxxx, joserenato.santos@xxxxxx
Delivery-date: Sun, 04 Oct 2009 08:11:13 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <patchbomb.1254668430@xxxxxxxxxxxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Steven Smith <steven.smith@xxxxxxxxxxxxx>
# Date 1222082608 -3600
# Node ID 2ffb577b2169147b09315d713a96326ef1349c95
# Parent  1df819bcf08654a2f23e88ce22295caf7806d65c
Introduce a grant_entry_v2 structure.

Signed-off-by: Steven Smith <steven.smith@xxxxxxxxxx>

diff -r 1df819bcf086 -r 2ffb577b2169 tools/libxc/xc_linux.c
--- a/tools/libxc/xc_linux.c    Mon Sep 22 12:23:28 2008 +0100
+++ b/tools/libxc/xc_linux.c    Mon Sep 22 12:23:28 2008 +0100
@@ -558,7 +558,21 @@
     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;
@@ -638,6 +652,22 @@
     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);
+}
+
 /*
  * Local variables:
  * mode: C
diff -r 1df819bcf086 -r 2ffb577b2169 tools/libxc/xc_offline_page.c
--- a/tools/libxc/xc_offline_page.c     Mon Sep 22 12:23:28 2008 +0100
+++ b/tools/libxc/xc_offline_page.c     Mon Sep 22 12:23:28 2008 +0100
@@ -132,8 +132,8 @@
  /*
   * 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 @@
 
     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 @@
     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 @@
             goto failed;
     }
 
-    gnttab = xc_gnttab_map_table(xc_handle, domid, &gnt_num);
-    if (!gnttab)
+    gnttab_v2 = xc_gnttab_map_table_v2(xc_handle, domid, &gnt_num);
+    if (!gnttab_v2)
     {
-        ERROR("Failed to map grant table\n");
-        goto failed;
+        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 (xc_is_page_granted(xc_handle, mfn, gnttab, gnt_num))
+    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 @@
     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 1df819bcf086 -r 2ffb577b2169 tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Mon Sep 22 12:23:28 2008 +0100
+++ b/tools/libxc/xenctrl.h     Mon Sep 22 12:23:28 2008 +0100
@@ -943,7 +943,9 @@
 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 1df819bcf086 -r 2ffb577b2169 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Mon Sep 22 12:23:28 2008 +0100
@@ -2084,12 +2084,26 @@
     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);
 }
@@ -2141,13 +2155,12 @@
 
 #else /* defined(__x86_64__) */
 
-static long hvm_grant_table_op_compat32(
-    unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
+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 */
+    if ( !grant_table_op_is_allowed(cmd) )
+        return -ENOSYS;
     return compat_grant_table_op(cmd, uop, count);
 }
 
diff -r 1df819bcf086 -r 2ffb577b2169 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/arch/x86/mm.c Mon Sep 22 12:23:28 2008 +0100
@@ -4000,12 +4000,25 @@
         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 1df819bcf086 -r 2ffb577b2169 xen/common/compat/grant_table.c
--- a/xen/common/compat/grant_table.c   Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/common/compat/grant_table.c   Mon Sep 22 12:23:28 2008 +0100
@@ -8,6 +8,14 @@
 #define xen_grant_entry_v1 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;
@@ -28,6 +36,18 @@
 #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_gnttab_get_version gnttab_get_version
+CHECK_gnttab_get_version;
+#undef xen_gnttab_get_version
+
+#define xen_gnttab_get_status_frames gnttab_get_status_frames
+CHECK_gnttab_get_status_frames;
+#undef xen_gnttab_get_status_frames
 
 int compat_grant_table_op(unsigned int cmd,
                           XEN_GUEST_HANDLE(void) cmp_uop,
diff -r 1df819bcf086 -r 2ffb577b2169 xen/common/grant_table.c
--- a/xen/common/grant_table.c  Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/common/grant_table.c  Mon Sep 22 12:23:28 2008 +0100
@@ -105,9 +105,24 @@
 }
 
 
-#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])
@@ -183,6 +198,174 @@
     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);
+}
+
 /*
  * Returns 0 if TLB flush / invalidate required by caller.
  * va will indicate the address to be invalidated.
@@ -205,18 +388,10 @@
     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 @@
 
     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 @@
          (!(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->frame;
+            act->frame = gmfn_to_mfn(rd, act->gfn);
         }
     }
 
@@ -343,7 +496,7 @@
     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 @@
     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 @@
 
     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 @@
     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 @@
     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 @@
 {
     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 @@
     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 @@
 
     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 @@
     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 @@
     /* 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 @@
 
     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 @@
 
     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 @@
     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;
 
@@ -1058,6 +1275,14 @@
 
     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)) )
     {
         gdprintk(XENLOG_INFO,
@@ -1066,7 +1291,7 @@
         goto fail;
     }
 
-    sha = &shared_entry(rgt, ref);
+    sha = shared_entry_header(rgt, ref);
     
     scombo.word = *(u32 *)&sha->flags;
 
@@ -1115,7 +1340,6 @@
     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 @@
         /* 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->frame, mfn, 0);
+            sha->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(
     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 @@
 
         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 @@
     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 @@
     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->frame;
+            act->frame = gmfn_to_mfn(rd, act->gfn);
         }
     }
 
@@ -1528,6 +1755,164 @@
     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 (raw_copy_to_guest((void *)(op.frame_list + i * sizeof(gmfn)),
+                              &gmfn,
+                              sizeof(gmfn)))
+            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 +2015,22 @@
         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;
@@ -1666,9 +2067,6 @@
     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 +2101,27 @@
         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 +2129,8 @@
 
  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 +2155,8 @@
     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 +2184,12 @@
         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 +2235,11 @@
             }
 
             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 +2261,8 @@
         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 +2271,10 @@
     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 1df819bcf086 -r 2ffb577b2169 xen/include/asm-x86/grant_table.h
--- a/xen/include/asm-x86/grant_table.h Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/include/asm-x86/grant_table.h Mon Sep 22 12:23:28 2008 +0100
@@ -21,15 +21,30 @@
 #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 1df819bcf086 -r 2ffb577b2169 xen/include/public/grant_table.h
--- a/xen/include/public/grant_table.h  Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/include/public/grant_table.h  Mon Sep 22 12:23:28 2008 +0100
@@ -90,6 +90,11 @@
  * [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
 #define grant_entry_v1_t grant_entry_t
@@ -154,6 +159,48 @@
 #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.
+ */
+struct grant_entry_v2 {
+    grant_entry_header_t hdr;
+    union {
+        /*
+         * The frame to which we are granting access.  This field has
+         * the same meaning as the grant_entry_v1 field of the same
+         * name.
+         */
+        uint32_t frame;
+
+        uint32_t __spacer[3]; /* Pad to a power of two */
+    };
+};
+typedef struct grant_entry_v2 grant_entry_v2_t;
+
+typedef uint16_t grant_status_t;
+
+#endif /* __XEN_INTERFACE_VERSION__ */
 
 /***********************************
  * GRANT TABLE QUERIES AND USES
@@ -363,6 +410,63 @@
 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_* */
+    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 1df819bcf086 -r 2ffb577b2169 xen/include/public/memory.h
--- a/xen/include/public/memory.h       Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/include/public/memory.h       Mon Sep 22 12:23:28 2008 +0100
@@ -211,6 +211,8 @@
 #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 1df819bcf086 -r 2ffb577b2169 xen/include/xen/grant_table.h
--- a/xen/include/xen/grant_table.h     Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/include/xen/grant_table.h     Mon Sep 22 12:23:28 2008 +0100
@@ -80,7 +80,15 @@
     /* 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;
+        struct 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 @@
     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 @@
     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 1df819bcf086 -r 2ffb577b2169 xen/include/xlat.lst
--- a/xen/include/xlat.lst      Mon Sep 22 12:23:28 2008 +0100
+++ b/xen/include/xlat.lst      Mon Sep 22 12:23:28 2008 +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-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel