Skip to content

Commit 18b6053

Browse files
[RFC] nvme: Add function spdk_nvme_ns_cmd_readv/writev_with_md_ext
These functions accept extendable structure with IO request options. The options structure contains a callback to get a memory key per Io request. This callback is used in RDMA transport. Change-Id: I65bfba279904e77539348520c3dfac7aadbe80d9 Signed-off-by: Alexey Marchuk <alexeymar@mellanox.com>
1 parent 7e1c1f0 commit 18b6053

File tree

4 files changed

+252
-10
lines changed

4 files changed

+252
-10
lines changed

include/spdk/nvme.h

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,6 +2545,90 @@ int spdk_nvme_ns_cmd_writev_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qp
25452545
spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
25462546
uint16_t apptag_mask, uint16_t apptag);
25472547

2548+
/**
2549+
* Callback used to get a Memory Key per IO request
2550+
*
2551+
* pd is input parameter and should point to a memory domain
2552+
* mkey is an output value
2553+
*/
2554+
typedef int (*spdk_nvme_ns_cmd_io_get_mkey)(void *cb_arg, void *address, size_t length, void *pd,
2555+
uint32_t *mkey);
2556+
2557+
enum spdk_nvme_ns_cmd_ext_io_opts_mem_types {
2558+
/** Memory in IO request belongs to another memory domain and it is described by Memory Key.
2559+
* If this value is set then \b mkey structure in spdk_nvme_ns_cmd_ext_io_opts_mem_type contains
2560+
* a callback and its argument that can be used to get a Memory Key */
2561+
SPDK_NVME_NS_CMD_EXT_IO_OPTS_MEM_TYPE_MEMORY_KEY = 0,
2562+
};
2563+
2564+
struct spdk_nvme_ns_cmd_ext_io_opts_mem_type {
2565+
/** This value determines which part of union should be used. Provides extensibility for this structure */
2566+
enum spdk_nvme_ns_cmd_ext_io_opts_mem_types type;
2567+
union {
2568+
struct {
2569+
spdk_nvme_ns_cmd_io_get_mkey get_mkey_cb;
2570+
} mkey;
2571+
} u;
2572+
};
2573+
2574+
enum spdk_nvme_ns_cmd_ext_io_opts_flags {
2575+
/** This flag determines the type of memory passed in IO request.
2576+
* Refer to \ref spdk_nvme_ns_cmd_ext_io_opts_mem_types for more information.
2577+
* If this flag is set in spdk_nvme_ns_cmd_ext_io_opts then \b mem_type member of
2578+
* \b spdk_nvme_ns_cmd_ext_io_opts should point to a structure that describes memory buffer */
2579+
SPDK_NVME_NS_CMD_EXT_IO_OPTS_MEM_TYPE = 1u << 0,
2580+
};
2581+
2582+
/**
2583+
* Structure with optional IO request parameters
2584+
*/
2585+
struct spdk_nvme_ns_cmd_ext_io_opts {
2586+
/** Combination of bits defined in \b enum spdk_nvme_ns_cmd_ext_io_opts_flags */
2587+
uint64_t flags;
2588+
/** Describes type of the memory used in IO request
2589+
* This structure must be filled by the user if \b SPDK_NVME_NS_CMD_EXT_IO_OPTS_MEM_TYPE bit is set
2590+
* in \b flags member. Used by RDMA transport, other transports ignore this extension */
2591+
struct spdk_nvme_ns_cmd_ext_io_opts_mem_type *mem_type;
2592+
};
2593+
2594+
/**
2595+
* Submit a write I/O to the specified NVMe namespace.
2596+
*
2597+
* The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
2598+
* The user must ensure that only one thread submits I/O on a given qpair at any
2599+
* given time.
2600+
*
2601+
* \param ns NVMe namespace to submit the write I/O
2602+
* \param qpair I/O queue pair to submit the request
2603+
* \param lba starting LBA to write the data
2604+
* \param lba_count length (in sectors) for the write operation
2605+
* \param cb_fn callback function to invoke when the I/O is completed
2606+
* \param cb_arg argument to pass to the callback function
2607+
* \param io_flags set flags, defined in nvme_spec.h, for this I/O
2608+
* \param reset_sgl_fn callback function to reset scattered payload
2609+
* \param next_sge_fn callback function to iterate each scattered
2610+
* payload memory segment
2611+
* \param metadata virtual address pointer to the metadata payload, the length
2612+
* of metadata is specified by spdk_nvme_ns_get_md_size()
2613+
* \param apptag_mask application tag mask.
2614+
* \param apptag application tag to use end-to-end protection information.
2615+
* \param opts Optional structure with extended IO request options.
2616+
*
2617+
* \return 0 if successfully submitted, negated errnos on the following error conditions:
2618+
* -EINVAL: The request is malformed.
2619+
* -ENOMEM: The request cannot be allocated.
2620+
* -ENXIO: The qpair is failed at the transport level.
2621+
* -EFAULT: Invalid address was specified as part of payload. cb_fn is also called
2622+
* with error status including dnr=1 in this case.
2623+
*/
2624+
int spdk_nvme_ns_cmd_writev_with_md_ext(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
2625+
uint64_t lba, uint32_t lba_count,
2626+
spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
2627+
spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
2628+
spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
2629+
uint16_t apptag_mask, uint16_t apptag,
2630+
struct spdk_nvme_ns_cmd_ext_io_opts *opts);
2631+
25482632
/**
25492633
* Submit a write I/O to the specified NVMe namespace.
25502634
*
@@ -2725,6 +2809,43 @@ int spdk_nvme_ns_cmd_readv_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpa
27252809
spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
27262810
uint16_t apptag_mask, uint16_t apptag);
27272811

2812+
/**
2813+
* Submit a read I/O to the specified NVMe namespace.
2814+
*
2815+
* The command is submitted to a qpair allocated by spdk_nvme_ctrlr_alloc_io_qpair().
2816+
* The user must ensure that only one thread submits I/O on a given qpair at any given time.
2817+
*
2818+
* \param ns NVMe namespace to submit the read I/O
2819+
* \param qpair I/O queue pair to submit the request
2820+
* \param lba starting LBA to read the data
2821+
* \param lba_count length (in sectors) for the read operation
2822+
* \param cb_fn callback function to invoke when the I/O is completed
2823+
* \param cb_arg argument to pass to the callback function
2824+
* \param io_flags set flags, defined in nvme_spec.h, for this I/O
2825+
* \param reset_sgl_fn callback function to reset scattered payload
2826+
* \param next_sge_fn callback function to iterate each scattered
2827+
* payload memory segment
2828+
* \param metadata virtual address pointer to the metadata payload, the length
2829+
* of metadata is specified by spdk_nvme_ns_get_md_size()
2830+
* \param apptag_mask application tag mask.
2831+
* \param apptag application tag to use end-to-end protection information.
2832+
* \param opts Optional structure with extended IO request options.
2833+
*
2834+
* \return 0 if successfully submitted, negated errnos on the following error conditions:
2835+
* -EINVAL: The request is malformed.
2836+
* -ENOMEM: The request cannot be allocated.
2837+
* -ENXIO: The qpair is failed at the transport level.
2838+
* -EFAULT: Invalid address was specified as part of payload. cb_fn is also called
2839+
* with error status including dnr=1 in this case.
2840+
*/
2841+
int spdk_nvme_ns_cmd_readv_with_md_ext(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
2842+
uint64_t lba, uint32_t lba_count,
2843+
spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
2844+
spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
2845+
spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
2846+
uint16_t apptag_mask, uint16_t apptag,
2847+
struct spdk_nvme_ns_cmd_ext_io_opts *opts);
2848+
27282849
/**
27292850
* Submits a read I/O to the specified NVMe namespace.
27302851
*

lib/nvme/nvme_internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,21 @@ struct nvme_payload {
214214
spdk_nvme_req_reset_sgl_cb reset_sgl_fn;
215215
spdk_nvme_req_next_sge_cb next_sge_fn;
216216

217+
/**
218+
* Function to be used to get an mkey for scattered payload
219+
*/
220+
spdk_nvme_ns_cmd_io_get_mkey get_sge_mkey;
221+
217222
/**
218223
* If reset_sgl_fn == NULL, this is a contig payload, and contig_or_cb_arg contains the
219224
* virtual memory address of a single virtually contiguous buffer.
220225
*
221226
* If reset_sgl_fn != NULL, this is a SGL payload, and contig_or_cb_arg contains the
222227
* cb_arg that will be passed to the SGL callback functions.
228+
*
229+
* If get_sgl_mkey != NULL, this is a SGL payload, and contig_or_cb_arg contains the
230+
* cb_arg that will be passed to the get_sge_mkey callback function. Moreover data returned
231+
* by next_sge_fn and get_sgl_mkey belongs to another memory domain and can not be accessed by SPDK
223232
*/
224233
void *contig_or_cb_arg;
225234

