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

[Xen-devel] [PATCH 08 of 11] grant-tables: Use get_page_from_gfn() instead of get_gfn()/put_gfn



# HG changeset patch
# User Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
# Date 1336661656 -3600
# Node ID ed61cd76e3e3fad3ec4c216669d1e9ee8c0bfa4b
# Parent  28d15a29ab59d29a1fd5deb79ceda5d557343f14
grant-tables: Use get_page_from_gfn() instead of get_gfn()/put_gfn.

This requires some careful re-engineering of __get_paged_frame and its callers.
Functions that previously returned gfn's to be put now return pages to be put.

Tested with Win7 + Citrix PV drivers guest, using speedtest for networking
(yes!) plus the loginVSI framework to constantly hit disk.

Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>

diff -r 28d15a29ab59 -r ed61cd76e3e3 xen/common/grant_table.c
--- a/xen/common/grant_table.c  Thu May 10 15:54:16 2012 +0100
+++ b/xen/common/grant_table.c  Thu May 10 15:54:16 2012 +0100
@@ -107,18 +107,6 @@ static unsigned inline int max_nr_maptra
     return (max_nr_grant_frames * MAX_MAPTRACK_TO_GRANTS_RATIO);
 }
 
-#ifdef CONFIG_X86
-#define gfn_to_mfn_private(_d, _gfn) ({                     \
-    p2m_type_t __p2mt;                                      \
-    unsigned long __x;                                      \
-    __x = mfn_x(get_gfn_unshare((_d), (_gfn), &__p2mt));    \
-    if ( p2m_is_shared(__p2mt) || !p2m_is_valid(__p2mt) )   \
-        __x = INVALID_MFN;                                  \
-    __x; })
-#else
-#define gfn_to_mfn_private(_d, _gfn) gmfn_to_mfn(_d, _gfn)
-#endif
-
 #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])
