summaryrefslogtreecommitdiffstats
path: root/src/spdk/examples/blob/hello_world
diff options
context:
space:
mode:
Diffstat (limited to 'src/spdk/examples/blob/hello_world')
-rw-r--r--src/spdk/examples/blob/hello_world/.gitignore1
-rw-r--r--src/spdk/examples/blob/hello_world/Makefile57
-rw-r--r--src/spdk/examples/blob/hello_world/hello_blob.c496
-rw-r--r--src/spdk/examples/blob/hello_world/hello_blob.conf3
4 files changed, 557 insertions, 0 deletions
diff --git a/src/spdk/examples/blob/hello_world/.gitignore b/src/spdk/examples/blob/hello_world/.gitignore
new file mode 100644
index 00000000..683a2255
--- /dev/null
+++ b/src/spdk/examples/blob/hello_world/.gitignore
@@ -0,0 +1 @@
+hello_blob
diff --git a/src/spdk/examples/blob/hello_world/Makefile b/src/spdk/examples/blob/hello_world/Makefile
new file mode 100644
index 00000000..7c567fcb
--- /dev/null
+++ b/src/spdk/examples/blob/hello_world/Makefile
@@ -0,0 +1,57 @@
+#
+# 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.
+#
+
+SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..)
+include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
+include $(SPDK_ROOT_DIR)/mk/spdk.app.mk
+include $(SPDK_ROOT_DIR)/mk/spdk.modules.mk
+
+APP = hello_blob
+
+C_SRCS := hello_blob.c
+
+SPDK_LIB_LIST = event_bdev event_copy
+SPDK_LIB_LIST += blobfs blob bdev blob_bdev copy event thread util conf trace \
+ log jsonrpc json rpc
+
+LIBS += $(COPY_MODULES_LINKER_ARGS) $(BLOCKDEV_MODULES_LINKER_ARGS) $(SOCK_MODULES_LINKER_ARGS)
+LIBS += $(SPDK_LIB_LINKER_ARGS) $(ENV_LINKER_ARGS)
+
+all : $(APP)
+ @:
+
+$(APP) : $(OBJS) $(SPDK_LIB_FILES) $(COPY_MODULES_FILES) $(BLOCKDEV_MODULES_FILES) $(SOCK_MODULES_FILES) $(LINKER_MODULES) $(ENV_LIBS)
+ $(LINK_C)
+
+clean :
+ $(CLEAN_C) $(APP)
+
+include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk
diff --git a/src/spdk/examples/blob/hello_world/hello_blob.c b/src/spdk/examples/blob/hello_world/hello_blob.c
new file mode 100644
index 00000000..ffcc2976
--- /dev/null
+++ b/src/spdk/examples/blob/hello_world/hello_blob.c
@@ -0,0 +1,496 @@
+/*-
+ * 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/bdev.h"
+#include "spdk/env.h"
+#include "spdk/event.h"
+#include "spdk/blob_bdev.h"
+#include "spdk/blob.h"
+#include "spdk/log.h"
+
+/*
+ * We'll use this struct to gather housekeeping hello_context to pass between
+ * our events and callbacks.
+ */
+struct hello_context_t {
+ struct spdk_blob_store *bs;
+ struct spdk_blob *blob;
+ spdk_blob_id blobid;
+ struct spdk_io_channel *channel;
+ uint8_t *read_buff;
+ uint8_t *write_buff;
+ uint64_t page_size;
+ int rc;
+};
+
+/*
+ * Free up memory that we allocated.
+ */
+static void
+hello_cleanup(struct hello_context_t *hello_context)
+{
+ spdk_dma_free(hello_context->read_buff);
+ spdk_dma_free(hello_context->write_buff);
+ free(hello_context);
+}
+
+/*
+ * Callback routine for the blobstore unload.
+ */
+static void
+unload_complete(void *cb_arg, int bserrno)
+{
+ struct hello_context_t *hello_context = cb_arg;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ SPDK_ERRLOG("Error %d unloading the bobstore\n", bserrno);
+ hello_context->rc = bserrno;
+ }
+
+ spdk_app_stop(hello_context->rc);
+}
+
+/*
+ * Unload the blobstore, cleaning up as needed.
+ */
+static void
+unload_bs(struct hello_context_t *hello_context, char *msg, int bserrno)
+{
+ if (bserrno) {
+ SPDK_ERRLOG("%s (err %d)\n", msg, bserrno);
+ hello_context->rc = bserrno;
+ }
+ if (hello_context->bs) {
+ if (hello_context->channel) {
+ spdk_bs_free_io_channel(hello_context->channel);
+ }
+ spdk_bs_unload(hello_context->bs, unload_complete, hello_context);
+ } else {
+ spdk_app_stop(bserrno);
+ }
+}
+
+/*
+ * Callback routine for the deletion of a blob.
+ */
+static void
+delete_complete(void *arg1, int bserrno)
+{
+ struct hello_context_t *hello_context = arg1;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ unload_bs(hello_context, "Error in delete completion",
+ bserrno);
+ return;
+ }
+
+ /* We're all done, we can unload the blobstore. */
+ unload_bs(hello_context, "", 0);
+}
+
+/*
+ * Function for deleting a blob.
+ */
+static void
+delete_blob(void *arg1, int bserrno)
+{
+ struct hello_context_t *hello_context = arg1;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ unload_bs(hello_context, "Error in close completion",
+ bserrno);
+ return;
+ }
+
+ spdk_bs_delete_blob(hello_context->bs, hello_context->blobid,
+ delete_complete, hello_context);
+}
+
+/*
+ * Callback function for reading a blob.
+ */
+static void
+read_complete(void *arg1, int bserrno)
+{
+ struct hello_context_t *hello_context = arg1;
+ int match_res = -1;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ unload_bs(hello_context, "Error in read completion",
+ bserrno);
+ return;
+ }
+
+ /* Now let's make sure things match. */
+ match_res = memcmp(hello_context->write_buff, hello_context->read_buff,
+ hello_context->page_size);
+ if (match_res) {
+ unload_bs(hello_context, "Error in data compare", -1);
+ return;
+ } else {
+ SPDK_NOTICELOG("read SUCCESS and data matches!\n");
+ }
+
+ /* Now let's close it and delete the blob in the callback. */
+ spdk_blob_close(hello_context->blob, delete_blob, hello_context);
+}
+
+/*
+ * Function for reading a blob.
+ */
+static void
+read_blob(struct hello_context_t *hello_context)
+{
+ SPDK_NOTICELOG("entry\n");
+
+ hello_context->read_buff = spdk_dma_malloc(hello_context->page_size,
+ 0x1000, NULL);
+ if (hello_context->read_buff == NULL) {
+ unload_bs(hello_context, "Error in memory allocation",
+ -ENOMEM);
+ return;
+ }
+
+ /* Issue the read and compare the results in the callback. */
+ spdk_blob_io_read(hello_context->blob, hello_context->channel,
+ hello_context->read_buff, 0, 1, read_complete,
+ hello_context);
+}
+
+/*
+ * Callback function for writing a blob.
+ */
+static void
+write_complete(void *arg1, int bserrno)
+{
+ struct hello_context_t *hello_context = arg1;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ unload_bs(hello_context, "Error in write completion",
+ bserrno);
+ return;
+ }
+
+ /* Now let's read back what we wrote and make sure it matches. */
+ read_blob(hello_context);
+}
+
+/*
+ * Function for writing to a blob.
+ */
+static void
+blob_write(struct hello_context_t *hello_context)
+{
+ SPDK_NOTICELOG("entry\n");
+
+ /*
+ * Buffers for data transfer need to be allocated via SPDK. We will
+ * tranfer 1 page of 4K aligned data at offset 0 in the blob.
+ */
+ hello_context->write_buff = spdk_dma_malloc(hello_context->page_size,
+ 0x1000, NULL);
+ if (hello_context->write_buff == NULL) {
+ unload_bs(hello_context, "Error in allocating memory",
+ -ENOMEM);
+ return;
+ }
+ memset(hello_context->write_buff, 0x5a, hello_context->page_size);
+
+ /* Now we have to allocate a channel. */
+ hello_context->channel = spdk_bs_alloc_io_channel(hello_context->bs);
+ if (hello_context->channel == NULL) {
+ unload_bs(hello_context, "Error in allocating channel",
+ -ENOMEM);
+ return;
+ }
+
+ /* Let's perform the write, 1 page at offset 0. */
+ spdk_blob_io_write(hello_context->blob, hello_context->channel,
+ hello_context->write_buff,
+ 0, 1, write_complete, hello_context);
+}
+
+/*
+ * Callback function for sync'ing metadata.
+ */
+static void
+sync_complete(void *arg1, int bserrno)
+{
+ struct hello_context_t *hello_context = arg1;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ unload_bs(hello_context, "Error in sync callback",
+ bserrno);
+ return;
+ }
+
+ /* Blob has been created & sized & MD sync'd, let's write to it. */
+ blob_write(hello_context);
+}
+
+static void
+resize_complete(void *cb_arg, int bserrno)
+{
+ struct hello_context_t *hello_context = cb_arg;
+ uint64_t total = 0;
+
+ if (bserrno) {
+ unload_bs(hello_context, "Error in blob resize", bserrno);
+ return;
+ }
+
+ total = spdk_blob_get_num_clusters(hello_context->blob);
+ SPDK_NOTICELOG("resized blob now has USED clusters of %" PRIu64 "\n",
+ total);
+
+ /*
+ * Metadata is stored in volatile memory for performance
+ * reasons and therefore needs to be synchronized with
+ * non-volatile storage to make it persistent. This can be
+ * done manually, as shown here, or if not it will be done
+ * automatically when the blob is closed. It is always a
+ * good idea to sync after making metadata changes unless
+ * it has an unacceptable impact on application performance.
+ */
+ spdk_blob_sync_md(hello_context->blob, sync_complete, hello_context);
+}
+
+/*
+ * Callback function for opening a blob.
+ */
+static void
+open_complete(void *cb_arg, struct spdk_blob *blob, int bserrno)
+{
+ struct hello_context_t *hello_context = cb_arg;
+ uint64_t free = 0;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ unload_bs(hello_context, "Error in open completion",
+ bserrno);
+ return;
+ }
+
+
+ hello_context->blob = blob;
+ free = spdk_bs_free_cluster_count(hello_context->bs);
+ SPDK_NOTICELOG("blobstore has FREE clusters of %" PRIu64 "\n",
+ free);
+
+ /*
+ * Before we can use our new blob, we have to resize it
+ * as the initial size is 0. For this example we'll use the
+ * full size of the blobstore but it would be expected that
+ * there'd usually be many blobs of various sizes. The resize
+ * unit is a cluster.
+ */
+ spdk_blob_resize(hello_context->blob, free, resize_complete, hello_context);
+}
+
+/*
+ * Callback function for creating a blob.
+ */
+static void
+blob_create_complete(void *arg1, spdk_blob_id blobid, int bserrno)
+{
+ struct hello_context_t *hello_context = arg1;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ unload_bs(hello_context, "Error in blob create callback",
+ bserrno);
+ return;
+ }
+
+ hello_context->blobid = blobid;
+ SPDK_NOTICELOG("new blob id %" PRIu64 "\n", hello_context->blobid);
+
+ /* We have to open the blob before we can do things like resize. */
+ spdk_bs_open_blob(hello_context->bs, hello_context->blobid,
+ open_complete, hello_context);
+}
+
+/*
+ * Function for creating a blob.
+ */
+static void
+create_blob(struct hello_context_t *hello_context)
+{
+ SPDK_NOTICELOG("entry\n");
+ spdk_bs_create_blob(hello_context->bs, blob_create_complete, hello_context);
+}
+
+/*
+ * Callback function for initializing the blobstore.
+ */
+static void
+bs_init_complete(void *cb_arg, struct spdk_blob_store *bs,
+ int bserrno)
+{
+ struct hello_context_t *hello_context = cb_arg;
+
+ SPDK_NOTICELOG("entry\n");
+ if (bserrno) {
+ unload_bs(hello_context, "Error init'ing the blobstore",
+ bserrno);
+ return;
+ }
+
+ hello_context->bs = bs;
+ SPDK_NOTICELOG("blobstore: %p\n", hello_context->bs);
+ /*
+ * We will use the page size in allocating buffers, etc., later
+ * so we'll just save it in out context buffer here.
+ */
+ hello_context->page_size = spdk_bs_get_page_size(hello_context->bs);
+
+ /*
+ * The blostore has been initialized, let's create a blob.
+ * Note that we could pass a message back to ourselves using
+ * spdk_thread_send_msg() if we wanted to keep our processing
+ * time limited.
+ */
+ create_blob(hello_context);
+}
+
+/*
+ * Our initial event that kicks off everything from main().
+ */
+static void
+hello_start(void *arg1, void *arg2)
+{
+ struct hello_context_t *hello_context = arg1;
+ struct spdk_bdev *bdev = NULL;
+ struct spdk_bs_dev *bs_dev = NULL;
+
+ SPDK_NOTICELOG("entry\n");
+ /*
+ * Get the bdev. For this example it is our malloc (RAM)
+ * disk configured via hello_blob.conf that was passed
+ * in when we started the SPDK app framework so we can
+ * get it via its name.
+ */
+ bdev = spdk_bdev_get_by_name("Malloc0");
+ if (bdev == NULL) {
+ SPDK_ERRLOG("Could not find a bdev\n");
+ spdk_app_stop(-1);
+ return;
+ }
+
+ /*
+ * spdk_bs_init() requires us to fill out the structure
+ * spdk_bs_dev with a set of callbacks. These callbacks
+ * implement read, write, and other operations on the
+ * underlying disks. As a convenience, a utility function
+ * is provided that creates an spdk_bs_dev that implements
+ * all of the callbacks by forwarding the I/O to the
+ * SPDK bdev layer. Other helper functions are also
+ * available in the blob lib in blob_bdev.c that simply
+ * make it easier to layer blobstore on top of a bdev.
+ * However blobstore can be more tightly integrated into
+ * any lower layer, such as NVMe for example.
+ */
+ bs_dev = spdk_bdev_create_bs_dev(bdev, NULL, NULL);
+ if (bs_dev == NULL) {
+ SPDK_ERRLOG("Could not create blob bdev!!\n");
+ spdk_app_stop(-1);
+ return;
+ }
+
+ spdk_bs_init(bs_dev, NULL, bs_init_complete, hello_context);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct spdk_app_opts opts = {};
+ int rc = 0;
+ struct hello_context_t *hello_context = NULL;
+
+ SPDK_NOTICELOG("entry\n");
+
+ /* Set default values in opts structure. */
+ spdk_app_opts_init(&opts);
+
+ /*
+ * Setup a few specifics before we init, for most SPDK cmd line
+ * apps, the config file will be passed in as an arg but to make
+ * this example super simple we just hardcode it. We also need to
+ * specify a name for the app.
+ */
+ opts.name = "hello_blob";
+ opts.config_file = "hello_blob.conf";
+
+
+ /*
+ * Now we'll allocate and intialize the blobstore itself. We
+ * can pass in an spdk_bs_opts if we want something other than
+ * the defaults (cluster size, etc), but here we'll just take the
+ * defaults. We'll also pass in a struct that we'll use for
+ * callbacks so we've got efficient bookeeping of what we're
+ * creating. This is an async operation and bs_init_complete()
+ * will be called when it is complete.
+ */
+ hello_context = calloc(1, sizeof(struct hello_context_t));
+ if (hello_context != NULL) {
+ /*
+ * spdk_app_start() will block running hello_start() until
+ * spdk_app_stop() is called by someone (not simply when
+ * hello_start() returns), or if an error occurs during
+ * spdk_app_start() before hello_start() runs.
+ */
+ rc = spdk_app_start(&opts, hello_start, hello_context, NULL);
+ if (rc) {
+ SPDK_NOTICELOG("ERROR!\n");
+ } else {
+ SPDK_NOTICELOG("SUCCCESS!\n");
+ }
+ /* Free up memory that we allocated */
+ hello_cleanup(hello_context);
+ } else {
+ SPDK_ERRLOG("Could not alloc hello_context struct!!\n");
+ rc = -ENOMEM;
+ }
+
+ /* Gracefully close out all of the SPDK subsystems. */
+ spdk_app_fini();
+ return rc;
+}
diff --git a/src/spdk/examples/blob/hello_world/hello_blob.conf b/src/spdk/examples/blob/hello_world/hello_blob.conf
new file mode 100644
index 00000000..3fa7e9d9
--- /dev/null
+++ b/src/spdk/examples/blob/hello_world/hello_blob.conf
@@ -0,0 +1,3 @@
+[Malloc]
+ NumberOfLuns 1
+ LunSizeInMB 16