#include #include #include #include #include #include #define BUFFER_SIZE 512 #define FILENAME_LENGTH 128 typedef struct zvfs_s { struct spdk_blob_store *blobstore; uint64_t unit_size; uint64_t free_cluster_count; uint64_t num_cluster; struct spdk_io_channel *channel; bool finished; } zvfs_t; typedef struct zvfs_operation_s { int (*mount)(struct zvfs_s *fs); int (*umount)(struct zvfs_s *fs); } zvfs_operation_t; typedef struct zvfs_file_s { uint8_t filename[FILENAME_LENGTH]; spdk_blob_id blob_id; struct spdk_blob *blob; zvfs_t *fs; uint8_t *write_buffer; uint8_t *read_buffer; bool finished; } zvfs_file_t; typedef struct zvfs_file_operation_s { int (*open)(struct zvfs_file_s *file); int (*read)(struct zvfs_file_s *file); int (*write)(struct zvfs_file_s *file); int (*close)(struct zvfs_file_s *file); } zvfs_file_operation_t; struct spdk_thread *global_thread = NULL; static const int WAITER_MAX_TIME = 100000; // mount void zvfs_do_mount(void *arg); void zvfs_spdk_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx); void zvfs_spdk_bs_init_cb(void *arg, struct spdk_blob_store *bs, int bserrno); // open void zvfs_do_create(void *arg); void zvfs_spdk_bs_create_blob_cb(void *arg, spdk_blob_id blobid, int bserrno); void zvfs_spdk_bs_open_blob_create_cb(void *arg, struct spdk_blob *blb, int bserrno); void zvfs_spdk_blob_resize_cb(void *arg, int bserrno); void zvfs_spdk_blob_sync_cb(void *arg, int bserrno); // read void zvfs_do_read(void *arg); void zvfs_spdk_blob_read_cb(void *arg, int bserrno); // write void zvfs_do_write(void *arg); void zvfs_spdk_blob_write_cb(void *arg, int bserrno); // close void zvfs_do_close(void *arg); void zvfs_spdk_blob_close_cb(void *arg, int bserrno); void zvfs_spdk_blob_delete_cb(void *arg, int bserrno); // waiter bool waiter(struct spdk_thread *thread, spdk_msg_fn start_fn, void *ctx, bool *finished); // setup int zvfs_env_setup(void); void zvfs_json_load_fn(void *arg); void json_app_load_done(int rc, void *ctx); // unmount void zvfs_do_umount(void *arg); void zvfs_spdk_bs_unload_cb(void *arg, int bserrno); // mount void zvfs_do_mount(void *arg) { zvfs_t *fs = (zvfs_t*)arg; struct spdk_bs_dev *bs_dev = NULL; int rc = spdk_bdev_create_bs_dev_ext("Malloc0", zvfs_spdk_bdev_event_cb, NULL, &bs_dev); if (rc != 0) { spdk_app_stop(0); } spdk_bs_init(bs_dev, NULL, zvfs_spdk_bs_init_cb, fs); SPDK_NOTICELOG("zvfs_entry\n"); } void zvfs_spdk_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx) { SPDK_NOTICELOG("zvfs_spdk_bdev_event_cb\n"); } void zvfs_spdk_bs_init_cb(void *arg, struct spdk_blob_store *bs, int bserrno) { zvfs_t *fs = (zvfs_t*)arg; uint64_t io_unit_size = spdk_bs_get_io_unit_size(bs); SPDK_NOTICELOG("io_unit_size : %"PRIu64"\n", io_unit_size); fs->unit_size = io_unit_size; fs->blobstore = bs; fs->channel = spdk_bs_alloc_io_channel(fs->blobstore); if (fs->channel == NULL) { return ; } fs->finished = true; SPDK_NOTICELOG("mount finished\n"); } // open void zvfs_do_create(void *arg) { zvfs_file_t *file = (zvfs_file_t *)arg; spdk_bs_create_blob(file->fs->blobstore, zvfs_spdk_bs_create_blob_cb, file); } void zvfs_spdk_bs_create_blob_cb(void *arg, spdk_blob_id blobid, int bserrno) { zvfs_file_t *file = (zvfs_file_t *)arg; file->blob_id = blobid; SPDK_NOTICELOG("blobid : %"PRIu64"\n", blobid); spdk_bs_open_blob(file->fs->blobstore, blobid, zvfs_spdk_bs_open_blob_create_cb, file); } void zvfs_spdk_bs_open_blob_create_cb(void *arg, struct spdk_blob *blb, int bserrno) { zvfs_file_t *file = (zvfs_file_t *)arg; file->blob = blb; uint64_t free_cluster = spdk_bs_free_cluster_count(file->fs->blobstore); // SPDK_NOTICELOG("free_cluster : %"PRIu64"\n", free_cluster); file->fs->free_cluster_count = free_cluster; spdk_blob_resize(blb, free_cluster, zvfs_spdk_blob_resize_cb, file); } void zvfs_spdk_blob_resize_cb(void *arg, int bserrno) { zvfs_file_t *file = (zvfs_file_t *)arg; uint64_t total = spdk_blob_get_num_clusters(file->blob); file->fs->num_cluster = total; SPDK_NOTICELOG("resize blob :%"PRIu64"\n", total); spdk_blob_sync_md(file->blob, zvfs_spdk_blob_sync_cb, file); } void zvfs_spdk_blob_sync_cb(void *arg, int bserrno) { zvfs_file_t *file = (zvfs_file_t *)arg; file->write_buffer = spdk_malloc(BUFFER_SIZE, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); if (file->write_buffer == NULL) { return ; } file->read_buffer = spdk_malloc(BUFFER_SIZE, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); if (file->read_buffer == NULL) { return ; } SPDK_NOTICELOG("open complete\n"); file->finished = true; } // read void zvfs_do_read(void *arg) { zvfs_file_t *file = (zvfs_file_t *)arg; memset(file->read_buffer, 0x0, BUFFER_SIZE); spdk_blob_io_read(file->blob, file->fs->channel, file->read_buffer, 0, 1, zvfs_spdk_blob_read_cb, file); } void zvfs_spdk_blob_read_cb(void *arg, int bserrno) { zvfs_file_t *file = (zvfs_file_t *)arg; SPDK_NOTICELOG("READ BUFFER : %s\n", file->read_buffer); file->finished = true; } // write void zvfs_do_write(void *arg) { zvfs_file_t *file = (zvfs_file_t *)arg; spdk_blob_io_write(file->blob, file->fs->channel, file->write_buffer, 0, 1, zvfs_spdk_blob_write_cb, file); } void zvfs_spdk_blob_write_cb(void *arg, int bserrno) { zvfs_file_t *file = (zvfs_file_t *)arg; SPDK_NOTICELOG("write complete\n"); file->finished = true; } // close void zvfs_do_close(void *arg) { zvfs_file_t *file = (zvfs_file_t *)arg; spdk_blob_close(file->blob, zvfs_spdk_blob_close_cb, file); } void zvfs_spdk_blob_close_cb(void *arg, int bserrno) { zvfs_file_t *file = (zvfs_file_t *)arg; spdk_bs_delete_blob(file->fs->blobstore, file->blob_id, zvfs_spdk_blob_delete_cb, file); } void zvfs_spdk_blob_delete_cb(void *arg, int bserrno) { zvfs_file_t *file = (zvfs_file_t *)arg; spdk_free(file->write_buffer); spdk_free(file->read_buffer); SPDK_NOTICELOG("close complete\n"); file->finished = true; } // unmount void zvfs_do_umount(void *arg) { zvfs_t *fs = (zvfs_t *)arg; if (fs->blobstore) { if (fs->channel) { spdk_bs_free_io_channel(fs->channel); } spdk_bs_unload(fs->blobstore, zvfs_spdk_bs_unload_cb, fs); } } void zvfs_spdk_bs_unload_cb(void *arg, int bserrno) { zvfs_t *fs = (zvfs_t *)arg; fs->finished = true; } // waiter bool waiter(struct spdk_thread *thread, spdk_msg_fn start_fn, void *ctx, bool *finished) { spdk_thread_send_msg(thread, start_fn, ctx); int waiter_count = 0; do { spdk_thread_poll(thread, 0, 0); waiter_count ++; } while(!(*finished) && waiter_count < WAITER_MAX_TIME); if (!(*finished) && waiter_count >= WAITER_MAX_TIME) { return false; // timeout } return true; } // setup // zvfs.json static const char *json_file = "/home/lian/share/10.1-spdk/zvfs/zvfs.json"; int zvfs_env_setup(void) { struct spdk_env_opts opts; spdk_env_opts_init(&opts); if (0 != spdk_env_init(&opts)) { return -1; } spdk_log_set_print_level(SPDK_LOG_NOTICE); spdk_log_set_level(SPDK_LOG_NOTICE); spdk_log_open(NULL); spdk_thread_lib_init(NULL, 0); global_thread = spdk_thread_create("global", NULL); spdk_set_thread(global_thread); bool done = false; waiter(global_thread, zvfs_json_load_fn, &done, &done); SPDK_NOTICELOG("json_app_load_done complete\n"); return 0; } void zvfs_json_load_fn(void *arg) { spdk_subsystem_init_from_json_config(json_file, SPDK_DEFAULT_RPC_ADDR, json_app_load_done, arg, true); } void json_app_load_done(int rc, void *ctx) { bool *done = ctx; *done = true; SPDK_NOTICELOG("json_app_load_done\n"); } // filesystem // load static int zvfs_mount(struct zvfs_s *fs) { fs->finished = false; return waiter(global_thread, zvfs_do_mount, fs, &fs->finished); } // unload static int zvfs_umount(struct zvfs_s *fs) { fs->finished = false; return waiter(global_thread, zvfs_do_umount, fs, &fs->finished); } // file // open static int zvfs_create(struct zvfs_file_s *file) { file->finished = false; return waiter(global_thread, zvfs_do_create, file, &file->finished); } // read static int zvfs_read(struct zvfs_file_s *file, uint8_t *buffer, size_t count) { file->finished = false; waiter(global_thread, zvfs_do_read, file, &file->finished); int len = strlen(file->read_buffer); memcpy(buffer, file->read_buffer, len); // return len; } // write static int zvfs_write(struct zvfs_file_s *file, const uint8_t *buffer, size_t count) { file->finished = false; memcpy(file->write_buffer, buffer, count); // count / 512 return waiter(global_thread, zvfs_do_write, file, &file->finished); } // close static int zvfs_close(struct zvfs_file_s *file) { file->finished = false; return waiter(global_thread, zvfs_do_close, file, &file->finished); } int main(int argc, char *argv[]) { if (zvfs_env_setup()) { return -1; } SPDK_NOTICELOG("zvfs_env_setup success\n"); SPDK_NOTICELOG("\n\n zvfs mount start \n\n"); zvfs_t *fs = calloc(1, sizeof(zvfs_t)); zvfs_mount(fs); SPDK_NOTICELOG("\n\n zvfs open start \n\n"); zvfs_file_t *file = calloc(1, sizeof(zvfs_file_t)); file->fs = fs; zvfs_create(file); SPDK_NOTICELOG("\n\n zvfs write start \n\n"); char *buffer = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; zvfs_write(file, buffer, strlen(buffer)); SPDK_NOTICELOG("\n\n zvfs read start \n\n"); char rbuffer[BUFFER_SIZE] = {0}; zvfs_read(file, rbuffer, BUFFER_SIZE); SPDK_NOTICELOG("READ BUFFER: %s\n", rbuffer); SPDK_NOTICELOG("\n\n zvfs close start \n\n"); zvfs_close(file); free(file); SPDK_NOTICELOG("\n\n zvfs umount start \n\n"); zvfs_umount(fs); free(fs); }