@@ -141,41 +129,41 @@ shared_entry_header(struct grant_table *
 #define active_entry(t, e) \
     ((t)->active[(e)/ACGNT_PER_PAGE][(e)%ACGNT_PER_PAGE])
 
-/* Check if the page has been paged out. If rc == GNTST_okay, caller must do 
put_gfn(rd, gfn) */
-static int __get_paged_frame(unsigned long gfn, unsigned long *frame, int 
readonly, struct domain *rd)
+/* Check if the page has been paged out, or needs unsharing. 
+   If rc == GNTST_okay, *page contains the page struct with a ref taken.
+   Caller must do put_page(*page).
+   If any error, *page = NULL, *frame = INVALID_MFN, no ref taken. */
+static int __get_paged_frame(unsigned long gfn, unsigned long *frame, struct 
page_info **page,
+                                int readonly, struct domain *rd)
 {
     int rc = GNTST_okay;
 #if defined(P2M_PAGED_TYPES) || defined(P2M_SHARED_TYPES)
     p2m_type_t p2mt;
-    mfn_t mfn;
-
-    if ( readonly )
-        mfn = get_gfn(rd, gfn, &p2mt);
-    else
+
+    *page = get_page_from_gfn(rd, gfn, &p2mt, 
+                              (readonly) ? P2M_ALLOC : P2M_UNSHARE);
+    if ( !(*page) )
     {
-        mfn = get_gfn_unshare(rd, gfn, &p2mt);
+        *frame = INVALID_MFN;
         if ( p2m_is_shared(p2mt) )
+            return GNTST_eagain;
+        if ( p2m_is_paging(p2mt) )
         {
-            put_gfn(rd, gfn);
+            p2m_mem_paging_populate(rd, gfn);
             return GNTST_eagain;
         }
+        return GNTST_bad_page;
     }
-
-    if ( p2m_is_valid(p2mt) ) {
-        *frame = mfn_x(mfn);
-        if ( p2m_is_paging(p2mt) )
-        {
-            put_gfn(rd, gfn);
-            p2m_mem_paging_populate(rd, gfn);
-            rc = GNTST_eagain;
-        }
-    } else {
-       put_gfn(rd, gfn);
-       *frame = INVALID_MFN;
-       rc = GNTST_bad_page;
+    *frame = page_to_mfn(*page);
+#else
+    *frame = gmfn_to_mfn(rd, gfn);
+    *page = mfn_valid(*frame) ? mfn_to_page(*frame) : NULL;
+    if ( (!(*page)) || (!get_page(*page, rd)) )
+    {
+        *frame = INVALID_MFN;
+        *page = NULL;
+        rc = GNTST_bad_page;
     }
-#else
-    *frame = readonly ? gmfn_to_mfn(rd, gfn) : gfn_to_mfn_private(rd, gfn);
 #endif
 
     return rc;
@@ -470,12 +458,11 @@ static void
 __gnttab_map_grant_ref(
     struct gnttab_map_grant_ref *op)
 {
-    struct domain *ld, *rd, *owner;
+    struct domain *ld, *rd, *owner = NULL;
     struct vcpu   *led;
     int            handle;
-    unsigned long  gfn = INVALID_GFN;
     unsigned long  frame = 0, nr_gets = 0;
-    struct page_info *pg;
+    struct page_info *pg = NULL;
     int            rc = GNTST_okay;
     u32            old_pin;
     u32            act_pin;
@@ -573,13 +560,11 @@ static void
         {
             unsigned long frame;
 
-            gfn = sha1 ? sha1->frame : sha2->full_page.frame;
-            rc = __get_paged_frame(gfn, &frame, !!(op->flags & 
GNTMAP_readonly), rd);
+            unsigned long gfn = sha1 ? sha1->frame : sha2->full_page.frame;
+            rc = __get_paged_frame(gfn, &frame, &pg, 
+                                    !!(op->flags & GNTMAP_readonly), rd);
             if ( rc != GNTST_okay )
-            {
-                gfn = INVALID_GFN;
                 goto unlock_out_clear;
-            }
             act->gfn = gfn;
             act->domid = ld->domain_id;
             act->frame = frame;
@@ -606,9 +591,17 @@ static void
 
     spin_unlock(&rd->grant_table->lock);
 
-    pg = mfn_valid(frame) ? mfn_to_page(frame) : NULL;
-
-    if ( !pg || (owner = page_get_owner_and_reference(pg)) == dom_io )
+    /* pg may be set, with a refcount included, from __get_paged_frame */
+    if ( !pg )
+    {
+        pg = mfn_valid(frame) ? mfn_to_page(frame) : NULL;
+        if ( pg )
+            owner = page_get_owner_and_reference(pg);
+    }
+    else
+        owner = page_get_owner(pg);
+
+    if ( !pg || (owner == dom_io) )
     {
         /* Only needed the reference to confirm dom_io ownership. */
         if ( pg )
@@ -708,8 +701,6 @@ static void
     op->handle       = handle;
     op->status       = GNTST_okay;
 
-    if ( gfn != INVALID_GFN )
-        put_gfn(rd, gfn);
     rcu_unlock_domain(rd);
     return;
 
@@ -748,8 +739,6 @@ static void
         gnttab_clear_flag(_GTF_reading, status);
 
  unlock_out:
-    if ( gfn != INVALID_GFN )
-        put_gfn(rd, gfn);
     spin_unlock(&rd->grant_table->lock);
     op->status = rc;
     put_maptrack_handle(ld->grant_table, handle);
@@ -1479,7 +1468,16 @@ gnttab_transfer(
             return -EFAULT;
         }
 
-        mfn = gfn_to_mfn_private(d, gop.mfn);
+#ifdef CONFIG_X86
+        {
+            p2m_type_t __p2mt;
+            mfn = mfn_x(get_gfn_unshare(d, gop.mfn, &__p2mt));
+            if ( p2m_is_shared(__p2mt) || !p2m_is_valid(__p2mt) )
+                mfn = INVALID_MFN;
+        }
+#else
+        mfn = gmfn_to_mfn(d, gop.mfn);
+#endif
 
         /* Check the passed page frame for basic validity. */
         if ( unlikely(!mfn_valid(mfn)) )
@@ -1723,15 +1721,14 @@ static void __fixup_status_for_pin(const
 }
 
 /* Grab a frame number from a grant entry and update the flags and pin
-   count as appropriate.  Note that this does *not* update the page
-   type or reference counts, and does not check that the mfn is
-   actually valid. If *gfn != INVALID_GFN, and rc == GNTST_okay, then
-   we leave this function holding the p2m entry for *gfn in *owning_domain */
+   count as appropriate. If rc == GNTST_okay, note that this *does* 
+   take one ref count on the target page, stored in *page.
+   If there is any error, *page = NULL, no ref taken. */
 static int
 __acquire_grant_for_copy(
     struct domain *rd, unsigned long gref, struct domain *ld, int readonly,
-    unsigned long *frame, unsigned long *gfn, unsigned *page_off, unsigned 
*length,
-    unsigned allow_transitive, struct domain **owning_domain)
+    unsigned long *frame, struct page_info **page, 
+    unsigned *page_off, unsigned *length, unsigned allow_transitive)
 {
     grant_entry_v1_t *sha1;
     grant_entry_v2_t *sha2;
@@ -1746,11 +1743,9 @@ static int
     unsigned trans_page_off;
     unsigned trans_length;
     int is_sub_page;
-    struct domain *ignore;
     s16 rc = GNTST_okay;
 
-    *owning_domain = NULL;
-    *gfn = INVALID_GFN;
+    *page = NULL;
 
     spin_lock(&rd->grant_table->lock);
 
@@ -1827,14 +1822,13 @@ static int
             spin_unlock(&rd->grant_table->lock);
 
             rc = __acquire_grant_for_copy(td, trans_gref, rd,
-                                          readonly, &grant_frame, gfn,
-                                          &trans_page_off, &trans_length,
-                                          0, &ignore);
+                                          readonly, &grant_frame, page,
+                                          &trans_page_off, &trans_length, 0);
 
             spin_lock(&rd->grant_table->lock);
             if ( rc != GNTST_okay ) {
                 __fixup_status_for_pin(act, status);
-               rcu_unlock_domain(td);
+                rcu_unlock_domain(td);
                 spin_unlock(&rd->grant_table->lock);
                 return rc;
             }
@@ -1846,56 +1840,49 @@ static int
             if ( act->pin != old_pin )
             {
                 __fixup_status_for_pin(act, status);
-               rcu_unlock_domain(td);
+                rcu_unlock_domain(td);
                 spin_unlock(&rd->grant_table->lock);
+                put_page(*page);
                 return __acquire_grant_for_copy(rd, gref, ld, readonly,
-                                                frame, gfn, page_off, length,
-                                                allow_transitive,
-                                                owning_domain);
+                                                frame, page, page_off, length,
+                                                allow_transitive);
             }
 
             /* The actual remote remote grant may or may not be a
                sub-page, but we always treat it as one because that
                blocks mappings of transitive grants. */
             is_sub_page = 1;
-            *owning_domain = td;
             act->gfn = -1ul;
         }
         else if ( sha1 )
         {
-            *gfn = sha1->frame;
-            rc = __get_paged_frame(*gfn, &grant_frame, readonly, rd);
+            rc = __get_paged_frame(sha1->frame, &grant_frame, page, readonly, 
rd);
             if ( rc != GNTST_okay )
                 goto unlock_out;
-            act->gfn = *gfn;
+            act->gfn = sha1->frame;
             is_sub_page = 0;
             trans_page_off = 0;
             trans_length = PAGE_SIZE;
-            *owning_domain = rd;
         }
         else if ( !(sha2->hdr.flags & GTF_sub_page) )
         {
-            *gfn = sha2->full_page.frame;
-            rc = __get_paged_frame(*gfn, &grant_frame, readonly, rd);
+            rc = __get_paged_frame(sha2->full_page.frame, &grant_frame, page, 
readonly, rd);
             if ( rc != GNTST_okay )
                 goto unlock_out;
-            act->gfn = *gfn;
+            act->gfn = sha2->full_page.frame;
             is_sub_page = 0;
             trans_page_off = 0;
             trans_length = PAGE_SIZE;
-            *owning_domain = rd;
         }
         else
         {
-            *gfn = sha2->sub_page.frame;
-            rc = __get_paged_frame(*gfn, &grant_frame, readonly, rd);
+            rc = __get_paged_frame(sha2->sub_page.frame, &grant_frame, page, 
readonly, rd);
             if ( rc != GNTST_okay )
                 goto unlock_out;
-            act->gfn = *gfn;
+            act->gfn = sha2->sub_page.frame;
             is_sub_page = 1;
             trans_page_off = sha2->sub_page.page_off;
             trans_length = sha2->sub_page.length;
-            *owning_domain = rd;
         }
 
         if ( !act->pin )
@@ -1911,7 +1898,9 @@ static int
     }
     else
     {
-        *owning_domain = rd;
+        ASSERT(mfn_valid(act->frame));
+        *page = mfn_to_page(act->frame);
+        (void)page_get_owner_and_reference(*page);
     }
 
     act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc;
@@ -1930,11 +1919,11 @@ static void
     struct gnttab_copy *op)
 {
     struct domain *sd = NULL, *dd = NULL;
-    struct domain *source_domain = NULL, *dest_domain = NULL;
-    unsigned long s_frame, d_frame, s_gfn = INVALID_GFN, d_gfn = INVALID_GFN;
+    unsigned long s_frame, d_frame;
+    struct page_info *s_pg = NULL, *d_pg = NULL;
     char *sp, *dp;
     s16 rc = GNTST_okay;
-    int have_d_grant = 0, have_s_grant = 0, have_s_ref = 0;
+    int have_d_grant = 0, have_s_grant = 0;
     int src_is_gref, dest_is_gref;
 
     if ( ((op->source.offset + op->len) > PAGE_SIZE) ||
@@ -1972,82 +1961,54 @@ static void
     {
         unsigned source_off, source_len;
         rc = __acquire_grant_for_copy(sd, op->source.u.ref, current->domain, 1,
-                                      &s_frame, &s_gfn, &source_off, 
&source_len, 1,
-                                      &source_domain);
+                                      &s_frame, &s_pg, &source_off, 
&source_len, 1);
         if ( rc != GNTST_okay )
             goto error_out;
         have_s_grant = 1;
         if ( op->source.offset < source_off ||
              op->len > source_len )
-            PIN_FAIL(error_put_s_gfn, GNTST_general_error,
+            PIN_FAIL(error_out, GNTST_general_error,
                      "copy source out of bounds: %d < %d || %d > %d\n",
                      op->source.offset, source_off,
                      op->len, source_len);
     }
     else
     {
-#ifdef CONFIG_X86
-        s_gfn = op->source.u.gmfn;
-        rc = __get_paged_frame(op->source.u.gmfn, &s_frame, 1, sd);
+        rc = __get_paged_frame(op->source.u.gmfn, &s_frame, &s_pg, 1, sd);
         if ( rc != GNTST_okay )
-            goto error_out;
-#else
-        s_frame = gmfn_to_mfn(sd, op->source.u.gmfn);        
-#endif
-        source_domain = sd;
+            PIN_FAIL(error_out, rc,
+                     "source frame %lx invalid.\n", s_frame);
     }
-    if ( unlikely(!mfn_valid(s_frame)) )
-        PIN_FAIL(error_put_s_gfn, GNTST_general_error,
-                 "source frame %lx invalid.\n", s_frame);
-    /* For the source frame, the page could still be shared, so
-     * don't assume ownership by source_domain */
-    if ( !page_get_owner_and_reference(mfn_to_page(s_frame)) )
-    {
-        if ( !sd->is_dying )
-            gdprintk(XENLOG_WARNING, "Could not get src frame %lx\n", s_frame);
-        rc = GNTST_general_error;
-        goto error_put_s_gfn;
-    }
-    have_s_ref = 1;
 
     if ( dest_is_gref )
     {
         unsigned dest_off, dest_len;
         rc = __acquire_grant_for_copy(dd, op->dest.u.ref, current->domain, 0,
-                                      &d_frame, &d_gfn, &dest_off, &dest_len, 
1,
-                                      &dest_domain);
+                                      &d_frame, &d_pg, &dest_off, &dest_len, 
1);
         if ( rc != GNTST_okay )
-            goto error_put_s_gfn;
+            goto error_out;
         have_d_grant = 1;
         if ( op->dest.offset < dest_off ||
              op->len > dest_len )
-            PIN_FAIL(error_put_d_gfn, GNTST_general_error,
+            PIN_FAIL(error_out, GNTST_general_error,
                      "copy dest out of bounds: %d < %d || %d > %d\n",
                      op->dest.offset, dest_off,
                      op->len, dest_len);
     }
     else
     {
-#ifdef CONFIG_X86
-        d_gfn = op->dest.u.gmfn;
-        rc = __get_paged_frame(op->dest.u.gmfn, &d_frame, 0, dd);
+        rc = __get_paged_frame(op->dest.u.gmfn, &d_frame, &d_pg, 0, dd);
         if ( rc != GNTST_okay )
-            goto error_put_s_gfn;
-#else
-        d_frame = gmfn_to_mfn(dd, op->dest.u.gmfn);
-#endif
-        dest_domain = dd;
+            PIN_FAIL(error_out, rc,
+                     "destination frame %lx invalid.\n", d_frame);
     }
-    if ( unlikely(!mfn_valid(d_frame)) )
-        PIN_FAIL(error_put_d_gfn, GNTST_general_error,
-                 "destination frame %lx invalid.\n", d_frame);
-    if ( !get_page_and_type(mfn_to_page(d_frame), dest_domain,
-                            PGT_writable_page) )
+
+    if ( !get_page_type(d_pg, PGT_writable_page) )
     {
         if ( !dd->is_dying )
             gdprintk(XENLOG_WARNING, "Could not get dst frame %lx\n", d_frame);
         rc = GNTST_general_error;
-        goto error_put_d_gfn;
+        goto error_out;
     }
 
     sp = map_domain_page(s_frame);
@@ -2060,16 +2021,12 @@ static void
 
     gnttab_mark_dirty(dd, d_frame);
 
-    put_page_and_type(mfn_to_page(d_frame));
- error_put_d_gfn:
-    if ( (d_gfn != INVALID_GFN) && (dest_domain) )
-        put_gfn(dest_domain, d_gfn);
- error_put_s_gfn:
-    if ( (s_gfn != INVALID_GFN) && (source_domain) )
-        put_gfn(source_domain, s_gfn);
+    put_page_type(d_pg);
  error_out:
-    if ( have_s_ref )
-        put_page(mfn_to_page(s_frame));
+    if ( d_pg )
+        put_page(d_pg);
+    if ( s_pg )
+        put_page(s_pg);
     if ( have_s_grant )
         __release_grant_for_copy(sd, op->source.u.ref, 1);
     if ( have_d_grant )

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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