nvme: add support for write zeroes command

Change-Id: I07ae5805c434d3c06ac24c1a8e09c761b5506ff4
Signed-off-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Haomai Wang 2016-01-12 15:43:24 +08:00 committed by Ben Walker
parent 5578f74dd4
commit 20c767e796
4 changed files with 81 additions and 0 deletions

View File

@ -365,6 +365,7 @@ enum nvme_namespace_flags {
NVME_NS_DEALLOCATE_SUPPORTED = 0x1, /**< The deallocate command is supported */ NVME_NS_DEALLOCATE_SUPPORTED = 0x1, /**< The deallocate command is supported */
NVME_NS_FLUSH_SUPPORTED = 0x2, /**< The flush command is supported */ NVME_NS_FLUSH_SUPPORTED = 0x2, /**< The flush command is supported */
NVME_NS_RESERVATION_SUPPORTED = 0x4, /**< The reservation command is supported */ NVME_NS_RESERVATION_SUPPORTED = 0x4, /**< The reservation command is supported */
NVME_NS_WRITE_ZEROES_SUPPORTED = 0x8, /**< The write zeroes command is supported */
}; };
/** /**
@ -440,6 +441,27 @@ int nvme_ns_cmd_writev(struct nvme_namespace *ns, uint64_t lba, uint32_t lba_cou
nvme_req_reset_sgl_fn_t reset_sgl_fn, nvme_req_reset_sgl_fn_t reset_sgl_fn,
nvme_req_next_sge_fn_t next_sge_fn); nvme_req_next_sge_fn_t next_sge_fn);
/**
* \brief Submits a write zeroes I/O to the specified NVMe namespace.
*
* \param ns NVMe namespace to submit the write zeroes I/O
* \param lba starting LBA for this command
* \param lba_count length (in sectors) for the write zero operation
* \param cb_fn callback function to invoke when the I/O is completed
* \param cb_arg argument to pass to the callback function
* \param io_flags set flags, defined by the NVME_IO_FLAGS_* entries
* in spdk/nvme_spec.h, for this I/O.
*
* \return 0 if successfully submitted, ENOMEM if an nvme_request
* structure cannot be allocated for the I/O request
*
* This function is thread safe and can be called at any point after
* nvme_register_io_thread().
*/
int nvme_ns_cmd_write_zeroes(struct nvme_namespace *ns, uint64_t lba,
uint32_t lba_count, nvme_cb_fn_t cb_fn, void *cb_arg,
uint32_t io_flags);
/** /**
* \brief Submits a read I/O to the specified NVMe namespace. * \brief Submits a read I/O to the specified NVMe namespace.
* *

View File

@ -126,6 +126,10 @@ nvme_ns_construct(struct nvme_namespace *ns, uint16_t id,
ns->flags |= NVME_NS_FLUSH_SUPPORTED; ns->flags |= NVME_NS_FLUSH_SUPPORTED;
} }
if (ctrlr->cdata.oncs.write_zeroes) {
ns->flags |= NVME_NS_WRITE_ZEROES_SUPPORTED;
}
if (nsdata->nsrescap.raw) { if (nsdata->nsrescap.raw) {
ns->flags |= NVME_NS_RESERVATION_SUPPORTED; ns->flags |= NVME_NS_RESERVATION_SUPPORTED;
} }

View File

@ -258,6 +258,38 @@ nvme_ns_cmd_writev(struct nvme_namespace *ns, uint64_t lba, uint32_t lba_count,
} }
} }
int
nvme_ns_cmd_write_zeroes(struct nvme_namespace *ns, uint64_t lba,
uint32_t lba_count, nvme_cb_fn_t cb_fn, void *cb_arg,
uint32_t io_flags)
{
struct nvme_request *req;
struct nvme_command *cmd;
uint64_t *tmp_lba;
if (lba_count == 0) {
return EINVAL;
}
req = nvme_allocate_request_null(cb_fn, cb_arg);
if (req == NULL) {
return ENOMEM;
}
cmd = &req->cmd;
cmd->opc = NVME_OPC_WRITE_ZEROES;
cmd->nsid = ns->id;
tmp_lba = (uint64_t *)&cmd->cdw10;
*tmp_lba = lba;
cmd->cdw12 = lba_count - 1;
cmd->cdw12 |= io_flags;
nvme_ctrlr_submit_io_request(ns->ctrlr, req);
return 0;
}
int int
nvme_ns_cmd_deallocate(struct nvme_namespace *ns, void *payload, nvme_ns_cmd_deallocate(struct nvme_namespace *ns, void *payload,
uint16_t num_ranges, nvme_cb_fn_t cb_fn, void *cb_arg) uint16_t num_ranges, nvme_cb_fn_t cb_fn, void *cb_arg)

View File

@ -331,6 +331,28 @@ test_nvme_ns_cmd_flush(void)
nvme_free_request(g_request); nvme_free_request(g_request);
} }
static void
test_nvme_ns_cmd_write_zeroes(void)
{
struct nvme_namespace ns = { 0 };
struct nvme_controller ctrlr = { 0 };
nvme_cb_fn_t cb_fn = NULL;
void *cb_arg = NULL;
uint64_t cmd_lba;
uint32_t cmd_lba_count;
prepare_for_test(&ns, &ctrlr, 512, 128 * 1024, 0);
nvme_ns_cmd_write_zeroes(&ns, 0, 2, cb_fn, cb_arg, 0);
CU_ASSERT(g_request->cmd.opc == NVME_OPC_WRITE_ZEROES);
CU_ASSERT(g_request->cmd.nsid == ns.id);
nvme_cmd_interpret_rw(&g_request->cmd, &cmd_lba, &cmd_lba_count);
CU_ASSERT_EQUAL(cmd_lba, 0);
CU_ASSERT_EQUAL(cmd_lba_count, 2);
nvme_free_request(g_request);
}
static void static void
test_nvme_ns_cmd_deallocate(void) test_nvme_ns_cmd_deallocate(void)
{ {
@ -426,6 +448,7 @@ int main(int argc, char **argv)
|| CU_add_test(suite, "nvme_ns_cmd_flush testing", test_nvme_ns_cmd_flush) == NULL || CU_add_test(suite, "nvme_ns_cmd_flush testing", test_nvme_ns_cmd_flush) == NULL
|| CU_add_test(suite, "nvme_ns_cmd_deallocate testing", test_nvme_ns_cmd_deallocate) == NULL || CU_add_test(suite, "nvme_ns_cmd_deallocate testing", test_nvme_ns_cmd_deallocate) == NULL
|| CU_add_test(suite, "io_flags", test_io_flags) == NULL || CU_add_test(suite, "io_flags", test_io_flags) == NULL
|| CU_add_test(suite, "nvme_ns_cmd_write_zeroes testing", test_nvme_ns_cmd_write_zeroes) == NULL
) { ) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); return CU_get_error();