diff --git a/CHANGELOG.md b/CHANGELOG.md index db08296a6..2e2fa44b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -131,6 +131,9 @@ names with this option to restrict allowed RPCs to only that list. Added `--vfio-vf-token` command line option to specify a VF token (UUID) shared between SR-IOV PF and VFs for vfio_pci driver. +The `spdk_iov_xfer_*()` APIs were added for handling incremental copying between +an iovec and a buffer. + ### json Added API `spdk_json_write_double` and `spdk_json_write_named_double` to allow diff --git a/include/spdk/util.h b/include/spdk/util.h index 08ff353ce..3cb053250 100644 --- a/include/spdk/util.h +++ b/include/spdk/util.h @@ -169,6 +169,37 @@ size_t spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_ */ size_t spdk_iovmove(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt); +/** + * Transfer state for iterative copying in or out of an iovec. + */ +struct spdk_iov_xfer { + struct iovec *iovs; + int iovcnt; + int cur_iov_idx; + size_t cur_iov_offset; +}; + +/** + * Initialize a transfer context to point to the given iovec. + */ +void +spdk_iov_xfer_init(struct spdk_iov_xfer *ix, struct iovec *iovs, int iovcnt); + +/** + * Copy from the given buf up to buf_len bytes, into the given ix iovec + * iterator, advancing the iterator as needed.. Returns the number of bytes + * copied. + */ +size_t +spdk_iov_xfer_from_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len); + +/** + * Copy from the given ix iovec iterator into the given buf up to buf_len + * bytes, advancing the iterator as needed. Returns the number of bytes copied. + */ +size_t +spdk_iov_xfer_to_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len); + /** * Copy iovs contents to buf through memcpy. */ diff --git a/lib/nvmf/ctrlr.c b/lib/nvmf/ctrlr.c index 504a8af1b..ca1265c67 100644 --- a/lib/nvmf/ctrlr.c +++ b/lib/nvmf/ctrlr.c @@ -53,56 +53,6 @@ static struct spdk_nvmf_custom_admin_cmd g_nvmf_custom_admin_cmd_hdlrs[SPDK_NVME static void _nvmf_request_complete(void *ctx); -struct copy_iovs_ctx { - struct iovec *iovs; - int iovcnt; - int cur_iov_idx; - size_t cur_iov_offset; -}; - -static void -_init_copy_iovs_ctx(struct copy_iovs_ctx *copy_ctx, struct iovec *iovs, int iovcnt) -{ - copy_ctx->iovs = iovs; - copy_ctx->iovcnt = iovcnt; - copy_ctx->cur_iov_idx = 0; - copy_ctx->cur_iov_offset = 0; -} - -static size_t -_copy_buf_to_iovs(struct copy_iovs_ctx *copy_ctx, const void *buf, size_t buf_len) -{ - size_t len, iov_remain_len, copied_len = 0; - struct iovec *iov; - - if (buf_len == 0) { - return 0; - } - - while (copy_ctx->cur_iov_idx < copy_ctx->iovcnt) { - iov = ©_ctx->iovs[copy_ctx->cur_iov_idx]; - iov_remain_len = iov->iov_len - copy_ctx->cur_iov_offset; - if (iov_remain_len == 0) { - copy_ctx->cur_iov_idx++; - copy_ctx->cur_iov_offset = 0; - continue; - } - - len = spdk_min(iov_remain_len, buf_len - copied_len); - memcpy((char *)iov->iov_base + copy_ctx->cur_iov_offset, - (const char *)buf + copied_len, - len); - copied_len += len; - copy_ctx->cur_iov_offset += len; - - if (buf_len == copied_len) { - return copied_len; - } - } - - return copied_len; -} - static inline void nvmf_invalid_connect_response(struct spdk_nvmf_fabric_connect_rsp *rsp, uint8_t iattr, uint16_t ipo) @@ -1712,7 +1662,7 @@ nvmf_ctrlr_get_features_host_identifier(struct spdk_nvmf_request *req) struct spdk_nvmf_ctrlr *ctrlr = req->qpair->ctrlr; struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; - struct copy_iovs_ctx copy_ctx; + struct spdk_iov_xfer ix; SPDK_DEBUGLOG(nvmf, "Get Features - Host Identifier\n"); @@ -1723,14 +1673,14 @@ nvmf_ctrlr_get_features_host_identifier(struct spdk_nvmf_request *req) return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } - if (req->data == NULL || req->length < sizeof(ctrlr->hostid)) { + if (req->iovcnt < 1 || req->length < sizeof(ctrlr->hostid)) { SPDK_ERRLOG("Invalid data buffer for Get Features - Host Identifier\n"); response->status.sc = SPDK_NVME_SC_INVALID_FIELD; return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } - _init_copy_iovs_ctx(©_ctx, req->iov, req->iovcnt); - _copy_buf_to_iovs(©_ctx, &ctrlr->hostid, sizeof(ctrlr->hostid)); + spdk_iov_xfer_init(&ix, req->iov, req->iovcnt); + spdk_iov_xfer_from_buf(&ix, &ctrlr->hostid, sizeof(ctrlr->hostid)); return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } @@ -1858,11 +1808,11 @@ nvmf_ctrlr_get_features_host_behavior_support(struct spdk_nvmf_request *req) struct spdk_nvmf_ctrlr *ctrlr = req->qpair->ctrlr; struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; struct spdk_nvme_host_behavior host_behavior = {}; - struct copy_iovs_ctx copy_ctx; + struct spdk_iov_xfer ix; SPDK_DEBUGLOG(nvmf, "Get Features - Host Behavior Support\n"); - if (req->data == NULL || req->length < sizeof(struct spdk_nvme_host_behavior)) { + if (req->iovcnt < 1 || req->length < sizeof(struct spdk_nvme_host_behavior)) { SPDK_ERRLOG("invalid data buffer for Host Behavior Support\n"); response->status.sct = SPDK_NVME_SCT_GENERIC; response->status.sc = SPDK_NVME_SC_INVALID_FIELD; @@ -1871,8 +1821,8 @@ nvmf_ctrlr_get_features_host_behavior_support(struct spdk_nvmf_request *req) host_behavior.acre = ctrlr->acre_enabled; - _init_copy_iovs_ctx(©_ctx, req->iov, req->iovcnt); - _copy_buf_to_iovs(©_ctx, &host_behavior, sizeof(host_behavior)); + spdk_iov_xfer_init(&ix, req->iov, req->iovcnt); + spdk_iov_xfer_from_buf(&ix, &host_behavior, sizeof(host_behavior)); return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } @@ -2151,9 +2101,9 @@ nvmf_get_firmware_slot_log_page(struct iovec *iovs, int iovcnt, uint64_t offset, { struct spdk_nvme_firmware_page fw_page; size_t copy_len; - struct copy_iovs_ctx copy_ctx; + struct spdk_iov_xfer ix; - _init_copy_iovs_ctx(©_ctx, iovs, iovcnt); + spdk_iov_xfer_init(&ix, iovs, iovcnt); memset(&fw_page, 0, sizeof(fw_page)); fw_page.afi.active_slot = 1; @@ -2163,7 +2113,7 @@ nvmf_get_firmware_slot_log_page(struct iovec *iovs, int iovcnt, uint64_t offset, if (offset < sizeof(fw_page)) { copy_len = spdk_min(sizeof(fw_page) - offset, length); if (copy_len > 0) { - _copy_buf_to_iovs(©_ctx, (const char *)&fw_page + offset, copy_len); + spdk_iov_xfer_from_buf(&ix, (const char *)&fw_page + offset, copy_len); } } } @@ -2259,9 +2209,9 @@ nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iov size_t copy_len, copied_len; uint32_t num_anagrp = 0, anagrpid; struct spdk_nvmf_ns *ns; - struct copy_iovs_ctx copy_ctx; + struct spdk_iov_xfer ix; - _init_copy_iovs_ctx(©_ctx, iovs, iovcnt); + spdk_iov_xfer_init(&ix, iovs, iovcnt); if (length == 0) { goto done; @@ -2283,7 +2233,7 @@ nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iov ana_hdr.change_count = 0; copy_len = spdk_min(sizeof(ana_hdr) - offset, length); - copied_len = _copy_buf_to_iovs(©_ctx, (const char *)&ana_hdr + offset, copy_len); + copied_len = spdk_iov_xfer_from_buf(&ix, (const char *)&ana_hdr + offset, copy_len); assert(copied_len == copy_len); length -= copied_len; offset = 0; @@ -2308,8 +2258,8 @@ nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iov ana_desc.ana_state = nvmf_ctrlr_get_ana_state(ctrlr, anagrpid); copy_len = spdk_min(sizeof(ana_desc) - offset, length); - copied_len = _copy_buf_to_iovs(©_ctx, (const char *)&ana_desc + offset, - copy_len); + copied_len = spdk_iov_xfer_from_buf(&ix, (const char *)&ana_desc + offset, + copy_len); assert(copied_len == copy_len); length -= copied_len; offset = 0; @@ -2334,8 +2284,8 @@ nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iov } copy_len = spdk_min(sizeof(uint32_t) - offset, length); - copied_len = _copy_buf_to_iovs(©_ctx, (const char *)&ns->nsid + offset, - copy_len); + copied_len = spdk_iov_xfer_from_buf(&ix, (const char *)&ns->nsid + offset, + copy_len); assert(copied_len == copy_len); length -= copied_len; offset = 0; @@ -2385,14 +2335,14 @@ nvmf_get_changed_ns_list_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iovcnt, uint64_t offset, uint32_t length, uint32_t rae) { size_t copy_length; - struct copy_iovs_ctx copy_ctx; + struct spdk_iov_xfer ix; - _init_copy_iovs_ctx(©_ctx, iovs, iovcnt); + spdk_iov_xfer_init(&ix, iovs, iovcnt); if (offset < sizeof(ctrlr->changed_ns_list)) { copy_length = spdk_min(length, sizeof(ctrlr->changed_ns_list) - offset); if (copy_length) { - _copy_buf_to_iovs(©_ctx, (char *)&ctrlr->changed_ns_list + offset, copy_length); + spdk_iov_xfer_from_buf(&ix, (char *)&ctrlr->changed_ns_list + offset, copy_length); } } @@ -2450,11 +2400,11 @@ nvmf_get_cmds_and_effects_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec * { uint32_t page_size = sizeof(struct spdk_nvme_cmds_and_effect_log_page); size_t copy_len = 0; - struct copy_iovs_ctx copy_ctx; struct spdk_nvme_cmds_and_effect_log_page cmds_and_effect_log_page = g_cmds_and_effect_log_page; struct spdk_nvme_cmds_and_effect_entry csupp_and_lbcc_effect_entry = {1, 1, 0, 0, 0, 0, 0, 0}; + struct spdk_iov_xfer ix; - _init_copy_iovs_ctx(©_ctx, iovs, iovcnt); + spdk_iov_xfer_init(&ix, iovs, iovcnt); if (offset < page_size) { if (ctrlr->subsys->zone_append_supported) { @@ -2462,7 +2412,7 @@ nvmf_get_cmds_and_effects_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec * csupp_and_lbcc_effect_entry; } copy_len = spdk_min(page_size - offset, length); - _copy_buf_to_iovs(©_ctx, (char *)(&cmds_and_effect_log_page) + offset, copy_len); + spdk_iov_xfer_from_buf(&ix, (char *)(&cmds_and_effect_log_page) + offset, copy_len); } } @@ -2472,9 +2422,9 @@ nvmf_get_reservation_notification_log_page(struct spdk_nvmf_ctrlr *ctrlr, { uint32_t unit_log_len, avail_log_len, next_pos, copy_len; struct spdk_nvmf_reservation_log *log, *log_tmp; - struct copy_iovs_ctx copy_ctx; + struct spdk_iov_xfer ix; - _init_copy_iovs_ctx(©_ctx, iovs, iovcnt); + spdk_iov_xfer_init(&ix, iovs, iovcnt); unit_log_len = sizeof(struct spdk_nvme_reservation_notification_log); /* No available log, return zeroed log pages */ @@ -2495,7 +2445,7 @@ nvmf_get_reservation_notification_log_page(struct spdk_nvmf_ctrlr *ctrlr, next_pos += unit_log_len; if (next_pos > offset) { copy_len = spdk_min(next_pos - offset, length); - _copy_buf_to_iovs(©_ctx, &log->log, copy_len); + spdk_iov_xfer_from_buf(&ix, &log->log, copy_len); length -= copy_len; offset += copy_len; } @@ -3055,9 +3005,9 @@ nvmf_ctrlr_identify(struct spdk_nvmf_request *req) struct spdk_nvmf_subsystem *subsystem = ctrlr->subsys; int ret = SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; char tmpbuf[SPDK_NVME_IDENTIFY_BUFLEN] = ""; - struct copy_iovs_ctx copy_ctx; + struct spdk_iov_xfer ix; - if (req->data == NULL || req->length < SPDK_NVME_IDENTIFY_BUFLEN) { + if (req->iovcnt < 1 || req->length < SPDK_NVME_IDENTIFY_BUFLEN) { SPDK_DEBUGLOG(nvmf, "identify command with invalid buffer\n"); rsp->status.sct = SPDK_NVME_SCT_GENERIC; rsp->status.sc = SPDK_NVME_SC_INVALID_FIELD; @@ -3076,7 +3026,7 @@ nvmf_ctrlr_identify(struct spdk_nvmf_request *req) * We must use a temporary buffer: it's entirely possible the out buffer * is split across more than one IOV. */ - _init_copy_iovs_ctx(©_ctx, req->iov, req->iovcnt); + spdk_iov_xfer_init(&ix, req->iov, req->iovcnt); SPDK_DEBUGLOG(nvmf, "Received identify command with CNS 0x%02x\n", cns); @@ -3105,7 +3055,7 @@ nvmf_ctrlr_identify(struct spdk_nvmf_request *req) } if (ret == SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE) { - _copy_buf_to_iovs(©_ctx, tmpbuf, sizeof(tmpbuf)); + spdk_iov_xfer_from_buf(&ix, tmpbuf, sizeof(tmpbuf)); } return ret; diff --git a/lib/nvmf/ctrlr_bdev.c b/lib/nvmf/ctrlr_bdev.c index d50e7b401..3a48709f2 100644 --- a/lib/nvmf/ctrlr_bdev.c +++ b/lib/nvmf/ctrlr_bdev.c @@ -581,7 +581,7 @@ nvmf_bdev_ctrlr_unmap(struct spdk_bdev *bdev, struct spdk_bdev_desc *desc, uint16_t nr, i; struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; - struct spdk_nvme_dsm_range *dsm_range; + struct spdk_iov_xfer ix; uint64_t lba; uint32_t lba_count; int rc; @@ -611,10 +611,15 @@ nvmf_bdev_ctrlr_unmap(struct spdk_bdev *bdev, struct spdk_bdev_desc *desc, unmap_ctx->count--; /* dequeued */ } - dsm_range = (struct spdk_nvme_dsm_range *)req->data; + spdk_iov_xfer_init(&ix, req->iov, req->iovcnt); + for (i = unmap_ctx->range_index; i < nr; i++) { - lba = dsm_range[i].starting_lba; - lba_count = dsm_range[i].length; + struct spdk_nvme_dsm_range dsm_range = { 0 }; + + spdk_iov_xfer_to_buf(&ix, &dsm_range, sizeof(dsm_range)); + + lba = dsm_range.starting_lba; + lba_count = dsm_range.length; unmap_ctx->count++; @@ -667,7 +672,8 @@ nvmf_bdev_ctrlr_copy_cmd(struct spdk_bdev *bdev, struct spdk_bdev_desc *desc, struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; uint64_t sdlba = ((uint64_t)cmd->cdw11 << 32) + cmd->cdw10; - struct spdk_nvme_scc_source_range *range; + struct spdk_nvme_scc_source_range range = { 0 }; + struct spdk_iov_xfer ix; int rc; SPDK_DEBUGLOG(nvmf, "Copy command: SDLBA %lu, NR %u, desc format %u, PRINFOR %u, " @@ -696,7 +702,10 @@ nvmf_bdev_ctrlr_copy_cmd(struct spdk_bdev *bdev, struct spdk_bdev_desc *desc, return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } - /* We support only one source range */ + /* + * We support only one source range, and rely on this with the xfer + * below. + */ if (cmd->cdw12_bits.copy.nr > 0) { response->status.sct = SPDK_NVME_SCT_COMMAND_SPECIFIC; response->status.sc = SPDK_NVME_SC_CMD_SIZE_LIMIT_SIZE_EXCEEDED; @@ -709,8 +718,10 @@ nvmf_bdev_ctrlr_copy_cmd(struct spdk_bdev *bdev, struct spdk_bdev_desc *desc, return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } - range = req->data; - rc = spdk_bdev_copy_blocks(desc, ch, sdlba, range->slba, range->nlb + 1, + spdk_iov_xfer_init(&ix, req->iov, req->iovcnt); + spdk_iov_xfer_to_buf(&ix, &range, sizeof(range)); + + rc = spdk_bdev_copy_blocks(desc, ch, sdlba, range.slba, range.nlb + 1, nvmf_bdev_ctrlr_complete_cmd, req); if (spdk_unlikely(rc)) { if (rc == -ENOMEM) { diff --git a/lib/util/iov.c b/lib/util/iov.c index 032021a7f..2f3fe216e 100644 --- a/lib/util/iov.c +++ b/lib/util/iov.c @@ -143,32 +143,80 @@ spdk_iovmove(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diov return total_sz; } +void +spdk_iov_xfer_init(struct spdk_iov_xfer *ix, struct iovec *iovs, int iovcnt) +{ + ix->iovs = iovs; + ix->iovcnt = iovcnt; + ix->cur_iov_idx = 0; + ix->cur_iov_offset = 0; +} + +static size_t +iov_xfer(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len, bool to_buf) +{ + size_t len, iov_remain_len, copied_len = 0; + struct iovec *iov; + + if (buf_len == 0) { + return 0; + } + + while (ix->cur_iov_idx < ix->iovcnt) { + iov = &ix->iovs[ix->cur_iov_idx]; + iov_remain_len = iov->iov_len - ix->cur_iov_offset; + if (iov_remain_len == 0) { + ix->cur_iov_idx++; + ix->cur_iov_offset = 0; + continue; + } + + len = spdk_min(iov_remain_len, buf_len - copied_len); + + if (to_buf) { + memcpy((char *)buf + copied_len, + iov->iov_base + ix->cur_iov_offset, len); + } else { + memcpy((char *)iov->iov_base + ix->cur_iov_offset, + (const char *)buf + copied_len, len); + } + copied_len += len; + ix->cur_iov_offset += len; + + if (buf_len == copied_len) { + return copied_len; + } + } + + return copied_len; +} + +size_t +spdk_iov_xfer_from_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len) +{ + return iov_xfer(ix, buf, buf_len, false); +} + +size_t +spdk_iov_xfer_to_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len) +{ + return iov_xfer(ix, buf, buf_len, true); +} + void spdk_copy_iovs_to_buf(void *buf, size_t buf_len, struct iovec *iovs, int iovcnt) { - int i; - size_t len; + struct spdk_iov_xfer ix; - for (i = 0; i < iovcnt; i++) { - len = spdk_min(iovs[i].iov_len, buf_len); - memcpy(buf, iovs[i].iov_base, len); - buf += len; - assert(buf_len >= len); - buf_len -= len; - } + spdk_iov_xfer_init(&ix, iovs, iovcnt); + spdk_iov_xfer_to_buf(&ix, buf, buf_len); } void spdk_copy_buf_to_iovs(struct iovec *iovs, int iovcnt, void *buf, size_t buf_len) { - int i; - size_t len; + struct spdk_iov_xfer ix; - for (i = 0; i < iovcnt; i++) { - len = spdk_min(iovs[i].iov_len, buf_len); - memcpy(iovs[i].iov_base, buf, len); - buf += len; - assert(buf_len >= len); - buf_len -= len; - } + spdk_iov_xfer_init(&ix, iovs, iovcnt); + spdk_iov_xfer_from_buf(&ix, buf, buf_len); } diff --git a/lib/util/spdk_util.map b/lib/util/spdk_util.map index ee0564f27..962c14b7a 100644 --- a/lib/util/spdk_util.map +++ b/lib/util/spdk_util.map @@ -137,6 +137,9 @@ spdk_ioviter_next; spdk_iov_memset; spdk_iov_one; + spdk_iov_xfer_init; + spdk_iov_xfer_from_buf; + spdk_iov_xfer_to_buf; spdk_copy_iovs_to_buf; spdk_copy_buf_to_iovs; spdk_memset_s; diff --git a/test/unit/lib/util/iov.c/iov_ut.c b/test/unit/lib/util/iov.c/iov_ut.c index b8e2a312b..9d3677708 100644 --- a/test/unit/lib/util/iov.c/iov_ut.c +++ b/test/unit/lib/util/iov.c/iov_ut.c @@ -281,6 +281,52 @@ test_iov_one(void) CU_ASSERT(iovcnt == 1); } +static void +test_iov_xfer(void) +{ + struct spdk_iov_xfer ix; + uint8_t data[64] = { 0 }; + uint8_t iov_buffer[64]; + struct iovec iov[4]; + size_t i; + + for (i = 0; i < sizeof(iov_buffer); i++) { + iov_buffer[i] = i; + } + + iov[0].iov_base = iov_buffer; + iov[0].iov_len = 5; + iov[1].iov_base = iov[0].iov_base + iov[0].iov_len; + iov[1].iov_len = 15; + iov[2].iov_base = iov[1].iov_base + iov[1].iov_len; + iov[2].iov_len = 21; + iov[3].iov_base = iov[2].iov_base + iov[2].iov_len; + iov[3].iov_len = 23; + + spdk_iov_xfer_init(&ix, iov, 4); + + spdk_iov_xfer_to_buf(&ix, data, 8); + spdk_iov_xfer_to_buf(&ix, data + 8, 56); + + for (i = 0; i < sizeof(data); i++) { + CU_ASSERT(data[i] == i); + } + + for (i = 0; i < sizeof(data); i++) { + data[i] = sizeof(data) - i; + } + + spdk_iov_xfer_init(&ix, iov, 4); + + spdk_iov_xfer_from_buf(&ix, data, 5); + spdk_iov_xfer_from_buf(&ix, data + 5, 3); + spdk_iov_xfer_from_buf(&ix, data + 8, 56); + + for (i = 0; i < sizeof(iov_buffer); i++) { + CU_ASSERT(iov_buffer[i] == sizeof(iov_buffer) - i); + } +} + int main(int argc, char **argv) { @@ -299,6 +345,7 @@ main(int argc, char **argv) CU_ADD_TEST(suite, test_buf_to_iovs); CU_ADD_TEST(suite, test_memset); CU_ADD_TEST(suite, test_iov_one); + CU_ADD_TEST(suite, test_iov_xfer); CU_basic_set_mode(CU_BRM_VERBOSE);