xref: /spdk/examples/blob/hello_world/hello_blob.c (revision 5db859da082485cbb7a8429d13818da4131da63a)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation.
385af63a5SPaul Luse  *   All rights reserved.
485af63a5SPaul Luse  */
585af63a5SPaul Luse 
685af63a5SPaul Luse #include "spdk/stdinc.h"
785af63a5SPaul Luse 
885af63a5SPaul Luse #include "spdk/bdev.h"
985af63a5SPaul Luse #include "spdk/env.h"
1085af63a5SPaul Luse #include "spdk/event.h"
1185af63a5SPaul Luse #include "spdk/blob_bdev.h"
1285af63a5SPaul Luse #include "spdk/blob.h"
1385af63a5SPaul Luse #include "spdk/log.h"
1497901dcaSShuhei Matsumoto #include "spdk/string.h"
1585af63a5SPaul Luse 
1685af63a5SPaul Luse /*
1785af63a5SPaul Luse  * We'll use this struct to gather housekeeping hello_context to pass between
1885af63a5SPaul Luse  * our events and callbacks.
1985af63a5SPaul Luse  */
2085af63a5SPaul Luse struct hello_context_t {
2185af63a5SPaul Luse 	struct spdk_blob_store *bs;
2285af63a5SPaul Luse 	struct spdk_blob *blob;
2385af63a5SPaul Luse 	spdk_blob_id blobid;
2485af63a5SPaul Luse 	struct spdk_io_channel *channel;
2585af63a5SPaul Luse 	uint8_t *read_buff;
2685af63a5SPaul Luse 	uint8_t *write_buff;
271a2de824SJim Harris 	uint64_t io_unit_size;
2885af63a5SPaul Luse 	int rc;
2985af63a5SPaul Luse };
3085af63a5SPaul Luse 
3185af63a5SPaul Luse /*
3285af63a5SPaul Luse  * Free up memory that we allocated.
3385af63a5SPaul Luse  */
3485af63a5SPaul Luse static void
hello_cleanup(struct hello_context_t * hello_context)3585af63a5SPaul Luse hello_cleanup(struct hello_context_t *hello_context)
3685af63a5SPaul Luse {
3727a23a33SDarek Stojaczyk 	spdk_free(hello_context->read_buff);
3827a23a33SDarek Stojaczyk 	spdk_free(hello_context->write_buff);
3985af63a5SPaul Luse 	free(hello_context);
4085af63a5SPaul Luse }
4185af63a5SPaul Luse 
4285af63a5SPaul Luse /*
4385af63a5SPaul Luse  * Callback routine for the blobstore unload.
4485af63a5SPaul Luse  */
4585af63a5SPaul Luse static void
unload_complete(void * cb_arg,int bserrno)4685af63a5SPaul Luse unload_complete(void *cb_arg, int bserrno)
4785af63a5SPaul Luse {
4885af63a5SPaul Luse 	struct hello_context_t *hello_context = cb_arg;
4985af63a5SPaul Luse 
5085af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
5185af63a5SPaul Luse 	if (bserrno) {
5285af63a5SPaul Luse 		SPDK_ERRLOG("Error %d unloading the bobstore\n", bserrno);
5385af63a5SPaul Luse 		hello_context->rc = bserrno;
5485af63a5SPaul Luse 	}
5585af63a5SPaul Luse 
5685af63a5SPaul Luse 	spdk_app_stop(hello_context->rc);
5785af63a5SPaul Luse }
5885af63a5SPaul Luse 
5985af63a5SPaul Luse /*
6085af63a5SPaul Luse  * Unload the blobstore, cleaning up as needed.
6185af63a5SPaul Luse  */
6285af63a5SPaul Luse static void
unload_bs(struct hello_context_t * hello_context,char * msg,int bserrno)6385af63a5SPaul Luse unload_bs(struct hello_context_t *hello_context, char *msg, int bserrno)
6485af63a5SPaul Luse {
6585af63a5SPaul Luse 	if (bserrno) {
6685af63a5SPaul Luse 		SPDK_ERRLOG("%s (err %d)\n", msg, bserrno);
6785af63a5SPaul Luse 		hello_context->rc = bserrno;
6885af63a5SPaul Luse 	}
6985af63a5SPaul Luse 	if (hello_context->bs) {
7085af63a5SPaul Luse 		if (hello_context->channel) {
7185af63a5SPaul Luse 			spdk_bs_free_io_channel(hello_context->channel);
7285af63a5SPaul Luse 		}
7385af63a5SPaul Luse 		spdk_bs_unload(hello_context->bs, unload_complete, hello_context);
7485af63a5SPaul Luse 	} else {
7585af63a5SPaul Luse 		spdk_app_stop(bserrno);
7685af63a5SPaul Luse 	}
7785af63a5SPaul Luse }
7885af63a5SPaul Luse 
7985af63a5SPaul Luse /*
8085af63a5SPaul Luse  * Callback routine for the deletion of a blob.
8185af63a5SPaul Luse  */
8285af63a5SPaul Luse static void
delete_complete(void * arg1,int bserrno)8385af63a5SPaul Luse delete_complete(void *arg1, int bserrno)
8485af63a5SPaul Luse {
8585af63a5SPaul Luse 	struct hello_context_t *hello_context = arg1;
8685af63a5SPaul Luse 
8785af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
8885af63a5SPaul Luse 	if (bserrno) {
8985af63a5SPaul Luse 		unload_bs(hello_context, "Error in delete completion",
9085af63a5SPaul Luse 			  bserrno);
9185af63a5SPaul Luse 		return;
9285af63a5SPaul Luse 	}
9385af63a5SPaul Luse 
9485af63a5SPaul Luse 	/* We're all done, we can unload the blobstore. */
9585af63a5SPaul Luse 	unload_bs(hello_context, "", 0);
9685af63a5SPaul Luse }
9785af63a5SPaul Luse 
9885af63a5SPaul Luse /*
9985af63a5SPaul Luse  * Function for deleting a blob.
10085af63a5SPaul Luse  */
10185af63a5SPaul Luse static void
delete_blob(void * arg1,int bserrno)10285af63a5SPaul Luse delete_blob(void *arg1, int bserrno)
10385af63a5SPaul Luse {
10485af63a5SPaul Luse 	struct hello_context_t *hello_context = arg1;
10585af63a5SPaul Luse 
10685af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
10785af63a5SPaul Luse 	if (bserrno) {
10885af63a5SPaul Luse 		unload_bs(hello_context, "Error in close completion",
10985af63a5SPaul Luse 			  bserrno);
11085af63a5SPaul Luse 		return;
11185af63a5SPaul Luse 	}
11285af63a5SPaul Luse 
113d52dbda2SJim Harris 	spdk_bs_delete_blob(hello_context->bs, hello_context->blobid,
11485af63a5SPaul Luse 			    delete_complete, hello_context);
11585af63a5SPaul Luse }
11685af63a5SPaul Luse 
11785af63a5SPaul Luse /*
11885af63a5SPaul Luse  * Callback function for reading a blob.
11985af63a5SPaul Luse  */
12085af63a5SPaul Luse static void
read_complete(void * arg1,int bserrno)12185af63a5SPaul Luse read_complete(void *arg1, int bserrno)
12285af63a5SPaul Luse {
12385af63a5SPaul Luse 	struct hello_context_t *hello_context = arg1;
12485af63a5SPaul Luse 	int match_res = -1;
12585af63a5SPaul Luse 
12685af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
12785af63a5SPaul Luse 	if (bserrno) {
12885af63a5SPaul Luse 		unload_bs(hello_context, "Error in read completion",
12985af63a5SPaul Luse 			  bserrno);
13085af63a5SPaul Luse 		return;
13185af63a5SPaul Luse 	}
13285af63a5SPaul Luse 
13385af63a5SPaul Luse 	/* Now let's make sure things match. */
13485af63a5SPaul Luse 	match_res = memcmp(hello_context->write_buff, hello_context->read_buff,
1351a2de824SJim Harris 			   hello_context->io_unit_size);
13685af63a5SPaul Luse 	if (match_res) {
13785af63a5SPaul Luse 		unload_bs(hello_context, "Error in data compare", -1);
13885af63a5SPaul Luse 		return;
13985af63a5SPaul Luse 	} else {
14085af63a5SPaul Luse 		SPDK_NOTICELOG("read SUCCESS and data matches!\n");
14185af63a5SPaul Luse 	}
14285af63a5SPaul Luse 
14385af63a5SPaul Luse 	/* Now let's close it and delete the blob in the callback. */
144e734bb9fSJim Harris 	spdk_blob_close(hello_context->blob, delete_blob, hello_context);
14585af63a5SPaul Luse }
14685af63a5SPaul Luse 
14785af63a5SPaul Luse /*
14885af63a5SPaul Luse  * Function for reading a blob.
14985af63a5SPaul Luse  */
15085af63a5SPaul Luse static void
read_blob(struct hello_context_t * hello_context)15185af63a5SPaul Luse read_blob(struct hello_context_t *hello_context)
15285af63a5SPaul Luse {
15385af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
15485af63a5SPaul Luse 
1551a2de824SJim Harris 	hello_context->read_buff = spdk_malloc(hello_context->io_unit_size,
15627a23a33SDarek Stojaczyk 					       0x1000, NULL, SPDK_ENV_LCORE_ID_ANY,
15727a23a33SDarek Stojaczyk 					       SPDK_MALLOC_DMA);
15885af63a5SPaul Luse 	if (hello_context->read_buff == NULL) {
15985af63a5SPaul Luse 		unload_bs(hello_context, "Error in memory allocation",
16085af63a5SPaul Luse 			  -ENOMEM);
16185af63a5SPaul Luse 		return;
16285af63a5SPaul Luse 	}
16385af63a5SPaul Luse 
16485af63a5SPaul Luse 	/* Issue the read and compare the results in the callback. */
16566fc591fSJim Harris 	spdk_blob_io_read(hello_context->blob, hello_context->channel,
16685af63a5SPaul Luse 			  hello_context->read_buff, 0, 1, read_complete,
16785af63a5SPaul Luse 			  hello_context);
16885af63a5SPaul Luse }
16985af63a5SPaul Luse 
17085af63a5SPaul Luse /*
17185af63a5SPaul Luse  * Callback function for writing a blob.
17285af63a5SPaul Luse  */
17385af63a5SPaul Luse static void
write_complete(void * arg1,int bserrno)17485af63a5SPaul Luse write_complete(void *arg1, int bserrno)
17585af63a5SPaul Luse {
17685af63a5SPaul Luse 	struct hello_context_t *hello_context = arg1;
17785af63a5SPaul Luse 
17885af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
17985af63a5SPaul Luse 	if (bserrno) {
18085af63a5SPaul Luse 		unload_bs(hello_context, "Error in write completion",
18185af63a5SPaul Luse 			  bserrno);
18285af63a5SPaul Luse 		return;
18385af63a5SPaul Luse 	}
18485af63a5SPaul Luse 
18585af63a5SPaul Luse 	/* Now let's read back what we wrote and make sure it matches. */
18685af63a5SPaul Luse 	read_blob(hello_context);
18785af63a5SPaul Luse }
18885af63a5SPaul Luse 
18985af63a5SPaul Luse /*
19085af63a5SPaul Luse  * Function for writing to a blob.
19185af63a5SPaul Luse  */
19285af63a5SPaul Luse static void
blob_write(struct hello_context_t * hello_context)19385af63a5SPaul Luse blob_write(struct hello_context_t *hello_context)
19485af63a5SPaul Luse {
19585af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
19685af63a5SPaul Luse 
19785af63a5SPaul Luse 	/*
19885af63a5SPaul Luse 	 * Buffers for data transfer need to be allocated via SPDK. We will
1991a2de824SJim Harris 	 * transfer 1 io_unit of 4K aligned data at offset 0 in the blob.
20085af63a5SPaul Luse 	 */
2011a2de824SJim Harris 	hello_context->write_buff = spdk_malloc(hello_context->io_unit_size,
20227a23a33SDarek Stojaczyk 						0x1000, NULL, SPDK_ENV_LCORE_ID_ANY,
20327a23a33SDarek Stojaczyk 						SPDK_MALLOC_DMA);
20485af63a5SPaul Luse 	if (hello_context->write_buff == NULL) {
20585af63a5SPaul Luse 		unload_bs(hello_context, "Error in allocating memory",
20685af63a5SPaul Luse 			  -ENOMEM);
20785af63a5SPaul Luse 		return;
20885af63a5SPaul Luse 	}
2091a2de824SJim Harris 	memset(hello_context->write_buff, 0x5a, hello_context->io_unit_size);
21085af63a5SPaul Luse 
21185af63a5SPaul Luse 	/* Now we have to allocate a channel. */
21285af63a5SPaul Luse 	hello_context->channel = spdk_bs_alloc_io_channel(hello_context->bs);
21385af63a5SPaul Luse 	if (hello_context->channel == NULL) {
21485af63a5SPaul Luse 		unload_bs(hello_context, "Error in allocating channel",
21585af63a5SPaul Luse 			  -ENOMEM);
21685af63a5SPaul Luse 		return;
21785af63a5SPaul Luse 	}
21885af63a5SPaul Luse 
2191a2de824SJim Harris 	/* Let's perform the write, 1 io_unit at offset 0. */
22066fc591fSJim Harris 	spdk_blob_io_write(hello_context->blob, hello_context->channel,
22185af63a5SPaul Luse 			   hello_context->write_buff,
22285af63a5SPaul Luse 			   0, 1, write_complete, hello_context);
22385af63a5SPaul Luse }
22485af63a5SPaul Luse 
22585af63a5SPaul Luse /*
226b7876f9aSJosh Soref  * Callback function for syncing metadata.
22785af63a5SPaul Luse  */
22885af63a5SPaul Luse static void
sync_complete(void * arg1,int bserrno)22985af63a5SPaul Luse sync_complete(void *arg1, int bserrno)
23085af63a5SPaul Luse {
23185af63a5SPaul Luse 	struct hello_context_t *hello_context = arg1;
23285af63a5SPaul Luse 
23385af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
23485af63a5SPaul Luse 	if (bserrno) {
23585af63a5SPaul Luse 		unload_bs(hello_context, "Error in sync callback",
23685af63a5SPaul Luse 			  bserrno);
23785af63a5SPaul Luse 		return;
23885af63a5SPaul Luse 	}
23985af63a5SPaul Luse 
24085af63a5SPaul Luse 	/* Blob has been created & sized & MD sync'd, let's write to it. */
24185af63a5SPaul Luse 	blob_write(hello_context);
24285af63a5SPaul Luse }
24385af63a5SPaul Luse 
244463925ffSJim Harris static void
resize_complete(void * cb_arg,int bserrno)245463925ffSJim Harris resize_complete(void *cb_arg, int bserrno)
246463925ffSJim Harris {
247463925ffSJim Harris 	struct hello_context_t *hello_context = cb_arg;
248463925ffSJim Harris 	uint64_t total = 0;
249463925ffSJim Harris 
250463925ffSJim Harris 	if (bserrno) {
251463925ffSJim Harris 		unload_bs(hello_context, "Error in blob resize", bserrno);
252463925ffSJim Harris 		return;
253463925ffSJim Harris 	}
254463925ffSJim Harris 
255463925ffSJim Harris 	total = spdk_blob_get_num_clusters(hello_context->blob);
256463925ffSJim Harris 	SPDK_NOTICELOG("resized blob now has USED clusters of %" PRIu64 "\n",
257463925ffSJim Harris 		       total);
258463925ffSJim Harris 
259463925ffSJim Harris 	/*
260463925ffSJim Harris 	 * Metadata is stored in volatile memory for performance
261463925ffSJim Harris 	 * reasons and therefore needs to be synchronized with
262463925ffSJim Harris 	 * non-volatile storage to make it persistent. This can be
263463925ffSJim Harris 	 * done manually, as shown here, or if not it will be done
264463925ffSJim Harris 	 * automatically when the blob is closed. It is always a
265463925ffSJim Harris 	 * good idea to sync after making metadata changes unless
266463925ffSJim Harris 	 * it has an unacceptable impact on application performance.
267463925ffSJim Harris 	 */
268463925ffSJim Harris 	spdk_blob_sync_md(hello_context->blob, sync_complete, hello_context);
269463925ffSJim Harris }
270463925ffSJim Harris 
27185af63a5SPaul Luse /*
27285af63a5SPaul Luse  * Callback function for opening a blob.
27385af63a5SPaul Luse  */
27485af63a5SPaul Luse static void
open_complete(void * cb_arg,struct spdk_blob * blob,int bserrno)27585af63a5SPaul Luse open_complete(void *cb_arg, struct spdk_blob *blob, int bserrno)
27685af63a5SPaul Luse {
27785af63a5SPaul Luse 	struct hello_context_t *hello_context = cb_arg;
27885af63a5SPaul Luse 	uint64_t free = 0;
27985af63a5SPaul Luse 
28085af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
28185af63a5SPaul Luse 	if (bserrno) {
28285af63a5SPaul Luse 		unload_bs(hello_context, "Error in open completion",
28385af63a5SPaul Luse 			  bserrno);
28485af63a5SPaul Luse 		return;
28585af63a5SPaul Luse 	}
28685af63a5SPaul Luse 
28785af63a5SPaul Luse 
28885af63a5SPaul Luse 	hello_context->blob = blob;
28985af63a5SPaul Luse 	free = spdk_bs_free_cluster_count(hello_context->bs);
29085af63a5SPaul Luse 	SPDK_NOTICELOG("blobstore has FREE clusters of %" PRIu64 "\n",
29185af63a5SPaul Luse 		       free);
29285af63a5SPaul Luse 
29385af63a5SPaul Luse 	/*
29485af63a5SPaul Luse 	 * Before we can use our new blob, we have to resize it
29585af63a5SPaul Luse 	 * as the initial size is 0. For this example we'll use the
29685af63a5SPaul Luse 	 * full size of the blobstore but it would be expected that
29785af63a5SPaul Luse 	 * there'd usually be many blobs of various sizes. The resize
29885af63a5SPaul Luse 	 * unit is a cluster.
29985af63a5SPaul Luse 	 */
300463925ffSJim Harris 	spdk_blob_resize(hello_context->blob, free, resize_complete, hello_context);
30185af63a5SPaul Luse }
30285af63a5SPaul Luse 
30385af63a5SPaul Luse /*
30485af63a5SPaul Luse  * Callback function for creating a blob.
30585af63a5SPaul Luse  */
30685af63a5SPaul Luse static void
blob_create_complete(void * arg1,spdk_blob_id blobid,int bserrno)30785af63a5SPaul Luse blob_create_complete(void *arg1, spdk_blob_id blobid, int bserrno)
30885af63a5SPaul Luse {
30985af63a5SPaul Luse 	struct hello_context_t *hello_context = arg1;
31085af63a5SPaul Luse 
31185af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
31285af63a5SPaul Luse 	if (bserrno) {
31385af63a5SPaul Luse 		unload_bs(hello_context, "Error in blob create callback",
31485af63a5SPaul Luse 			  bserrno);
31585af63a5SPaul Luse 		return;
31685af63a5SPaul Luse 	}
31785af63a5SPaul Luse 
31885af63a5SPaul Luse 	hello_context->blobid = blobid;
31985af63a5SPaul Luse 	SPDK_NOTICELOG("new blob id %" PRIu64 "\n", hello_context->blobid);
32085af63a5SPaul Luse 
32185af63a5SPaul Luse 	/* We have to open the blob before we can do things like resize. */
322d52dbda2SJim Harris 	spdk_bs_open_blob(hello_context->bs, hello_context->blobid,
32385af63a5SPaul Luse 			  open_complete, hello_context);
32485af63a5SPaul Luse }
32585af63a5SPaul Luse 
32685af63a5SPaul Luse /*
32785af63a5SPaul Luse  * Function for creating a blob.
32885af63a5SPaul Luse  */
32985af63a5SPaul Luse static void
create_blob(struct hello_context_t * hello_context)33085af63a5SPaul Luse create_blob(struct hello_context_t *hello_context)
33185af63a5SPaul Luse {
33285af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
333d52dbda2SJim Harris 	spdk_bs_create_blob(hello_context->bs, blob_create_complete, hello_context);
33485af63a5SPaul Luse }
33585af63a5SPaul Luse 
33685af63a5SPaul Luse /*
33785af63a5SPaul Luse  * Callback function for initializing the blobstore.
33885af63a5SPaul Luse  */
33985af63a5SPaul Luse static void
bs_init_complete(void * cb_arg,struct spdk_blob_store * bs,int bserrno)34085af63a5SPaul Luse bs_init_complete(void *cb_arg, struct spdk_blob_store *bs,
34185af63a5SPaul Luse 		 int bserrno)
34285af63a5SPaul Luse {
34385af63a5SPaul Luse 	struct hello_context_t *hello_context = cb_arg;
34485af63a5SPaul Luse 
34585af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
34685af63a5SPaul Luse 	if (bserrno) {
347b7876f9aSJosh Soref 		unload_bs(hello_context, "Error initing the blobstore",
34885af63a5SPaul Luse 			  bserrno);
34985af63a5SPaul Luse 		return;
35085af63a5SPaul Luse 	}
35185af63a5SPaul Luse 
35285af63a5SPaul Luse 	hello_context->bs = bs;
35385af63a5SPaul Luse 	SPDK_NOTICELOG("blobstore: %p\n", hello_context->bs);
35485af63a5SPaul Luse 	/*
3551a2de824SJim Harris 	 * We will use the io_unit size in allocating buffers, etc., later
35685af63a5SPaul Luse 	 * so we'll just save it in out context buffer here.
35785af63a5SPaul Luse 	 */
3581a2de824SJim Harris 	hello_context->io_unit_size = spdk_bs_get_io_unit_size(hello_context->bs);
35985af63a5SPaul Luse 
36085af63a5SPaul Luse 	/*
36104f7bfe0Spaul luse 	 * The blobstore has been initialized, let's create a blob.
362bfc5b558SBen Walker 	 * Note that we could pass a message back to ourselves using
363bfc5b558SBen Walker 	 * spdk_thread_send_msg() if we wanted to keep our processing
364bfc5b558SBen Walker 	 * time limited.
36585af63a5SPaul Luse 	 */
36685af63a5SPaul Luse 	create_blob(hello_context);
36785af63a5SPaul Luse }
36885af63a5SPaul Luse 
36997901dcaSShuhei Matsumoto static void
base_bdev_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)37097901dcaSShuhei Matsumoto base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
37197901dcaSShuhei Matsumoto 		   void *event_ctx)
37297901dcaSShuhei Matsumoto {
37397901dcaSShuhei Matsumoto 	SPDK_WARNLOG("Unsupported bdev event: type %d\n", type);
37497901dcaSShuhei Matsumoto }
37597901dcaSShuhei Matsumoto 
37685af63a5SPaul Luse /*
37785af63a5SPaul Luse  * Our initial event that kicks off everything from main().
37885af63a5SPaul Luse  */
37985af63a5SPaul Luse static void
hello_start(void * arg1)380deb8ee5cSBen Walker hello_start(void *arg1)
38185af63a5SPaul Luse {
38285af63a5SPaul Luse 	struct hello_context_t *hello_context = arg1;
38385af63a5SPaul Luse 	struct spdk_bs_dev *bs_dev = NULL;
38497901dcaSShuhei Matsumoto 	int rc;
38585af63a5SPaul Luse 
38685af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
38785af63a5SPaul Luse 
38885af63a5SPaul Luse 	/*
38997901dcaSShuhei Matsumoto 	 * In this example, use our malloc (RAM) disk configured via
390585543acSwanghailiangx 	 * hello_blob.json that was passed in when we started the
39197901dcaSShuhei Matsumoto 	 * SPDK app framework.
39297901dcaSShuhei Matsumoto 	 *
39385af63a5SPaul Luse 	 * spdk_bs_init() requires us to fill out the structure
39485af63a5SPaul Luse 	 * spdk_bs_dev with a set of callbacks. These callbacks
39585af63a5SPaul Luse 	 * implement read, write, and other operations on the
39685af63a5SPaul Luse 	 * underlying disks. As a convenience, a utility function
39785af63a5SPaul Luse 	 * is provided that creates an spdk_bs_dev that implements
39885af63a5SPaul Luse 	 * all of the callbacks by forwarding the I/O to the
39985af63a5SPaul Luse 	 * SPDK bdev layer. Other helper functions are also
40085af63a5SPaul Luse 	 * available in the blob lib in blob_bdev.c that simply
40185af63a5SPaul Luse 	 * make it easier to layer blobstore on top of a bdev.
40285af63a5SPaul Luse 	 * However blobstore can be more tightly integrated into
40385af63a5SPaul Luse 	 * any lower layer, such as NVMe for example.
40485af63a5SPaul Luse 	 */
40597901dcaSShuhei Matsumoto 	rc = spdk_bdev_create_bs_dev_ext("Malloc0", base_bdev_event_cb, NULL, &bs_dev);
40697901dcaSShuhei Matsumoto 	if (rc != 0) {
40797901dcaSShuhei Matsumoto 		SPDK_ERRLOG("Could not create blob bdev, %s!!\n",
40897901dcaSShuhei Matsumoto 			    spdk_strerror(-rc));
40985af63a5SPaul Luse 		spdk_app_stop(-1);
41085af63a5SPaul Luse 		return;
41185af63a5SPaul Luse 	}
41285af63a5SPaul Luse 
41385af63a5SPaul Luse 	spdk_bs_init(bs_dev, NULL, bs_init_complete, hello_context);
41485af63a5SPaul Luse }
41585af63a5SPaul Luse 
41685af63a5SPaul Luse int
main(int argc,char ** argv)41785af63a5SPaul Luse main(int argc, char **argv)
41885af63a5SPaul Luse {
41985af63a5SPaul Luse 	struct spdk_app_opts opts = {};
42085af63a5SPaul Luse 	int rc = 0;
42185af63a5SPaul Luse 	struct hello_context_t *hello_context = NULL;
42285af63a5SPaul Luse 
42385af63a5SPaul Luse 	SPDK_NOTICELOG("entry\n");
42485af63a5SPaul Luse 
42585af63a5SPaul Luse 	/* Set default values in opts structure. */
42648701bd9SZiye Yang 	spdk_app_opts_init(&opts, sizeof(opts));
42785af63a5SPaul Luse 
42885af63a5SPaul Luse 	/*
42985af63a5SPaul Luse 	 * Setup a few specifics before we init, for most SPDK cmd line
43085af63a5SPaul Luse 	 * apps, the config file will be passed in as an arg but to make
43185af63a5SPaul Luse 	 * this example super simple we just hardcode it. We also need to
43285af63a5SPaul Luse 	 * specify a name for the app.
43385af63a5SPaul Luse 	 */
43485af63a5SPaul Luse 	opts.name = "hello_blob";
435a1c00096SWANGHAILIANG 	opts.json_config_file = argv[1];
436*5db859daSKrzysztof Karas 	opts.rpc_addr = NULL;
43785af63a5SPaul Luse 
43885af63a5SPaul Luse 	/*
43904f7bfe0Spaul luse 	 * Now we'll allocate and initialize the blobstore itself. We
44085af63a5SPaul Luse 	 * can pass in an spdk_bs_opts if we want something other than
44185af63a5SPaul Luse 	 * the defaults (cluster size, etc), but here we'll just take the
44285af63a5SPaul Luse 	 * defaults.  We'll also pass in a struct that we'll use for
443b7876f9aSJosh Soref 	 * callbacks so we've got efficient bookkeeping of what we're
44485af63a5SPaul Luse 	 * creating. This is an async operation and bs_init_complete()
44585af63a5SPaul Luse 	 * will be called when it is complete.
44685af63a5SPaul Luse 	 */
44785af63a5SPaul Luse 	hello_context = calloc(1, sizeof(struct hello_context_t));
44885af63a5SPaul Luse 	if (hello_context != NULL) {
44985af63a5SPaul Luse 		/*
45085af63a5SPaul Luse 		 * spdk_app_start() will block running hello_start() until
45185af63a5SPaul Luse 		 * spdk_app_stop() is called by someone (not simply when
452b9be940aSLance Hartmann 		 * hello_start() returns), or if an error occurs during
453b9be940aSLance Hartmann 		 * spdk_app_start() before hello_start() runs.
45485af63a5SPaul Luse 		 */
45536287957SBen Walker 		rc = spdk_app_start(&opts, hello_start, hello_context);
45685af63a5SPaul Luse 		if (rc) {
45785af63a5SPaul Luse 			SPDK_NOTICELOG("ERROR!\n");
45885af63a5SPaul Luse 		} else {
45904f7bfe0Spaul luse 			SPDK_NOTICELOG("SUCCESS!\n");
46085af63a5SPaul Luse 		}
46185af63a5SPaul Luse 		/* Free up memory that we allocated */
46285af63a5SPaul Luse 		hello_cleanup(hello_context);
46385af63a5SPaul Luse 	} else {
46485af63a5SPaul Luse 		SPDK_ERRLOG("Could not alloc hello_context struct!!\n");
46585af63a5SPaul Luse 		rc = -ENOMEM;
46685af63a5SPaul Luse 	}
46785af63a5SPaul Luse 
46885af63a5SPaul Luse 	/* Gracefully close out all of the SPDK subsystems. */
46985af63a5SPaul Luse 	spdk_app_fini();
47085af63a5SPaul Luse 	return rc;
47185af63a5SPaul Luse }
472