|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH for-4.14 v4] x86/tlb: fix assisted flush usage
On Tue, Jun 30, 2020 at 02:13:36PM +0200, Jan Beulich wrote:
> On 26.06.2020 17:57, Roger Pau Monne wrote:
> > Commit e9aca9470ed86 introduced a regression when avoiding sending
> > IPIs for certain flush operations. Xen page fault handler
> > (spurious_page_fault) relies on blocking interrupts in order to
> > prevent handling TLB flush IPIs and thus preventing other CPUs from
> > removing page tables pages. Switching to assisted flushing avoided such
> > IPIs, and thus can result in pages belonging to the page tables being
> > removed (and possibly re-used) while __page_fault_type is being
> > executed.
> >
> > Force some of the TLB flushes to use IPIs, thus avoiding the assisted
> > TLB flush. Those selected flushes are the page type change (when
> > switching from a page table type to a different one, ie: a page that
> > has been removed as a page table) and page allocation. This sadly has
> > a negative performance impact on the pvshim, as less assisted flushes
> > can be used. Note the flush in grant-table code is also switched to
> > use an IPI even when not strictly needed. This is done so that a
> > common arch_flush_tlb_mask can be introduced and always used in common
> > code.
> >
> > Introduce a new flag (FLUSH_FORCE_IPI) and helper to force a TLB flush
> > using an IPI (flush_tlb_mask_sync, x86 only). Note that the flag is
> > only meaningfully defined when the hypervisor supports PV or shadow
> > paging mode, as otherwise hardware assisted paging domains are in
> > charge of their page tables and won't share page tables with Xen, thus
> > not influencing the result of page walks performed by the spurious
> > fault handler.
> >
> > Just passing this new flag when calling flush_area_mask prevents the
> > usage of the assisted flush without any other side effects.
> >
> > Note the flag is not defined on Arm.
> >
> > Fixes: e9aca9470ed86 ('x86/tlb: use Xen L0 assisted TLB flush when
> > available')
> > Reported-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> > Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
>
> In principle
> Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
> A few cosmetic remarks though:
>
> > --- a/xen/arch/x86/mm.c
> > +++ b/xen/arch/x86/mm.c
> > @@ -2894,7 +2894,17 @@ static int _get_page_type(struct page_info *page,
> > unsigned long type,
> > ((nx & PGT_type_mask) == PGT_writable_page)) )
> > {
> > perfc_incr(need_flush_tlb_flush);
> > - flush_tlb_mask(mask);
> > + if ( (x & PGT_type_mask) &&
> > + (x & PGT_type_mask) <= PGT_root_page_table )
> > + /*
> > + * If page was a page table make sure the flush is
> > + * performed using an IPI in order to avoid
> > changing
> > + * the type of a page table page under the feet of
> > + * spurious_page_fault.
> > + */
> > + flush_tlb_mask_sync(mask);
> > + else
> > + flush_tlb_mask(mask);
>
> Effectively this now is the only user of the new macro. I'd prefer
> avoiding its introduction (and hence avoiding the questionable
> "_sync" suffix), doing
>
> flush_mask(mask, FLUSH_TLB | (... ? FLUSH_FORCE_IPI : 0));
Right, maybe placing the '(x & PGT_type_mask) && (x & PGT_type_mask) <=
PGT_root_page_table' condition inside the parameter list of flush_mask
will make the code hard to read, so it might be worth to keep the
if?
> here and ...
>
> > @@ -148,9 +158,24 @@ void flush_area_mask(const cpumask_t *, const void
> > *va, unsigned int flags);
> > /* Flush specified CPUs' TLBs */
> > #define flush_tlb_mask(mask) \
> > flush_mask(mask, FLUSH_TLB)
> > +/*
> > + * Flush specified CPUs' TLBs and force the usage of an IPI to do so. This
> > is
> > + * required for certain operations that rely on page tables themselves not
> > + * being freed and reused when interrupts are blocked, as the flush IPI
> > won't
> > + * be fulfilled until exiting from that critical region.
> > + */
> > +#define flush_tlb_mask_sync(mask) \
> > + flush_mask(mask, FLUSH_TLB | FLUSH_FORCE_IPI)
> > #define flush_tlb_one_mask(mask,v) \
> > flush_area_mask(mask, (const void *)(v), FLUSH_TLB|FLUSH_ORDER(0))
> >
> > +/*
> > + * Alias the common code TLB flush helper to the sync one in order to be
> > on the
> > + * safe side. Note that not all calls from common code strictly require the
> > + * _sync variant.
> > + */
> > +#define arch_flush_tlb_mask flush_tlb_mask_sync
>
> ...
>
> #define arch_flush_tlb_mask(mask) \
> flush_mask(mask, FLUSH_TLB | FLUSH_FORCE_IPI)
Sure. Feel free to slightly adjust the comment, I think doing
s/Alias/Force/ would be enough.
> here. I'd be okay making these adjustments while committing, if
> you and others don't object.
That's fine, I leave to your judgment whether to use the ternary
operator in the _get_page_type case.
Roger.
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |