From e83f976743b6459fa8d1012f117625330c32ca35 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Mon, 28 Aug 2017 14:55:35 -0700 Subject: [PATCH] bdev: introduce APIs with block units Add new versions of all of the I/O calls that take parameters in blocks instead of bytes. These are intended to replace the old APIs, but we'll keep them for now to preserve compatibility. Change-Id: I85ab665c653e8c697016c628837d49aa0c3bfcd0 Signed-off-by: Daniel Verkamp Reviewed-on: https://review.gerrithub.io/376255 Tested-by: SPDK Automated Test System Reviewed-by: John Kariuki Reviewed-by: Jim Harris Reviewed-by: Dariusz Stojaczyk --- CHANGELOG.md | 7 ++ include/spdk/bdev.h | 147 ++++++++++++++++++++++ lib/bdev/bdev.c | 184 ++++++++++++++++++++++------ test/unit/lib/bdev/bdev.c/bdev_ut.c | 43 +++++-- 4 files changed, 332 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da24f077c..848a56057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,13 @@ 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. +New API functions that accept I/O parameters in units of blocks instead of bytes +have been added: +- spdk_bdev_read_blocks(), spdk_bdev_readv_blocks() +- spdk_bdev_write_blocks(), spdk_bdev_writev_blocks() +- spdk_bdev_write_zeroes_blocks() +- spdk_bdev_unmap_blocks() + ### 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 d1c98aaf2..04ea58a5f 100644 --- a/include/spdk/bdev.h +++ b/include/spdk/bdev.h @@ -270,6 +270,25 @@ int spdk_bdev_read(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf, uint64_t offset, uint64_t nbytes, spdk_bdev_io_completion_cb cb, void *cb_arg); +/** + * Submit a read request to the bdev on the given channel. + * + * \param desc Block device descriptor + * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel(). + * \param buf Data buffer to read into. + * \param offset_blocks The offset, in blocks, from the start of the block device. + * \param num_blocks The number of blocks to read. + * \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_read_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + void *buf, uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg); + /** * Submit a read request to the bdev on the given channel. This differs from * spdk_bdev_read by allowing the data buffer to be described in a scatter @@ -295,6 +314,31 @@ int spdk_bdev_readv(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset, uint64_t nbytes, spdk_bdev_io_completion_cb cb, void *cb_arg); +/** + * Submit a read request to the bdev on the given channel. This differs from + * spdk_bdev_read by allowing the data buffer to be described in a scatter + * gather list. Some physical devices place memory alignment requirements on + * data and may not be able to directly transfer into the buffers provided. In + * this case, the request may fail. + * + * \param desc Block device descriptor + * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel(). + * \param iov A scatter gather list of buffers to be read into. + * \param iovcnt The number of elements in iov. + * \param offset_blocks The offset, in blocks, from the start of the block device. + * \param num_blocks The number of blocks to read. + * \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_readv_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + struct iovec *iov, int iovcnt, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg); + /** * Submit a write request to the bdev on the given channel. * @@ -314,6 +358,25 @@ int spdk_bdev_write(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf, uint64_t offset, uint64_t nbytes, spdk_bdev_io_completion_cb cb, void *cb_arg); +/** + * Submit a write request to the bdev on the given channel. + * + * \param desc Block device descriptor + * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel(). + * \param buf Data buffer to written from. + * \param offset_blocks The offset, in blocks, from the start of the block device. + * \param num_blocks The number of blocks to write. buf must be greater than or equal to this size. + * \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_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + void *buf, uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg); + /** * Submit a write request to the bdev on the given channel. This differs from * spdk_bdev_write by allowing the data buffer to be described in a scatter @@ -339,6 +402,31 @@ 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 request to the bdev on the given channel. This differs from + * spdk_bdev_write by allowing the data buffer to be described in a scatter + * gather list. Some physical devices place memory alignment requirements on + * data and may not be able to directly transfer out of the buffers provided. In + * this case, the request may fail. + * + * \param desc Block device descriptor + * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel(). + * \param iov A scatter gather list of buffers to be written from. + * \param iovcnt The number of elements in iov. + * \param offset_blocks The offset, in blocks, from the start of the block device. + * \param num_blocks The number of blocks to write. buf must be greater than or equal to this size. + * \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_writev_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + struct iovec *iov, int iovcnt, + uint64_t offset_blocks, uint64_t num_blocks, + 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 @@ -358,6 +446,25 @@ int spdk_bdev_write_zeroes(struct spdk_bdev_desc *desc, struct spdk_io_channel * 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 desc Block device descriptor + * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel(). + * \param offset_blocks The offset, in blocks, from the start of the block device. + * \param num_blocks The number of blocks 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_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset_blocks, uint64_t num_blocks, + 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 @@ -378,6 +485,26 @@ int spdk_bdev_unmap(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset, uint64_t nbytes, 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 + * longer valid. Reading blocks that have been unmapped results in indeterminate data. + * + * \param desc Block device descriptor + * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel(). + * \param offset_blocks The offset, in blocks, from the start of the block device. + * \param num_blocks The number of blocks to unmap. + * \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_unmap_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg); + /** * Submit a flush request to the bdev on the given channel. For devices with volatile * caches, data is not guaranteed to be persistent until the completion of a flush @@ -398,6 +525,26 @@ int spdk_bdev_flush(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset, uint64_t length, spdk_bdev_io_completion_cb cb, void *cb_arg); +/** + * Submit a flush request to the bdev on the given channel. For devices with volatile + * caches, data is not guaranteed to be persistent until the completion of a flush + * request. Call spdk_bdev_has_write_cache() to check if the bdev has a volatile cache. + * + * \param desc Block device descriptor + * \param ch I/O channel. Obtained by calling spdk_bdev_get_io_channel(). + * \param offset_blocks The offset, in blocks, from the start of the block device. + * \param num_blocks The number of blocks. + * \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_flush_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg); + /** * Submit a reset request to the bdev on the given channel. * diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index b553b6c02..e97a46107 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -780,27 +780,34 @@ spdk_bdev_has_write_cache(const struct spdk_bdev *bdev) return bdev->write_cache; } -static bool -spdk_bdev_io_valid(struct spdk_bdev *bdev, uint64_t offset, uint64_t nbytes) +/* + * Convert I/O offset and length from bytes to blocks. + * + * Returns zero on success or non-zero if the byte parameters aren't divisible by the block size. + */ +static uint64_t +spdk_bdev_bytes_to_blocks(struct spdk_bdev *bdev, uint64_t offset_bytes, uint64_t *offset_blocks, + uint64_t num_bytes, uint64_t *num_blocks) { - /* Return failure if offset is not a multiple of bdev->blocklen */ - if (offset % bdev->blocklen) { - return false; - } + uint32_t block_size = bdev->blocklen; - /* Return failure if nbytes is not a multiple of bdev->blocklen */ - if (nbytes % bdev->blocklen) { - return false; - } + *offset_blocks = offset_bytes / block_size; + *num_blocks = num_bytes / block_size; - /* Return failure if offset + nbytes is less than offset; indicates there + return (offset_bytes % block_size) | (num_bytes % block_size); +} + +static bool +spdk_bdev_io_valid_blocks(struct spdk_bdev *bdev, uint64_t offset_blocks, uint64_t num_blocks) +{ + /* Return failure if offset_blocks + num_blocks is less than offset_blocks; indicates there * has been an overflow and hence the offset has been wrapped around */ - if (offset + nbytes < offset) { + if (offset_blocks + num_blocks < offset_blocks) { return false; } - /* Return failure if offset + nbytes exceeds the size of the bdev */ - if (offset + nbytes > bdev->blockcnt * bdev->blocklen) { + /* Return failure if offset_blocks + num_blocks exceeds the size of the bdev */ + if (offset_blocks + num_blocks > bdev->blockcnt) { return false; } @@ -811,13 +818,27 @@ int spdk_bdev_read(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf, uint64_t offset, uint64_t nbytes, spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + uint64_t offset_blocks, num_blocks; + + if (spdk_bdev_bytes_to_blocks(desc->bdev, offset, &offset_blocks, nbytes, &num_blocks) != 0) { + return -EINVAL; + } + + return spdk_bdev_read_blocks(desc, ch, buf, offset_blocks, num_blocks, cb, cb_arg); +} + +int +spdk_bdev_read_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + void *buf, uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg) { struct spdk_bdev *bdev = desc->bdev; struct spdk_bdev_io *bdev_io; struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch); int rc; - if (!spdk_bdev_io_valid(bdev, offset, nbytes)) { + if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) { return -EINVAL; } @@ -830,11 +851,11 @@ spdk_bdev_read(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, bdev_io->ch = channel; bdev_io->type = SPDK_BDEV_IO_TYPE_READ; bdev_io->u.read.iov.iov_base = buf; - bdev_io->u.read.iov.iov_len = nbytes; + bdev_io->u.read.iov.iov_len = num_blocks * bdev->blocklen; bdev_io->u.read.iovs = &bdev_io->u.read.iov; bdev_io->u.read.iovcnt = 1; - bdev_io->u.read.num_blocks = nbytes / bdev->blocklen; - bdev_io->u.read.offset_blocks = offset / bdev->blocklen; + bdev_io->u.read.num_blocks = num_blocks; + bdev_io->u.read.offset_blocks = offset_blocks; spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); rc = spdk_bdev_io_submit(bdev_io); @@ -851,13 +872,27 @@ spdk_bdev_readv(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, uint64_t offset, uint64_t nbytes, spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + uint64_t offset_blocks, num_blocks; + + if (spdk_bdev_bytes_to_blocks(desc->bdev, offset, &offset_blocks, nbytes, &num_blocks) != 0) { + return -EINVAL; + } + + return spdk_bdev_readv_blocks(desc, ch, iov, iovcnt, offset_blocks, num_blocks, cb, cb_arg); +} + +int spdk_bdev_readv_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + struct iovec *iov, int iovcnt, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg) { struct spdk_bdev *bdev = desc->bdev; struct spdk_bdev_io *bdev_io; struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch); int rc; - if (!spdk_bdev_io_valid(bdev, offset, nbytes)) { + if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) { return -EINVAL; } @@ -871,8 +906,8 @@ spdk_bdev_readv(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, bdev_io->type = SPDK_BDEV_IO_TYPE_READ; bdev_io->u.read.iovs = iov; bdev_io->u.read.iovcnt = iovcnt; - bdev_io->u.read.num_blocks = nbytes / bdev->blocklen; - bdev_io->u.read.offset_blocks = offset / bdev->blocklen; + bdev_io->u.read.num_blocks = num_blocks; + bdev_io->u.read.offset_blocks = offset_blocks; spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); rc = spdk_bdev_io_submit(bdev_io); @@ -888,6 +923,20 @@ int spdk_bdev_write(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf, uint64_t offset, uint64_t nbytes, spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + uint64_t offset_blocks, num_blocks; + + if (spdk_bdev_bytes_to_blocks(desc->bdev, offset, &offset_blocks, nbytes, &num_blocks) != 0) { + return -EINVAL; + } + + return spdk_bdev_write_blocks(desc, ch, buf, offset_blocks, num_blocks, cb, cb_arg); +} + +int +spdk_bdev_write_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + void *buf, uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg) { struct spdk_bdev *bdev = desc->bdev; struct spdk_bdev_io *bdev_io; @@ -898,7 +947,7 @@ spdk_bdev_write(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, return -EBADF; } - if (!spdk_bdev_io_valid(bdev, offset, nbytes)) { + if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) { return -EINVAL; } @@ -911,11 +960,11 @@ spdk_bdev_write(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, bdev_io->ch = channel; bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE; bdev_io->u.write.iov.iov_base = buf; - bdev_io->u.write.iov.iov_len = nbytes; + bdev_io->u.write.iov.iov_len = num_blocks * bdev->blocklen; bdev_io->u.write.iovs = &bdev_io->u.write.iov; bdev_io->u.write.iovcnt = 1; - bdev_io->u.write.num_blocks = nbytes / bdev->blocklen; - bdev_io->u.write.offset_blocks = offset / bdev->blocklen; + bdev_io->u.write.num_blocks = num_blocks; + bdev_io->u.write.offset_blocks = offset_blocks; spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); rc = spdk_bdev_io_submit(bdev_io); @@ -932,6 +981,21 @@ spdk_bdev_writev(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt, uint64_t offset, uint64_t len, spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + uint64_t offset_blocks, num_blocks; + + if (spdk_bdev_bytes_to_blocks(desc->bdev, offset, &offset_blocks, len, &num_blocks) != 0) { + return -EINVAL; + } + + return spdk_bdev_writev_blocks(desc, ch, iov, iovcnt, offset_blocks, num_blocks, cb, cb_arg); +} + +int +spdk_bdev_writev_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + struct iovec *iov, int iovcnt, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg) { struct spdk_bdev *bdev = desc->bdev; struct spdk_bdev_io *bdev_io; @@ -942,7 +1006,7 @@ spdk_bdev_writev(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, return -EBADF; } - if (!spdk_bdev_io_valid(bdev, offset, len)) { + if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) { return -EINVAL; } @@ -956,8 +1020,8 @@ spdk_bdev_writev(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE; bdev_io->u.write.iovs = iov; bdev_io->u.write.iovcnt = iovcnt; - bdev_io->u.write.num_blocks = len / bdev->blocklen; - bdev_io->u.write.offset_blocks = offset / bdev->blocklen; + bdev_io->u.write.num_blocks = num_blocks; + bdev_io->u.write.offset_blocks = offset_blocks; spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); rc = spdk_bdev_io_submit(bdev_io); @@ -973,13 +1037,27 @@ 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) +{ + uint64_t offset_blocks, num_blocks; + + if (spdk_bdev_bytes_to_blocks(desc->bdev, offset, &offset_blocks, len, &num_blocks) != 0) { + return -EINVAL; + } + + return spdk_bdev_write_zeroes_blocks(desc, ch, offset_blocks, num_blocks, cb, cb_arg); +} + +int +spdk_bdev_write_zeroes_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset_blocks, uint64_t num_blocks, + 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)) { + if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) { return -EINVAL; } @@ -990,8 +1068,8 @@ spdk_bdev_write_zeroes(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, } bdev_io->ch = channel; - bdev_io->u.write.num_blocks = len / bdev->blocklen; - bdev_io->u.write.offset_blocks = offset / bdev->blocklen; + bdev_io->u.write.num_blocks = num_blocks; + bdev_io->u.write.offset_blocks = offset_blocks; bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE_ZEROES; spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); @@ -1009,6 +1087,20 @@ int spdk_bdev_unmap(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset, uint64_t nbytes, spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + uint64_t offset_blocks, num_blocks; + + if (spdk_bdev_bytes_to_blocks(desc->bdev, offset, &offset_blocks, nbytes, &num_blocks) != 0) { + return -EINVAL; + } + + return spdk_bdev_unmap_blocks(desc, ch, offset_blocks, num_blocks, cb, cb_arg); +} + +int +spdk_bdev_unmap_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg) { struct spdk_bdev *bdev = desc->bdev; struct spdk_bdev_io *bdev_io; @@ -1019,11 +1111,11 @@ spdk_bdev_unmap(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, return -EBADF; } - if (!spdk_bdev_io_valid(bdev, offset, nbytes)) { + if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) { return -EINVAL; } - if (nbytes == 0) { + if (num_blocks == 0) { SPDK_ERRLOG("Can't unmap 0 bytes\n"); return -EINVAL; } @@ -1036,8 +1128,8 @@ spdk_bdev_unmap(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, bdev_io->ch = channel; bdev_io->type = SPDK_BDEV_IO_TYPE_UNMAP; - bdev_io->u.unmap.offset_blocks = offset / bdev->blocklen; - bdev_io->u.unmap.num_blocks = nbytes / bdev->blocklen; + bdev_io->u.unmap.offset_blocks = offset_blocks; + bdev_io->u.unmap.num_blocks = num_blocks; spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); rc = spdk_bdev_io_submit(bdev_io); @@ -1053,6 +1145,20 @@ int spdk_bdev_flush(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset, uint64_t length, spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + uint64_t offset_blocks, num_blocks; + + if (spdk_bdev_bytes_to_blocks(desc->bdev, offset, &offset_blocks, length, &num_blocks) != 0) { + return -EINVAL; + } + + return spdk_bdev_flush_blocks(desc, ch, offset_blocks, num_blocks, cb, cb_arg); +} + +int +spdk_bdev_flush_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, + uint64_t offset_blocks, uint64_t num_blocks, + spdk_bdev_io_completion_cb cb, void *cb_arg) { struct spdk_bdev *bdev = desc->bdev; struct spdk_bdev_io *bdev_io; @@ -1063,6 +1169,10 @@ spdk_bdev_flush(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, return -EBADF; } + if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) { + return -EINVAL; + } + bdev_io = spdk_bdev_get_io(); if (!bdev_io) { SPDK_ERRLOG("bdev_io memory allocation failed duing flush\n"); @@ -1071,8 +1181,8 @@ spdk_bdev_flush(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, bdev_io->ch = channel; bdev_io->type = SPDK_BDEV_IO_TYPE_FLUSH; - bdev_io->u.flush.offset_blocks = offset / bdev->blocklen; - bdev_io->u.flush.num_blocks = length / bdev->blocklen; + bdev_io->u.flush.offset_blocks = offset_blocks; + bdev_io->u.flush.num_blocks = num_blocks; spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); rc = spdk_bdev_io_submit(bdev_io); diff --git a/test/unit/lib/bdev/bdev.c/bdev_ut.c b/test/unit/lib/bdev/bdev.c/bdev_ut.c index c1f82de20..167cadb7d 100644 --- a/test/unit/lib/bdev/bdev.c/bdev_ut.c +++ b/test/unit/lib/bdev/bdev.c/bdev_ut.c @@ -302,6 +302,30 @@ open_write_test(void) } +static void +bytes_to_blocks_test(void) +{ + struct spdk_bdev bdev; + uint64_t offset_blocks, num_blocks; + + memset(&bdev, 0, sizeof(bdev)); + + bdev.blocklen = 512; + + /* All parameters valid */ + offset_blocks = 0; + num_blocks = 0; + CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 512, &offset_blocks, 1024, &num_blocks) == 0); + CU_ASSERT(offset_blocks == 1); + CU_ASSERT(num_blocks == 2); + + /* Offset not a block multiple */ + CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 3, &offset_blocks, 512, &num_blocks) != 0); + + /* Length not a block multiple */ + CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 512, &offset_blocks, 3, &num_blocks) != 0); +} + static void io_valid_test(void) { @@ -313,25 +337,19 @@ io_valid_test(void) bdev.blockcnt = 100; /* All parameters valid */ - CU_ASSERT(spdk_bdev_io_valid(&bdev, 512, 1024) == true); - - /* Offset not a block multiple */ - CU_ASSERT(spdk_bdev_io_valid(&bdev, 3, 512) == false); - - /* Length not a block multiple */ - CU_ASSERT(spdk_bdev_io_valid(&bdev, 512, 3) == false); + CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 1, 2) == true); /* Last valid block */ - CU_ASSERT(spdk_bdev_io_valid(&bdev, 50688, 512) == true); + CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 99, 1) == true); /* Offset past end of bdev */ - CU_ASSERT(spdk_bdev_io_valid(&bdev, 51200, 512) == false); + CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 100, 1) == false); /* Offset + length past end of bdev */ - CU_ASSERT(spdk_bdev_io_valid(&bdev, 50688, 1024) == false); + CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 99, 2) == false); - /* Offset near end of uint64_t range (2^64 - 512) */ - CU_ASSERT(spdk_bdev_io_valid(&bdev, 18446744073709551104ULL, 512) == false); + /* Offset near end of uint64_t range (2^64 - 1) */ + CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 18446744073709551615ULL, 1) == false); } int @@ -351,6 +369,7 @@ main(int argc, char **argv) } if ( + CU_add_test(suite, "bytes_to_blocks_test", bytes_to_blocks_test) == NULL || CU_add_test(suite, "io_valid", io_valid_test) == NULL || CU_add_test(suite, "open_write", open_write_test) == NULL ) {