diff mbox series

x86/flushtlb: remove flush_area check on system state

Message ID 20220516143116.28602-1-roger.pau@citrix.com (mailing list archive)
State Superseded
Headers show
Series x86/flushtlb: remove flush_area check on system state | expand

Commit Message

Roger Pau Monné May 16, 2022, 2:31 p.m. UTC
Booting with Shadow Stacks leads to the following assert on a debug
hypervisor:

(XEN) [   11.625166] Assertion 'local_irq_is_enabled()' failed at arch/x86/smp.c:265
(XEN) [   11.629410] ----[ Xen-4.17.0-10.24-d  x86_64  debug=y  Not tainted ]----
(XEN) [   11.633679] CPU:    0
(XEN) [   11.637834] RIP:    e008:[<ffff82d040345300>] flush_area_mask+0x40/0x13e
[...]
(XEN) [   11.806158] Xen call trace:
(XEN) [   11.811255]    [<ffff82d040345300>] R flush_area_mask+0x40/0x13e
(XEN) [   11.816459]    [<ffff82d040338a40>] F modify_xen_mappings+0xc5/0x958
(XEN) [   11.821689]    [<ffff82d0404474f9>] F arch/x86/alternative.c#_alternative_instructions+0xb7/0xb9
(XEN) [   11.827053]    [<ffff82d0404476cc>] F alternative_branches+0xf/0x12
(XEN) [   11.832416]    [<ffff82d04044e37d>] F __start_xen+0x1ef4/0x2776
(XEN) [   11.837809]    [<ffff82d040203344>] F __high_start+0x94/0xa0


This is due to SYS_STATE_smp_boot being set before calling
alternative_branches(), and the flush in modify_xen_mappings() then
using flush_area_all() with interrupts disabled.  Note that
alternative_branches() is called before APs are started, so the flush
must be a local one (and indeed the cpumask passed to
flush_area_mask() just contains one CPU).

Take the opportunity to simplify a bit the logic and make flush_area()
an alias for flush_area_mask(&cpu_online_map...), taking into account
that cpu_online_map just contains the BSP before APs are started.
This requires widening the assert in flush_area_mask() to allow
being called with interrupts disabled as long as it's strictly a local
only flush.

The overall result is that a conditional can be removed from
flush_area().

Fixes: (78e072bc37 'x86/mm: avoid inadvertently degrading a TLB flush to local only')
Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
 xen/arch/x86/include/asm/flushtlb.h | 3 ++-
 xen/arch/x86/mm.c                   | 8 --------
 xen/arch/x86/smp.c                  | 3 ++-
 3 files changed, 4 insertions(+), 10 deletions(-)

Comments

Andrew Cooper May 16, 2022, 2:47 p.m. UTC | #1
On 16/05/2022 15:31, Roger Pau Monne wrote:
> Booting with Shadow Stacks leads to the following assert on a debug
> hypervisor:
>
> (XEN) [   11.625166] Assertion 'local_irq_is_enabled()' failed at arch/x86/smp.c:265
> (XEN) [   11.629410] ----[ Xen-4.17.0-10.24-d  x86_64  debug=y  Not tainted ]----
> (XEN) [   11.633679] CPU:    0
> (XEN) [   11.637834] RIP:    e008:[<ffff82d040345300>] flush_area_mask+0x40/0x13e
> [...]
> (XEN) [   11.806158] Xen call trace:
> (XEN) [   11.811255]    [<ffff82d040345300>] R flush_area_mask+0x40/0x13e
> (XEN) [   11.816459]    [<ffff82d040338a40>] F modify_xen_mappings+0xc5/0x958
> (XEN) [   11.821689]    [<ffff82d0404474f9>] F arch/x86/alternative.c#_alternative_instructions+0xb7/0xb9
> (XEN) [   11.827053]    [<ffff82d0404476cc>] F alternative_branches+0xf/0x12
> (XEN) [   11.832416]    [<ffff82d04044e37d>] F __start_xen+0x1ef4/0x2776
> (XEN) [   11.837809]    [<ffff82d040203344>] F __high_start+0x94/0xa0
>
>
> This is due to SYS_STATE_smp_boot being set before calling
> alternative_branches(), and the flush in modify_xen_mappings() then
> using flush_area_all() with interrupts disabled.  Note that
> alternative_branches() is called before APs are started, so the flush
> must be a local one (and indeed the cpumask passed to
> flush_area_mask() just contains one CPU).
>
> Take the opportunity to simplify a bit the logic and make flush_area()
> an alias for flush_area_mask(&cpu_online_map...), taking into account
> that cpu_online_map just contains the BSP before APs are started.
> This requires widening the assert in flush_area_mask() to allow
> being called with interrupts disabled as long as it's strictly a local
> only flush.
>
> The overall result is that a conditional can be removed from
> flush_area().
>
> Fixes: (78e072bc37 'x86/mm: avoid inadvertently degrading a TLB flush to local only')
> Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com>
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>

