From: Paul Durrant <pdurrant@amazon.com>
To: <xen-devel@lists.xenproject.org>
Cc: "Stefano Stabellini" <sstabellini@kernel.org>,
"Julien Grall" <julien@xen.org>, "Wei Liu" <wl@xen.org>,
"Konrad Rzeszutek Wilk" <konrad.wilk@oracle.com>,
"George Dunlap" <George.Dunlap@eu.citrix.com>,
"Andrew Cooper" <andrew.cooper3@citrix.com>,
"Paul Durrant" <pdurrant@amazon.com>,
"Ian Jackson" <ian.jackson@eu.citrix.com>,
"Volodymyr Babchuk" <Volodymyr_Babchuk@epam.com>,
"Roger Pau Monné" <roger.pau@citrix.com>
Subject: [Xen-devel] [PATCH v8 3/4] mm: make pages allocated with MEMF_no_refcount safe to assign
Date: Thu, 30 Jan 2020 14:57:44 +0000 [thread overview]
Message-ID: <20200130145745.1306-4-pdurrant@amazon.com> (raw)
In-Reply-To: <20200130145745.1306-1-pdurrant@amazon.com>
Currently it is unsafe to assign a domheap page allocated with
MEMF_no_refcount to a domain because the domain't 'tot_pages' will not
be incremented, but will be decrement when the page is freed (since
free_domheap_pages() has no way of telling that the increment was skipped).
This patch allocates a new 'count_info' bit for a PGC_extra flag
which is then used to mark pages when alloc_domheap_pages() is called
with MEMF_no_refcount. assign_pages() because it still needs to call
domain_adjust_tot_pages() to make sure the domain is appropriately
referenced. Hence it is modified to do that for PGC_extra pages even if it
is passed MEMF_no_refount.
The number of PGC_extra pages assigned to a domain is tracked in a new
'extra_pages' counter, which is then subtracted from 'total_pages' in
the domain_tot_pages() helper. Thus 'normal' page assignments will still
be appropriately checked against 'max_pages'.
Signed-off-by: Paul Durrant <pdurrant@amazon.com>
---
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: George Dunlap <George.Dunlap@eu.citrix.com>
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Julien Grall <julien@xen.org>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Wei Liu <wl@xen.org>
Cc: Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
Cc: "Roger Pau Monné" <roger.pau@citrix.com>
v8:
- Drop the idea of post-allocation assignment adding an error path to
steal_page() if it encounters a PGC_extra page
- Tighten up the ASSERTs in assign_pages()
v7:
- s/PGC_no_refcount/PGC_extra/g
- Re-work allocation to account for 'extra' pages, also making it
safe to assign PGC_extra pages post-allocation
v6:
- Add an extra ASSERT into assign_pages() that PGC_no_refcount is not
set if MEMF_no_refcount is clear
- ASSERT that count_info is 0 in alloc_domheap_pages() and set to
PGC_no_refcount rather than ORing
v5:
- Make sure PGC_no_refcount is set before assign_pages() is called
- Don't bother to clear PGC_no_refcount in free_domheap_pages() and
drop ASSERT in free_heap_pages()
- Don't latch count_info in free_heap_pages()
v4:
- New in v4
---
xen/arch/x86/mm.c | 3 +-
xen/common/page_alloc.c | 63 +++++++++++++++++++++++++++++++---------
xen/include/asm-arm/mm.h | 5 +++-
xen/include/asm-x86/mm.h | 7 +++--
xen/include/xen/sched.h | 5 +++-
5 files changed, 64 insertions(+), 19 deletions(-)
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 8bb66cf30c..2796161c1f 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -4217,7 +4217,8 @@ int steal_page(
if ( !(owner = page_get_owner_and_reference(page)) )
goto fail;
- if ( owner != d || is_xen_heap_page(page) )
+ if ( owner != d || is_xen_heap_page(page) ||
+ (page->count_info & PGC_extra) )
goto fail_put;
/*
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index bbd3163909..1ac9d9c719 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -2267,7 +2267,29 @@ int assign_pages(
goto out;
}
- if ( !(memflags & MEMF_no_refcount) )
+#ifndef NDEBUG
+ {
+ unsigned int extra_pages = 0;
+
+ for ( i = 0; i < (1ul << order); i++ )
+ {
+ ASSERT(!(pg[i].count_info & ~PGC_extra));
+ if ( pg[i].count_info & PGC_extra )
+ extra_pages++;
+ }
+
+ ASSERT(!extra_pages ||
+ ((memflags & MEMF_no_refcount) &&
+ extra_pages == 1u << order));
+ }
+#endif
+
+ if ( pg[0].count_info & PGC_extra )
+ {
+ d->extra_pages += 1u << order;
+ memflags &= ~MEMF_no_refcount;
+ }
+ else if ( !(memflags & MEMF_no_refcount) )
{
unsigned int tot_pages = domain_tot_pages(d) + (1 << order);
@@ -2278,18 +2300,19 @@ int assign_pages(
rc = -E2BIG;
goto out;
}
+ }
- if ( unlikely(domain_adjust_tot_pages(d, 1 << order) == (1 << order)) )
+ if ( !(memflags & MEMF_no_refcount) &&
+ unlikely(domain_adjust_tot_pages(d, 1 << order) == (1 << order)) )
get_knownalive_domain(d);
- }
for ( i = 0; i < (1 << order); i++ )
{
ASSERT(page_get_owner(&pg[i]) == NULL);
- ASSERT(!pg[i].count_info);
page_set_owner(&pg[i], d);
smp_wmb(); /* Domain pointer must be visible before updating refcnt. */
- pg[i].count_info = PGC_allocated | 1;
+ pg[i].count_info =
+ (pg[i].count_info & PGC_extra) | PGC_allocated | 1;
page_list_add_tail(&pg[i], &d->page_list);
}
@@ -2315,11 +2338,6 @@ struct page_info *alloc_domheap_pages(
if ( memflags & MEMF_no_owner )
memflags |= MEMF_no_refcount;
- else if ( (memflags & MEMF_no_refcount) && d )
- {
- ASSERT(!(memflags & MEMF_no_refcount));
- return NULL;
- }
if ( !dma_bitsize )
memflags &= ~MEMF_no_dma;
@@ -2332,11 +2350,23 @@ struct page_info *alloc_domheap_pages(
memflags, d)) == NULL)) )
return NULL;
- if ( d && !(memflags & MEMF_no_owner) &&
- assign_pages(d, pg, order, memflags) )
+ if ( d && !(memflags & MEMF_no_owner) )
{
- free_heap_pages(pg, order, memflags & MEMF_no_scrub);
- return NULL;
+ if ( memflags & MEMF_no_refcount )
+ {
+ unsigned long i;
+
+ for ( i = 0; i < (1ul << order); i++ )
+ {
+ ASSERT(!pg[i].count_info);
+ pg[i].count_info = PGC_extra;
+ }
+ }
+ if ( assign_pages(d, pg, order, memflags) )
+ {
+ free_heap_pages(pg, order, memflags & MEMF_no_scrub);
+ return NULL;
+ }
}
return pg;
@@ -2384,6 +2414,11 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
BUG();
}
arch_free_heap_page(d, &pg[i]);
+ if ( pg[i].count_info & PGC_extra )
+ {
+ ASSERT(d->extra_pages);
+ d->extra_pages--;
+ }
}
drop_dom_ref = !domain_adjust_tot_pages(d, -(1 << order));
diff --git a/xen/include/asm-arm/mm.h b/xen/include/asm-arm/mm.h
index 333efd3a60..7df91280bc 100644
--- a/xen/include/asm-arm/mm.h
+++ b/xen/include/asm-arm/mm.h
@@ -119,9 +119,12 @@ struct page_info
#define PGC_state_offlined PG_mask(2, 9)
#define PGC_state_free PG_mask(3, 9)
#define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
+/* Page is not reference counted */
+#define _PGC_extra PG_shift(10)
+#define PGC_extra PG_mask(1, 10)
/* Count of references to this frame. */
-#define PGC_count_width PG_shift(9)
+#define PGC_count_width PG_shift(10)
#define PGC_count_mask ((1UL<<PGC_count_width)-1)
/*
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index 2ca8882ad0..06d64d494d 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -77,9 +77,12 @@
#define PGC_state_offlined PG_mask(2, 9)
#define PGC_state_free PG_mask(3, 9)
#define page_state_is(pg, st) (((pg)->count_info&PGC_state) == PGC_state_##st)
+/* Page is not reference counted */
+#define _PGC_extra PG_shift(10)
+#define PGC_extra PG_mask(1, 10)
- /* Count of references to this frame. */
-#define PGC_count_width PG_shift(9)
+/* Count of references to this frame. */
+#define PGC_count_width PG_shift(10)
#define PGC_count_mask ((1UL<<PGC_count_width)-1)
/*
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 1b6d7b941f..21b5f4cebd 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -374,6 +374,7 @@ struct domain
unsigned int xenheap_pages; /* pages allocated from Xen heap */
unsigned int outstanding_pages; /* pages claimed but not possessed */
unsigned int max_pages; /* maximum value for domain_tot_pages() */
+ unsigned int extra_pages; /* pages not included in domain_tot_pages() */
atomic_t shr_pages; /* shared pages */
atomic_t paged_pages; /* paged-out pages */
@@ -548,7 +549,9 @@ struct domain
/* Return number of pages currently posessed by the domain */
static inline unsigned int domain_tot_pages(const struct domain *d)
{
- return d->tot_pages;
+ ASSERT(d->extra_pages <= d->tot_pages);
+
+ return d->tot_pages - d->extra_pages;
}
/* Protect updates/reads (resp.) of domain_list and domain_hash. */
--
2.20.1
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel
next prev parent reply other threads:[~2020-01-30 14:58 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-30 14:57 [Xen-devel] [PATCH v8 0/4] purge free_shared_domheap_page() Paul Durrant
2020-01-30 14:57 ` [Xen-devel] [PATCH v8 1/4] x86 / vmx: move teardown from domain_destroy() Paul Durrant
2020-01-31 13:32 ` Jan Beulich
2020-01-31 13:34 ` Durrant, Paul
2020-01-30 14:57 ` [Xen-devel] [PATCH v8 2/4] add a domain_tot_pages() helper function Paul Durrant
2020-01-30 16:29 ` Jan Beulich
2020-01-30 16:32 ` Durrant, Paul
2020-01-30 16:37 ` Jan Beulich
2020-01-31 12:52 ` Jan Beulich
2020-01-31 15:18 ` Durrant, Paul
2020-01-31 15:42 ` Durrant, Paul
2020-01-30 14:57 ` Paul Durrant [this message]
2020-01-30 16:27 ` [Xen-devel] [PATCH v8 3/4] mm: make pages allocated with MEMF_no_refcount safe to assign Jan Beulich
2020-01-30 14:57 ` [Xen-devel] [PATCH v8 4/4] x86 / vmx: use a MEMF_no_refcount domheap page for APIC_DEFAULT_PHYS_BASE Paul Durrant
2020-02-03 8:10 ` Tian, Kevin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200130145745.1306-4-pdurrant@amazon.com \
--to=pdurrant@amazon.com \
--cc=George.Dunlap@eu.citrix.com \
--cc=Volodymyr_Babchuk@epam.com \
--cc=andrew.cooper3@citrix.com \
--cc=ian.jackson@eu.citrix.com \
--cc=julien@xen.org \
--cc=konrad.wilk@oracle.com \
--cc=roger.pau@citrix.com \
--cc=sstabellini@kernel.org \
--cc=wl@xen.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.