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 <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/376255
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: John Kariuki <John.K.Kariuki@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
This commit is contained in:
Daniel Verkamp 2017-08-28 14:55:35 -07:00
parent 7394f69054
commit e83f976743
4 changed files with 332 additions and 49 deletions

View File

@ -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 It ensures that all unmapped blocks will be zeroed out. This function is
currently only supported by NVMe block devices. 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 ### Linux AIO bdev
The AIO bdev now allows the user to override the auto-detected block size. The AIO bdev now allows the user to override the auto-detected block size.

View File

@ -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, void *buf, uint64_t offset, uint64_t nbytes,
spdk_bdev_io_completion_cb cb, void *cb_arg); 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 * 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 * 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, uint64_t offset, uint64_t nbytes,
spdk_bdev_io_completion_cb cb, void *cb_arg); 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. * 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, void *buf, uint64_t offset, uint64_t nbytes,
spdk_bdev_io_completion_cb cb, void *cb_arg); 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 * 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 * 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, uint64_t offset, uint64_t len,
spdk_bdev_io_completion_cb cb, void *cb_arg); 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 * 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 * 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, uint64_t offset, uint64_t len,
spdk_bdev_io_completion_cb cb, void *cb_arg); 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 * 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 * 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, uint64_t offset, uint64_t nbytes,
spdk_bdev_io_completion_cb cb, void *cb_arg); 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 * 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 * 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, uint64_t offset, uint64_t length,
spdk_bdev_io_completion_cb cb, void *cb_arg); 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. * Submit a reset request to the bdev on the given channel.
* *

View File

