Message ID | 20230329142341.863175-1-linus.walleij@linaro.org (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Jason Gunthorpe |
Headers | show |
Series | [v2,1/2] RDMA/rxe: Treat physical addresses right | expand |
在 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@gmail.com> Zhu Yanjun > > Fixes: 592627ccbdff ("RDMA/rxe: Replace rxe_map and rxe_phys_buf by xarray") > Cc: Bob Pearson <rpearsonhpe@gmail.com> > Reported-by: Jason Gunthorpe <jgg@nvidia.com> > Link: https://lore.kernel.org/linux-rdma/ZB2s3GeaN%2FFBpR5K@nvidia.com/ > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > 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;
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;
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. Fixes: 592627ccbdff ("RDMA/rxe: Replace rxe_map and rxe_phys_buf by xarray") Cc: Bob Pearson <rpearsonhpe@gmail.com> Reported-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/linux-rdma/ZB2s3GeaN%2FFBpR5K@nvidia.com/ Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- ChangeLog v1->v2: - New patch prepended to patch set. --- drivers/infiniband/sw/rxe/rxe_mr.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)