Commit 6defafc9 authored by Damiano's avatar Damiano Committed by Tomasz Zawadzki
Browse files

bdev: Add functions to [hole,data] seek



These functions start from a given offset and seek for next
data or for next hole. For bdevs that do not support seeking,
it is assumed that only data and no holes are present

Signed-off-by: default avatarDamiano Cipriani <damiano.cipriani@suse.com>
Change-Id: I6bc831970223333b25683f60ce3fcbbfebb5bb81
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14361


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Community-CI: Mellanox Build Bot
parent d8a3dee1
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -117,6 +117,8 @@ enum spdk_bdev_io_type {
	SPDK_BDEV_IO_TYPE_COMPARE,
	SPDK_BDEV_IO_TYPE_COMPARE_AND_WRITE,
	SPDK_BDEV_IO_TYPE_ABORT,
	SPDK_BDEV_IO_TYPE_SEEK_HOLE,
	SPDK_BDEV_IO_TYPE_SEEK_DATA,
	SPDK_BDEV_NUM_IO_TYPES /* Keep last */
};

@@ -772,6 +774,52 @@ void *spdk_bdev_get_module_ctx(struct spdk_bdev_desc *desc);
 *  These functions will return -ENOMEM if the spdk_bdev_io pool is empty.
 */

/**
 * Submit a data seek request to the bdev on the given channel.
 * Starting from offset_blocks, search for next allocated data:
 * seek result can be obtained with spdk_bdev_io_get_seek_offset
 *
 * \ingroup bdev_io_submit_functions
 *
 * \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 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.
 *   * -EINVAL - offset_blocks is out of range
 *   * -ENOMEM - spdk_bdev_io buffer cannot be allocated
 */
int spdk_bdev_seek_data(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
			uint64_t offset_blocks,
			spdk_bdev_io_completion_cb cb, void *cb_arg);

/**
 * Submit a hole seek request to the bdev on the given channel.
 * Starting from offset_blocks, search for next unallocated hole:
 * seek result can be obtained with spdk_bdev_io_get_seek_offset
 *
 * \ingroup bdev_io_submit_functions
 *
 * \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 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.
 *   * -EINVAL - offset_blocks is out of range
 *   * -ENOMEM - spdk_bdev_io buffer cannot be allocated
 */
int spdk_bdev_seek_hole(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
			uint64_t offset_blocks,
			spdk_bdev_io_completion_cb cb, void *cb_arg);

/**
 * Submit a read request to the bdev on the given channel.
 *
@@ -1818,6 +1866,17 @@ typedef void (*spdk_bdev_histogram_status_cb)(void *cb_arg, int status);
typedef void (*spdk_bdev_histogram_data_cb)(void *cb_arg, int status,
		struct spdk_histogram_data *histogram);

/**
 * Get the result of a previous seek function.
 * After calling spdk_bdev_seek_data or spdk_bdev_seek_hole, call this function
 * to retrieve the offset of next allocated data or next unallocated hole.
 *
 * \param bdev_io I/O to get the status from.
 *
 * \return data/hole offset in blocks or UINT64_MAX if not found
 */
uint64_t spdk_bdev_io_get_seek_offset(const struct spdk_bdev_io *bdev_io);

