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: Damiano Cipriani <damiano.cipriani@suse.com> Change-Id: I6bc831970223333b25683f60ce3fcbbfebb5bb81 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14361 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com> Community-CI: Mellanox Build Bot
This commit is contained in:
parent
d8a3dee1c1
commit
6defafc913
@ -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.
|
||||
*
|
||||
|
@ -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. */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user