]> xenbits.xensource.com Git - people/dwmw2/xen.git/commitdiff
xen/page-alloc: Clamp get_free_buddy() to online nodes
authorAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 24 Jun 2019 15:38:36 +0000 (16:38 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 31 Jul 2019 13:18:31 +0000 (14:18 +0100)
d->node_affinity defaults to NODE_MASK_ALL which has bits set outside of
node_online_map.  This in turn causes the loop in get_free_buddy() to waste
effort iterating over offline nodes.

Always clamp d->node_affinity to node_online_map.

This in turn requires ensuring that d->node_affinity intersects with
node_online_map, and there is one case via XEN_DOMCTL_setnodeaffinity where a
disjoint mask can end up being specified.

Tighten up the hypercall check, because there is no plausible reason to select
a node affinity which is disjoint with the system, and leave get_free_buddy()
with an assertion to the same effect, but with a runtime-safe fallback to the
full online node map.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
xen/common/domain.c
xen/common/page_alloc.c

index df523c9ce4803a7db04779f826dd6f7ce38ca41a..744b57219598882bd52148e7091b07b7f8c2fa9a 100644 (file)
@@ -627,8 +627,8 @@ void domain_update_node_affinity(struct domain *d)
 
 int domain_set_node_affinity(struct domain *d, const nodemask_t *affinity)
 {
-    /* Being affine with no nodes is just wrong */
-    if ( nodes_empty(*affinity) )
+    /* Being disjoint with the system is just wrong. */
+    if ( !nodes_intersects(*affinity, node_online_map) )
         return -EINVAL;
 
     spin_lock(&d->node_affinity_lock);
index 44a72d0b19acc2e6db36f80603875419e5a74813..4b16ef0d543487d45a2062dcbe2e3d3ade6aef5a 100644 (file)
@@ -811,11 +811,27 @@ static struct page_info *get_free_buddy(unsigned int zone_lo,
                                         const struct domain *d)
 {
     nodeid_t first, node = MEMF_get_node(memflags), req_node = node;
-    nodemask_t nodemask = d ? d->node_affinity : node_online_map;
+    nodemask_t nodemask = node_online_map;
     unsigned int j, zone, nodemask_retry = 0;
     struct page_info *pg;
     bool use_unscrubbed = (memflags & MEMF_no_scrub);
 
+    /*
+     * d->node_affinity is our preferred allocation set if provided, but it
+     * may have bits set outside of node_online_map.  Clamp it.
+     */
+    if ( d )
+    {
+        /*
+         * It is the callers responsibility to ensure that d->node_affinity
+         * isn't complete junk.
+         */
+        if ( nodes_intersects(nodemask, d->node_affinity) )
+            nodes_and(nodemask, nodemask, d->node_affinity);
+        else
+            ASSERT_UNREACHABLE();
+    }
+
     if ( node == NUMA_NO_NODE )
     {
         if ( d != NULL )