/**
 * Enable or disable collecting histogram data on a bdev.
 *
+5 −0
Original line number Diff line number Diff line
@@ -620,6 +620,11 @@ struct spdk_bdev_io {
				 */
				void *bio_cb_arg;
			} abort;

			struct {
				/** The offset of next data/hole.  */
				uint64_t offset;
			} seek;
		} bdev;
		struct {
			/** Channel reference held while messages for this reset are in progress. */
+75 −0
Original line number Diff line number Diff line
@@ -4206,6 +4206,81 @@ bdev_io_valid_blocks(struct spdk_bdev *bdev, uint64_t offset_blocks, uint64_t nu
	return true;
}

static void
bdev_seek_complete_cb(void *ctx)
{
	struct spdk_bdev_io *bdev_io = ctx;

	bdev_io->internal.status = SPDK_BDEV_IO_STATUS_SUCCESS;
	bdev_io->internal.cb(bdev_io, true, bdev_io->internal.caller_ctx);
}

static int
bdev_seek(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
	  uint64_t offset_blocks, enum spdk_bdev_io_type io_type,
	  spdk_bdev_io_completion_cb cb, void *cb_arg)
{
	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
	struct spdk_bdev_io *bdev_io;
	struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch);

	assert(io_type == SPDK_BDEV_IO_TYPE_SEEK_DATA || io_type == SPDK_BDEV_IO_TYPE_SEEK_HOLE);

	/* Check if offset_blocks is valid looking at the validity of one block */
	if (!bdev_io_valid_blocks(bdev, offset_blocks, 1)) {
		return -EINVAL;
	}

	bdev_io = bdev_channel_get_io(channel);
	if (!bdev_io) {
		return -ENOMEM;
	}

	bdev_io->internal.ch = channel;
	bdev_io->internal.desc = desc;
	bdev_io->type = io_type;
	bdev_io->u.bdev.offset_blocks = offset_blocks;
	bdev_io_init(bdev_io, bdev, cb_arg, cb);

	if (!spdk_bdev_io_type_supported(bdev, io_type)) {
		/* In case bdev doesn't support seek to next data/hole offset,
		 * it is assumed that only data and no holes are present */
		if (io_type == SPDK_BDEV_IO_TYPE_SEEK_DATA) {
			bdev_io->u.bdev.seek.offset = offset_blocks;
		} else {
			bdev_io->u.bdev.seek.offset = UINT64_MAX;
		}

		spdk_thread_send_msg(spdk_get_thread(), bdev_seek_complete_cb, bdev_io);
		return 0;
	}

	bdev_io_submit(bdev_io);
	return 0;
}

int
spdk_bdev_seek_data(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
		    uint64_t offset_blocks,
		    spdk_bdev_io_completion_cb cb, void *cb_arg)
{
	return bdev_seek(desc, ch, offset_blocks, SPDK_BDEV_IO_TYPE_SEEK_DATA, cb, cb_arg);
}

int
spdk_bdev_seek_hole(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
		    uint64_t offset_blocks,
		    spdk_bdev_io_completion_cb cb, void *cb_arg)
{
	return bdev_seek(desc, ch, offset_blocks, SPDK_BDEV_IO_TYPE_SEEK_HOLE, cb, cb_arg);
}

uint64_t
spdk_bdev_io_get_seek_offset(const struct spdk_bdev_io *bdev_io)
{
	return bdev_io->u.bdev.seek.offset;
}

static int
bdev_read_blocks_with_md(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf,
			 void *md_buf, uint64_t offset_blocks, uint64_t num_blocks,
+3 −0
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@
	spdk_bdev_get_weighted_io_time;
	spdk_bdev_get_io_channel;
	spdk_bdev_get_module_ctx;
	spdk_bdev_seek_data;
	spdk_bdev_seek_hole;
	spdk_bdev_read;
	spdk_bdev_read_blocks;
	spdk_bdev_read_blocks_with_md;
@@ -94,6 +96,7 @@
	spdk_bdev_io_get_iovec;
	spdk_bdev_io_get_md_buf;
	spdk_bdev_io_get_cb_arg;
	spdk_bdev_io_get_seek_offset;
	spdk_bdev_histogram_enable;
	spdk_bdev_histogram_get;
	spdk_bdev_get_media_events;
+85 −0
Original line number Diff line number Diff line
@@ -119,6 +119,9 @@ static uint32_t g_zcopy_read_buf_len;
static void *g_zcopy_write_buf;
static uint32_t g_zcopy_write_buf_len;
static struct spdk_bdev_io *g_zcopy_bdev_io;
static uint64_t g_seek_data_offset;
static uint64_t g_seek_hole_offset;
static uint64_t g_seek_offset;

static struct ut_expected_io *
ut_alloc_expected_io(uint8_t type, uint64_t offset, uint64_t length, int iovcnt)
@@ -239,6 +242,14 @@ stub_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
		}
	}

	if (bdev_io->type == SPDK_BDEV_IO_TYPE_SEEK_DATA) {
		bdev_io->u.bdev.seek.offset = g_seek_data_offset;
	}

	if (bdev_io->type == SPDK_BDEV_IO_TYPE_SEEK_HOLE) {
		bdev_io->u.bdev.seek.offset = g_seek_hole_offset;
	}

	TAILQ_INSERT_TAIL(&ch->outstanding_io, bdev_io, module_link);
	ch->outstanding_io_count++;