lib/nvme/nvme_ns_cmd.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3232
*/
3333

34+
#include <spdk/nvme.h>
3435
#include "nvme_internal.h"
3536

3637
static inline struct nvme_request *_nvme_ns_cmd_rw(struct spdk_nvme_ns *ns,
@@ -709,6 +710,52 @@ spdk_nvme_ns_cmd_readv_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *
709710
}
710711
}
711712

713+
int
714+
spdk_nvme_ns_cmd_readv_with_md_ext(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
715+
uint64_t lba, uint32_t lba_count,
716+
spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
717+
spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
718+
spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
719+
uint16_t apptag_mask, uint16_t apptag,
720+
struct spdk_nvme_ns_cmd_ext_io_opts *opts)
721+
{
722+
struct nvme_request *req;
723+
struct nvme_payload payload;
724+
725+
if (!_is_io_flags_valid(io_flags)) {
726+
return -EINVAL;
727+
}
728+
729+
if (reset_sgl_fn == NULL || next_sge_fn == NULL) {
730+
return -EINVAL;
731+
}
732+
733+
payload = NVME_PAYLOAD_SGL(reset_sgl_fn, next_sge_fn, cb_arg, metadata);
734+
735+
if (opts) {
736+
if (opts->flags & SPDK_NVME_NS_CMD_EXT_IO_OPTS_MEM_TYPE) {
737+
if (opts->mem_type->type != SPDK_NVME_NS_CMD_EXT_IO_OPTS_MEM_TYPE_MEMORY_KEY) {
738+
SPDK_ERRLOG("Unknown memory type %d\n", opts->mem_type->type);
739+
return -EINVAL;
740+
}
741+
payload.get_sge_mkey = opts->mem_type->u.mkey.get_mkey_cb;
742+
}
743+
}
744+
745+
req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_READ,
746+
io_flags, apptag_mask, apptag, true);
747+
if (req != NULL) {
748+
return nvme_qpair_submit_request(qpair, req);
749+
} else if (nvme_ns_check_request_length(lba_count,
750+
ns->sectors_per_max_io,
751+
ns->sectors_per_stripe,
752+
qpair->ctrlr->opts.io_queue_requests)) {
753+
return -EINVAL;
754+
} else {
755+
return -ENOMEM;
756+
}
757+
}
758+
712759
int
713760
spdk_nvme_ns_cmd_write(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
714761
void *buffer, uint64_t lba,
@@ -836,6 +883,53 @@ spdk_nvme_ns_cmd_writev_with_md(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair
836883
}
837884
}
838885

