blobstore: add inflate call
Inflate call can be used on thin provisioned blob or clones. Function allocates all unallocated clusters on specified blob and: - For clones, copies data from backing blob. - For thin provisioned blobs, clusters are zeroed. After this call all dependency from specified blob is removed what allows deletion i.e. snapshots. Signed-off-by: Piotr Pelplinski <piotr.pelplinski@intel.com> Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com> Change-Id: Ibff569e45b12068b2fb46557156be348b36c252b Reviewed-on: https://review.gerrithub.io/399367 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
b1ccb095e4
commit
ede6d97e3c
@ -467,6 +467,19 @@ bool spdk_blob_is_thin_provisioned(struct spdk_blob *blob);
|
|||||||
void spdk_bs_delete_blob(struct spdk_blob_store *bs, spdk_blob_id blobid,
|
void spdk_bs_delete_blob(struct spdk_blob_store *bs, spdk_blob_id blobid,
|
||||||
spdk_blob_op_complete cb_fn, void *cb_arg);
|
spdk_blob_op_complete cb_fn, void *cb_arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate all unallocated clusters in this blob and copy data from backing blob.
|
||||||
|
* This call removes dependency on backing blob.
|
||||||
|
*
|
||||||
|
* \param bs blobstore.
|
||||||
|
* \param channel IO channel used to inflate blob.
|
||||||
|
* \param blobid The id of the blob to inflate.
|
||||||
|
* \param cb_fn Called when the operation is complete.
|
||||||
|
* \param cb_arg Argument passed to function cb_fn.
|
||||||
|
*/
|
||||||
|
void spdk_bs_inflate_blob(struct spdk_blob_store *bs, struct spdk_io_channel *channel,
|
||||||
|
spdk_blob_id blobid, spdk_blob_op_complete cb_fn, void *cb_arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a blob from the given blobstore.
|
* Open a blob from the given blobstore.
|
||||||
*
|
*
|
||||||
|
@ -1699,6 +1699,11 @@ _spdk_blob_request_submit_op_single(struct spdk_io_channel *_ch, struct spdk_blo
|
|||||||
/* Write to the blob */
|
/* Write to the blob */
|
||||||
spdk_bs_batch_t *batch;
|
spdk_bs_batch_t *batch;
|
||||||
|
|
||||||
|
if (lba_count == 0) {
|
||||||
|
cb_fn(cb_arg, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
batch = spdk_bs_batch_open(_ch, &cpl);
|
batch = spdk_bs_batch_open(_ch, &cpl);
|
||||||
if (!batch) {
|
if (!batch) {
|
||||||
cb_fn(cb_arg, -ENOMEM);
|
cb_fn(cb_arg, -ENOMEM);
|
||||||
@ -3706,6 +3711,11 @@ struct spdk_clone_snapshot_ctx {
|
|||||||
struct spdk_bs_cpl cpl;
|
struct spdk_bs_cpl cpl;
|
||||||
int bserrno;
|
int bserrno;
|
||||||
|
|
||||||
|
struct spdk_io_channel *channel;
|
||||||
|
|
||||||
|
/* Current cluster for inflate operation */
|
||||||
|
uint64_t cluster;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
spdk_blob_id id;
|
spdk_blob_id id;
|
||||||
struct spdk_blob *blob;
|
struct spdk_blob *blob;
|
||||||
@ -3738,6 +3748,9 @@ _spdk_bs_clone_snapshot_cleanup_finish(void *cb_arg, int bserrno)
|
|||||||
case SPDK_BS_CPL_TYPE_BLOBID:
|
case SPDK_BS_CPL_TYPE_BLOBID:
|
||||||
cpl->u.blobid.cb_fn(cpl->u.blobid.cb_arg, cpl->u.blobid.blobid, ctx->bserrno);
|
cpl->u.blobid.cb_fn(cpl->u.blobid.cb_arg, cpl->u.blobid.blobid, ctx->bserrno);
|
||||||
break;
|
break;
|
||||||
|
case SPDK_BS_CPL_TYPE_BLOB_BASIC:
|
||||||
|
cpl->u.blob_basic.cb_fn(cpl->u.blob_basic.cb_arg, ctx->bserrno);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
SPDK_UNREACHABLE();
|
SPDK_UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
@ -4072,6 +4085,140 @@ void spdk_bs_create_clone(struct spdk_blob_store *bs, spdk_blob_id blobid,
|
|||||||
|
|
||||||
/* END spdk_bs_create_clone */
|
/* END spdk_bs_create_clone */
|
||||||
|
|
||||||
|
/* START spdk_bs_inflate_blob */
|
||||||
|
|
||||||
|
static void
|
||||||
|
_spdk_bs_inflate_blob_sync(void *cb_arg, int bserrno)
|
||||||
|
{
|
||||||
|
struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
|
||||||
|
struct spdk_blob *_blob = ctx->original.blob;
|
||||||
|
|
||||||
|
if (bserrno != 0) {
|
||||||
|
_spdk_bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destroy back_bs_dev */
|
||||||
|
_blob->back_bs_dev->destroy(_blob->back_bs_dev);
|
||||||
|
_blob->back_bs_dev = NULL;
|
||||||
|
|
||||||
|
_spdk_bs_clone_snapshot_origblob_cleanup(ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_spdk_bs_inflate_blob_done(void *cb_arg, int bserrno)
|
||||||
|
{
|
||||||
|
struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
|
||||||
|
struct spdk_blob *_blob = ctx->original.blob;
|
||||||
|
|
||||||
|
if (bserrno != 0) {
|
||||||
|
_spdk_bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_spdk_bs_blob_list_remove(_blob);
|
||||||
|
|
||||||
|
_spdk_blob_remove_xattr(_blob, BLOB_SNAPSHOT, true);
|
||||||
|
|
||||||
|
/* Unset thin provision */
|
||||||
|
_blob->invalid_flags = _blob->invalid_flags & ~SPDK_BLOB_THIN_PROV;
|
||||||
|
_blob->state = SPDK_BLOB_STATE_DIRTY;
|
||||||
|
|
||||||
|
spdk_blob_sync_md(_blob, _spdk_bs_inflate_blob_sync, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_spdk_bs_inflate_blob_touch_next(void *cb_arg, int bserrno)
|
||||||
|
{
|
||||||
|
struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
|
||||||
|
struct spdk_blob *_blob = ctx->original.blob;
|
||||||
|
uint64_t offset;
|
||||||
|
|
||||||
|
if (bserrno != 0) {
|
||||||
|
_spdk_bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; ctx->cluster < _blob->active.num_clusters; ctx->cluster++) {
|
||||||
|
if (_blob->active.clusters[ctx->cluster] == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->cluster < _blob->active.num_clusters) {
|
||||||
|
offset = _spdk_bs_cluster_to_page(_blob->bs, ctx->cluster);
|
||||||
|
|
||||||
|
/* We may safely increment a cluster before write */
|
||||||
|
ctx->cluster++;
|
||||||
|
|
||||||
|
/* Use zero length write to touch a cluster */
|
||||||
|
spdk_blob_io_write(_blob, ctx->channel, NULL, offset, 0,
|
||||||
|
_spdk_bs_inflate_blob_touch_next, ctx);
|
||||||
|
} else {
|
||||||
|
_spdk_bs_inflate_blob_done(cb_arg, bserrno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_spdk_bs_inflate_blob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bserrno)
|
||||||
|
{
|
||||||
|
struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
|
||||||
|
uint64_t lfc; /* lowest free cluster */
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
if (bserrno != 0) {
|
||||||
|
_spdk_bs_clone_snapshot_cleanup_finish(ctx, bserrno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx->original.blob = _blob;
|
||||||
|
|
||||||
|
if (spdk_blob_is_thin_provisioned(_blob) == false) {
|
||||||
|
/* This is not thin provisioned blob. No need to inflate. */
|
||||||
|
_spdk_bs_clone_snapshot_origblob_cleanup(ctx, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do two passes - one to verify that we can obtain enough clusters
|
||||||
|
* and another to actually claim them.
|
||||||
|
*/
|
||||||
|
lfc = 0;
|
||||||
|
for (i = 0; i < _blob->active.num_clusters; i++) {
|
||||||
|
if (_blob->active.clusters[i] == 0) {
|
||||||
|
lfc = spdk_bit_array_find_first_clear(_blob->bs->used_clusters, lfc);
|
||||||
|
if (lfc >= _blob->bs->total_clusters) {
|
||||||
|
/* No more free clusters. Cannot satisfy the request */
|
||||||
|
_spdk_bs_clone_snapshot_origblob_cleanup(ctx, -ENOSPC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lfc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->cluster = 0;
|
||||||
|
_spdk_bs_inflate_blob_touch_next(ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdk_bs_inflate_blob(struct spdk_blob_store *bs, struct spdk_io_channel *channel,
|
||||||
|
spdk_blob_id blobid, spdk_blob_op_complete cb_fn, void *cb_arg)
|
||||||
|
{
|
||||||
|
struct spdk_clone_snapshot_ctx *ctx = calloc(1, sizeof(*ctx));
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
cb_fn(cb_arg, -ENOMEM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx->cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
|
||||||
|
ctx->cpl.u.bs_basic.cb_fn = cb_fn;
|
||||||
|
ctx->cpl.u.bs_basic.cb_arg = cb_arg;
|
||||||
|
ctx->bserrno = 0;
|
||||||
|
ctx->original.id = blobid;
|
||||||
|
ctx->channel = channel;
|
||||||
|
|
||||||
|
spdk_bs_open_blob(bs, ctx->original.id, _spdk_bs_inflate_blob_open_cpl, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* END spdk_bs_inflate_blob */
|
||||||
|
|
||||||
/* START spdk_blob_resize */
|
/* START spdk_blob_resize */
|
||||||
void
|
void
|
||||||
spdk_blob_resize(struct spdk_blob *blob, uint64_t sz, spdk_blob_op_complete cb_fn, void *cb_arg)
|
spdk_blob_resize(struct spdk_blob *blob, uint64_t sz, spdk_blob_op_complete cb_fn, void *cb_arg)
|
||||||
|
@ -805,6 +805,92 @@ blob_clone(void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
blob_inflate(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;
|
||||||
|
uint64_t free_clusters;
|
||||||
|
|
||||||
|
dev = init_dev();
|
||||||
|
|
||||||
|
spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Create blob with 10 clusters */
|
||||||
|
|
||||||
|
spdk_blob_opts_init(&opts);
|
||||||
|
opts.num_clusters = 10;
|
||||||
|
|
||||||
|
spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
|
||||||
|
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);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
SPDK_CU_ASSERT_FATAL(g_blob != NULL);
|
||||||
|
blob = g_blob;
|
||||||
|
|
||||||
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10)
|
||||||
|
CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == false);
|
||||||
|
|
||||||
|
/* Create snapshot */
|
||||||
|
|
||||||
|
spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
||||||
|
snapshotid = g_blobid;
|
||||||
|
|
||||||
|
CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
|
||||||
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10)
|
||||||
|
|
||||||
|
spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
SPDK_CU_ASSERT_FATAL(g_blob != NULL);
|
||||||
|
snapshot = g_blob;
|
||||||
|
CU_ASSERT(snapshot->data_ro == true)
|
||||||
|
CU_ASSERT(snapshot->md_ro == true)
|
||||||
|
CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
|
||||||
|
|
||||||
|
spdk_blob_close(snapshot, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
free_clusters = spdk_bs_free_cluster_count(bs);
|
||||||
|
|
||||||
|
/* Inflate blob */
|
||||||
|
spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
/* All 10 clusters should be allocated from blob store */
|
||||||
|
CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 10);
|
||||||
|
|
||||||
|
/* Now, it should be possible to delete snapshot */
|
||||||
|
spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10)
|
||||||
|
CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == false);
|
||||||
|
|
||||||
|
spdk_blob_close(blob, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
g_bs = NULL;
|
||||||
|
|
||||||
|
spdk_bs_free_io_channel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
blob_delete(void)
|
blob_delete(void)
|
||||||
{
|
{
|
||||||
@ -3762,6 +3848,178 @@ blob_snapshot_rw_iov(void)
|
|||||||
g_blobid = 0;
|
g_blobid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
blob_inflate_rw(void)
|
||||||
|
{
|
||||||
|
static uint8_t *zero;
|
||||||
|
struct spdk_blob_store *bs;
|
||||||
|
struct spdk_bs_dev *dev;
|
||||||
|
struct spdk_blob *blob, *snapshot;
|
||||||
|
struct spdk_io_channel *channel;
|
||||||
|
struct spdk_blob_opts opts;
|
||||||
|
spdk_blob_id blobid, snapshotid;
|
||||||
|
uint64_t free_clusters;
|
||||||
|
uint64_t cluster_size;
|
||||||
|
|
||||||
|
uint64_t payload_size;
|
||||||
|
uint8_t *payload_read;
|
||||||
|
uint8_t *payload_write;
|
||||||
|
uint8_t *payload_clone;
|
||||||
|
|
||||||
|
uint64_t pages_per_cluster;
|
||||||
|
uint64_t pages_per_payload;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dev = init_dev();
|
||||||
|
|
||||||
|
spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
||||||
|
bs = g_bs;
|
||||||
|
|
||||||
|
free_clusters = spdk_bs_free_cluster_count(bs);
|
||||||
|
cluster_size = spdk_bs_get_cluster_size(bs);
|
||||||
|
pages_per_cluster = cluster_size / spdk_bs_get_page_size(bs);
|
||||||
|
pages_per_payload = pages_per_cluster * 5;
|
||||||
|
|
||||||
|
payload_size = cluster_size * 5;
|
||||||
|
|
||||||
|
payload_read = malloc(payload_size);
|
||||||
|
SPDK_CU_ASSERT_FATAL(payload_read != NULL);
|
||||||
|
|
||||||
|
payload_write = malloc(payload_size);
|
||||||
|
SPDK_CU_ASSERT_FATAL(payload_write != NULL);
|
||||||
|
|
||||||
|
payload_clone = malloc(payload_size);
|
||||||
|
SPDK_CU_ASSERT_FATAL(payload_clone != NULL);
|
||||||
|
|
||||||
|
zero = calloc(1, payload_size);
|
||||||
|
SPDK_CU_ASSERT_FATAL(zero != NULL);
|
||||||
|
|
||||||
|
channel = spdk_bs_alloc_io_channel(bs);
|
||||||
|
SPDK_CU_ASSERT_FATAL(channel != NULL);
|
||||||
|
|
||||||
|
/* Create blob */
|
||||||
|
spdk_blob_opts_init(&opts);
|
||||||
|
opts.thin_provision = true;
|
||||||
|
opts.num_clusters = 5;
|
||||||
|
|
||||||
|
spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
||||||
|
CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
|
||||||
|
blobid = g_blobid;
|
||||||
|
|
||||||
|
spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
SPDK_CU_ASSERT_FATAL(g_blob != NULL);
|
||||||
|
blob = g_blob;
|
||||||
|
|
||||||
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
|
||||||
|
|
||||||
|
/* Initial read should return zeroed payload */
|
||||||
|
memset(payload_read, 0xFF, payload_size);
|
||||||
|
spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
CU_ASSERT(memcmp(zero, payload_read, payload_size) == 0);
|
||||||
|
|
||||||
|
/* Fill whole blob with a pattern */
|
||||||
|
memset(payload_write, 0xE5, payload_size);
|
||||||
|
spdk_blob_io_write(blob, channel, payload_write, 0, pages_per_payload,
|
||||||
|
blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
|
||||||
|
|
||||||
|
/* Create snapshot from blob */
|
||||||
|
spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
|
||||||
|
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);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
SPDK_CU_ASSERT_FATAL(g_blob != NULL);
|
||||||
|
snapshot = g_blob;
|
||||||
|
CU_ASSERT(snapshot->data_ro == true)
|
||||||
|
CU_ASSERT(snapshot->md_ro == true)
|
||||||
|
|
||||||
|
CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5)
|
||||||
|
|
||||||
|
/* Write every second cluster with a pattern.
|
||||||
|
*
|
||||||
|
* payload_clone stores expected result on "blob" read at the time and
|
||||||
|
* is used only to check data consistency on clone before and after
|
||||||
|
* inflation. Initially we fill it with a backing snapshots pattern
|
||||||
|
* used before.
|
||||||
|
*/
|
||||||
|
memset(payload_clone, 0xE5, payload_size);
|
||||||
|
memset(payload_write, 0xAA, payload_size);
|
||||||
|
for (i = 1; i < 5; i += 2) {
|
||||||
|
spdk_blob_io_write(blob, channel, payload_write, i * pages_per_cluster,
|
||||||
|
pages_per_cluster, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
/* Update expected result */
|
||||||
|
memcpy(payload_clone + (cluster_size * i), payload_write,
|
||||||
|
cluster_size);
|
||||||
|
}
|
||||||
|
CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
|
||||||
|
|
||||||
|
/* Check data consistency on clone */
|
||||||
|
memset(payload_read, 0xFF, payload_size);
|
||||||
|
spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
|
||||||
|
blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
|
||||||
|
|
||||||
|
/* Close all blobs */
|
||||||
|
spdk_blob_close(blob, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
spdk_blob_close(snapshot, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
/* Inflate blob */
|
||||||
|
spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
/* Try to delete snapshot (should pass) */
|
||||||
|
spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
/* Reopen blob after snapshot deletion */
|
||||||
|
spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
SPDK_CU_ASSERT_FATAL(g_blob != NULL);
|
||||||
|
blob = g_blob;
|
||||||
|
|
||||||
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
|
||||||
|
|
||||||
|
/* Check data consistency on inflated blob */
|
||||||
|
memset(payload_read, 0xFF, payload_size);
|
||||||
|
spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
|
||||||
|
|
||||||
|
spdk_blob_close(blob, blob_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
|
||||||
|
spdk_bs_free_io_channel(channel);
|
||||||
|
|
||||||
|
/* Unload the blob store */
|
||||||
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
||||||
|
CU_ASSERT(g_bserrno == 0);
|
||||||
|
g_bs = NULL;
|
||||||
|
g_blob = NULL;
|
||||||
|
g_blobid = 0;
|
||||||
|
|
||||||
|
free(payload_read);
|
||||||
|
free(payload_write);
|
||||||
|
free(payload_clone);
|
||||||
|
free(zero);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Snapshot-clones relation test
|
* Snapshot-clones relation test
|
||||||
*
|
*
|
||||||
@ -4054,6 +4312,7 @@ int main(int argc, char **argv)
|
|||||||
CU_add_test(suite, "blob_thin_provision", blob_thin_provision) == NULL ||
|
CU_add_test(suite, "blob_thin_provision", blob_thin_provision) == NULL ||
|
||||||
CU_add_test(suite, "blob_snapshot", blob_snapshot) == NULL ||
|
CU_add_test(suite, "blob_snapshot", blob_snapshot) == NULL ||
|
||||||
CU_add_test(suite, "blob_clone", blob_clone) == NULL ||
|
CU_add_test(suite, "blob_clone", blob_clone) == NULL ||
|
||||||
|
CU_add_test(suite, "blob_inflate", blob_inflate) == NULL ||
|
||||||
CU_add_test(suite, "blob_delete", blob_delete) == NULL ||
|
CU_add_test(suite, "blob_delete", blob_delete) == NULL ||
|
||||||
CU_add_test(suite, "blob_resize", blob_resize) == NULL ||
|
CU_add_test(suite, "blob_resize", blob_resize) == NULL ||
|
||||||
CU_add_test(suite, "blob_read_only", blob_read_only) == NULL ||
|
CU_add_test(suite, "blob_read_only", blob_read_only) == NULL ||
|
||||||
@ -4090,6 +4349,7 @@ int main(int argc, char **argv)
|
|||||||
CU_add_test(suite, "bs_load_iter", bs_load_iter) == NULL ||
|
CU_add_test(suite, "bs_load_iter", bs_load_iter) == NULL ||
|
||||||
CU_add_test(suite, "blob_snapshot_rw", blob_snapshot_rw) == NULL ||
|
CU_add_test(suite, "blob_snapshot_rw", blob_snapshot_rw) == NULL ||
|
||||||
CU_add_test(suite, "blob_snapshot_rw_iov", blob_snapshot_rw_iov) == NULL ||
|
CU_add_test(suite, "blob_snapshot_rw_iov", blob_snapshot_rw_iov) == NULL ||
|
||||||
|
CU_add_test(suite, "blob_inflate_rw", blob_inflate_rw) == NULL ||
|
||||||
CU_add_test(suite, "blob_relations", blob_relations) == NULL
|
CU_add_test(suite, "blob_relations", blob_relations) == NULL
|
||||||
) {
|
) {
|
||||||
CU_cleanup_registry();
|
CU_cleanup_registry();
|
||||||
|
Loading…
Reference in New Issue
Block a user