@@ -363,6 +374,8 @@ static bool g_io_types_supported[SPDK_BDEV_NUM_IO_TYPES] = {
	[SPDK_BDEV_IO_TYPE_WRITE_ZEROES]	= true,
	[SPDK_BDEV_IO_TYPE_ZCOPY]		= true,
	[SPDK_BDEV_IO_TYPE_ABORT]		= true,
	[SPDK_BDEV_IO_TYPE_SEEK_HOLE]		= true,
	[SPDK_BDEV_IO_TYPE_SEEK_DATA]		= true,
};

static void
@@ -579,6 +592,13 @@ bdev_open_cb4(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *even
	g_event_type4 = type;
}

static void
bdev_seek_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
{
	g_seek_offset = spdk_bdev_io_get_seek_offset(bdev_io);
	spdk_bdev_free_io(bdev_io);
}

static void
get_device_stat_test(void)
{
@@ -5765,6 +5785,70 @@ for_each_bdev_test(void)
	free_bdev(bdev[7]);
}

static void
bdev_seek_test(void)
{
	struct spdk_bdev *bdev;
	struct spdk_bdev_desc *desc = NULL;
	struct spdk_io_channel *io_ch;
	int rc;

	spdk_bdev_initialize(bdev_init_cb, NULL);
	poll_threads();

	bdev = allocate_bdev("bdev0");

	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
	CU_ASSERT(rc == 0);
	poll_threads();
	SPDK_CU_ASSERT_FATAL(desc != NULL);
	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
	io_ch = spdk_bdev_get_io_channel(desc);
	CU_ASSERT(io_ch != NULL);

	/* Seek data not supported */
	ut_enable_io_type(SPDK_BDEV_IO_TYPE_SEEK_DATA, false);
	rc = spdk_bdev_seek_data(desc, io_ch, 0, bdev_seek_cb, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
	poll_threads();
	CU_ASSERT(g_seek_offset == 0);

	/* Seek hole not supported */
	ut_enable_io_type(SPDK_BDEV_IO_TYPE_SEEK_HOLE, false);
	rc = spdk_bdev_seek_hole(desc, io_ch, 0, bdev_seek_cb, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
	poll_threads();
	CU_ASSERT(g_seek_offset == UINT64_MAX);

	/* Seek data supported */
	g_seek_data_offset = 12345;
	ut_enable_io_type(SPDK_BDEV_IO_TYPE_SEEK_DATA, true);
	rc = spdk_bdev_seek_data(desc, io_ch, 0, bdev_seek_cb, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
	stub_complete_io(1);
	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
	CU_ASSERT(g_seek_offset == 12345);

	/* Seek hole supported */
	g_seek_hole_offset = 67890;
	ut_enable_io_type(SPDK_BDEV_IO_TYPE_SEEK_HOLE, true);
	rc = spdk_bdev_seek_hole(desc, io_ch, 0, bdev_seek_cb, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
	stub_complete_io(1);
	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
	CU_ASSERT(g_seek_offset == 67890);

	spdk_put_io_channel(io_ch);
	spdk_bdev_close(desc);
	free_bdev(bdev);
	spdk_bdev_finish(bdev_fini_cb, NULL);
	poll_threads();
}

int
main(int argc, char **argv)
{
@@ -5823,6 +5907,7 @@ main(int argc, char **argv)
	CU_ADD_TEST(suite, bdev_register_uuid_alias);
	CU_ADD_TEST(suite, bdev_unregister_by_name);
	CU_ADD_TEST(suite, for_each_bdev_test);
	CU_ADD_TEST(suite, bdev_seek_test);

	allocate_cores(1);
	allocate_threads(1);