The function just needs to zero out metadata so that the blobstore is effectively destroyed. If the user wants to unmap the rest of the disk after the blobstore is destroyed, they are free to do so. On future initializations of blobstores the code will do the unmapping, so performance is not impacted. While here, implement the zeroing using the new write_zeroes functionality instead of allocating a buffer full of zeroes. Change-Id: I7f18be0fd5e13a48b171ab3f4d5f5e12876023bc Signed-off-by: Ben Walker <benjamin.walker@intel.com> Reviewed-on: https://review.gerrithub.io/390307 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
2169 lines
59 KiB
C
2169 lines
59 KiB
C
/*-
|
|
* BSD LICENSE
|
|
*
|
|
* Copyright (c) Intel Corporation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#include "spdk_cunit.h"
|
|
#include "spdk/blob.h"
|
|
|
|
#include "lib/test_env.c"
|
|
#include "../bs_dev_common.c"
|
|
#include "blobstore.c"
|
|
#include "request.c"
|
|
|
|
struct spdk_blob_store *g_bs;
|
|
spdk_blob_id g_blobid;
|
|
struct spdk_blob *g_blob;
|
|
int g_bserrno;
|
|
struct spdk_xattr_names *g_names;
|
|
int g_done;
|
|
|
|
bool g_scheduler_delay = false;
|
|
|
|
struct scheduled_ops {
|
|
spdk_thread_fn fn;
|
|
void *ctx;
|
|
|
|
TAILQ_ENTRY(scheduled_ops) ops_queue;
|
|
};
|
|
|
|
static TAILQ_HEAD(, scheduled_ops) g_scheduled_ops = TAILQ_HEAD_INITIALIZER(g_scheduled_ops);
|
|
|
|
struct spdk_bs_super_block_ver1 {
|
|
uint8_t signature[8];
|
|
uint32_t version;
|
|
uint32_t length;
|
|
uint32_t clean; /* If there was a clean shutdown, this is 1. */
|
|
spdk_blob_id super_blob;
|
|
|
|
uint32_t cluster_size; /* In bytes */
|
|
|
|
uint32_t used_page_mask_start; /* Offset from beginning of disk, in pages */
|
|
uint32_t used_page_mask_len; /* Count, in pages */
|
|
|
|
uint32_t used_cluster_mask_start; /* Offset from beginning of disk, in pages */
|
|
uint32_t used_cluster_mask_len; /* Count, in pages */
|
|
|
|
uint32_t md_start; /* Offset from beginning of disk, in pages */
|
|
uint32_t md_len; /* Count, in pages */
|
|
|
|
uint8_t reserved[4036];
|
|
uint32_t crc;
|
|
} __attribute__((packed));
|
|
SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_super_block_ver1) == 0x1000, "Invalid super block size");
|
|
|
|
static void
|
|
_bs_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx)
|
|
{
|
|
if (g_scheduler_delay) {
|
|
struct scheduled_ops *ops = calloc(1, sizeof(*ops));
|
|
|
|
SPDK_CU_ASSERT_FATAL(ops != NULL);
|
|
ops->fn = fn;
|
|
ops->ctx = ctx;
|
|
TAILQ_INSERT_TAIL(&g_scheduled_ops, ops, ops_queue);
|
|
} else {
|
|
fn(ctx);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_bs_flush_scheduler(void)
|
|
{
|
|
struct scheduled_ops *ops, *tmp;
|
|
|
|
TAILQ_FOREACH_SAFE(ops, &g_scheduled_ops, ops_queue, tmp) {
|
|
ops->fn(ops->ctx);
|
|
TAILQ_REMOVE(&g_scheduled_ops, ops, ops_queue);
|
|
free(ops);
|
|
}
|
|
}
|
|
|
|
static void
|
|
bs_op_complete(void *cb_arg, int bserrno)
|
|
{
|
|
g_bserrno = bserrno;
|
|
}
|
|
|
|
static void
|
|
bs_op_with_handle_complete(void *cb_arg, struct spdk_blob_store *bs,
|
|
int bserrno)
|
|
{
|
|
g_bs = bs;
|
|
g_bserrno = bserrno;
|
|
}
|
|
|
|
static void
|
|
blob_op_complete(void *cb_arg, int bserrno)
|
|
{
|
|
g_bserrno = bserrno;
|
|
}
|
|
|
|
static void
|
|
blob_op_with_id_complete(void *cb_arg, spdk_blob_id blobid, int bserrno)
|
|
{
|
|
g_blobid = blobid;
|
|
g_bserrno = bserrno;
|
|
}
|
|
|
|
static void
|
|
blob_op_with_handle_complete(void *cb_arg, struct spdk_blob *blb, int bserrno)
|
|
{
|
|
g_blob = blb;
|
|
g_bserrno = bserrno;
|
|
}
|
|
|
|
static void
|
|
blob_init(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
|
|
dev = init_dev();
|
|
|
|
/* should fail for an unsupported blocklen */
|
|
dev->blocklen = 500;
|
|
spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
|
|
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);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_super(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
spdk_blob_id blobid;
|
|
|
|
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;
|
|
|
|
/* Get the super blob without having set one */
|
|
spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -ENOENT);
|
|
CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
|
|
|
|
/* Create a blob */
|
|
spdk_bs_md_create_blob(bs,
|
|
blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
/* Set the blob as the super blob */
|
|
spdk_bs_set_super(bs, blobid, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/* Get the super blob */
|
|
spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(blobid == g_blobid);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_open(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
spdk_blob_id blobid, blobid2;
|
|
|
|
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;
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
blobid2 = spdk_blob_get_id(blob);
|
|
CU_ASSERT(blobid == blobid2);
|
|
|
|
/* Try to open file again. It should return success. */
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(blob == g_blob);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(blob == NULL);
|
|
|
|
/*
|
|
* Close the file a second time, releasing the second reference. This
|
|
* should succeed.
|
|
*/
|
|
blob = g_blob;
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/*
|
|
* Try to open file again. It should succeed. This tests the case
|
|
* where the file is opened, closed, then re-opened again.
|
|
*/
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
spdk_bs_md_close_blob(&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;
|
|
}
|
|
|
|
static void
|
|
blob_delete(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
spdk_blob_id blobid;
|
|
|
|
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;
|
|
|
|
/* Create a blob and then delete it. */
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid > 0);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_delete_blob(bs, blobid, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/* Try to open the blob */
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -ENOENT);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_resize(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
spdk_blob_id blobid;
|
|
uint64_t free_clusters;
|
|
int rc;
|
|
|
|
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);
|
|
|
|
spdk_bs_md_create_blob(bs, 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_md_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;
|
|
|
|
/* Confirm that resize fails if blob is marked read-only. */
|
|
blob->md_ro = true;
|
|
rc = spdk_bs_md_resize_blob(blob, 5);
|
|
CU_ASSERT(rc == -EPERM);
|
|
blob->md_ro = false;
|
|
|
|
/* The blob started at 0 clusters. Resize it to be 5. */
|
|
rc = spdk_bs_md_resize_blob(blob, 5);
|
|
CU_ASSERT(rc == 0);
|
|
CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
|
|
|
|
/* Shrink the blob to 3 clusters. This will not actually release
|
|
* the old clusters until the blob is synced.
|
|
*/
|
|
rc = spdk_bs_md_resize_blob(blob, 3);
|
|
CU_ASSERT(rc == 0);
|
|
/* Verify there are still 5 clusters in use */
|
|
CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
|
|
|
|
spdk_bs_md_sync_blob(blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
/* Now there are only 3 clusters in use */
|
|
CU_ASSERT((free_clusters - 3) == spdk_bs_free_cluster_count(bs));
|
|
|
|
/* Resize the blob to be 10 clusters. Growth takes effect immediately. */
|
|
rc = spdk_bs_md_resize_blob(blob, 10);
|
|
CU_ASSERT(rc == 0);
|
|
CU_ASSERT((free_clusters - 10) == spdk_bs_free_cluster_count(bs));
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_md_delete_blob(bs, blobid, 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;
|
|
}
|
|
|
|
static void
|
|
channel_ops(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_io_channel *channel;
|
|
|
|
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);
|
|
CU_ASSERT(channel != NULL);
|
|
|
|
spdk_bs_free_io_channel(channel);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_write(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
struct spdk_io_channel *channel;
|
|
spdk_blob_id blobid;
|
|
uint64_t pages_per_cluster;
|
|
uint8_t payload[10 * 4096];
|
|
int rc;
|
|
|
|
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;
|
|
|
|
pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
|
|
|
|
channel = spdk_bs_alloc_io_channel(bs);
|
|
CU_ASSERT(channel != NULL);
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_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;
|
|
|
|
/* Write to a blob with 0 size */
|
|
spdk_bs_io_write_blob(blob, channel, payload, 0, 1, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
|
|
/* Resize the blob */
|
|
rc = spdk_bs_md_resize_blob(blob, 5);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/* Confirm that write fails if blob is marked read-only. */
|
|
blob->data_ro = true;
|
|
spdk_bs_io_write_blob(blob, channel, payload, 0, 1, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EPERM);
|
|
blob->data_ro = false;
|
|
|
|
/* Write to the blob */
|
|
spdk_bs_io_write_blob(blob, channel, payload, 0, 1, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/* Write starting beyond the end */
|
|
spdk_bs_io_write_blob(blob, channel, payload, 5 * pages_per_cluster, 1, blob_op_complete,
|
|
NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
|
|
/* Write starting at a valid location but going off the end */
|
|
spdk_bs_io_write_blob(blob, channel, payload, 4 * pages_per_cluster, pages_per_cluster + 1,
|
|
blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_free_io_channel(channel);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_read(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
struct spdk_io_channel *channel;
|
|
spdk_blob_id blobid;
|
|
uint64_t pages_per_cluster;
|
|
uint8_t payload[10 * 4096];
|
|
int rc;
|
|
|
|
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;
|
|
|
|
pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
|
|
|
|
channel = spdk_bs_alloc_io_channel(bs);
|
|
CU_ASSERT(channel != NULL);
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_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;
|
|
|
|
/* Read from a blob with 0 size */
|
|
spdk_bs_io_read_blob(blob, channel, payload, 0, 1, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
|
|
/* Resize the blob */
|
|
rc = spdk_bs_md_resize_blob(blob, 5);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/* Confirm that read passes if blob is marked read-only. */
|
|
blob->data_ro = true;
|
|
spdk_bs_io_read_blob(blob, channel, payload, 0, 1, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob->data_ro = false;
|
|
|
|
/* Read from the blob */
|
|
spdk_bs_io_read_blob(blob, channel, payload, 0, 1, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/* Read starting beyond the end */
|
|
spdk_bs_io_read_blob(blob, channel, payload, 5 * pages_per_cluster, 1, blob_op_complete,
|
|
NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
|
|
/* Read starting at a valid location but going off the end */
|
|
spdk_bs_io_read_blob(blob, channel, payload, 4 * pages_per_cluster, pages_per_cluster + 1,
|
|
blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_free_io_channel(channel);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_rw_verify(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
struct spdk_io_channel *channel;
|
|
spdk_blob_id blobid;
|
|
uint8_t payload_read[10 * 4096];
|
|
uint8_t payload_write[10 * 4096];
|
|
int rc;
|
|
|
|
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);
|
|
CU_ASSERT(channel != NULL);
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
rc = spdk_bs_md_resize_blob(blob, 32);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
memset(payload_write, 0xE5, sizeof(payload_write));
|
|
spdk_bs_io_write_blob(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
memset(payload_read, 0x00, sizeof(payload_read));
|
|
spdk_bs_io_read_blob(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(memcmp(payload_write, payload_read, 4 * 4096) == 0);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_free_io_channel(channel);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_rw_verify_iov(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
struct spdk_io_channel *channel;
|
|
spdk_blob_id blobid;
|
|
uint8_t payload_read[10 * 4096];
|
|
uint8_t payload_write[10 * 4096];
|
|
struct iovec iov_read[3];
|
|
struct iovec iov_write[3];
|
|
void *buf;
|
|
int rc;
|
|
|
|
dev = init_dev();
|
|
memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
|
|
|
|
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);
|
|
CU_ASSERT(channel != NULL);
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_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;
|
|
|
|
rc = spdk_bs_md_resize_blob(blob, 2);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/*
|
|
* Manually adjust the offset of the blob's second cluster. This allows
|
|
* us to make sure that the readv/write code correctly accounts for I/O
|
|
* that cross cluster boundaries. Start by asserting that the allocated
|
|
* clusters are where we expect before modifying the second cluster.
|
|
*/
|
|
CU_ASSERT(blob->active.clusters[0] == 1 * 256);
|
|
CU_ASSERT(blob->active.clusters[1] == 2 * 256);
|
|
blob->active.clusters[1] = 3 * 256;
|
|
|
|
memset(payload_write, 0xE5, sizeof(payload_write));
|
|
iov_write[0].iov_base = payload_write;
|
|
iov_write[0].iov_len = 1 * 4096;
|
|
iov_write[1].iov_base = payload_write + 1 * 4096;
|
|
iov_write[1].iov_len = 5 * 4096;
|
|
iov_write[2].iov_base = payload_write + 6 * 4096;
|
|
iov_write[2].iov_len = 4 * 4096;
|
|
/*
|
|
* Choose a page offset just before the cluster boundary. The first 6 pages of payload
|
|
* will get written to the first cluster, the last 4 to the second cluster.
|
|
*/
|
|
spdk_bs_io_writev_blob(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
memset(payload_read, 0xAA, sizeof(payload_read));
|
|
iov_read[0].iov_base = payload_read;
|
|
iov_read[0].iov_len = 3 * 4096;
|
|
iov_read[1].iov_base = payload_read + 3 * 4096;
|
|
iov_read[1].iov_len = 4 * 4096;
|
|
iov_read[2].iov_base = payload_read + 7 * 4096;
|
|
iov_read[2].iov_len = 3 * 4096;
|
|
spdk_bs_io_readv_blob(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
|
|
|
|
buf = calloc(1, 256 * 4096);
|
|
SPDK_CU_ASSERT_FATAL(buf != NULL);
|
|
/* Check that cluster 2 on "disk" was not modified. */
|
|
CU_ASSERT(memcmp(buf, &g_dev_buffer[512 * 4096], 256 * 4096) == 0);
|
|
free(buf);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_free_io_channel(channel);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static uint32_t
|
|
bs_channel_get_req_count(struct spdk_io_channel *_channel)
|
|
{
|
|
struct spdk_bs_channel *channel = spdk_io_channel_get_ctx(_channel);
|
|
struct spdk_bs_request_set *set;
|
|
uint32_t count = 0;
|
|
|
|
TAILQ_FOREACH(set, &channel->reqs, link) {
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static void
|
|
blob_rw_verify_iov_nomem(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
struct spdk_io_channel *channel;
|
|
spdk_blob_id blobid;
|
|
uint8_t payload_write[10 * 4096];
|
|
struct iovec iov_write[3];
|
|
uint32_t req_count;
|
|
int rc;
|
|
|
|
dev = init_dev();
|
|
memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
|
|
|
|
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);
|
|
CU_ASSERT(channel != NULL);
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
rc = spdk_bs_md_resize_blob(blob, 2);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/*
|
|
* Choose a page offset just before the cluster boundary. The first 6 pages of payload
|
|
* will get written to the first cluster, the last 4 to the second cluster.
|
|
*/
|
|
iov_write[0].iov_base = payload_write;
|
|
iov_write[0].iov_len = 1 * 4096;
|
|
iov_write[1].iov_base = payload_write + 1 * 4096;
|
|
iov_write[1].iov_len = 5 * 4096;
|
|
iov_write[2].iov_base = payload_write + 6 * 4096;
|
|
iov_write[2].iov_len = 4 * 4096;
|
|
MOCK_SET(calloc, void *, NULL);
|
|
req_count = bs_channel_get_req_count(channel);
|
|
spdk_bs_io_writev_blob(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno = -ENOMEM);
|
|
CU_ASSERT(req_count == bs_channel_get_req_count(channel));
|
|
MOCK_SET(calloc, void *, (void *)MOCK_PASS_THRU);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_free_io_channel(channel);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_rw_iov_read_only(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
struct spdk_io_channel *channel;
|
|
spdk_blob_id blobid;
|
|
uint8_t payload_read[4096];
|
|
uint8_t payload_write[4096];
|
|
struct iovec iov_read;
|
|
struct iovec iov_write;
|
|
int rc;
|
|
|
|
dev = init_dev();
|
|
memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
|
|
|
|
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);
|
|
CU_ASSERT(channel != NULL);
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_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;
|
|
|
|
rc = spdk_bs_md_resize_blob(blob, 2);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/* Verify that writev failed if read_only flag is set. */
|
|
blob->data_ro = true;
|
|
iov_write.iov_base = payload_write;
|
|
iov_write.iov_len = sizeof(payload_write);
|
|
spdk_bs_io_writev_blob(blob, channel, &iov_write, 1, 0, 1, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EPERM);
|
|
|
|
/* Verify that reads pass if data_ro flag is set. */
|
|
iov_read.iov_base = payload_read;
|
|
iov_read.iov_len = sizeof(payload_read);
|
|
spdk_bs_io_readv_blob(blob, channel, &iov_read, 1, 0, 1, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_free_io_channel(channel);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_iter(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
spdk_blob_id blobid;
|
|
|
|
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;
|
|
|
|
spdk_bs_md_iter_first(bs, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_blob == NULL);
|
|
CU_ASSERT(g_bserrno == -ENOENT);
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_iter_first(bs, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_blob != NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob = g_blob;
|
|
CU_ASSERT(spdk_blob_get_id(blob) == blobid);
|
|
|
|
spdk_bs_md_iter_next(bs, &blob, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_blob == NULL);
|
|
CU_ASSERT(g_bserrno == -ENOENT);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_xattr(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
spdk_blob_id blobid;
|
|
uint64_t length;
|
|
int rc;
|
|
const char *name1, *name2;
|
|
const void *value;
|
|
size_t value_len;
|
|
struct spdk_xattr_names *names;
|
|
|
|
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;
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_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;
|
|
|
|
/* Test that set_xattr fails if md_ro flag is set. */
|
|
blob->md_ro = true;
|
|
rc = spdk_blob_md_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
|
|
CU_ASSERT(rc == -EPERM);
|
|
|
|
blob->md_ro = false;
|
|
rc = spdk_blob_md_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
length = 2345;
|
|
rc = spdk_blob_md_set_xattr(blob, "length", &length, sizeof(length));
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/* Overwrite "length" xattr. */
|
|
length = 3456;
|
|
rc = spdk_blob_md_set_xattr(blob, "length", &length, sizeof(length));
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/* get_xattr should still work even if md_ro flag is set. */
|
|
value = NULL;
|
|
blob->md_ro = true;
|
|
rc = spdk_bs_md_get_xattr_value(blob, "length", &value, &value_len);
|
|
CU_ASSERT(rc == 0);
|
|
SPDK_CU_ASSERT_FATAL(value != NULL);
|
|
CU_ASSERT(*(uint64_t *)value == length);
|
|
CU_ASSERT(value_len == 8);
|
|
blob->md_ro = false;
|
|
|
|
rc = spdk_bs_md_get_xattr_value(blob, "foobar", &value, &value_len);
|
|
CU_ASSERT(rc == -ENOENT);
|
|
|
|
names = NULL;
|
|
rc = spdk_bs_md_get_xattr_names(blob, &names);
|
|
CU_ASSERT(rc == 0);
|
|
SPDK_CU_ASSERT_FATAL(names != NULL);
|
|
CU_ASSERT(spdk_xattr_names_get_count(names) == 2);
|
|
name1 = spdk_xattr_names_get_name(names, 0);
|
|
SPDK_CU_ASSERT_FATAL(name1 != NULL);
|
|
CU_ASSERT(!strcmp(name1, "name") || !strcmp(name1, "length"));
|
|
name2 = spdk_xattr_names_get_name(names, 1);
|
|
SPDK_CU_ASSERT_FATAL(name2 != NULL);
|
|
CU_ASSERT(!strcmp(name2, "name") || !strcmp(name2, "length"));
|
|
CU_ASSERT(strcmp(name1, name2));
|
|
spdk_xattr_names_free(names);
|
|
|
|
/* Confirm that remove_xattr fails if md_ro is set to true. */
|
|
blob->md_ro = true;
|
|
rc = spdk_blob_md_remove_xattr(blob, "name");
|
|
CU_ASSERT(rc == -EPERM);
|
|
|
|
blob->md_ro = false;
|
|
rc = spdk_blob_md_remove_xattr(blob, "name");
|
|
CU_ASSERT(rc == 0);
|
|
|
|
rc = spdk_blob_md_remove_xattr(blob, "foobar");
|
|
CU_ASSERT(rc == -ENOENT);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
bs_load(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
spdk_blob_id blobid;
|
|
struct spdk_blob *blob;
|
|
struct spdk_bs_super_block *super_block;
|
|
uint64_t length;
|
|
int rc;
|
|
const void *value;
|
|
size_t value_len;
|
|
struct spdk_bs_opts opts;
|
|
|
|
g_scheduler_delay = true;
|
|
|
|
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);
|
|
|
|
/* Try to open a blobid that does not exist */
|
|
spdk_bs_md_open_blob(g_bs, 0, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -ENOENT);
|
|
CU_ASSERT(g_blob == NULL);
|
|
|
|
/* Create a blob */
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Try again to open valid blob but without the upper bit set */
|
|
spdk_bs_md_open_blob(g_bs, blobid & 0xFFFFFFFF, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -ENOENT);
|
|
CU_ASSERT(g_blob == NULL);
|
|
|
|
/* Set some xattrs */
|
|
rc = spdk_blob_md_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
length = 2345;
|
|
rc = spdk_blob_md_set_xattr(blob, "length", &length, sizeof(length));
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/* Resize the blob */
|
|
rc = spdk_bs_md_resize_blob(blob, 10);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
/* 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;
|
|
|
|
super_block = (struct spdk_bs_super_block *)g_dev_buffer;
|
|
CU_ASSERT(super_block->clean == 1);
|
|
|
|
|
|
/* Load an existing blob store */
|
|
dev = init_dev();
|
|
strncpy(opts.bstype.bstype, "TESTTYPE", SPDK_BLOBSTORE_TYPE_LENGTH);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
super_block = (struct spdk_bs_super_block *)g_dev_buffer;
|
|
CU_ASSERT(super_block->clean == 0);
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Get the xattrs */
|
|
value = NULL;
|
|
rc = spdk_bs_md_get_xattr_value(blob, "length", &value, &value_len);
|
|
CU_ASSERT(rc == 0);
|
|
SPDK_CU_ASSERT_FATAL(value != NULL);
|
|
CU_ASSERT(*(uint64_t *)value == length);
|
|
CU_ASSERT(value_len == 8);
|
|
|
|
rc = spdk_bs_md_get_xattr_value(blob, "foobar", &value, &value_len);
|
|
CU_ASSERT(rc == -ENOENT);
|
|
|
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
g_scheduler_delay = false;
|
|
}
|
|
|
|
static void
|
|
bs_type(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_bs_opts opts;
|
|
|
|
g_scheduler_delay = true;
|
|
|
|
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);
|
|
|
|
/* 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;
|
|
|
|
/* Load non existing blobstore type */
|
|
dev = init_dev();
|
|
strncpy(opts.bstype.bstype, "NONEXISTING", SPDK_BLOBSTORE_TYPE_LENGTH);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno != 0);
|
|
|
|
/* Load with empty blobstore type */
|
|
dev = init_dev();
|
|
strncpy(opts.bstype.bstype, "", SPDK_BLOBSTORE_TYPE_LENGTH);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
|
|
/* Initialize a new blob store with empty bstype */
|
|
dev = init_dev();
|
|
strncpy(opts.bstype.bstype, "", SPDK_BLOBSTORE_TYPE_LENGTH);
|
|
spdk_bs_init(dev, NULL, 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;
|
|
|
|
/* Load non existing blobstore type */
|
|
dev = init_dev();
|
|
strncpy(opts.bstype.bstype, "NONEXISTING", SPDK_BLOBSTORE_TYPE_LENGTH);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno != 0);
|
|
|
|
/* Load with empty blobstore type */
|
|
dev = init_dev();
|
|
strncpy(opts.bstype.bstype, "", SPDK_BLOBSTORE_TYPE_LENGTH);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
g_scheduler_delay = false;
|
|
}
|
|
|
|
static void
|
|
bs_super_block(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_bs_super_block *super_block;
|
|
struct spdk_bs_opts opts;
|
|
struct spdk_bs_super_block_ver1 super_block_v1;
|
|
|
|
g_scheduler_delay = true;
|
|
|
|
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);
|
|
|
|
/* 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;
|
|
|
|
/* Load an existing blob store with version newer than supported */
|
|
super_block = (struct spdk_bs_super_block *)g_dev_buffer;
|
|
super_block->version++;
|
|
|
|
dev = init_dev();
|
|
strncpy(opts.bstype.bstype, "", SPDK_BLOBSTORE_TYPE_LENGTH);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno != 0);
|
|
|
|
/* Create a new blob store with super block version 1 */
|
|
dev = init_dev();
|
|
super_block_v1.version = 1;
|
|
strncpy(super_block_v1.signature, "SPDKBLOB", sizeof(super_block_v1.signature));
|
|
super_block_v1.length = 0x1000;
|
|
super_block_v1.clean = 1;
|
|
super_block_v1.super_blob = 0xFFFFFFFFFFFFFFFF;
|
|
super_block_v1.cluster_size = 0x100000;
|
|
super_block_v1.used_page_mask_start = 0x01;
|
|
super_block_v1.used_page_mask_len = 0x01;
|
|
super_block_v1.used_cluster_mask_start = 0x02;
|
|
super_block_v1.used_cluster_mask_len = 0x01;
|
|
super_block_v1.md_start = 0x03;
|
|
super_block_v1.md_len = 0x40;
|
|
memset(super_block_v1.reserved, 0, 4036);
|
|
super_block_v1.crc = _spdk_blob_md_page_calc_crc(&super_block_v1);
|
|
memcpy(g_dev_buffer, &super_block_v1, sizeof(struct spdk_bs_super_block_ver1));
|
|
|
|
strncpy(opts.bstype.bstype, "", SPDK_BLOBSTORE_TYPE_LENGTH);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
g_scheduler_delay = false;
|
|
}
|
|
|
|
/*
|
|
* Create a blobstore and then unload it.
|
|
*/
|
|
static void
|
|
bs_unload(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob_store *bs;
|
|
spdk_blob_id blobid;
|
|
struct spdk_blob *blob;
|
|
|
|
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;
|
|
|
|
/* Create a blob and open it. */
|
|
g_bserrno = -1;
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid > 0);
|
|
blobid = g_blobid;
|
|
|
|
g_bserrno = -1;
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Try to unload blobstore, should fail with open blob */
|
|
g_bserrno = -1;
|
|
spdk_bs_unload(bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EBUSY);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
/* Close the blob, then successfully unload blobstore */
|
|
g_bserrno = -1;
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(blob == NULL);
|
|
|
|
g_bserrno = -1;
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
/*
|
|
* Create a blobstore with a cluster size different than the default, and ensure it is
|
|
* persisted.
|
|
*/
|
|
static void
|
|
bs_cluster_sz(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_bs_opts opts;
|
|
uint32_t cluster_sz;
|
|
|
|
/* Set cluster size to zero */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
opts.cluster_sz = 0;
|
|
|
|
/* Initialize a new blob store */
|
|
spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
SPDK_CU_ASSERT_FATAL(g_bs == NULL);
|
|
|
|
/*
|
|
* Set cluster size to blobstore page size,
|
|
* to work it is required to be at least twice the blobstore page size.
|
|
*/
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
opts.cluster_sz = SPDK_BS_PAGE_SIZE;
|
|
|
|
/* Initialize a new blob store */
|
|
spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -ENOMEM);
|
|
SPDK_CU_ASSERT_FATAL(g_bs == NULL);
|
|
|
|
/*
|
|
* Set cluster size to lower than page size,
|
|
* to work it is required to be at least twice the blobstore page size.
|
|
*/
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
opts.cluster_sz = SPDK_BS_PAGE_SIZE - 1;
|
|
|
|
/* Initialize a new blob store */
|
|
spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -ENOMEM);
|
|
SPDK_CU_ASSERT_FATAL(g_bs == NULL);
|
|
|
|
/* Set cluster size to twice the default */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
opts.cluster_sz *= 2;
|
|
cluster_sz = opts.cluster_sz;
|
|
|
|
/* 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);
|
|
|
|
CU_ASSERT(spdk_bs_get_cluster_size(g_bs) == cluster_sz);
|
|
|
|
/* 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;
|
|
|
|
dev = init_dev();
|
|
/* Load an existing blob store */
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
CU_ASSERT(spdk_bs_get_cluster_size(g_bs) == cluster_sz);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
/*
|
|
* Create a blobstore, reload it and ensure total usable cluster count
|
|
* stays the same.
|
|
*/
|
|
static void
|
|
bs_usable_clusters(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_bs_opts opts;
|
|
uint32_t clusters;
|
|
int i, rc;
|
|
|
|
/* Init blobstore */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
|
|
spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
clusters = spdk_bs_total_data_cluster_count(g_bs);
|
|
|
|
/* Unload the blob store */
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
|
|
dev = init_dev();
|
|
/* Load an existing blob store */
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
CU_ASSERT(spdk_bs_total_data_cluster_count(g_bs) == clusters);
|
|
|
|
/* Create and resize blobs to make sure that useable cluster count won't change */
|
|
for (i = 0; i < 4; i++) {
|
|
g_bserrno = -1;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
|
|
g_bserrno = -1;
|
|
g_blob = NULL;
|
|
spdk_bs_md_open_blob(g_bs, g_blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
|
|
rc = spdk_bs_md_resize_blob(g_blob, 10);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
g_bserrno = -1;
|
|
spdk_bs_md_close_blob(&g_blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
CU_ASSERT(spdk_bs_total_data_cluster_count(g_bs) == clusters);
|
|
}
|
|
|
|
/* Reload the blob store to make sure that nothing changed */
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
|
|
dev = init_dev();
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
CU_ASSERT(spdk_bs_total_data_cluster_count(g_bs) == clusters);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
/*
|
|
* Test resizing of the metadata blob. This requires creating enough blobs
|
|
* so that one cluster is not enough to fit the metadata for those blobs.
|
|
* To induce this condition to happen more quickly, we reduce the cluster
|
|
* size to 16KB, which means only 4 4KB blob metadata pages can fit.
|
|
*/
|
|
static void
|
|
bs_resize_md(void)
|
|
{
|
|
const int CLUSTER_PAGE_COUNT = 4;
|
|
const int NUM_BLOBS = CLUSTER_PAGE_COUNT * 4;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_bs_opts opts;
|
|
uint32_t cluster_sz;
|
|
spdk_blob_id blobids[NUM_BLOBS];
|
|
int i;
|
|
|
|
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
opts.cluster_sz = CLUSTER_PAGE_COUNT * 4096;
|
|
cluster_sz = opts.cluster_sz;
|
|
|
|
/* 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);
|
|
|
|
CU_ASSERT(spdk_bs_get_cluster_size(g_bs) == cluster_sz);
|
|
|
|
for (i = 0; i < NUM_BLOBS; i++) {
|
|
g_bserrno = -1;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
spdk_bs_md_create_blob(g_bs,
|
|
blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobids[i] = g_blobid;
|
|
}
|
|
|
|
/* Unload the blob store */
|
|
g_bserrno = -1;
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/* Load an existing blob store */
|
|
g_bserrno = -1;
|
|
g_bs = NULL;
|
|
dev = init_dev();
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
CU_ASSERT(spdk_bs_get_cluster_size(g_bs) == cluster_sz);
|
|
|
|
for (i = 0; i < NUM_BLOBS; i++) {
|
|
g_bserrno = -1;
|
|
g_blob = NULL;
|
|
spdk_bs_md_open_blob(g_bs, blobids[i], blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
g_bserrno = -1;
|
|
spdk_bs_md_close_blob(&g_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;
|
|
}
|
|
|
|
static void
|
|
bs_destroy(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_bs_opts opts;
|
|
|
|
g_scheduler_delay = true;
|
|
|
|
_bs_flush_scheduler();
|
|
CU_ASSERT(TAILQ_EMPTY(&g_scheduled_ops));
|
|
|
|
/* Initialize a new blob store */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
/* Destroy the blob store */
|
|
g_bserrno = -1;
|
|
spdk_bs_destroy(g_bs, bs_op_complete, NULL);
|
|
/* Callback is called after device is destroyed in next scheduler run. */
|
|
_bs_flush_scheduler();
|
|
CU_ASSERT(TAILQ_EMPTY(&g_scheduled_ops));
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/* Loading an non-existent blob store should fail. */
|
|
g_bserrno = -1;
|
|
g_bs = NULL;
|
|
dev = init_dev();
|
|
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno != 0);
|
|
g_scheduler_delay = false;
|
|
}
|
|
|
|
/* Try to hit all of the corner cases associated with serializing
|
|
* a blob to disk
|
|
*/
|
|
static void
|
|
blob_serialize(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_bs_opts opts;
|
|
struct spdk_blob_store *bs;
|
|
spdk_blob_id blobid[2];
|
|
struct spdk_blob *blob[2];
|
|
uint64_t i;
|
|
char *value;
|
|
int rc;
|
|
|
|
dev = init_dev();
|
|
|
|
/* Initialize a new blobstore with very small clusters */
|
|
spdk_bs_opts_init(&opts);
|
|
opts.cluster_sz = dev->blocklen * 8;
|
|
spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
bs = g_bs;
|
|
|
|
/* Create and open two blobs */
|
|
for (i = 0; i < 2; i++) {
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid[i] = g_blobid;
|
|
|
|
/* Open a blob */
|
|
spdk_bs_md_open_blob(bs, blobid[i], blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob[i] = g_blob;
|
|
|
|
/* Set a fairly large xattr on both blobs to eat up
|
|
* metadata space
|
|
*/
|
|
value = calloc(dev->blocklen - 64, sizeof(char));
|
|
SPDK_CU_ASSERT_FATAL(value != NULL);
|
|
memset(value, i, dev->blocklen / 2);
|
|
rc = spdk_blob_md_set_xattr(blob[i], "name", value, dev->blocklen - 64);
|
|
CU_ASSERT(rc == 0);
|
|
free(value);
|
|
}
|
|
|
|
/* Resize the blobs, alternating 1 cluster at a time.
|
|
* This thwarts run length encoding and will cause spill
|
|
* over of the extents.
|
|
*/
|
|
for (i = 0; i < 6; i++) {
|
|
rc = spdk_bs_md_resize_blob(blob[i % 2], (i / 2) + 1);
|
|
CU_ASSERT(rc == 0);
|
|
}
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
spdk_bs_md_sync_blob(blob[i], blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
}
|
|
|
|
/* Close the blobs */
|
|
for (i = 0; i < 2; i++) {
|
|
spdk_bs_md_close_blob(&blob[i], blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
}
|
|
|
|
/* Unload the blobstore */
|
|
spdk_bs_unload(bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = 0;
|
|
bs = NULL;
|
|
|
|
dev = init_dev();
|
|
/* Load an existing blob store */
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
bs = g_bs;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
blob[i] = NULL;
|
|
|
|
spdk_bs_md_open_blob(bs, blobid[i], blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob[i] = g_blob;
|
|
|
|
CU_ASSERT(spdk_blob_get_num_clusters(blob[i]) == 3);
|
|
|
|
spdk_bs_md_close_blob(&blob[i], blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
}
|
|
|
|
spdk_bs_unload(bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_crc(void)
|
|
{
|
|
struct spdk_blob_store *bs;
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_blob *blob;
|
|
spdk_blob_id blobid;
|
|
uint32_t page_num;
|
|
int index;
|
|
struct spdk_blob_md_page *page;
|
|
|
|
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;
|
|
|
|
spdk_bs_md_create_blob(bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(blob == NULL);
|
|
|
|
page_num = _spdk_bs_blobid_to_page(blobid);
|
|
index = DEV_BUFFER_BLOCKLEN * (bs->md_start + page_num);
|
|
page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
|
|
page->crc = 0;
|
|
|
|
spdk_bs_md_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
CU_ASSERT(g_blob == NULL);
|
|
g_bserrno = 0;
|
|
|
|
spdk_bs_md_delete_blob(bs, blobid, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == -EINVAL);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
super_block_crc(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
struct spdk_bs_super_block *super_block;
|
|
struct spdk_bs_opts opts;
|
|
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
|
|
spdk_bs_init(dev, NULL, 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;
|
|
|
|
super_block = (struct spdk_bs_super_block *)g_dev_buffer;
|
|
super_block->crc = 0;
|
|
dev = init_dev();
|
|
|
|
g_scheduler_delay = true;
|
|
/* Load an existing blob store */
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
|
|
CU_ASSERT(g_bserrno == -EILSEQ);
|
|
_bs_flush_scheduler();
|
|
CU_ASSERT(TAILQ_EMPTY(&g_scheduled_ops));
|
|
|
|
g_scheduler_delay = false;
|
|
}
|
|
|
|
/* For blob dirty shutdown test case we do the following sub-test cases:
|
|
* 1 Initialize new blob store and create 1 blob with some xattrs, then we
|
|
* dirty shutdown and reload the blob store and verify the xattrs.
|
|
* 2 Resize the blob from 10 clusters to 20 clusters and then dirty shutdown,
|
|
* reload the blob store and verify the clusters number.
|
|
* 3 Create the second blob and then dirty shutdown, reload the blob store
|
|
* and verify the second blob.
|
|
* 4 Delete the second blob and then dirty shutdown, reload teh blob store
|
|
* and verify the second blob is invalid.
|
|
* 5 Create the second blob again and also create the third blob, modify the
|
|
* md of second blob which makes the md invalid, and then dirty shutdown,
|
|
* reload the blob store verify the second blob, it should invalid and also
|
|
* verify the third blob, it should correct.
|
|
*/
|
|
static void
|
|
blob_dirty_shutdown(void)
|
|
{
|
|
int rc;
|
|
int index;
|
|
struct spdk_bs_dev *dev;
|
|
spdk_blob_id blobid1, blobid2, blobid3;
|
|
struct spdk_blob *blob;
|
|
uint64_t length;
|
|
const void *value;
|
|
size_t value_len;
|
|
uint32_t page_num;
|
|
struct spdk_blob_md_page *page;
|
|
struct spdk_bs_opts opts;
|
|
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
/* Initialize a new blob store */
|
|
spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
/* Create first blob */
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid1 = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid1, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Set some xattrs */
|
|
rc = spdk_blob_md_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
length = 2345;
|
|
rc = spdk_blob_md_set_xattr(blob, "length", &length, sizeof(length));
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/* Resize the blob */
|
|
rc = spdk_bs_md_resize_blob(blob, 10);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
/* Dirty shutdown */
|
|
_spdk_bs_free(g_bs);
|
|
|
|
/* reload blobstore */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid1, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Get the xattrs */
|
|
value = NULL;
|
|
rc = spdk_bs_md_get_xattr_value(blob, "length", &value, &value_len);
|
|
CU_ASSERT(rc == 0);
|
|
SPDK_CU_ASSERT_FATAL(value != NULL);
|
|
CU_ASSERT(*(uint64_t *)value == length);
|
|
CU_ASSERT(value_len == 8);
|
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
|
|
|
|
/* Resize the blob */
|
|
rc = spdk_bs_md_resize_blob(blob, 20);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
/* Dirty shutdown */
|
|
_spdk_bs_free(g_bs);
|
|
|
|
/* reload the blobstore */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
/* Load an existing blob store */
|
|
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_md_open_blob(g_bs, blobid1, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 20);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
/* Create second blob */
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid2 = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid2, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Set some xattrs */
|
|
rc = spdk_blob_md_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
length = 5432;
|
|
rc = spdk_blob_md_set_xattr(blob, "length", &length, sizeof(length));
|
|
CU_ASSERT(rc == 0);
|
|
|
|
/* Resize the blob */
|
|
rc = spdk_bs_md_resize_blob(blob, 10);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
/* Dirty shutdown */
|
|
_spdk_bs_free(g_bs);
|
|
|
|
/* reload the blobstore */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid2, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Get the xattrs */
|
|
value = NULL;
|
|
rc = spdk_bs_md_get_xattr_value(blob, "length", &value, &value_len);
|
|
CU_ASSERT(rc == 0);
|
|
SPDK_CU_ASSERT_FATAL(value != NULL);
|
|
CU_ASSERT(*(uint64_t *)value == length);
|
|
CU_ASSERT(value_len == 8);
|
|
CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
spdk_bs_md_delete_blob(g_bs, blobid2, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/* Dirty shutdown */
|
|
_spdk_bs_free(g_bs);
|
|
/* reload the blobstore */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid2, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno != 0);
|
|
CU_ASSERT(g_blob == NULL);
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid1, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
spdk_bs_md_close_blob(&g_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;
|
|
|
|
/* reload the blobstore */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
/* Create second blob */
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid2 = g_blobid;
|
|
|
|
/* Create third blob */
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid3 = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid2, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Set some xattrs for second blob */
|
|
rc = spdk_blob_md_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
length = 5432;
|
|
rc = spdk_blob_md_set_xattr(blob, "length", &length, sizeof(length));
|
|
CU_ASSERT(rc == 0);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid3, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
/* Set some xattrs for third blob */
|
|
rc = spdk_blob_md_set_xattr(blob, "name", "log2.txt", strlen("log2.txt") + 1);
|
|
CU_ASSERT(rc == 0);
|
|
|
|
length = 5432;
|
|
rc = spdk_blob_md_set_xattr(blob, "length", &length, sizeof(length));
|
|
CU_ASSERT(rc == 0);
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
/* Mark second blob as invalid */
|
|
page_num = _spdk_bs_blobid_to_page(blobid2);
|
|
|
|
index = DEV_BUFFER_BLOCKLEN * (g_bs->md_start + page_num);
|
|
page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
|
|
page->sequence_num = 1;
|
|
page->crc = _spdk_blob_md_page_calc_crc(page);
|
|
|
|
/* Dirty shutdown */
|
|
_spdk_bs_free(g_bs);
|
|
/* reload the blobstore */
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid2, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno != 0);
|
|
CU_ASSERT(g_blob == NULL);
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid3, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob = g_blob;
|
|
|
|
spdk_bs_md_close_blob(&blob, blob_op_complete, NULL);
|
|
blob = NULL;
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
}
|
|
|
|
static void
|
|
blob_flags(void)
|
|
{
|
|
struct spdk_bs_dev *dev;
|
|
spdk_blob_id blobid_invalid, blobid_data_ro, blobid_md_ro;
|
|
struct spdk_blob *blob_invalid, *blob_data_ro, *blob_md_ro;
|
|
struct spdk_bs_opts opts;
|
|
|
|
dev = init_dev();
|
|
spdk_bs_opts_init(&opts);
|
|
|
|
/* 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);
|
|
|
|
/* Create three blobs - one each for testing invalid, data_ro and md_ro flags. */
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid_invalid = g_blobid;
|
|
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid_data_ro = g_blobid;
|
|
|
|
spdk_bs_md_create_blob(g_bs, blob_op_with_id_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
|
|
blobid_md_ro = g_blobid;
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid_invalid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob_invalid = g_blob;
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid_data_ro, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob_data_ro = g_blob;
|
|
|
|
spdk_bs_md_open_blob(g_bs, blobid_md_ro, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
CU_ASSERT(g_blob != NULL);
|
|
blob_md_ro = g_blob;
|
|
|
|
blob_invalid->invalid_flags = (1ULL << 63);
|
|
blob_invalid->state = SPDK_BLOB_STATE_DIRTY;
|
|
blob_data_ro->data_ro_flags = (1ULL << 62);
|
|
blob_data_ro->state = SPDK_BLOB_STATE_DIRTY;
|
|
blob_md_ro->md_ro_flags = (1ULL << 61);
|
|
blob_md_ro->state = SPDK_BLOB_STATE_DIRTY;
|
|
|
|
g_bserrno = -1;
|
|
spdk_bs_md_sync_blob(blob_invalid, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bserrno = -1;
|
|
spdk_bs_md_sync_blob(blob_data_ro, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bserrno = -1;
|
|
spdk_bs_md_sync_blob(blob_md_ro, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
g_bserrno = -1;
|
|
spdk_bs_md_close_blob(&blob_invalid, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob_invalid = NULL;
|
|
g_bserrno = -1;
|
|
spdk_bs_md_close_blob(&blob_data_ro, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob_data_ro = NULL;
|
|
g_bserrno = -1;
|
|
spdk_bs_md_close_blob(&blob_md_ro, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
blob_md_ro = NULL;
|
|
|
|
g_blob = NULL;
|
|
g_blobid = SPDK_BLOBID_INVALID;
|
|
|
|
/* Unload the blob store */
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
g_bs = NULL;
|
|
|
|
/* Load an existing blob store */
|
|
dev = init_dev();
|
|
spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_bs != NULL);
|
|
|
|
g_blob = NULL;
|
|
g_bserrno = 0;
|
|
spdk_bs_md_open_blob(g_bs, blobid_invalid, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno != 0);
|
|
CU_ASSERT(g_blob == NULL);
|
|
|
|
g_blob = NULL;
|
|
g_bserrno = -1;
|
|
spdk_bs_md_open_blob(g_bs, blobid_data_ro, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_blob != NULL);
|
|
blob_data_ro = g_blob;
|
|
/* If an unknown data_ro flag was found, the blob should be marked both data and md read-only. */
|
|
CU_ASSERT(blob_data_ro->data_ro == true);
|
|
CU_ASSERT(blob_data_ro->md_ro == true);
|
|
|
|
g_blob = NULL;
|
|
g_bserrno = -1;
|
|
spdk_bs_md_open_blob(g_bs, blobid_md_ro, blob_op_with_handle_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
SPDK_CU_ASSERT_FATAL(g_blob != NULL);
|
|
blob_md_ro = g_blob;
|
|
CU_ASSERT(blob_md_ro->data_ro == false);
|
|
CU_ASSERT(blob_md_ro->md_ro == true);
|
|
|
|
spdk_bs_md_close_blob(&blob_data_ro, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
spdk_bs_md_close_blob(&blob_md_ro, blob_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
|
|
spdk_bs_unload(g_bs, bs_op_complete, NULL);
|
|
CU_ASSERT(g_bserrno == 0);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
CU_pSuite suite = NULL;
|
|
unsigned int num_failures;
|
|
|
|
if (CU_initialize_registry() != CUE_SUCCESS) {
|
|
return CU_get_error();
|
|
}
|
|
|
|
suite = CU_add_suite("blob", NULL, NULL);
|
|
if (suite == NULL) {
|
|
CU_cleanup_registry();
|
|
return CU_get_error();
|
|
}
|
|
|
|
if (
|
|
CU_add_test(suite, "blob_init", blob_init) == NULL ||
|
|
CU_add_test(suite, "blob_open", blob_open) == NULL ||
|
|
CU_add_test(suite, "blob_delete", blob_delete) == NULL ||
|
|
CU_add_test(suite, "blob_resize", blob_resize) == NULL ||
|
|
CU_add_test(suite, "channel_ops", channel_ops) == NULL ||
|
|
CU_add_test(suite, "blob_super", blob_super) == NULL ||
|
|
CU_add_test(suite, "blob_write", blob_write) == NULL ||
|
|
CU_add_test(suite, "blob_read", blob_read) == NULL ||
|
|
CU_add_test(suite, "blob_rw_verify", blob_rw_verify) == NULL ||
|
|
CU_add_test(suite, "blob_rw_verify_iov", blob_rw_verify_iov) == NULL ||
|
|
CU_add_test(suite, "blob_rw_verify_iov_nomem", blob_rw_verify_iov_nomem) == NULL ||
|
|
CU_add_test(suite, "blob_rw_iov_read_only", blob_rw_iov_read_only) == NULL ||
|
|
CU_add_test(suite, "blob_iter", blob_iter) == NULL ||
|
|
CU_add_test(suite, "blob_xattr", blob_xattr) == NULL ||
|
|
CU_add_test(suite, "bs_load", bs_load) == NULL ||
|
|
CU_add_test(suite, "bs_unload", bs_unload) == NULL ||
|
|
CU_add_test(suite, "bs_cluster_sz", bs_cluster_sz) == NULL ||
|
|
CU_add_test(suite, "bs_usable_clusters", bs_usable_clusters) == NULL ||
|
|
CU_add_test(suite, "bs_resize_md", bs_resize_md) == NULL ||
|
|
CU_add_test(suite, "bs_destroy", bs_destroy) == NULL ||
|
|
CU_add_test(suite, "bs_type", bs_type) == NULL ||
|
|
CU_add_test(suite, "bs_super_block", bs_super_block) == NULL ||
|
|
CU_add_test(suite, "blob_serialize", blob_serialize) == NULL ||
|
|
CU_add_test(suite, "blob_crc", blob_crc) == NULL ||
|
|
CU_add_test(suite, "super_block_crc", super_block_crc) == NULL ||
|
|
CU_add_test(suite, "blob_dirty_shutdown", blob_dirty_shutdown) == NULL ||
|
|
CU_add_test(suite, "blob_flags", blob_flags) == NULL
|
|
) {
|
|
CU_cleanup_registry();
|
|
return CU_get_error();
|
|
}
|
|
|
|
g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
|
|
spdk_allocate_thread(_bs_send_msg, NULL, NULL, NULL, "thread0");
|
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
|
CU_basic_run_tests();
|
|
num_failures = CU_get_number_of_failures();
|
|
CU_cleanup_registry();
|
|
spdk_free_thread();
|
|
free(g_dev_buffer);
|
|
return num_failures;
|
|
}
|