From 670dc20f6388ee0e5a89bb10638427156cd87142 Mon Sep 17 00:00:00 2001 From: Seth Howell Date: Tue, 1 Aug 2017 11:28:29 -0700 Subject: [PATCH] bdev: add write_zeroes function Add functionality to the bdev layer to handle the nvme write_zeroes function. Change-Id: I0dadad273b28c16db5a2275f7d8d57e98253a8d3 Signed-off-by: Seth Howell Reviewed-on: https://review.gerrithub.io/372171 Tested-by: SPDK Automated Test System Reviewed-by: Ben Walker Reviewed-by: Daniel Verkamp --- CHANGELOG.md | 6 ++++++ include/spdk/bdev.h | 20 ++++++++++++++++++++ lib/bdev/bdev.c | 36 ++++++++++++++++++++++++++++++++++++ lib/bdev/rpc/bdev_rpc.c | 2 ++ 4 files changed, 64 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6b3766e9..d33664516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,16 @@ An [fio](http://github.com/axboe/fio) plugin was added that can route I/O to the bdev layer. See the [plugin documentation](https://github.com/spdk/spdk/blob/master/examples/bdev/fio_plugin/README.md) for more information. +### Block Device Abstraction Layer (bdev) + spdk_bdev_unmap() was modified to take an offset and a length in bytes as arguments instead of requiring the user to provide an array of SCSI unmap descriptors. This limits unmaps to a single contiguous range. +spdk_bdev_write_zeroes() was introduced as an alternative to spdk_bdev_unmap(). +It ensures that all unmapped blocks will be zeroed out. This function is +currently only supported by NVMe block devices. + ### Linux AIO bdev The AIO bdev now allows the user to override the auto-detected block size. diff --git a/include/spdk/bdev.h b/include/spdk/bdev.h index a0f816cfb..1d7c5f77a 100644 --- a/include/spdk/bdev.h +++ b/include/spdk/bdev.h @@ -88,6 +88,7 @@ enum spdk_bdev_io_type { SPDK_BDEV_IO_TYPE_RESET, SPDK_BDEV_IO_TYPE_NVME_ADMIN, SPDK_BDEV_IO_TYPE_NVME_IO, + SPDK_BDEV_IO_TYPE_WRITE_ZEROES, }; /** @@ -329,6 +330,25 @@ int spdk_bdev_writev(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset, uint64_t len, spdk_bdev_io_completion_cb cb, void *cb_arg); +/** + * Submit a write zeroes request to the bdev on the given channel. This command + * ensures that all bytes in the specified range are set to 00h + * + * \param bdev Block device + * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel(). + * \param offset The offset, in bytes, from the start of the block device. + * \param nbytes The number of bytes to zero. + * \param cb Called when the request is complete. + * \param cb_arg Argument passed to cb. + * + * \return 0 on success. On success, the callback will always + * be called (even if the request ultimately failed). Return + * negated errno on failure, in which case the callback will not be called. + */ +int spdk_bdev_write_zeroes(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset, uint64_t len, + spdk_bdev_io_completion_cb cb, void *cb_arg); + /** * Submit an unmap request to the block device. Unmap is sometimes also called trim or * deallocate. This notifies the device that the data in the blocks described is no diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index d106fa0c2..e0a93076f 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -928,6 +928,42 @@ spdk_bdev_writev(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, return 0; } +int +spdk_bdev_write_zeroes(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset, uint64_t len, + spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + int rc; + struct spdk_bdev *bdev = desc->bdev; + struct spdk_bdev_io *bdev_io; + struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch); + + if (!spdk_bdev_io_valid(bdev, offset, len)) { + return -EINVAL; + } + + bdev_io = spdk_bdev_get_io(); + if (!bdev_io) { + SPDK_ERRLOG("bdev_io memory allocation failed duing write_zeroes\n"); + return -ENOMEM; + } + + bdev_io->ch = channel; + bdev_io->u.write.len = len; + bdev_io->u.write.offset = offset; + bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE_ZEROES; + + spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); + + rc = spdk_bdev_io_submit(bdev_io); + if (rc < 0) { + spdk_bdev_put_io(bdev_io); + return rc; + } + + return 0; +} + int spdk_bdev_unmap(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset, uint64_t nbytes, diff --git a/lib/bdev/rpc/bdev_rpc.c b/lib/bdev/rpc/bdev_rpc.c index 317833a03..9dc71f45a 100644 --- a/lib/bdev/rpc/bdev_rpc.c +++ b/lib/bdev/rpc/bdev_rpc.c @@ -82,6 +82,8 @@ spdk_rpc_get_bdevs(struct spdk_jsonrpc_request *request, spdk_json_write_bool(w, spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE)); spdk_json_write_name(w, "unmap"); spdk_json_write_bool(w, spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP)); + spdk_json_write_name(w, "write_zeroes"); + spdk_json_write_bool(w, spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)); spdk_json_write_name(w, "flush"); spdk_json_write_bool(w, spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_FLUSH)); spdk_json_write_name(w, "reset");