[PATCH v3 6/7] xen/page_alloc: Protect claimed memory against other allocations

Bernhard Kaindl posted 7 patches 2 days, 13 hours ago
[PATCH v3 6/7] xen/page_alloc: Protect claimed memory against other allocations
Posted by Bernhard Kaindl 2 days, 13 hours ago
Extend get_free_buddy() to only allocate from nodes with enough
unclaimed memory left, unless the allocation is made by a domain
with sufficient claims on this node to cover the allocation.

Signed-off-by: Marcus Granado <marcus.granado@cloud.com>
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Signed-off-by: Bernhard Kaindl <bernhard.kaindl@cloud.com>

---
Changes in v3:

Rewritten based on a check by Marcus Granado which needs to be inside
the NUMA node loop of get_free_buddy() to only allow it to allocating
from NUMA nodes with enough unclaimed memory.

It was originally only intented for when looping over all NUMA nodes,
but the check also needs to be done when falling back to other nodes:

I updated the check to be generic: Now, it used for all requests by
integrating the check of the claim of the domain from Alejandro's
can_alloc() helper into it.

This fixes the issue that when falling back from a nodemask to allocate
from (based on MEMF_get_node(memflags) or from d->node_affinity):

When falling back to other NUMA nodes, still only allocate from nodes
with enough unclaimed memory left, unless the allocation is made by
a domain with sufficient claims on this node to cover the allocation.

This makes the can_alloc() helper function obsolete, as the needed
checks are done for the NUMA nodes as they are considered, not only
for the orignally requested NUMA node (not just before searching).
---
 xen/common/page_alloc.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index ebf41a1b33..b866076b78 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -980,9 +980,19 @@ static struct page_info *get_free_buddy(unsigned int zone_lo,
     {
         zone = zone_hi;
         do {
-            /* Check if target node can support the allocation. */
-            if ( !avail[node] || (avail[node][zone] < (1UL << order)) )
-                continue;
+            unsigned long request = 1UL << order;
+            /*
+             * Check if this node is currently suitable for this allocation.
+             * 1. It has sufficient memory in the requested zone and the
+             * 2. request must fit in the unclaimed memory of the node minus
+             *    outstanding claims, unless the allocation is made by a domain
+             *    with sufficient node-claimed memory to cover the allocation.
+             */
+            if ( !avail[node] || (avail[node][zone] < request) ||
+                 (insufficient_memory(node, request) &&
+                  (!d || node != d->claim_node ||     /* a domain with claims */
+                   request > d->outstanding_pages)) ) /* claim covers request */
+                continue;  /* next zone/node if insufficient memory or claims */
 
             /* Find smallest order which can satisfy the request. */
             for ( j = order; j <= MAX_ORDER; j++ )
-- 
2.43.0