在 2023/3/29 22:23, Linus Walleij 写道:
Whenever the IB_MR_TYPE_DMA flag is set in imbr.type, the "iova"
(I/O virtual address) is not really a virtual address but a physical
address.
This means that the use of virt_to_page() on these addresses is also
incorrect, this needs to be treated and converted to a page using
the page frame number and pfn_to_page().
Fix up all users in this file.
It is better to have a summary to these 2 commits.
Anyway, thanks.
Acked-by: Zhu Yanjun <zyjzyj2000@xxxxxxxxx>
Zhu Yanjun
Fixes: 592627ccbdff ("RDMA/rxe: Replace rxe_map and rxe_phys_buf by xarray")
Cc: Bob Pearson <rpearsonhpe@xxxxxxxxx>
Reported-by: Jason Gunthorpe <jgg@xxxxxxxxxx>
Link: https://lore.kernel.org/linux-rdma/ZB2s3GeaN%2FFBpR5K@xxxxxxxxxx/
Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
---
ChangeLog v1->v2:
- New patch prepended to patch set.
---
drivers/infiniband/sw/rxe/rxe_mr.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
index b10aa1580a64..8e8250652f9d 100644
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -279,16 +279,20 @@ static int rxe_mr_copy_xarray(struct rxe_mr *mr, u64 iova, void *addr,
return 0;
}
-static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 iova, void *addr,
+/*
+ * This function is always called with a physical address as parameter,
+ * since DMA only operates on physical addresses.
+ */
+static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 phys, void *addr,
unsigned int length, enum rxe_mr_copy_dir dir)
{
- unsigned int page_offset = iova & (PAGE_SIZE - 1);
+ unsigned int page_offset = phys & (PAGE_SIZE - 1);
unsigned int bytes;
struct page *page;
u8 *va;
while (length) {
- page = virt_to_page(iova & mr->page_mask);
+ page = pfn_to_page(phys >> PAGE_SHIFT);
bytes = min_t(unsigned int, length,
PAGE_SIZE - page_offset);
va = kmap_local_page(page);
@@ -300,7 +304,7 @@ static void rxe_mr_copy_dma(struct rxe_mr *mr, u64 iova, void *addr,
kunmap_local(va);
page_offset = 0;
- iova += bytes;
+ phys += bytes;
addr += bytes;
length -= bytes;
}
@@ -487,8 +491,11 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode,
}
if (mr->ibmr.type == IB_MR_TYPE_DMA) {
- page_offset = iova & (PAGE_SIZE - 1);
- page = virt_to_page(iova & PAGE_MASK);
+ /* In this case iova is a physical address */
+ u64 phys = iova;
+
+ page_offset = phys & (PAGE_SIZE - 1);
+ page = pfn_to_page(phys >> PAGE_SHIFT);
} else {
unsigned long index;
int err;
@@ -544,8 +551,11 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value)
}
if (mr->ibmr.type == IB_MR_TYPE_DMA) {
- page_offset = iova & (PAGE_SIZE - 1);
- page = virt_to_page(iova & PAGE_MASK);
+ /* In this case iova is a physical address */
+ u64 phys = iova;
+
+ page_offset = phys & (PAGE_SIZE - 1);
+ page = pfn_to_page(phys >> PAGE_SHIFT);
} else {
unsigned long index;
int err;