While hunting an issue in swiotlb-xen I stumbled over a wrong test
and found some areas for improvement.
Juergen Gross (3):
xen/swiotlb: fix condition for calling xen_destroy_contiguous_region()
xen/swiotlb: simplify range_straddles_page_boundary()
xen/swiotlb: remember having called xen_create_contiguous_region()
drivers/xen/swiotlb-xen.c | 36 ++++++++++++------------------------
include/linux/page-flags.h | 3 +++
2 files changed, 15 insertions(+), 24 deletions(-)
--
2.16.4
The condition in xen_swiotlb_free_coherent() for deciding whether to
call xen_destroy_contiguous_region() is wrong: in case the region to
be freed is not contiguous calling xen_destroy_contiguous_region() is
the wrong thing to do: it would result in inconsistent mappings of
multiple PFNs to the same MFN. This will lead to various strange
crashes or data corruption.
Instead of calling xen_destroy_contiguous_region() in that case a
warning should be issued as that situation should never occur.
Cc: [email protected]
Signed-off-by: Juergen Gross <[email protected]>
Reviewed-by: Boris Ostrovsky <[email protected]>
---
V2: always issue a warning in case xen_destroy_contiguous_region()
isn't called (Jan Beulich)
---
drivers/xen/swiotlb-xen.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 5dcb06fe9667..1caadca124b3 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -360,8 +360,8 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
/* Convert the size to actually allocated. */
size = 1UL << (order + XEN_PAGE_SHIFT);
- if (((dev_addr + size - 1 <= dma_mask)) ||
- range_straddles_page_boundary(phys, size))
+ if (!WARN_ON((dev_addr + size - 1 > dma_mask) ||
+ range_straddles_page_boundary(phys, size)))
xen_destroy_contiguous_region(phys, order);
xen_free_coherent_pages(hwdev, size, vaddr, (dma_addr_t)phys, attrs);
--
2.16.4
Instead of always calling xen_destroy_contiguous_region() in case the
memory is DMA-able for the used device, do so only in case it has been
made DMA-able via xen_create_contiguous_region() before.
This will avoid a lot of xen_destroy_contiguous_region() calls for
64-bit capable devices.
As the memory in question is owned by swiotlb-xen the PG_owner_priv_1
flag of the first allocated page can be used for remembering.
Signed-off-by: Juergen Gross <[email protected]>
---
V2: add PG_xen_remapped alias for PG_owner_priv_1 (Boris Ostrovsky)
only clear page flag in case of sane conditions (Jan Beulich)
---
drivers/xen/swiotlb-xen.c | 6 +++++-
include/linux/page-flags.h | 3 +++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index aba5247b9145..7e2d9d1b6f63 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -321,6 +321,7 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
xen_free_coherent_pages(hwdev, size, ret, (dma_addr_t)phys, attrs);
return NULL;
}
+ SetPageXenRemapped(virt_to_page(ret));
}
memset(ret, 0, size);
return ret;
@@ -345,8 +346,11 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
size = 1UL << (order + XEN_PAGE_SHIFT);
if (!WARN_ON((dev_addr + size - 1 > dma_mask) ||
- range_straddles_page_boundary(phys, size)))
+ range_straddles_page_boundary(phys, size)) &&
+ PageXenRemapped(virt_to_page(vaddr))) {
xen_destroy_contiguous_region(phys, order);
+ ClearPageXenRemapped(virt_to_page(vaddr));
+ }
xen_free_coherent_pages(hwdev, size, vaddr, (dma_addr_t)phys, attrs);
}
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 9f8712a4b1a5..296480e990f2 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -152,6 +152,8 @@ enum pageflags {
PG_savepinned = PG_dirty,
/* Has a grant mapping of another (foreign) domain's page. */
PG_foreign = PG_owner_priv_1,
+ /* Remapped by swiotlb-xen. */
+ PG_xen_remapped = PG_owner_priv_1,
/* SLOB */
PG_slob_free = PG_private,
@@ -329,6 +331,7 @@ PAGEFLAG(Pinned, pinned, PF_NO_COMPOUND)
TESTSCFLAG(Pinned, pinned, PF_NO_COMPOUND)
PAGEFLAG(SavePinned, savepinned, PF_NO_COMPOUND);
PAGEFLAG(Foreign, foreign, PF_NO_COMPOUND);
+PAGEFLAG(XenRemapped, xen_remapped, PF_NO_COMPOUND);
PAGEFLAG(Reserved, reserved, PF_NO_COMPOUND)
__CLEARPAGEFLAG(Reserved, reserved, PF_NO_COMPOUND)
--
2.16.4
>>> On 29.05.19 at 11:04, <[email protected]> wrote:
> The condition in xen_swiotlb_free_coherent() for deciding whether to
> call xen_destroy_contiguous_region() is wrong: in case the region to
> be freed is not contiguous calling xen_destroy_contiguous_region() is
> the wrong thing to do: it would result in inconsistent mappings of
> multiple PFNs to the same MFN. This will lead to various strange
> crashes or data corruption.
>
> Instead of calling xen_destroy_contiguous_region() in that case a
> warning should be issued as that situation should never occur.
>
> Cc: [email protected]
> Signed-off-by: Juergen Gross <[email protected]>
> Reviewed-by: Boris Ostrovsky <[email protected]>
Reviewed-by: Jan Beulich <[email protected]>
>>> On 29.05.19 at 11:04, <[email protected]> wrote:
> @@ -345,8 +346,11 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
> size = 1UL << (order + XEN_PAGE_SHIFT);
>
> if (!WARN_ON((dev_addr + size - 1 > dma_mask) ||
> - range_straddles_page_boundary(phys, size)))
> + range_straddles_page_boundary(phys, size)) &&
> + PageXenRemapped(virt_to_page(vaddr))) {
> xen_destroy_contiguous_region(phys, order);
> + ClearPageXenRemapped(virt_to_page(vaddr));
> + }
To be symmetric with setting the flag only after having made the region
contiguous, and to avoid (perhaps just theoretical) races, wouldn't it be
better to clear the flag before calling xen_destroy_contiguous_region()?
Even better would be a TestAndClear...() operation.
Jan
On 29/05/2019 11:57, Jan Beulich wrote:
>>>> On 29.05.19 at 11:04, <[email protected]> wrote:
>> @@ -345,8 +346,11 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
>> size = 1UL << (order + XEN_PAGE_SHIFT);
>>
>> if (!WARN_ON((dev_addr + size - 1 > dma_mask) ||
>> - range_straddles_page_boundary(phys, size)))
>> + range_straddles_page_boundary(phys, size)) &&
>> + PageXenRemapped(virt_to_page(vaddr))) {
>> xen_destroy_contiguous_region(phys, order);
>> + ClearPageXenRemapped(virt_to_page(vaddr));
>> + }
>
> To be symmetric with setting the flag only after having made the region
> contiguous, and to avoid (perhaps just theoretical) races, wouldn't it be
> better to clear the flag before calling xen_destroy_contiguous_region()?
> Even better would be a TestAndClear...() operation.
I like that idea.
Juergen
Please don't add your private flag to page-flags.h. The whole point of
the private flag is that you can use it in any way you want withou
touching the common code.
On 5/30/19 5:04 AM, Christoph Hellwig wrote:
> Please don't add your private flag to page-flags.h. The whole point of
> the private flag is that you can use it in any way you want withou
> touching the common code.
There is already a bunch of aliases for various sub-components
(including Xen) in page-flags.h for private flags, which is why I
suggested we do the same for the new use case. Adding this new alias
will keep flag usage consistent.
-boris
On 30/05/2019 14:46, Boris Ostrovsky wrote:
> On 5/30/19 5:04 AM, Christoph Hellwig wrote:
>> Please don't add your private flag to page-flags.h. The whole point of
>> the private flag is that you can use it in any way you want withou
>> touching the common code.
>
>
> There is already a bunch of aliases for various sub-components
> (including Xen) in page-flags.h for private flags, which is why I
> suggested we do the same for the new use case. Adding this new alias
> will keep flag usage consistent.
What about me adding another patch moving those Xen private aliases
into arch/x86/include/asm/xen/page.h ?
Juergen
On 31.05.19 13:38, Juergen Gross wrote:
> On 30/05/2019 14:46, Boris Ostrovsky wrote:
>> On 5/30/19 5:04 AM, Christoph Hellwig wrote:
>>> Please don't add your private flag to page-flags.h. The whole point of
>>> the private flag is that you can use it in any way you want withou
>>> touching the common code.
>>
>>
>> There is already a bunch of aliases for various sub-components
>> (including Xen) in page-flags.h for private flags, which is why I
>> suggested we do the same for the new use case. Adding this new alias
>> will keep flag usage consistent.
>
> What about me adding another patch moving those Xen private aliases
> into arch/x86/include/asm/xen/page.h ?
This is becoming difficult.
I'd need to remove the "#undef PF_NO_COMPOUND" from page-flags.h or to
#include a (new) xen/page-flags.h from page-flags.h after all the
defines are ready. Is that really worth the effort given that other
components (e.g. file systems) are doing the same?
Juergen