Commit e6100af4 authored by Maciej Szwed's avatar Maciej Szwed Committed by Jim Harris
Browse files

blobstore: block simultaneous operations on blobs



Block operation that should not be done simultaneously.

Signed-off-by: default avatarMaciej Szwed <maciej.szwed@intel.com>
Change-Id: I3cab510377a49be4e5847ba37a6218f0025c0db6

Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/450014


Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 478c2e6f
Loading
Loading
Loading
Loading
+42 −2
Original line number Diff line number Diff line
@@ -4296,6 +4296,8 @@ _spdk_bs_snapshot_unfreeze_cpl(void *cb_arg, int bserrno)
	}

	ctx->original.id = origblob->id;
	origblob->locked_operation_in_progress = false;

	spdk_blob_close(origblob, _spdk_bs_clone_snapshot_cleanup_finish, ctx);
}

@@ -4533,10 +4535,20 @@ _spdk_bs_snapshot_origblob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int b
	if (_blob->data_ro || _blob->md_ro) {
		SPDK_DEBUGLOG(SPDK_LOG_BLOB, "Cannot create snapshot from read only blob with id %lu\n",
			      _blob->id);
		_spdk_bs_clone_snapshot_origblob_cleanup(ctx, -EINVAL);
		ctx->bserrno = -EINVAL;
		spdk_blob_close(_blob, _spdk_bs_clone_snapshot_cleanup_finish, ctx);
		return;
	}

	if (_blob->locked_operation_in_progress) {
		SPDK_DEBUGLOG(SPDK_LOG_BLOB, "Cannot create snapshot - another operation in progress\n");
		ctx->bserrno = -EBUSY;
		spdk_blob_close(_blob, _spdk_bs_clone_snapshot_cleanup_finish, ctx);
		return;
	}

	_blob->locked_operation_in_progress = true;

	spdk_blob_opts_init(&opts);
	_spdk_blob_xattrs_init(&internal_xattrs);

@@ -4633,10 +4645,20 @@ _spdk_bs_clone_origblob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bser

	if (!_blob->data_ro || !_blob->md_ro) {
		SPDK_DEBUGLOG(SPDK_LOG_BLOB, "Clone not from read-only blob\n");
		_spdk_bs_clone_snapshot_origblob_cleanup(ctx, -EINVAL);
		ctx->bserrno = -EINVAL;
		spdk_blob_close(_blob, _spdk_bs_clone_snapshot_cleanup_finish, ctx);
		return;
	}

	if (_blob->locked_operation_in_progress) {
		SPDK_DEBUGLOG(SPDK_LOG_BLOB, "Cannot create clone - another operation in progress\n");
		ctx->bserrno = -EBUSY;
		spdk_blob_close(_blob, _spdk_bs_clone_snapshot_cleanup_finish, ctx);
		return;
	}

	_blob->locked_operation_in_progress = true;

	spdk_blob_opts_init(&opts);
	_spdk_blob_xattrs_init(&internal_xattrs);

