Commit effe7a01 authored by Artur Paszkiewicz's avatar Artur Paszkiewicz Committed by Tomasz Zawadzki
Browse files

bdev: make quiesce work also for read I/O



The quiesce API is based on range lock functionality, which ignores read
I/O by design because it was meant for compare and write. However,
quiesce should work for all I/O - also reads.

Change-Id: I2d81173d1e41e80a6de0b5d69b2dd7c7f761b66c
Signed-off-by: default avatarArtur Paszkiewicz <artur.paszkiewicz@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/21153


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
parent 70c6a99e
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ struct lba_range {
	struct spdk_bdev		*bdev;
	uint64_t			offset;
	uint64_t			length;
	bool				quiesce;
	void				*locked_ctx;
	struct spdk_thread		*owner_thread;
	struct spdk_bdev_channel	*owner_ch;
@@ -3492,6 +3493,11 @@ bdev_io_range_is_locked(struct spdk_bdev_io *bdev_io, struct lba_range *range)
		 * it overlaps a locked range.
		 */
		return true;
	case SPDK_BDEV_IO_TYPE_READ:
		if (!range->quiesce) {
			return false;
		}
	/* fallthrough */
	case SPDK_BDEV_IO_TYPE_WRITE:
	case SPDK_BDEV_IO_TYPE_UNMAP:
	case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
@@ -9623,6 +9629,7 @@ bdev_lock_lba_range_get_channel(struct spdk_bdev_channel_iter *i, struct spdk_bd
	range->length = ctx->range.length;
	range->offset = ctx->range.offset;
	range->locked_ctx = ctx->range.locked_ctx;
	range->quiesce = ctx->range.quiesce;
	ctx->current_range = range;
	if (ctx->range.owner_ch == ch) {
		/* This is the range object for the channel that will hold
@@ -9660,6 +9667,8 @@ bdev_lba_range_overlaps_tailq(struct lba_range *range, lba_range_tailq_t *tailq)
	return false;
}

static void bdev_quiesce_range_locked(struct lba_range *range, void *ctx, int status);

static int
_bdev_lock_lba_range(struct spdk_bdev *bdev, struct spdk_bdev_channel *ch,
		     uint64_t offset, uint64_t length,
@@ -9678,6 +9687,7 @@ _bdev_lock_lba_range(struct spdk_bdev *bdev, struct spdk_bdev_channel *ch,
	ctx->range.owner_ch = ch;
	ctx->range.locked_ctx = cb_arg;
	ctx->range.bdev = bdev;
	ctx->range.quiesce = (cb_fn == bdev_quiesce_range_locked);
	ctx->cb_fn = cb_fn;
	ctx->cb_arg = cb_arg;

+47 −0
Original line number Diff line number Diff line
@@ -5201,6 +5201,7 @@ bdev_quiesce(void)
	struct spdk_io_channel *io_ch;
	struct spdk_bdev_channel *channel;
	struct lba_range *range;
	struct spdk_bdev_io *bdev_io;
	int ctx1;
	int rc;

@@ -5284,6 +5285,52 @@ bdev_quiesce(void)
	CU_ASSERT(g_lock_lba_range_done == true);
	CU_ASSERT(g_unlock_lba_range_done == true);

	/* Test quiesce with read I/O */
	g_lock_lba_range_done = false;
	g_unlock_lba_range_done = false;
	g_io_done = false;
	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 20, 1, io_done, &ctx1);
	CU_ASSERT(rc == 0);

	rc = spdk_bdev_quiesce(bdev, &bdev_ut_if, bdev_quiesce_done, &ctx1);
	CU_ASSERT(rc == 0);
	poll_threads();

	CU_ASSERT(g_io_done == false);
	CU_ASSERT(g_lock_lba_range_done == false);
	range = TAILQ_FIRST(&channel->locked_ranges);
	SPDK_CU_ASSERT_FATAL(range != NULL);

	stub_complete_io(1);
	spdk_delay_us(100);
	poll_threads();
	CU_ASSERT(g_io_done == true);
	CU_ASSERT(g_lock_lba_range_done == true);
	CU_ASSERT(TAILQ_EMPTY(&channel->io_locked));

	g_io_done = false;
	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 20, 1, io_done, &ctx1);
	CU_ASSERT(rc == 0);

	bdev_io = TAILQ_FIRST(&channel->io_locked);
	SPDK_CU_ASSERT_FATAL(bdev_io != NULL);
	CU_ASSERT(bdev_io->u.bdev.offset_blocks == 20);
	CU_ASSERT(bdev_io->u.bdev.num_blocks == 1);

	rc = spdk_bdev_unquiesce(bdev, &bdev_ut_if, bdev_unquiesce_done, &ctx1);
	CU_ASSERT(rc == 0);
	spdk_delay_us(100);
	poll_threads();

	CU_ASSERT(g_unlock_lba_range_done == true);
	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
	CU_ASSERT(TAILQ_EMPTY(&bdev_ut_if.internal.quiesced_ranges));

	CU_ASSERT(TAILQ_EMPTY(&channel->io_locked));
	spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
	poll_threads();
	CU_ASSERT(g_io_done == true);

	spdk_put_io_channel(io_ch);
	spdk_bdev_close(desc);
	free_bdev(bdev);