Commit 4b92ffb3 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Changpeng Liu
Browse files

bdev: Not assert but pass completion status to spdk_bdev_io_get_buf_cb



When the specified buffer size to spdk_bdev_io_get_buf() is greater
than the permitted maximum, spdk_bdev_io_get_buf() asserts simply and
doesn't call the specified callback function.

SPDK SCSI library doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().

Bdev perf tool also doesn't allocate read buffer and specifies
expected read buffer size, and expects that it is allocated by
spdk_bdev_io_get_buf().

When we support DIF insert and strip in iSCSI target, the read
buffer size iSCSI initiator requests and the read buffer size iSCSI target
requests will become different.

Even after that, iSCSI initiator and iSCSI target will negotiate correctly
not to cause buffer overflow in spdk_bdev_io_get_buf(), but if iSCSI
initiator ignores the result of negotiation, iSCSI initiator can request
read buffer size larger than the permitted maximum, and can cause
failure in iSCSI target. This is very flagile and should be avoided.

This patch do the following
- Add the completion status of spdk_bdev_io_get_buf() to
  spdk_bdev_io_get_buf_cb(),
- spdk_bdev_io_get_buf() calls spdk_bdev_io_get_buf_cb() by setting
  success to false, and return.
- spdk_bdev_io_get_buf_cb() in each bdev module calls assert if success
  is false.

Subsequent patches will process the case that success is false
in spdk_bdev_io_get_buf_cb().

Change-Id: I76429a86e18a69aa085a353ac94743296d270b82
Signed-off-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-on: https://review.gerrithub.io/c/446045


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarZiye Yang <ziye.yang@intel.com>
Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
parent 518c8add
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -396,7 +396,17 @@ struct spdk_bdev {
	} internal;
};

typedef void (*spdk_bdev_io_get_buf_cb)(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io);
/**
 * Callback when buffer is allocated for the bdev I/O.
 *
 * \param ch The I/O channel the bdev I/O was handled on.
 * \param bdev_io The bdev I/O
 * \param success True if buffer is allocated successfully or the bdev I/O has an SGL
 * assigned already, or false if it failed. The possible reason of failure is the size
 * of the buffer to allocate is greater than the permitted maximum.
 */
typedef void (*spdk_bdev_io_get_buf_cb)(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
					bool success);

#define BDEV_IO_NUM_CHILD_IOV 32

+5 −1
Original line number Diff line number Diff line
@@ -394,8 +394,12 @@ bdev_aio_reset(struct file_disk *fdisk, struct bdev_aio_task *aio_task)
	bdev_aio_reset_retry_timer(fdisk);
}

static void bdev_aio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
static void
bdev_aio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
		    bool success)
{
	assert(success == true);

	switch (bdev_io->type) {
	case SPDK_BDEV_IO_TYPE_READ:
		bdev_aio_readv((struct file_disk *)bdev_io->bdev->ctxt,
+20 −5
Original line number Diff line number Diff line
@@ -549,7 +549,7 @@ spdk_bdev_io_put_buf(struct spdk_bdev_io *bdev_io)

		STAILQ_REMOVE_HEAD(stailq, internal.buf_link);
		tmp->internal.buf = buf;
		tmp->internal.get_buf_cb(tmp->internal.ch->channel, tmp);
		tmp->internal.get_buf_cb(tmp->internal.ch->channel, tmp, true);
	}
}

@@ -591,11 +591,17 @@ spdk_bdev_io_get_buf(struct spdk_bdev_io *bdev_io, spdk_bdev_io_get_buf_cb cb, u
	if (buf_allocated &&
	    _are_iovs_aligned(bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, alignment)) {
		/* Buffer already present and aligned */
		cb(bdev_io->internal.ch->channel, bdev_io);
		cb(bdev_io->internal.ch->channel, bdev_io, true);
		return;
	}

	if (len + alignment > SPDK_BDEV_LARGE_BUF_MAX_SIZE + SPDK_BDEV_POOL_ALIGNMENT) {
		SPDK_ERRLOG("Length + alignment %" PRIu64 " is larger than allowed\n",
			    len + alignment);
		cb(bdev_io->internal.ch->channel, bdev_io, false);
		return;
	}

	assert(len + alignment <= SPDK_BDEV_LARGE_BUF_MAX_SIZE + SPDK_BDEV_POOL_ALIGNMENT);
	mgmt_ch = bdev_io->internal.ch->shared_resource->mgmt_ch;

	bdev_io->internal.buf_len = len;
@@ -622,7 +628,7 @@ spdk_bdev_io_get_buf(struct spdk_bdev_io *bdev_io, spdk_bdev_io_get_buf_cb cb, u
			spdk_bdev_io_set_buf(bdev_io, aligned_buf, len);
		}
		bdev_io->internal.buf = buf;
		bdev_io->internal.get_buf_cb(bdev_io->internal.ch->channel, bdev_io);
		bdev_io->internal.get_buf_cb(bdev_io->internal.ch->channel, bdev_io, true);
	}
}

@@ -1647,6 +1653,15 @@ _spdk_bdev_io_split(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
	_spdk_bdev_io_split_with_payload(bdev_io);
}

static void
_spdk_bdev_io_split_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
			       bool success)
{
	assert(success == true);

	_spdk_bdev_io_split(ch, bdev_io);
}

/* Explicitly mark this inline, since it's used as a function pointer and otherwise won't
 *  be inlined, at least on some compilers.
 */
@@ -1699,7 +1714,7 @@ spdk_bdev_io_submit(struct spdk_bdev_io *bdev_io)

	if (bdev->split_on_optimal_io_boundary && _spdk_bdev_io_should_split(bdev_io)) {
		if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
			spdk_bdev_io_get_buf(bdev_io, _spdk_bdev_io_split,
			spdk_bdev_io_get_buf(bdev_io, _spdk_bdev_io_split_get_buf_cb,
					     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
		} else {
			_spdk_bdev_io_split(NULL, bdev_io);
+4 −1
Original line number Diff line number Diff line
@@ -905,13 +905,16 @@ _complete_internal_read(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg
 * beneath us before we're done with it.
 */
static void
crypto_read_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
crypto_read_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
		       bool success)
{
	struct vbdev_crypto *crypto_bdev = SPDK_CONTAINEROF(bdev_io->bdev, struct vbdev_crypto,
					   crypto_bdev);
	struct crypto_io_channel *crypto_ch = spdk_io_channel_get_ctx(ch);
	int rc;

	assert(success == true);

	rc = spdk_bdev_readv_blocks(crypto_bdev->base_desc, crypto_ch->base_ch, bdev_io->u.bdev.iovs,
				    bdev_io->u.bdev.iovcnt, bdev_io->u.bdev.offset_blocks,
				    bdev_io->u.bdev.num_blocks, _complete_internal_read,
+4 −1
Original line number Diff line number Diff line
@@ -312,8 +312,11 @@ bdev_ftl_writev(struct ftl_bdev *ftl_bdev, struct spdk_io_channel *ch,
}

static void
bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
		    bool success)
{
	assert(success == true);

	int rc = bdev_ftl_readv((struct ftl_bdev *)bdev_io->bdev->ctxt,
				ch, (struct ftl_bdev_io *)bdev_io->driver_ctx);

Loading