blob: add option to iterate all blobs during spdk_bs_load
blobfs and lvol can now use this to automatically iterate all existing blobs during spdk_bs_load. Changes to blobfs and lvol will come in future patches. This will also be used in some upcoming patches which need to iterate through blobs during load to determine snapshot/clone relationships. Signed-off-by: Jim Harris <james.r.harris@intel.com> Change-Id: Ic7c5fac4535ceaa926217a105dda532517e3e251 Reviewed-on: https://review.gerrithub.io/400177 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Maciej Szwed <maciej.szwed@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
parent
5c2952ab9d
commit
7560f2b2a3
@ -161,6 +161,12 @@ struct spdk_bs_opts {
|
||||
|
||||
/** Blobstore type */
|
||||
struct spdk_bs_type bstype;
|
||||
|
||||
/** Callback function to invoke for each blob. */
|
||||
spdk_blob_op_with_handle_complete iter_cb_fn;
|
||||
|
||||
/** Argument passed to iter_cb_fn for each blob. */
|
||||
void *iter_cb_arg;
|
||||
};
|
||||
|
||||
/* Initialize an spdk_bs_opts structure to the default blobstore option values. */
|
||||
|
@ -1966,6 +1966,8 @@ spdk_bs_opts_init(struct spdk_bs_opts *opts)
|
||||
opts->max_md_ops = SPDK_BLOB_OPTS_MAX_MD_OPS;
|
||||
opts->max_channel_ops = SPDK_BLOB_OPTS_DEFAULT_CHANNEL_OPS;
|
||||
memset(&opts->bstype, 0, sizeof(opts->bstype));
|
||||
opts->iter_cb_fn = NULL;
|
||||
opts->iter_cb_arg = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2062,6 +2064,10 @@ struct spdk_bs_load_ctx {
|
||||
uint32_t cur_page;
|
||||
struct spdk_blob_md_page *page;
|
||||
bool is_load;
|
||||
|
||||
spdk_bs_sequence_t *seq;
|
||||
spdk_blob_op_with_handle_complete iter_cb_fn;
|
||||
void *iter_cb_arg;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -2188,9 +2194,45 @@ _spdk_bs_write_used_blobids(spdk_bs_sequence_t *seq, void *arg, spdk_bs_sequence
|
||||
spdk_bs_sequence_write_dev(seq, ctx->mask, lba, lba_count, cb_fn, arg);
|
||||
}
|
||||
|
||||
static void _spdk_bs_load_complete(spdk_bs_sequence_t *seq, struct spdk_bs_load_ctx *ctx,
|
||||
int bserrno);
|
||||
|
||||
static void
|
||||
_spdk_bs_load_iter(void *arg, struct spdk_blob *blob, int bserrno)
|
||||
{
|
||||
struct spdk_bs_load_ctx *ctx = arg;
|
||||
|
||||
if (bserrno == 0) {
|
||||
ctx->iter_cb_fn(ctx->iter_cb_arg, blob, 0);
|
||||
spdk_bs_iter_next(ctx->bs, blob, _spdk_bs_load_iter, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bserrno == -ENOENT) {
|
||||
bserrno = 0;
|
||||
} else {
|
||||
/*
|
||||
* This case needs to be looked at further. Same problem
|
||||
* exists with applications that rely on explicit blob
|
||||
* iteration. We should just skip the blob that failed
|
||||
* to load and coontinue on to the next one.
|
||||
*/
|
||||
SPDK_ERRLOG("Error in iterating blobs\n");
|
||||
}
|
||||
|
||||
ctx->iter_cb_fn = NULL;
|
||||
_spdk_bs_load_complete(ctx->seq, ctx, bserrno);
|
||||
}
|
||||
|
||||
static void
|
||||
_spdk_bs_load_complete(spdk_bs_sequence_t *seq, struct spdk_bs_load_ctx *ctx, int bserrno)
|
||||
{
|
||||
if (ctx->iter_cb_fn) {
|
||||
ctx->seq = seq;
|
||||
spdk_bs_iter_first(ctx->bs, _spdk_bs_load_iter, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
spdk_dma_free(ctx->super);
|
||||
spdk_dma_free(ctx->mask);
|
||||
free(ctx);
|
||||
@ -2678,6 +2720,8 @@ spdk_bs_load(struct spdk_bs_dev *dev, struct spdk_bs_opts *o,
|
||||
|
||||
ctx->bs = bs;
|
||||
ctx->is_load = true;
|
||||
ctx->iter_cb_fn = opts.iter_cb_fn;
|
||||
ctx->iter_cb_arg = opts.iter_cb_arg;
|
||||
|
||||
/* Allocate memory for the super block */
|
||||
ctx->super = spdk_dma_zmalloc(sizeof(*ctx->super), 0x1000, NULL);
|
||||
|
@ -3087,6 +3087,103 @@ blob_thin_prov_rw_iov(void)
|
||||
g_blobid = 0;
|
||||
}
|
||||
|
||||
struct iter_ctx {
|
||||
int current_iter;
|
||||
spdk_blob_id blobid[4];
|
||||
};
|
||||
|
||||
static void
|
||||
test_iter(void *arg, struct spdk_blob *blob, int bserrno)
|
||||
{
|
||||
struct iter_ctx *iter_ctx = arg;
|
||||
spdk_blob_id blobid;
|
||||
|
||||
CU_ASSERT(bserrno == 0);
|
||||
blobid = spdk_blob_get_id(blob);
|
||||
CU_ASSERT(blobid == iter_ctx->blobid[iter_ctx->current_iter++]);
|
||||
}
|
||||
|
||||
static void
|
||||
bs_load_iter(void)
|
||||
{
|
||||
struct spdk_bs_dev *dev;
|
||||
struct iter_ctx iter_ctx = { 0 };
|
||||
struct spdk_blob *blob;
|
||||
int i, rc;
|
||||
struct spdk_bs_opts opts;
|
||||
|
||||
dev = init_dev();
|
||||
spdk_bs_opts_init(&opts);
|
||||
strncpy(opts.bstype.bstype, "TESTTYPE", SPDK_BLOBSTORE_TYPE_LENGTH);
|
||||
|
||||
/* Initialize a new blob store */
|
||||
spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
|
||||
CU_ASSERT(g_bserrno == 0);
|
||||
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
g_bserrno = -1;
|
||||
g_blobid = SPDK_BLOBID_INVALID;
|
||||
spdk_bs_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
||||
CU_ASSERT(g_bserrno == 0);
|
||||
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
||||
iter_ctx.blobid[i] = g_blobid;
|
||||
|
||||
g_bserrno = -1;
|
||||
g_blob = NULL;
|
||||
spdk_bs_open_blob(g_bs, g_blobid, blob_op_with_handle_complete, NULL);
|
||||
CU_ASSERT(g_bserrno == 0);
|
||||
CU_ASSERT(g_blob != NULL);
|
||||
blob = g_blob;
|
||||
|
||||
/* Just save the blobid as an xattr for testing purposes. */
|
||||
rc = spdk_blob_set_xattr(blob, "blobid", &g_blobid, sizeof(g_blobid));
|
||||
CU_ASSERT(rc == 0);
|
||||
|
||||
/* Resize the blob */
|
||||
rc = spdk_blob_resize(blob, i);
|
||||
CU_ASSERT(rc == 0);
|
||||
|
||||
spdk_blob_close(blob, blob_op_complete, NULL);
|
||||
CU_ASSERT(g_bserrno == 0);
|
||||
}
|
||||
|
||||
g_bserrno = -1;
|
||||
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
||||
CU_ASSERT(g_bserrno == 0);
|
||||
|
||||
dev = init_dev();
|
||||
spdk_bs_opts_init(&opts);
|
||||
strncpy(opts.bstype.bstype, "TESTTYPE", SPDK_BLOBSTORE_TYPE_LENGTH);
|
||||
opts.iter_cb_fn = test_iter;
|
||||
opts.iter_cb_arg = &iter_ctx;
|
||||
|
||||
/* Test blob iteration during load after a clean shutdown. */
|
||||
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
||||
CU_ASSERT(g_bserrno == 0);
|
||||
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
||||
|
||||
/* Dirty shutdown */
|
||||
_spdk_bs_free(g_bs);
|
||||
|
||||
dev = init_dev();
|
||||
spdk_bs_opts_init(&opts);
|
||||
strncpy(opts.bstype.bstype, "TESTTYPE", SPDK_BLOBSTORE_TYPE_LENGTH);
|
||||
opts.iter_cb_fn = test_iter;
|
||||
iter_ctx.current_iter = 0;
|
||||
opts.iter_cb_arg = &iter_ctx;
|
||||
|
||||
/* Test blob iteration during load after a dirty shutdown. */
|
||||
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
||||
CU_ASSERT(g_bserrno == 0);
|
||||
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
||||
|
||||
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
||||
CU_ASSERT(g_bserrno == 0);
|
||||
g_bs = NULL;
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CU_pSuite suite = NULL;
|
||||
@ -3139,7 +3236,8 @@ int main(int argc, char **argv)
|
||||
CU_add_test(suite, "blob_thin_prov_alloc", blob_thin_prov_alloc) == NULL ||
|
||||
CU_add_test(suite, "blob_insert_cluster_msg", blob_insert_cluster_msg) == NULL ||
|
||||
CU_add_test(suite, "blob_thin_prov_rw", blob_thin_prov_rw) == NULL ||
|
||||
CU_add_test(suite, "blob_thin_prov_rw_iov", blob_thin_prov_rw_iov) == NULL
|
||||
CU_add_test(suite, "blob_thin_prov_rw_iov", blob_thin_prov_rw_iov) == NULL ||
|
||||
CU_add_test(suite, "bs_load_iter", bs_load_iter) == NULL
|
||||
) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
|
Loading…
x
Reference in New Issue
Block a user