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:
Jim Harris 2018-02-15 13:46:41 -07:00
parent 5c2952ab9d
commit 7560f2b2a3
3 changed files with 149 additions and 1 deletions

View File

@ -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. */

View File

@ -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);

View File

@ -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();