tmem: reclaim minimal memory proactively
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 9 Dec 2009 10:44:56 +0000 (10:44 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 9 Dec 2009 10:44:56 +0000 (10:44 +0000)
When a single domain is using most/all of tmem memory
for ephemeral pages belonging to the same object, e.g.
when copying a single huge file larger than ephemeral
memory, long lists are traversed looking for a page to
evict that doesn't belong to this object (as pages in
the object for which a page is currently being inserted
are locked and cannot be evicted).  This is essentially
a livelock.

Avoid this by proactively ensuring there is a margin
of available memory (1MB) before locks are taken on
the object.

Signed-off-by: Dan Magenheimer <dan.magenheimer@oracle.com>
xen/common/tmem.c
xen/include/xen/tmem_xen.h

index af1537d3b559995c58ff980625b70defb6d9d953..ab1b3cd8f637a418186114e5761257517e275b59 100644 (file)
@@ -1093,6 +1093,24 @@ static unsigned long tmem_relinquish_npages(unsigned long n)
     return avail_pages;
 }
 
+/* Under certain conditions (e.g. if each client is putting pages for exactly
+ * one object), once locks are held, freeing up memory may
+ * result in livelocks and very long "put" times, so we try to ensure there
+ * is a minimum amount of memory (1MB) available BEFORE any data structure
+ * locks are held */
+static inline void tmem_ensure_avail_pages(void)
+{
+    int failed_evict = 10;
+
+    while ( !tmh_free_mb() )
+    {
+        if ( tmem_evict() )
+            continue;
+        else if ( failed_evict-- <= 0 )
+            break;
+    }
+}
+
 /************ TMEM CORE OPERATIONS ************************************/
 
 static NOINLINE int do_tmem_put_compress(pgp_t *pgp, tmem_cli_mfn_t cmfn,
@@ -2315,10 +2333,12 @@ EXPORT long do_tmem_op(tmem_cli_op_t uops)
                               op.u.new.uuid[0], op.u.new.uuid[1]);
         break;
     case TMEM_NEW_PAGE:
+        tmem_ensure_avail_pages();
         rc = do_tmem_put(pool, op.u.gen.object,
                          op.u.gen.index, op.u.gen.cmfn, 0, 0, 0, NULL);
         break;
     case TMEM_PUT_PAGE:
+        tmem_ensure_avail_pages();
         rc = do_tmem_put(pool, op.u.gen.object,
                     op.u.gen.index, op.u.gen.cmfn, 0, 0, PAGE_SIZE, NULL);
         if (rc == 1) succ_put = 1;
index 90b860a5f975defa0c08bb438fb5a95a1afe2117..6095db82480f80f455726777bc06b347e16c7215 100644 (file)
@@ -252,6 +252,11 @@ static inline unsigned long tmh_freeable_mb(void)
             (20 - PAGE_SHIFT);
 }
 
+static inline unsigned long tmh_free_mb(void)
+{
+    return (tmh_avail_pages() + total_free_pages()) >> (20 - PAGE_SHIFT);
+}
+
 /*
  * Memory allocation for "infrastructure" data
  */