Commit 7560f2b2 authored by Jim Harris's avatar Jim Harris
Browse files

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: default avatarJim Harris <james.r.harris@intel.com>
Change-Id: Ic7c5fac4535ceaa926217a105dda532517e3e251

Reviewed-on: https://review.gerrithub.io/400177


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarMaciej Szwed <maciej.szwed@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
parent 5c2952ab
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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. */
+44 −0
Original line number Diff line number Diff line
@@ -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);
+99 −1
Original line number Diff line number Diff line
@@ -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();