Tentatively Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>

This seems like the least bad option of a lot of bad options.  I'd say
it's more than just removing a conditional from flush_area(); it's
removing a runtime special case for init-time code.

~Andrew
Jan Beulich May 18, 2022, 8:49 a.m. UTC | #2
On 16.05.2022 16:31, Roger Pau Monne wrote:
> --- a/xen/arch/x86/include/asm/flushtlb.h
> +++ b/xen/arch/x86/include/asm/flushtlb.h
> @@ -146,7 +146,8 @@ void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags);
>  #define flush_mask(mask, flags) flush_area_mask(mask, NULL, flags)
>  
>  /* Flush all CPUs' TLBs/caches */
> -#define flush_area_all(va, flags) flush_area_mask(&cpu_online_map, va, flags)
> +#define flush_area(va, flags) \
> +    flush_area_mask(&cpu_online_map, (const void *)(va), flags)

I have to admit that I would prefer if we kept the "_all" name suffix,
to continue to clearly express the scope of the flush. I'm also not
really happy to see the cast being added globally now.

> --- a/xen/arch/x86/smp.c
> +++ b/xen/arch/x86/smp.c
> @@ -262,7 +262,8 @@ void flush_area_mask(const cpumask_t *mask, const void *va, unsigned int flags)
>  {
>      unsigned int cpu = smp_processor_id();
>  
> -    ASSERT(local_irq_is_enabled());
> +    /* Local flushes can be performed with interrupts disabled. */
> +    ASSERT(local_irq_is_enabled() || cpumask_equal(mask, cpumask_of(cpu)));

Further down we use cpumask_subset(mask, cpumask_of(cpu)),
apparently to also cover the case where mask is empty. I think
you want to do so here as well.

>      if ( (flags & ~(FLUSH_VCPU_STATE | FLUSH_ORDER_MASK)) &&
>           cpumask_test_cpu(cpu, mask) )

I suppose we want a further precaution here: Despite the
!cpumask_subset(mask, cpumask_of(cpu)) below I think we want to
extend what c64bf2d2a625 ("x86: make CPU state flush requests
explicit") and later changes (isolating uses of FLUSH_VCPU_STATE
from other FLUSH_*) did and exclude the use of FLUSH_VCPU_STATE
for the local CPU altogether. That's because if such somehow made
it into the conditional below here, it would still involve an IPI.
E.g.

    ASSERT(local_irq_is_enabled() ||
           (cpumask_subset(mask, cpumask_of(cpu)) &&
            !(flags & FLUSH_VCPU_STATE)));

Jan
Roger Pau Monné May 23, 2022, 2:37 p.m. UTC | #3
On Wed, May 18, 2022 at 10:49:22AM +0200, Jan Beulich wrote:
> On 16.05.2022 16:31, Roger Pau Monne wrote:
> > --- a/xen/arch/x86/include/asm/flushtlb.h
> > +++ b/xen/arch/x86/include/asm/flushtlb.h
> > @@ -146,7 +146,8 @@ void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags);
> >  #define flush_mask(mask, flags) flush_area_mask(mask, NULL, flags)
> >  
> >  /* Flush all CPUs' TLBs/caches */
> > -#define flush_area_all(va, flags) flush_area_mask(&cpu_online_map, va, flags)
> > +#define flush_area(va, flags) \
> > +    flush_area_mask(&cpu_online_map, (const void *)(va), flags)
> 
> I have to admit that I would prefer if we kept the "_all" name suffix,
> to continue to clearly express the scope of the flush. I'm also not
> really happy to see the cast being added globally now.

