You must be so glad I no longer use kmap_atomic from NMI context :-)

On Wed, Apr 03, 2019 at 11:34:04AM -0600, Khalid Aziz wrote:
> +static inline void xpfo_kmap(void *kaddr, struct page *page)
> +{
> +     unsigned long flags;
> +
> +     if (!static_branch_unlikely(&xpfo_inited))
> +             return;
> +
> +     if (!PageXpfoUser(page))
> +             return;
> +
> +     /*
> +      * The page was previously allocated to user space, so
> +      * map it back into the kernel if needed. No TLB flush required.
> +      */
> +     spin_lock_irqsave(&page->xpfo_lock, flags);
> +
> +     if ((atomic_inc_return(&page->xpfo_mapcount) == 1) &&
> +             TestClearPageXpfoUnmapped(page))
> +             set_kpte(kaddr, page, PAGE_KERNEL);
> +
> +     spin_unlock_irqrestore(&page->xpfo_lock, flags);

That's a really sad sequence, not wrong, but sad. _3_ atomic operations,
2 on likely the same cacheline. And mostly all pointless.

This patch makes xpfo_mapcount an atomic, but then all modifications are
under the spinlock, what gives?

Anyway, a possibly saner sequence might be:

        if (atomic_inc_not_zero(&page->xpfo_mapcount))
                return;

        spin_lock_irqsave(&page->xpfo_lock, flag);
        if ((atomic_inc_return(&page->xpfo_mapcount) == 1) &&
            TestClearPageXpfoUnmapped(page))
                set_kpte(kaddr, page, PAGE_KERNEL);
        spin_unlock_irqrestore(&page->xpfo_lock, flags);

> +}
> +
> +static inline void xpfo_kunmap(void *kaddr, struct page *page)
> +{
> +     unsigned long flags;
> +
> +     if (!static_branch_unlikely(&xpfo_inited))
> +             return;
> +
> +     if (!PageXpfoUser(page))
> +             return;
> +
> +     /*
> +      * The page is to be allocated back to user space, so unmap it from
> +      * the kernel, flush the TLB and tag it as a user page.
> +      */
> +     spin_lock_irqsave(&page->xpfo_lock, flags);
> +
> +     if (atomic_dec_return(&page->xpfo_mapcount) == 0) {
> +#ifdef CONFIG_XPFO_DEBUG
> +             WARN_ON(PageXpfoUnmapped(page));
> +#endif
> +             SetPageXpfoUnmapped(page);
> +             set_kpte(kaddr, page, __pgprot(0));
> +             xpfo_flush_kernel_tlb(page, 0);

You didn't speak about the TLB invalidation anywhere. But basically this
is one that x86 cannot do.

> +     }
> +
> +     spin_unlock_irqrestore(&page->xpfo_lock, flags);

Idem:

        if (atomic_add_unless(&page->xpfo_mapcount, -1, 1))
                return;

        ....


> +}

Also I'm failing to see the point of PG_xpfo_unmapped, afaict it
is identical to !atomic_read(&page->xpfo_mapcount).

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to