blobstore: block simultaneous operations on blobs

Block operation that should not be done simultaneously.

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

Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/450014
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Maciej Szwed 2019-04-01 14:16:44 +02:00 committed by Jim Harris
parent 478c2e6f64
commit e6100af425
2 changed files with 168 additions and 3 deletions

View File

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

View File

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