examples: blobstore hello world
Example hello world for blobstore that: - uses the spdk app framework - uses a malloc backend bdev - shows the basic blobstore operations Change-Id: I1662139e6b1fa33c6109006407a11c8c0936ac0c Signed-off-by: Paul Luse <paul.e.luse@intel.com> Reviewed-on: https://review.gerrithub.io/370785 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
442ee2303e
commit
85af63a5f5
@ -34,7 +34,7 @@
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y += bdev ioat nvme
|
||||
DIRS-y += bdev blob ioat nvme
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
|
44
examples/blob/Makefile
Normal file
44
examples/blob/Makefile
Normal file
@ -0,0 +1,44 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
DIRS-y += hello_world
|
||||
|
||||
.PHONY: all clean $(DIRS-y)
|
||||
|
||||
all: $(DIRS-y)
|
||||
clean: $(DIRS-y)
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk
|
1
examples/blob/hello_world/.gitignore
vendored
Normal file
1
examples/blob/hello_world/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
hello_blob
|
56
examples/blob/hello_world/Makefile
Normal file
56
examples/blob/hello_world/Makefile
Normal file
@ -0,0 +1,56 @@
|
||||
#
|
||||
# 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 util conf trace \
|
||||
log jsonrpc json rpc
|
||||
|
||||
LIBS += $(COPY_MODULES_LINKER_ARGS) $(BLOCKDEV_MODULES_LINKER_ARGS)
|
||||
LIBS += $(SPDK_LIB_LINKER_ARGS) $(ENV_LINKER_ARGS)
|
||||
|
||||
all : $(APP)
|
||||
|
||||
$(APP) : $(OBJS) $(SPDK_LIB_FILES)
|
||||
$(LINK_C)
|
||||
|
||||
clean :
|
||||
$(CLEAN_C) $(APP)
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk
|
500
examples/blob/hello_world/hello_blob.c
Normal file
500
examples/blob/hello_world/hello_blob.c
Normal file
@ -0,0 +1,500 @@
|
||||
/*-
|
||||
* 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)
|
||||
{
|
||||
if (hello_context->read_buff) {
|
||||
spdk_dma_free(hello_context->read_buff);
|
||||
}
|
||||
if (hello_context->write_buff) {
|
||||
spdk_dma_free(hello_context->write_buff);
|
||||
}
|
||||
if (hello_context) {
|
||||
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_md_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_bs_md_close_blob(&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_bs_io_read_blob(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_bs_io_write_blob(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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
uint64_t total = 0;
|
||||
int rc = 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.
|
||||
*/
|
||||
rc = spdk_bs_md_resize_blob(hello_context->blob, free);
|
||||
if (rc) {
|
||||
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_bs_md_sync_blob(hello_context->blob, sync_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_md_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_md_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 allcoate an SPDK event and use
|
||||
* spdk_event_call() to schedule it if we wanted to keep
|
||||
* our events as limited as possible wrt the amount of
|
||||
* work that they do.
|
||||
*/
|
||||
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);
|
||||
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)
|
||||
*/
|
||||
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;
|
||||
}
|
3
examples/blob/hello_world/hello_blob.conf
Normal file
3
examples/blob/hello_world/hello_blob.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[Malloc]
|
||||
NumberOfLuns 1
|
||||
LunSizeInMB 16
|
Loading…
Reference in New Issue
Block a user