886+
int
887+
spdk_nvme_ns_cmd_writev_with_md_ext(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
888+
uint64_t lba, uint32_t lba_count,
889+
spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags,
890+
spdk_nvme_req_reset_sgl_cb reset_sgl_fn,
891+
spdk_nvme_req_next_sge_cb next_sge_fn, void *metadata,
892+
uint16_t apptag_mask, uint16_t apptag,
893+
struct spdk_nvme_ns_cmd_ext_io_opts *opts)
894+
{
895+
struct nvme_request *req;
896+
struct nvme_payload payload;
897+
898+
if (!_is_io_flags_valid(io_flags)) {
899+
return -EINVAL;
900+
}
901+
902+
if (reset_sgl_fn == NULL || next_sge_fn == NULL) {
903+
return -EINVAL;
904+
}
905+
906+
payload = NVME_PAYLOAD_SGL(reset_sgl_fn, next_sge_fn, cb_arg, metadata);
907+
908+
if (opts) {
909+
if (opts->flags & SPDK_NVME_NS_CMD_EXT_IO_OPTS_MEM_TYPE) {
910+
if (opts->mem_type->type != SPDK_NVME_NS_CMD_EXT_IO_OPTS_MEM_TYPE_MEMORY_KEY) {
911+
SPDK_ERRLOG("Unknown memory type %d\n", opts->mem_type->type);
912+
return -EINVAL;
913+
}
914+
payload.get_sge_mkey = opts->mem_type->u.mkey.get_mkey_cb;
915+
}
916+
}
917+
918+
req = _nvme_ns_cmd_rw(ns, qpair, &payload, 0, 0, lba, lba_count, cb_fn, cb_arg, SPDK_NVME_OPC_WRITE,
919+
io_flags, apptag_mask, apptag, true);
920+
if (req != NULL) {
921+
return nvme_qpair_submit_request(qpair, req);
922+
} else if (nvme_ns_check_request_length(lba_count,
923+
ns->sectors_per_max_io,
924+
ns->sectors_per_stripe,
925+
qpair->ctrlr->opts.io_queue_requests)) {
926+
return -EINVAL;
927+
} else {
928+
return -ENOMEM;
929+
}
930+
931+
}
932+
839933
int
840934
spdk_nvme_ns_cmd_write_zeroes(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair,
841935
uint64_t lba, uint32_t lba_count,

lib/nvme/nvme_rdma.c

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ nvme_rdma_build_sgl_request(struct nvme_rdma_qpair *rqpair,
15641564
uint32_t remaining_size;
15651565
uint32_t sge_length;
15661566
int rc, max_num_sgl, num_sgl_desc;
1567-
uint32_t rkey = 0;
1567+
uint32_t mkey = 0;
15681568

15691569
assert(req->payload_size != 0);
15701570
assert(nvme_payload_type(&req->payload) == NVME_PAYLOAD_TYPE_SGL);
@@ -1590,12 +1590,21 @@ nvme_rdma_build_sgl_request(struct nvme_rdma_qpair *rqpair,
15901590
return -1;
15911591
}
15921592

1593-
if (spdk_unlikely(!nvme_rdma_get_key(rqpair->mr_map->map, virt_addr, sge_length,
1594-
NVME_RDMA_MR_RKEY, &rkey))) {
1595-
return -1;
1593+
if (req->payload.get_sge_mkey) {
1594+
rc = req->payload.get_sge_mkey(req->payload.contig_or_cb_arg, virt_addr, sge_length,
1595+
rqpair->rdma_qp->qp->pd, &mkey);
1596+
if (spdk_unlikely(rc)) {
1597+
SPDK_ERRLOG("Memory translation failed, rc %d\n", rc);
1598+
return -1;
1599+
}
1600+
} else {
1601+
if (spdk_unlikely(!nvme_rdma_get_key(rqpair->mr_map->map, virt_addr, sge_length,
1602+
NVME_RDMA_MR_RKEY, &mkey))) {
1603+
return -1;
1604+
}
15961605
}
15971606

1598-
cmd->sgl[num_sgl_desc].keyed.key = rkey;
1607+
cmd->sgl[num_sgl_desc].keyed.key = mkey;
15991608
cmd->sgl[num_sgl_desc].keyed.type = SPDK_NVME_SGL_TYPE_KEYED_DATA_BLOCK;
16001609
cmd->sgl[num_sgl_desc].keyed.subtype = SPDK_NVME_SGL_SUBTYPE_ADDRESS;
16011610
cmd->sgl[num_sgl_desc].keyed.length = sge_length;
@@ -1664,7 +1673,7 @@ nvme_rdma_build_sgl_inline_request(struct nvme_rdma_qpair *rqpair,
16641673
struct spdk_nvme_rdma_req *rdma_req)
16651674
{
16661675
struct nvme_request *req = rdma_req->req;
1667-
uint32_t lkey = 0;
1676+
uint32_t mkey = 0;
16681677
uint32_t length;
16691678
void *virt_addr;
16701679
int rc;
@@ -1689,14 +1698,23 @@ nvme_rdma_build_sgl_inline_request(struct nvme_rdma_qpair *rqpair,
16891698
length = req->payload_size;
16901699
}
16911700

1692-
if (spdk_unlikely(!nvme_rdma_get_key(rqpair->mr_map->map, virt_addr, length,
1693-
NVME_RDMA_MR_LKEY, &lkey))) {
1694-
return -1;
1701+
if (req->payload.get_sge_mkey) {
1702+
rc = req->payload.get_sge_mkey(req->payload.contig_or_cb_arg, virt_addr, length,
1703+
rqpair->rdma_qp->qp->pd, &mkey);
1704+
if (spdk_unlikely(rc)) {
1705+
SPDK_ERRLOG("Memory translation failed, rc %d\n", rc);
1706+
return -1;
1707+
}
1708+
} else {
1709+
if (spdk_unlikely(!nvme_rdma_get_key(rqpair->mr_map->map, virt_addr, length,
1710+
NVME_RDMA_MR_LKEY, &mkey))) {
1711+
return -1;
1712+
}
16951713
}
16961714

16971715
rdma_req->send_sgl[1].addr = (uint64_t)virt_addr;
16981716
rdma_req->send_sgl[1].length = length;
1699-
rdma_req->send_sgl[1].lkey = lkey;
1717+
rdma_req->send_sgl[1].lkey = mkey;
17001718

17011719
rdma_req->send_wr.num_sge = 2;
17021720

0 commit comments

Comments
 (0)