@ -780,27 +780,34 @@ spdk_bdev_has_write_cache(const struct spdk_bdev *bdev)
return bdev->write_cache; 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 */ uint32_t block_size = bdev->blocklen;
if (offset % bdev->blocklen) {
return false; *offset_blocks = offset_bytes / block_size;
*num_blocks = num_bytes / block_size;
return (offset_bytes % block_size) | (num_bytes % block_size);
} }
/* Return failure if nbytes is not a multiple of bdev->blocklen */ static bool
if (nbytes % bdev->blocklen) { spdk_bdev_io_valid_blocks(struct spdk_bdev *bdev, uint64_t offset_blocks, uint64_t num_blocks)
return false; {
} /* Return failure if offset_blocks + num_blocks is less than offset_blocks; indicates there
/* Return failure if offset + nbytes is less than offset; indicates there
* has been an overflow and hence the offset has been wrapped around */ * 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 false;
} }
/* Return failure if offset + nbytes exceeds the size of the bdev */ /* Return failure if offset_blocks + num_blocks exceeds the size of the bdev */
if (offset + nbytes > bdev->blockcnt * bdev->blocklen) { if (offset_blocks + num_blocks > bdev->blockcnt) {
return false; return false;
} }
@ -811,13 +818,27 @@ int
spdk_bdev_read(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, spdk_bdev_read(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
void *buf, uint64_t offset, uint64_t nbytes, void *buf, uint64_t offset, uint64_t nbytes,
spdk_bdev_io_completion_cb cb, void *cb_arg) 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 *bdev = desc->bdev;
struct spdk_bdev_io *bdev_io; struct spdk_bdev_io *bdev_io;
struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch); struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch);
int rc; int rc;
if (!spdk_bdev_io_valid(bdev, offset, nbytes)) { if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) {
return -EINVAL; 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->ch = channel;
bdev_io->type = SPDK_BDEV_IO_TYPE_READ; bdev_io->type = SPDK_BDEV_IO_TYPE_READ;
bdev_io->u.read.iov.iov_base = buf; 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.iovs = &bdev_io->u.read.iov;
bdev_io->u.read.iovcnt = 1; bdev_io->u.read.iovcnt = 1;
bdev_io->u.read.num_blocks = nbytes / bdev->blocklen; bdev_io->u.read.num_blocks = num_blocks;
bdev_io->u.read.offset_blocks = offset / bdev->blocklen; bdev_io->u.read.offset_blocks = offset_blocks;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb);
rc = spdk_bdev_io_submit(bdev_io); 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, struct iovec *iov, int iovcnt,
uint64_t offset, uint64_t nbytes, uint64_t offset, uint64_t nbytes,
spdk_bdev_io_completion_cb cb, void *cb_arg) 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 *bdev = desc->bdev;
struct spdk_bdev_io *bdev_io; struct spdk_bdev_io *bdev_io;
struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch); struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch);
int rc; int rc;
if (!spdk_bdev_io_valid(bdev, offset, nbytes)) { if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) {
return -EINVAL; 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->type = SPDK_BDEV_IO_TYPE_READ;
bdev_io->u.read.iovs = iov; bdev_io->u.read.iovs = iov;
bdev_io->u.read.iovcnt = iovcnt; bdev_io->u.read.iovcnt = iovcnt;
bdev_io->u.read.num_blocks = nbytes / bdev->blocklen; bdev_io->u.read.num_blocks = num_blocks;
bdev_io->u.read.offset_blocks = offset / bdev->blocklen; bdev_io->u.read.offset_blocks = offset_blocks;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb);
rc = spdk_bdev_io_submit(bdev_io); 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, spdk_bdev_write(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
void *buf, uint64_t offset, uint64_t nbytes, void *buf, uint64_t offset, uint64_t nbytes,
spdk_bdev_io_completion_cb cb, void *cb_arg) 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 *bdev = desc->bdev;
struct spdk_bdev_io *bdev_io; 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; return -EBADF;
} }
if (!spdk_bdev_io_valid(bdev, offset, nbytes)) { if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) {
return -EINVAL; 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->ch = channel;
bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE; bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE;
bdev_io->u.write.iov.iov_base = buf; 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.iovs = &bdev_io->u.write.iov;
bdev_io->u.write.iovcnt = 1; bdev_io->u.write.iovcnt = 1;
bdev_io->u.write.num_blocks = nbytes / bdev->blocklen; bdev_io->u.write.num_blocks = num_blocks;
bdev_io->u.write.offset_blocks = offset / bdev->blocklen; bdev_io->u.write.offset_blocks = offset_blocks;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb);
rc = spdk_bdev_io_submit(bdev_io); 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, struct iovec *iov, int iovcnt,
uint64_t offset, uint64_t len, uint64_t offset, uint64_t len,
spdk_bdev_io_completion_cb cb, void *cb_arg) 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 *bdev = desc->bdev;
struct spdk_bdev_io *bdev_io; 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; return -EBADF;
} }
if (!spdk_bdev_io_valid(bdev, offset, len)) { if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) {
return -EINVAL; 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->type = SPDK_BDEV_IO_TYPE_WRITE;
bdev_io->u.write.iovs = iov; bdev_io->u.write.iovs = iov;
bdev_io->u.write.iovcnt = iovcnt; bdev_io->u.write.iovcnt = iovcnt;
bdev_io->u.write.num_blocks = len / bdev->blocklen; bdev_io->u.write.num_blocks = num_blocks;
bdev_io->u.write.offset_blocks = offset / bdev->blocklen; bdev_io->u.write.offset_blocks = offset_blocks;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb);
rc = spdk_bdev_io_submit(bdev_io); 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, spdk_bdev_write_zeroes(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
uint64_t offset, uint64_t len, uint64_t offset, uint64_t len,
spdk_bdev_io_completion_cb cb, void *cb_arg) 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; int rc;
struct spdk_bdev *bdev = desc->bdev; struct spdk_bdev *bdev = desc->bdev;
struct spdk_bdev_io *bdev_io; struct spdk_bdev_io *bdev_io;
struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch); 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; 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->ch = channel;
bdev_io->u.write.num_blocks = len / bdev->blocklen; bdev_io->u.write.num_blocks = num_blocks;
bdev_io->u.write.offset_blocks = offset / bdev->blocklen; bdev_io->u.write.offset_blocks = offset_blocks;
bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE_ZEROES; bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE_ZEROES;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); 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, spdk_bdev_unmap(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
uint64_t offset, uint64_t nbytes, uint64_t offset, uint64_t nbytes,
spdk_bdev_io_completion_cb cb, void *cb_arg) 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 *bdev = desc->bdev;
struct spdk_bdev_io *bdev_io; 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; return -EBADF;
} }
if (!spdk_bdev_io_valid(bdev, offset, nbytes)) { if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) {
return -EINVAL; return -EINVAL;
} }
if (nbytes == 0) { if (num_blocks == 0) {
SPDK_ERRLOG("Can't unmap 0 bytes\n"); SPDK_ERRLOG("Can't unmap 0 bytes\n");
return -EINVAL; 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->ch = channel;
bdev_io->type = SPDK_BDEV_IO_TYPE_UNMAP; bdev_io->type = SPDK_BDEV_IO_TYPE_UNMAP;
bdev_io->u.unmap.offset_blocks = offset / bdev->blocklen; bdev_io->u.unmap.offset_blocks = offset_blocks;
bdev_io->u.unmap.num_blocks = nbytes / bdev->blocklen; bdev_io->u.unmap.num_blocks = num_blocks;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb);
rc = spdk_bdev_io_submit(bdev_io); 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, spdk_bdev_flush(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
uint64_t offset, uint64_t length, uint64_t offset, uint64_t length,
spdk_bdev_io_completion_cb cb, void *cb_arg) 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 *bdev = desc->bdev;
struct spdk_bdev_io *bdev_io; 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; return -EBADF;
} }
if (!spdk_bdev_io_valid_blocks(bdev, offset_blocks, num_blocks)) {
return -EINVAL;
}
bdev_io = spdk_bdev_get_io(); bdev_io = spdk_bdev_get_io();
if (!bdev_io) { if (!bdev_io) {
SPDK_ERRLOG("bdev_io memory allocation failed duing flush\n"); 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->ch = channel;
bdev_io->type = SPDK_BDEV_IO_TYPE_FLUSH; bdev_io->type = SPDK_BDEV_IO_TYPE_FLUSH;
bdev_io->u.flush.offset_blocks = offset / bdev->blocklen; bdev_io->u.flush.offset_blocks = offset_blocks;
bdev_io->u.flush.num_blocks = length / bdev->blocklen; bdev_io->u.flush.num_blocks = num_blocks;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb);
rc = spdk_bdev_io_submit(bdev_io); rc = spdk_bdev_io_submit(bdev_io);

View File

@ -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 static void
io_valid_test(void) io_valid_test(void)
{ {
@ -313,25 +337,19 @@ io_valid_test(void)
bdev.blockcnt = 100; bdev.blockcnt = 100;
/* All parameters valid */ /* All parameters valid */
CU_ASSERT(spdk_bdev_io_valid(&bdev, 512, 1024) == true); CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 1, 2) == 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);
/* Last valid block */ /* 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 */ /* 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 */ /* 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) */ /* Offset near end of uint64_t range (2^64 - 1) */
CU_ASSERT(spdk_bdev_io_valid(&bdev, 18446744073709551104ULL, 512) == false); CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 18446744073709551615ULL, 1) == false);
} }
int int
@ -351,6 +369,7 @@ main(int argc, char **argv)
} }
if ( 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, "io_valid", io_valid_test) == NULL ||
CU_add_test(suite, "open_write", open_write_test) == NULL CU_add_test(suite, "open_write", open_write_test) == NULL
) { ) {