@@ -4812,8 +4834,18 @@ _spdk_bs_inflate_blob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bserrn
		_spdk_bs_clone_snapshot_cleanup_finish(ctx, bserrno);
		return;
	}

	ctx->original.blob = _blob;

	if (_blob->locked_operation_in_progress) {
		SPDK_DEBUGLOG(SPDK_LOG_BLOB, "Cannot inflate blob - another operation in progress\n");
		ctx->bserrno = -EBUSY;
		spdk_blob_close(_blob, _spdk_bs_clone_snapshot_cleanup_finish, ctx);
		return;
	}

	_blob->locked_operation_in_progress = true;

	if (!ctx->allocate_all && _blob->parent_id == SPDK_BLOBID_INVALID) {
		/* This blob have no parent, so we cannot decouple it. */
		SPDK_ERRLOG("Cannot decouple parent of blob with no parent.\n");
@@ -5060,6 +5092,14 @@ _spdk_bs_delete_open_cpl(void *cb_arg, struct spdk_blob *blob, int bserrno)
		return;
	}

	if (blob->locked_operation_in_progress) {
		SPDK_DEBUGLOG(SPDK_LOG_BLOB, "Cannot remove blob - another operation in progress\n");
		spdk_blob_close(blob, _spdk_bs_delete_ebusy_close_cpl, seq);
		return;
	}

	blob->locked_operation_in_progress = true;

	/*
	 * Remove the blob from the blob_store list now, to ensure it does not
	 *  get returned after this point by _spdk_blob_lookup().
+126 −1
Original line number Diff line number Diff line
@@ -6463,6 +6463,130 @@ blob_io_unit_compatiblity(void)
	g_blobid = 0;
}

static void
blob_simultaneous_operations(void)
{
	struct spdk_blob_store *bs;
	struct spdk_bs_dev *dev;
	struct spdk_blob_opts opts;
	struct spdk_blob *blob, *snapshot;
	spdk_blob_id blobid, snapshotid;
	struct spdk_io_channel *channel;

	dev = init_dev();

	spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
	poll_threads();
	CU_ASSERT(g_bserrno == 0);
	SPDK_CU_ASSERT_FATAL(g_bs != NULL);
	bs = g_bs;

	channel = spdk_bs_alloc_io_channel(bs);
	SPDK_CU_ASSERT_FATAL(channel != NULL);

	spdk_blob_opts_init(&opts);
	opts.num_clusters = 10;

	spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
	poll_threads();
	CU_ASSERT(g_bserrno == 0);
	CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
	blobid = g_blobid;

	spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
	poll_threads();
	CU_ASSERT(g_bserrno == 0);
	SPDK_CU_ASSERT_FATAL(g_blob != NULL);
	blob = g_blob;

	/* Create snapshot and try to remove blob in the same time:
	 * - snapshot should be created successfully
	 * - delete operation should fail w -EBUSY */
	CU_ASSERT(blob->locked_operation_in_progress == false);
	spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
	CU_ASSERT(blob->locked_operation_in_progress == true);
	spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
	CU_ASSERT(blob->locked_operation_in_progress == true);
	/* Deletion failure */
	CU_ASSERT(g_bserrno == -EBUSY);
	poll_threads();
	CU_ASSERT(blob->locked_operation_in_progress == false);
	/* Snapshot creation success */
	CU_ASSERT(g_bserrno == 0);
	CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);

	snapshotid = g_blobid;

	spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
	poll_threads();
	CU_ASSERT(g_bserrno == 0);
	SPDK_CU_ASSERT_FATAL(g_blob != NULL);
	snapshot = g_blob;

	/* Inflate blob and try to remove blob in the same time:
	 * - blob should be inflated successfully
	 * - delete operation should fail w -EBUSY */
	CU_ASSERT(blob->locked_operation_in_progress == false);
	spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
	CU_ASSERT(blob->locked_operation_in_progress == true);
	spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
	CU_ASSERT(blob->locked_operation_in_progress == true);
	/* Deletion failure */
	CU_ASSERT(g_bserrno == -EBUSY);
	poll_threads();
	CU_ASSERT(blob->locked_operation_in_progress == false);
	/* Inflation success */
	CU_ASSERT(g_bserrno == 0);

	/* Clone snapshot and try to remove snapshot in the same time:
	 * - snapshot should be cloned successfully
	 * - delete operation should fail w -EBUSY */
	CU_ASSERT(blob->locked_operation_in_progress == false);
	spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
	spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
	/* Deletion failure */
	CU_ASSERT(g_bserrno == -EBUSY);
	poll_threads();
	CU_ASSERT(blob->locked_operation_in_progress == false);
	/* Clone created */
	CU_ASSERT(g_bserrno == 0);

	/* Resize blob and try to remove blob in the same time:
	 * - blob should be resized successfully
	 * - delete operation should fail w -EBUSY */
	CU_ASSERT(blob->locked_operation_in_progress == false);
	spdk_blob_resize(blob, 50, blob_op_complete, NULL);
	CU_ASSERT(blob->locked_operation_in_progress == true);
	spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
	CU_ASSERT(blob->locked_operation_in_progress == true);
	/* Deletion failure */
	CU_ASSERT(g_bserrno == -EBUSY);
	poll_threads();
	CU_ASSERT(blob->locked_operation_in_progress == false);
	/* Blob resized successfully */
	CU_ASSERT(g_bserrno == 0);

	spdk_blob_close(blob, blob_op_complete, NULL);
	poll_threads();
	CU_ASSERT(g_bserrno == 0);

	spdk_blob_close(snapshot, blob_op_complete, NULL);
	poll_threads();
	CU_ASSERT(g_bserrno == 0);

	spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
	poll_threads();
	CU_ASSERT(g_bserrno == 0);

	spdk_bs_unload(g_bs, bs_op_complete, NULL);
	poll_threads();
	CU_ASSERT(g_bserrno == 0);
	g_bs = NULL;

	spdk_bs_free_io_channel(channel);
	poll_threads();
}

int main(int argc, char **argv)
{
	CU_pSuite	suite = NULL;
@@ -6530,7 +6654,8 @@ int main(int argc, char **argv)
		CU_add_test(suite, "blob_operation_split_rw", blob_operation_split_rw) == NULL ||
		CU_add_test(suite, "blob_operation_split_rw_iov", blob_operation_split_rw_iov) == NULL ||
		CU_add_test(suite, "blob_io_unit", blob_io_unit) == NULL ||
		CU_add_test(suite, "blob_io_unit_compatiblity", blob_io_unit_compatiblity) == NULL
		CU_add_test(suite, "blob_io_unit_compatiblity", blob_io_unit_compatiblity) == NULL ||
		CU_add_test(suite, "blob_simultaneous_operations", blob_simultaneous_operations) == NULL
	) {
		CU_cleanup_registry();
		return CU_get_error();