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
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu