RDMA/core: add bio_vec based RDMA read/write API

The existing rdma_rw_ctx_init() API requires callers to construct a
scatterlist, which is then DMA-mapped page by page. Callers that
already have data in bio_vec form (such as the NVMe-oF target) must
first convert to scatterlist, adding overhead and complexity.

Introduce rdma_rw_ctx_init_bvec() and rdma_rw_ctx_destroy_bvec() to
accept bio_vec arrays directly. The new helpers use dma_map_phys()
for hardware RDMA devices and virtual addressing for software RDMA
devices (rxe, siw), avoiding intermediate scatterlist construction.

Memory registration (MR) path support is deferred to a follow-up
series; callers requiring MR-based transfers (iWARP devices or
force_mr=1) receive -EOPNOTSUPP and should use the scatterlist API.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://patch.msgid.link/20260128005400.25147-2-cel@kernel.org
Signed-off-by: Leon Romanovsky <leon@kernel.org>
This commit is contained in:
Chuck Lever
2026-01-27 19:53:56 -05:00
committed by Leon Romanovsky
parent 959d2c356e
commit 5e54155358
3 changed files with 250 additions and 0 deletions

View File

@@ -15,6 +15,7 @@
#include <linux/ethtool.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/bvec.h>
#include <linux/dma-mapping.h>
#include <linux/kref.h>
#include <linux/list.h>
@@ -4266,6 +4267,47 @@ static inline void ib_dma_unmap_page(struct ib_device *dev,
dma_unmap_page(dev->dma_device, addr, size, direction);
}
/**
* ib_dma_map_bvec - Map a bio_vec to DMA address
* @dev: The device for which the dma_addr is to be created
* @bvec: The bio_vec to map
* @direction: The direction of the DMA
*
* Returns a DMA address for the bio_vec. The caller must check the
* result with ib_dma_mapping_error() before use; a failed mapping
* must not be passed to ib_dma_unmap_bvec().
*
* For software RDMA devices (rxe, siw), returns a virtual address
* and no actual DMA mapping occurs.
*/
static inline u64 ib_dma_map_bvec(struct ib_device *dev,
struct bio_vec *bvec,
enum dma_data_direction direction)
{
if (ib_uses_virt_dma(dev))
return (uintptr_t)bvec_virt(bvec);
return dma_map_phys(dev->dma_device, bvec_phys(bvec),
bvec->bv_len, direction, 0);
}
/**
* ib_dma_unmap_bvec - Unmap a bio_vec DMA mapping
* @dev: The device for which the DMA address was created
* @addr: The DMA address returned by ib_dma_map_bvec()
* @size: The size of the region in bytes
* @direction: The direction of the DMA
*
* Releases a DMA mapping created by ib_dma_map_bvec(). For software
* RDMA devices this is a no-op since no actual mapping occurred.
*/
static inline void ib_dma_unmap_bvec(struct ib_device *dev,
u64 addr, size_t size,
enum dma_data_direction direction)
{
if (!ib_uses_virt_dma(dev))
dma_unmap_phys(dev->dma_device, addr, size, direction, 0);
}
int ib_dma_virt_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents);
static inline int ib_dma_map_sg_attrs(struct ib_device *dev,
struct scatterlist *sg, int nents,

View File

@@ -5,6 +5,7 @@
#ifndef _RDMA_RW_H
#define _RDMA_RW_H
#include <linux/bvec.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <rdma/ib_verbs.h>
@@ -49,6 +50,16 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u32 port_num, struct scatterlist *sg, u32 sg_cnt,
enum dma_data_direction dir);
struct bio_vec;
int rdma_rw_ctx_init_bvec(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u32 port_num, const struct bio_vec *bvecs, u32 nr_bvec,
struct bvec_iter iter, u64 remote_addr, u32 rkey,
enum dma_data_direction dir);
void rdma_rw_ctx_destroy_bvec(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u32 port_num, const struct bio_vec *bvecs, u32 nr_bvec,
enum dma_data_direction dir);
int rdma_rw_ctx_signature_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u32 port_num, struct scatterlist *sg, u32 sg_cnt,
struct scatterlist *prot_sg, u32 prot_sg_cnt,