2017-03-22 20:35:00 +00:00
|
|
|
/*-
|
|
|
|
* 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 <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "CUnit/Basic.h"
|
|
|
|
|
|
|
|
#include "lib/test_env.c"
|
|
|
|
|
|
|
|
#include "spdk_cunit.h"
|
|
|
|
#include "blobfs.c"
|
|
|
|
#include "tree.c"
|
|
|
|
|
|
|
|
#include "lib/blob/bs_dev_common.c"
|
|
|
|
|
|
|
|
struct spdk_filesystem *g_fs;
|
|
|
|
struct spdk_file *g_file;
|
|
|
|
int g_fserrno;
|
|
|
|
|
|
|
|
static void
|
|
|
|
fs_op_complete(void *ctx, int fserrno)
|
|
|
|
{
|
|
|
|
g_fserrno = fserrno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fs_op_with_handle_complete(void *ctx, struct spdk_filesystem *fs, int fserrno)
|
|
|
|
{
|
|
|
|
g_fs = fs;
|
|
|
|
g_fserrno = fserrno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fs_init(void)
|
|
|
|
{
|
|
|
|
struct spdk_filesystem *fs;
|
|
|
|
struct spdk_bs_dev dev;
|
|
|
|
|
|
|
|
init_dev(&dev);
|
|
|
|
spdk_allocate_thread();
|
|
|
|
|
|
|
|
spdk_fs_init(&dev, NULL, fs_op_with_handle_complete, NULL);
|
|
|
|
CU_ASSERT(g_fs != NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
fs = g_fs;
|
|
|
|
|
|
|
|
spdk_fs_unload(fs, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
|
|
|
|
spdk_free_thread();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
create_cb(void *ctx, int fserrno)
|
|
|
|
{
|
|
|
|
g_fserrno = fserrno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
open_cb(void *ctx, struct spdk_file *f, int fserrno)
|
|
|
|
{
|
|
|
|
g_fserrno = fserrno;
|
|
|
|
g_file = f;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
delete_cb(void *ctx, int fserrno)
|
|
|
|
{
|
|
|
|
g_fserrno = fserrno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fs_open(void)
|
|
|
|
{
|
|
|
|
struct spdk_filesystem *fs;
|
|
|
|
spdk_fs_iter iter;
|
|
|
|
struct spdk_bs_dev dev;
|
|
|
|
struct spdk_file *file;
|
|
|
|
|
|
|
|
init_dev(&dev);
|
|
|
|
spdk_allocate_thread();
|
|
|
|
|
|
|
|
spdk_fs_init(&dev, NULL, fs_op_with_handle_complete, NULL);
|
|
|
|
CU_ASSERT(g_fs != NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
fs = g_fs;
|
|
|
|
|
|
|
|
g_fserrno = 0;
|
|
|
|
spdk_fs_open_file_async(fs, "file1", 0, open_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == -ENOENT);
|
|
|
|
|
|
|
|
g_file = NULL;
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
SPDK_CU_ASSERT_FATAL(g_file != NULL);
|
|
|
|
CU_ASSERT(!strcmp("file1", g_file->name));
|
|
|
|
CU_ASSERT(g_file->ref_count == 1);
|
|
|
|
|
|
|
|
iter = spdk_fs_iter_first(fs);
|
|
|
|
CU_ASSERT(iter != NULL);
|
|
|
|
file = spdk_fs_iter_get_file(iter);
|
|
|
|
SPDK_CU_ASSERT_FATAL(file != NULL);
|
|
|
|
CU_ASSERT(!strcmp("file1", file->name));
|
|
|
|
iter = spdk_fs_iter_next(iter);
|
|
|
|
CU_ASSERT(iter == NULL);
|
|
|
|
|
|
|
|
g_fserrno = 0;
|
|
|
|
/* Delete should fail, since we have an open reference. */
|
|
|
|
spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == -EBUSY);
|
|
|
|
CU_ASSERT(!TAILQ_EMPTY(&fs->files));
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_file_close_async(g_file, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(g_file->ref_count == 0);
|
|
|
|
|
|
|
|
g_fserrno = 0;
|
|
|
|
spdk_file_close_async(g_file, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == -EBADF);
|
|
|
|
CU_ASSERT(g_file->ref_count == 0);
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(TAILQ_EMPTY(&fs->files));
|
|
|
|
|
|
|
|
spdk_fs_unload(fs, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
|
|
|
|
spdk_free_thread();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fs_truncate(void)
|
|
|
|
{
|
|
|
|
struct spdk_filesystem *fs;
|
|
|
|
struct spdk_bs_dev dev;
|
|
|
|
|
|
|
|
init_dev(&dev);
|
|
|
|
spdk_allocate_thread();
|
|
|
|
|
|
|
|
spdk_fs_init(&dev, NULL, fs_op_with_handle_complete, NULL);
|
|
|
|
SPDK_CU_ASSERT_FATAL(g_fs != NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
fs = g_fs;
|
|
|
|
|
|
|
|
g_file = NULL;
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_open_file_async(fs, "file1", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
SPDK_CU_ASSERT_FATAL(g_file != NULL);
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_file_truncate_async(g_file, 18 * 1024 * 1024 + 1, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(g_file->length == 18 * 1024 * 1024 + 1);
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_file_truncate_async(g_file, 1, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(g_file->length == 1);
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_file_truncate_async(g_file, 18 * 1024 * 1024 + 1, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(g_file->length == 18 * 1024 * 1024 + 1);
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_file_close_async(g_file, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(g_file->ref_count == 0);
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(TAILQ_EMPTY(&fs->files));
|
|
|
|
|
|
|
|
spdk_fs_unload(fs, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
|
|
|
|
spdk_free_thread();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fs_rename(void)
|
|
|
|
{
|
|
|
|
struct spdk_filesystem *fs;
|
|
|
|
struct spdk_file *file, *file2;
|
|
|
|
struct spdk_bs_dev dev;
|
|
|
|
|
|
|
|
init_dev(&dev);
|
|
|
|
spdk_allocate_thread();
|
|
|
|
|
|
|
|
spdk_fs_init(&dev, NULL, fs_op_with_handle_complete, NULL);
|
|
|
|
SPDK_CU_ASSERT_FATAL(g_fs != NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
fs = g_fs;
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_create_file_async(fs, "file1", create_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
|
|
|
|
g_file = NULL;
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_open_file_async(fs, "file1", 0, open_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
SPDK_CU_ASSERT_FATAL(g_file != NULL);
|
|
|
|
CU_ASSERT(g_file->ref_count == 1);
|
|
|
|
|
|
|
|
file = g_file;
|
|
|
|
g_file = NULL;
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_file_close_async(file, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
SPDK_CU_ASSERT_FATAL(file->ref_count == 0);
|
|
|
|
|
|
|
|
g_file = NULL;
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_open_file_async(fs, "file2", SPDK_BLOBFS_OPEN_CREATE, open_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
SPDK_CU_ASSERT_FATAL(g_file != NULL);
|
|
|
|
CU_ASSERT(g_file->ref_count == 1);
|
|
|
|
|
|
|
|
file2 = g_file;
|
|
|
|
g_file = NULL;
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_file_close_async(file2, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
SPDK_CU_ASSERT_FATAL(file2->ref_count == 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do a 3-way rename. This should delete the old "file2", then rename
|
|
|
|
* "file1" to "file2".
|
|
|
|
*/
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_rename_file_async(fs, "file1", "file2", fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(file->ref_count == 0);
|
|
|
|
CU_ASSERT(!strcmp(file->name, "file2"));
|
|
|
|
CU_ASSERT(TAILQ_FIRST(&fs->files) == file);
|
|
|
|
CU_ASSERT(TAILQ_NEXT(file, tailq) == NULL);
|
|
|
|
|
|
|
|
g_fserrno = 0;
|
|
|
|
spdk_fs_delete_file_async(fs, "file1", delete_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == -ENOENT);
|
|
|
|
CU_ASSERT(!TAILQ_EMPTY(&fs->files));
|
|
|
|
|
|
|
|
g_fserrno = 1;
|
|
|
|
spdk_fs_delete_file_async(fs, "file2", delete_cb, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
CU_ASSERT(TAILQ_EMPTY(&fs->files));
|
|
|
|
|
|
|
|
spdk_fs_unload(fs, fs_op_complete, NULL);
|
|
|
|
CU_ASSERT(g_fserrno == 0);
|
|
|
|
|
|
|
|
spdk_free_thread();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
tree_find_buffer_ut(void)
|
|
|
|
{
|
|
|
|
struct cache_tree *root;
|
|
|
|
struct cache_tree *level1_0;
|
|
|
|
struct cache_tree *level0_0_0;
|
|
|
|
struct cache_tree *level0_0_12;
|
|
|
|
struct cache_buffer *leaf_0_0_4;
|
|
|
|
struct cache_buffer *leaf_0_12_8;
|
|
|
|
struct cache_buffer *leaf_9_23_15;
|
|
|
|
struct cache_buffer *buffer;
|
|
|
|
|
|
|
|
level1_0 = calloc(1, sizeof(struct cache_tree));
|
2017-03-24 22:31:09 +00:00
|
|
|
SPDK_CU_ASSERT_FATAL(level1_0 != NULL);
|
2017-03-22 20:35:00 +00:00
|
|
|
level0_0_0 = calloc(1, sizeof(struct cache_tree));
|
2017-03-24 22:31:09 +00:00
|
|
|
SPDK_CU_ASSERT_FATAL(level0_0_0 != NULL);
|
2017-03-22 20:35:00 +00:00
|
|
|
level0_0_12 = calloc(1, sizeof(struct cache_tree));
|
2017-03-24 22:31:09 +00:00
|
|
|
SPDK_CU_ASSERT_FATAL(level0_0_12 != NULL);
|
2017-03-22 20:35:00 +00:00
|
|
|
leaf_0_0_4 = calloc(1, sizeof(struct cache_buffer));
|
2017-03-24 22:31:09 +00:00
|
|
|
SPDK_CU_ASSERT_FATAL(leaf_0_0_4 != NULL);
|
2017-03-22 20:35:00 +00:00
|
|
|
leaf_0_12_8 = calloc(1, sizeof(struct cache_buffer));
|
2017-03-24 22:31:09 +00:00
|
|
|
SPDK_CU_ASSERT_FATAL(leaf_0_12_8 != NULL);
|
2017-03-22 20:35:00 +00:00
|
|
|
leaf_9_23_15 = calloc(1, sizeof(struct cache_buffer));
|
2017-03-24 22:31:09 +00:00
|
|
|
SPDK_CU_ASSERT_FATAL(leaf_9_23_15 != NULL);
|
2017-03-22 20:35:00 +00:00
|
|
|
|
|
|
|
level1_0->level = 1;
|
|
|
|
level0_0_0->level = 0;
|
|
|
|
level0_0_12->level = 0;
|
|
|
|
|
|
|
|
leaf_0_0_4->offset = CACHE_BUFFER_SIZE * 4;
|
|
|
|
level0_0_0->u.buffer[4] = leaf_0_0_4;
|
|
|
|
level0_0_0->present_mask |= (1ULL << 4);
|
|
|
|
|
|
|
|
leaf_0_12_8->offset = CACHE_TREE_LEVEL_SIZE(1) * 12 + CACHE_BUFFER_SIZE * 8;
|
|
|
|
level0_0_12->u.buffer[8] = leaf_0_12_8;
|
|
|
|
level0_0_12->present_mask |= (1ULL << 8);
|
|
|
|
|
|
|
|
level1_0->u.tree[0] = level0_0_0;
|
|
|
|
level1_0->present_mask |= (1ULL << 0);
|
|
|
|
level1_0->u.tree[12] = level0_0_12;
|
|
|
|
level1_0->present_mask |= (1ULL << 12);
|
|
|
|
|
|
|
|
buffer = spdk_tree_find_buffer(NULL, 0);
|
|
|
|
CU_ASSERT(buffer == NULL);
|
|
|
|
|
|
|
|
buffer = spdk_tree_find_buffer(level0_0_0, 0);
|
|
|
|
CU_ASSERT(buffer == NULL);
|
|
|
|
|
|
|
|
buffer = spdk_tree_find_buffer(level0_0_0, CACHE_TREE_LEVEL_SIZE(0) + 1);
|
|
|
|
CU_ASSERT(buffer == NULL);
|
|
|
|
|
|
|
|
buffer = spdk_tree_find_buffer(level0_0_0, leaf_0_0_4->offset);
|
|
|
|
CU_ASSERT(buffer == leaf_0_0_4);
|
|
|
|
|
|
|
|
buffer = spdk_tree_find_buffer(level1_0, leaf_0_0_4->offset);
|
|
|
|
CU_ASSERT(buffer == leaf_0_0_4);
|
|
|
|
|
|
|
|
buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset);
|
|
|
|
CU_ASSERT(buffer == leaf_0_12_8);
|
|
|
|
|
|
|
|
buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset + CACHE_BUFFER_SIZE - 1);
|
|
|
|
CU_ASSERT(buffer == leaf_0_12_8);
|
|
|
|
|
|
|
|
buffer = spdk_tree_find_buffer(level1_0, leaf_0_12_8->offset - 1);
|
|
|
|
CU_ASSERT(buffer == NULL);
|
|
|
|
|
|
|
|
leaf_9_23_15->offset = CACHE_TREE_LEVEL_SIZE(2) * 9 +
|
|
|
|
CACHE_TREE_LEVEL_SIZE(1) * 23 +
|
|
|
|
CACHE_BUFFER_SIZE * 15;
|
|
|
|
root = spdk_tree_insert_buffer(level1_0, leaf_9_23_15);
|
|
|
|
CU_ASSERT(root != level1_0);
|
|
|
|
buffer = spdk_tree_find_buffer(root, leaf_9_23_15->offset);
|
|
|
|
CU_ASSERT(buffer == leaf_9_23_15);
|
|
|
|
spdk_tree_free_buffers(root);
|
|
|
|
free(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
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("blobfs", NULL, NULL);
|
|
|
|
if (suite == NULL) {
|
|
|
|
CU_cleanup_registry();
|
|
|
|
return CU_get_error();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
CU_add_test(suite, "fs_init", fs_init) == NULL ||
|
|
|
|
CU_add_test(suite, "fs_open", fs_open) == NULL ||
|
|
|
|
CU_add_test(suite, "fs_truncate", fs_truncate) == NULL ||
|
|
|
|
CU_add_test(suite, "fs_rename", fs_rename) == NULL ||
|
|
|
|
CU_add_test(suite, "tree_find_buffer", tree_find_buffer_ut) == NULL
|
|
|
|
) {
|
|
|
|
CU_cleanup_registry();
|
|
|
|
return CU_get_error();
|
|
|
|
}
|
|
|
|
|
|
|
|
g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
|
|
|
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
|
|
|
CU_basic_run_tests();
|
|
|
|
num_failures = CU_get_number_of_failures();
|
|
|
|
CU_cleanup_registry();
|
|
|
|
free(g_dev_buffer);
|
|
|
|
return num_failures;
|
|
|
|
}
|