But there where no direct callers of flush_area_all(), so the name was
just relevant for it's use in flush_area().  With that now gone I
don't see a need for a flush_area_all(), as flush_area_mask() is more
appropriate.

> > --- a/xen/arch/x86/smp.c
> > +++ b/xen/arch/x86/smp.c
> > @@ -262,7 +262,8 @@ void flush_area_mask(const cpumask_t *mask, const void *va, unsigned int flags)
> >  {
> >      unsigned int cpu = smp_processor_id();
> >  
> > -    ASSERT(local_irq_is_enabled());
> > +    /* Local flushes can be performed with interrupts disabled. */
> > +    ASSERT(local_irq_is_enabled() || cpumask_equal(mask, cpumask_of(cpu)));
> 
> Further down we use cpumask_subset(mask, cpumask_of(cpu)),
> apparently to also cover the case where mask is empty. I think
> you want to do so here as well.

Hm, yes.  I guess that's cheaper than adding an extra:

if ( cpumask_empty() )
    return;

check at the start of the function.

> >      if ( (flags & ~(FLUSH_VCPU_STATE | FLUSH_ORDER_MASK)) &&
> >           cpumask_test_cpu(cpu, mask) )
> 
> I suppose we want a further precaution here: Despite the
> !cpumask_subset(mask, cpumask_of(cpu)) below I think we want to
> extend what c64bf2d2a625 ("x86: make CPU state flush requests
> explicit") and later changes (isolating uses of FLUSH_VCPU_STATE
> from other FLUSH_*) did and exclude the use of FLUSH_VCPU_STATE
> for the local CPU altogether.

If we really want to exclude the use of FLUSH_VCPU_STATE for the local
CPU, we might wish to add this as a separate ASSERT, so that such
checking doesn't depend on !local_irq_is_enabled():

ASSERT(local_irq_is_enabled() || cpumask_subset(mask, cpumask_of(cpu));
ASSERT(!cpumask_subset(mask, cpumask_of(cpu)) || !(flags & FLUSH_VCPU_STATE));


> That's because if such somehow made
> it into the conditional below here, it would still involve an IPI.

Sorry, I'm confused by this: if the mask is empty there should be no
IPI involved at all?  And we shouldn't even get into the second
conditional on the function.

Thanks, Roger.
Jan Beulich May 23, 2022, 3:13 p.m. UTC | #4
On 23.05.2022 16:37, Roger Pau Monné wrote:
> On Wed, May 18, 2022 at 10:49:22AM +0200, Jan Beulich wrote:
>> On 16.05.2022 16:31, Roger Pau Monne wrote:
>>> --- a/xen/arch/x86/include/asm/flushtlb.h
>>> +++ b/xen/arch/x86/include/asm/flushtlb.h
>>> @@ -146,7 +146,8 @@ void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags);
>>>  #define flush_mask(mask, flags) flush_area_mask(mask, NULL, flags)
>>>  
>>>  /* Flush all CPUs' TLBs/caches */
>>> -#define flush_area_all(va, flags) flush_area_mask(&cpu_online_map, va, flags)
>>> +#define flush_area(va, flags) \
>>> +    flush_area_mask(&cpu_online_map, (const void *)(va), flags)
>>
>> I have to admit that I would prefer if we kept the "_all" name suffix,
>> to continue to clearly express the scope of the flush. I'm also not
>> really happy to see the cast being added globally now.
> 
> But there where no direct callers of flush_area_all(), so the name was
> just relevant for it's use in flush_area().  With that now gone I
> don't see a need for a flush_area_all(), as flush_area_mask() is more
> appropriate.

And flush_area_all() is shorthand for flush_area_mask(&cpu_online_map, ...).
That's more clearly distinguished from flush_area_local() than simply
flush_area(); the latter was okay-ish with its mm.c-only exposure, but imo
isn't anymore when put in a header.

>>> --- a/xen/arch/x86/smp.c
>>> +++ b/xen/arch/x86/smp.c
>>> @@ -262,7 +262,8 @@ void flush_area_mask(const cpumask_t *mask, const void *va, unsigned int flags)
>>>  {
>>>      unsigned int cpu = smp_processor_id();
>>>  
>>> -    ASSERT(local_irq_is_enabled());
>>> +    /* Local flushes can be performed with interrupts disabled. */
>>> +    ASSERT(local_irq_is_enabled() || cpumask_equal(mask, cpumask_of(cpu)));
>>
>> Further down we use cpumask_subset(mask, cpumask_of(cpu)),
>> apparently to also cover the case where mask is empty. I think
>> you want to do so here as well.
> 
> Hm, yes.  I guess that's cheaper than adding an extra:
> 
> if ( cpumask_empty() )
>     return;
> 
> check at the start of the function.
> 
>>>      if ( (flags & ~(FLUSH_VCPU_STATE | FLUSH_ORDER_MASK)) &&
>>>           cpumask_test_cpu(cpu, mask) )
>>
>> I suppose we want a further precaution here: Despite the
>> !cpumask_subset(mask, cpumask_of(cpu)) below I think we want to
>> extend what c64bf2d2a625 ("x86: make CPU state flush requests
>> explicit") and later changes (isolating uses of FLUSH_VCPU_STATE
>> from other FLUSH_*) did and exclude the use of FLUSH_VCPU_STATE
>> for the local CPU altogether.
> 
> If we really want to exclude the use of FLUSH_VCPU_STATE for the local
> CPU, we might wish to add this as a separate ASSERT, so that such
> checking doesn't depend on !local_irq_is_enabled():
> 
> ASSERT(local_irq_is_enabled() || cpumask_subset(mask, cpumask_of(cpu));
> ASSERT(!cpumask_subset(mask, cpumask_of(cpu)) || !(flags & FLUSH_VCPU_STATE));
> 
> 
>> That's because if such somehow made
>> it into the conditional below here, it would still involve an IPI.
> 
> Sorry, I'm confused by this: if the mask is empty there should be no
> IPI involved at all?  And we shouldn't even get into the second
> conditional on the function.

Should perhaps have made more explicit that "somehow" means a hypothetical
way, perhaps even as a result of some further breakage somewhere.

Jan
Roger Pau Monné May 23, 2022, 4:24 p.m. UTC | #5
On Mon, May 23, 2022 at 05:13:43PM +0200, Jan Beulich wrote:
> On 23.05.2022 16:37, Roger Pau Monné wrote:
> > On Wed, May 18, 2022 at 10:49:22AM +0200, Jan Beulich wrote:
> >> On 16.05.2022 16:31, Roger Pau Monne wrote:
> >>> --- a/xen/arch/x86/include/asm/flushtlb.h
> >>> +++ b/xen/arch/x86/include/asm/flushtlb.h
> >>> @@ -146,7 +146,8 @@ void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags);
> >>>  #define flush_mask(mask, flags) flush_area_mask(mask, NULL, flags)
> >>>  
> >>>  /* Flush all CPUs' TLBs/caches */
> >>> -#define flush_area_all(va, flags) flush_area_mask(&cpu_online_map, va, flags)
> >>> +#define flush_area(va, flags) \
> >>> +    flush_area_mask(&cpu_online_map, (const void *)(va), flags)
> >>
> >> I have to admit that I would prefer if we kept the "_all" name suffix,
> >> to continue to clearly express the scope of the flush. I'm also not
> >> really happy to see the cast being added globally now.
> > 
> > But there where no direct callers of flush_area_all(), so the name was
> > just relevant for it's use in flush_area().  With that now gone I
> > don't see a need for a flush_area_all(), as flush_area_mask() is more
> > appropriate.
> 
> And flush_area_all() is shorthand for flush_area_mask(&cpu_online_map, ...).
> That's more clearly distinguished from flush_area_local() than simply
> flush_area(); the latter was okay-ish with its mm.c-only exposure, but imo
> isn't anymore when put in a header.

OK, so you would prefer to replace callers to use flush_area_all() and
drop flush_area() altogether.  I can do that.

> >>> --- a/xen/arch/x86/smp.c
> >>> +++ b/xen/arch/x86/smp.c
> >>> @@ -262,7 +262,8 @@ void flush_area_mask(const cpumask_t *mask, const void *va, unsigned int flags)
> >>>  {
> >>>      unsigned int cpu = smp_processor_id();
> >>>  
> >>> -    ASSERT(local_irq_is_enabled());
> >>> +    /* Local flushes can be performed with interrupts disabled. */
> >>> +    ASSERT(local_irq_is_enabled() || cpumask_equal(mask, cpumask_of(cpu)));
> >>
> >> Further down we use cpumask_subset(mask, cpumask_of(cpu)),
> >> apparently to also cover the case where mask is empty. I think
> >> you want to do so here as well.
> > 
> > Hm, yes.  I guess that's cheaper than adding an extra:
> > 
> > if ( cpumask_empty() )
> >     return;
> > 
> > check at the start of the function.
> > 
> >>>      if ( (flags & ~(FLUSH_VCPU_STATE | FLUSH_ORDER_MASK)) &&
> >>>           cpumask_test_cpu(cpu, mask) )
> >>
> >> I suppose we want a further precaution here: Despite the
> >> !cpumask_subset(mask, cpumask_of(cpu)) below I think we want to
> >> extend what c64bf2d2a625 ("x86: make CPU state flush requests
> >> explicit") and later changes (isolating uses of FLUSH_VCPU_STATE
> >> from other FLUSH_*) did and exclude the use of FLUSH_VCPU_STATE
> >> for the local CPU altogether.
> > 
> > If we really want to exclude the use of FLUSH_VCPU_STATE for the local
> > CPU, we might wish to add this as a separate ASSERT, so that such
> > checking doesn't depend on !local_irq_is_enabled():
> > 
> > ASSERT(local_irq_is_enabled() || cpumask_subset(mask, cpumask_of(cpu));
> > ASSERT(!cpumask_subset(mask, cpumask_of(cpu)) || !(flags & FLUSH_VCPU_STATE));
> > 
> > 
> >> That's because if such somehow made
> >> it into the conditional below here, it would still involve an IPI.
> > 
> > Sorry, I'm confused by this: if the mask is empty there should be no
> > IPI involved at all?  And we shouldn't even get into the second
> > conditional on the function.
> 
> Should perhaps have made more explicit that "somehow" means a hypothetical
> way, perhaps even as a result of some further breakage somewhere.

Oh, OK, then I wasn't so confused after all :).  Given your lack of
comments I assume you are fine with the addition of a separate ASSERT
to cover the usage of FLUSH_VCPU_STATE.

Thanks, Roger.
Roger Pau Monné May 24, 2022, 7:32 a.m. UTC | #6
(trying to send again, as I've replied yesterday but the email never
reached xen-devel).

On Mon, May 23, 2022 at 05:13:43PM +0200, Jan Beulich wrote:
> On 23.05.2022 16:37, Roger Pau Monné wrote:
> > On Wed, May 18, 2022 at 10:49:22AM +0200, Jan Beulich wrote:
> >> On 16.05.2022 16:31, Roger Pau Monne wrote:
> >>> --- a/xen/arch/x86/include/asm/flushtlb.h
> >>> +++ b/xen/arch/x86/include/asm/flushtlb.h
> >>> @@ -146,7 +146,8 @@ void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags);
> >>>  #define flush_mask(mask, flags) flush_area_mask(mask, NULL, flags)
> >>>  
> >>>  /* Flush all CPUs' TLBs/caches */
> >>> -#define flush_area_all(va, flags) flush_area_mask(&cpu_online_map, va, flags)
> >>> +#define flush_area(va, flags) \
> >>> +    flush_area_mask(&cpu_online_map, (const void *)(va), flags)
> >>
> >> I have to admit that I would prefer if we kept the "_all" name suffix,
> >> to continue to clearly express the scope of the flush. I'm also not
> >> really happy to see the cast being added globally now.
> > 
> > But there where no direct callers of flush_area_all(), so the name was
> > just relevant for it's use in flush_area().  With that now gone I
> > don't see a need for a flush_area_all(), as flush_area_mask() is more
> > appropriate.
> 
> And flush_area_all() is shorthand for flush_area_mask(&cpu_online_map, ...).
> That's more clearly distinguished from flush_area_local() than simply
> flush_area(); the latter was okay-ish with its mm.c-only exposure, but imo
> isn't anymore when put in a header.

OK, so you would prefer to replace callers to use flush_area_all() and
drop flush_area() altogether.  I can do that.

> >>> --- a/xen/arch/x86/smp.c
> >>> +++ b/xen/arch/x86/smp.c
> >>> @@ -262,7 +262,8 @@ void flush_area_mask(const cpumask_t *mask, const void *va, unsigned int flags)
> >>>  {
> >>>      unsigned int cpu = smp_processor_id();
> >>>  
> >>> -    ASSERT(local_irq_is_enabled());
> >>> +    /* Local flushes can be performed with interrupts disabled. */
> >>> +    ASSERT(local_irq_is_enabled() || cpumask_equal(mask, cpumask_of(cpu)));
> >>
> >> Further down we use cpumask_subset(mask, cpumask_of(cpu)),
> >> apparently to also cover the case where mask is empty. I think
> >> you want to do so here as well.
> > 
> > Hm, yes.  I guess that's cheaper than adding an extra:
> > 
> > if ( cpumask_empty() )
> >     return;
> > 
> > check at the start of the function.
> > 
> >>>      if ( (flags & ~(FLUSH_VCPU_STATE | FLUSH_ORDER_MASK)) &&
> >>>           cpumask_test_cpu(cpu, mask) )
> >>
> >> I suppose we want a further precaution here: Despite the
> >> !cpumask_subset(mask, cpumask_of(cpu)) below I think we want to
> >> extend what c64bf2d2a625 ("x86: make CPU state flush requests
> >> explicit") and later changes (isolating uses of FLUSH_VCPU_STATE
> >> from other FLUSH_*) did and exclude the use of FLUSH_VCPU_STATE
> >> for the local CPU altogether.
> > 
> > If we really want to exclude the use of FLUSH_VCPU_STATE for the local
> > CPU, we might wish to add this as a separate ASSERT, so that such
> > checking doesn't depend on !local_irq_is_enabled():
> > 
> > ASSERT(local_irq_is_enabled() || cpumask_subset(mask, cpumask_of(cpu));
> > ASSERT(!cpumask_subset(mask, cpumask_of(cpu)) || !(flags & FLUSH_VCPU_STATE));
> > 
> > 
> >> That's because if such somehow made
> >> it into the conditional below here, it would still involve an IPI.
> > 
> > Sorry, I'm confused by this: if the mask is empty there should be no
> > IPI involved at all?  And we shouldn't even get into the second
> > conditional on the function.
> 
> Should perhaps have made more explicit that "somehow" means a hypothetical
> way, perhaps even as a result of some further breakage somewhere.

Oh, OK, then I wasn't so confused after all :).  Given your lack of
comments I assume you are fine with the addition of a separate ASSERT
to cover the usage of FLUSH_VCPU_STATE.

Thanks, Roger.
Roger Pau Monné May 24, 2022, 10:48 a.m. UTC | #7
On Mon, May 23, 2022 at 06:24:48PM +0200, Roger Pau Monné wrote:
> On Mon, May 23, 2022 at 05:13:43PM +0200, Jan Beulich wrote:
> > On 23.05.2022 16:37, Roger Pau Monné wrote:
> > > On Wed, May 18, 2022 at 10:49:22AM +0200, Jan Beulich wrote:
> > >> On 16.05.2022 16:31, Roger Pau Monne wrote:
> > >>> --- a/xen/arch/x86/smp.c
> > >>> +++ b/xen/arch/x86/smp.c
> > >>> @@ -262,7 +262,8 @@ void flush_area_mask(const cpumask_t *mask, const void *va, unsigned int flags)
> > >>>  {
> > >>>      unsigned int cpu = smp_processor_id();
> > >>>  
> > >>> -    ASSERT(local_irq_is_enabled());
> > >>> +    /* Local flushes can be performed with interrupts disabled. */
> > >>> +    ASSERT(local_irq_is_enabled() || cpumask_equal(mask, cpumask_of(cpu)));
> > >>
> > >> Further down we use cpumask_subset(mask, cpumask_of(cpu)),
> > >> apparently to also cover the case where mask is empty. I think
> > >> you want to do so here as well.
> > > 
> > > Hm, yes.  I guess that's cheaper than adding an extra:
> > > 
> > > if ( cpumask_empty() )
> > >     return;
> > > 
> > > check at the start of the function.
> > > 
> > >>>      if ( (flags & ~(FLUSH_VCPU_STATE | FLUSH_ORDER_MASK)) &&
> > >>>           cpumask_test_cpu(cpu, mask) )
> > >>
> > >> I suppose we want a further precaution here: Despite the
> > >> !cpumask_subset(mask, cpumask_of(cpu)) below I think we want to
> > >> extend what c64bf2d2a625 ("x86: make CPU state flush requests
> > >> explicit") and later changes (isolating uses of FLUSH_VCPU_STATE
> > >> from other FLUSH_*) did and exclude the use of FLUSH_VCPU_STATE
> > >> for the local CPU altogether.
> > > 
> > > If we really want to exclude the use of FLUSH_VCPU_STATE for the local
> > > CPU, we might wish to add this as a separate ASSERT, so that such
> > > checking doesn't depend on !local_irq_is_enabled():
> > > 
> > > ASSERT(local_irq_is_enabled() || cpumask_subset(mask, cpumask_of(cpu));
> > > ASSERT(!cpumask_subset(mask, cpumask_of(cpu)) || !(flags & FLUSH_VCPU_STATE));

Actually, it would seem even more accurate to use:

ASSERT(!cpumask_test_cpu(cpu, mask) || !(flags & FLUSH_VCPU_STATE));

Thanks, Roger.
diff mbox series

Patch

diff --git a/xen/arch/x86/include/asm/flushtlb.h b/xen/arch/x86/include/asm/flushtlb.h
index 18777f1d4c..a97b3a2327 100644
--- a/xen/arch/x86/include/asm/flushtlb.h
+++ b/xen/arch/x86/include/asm/flushtlb.h
@@ -146,7 +146,8 @@  void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags);
 #define flush_mask(mask, flags) flush_area_mask(mask, NULL, flags)
 
 /* Flush all CPUs' TLBs/caches */
-#define flush_area_all(va, flags) flush_area_mask(&cpu_online_map, va, flags)
+#define flush_area(va, flags) \
+    flush_area_mask(&cpu_online_map, (const void *)(va), flags)
 #define flush_all(flags) flush_mask(&cpu_online_map, flags)
 
 /* Flush local TLBs */
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 67c0427963..45235c5aa6 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -5066,14 +5066,6 @@  l1_pgentry_t *virt_to_xen_l1e(unsigned long v)
 #define l1f_to_lNf(f) (((f) & _PAGE_PRESENT) ? ((f) |  _PAGE_PSE) : (f))
 #define lNf_to_l1f(f) (((f) & _PAGE_PRESENT) ? ((f) & ~_PAGE_PSE) : (f))
 
-/*
- * map_pages_to_xen() can be called early in boot before any other
- * CPUs are online. Use flush_area_local() in this case.
- */
-#define flush_area(v,f) (system_state < SYS_STATE_smp_boot ?    \
-                         flush_area_local((const void *)v, f) : \
-                         flush_area_all((const void *)v, f))
-
 #define L3T_INIT(page) (page) = ZERO_BLOCK_PTR
 
 #define L3T_LOCK(page)        \
diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c
index 0a02086966..2f4e98cec9 100644
--- a/xen/arch/x86/smp.c
+++ b/xen/arch/x86/smp.c
@@ -262,7 +262,8 @@  void flush_area_mask(const cpumask_t *mask, const void *va, unsigned int flags)
 {
     unsigned int cpu = smp_processor_id();
 
-    ASSERT(local_irq_is_enabled());
+    /* Local flushes can be performed with interrupts disabled. */
+    ASSERT(local_irq_is_enabled() || cpumask_equal(mask, cpumask_of(cpu)));
 
     if ( (flags & ~(FLUSH_VCPU_STATE | FLUSH_ORDER_MASK)) &&
          cpumask_test_cpu(cpu, mask) )