bdev: do not reuse bdev_io when splitting write_zeroes

Now that we split on I/O boundaries, that code needs to
be able to use the bdev_io split* members to track
what is left to submit.  This means that the write_zeroes
code cannot submit the parent bdev_io as the child bdev_io,
since the I/O boundary code will overwrite the write_zeroes
split accounting.

Signed-off-by: Jim Harris <james.r.harris@intel.com>
Change-Id: I9316b59267508f60799766fc4f1ea05a4b3e5d9e

Reviewed-on: https://review.gerrithub.io/423404
Reviewed-by: Seth Howell <seth.howell5141@gmail.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Jim Harris 2018-08-23 15:08:17 -07:00 committed by Ben Walker
parent d38b3d28a8
commit 183f37e8ad

View File

@ -259,7 +259,9 @@ struct spdk_bdev_iostat_ctx {
#define __bdev_to_io_dev(bdev) (((char *)bdev) + 1) #define __bdev_to_io_dev(bdev) (((char *)bdev) + 1)
#define __bdev_from_io_dev(io_dev) ((struct spdk_bdev *)(((char *)io_dev) - 1)) #define __bdev_from_io_dev(io_dev) ((struct spdk_bdev *)(((char *)io_dev) - 1))
static void spdk_bdev_write_zeroes_split(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg); static void _spdk_bdev_write_zero_buffer_done(struct spdk_bdev_io *bdev_io, bool success,
void *cb_arg);
static void _spdk_bdev_write_zero_buffer_next(void *_bdev_io);
void void
spdk_bdev_get_opts(struct spdk_bdev_opts *opts) spdk_bdev_get_opts(struct spdk_bdev_opts *opts)
@ -2236,8 +2238,6 @@ spdk_bdev_write_zeroes_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channe
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);
uint64_t len;
bool split_request = false;
if (!desc->write) { if (!desc->write) {
return -EBADF; return -EBADF;
@ -2253,47 +2253,26 @@ spdk_bdev_write_zeroes_blocks(struct spdk_bdev_desc *desc, struct spdk_io_channe
return -ENOMEM; return -ENOMEM;
} }
bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE_ZEROES;
bdev_io->internal.ch = channel; bdev_io->internal.ch = channel;
bdev_io->internal.desc = desc; bdev_io->internal.desc = desc;
bdev_io->u.bdev.offset_blocks = offset_blocks; bdev_io->u.bdev.offset_blocks = offset_blocks;
bdev_io->u.bdev.num_blocks = num_blocks;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb);
if (_spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) { if (_spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) {
bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE_ZEROES; spdk_bdev_io_submit(bdev_io);
bdev_io->u.bdev.num_blocks = num_blocks; return 0;
bdev_io->u.bdev.iovs = NULL;
bdev_io->u.bdev.iovcnt = 0;
} else if (_spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE)) { } else if (_spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE)) {
assert(spdk_bdev_get_block_size(bdev) <= ZERO_BUFFER_SIZE); assert(spdk_bdev_get_block_size(bdev) <= ZERO_BUFFER_SIZE);
bdev_io->u.bdev.split_remaining_num_blocks = num_blocks;
len = spdk_bdev_get_block_size(bdev) * num_blocks; bdev_io->u.bdev.split_current_offset_blocks = offset_blocks;
_spdk_bdev_write_zero_buffer_next(bdev_io);
if (len > ZERO_BUFFER_SIZE) { return 0;
split_request = true;
len = ZERO_BUFFER_SIZE;
}
bdev_io->type = SPDK_BDEV_IO_TYPE_WRITE;
bdev_io->u.bdev.iovs = &bdev_io->iov;
bdev_io->u.bdev.iovs[0].iov_base = g_bdev_mgr.zero_buffer;
bdev_io->u.bdev.iovs[0].iov_len = len;
bdev_io->u.bdev.iovcnt = 1;
bdev_io->u.bdev.num_blocks = len / spdk_bdev_get_block_size(bdev);
bdev_io->u.bdev.split_remaining_num_blocks = num_blocks - bdev_io->u.bdev.num_blocks;
bdev_io->u.bdev.split_current_offset_blocks = offset_blocks + bdev_io->u.bdev.num_blocks;
} else { } else {
spdk_bdev_free_io(bdev_io); spdk_bdev_free_io(bdev_io);
return -ENOTSUP; return -ENOTSUP;
} }
if (split_request) {
bdev_io->u.bdev.stored_user_cb = cb;
spdk_bdev_io_init(bdev_io, bdev, cb_arg, spdk_bdev_write_zeroes_split);
} else {
spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb);
}
spdk_bdev_io_submit(bdev_io);
return 0;
} }
int int
@ -3442,33 +3421,57 @@ spdk_bdev_module_list_find(const char *name)
} }
static void static void
spdk_bdev_write_zeroes_split(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) _spdk_bdev_write_zero_buffer_next(void *_bdev_io)
{ {
uint64_t len; struct spdk_bdev_io *bdev_io = _bdev_io;
uint64_t num_bytes, num_blocks;
int rc;
num_bytes = spdk_min(spdk_bdev_get_block_size(bdev_io->bdev) *
bdev_io->u.bdev.split_remaining_num_blocks,
ZERO_BUFFER_SIZE);
num_blocks = num_bytes / spdk_bdev_get_block_size(bdev_io->bdev);
rc = spdk_bdev_write_blocks(bdev_io->internal.desc,
spdk_io_channel_from_ctx(bdev_io->internal.ch),
g_bdev_mgr.zero_buffer,
bdev_io->u.bdev.split_current_offset_blocks, num_blocks,
_spdk_bdev_write_zero_buffer_done, bdev_io);
if (rc == 0) {
bdev_io->u.bdev.split_remaining_num_blocks -= num_blocks;
bdev_io->u.bdev.split_current_offset_blocks += num_blocks;
} else if (rc == -ENOMEM) {
bdev_io->internal.waitq_entry.bdev = bdev_io->bdev;
bdev_io->internal.waitq_entry.cb_fn = _spdk_bdev_write_zero_buffer_next;
bdev_io->internal.waitq_entry.cb_arg = bdev_io;
spdk_bdev_queue_io_wait(bdev_io->bdev, spdk_io_channel_from_ctx(bdev_io->internal.ch),
&bdev_io->internal.waitq_entry);
} else {
/* This should never happen. */
assert(false);
bdev_io->internal.status = SPDK_BDEV_IO_STATUS_FAILED;
bdev_io->internal.cb(bdev_io, SPDK_BDEV_IO_STATUS_FAILED, bdev_io->internal.caller_ctx);
}
}
static void
_spdk_bdev_write_zero_buffer_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
struct spdk_bdev_io *parent_io = cb_arg;
if (!success) { if (!success) {
bdev_io->internal.cb = bdev_io->u.bdev.stored_user_cb; parent_io->internal.status = SPDK_BDEV_IO_STATUS_FAILED;
_spdk_bdev_io_complete(bdev_io); parent_io->internal.cb(parent_io, SPDK_BDEV_IO_STATUS_FAILED, parent_io->internal.caller_ctx);
return; return;
} }
/* no need to perform the error checking from write_zeroes_blocks because this request already passed those checks. */ if (parent_io->u.bdev.split_remaining_num_blocks == 0) {
len = spdk_min(spdk_bdev_get_block_size(bdev_io->bdev) * bdev_io->u.bdev.split_remaining_num_blocks, parent_io->internal.status = SPDK_BDEV_IO_STATUS_SUCCESS;
ZERO_BUFFER_SIZE); parent_io->internal.cb(parent_io, SPDK_BDEV_IO_STATUS_SUCCESS, parent_io->internal.caller_ctx);
return;
bdev_io->u.bdev.offset_blocks = bdev_io->u.bdev.split_current_offset_blocks;
bdev_io->u.bdev.iovs[0].iov_len = len;
bdev_io->u.bdev.num_blocks = len / spdk_bdev_get_block_size(bdev_io->bdev);
bdev_io->u.bdev.split_remaining_num_blocks -= bdev_io->u.bdev.num_blocks;
bdev_io->u.bdev.split_current_offset_blocks += bdev_io->u.bdev.num_blocks;
/* if this round completes the i/o, change the callback to be the original user callback */
if (bdev_io->u.bdev.split_remaining_num_blocks == 0) {
spdk_bdev_io_init(bdev_io, bdev_io->bdev, cb_arg, bdev_io->u.bdev.stored_user_cb);
} else {
spdk_bdev_io_init(bdev_io, bdev_io->bdev, cb_arg, spdk_bdev_write_zeroes_split);
} }
spdk_bdev_io_submit(bdev_io);
_spdk_bdev_write_zero_buffer_next(parent_io);
} }
struct set_qos_limit_ctx { struct set_qos_limit_ctx {