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

[Xen-devel] [PATCH v3 5/9] mm: Do not discard already-scrubbed pages if softirqs are pending



While scrubbing from idle loop, check for softirqs every 256 pages.
If softirq is pending, don't scrub any further and merge the
partially-scrubbed buddy back into heap by breaking the clean portion
into smaller power-of-2 chunks. Then repeat the same process for the
dirty part.

Signed-off-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
---
 xen/common/page_alloc.c |   78 ++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 64 insertions(+), 14 deletions(-)

diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index fcd7308..0b2dff1 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -996,7 +996,7 @@ static int reserve_offlined_page(struct page_info *head)
 static struct page_info *
 merge_and_free_buddy(struct page_info *pg, unsigned int node,
                      unsigned int zone, unsigned int order,
-                     bool need_scrub)
+                     bool need_scrub, bool is_frag)
 {
     ASSERT(spin_is_locked(&heap_lock));
 
@@ -1011,7 +1011,15 @@ merge_and_free_buddy(struct page_info *pg, unsigned int 
node,
         if ( (page_to_mfn(pg) & mask) )
             buddy = pg - mask; /* Merge with predecessor block. */
         else
-            buddy = pg + mask; /* Merge with successor block. */
+        {
+            /*
+             * Merge with successor block.
+             * Only un-fragmented buddy can be merged forward.
+             */
+            if ( is_frag )
+                break;
+            buddy = pg + mask;
+        }
 
         if ( !mfn_valid(_mfn(page_to_mfn(buddy))) ||
              !page_state_is(buddy, free) ||
@@ -1093,12 +1101,15 @@ static unsigned int node_to_scrub(bool get_node)
 bool scrub_free_pages(void)
 {
     struct page_info *pg;
-    unsigned int zone, order;
-    unsigned long i;
+    unsigned int zone, order, scrub_order;
+    unsigned long i, num_processed, start, end;
     unsigned int cpu = smp_processor_id();
-    bool preempt = false;
+    bool preempt = false, is_frag;
     nodeid_t node;
 
+    /* Scrubbing granularity. */
+#define SCRUB_CHUNK_ORDER  8
+
     /*
      * Don't scrub while dom0 is being constructed since we may
      * fail trying to call map_domain_page() from scrub_one_page().
@@ -1123,25 +1134,64 @@ bool scrub_free_pages(void)
                 if ( !pg->u.free.dirty_head )
                     break;
 
-                for ( i = 0; i < (1UL << order); i++)
+                scrub_order = MIN(order, SCRUB_CHUNK_ORDER);
+                num_processed = 0;
+                is_frag = false;
+                while ( num_processed < (1UL << order) )
                 {
-                    if ( test_bit(_PGC_need_scrub, &pg[i].count_info) )
+                    for ( i = num_processed;
+                          i < num_processed + (1UL << scrub_order); i++ )
                     {
-                        scrub_one_page(&pg[i]);
-                        pg[i].count_info &= ~PGC_need_scrub;
-                        node_need_scrub[node]--;
+                        if ( test_bit(_PGC_need_scrub, &pg[i].count_info) )
+                        {
+                            scrub_one_page(&pg[i]);
+                            pg[i].count_info &= ~PGC_need_scrub;
+                            node_need_scrub[node]--;
+                        }
                     }
+
+                    num_processed += (1UL << scrub_order);
                     if ( softirq_pending(cpu) )
                     {
                         preempt = true;
+                        is_frag = (num_processed < (1UL << order));
                         break;
                     }
                 }
 
-                if ( i == (1UL << order) )
+                start = 0;
+                end = num_processed;
+
+                page_list_del(pg, &heap(node, zone, order));
+
+                /* Merge clean pages */
+                while ( start < end )
+                {
+                    /*
+                     * Largest power-of-two chunk starting @start,
+                     * not greater than @end
+                     */
+                    unsigned chunk_order = flsl(end - start) - 1;
+                    struct page_info *ppg = &pg[start];
+
+                    PFN_ORDER(ppg) = chunk_order;
+                    merge_and_free_buddy(ppg, node, zone, chunk_order, false, 
is_frag);
+                    start += (1UL << chunk_order);
+                }
+
+                /* Merge unscrubbed pages */
+                while ( end < (1UL << order) )
                 {
-                    page_list_del(pg, &heap(node, zone, order));
-                    merge_and_free_buddy(pg, node, zone, order, false);
+                    /*
+                     * Largest power-of-two chunk starting @end, not crossing
+                     * next power-of-two boundary
+                     */
+                    unsigned chunk_order = ffsl(end) - 1;
+                    struct page_info *ppg = &pg[end];
+
+                    PFN_ORDER(ppg) = chunk_order;
+                    merge_and_free_buddy(ppg, node, zone, chunk_order, true, 
true);
+                    end += (1UL << chunk_order);
                 }
 
                 if ( preempt || (node_need_scrub[node] == 0) )
@@ -1215,7 +1265,7 @@ static void free_heap_pages(
         node_need_scrub[node] += (1UL << order);
     }
 
-    pg = merge_and_free_buddy(pg, node, zone, order, need_scrub);
+    pg = merge_and_free_buddy(pg, node, zone, order, need_scrub, false);
 
     if ( tainted )
         reserve_offlined_page(pg);
-- 
1.7.1


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

 


Rackspace

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