|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 4/4] xen/mm: Recall claims when offlining pages if needed
Fix a bug where offlining pages could cause an unsigned underflow
in total_avail_pages - outstanding_claims, leading to incorrect
claim behavior.
This issue arises when outstanding claims are close to the total
available pages. It occurse when domain_set_outstanding_claims()
and domain_install_claim_set effectively do this:
unsigned long avail_pages = total_avail_pages - outstanding_claims;
When this unsigned subtraction underflows, staking claims can succeed
even when there is insufficient unclaimed memory for the new claim.
This leads to a state where claims always succeed, regardless of
actual memory availability.
To prevent this, recall claims when offlining pages if needed to maintain
equilibrium between `total_avail_pages` and outstanding claims for global
and for per-NUMA-node claims.
Signed-off-by: Bernhard Kaindl <bernhard.kaindl@xxxxxxxxxx>
---
tools/tests/alloc/test-offlining-claims.c | 4 ---
xen/common/page_alloc.c | 42 +++++++++++++++++++++++
2 files changed, 42 insertions(+), 4 deletions(-)
diff --git a/tools/tests/alloc/test-offlining-claims.c
b/tools/tests/alloc/test-offlining-claims.c
index d22d270ceeb4..0844c792e740 100644
--- a/tools/tests/alloc/test-offlining-claims.c
+++ b/tools/tests/alloc/test-offlining-claims.c
@@ -41,9 +41,7 @@ static void test_offlining_with_global_claims(int mfn)
/* ASSERT */
CHECK_BUDDY(page, "After offlining the 2nd page");
CHECK(FREE_PAGES == 2, "Expect 2 free pages after offlining two pages");
- EXPECTED_TO_FAIL_BEGIN();
CHECK(TOTAL_CLAIMS == 2, "Expect 2 claims after offlining two pages");
- EXPECTED_TO_FAIL_END(1);
}
@@ -75,9 +73,7 @@ static void test_offlining_with_node_claims(int mfn)
/* ASSERT */
CHECK_BUDDY(page, "After offlining the 2nd page");
CHECK(FREE_PAGES == 2, "Expect 2 free pages after offlining two pages");
- EXPECTED_TO_FAIL_BEGIN();
CHECK(TOTAL_CLAIMS == 2, "Expect 2 claims after offlining two pages");
- EXPECTED_TO_FAIL_END(1);
}
int main(int argc, char *argv[])
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 6101bd6be9a9..adedf6fae590 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -1575,6 +1575,48 @@ static int reserve_offlined_page(struct page_info *head)
count++;
}
+ if ( count )
+ {
+ long recall_pages;
+ struct domain *d;
+
+ /* Ensure that claims on the node are in line with its free memory. */
+ recall_pages = node_outstanding_claims[node] - node_avail_pages[node];
+ if ( recall_pages > 0 )
+ /*
+ * node_avail_pages slipped below node_outstanding_claims.
+ * We need to recall claimed pages until the amount of claimed
+ * memory is in line with the amount of available memory again.
+ */
+ for_each_domain ( d )
+ {
+ if ( d->claims[node] )
+ {
+ recall_pages -= deduct_node_claims(d, node, recall_pages);
+ if ( recall_pages <= 0 )
+ break;
+ }
+ }
+
+ /* Ensure that outstanding claims are in line with available memory. */
+ recall_pages = outstanding_claims - total_avail_pages;
+ if ( recall_pages > 0 )
+ /*
+ * total_avail_pages slipped below outstanding_claims.
+ * We need to recall claimed pages until the amount of claimed
+ * memory is in line with the amount of available memory again.
+ */
+ for_each_domain ( d )
+ {
+ if ( d->global_claims )
+ {
+ recall_pages -= deduct_global_claims(d, recall_pages);
+ if ( recall_pages <= 0 )
+ break;
+ }
+ }
+ }
+
return count;
}
--
2.39.5
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |