xref: /spdk/examples/blob/hello_world/hello_blob.c (revision 4d43844f4d50a7abd5b6029ff3f2baff329890a8)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk/bdev.h"
37 #include "spdk/env.h"
38 #include "spdk/event.h"
39 #include "spdk/blob_bdev.h"
40 #include "spdk/blob.h"
41 #include "spdk/log.h"
42 
43 /*
44  * We'll use this struct to gather housekeeping hello_context to pass between
45  * our events and callbacks.
46  */
47 struct hello_context_t {
48 	struct spdk_blob_store *bs;
49 	struct spdk_blob *blob;
50 	spdk_blob_id blobid;
51 	struct spdk_io_channel *channel;
52 	uint8_t *read_buff;
53 	uint8_t *write_buff;
54 	uint64_t page_size;
55 	int rc;
56 };
57 
58 /*
59  * Free up memory that we allocated.
60  */
61 static void
62 hello_cleanup(struct hello_context_t *hello_context)
63 {
64 	if (hello_context->read_buff) {
65 		spdk_dma_free(hello_context->read_buff);
66 	}
67 	if (hello_context->write_buff) {
68 		spdk_dma_free(hello_context->write_buff);
69 	}
70 	if (hello_context) {
71 		free(hello_context);
72 	}
73 }
74 
75 /*
76  * Callback routine for the blobstore unload.
77  */
78 static void
79 unload_complete(void *cb_arg, int bserrno)
80 {
81 	struct hello_context_t *hello_context = cb_arg;
82 
83 	SPDK_NOTICELOG("entry\n");
84 	if (bserrno) {
85 		SPDK_ERRLOG("Error %d unloading the bobstore\n", bserrno);
86 		hello_context->rc = bserrno;
87 	}
88 
89 	spdk_app_stop(hello_context->rc);
90 }
91 
92 /*
93  * Unload the blobstore, cleaning up as needed.
94  */
95 static void
96 unload_bs(struct hello_context_t *hello_context, char *msg, int bserrno)
97 {
98 	if (bserrno) {
99 		SPDK_ERRLOG("%s (err %d)\n", msg, bserrno);
100 		hello_context->rc = bserrno;
101 	}
102 	if (hello_context->bs) {
103 		if (hello_context->channel) {
104 			spdk_bs_free_io_channel(hello_context->channel);
105 		}
106 		spdk_bs_unload(hello_context->bs, unload_complete, hello_context);
107 	} else {
108 		spdk_app_stop(bserrno);
109 	}
110 }
111 
112 /*
113  * Callback routine for the deletion of a blob.
114  */
115 static void
116 delete_complete(void *arg1, int bserrno)
117 {
118 	struct hello_context_t *hello_context = arg1;
119 
120 	SPDK_NOTICELOG("entry\n");
121 	if (bserrno) {
122 		unload_bs(hello_context, "Error in delete completion",
123 			  bserrno);
124 		return;
125 	}
126 
127 	/* We're all done, we can unload the blobstore. */
128 	unload_bs(hello_context, "", 0);
129 }
130 
131 /*
132  * Function for deleting a blob.
133  */
134 static void
135 delete_blob(void *arg1, int bserrno)
136 {
137 	struct hello_context_t *hello_context = arg1;
138 
139 	SPDK_NOTICELOG("entry\n");
140 	if (bserrno) {
141 		unload_bs(hello_context, "Error in close completion",
142 			  bserrno);
143 		return;
144 	}
145 
146 	spdk_bs_md_delete_blob(hello_context->bs, hello_context->blobid,
147 			       delete_complete, hello_context);
148 }
149 
150 /*
151  * Callback function for reading a blob.
152  */
153 static void
154 read_complete(void *arg1, int bserrno)
155 {
156 	struct hello_context_t *hello_context = arg1;
157 	int match_res = -1;
158 
159 	SPDK_NOTICELOG("entry\n");
160 	if (bserrno) {
161 		unload_bs(hello_context, "Error in read completion",
162 			  bserrno);
163 		return;
164 	}
165 
166 	/* Now let's make sure things match. */
167 	match_res = memcmp(hello_context->write_buff, hello_context->read_buff,
168 			   hello_context->page_size);
169 	if (match_res) {
170 		unload_bs(hello_context, "Error in data compare", -1);
171 		return;
172 	} else {
173 		SPDK_NOTICELOG("read SUCCESS and data matches!\n");
174 	}
175 
176 	/* Now let's close it and delete the blob in the callback. */
177 	spdk_bs_md_close_blob(&hello_context->blob, delete_blob,
178 			      hello_context);
179 }
180 
181 /*
182  * Function for reading a blob.
183  */
184 static void
185 read_blob(struct hello_context_t *hello_context)
186 {
187 	SPDK_NOTICELOG("entry\n");
188 
189 	hello_context->read_buff = spdk_dma_malloc(hello_context->page_size,
190 				   0x1000, NULL);
191 	if (hello_context->read_buff == NULL) {
192 		unload_bs(hello_context, "Error in memory allocation",
193 			  -ENOMEM);
194 		return;
195 	}
196 
197 	/* Issue the read and compare the results in the callback. */
198 	spdk_bs_io_read_blob(hello_context->blob, hello_context->channel,
199 			     hello_context->read_buff, 0, 1, read_complete,
200 			     hello_context);
201 }
202 
203 /*
204  * Callback function for writing a blob.
205  */
206 static void
207 write_complete(void *arg1, int bserrno)
208 {
209 	struct hello_context_t *hello_context = arg1;
210 
211 	SPDK_NOTICELOG("entry\n");
212 	if (bserrno) {
213 		unload_bs(hello_context, "Error in write completion",
214 			  bserrno);
215 		return;
216 	}
217 
218 	/* Now let's read back what we wrote and make sure it matches. */
219 	read_blob(hello_context);
220 }
221 
222 /*
223  * Function for writing to a blob.
224  */
225 static void
226 blob_write(struct hello_context_t *hello_context)
227 {
228 	SPDK_NOTICELOG("entry\n");
229 
230 	/*
231 	 * Buffers for data transfer need to be allocated via SPDK. We will
232 	 * tranfer 1 page of 4K aligned data at offset 0 in the blob.
233 	 */
234 	hello_context->write_buff = spdk_dma_malloc(hello_context->page_size,
235 				    0x1000, NULL);
236 	if (hello_context->write_buff == NULL) {
237 		unload_bs(hello_context, "Error in allocating memory",
238 			  -ENOMEM);
239 		return;
240 	}
241 	memset(hello_context->write_buff, 0x5a, hello_context->page_size);
242 
243 	/* Now we have to allocate a channel. */
244 	hello_context->channel = spdk_bs_alloc_io_channel(hello_context->bs);
245 	if (hello_context->channel == NULL) {
246 		unload_bs(hello_context, "Error in allocating channel",
247 			  -ENOMEM);
248 		return;
249 	}
250 
251 	/* Let's perform the write, 1 page at offset 0. */
252 	spdk_bs_io_write_blob(hello_context->blob, hello_context->channel,
253 			      hello_context->write_buff,
254 			      0, 1, write_complete, hello_context);
255 }
256 
257 /*
258  * Callback function for sync'ing metadata.
259  */
260 static void
261 sync_complete(void *arg1, int bserrno)
262 {
263 	struct hello_context_t *hello_context = arg1;
264 
265 	SPDK_NOTICELOG("entry\n");
266 	if (bserrno) {
267 		unload_bs(hello_context, "Error in sync callback",
268 			  bserrno);
269 		return;
270 	}
271 
272 	/* Blob has been created & sized & MD sync'd, let's write to it. */
273 	blob_write(hello_context);
274 }
275 
276 /*
277  * Callback function for opening a blob.
278  */
279 static void
280 open_complete(void *cb_arg, struct spdk_blob *blob, int bserrno)
281 {
282 	struct hello_context_t *hello_context = cb_arg;
283 	uint64_t free = 0;
284 	uint64_t total = 0;
285 	int rc = 0;
286 
287 	SPDK_NOTICELOG("entry\n");
288 	if (bserrno) {
289 		unload_bs(hello_context, "Error in open completion",
290 			  bserrno);
291 		return;
292 	}
293 
294 
295 	hello_context->blob = blob;
296 	free = spdk_bs_free_cluster_count(hello_context->bs);
297 	SPDK_NOTICELOG("blobstore has FREE clusters of %" PRIu64 "\n",
298 		       free);
299 
300 	/*
301 	 * Before we can use our new blob, we have to resize it
302 	 * as the initial size is 0. For this example we'll use the
303 	 * full size of the blobstore but it would be expected that
304 	 * there'd usually be many blobs of various sizes. The resize
305 	 * unit is a cluster.
306 	 */
307 	rc = spdk_bs_md_resize_blob(hello_context->blob, free);
308 	if (rc) {
309 		unload_bs(hello_context, "Error in blob resize",
310 			  bserrno);
311 		return;
312 	}
313 
314 	total = spdk_blob_get_num_clusters(hello_context->blob);
315 	SPDK_NOTICELOG("resized blob now has USED clusters of %" PRIu64 "\n",
316 		       total);
317 
318 	/*
319 	 * Metadata is stored in volatile memory for performance
320 	 * reasons and therefore needs to be synchronized with
321 	 * non-volatile storage to make it persistent. This can be
322 	 * done manually, as shown here, or if not it will be done
323 	 * automatically when the blob is closed. It is always a
324 	 * good idea to sync after making metadata changes unless
325 	 * it has an unacceptable impact on application performance.
326 	 */
327 	spdk_bs_md_sync_blob(hello_context->blob, sync_complete,
328 			     hello_context);
329 }
330 
331 /*
332  * Callback function for creating a blob.
333  */
334 static void
335 blob_create_complete(void *arg1, spdk_blob_id blobid, int bserrno)
336 {
337 	struct hello_context_t *hello_context = arg1;
338 
339 	SPDK_NOTICELOG("entry\n");
340 	if (bserrno) {
341 		unload_bs(hello_context, "Error in blob create callback",
342 			  bserrno);
343 		return;
344 	}
345 
346 	hello_context->blobid = blobid;
347 	SPDK_NOTICELOG("new blob id %" PRIu64 "\n", hello_context->blobid);
348 
349 	/* We have to open the blob before we can do things like resize. */
350 	spdk_bs_md_open_blob(hello_context->bs, hello_context->blobid,
351 			     open_complete, hello_context);
352 }
353 
354 /*
355  * Function for creating a blob.
356  */
357 static void
358 create_blob(struct hello_context_t *hello_context)
359 {
360 	SPDK_NOTICELOG("entry\n");
361 	spdk_bs_md_create_blob(hello_context->bs, blob_create_complete,
362 			       hello_context);
363 }
364 
365 /*
366  * Callback function for initializing the blobstore.
367  */
368 static void
369 bs_init_complete(void *cb_arg, struct spdk_blob_store *bs,
370 		 int bserrno)
371 {
372 	struct hello_context_t *hello_context = cb_arg;
373 
374 	SPDK_NOTICELOG("entry\n");
375 	if (bserrno) {
376 		unload_bs(hello_context, "Error init'ing the blobstore",
377 			  bserrno);
378 		return;
379 	}
380 
381 	hello_context->bs = bs;
382 	SPDK_NOTICELOG("blobstore: %p\n", hello_context->bs);
383 	/*
384 	 * We will use the page size in allocating buffers, etc., later
385 	 * so we'll just save it in out context buffer here.
386 	 */
387 	hello_context->page_size = spdk_bs_get_page_size(hello_context->bs);
388 
389 	/*
390 	 * The blostore has been initialized, let's create a blob.
391 	 * Note that we could allcoate an SPDK event and use
392 	 * spdk_event_call() to schedule it if we wanted to keep
393 	 * our events as limited as possible wrt the amount of
394 	 * work that they do.
395 	 */
396 	create_blob(hello_context);
397 }
398 
399 /*
400  * Our initial event that kicks off everything from main().
401  */
402 static void
403 hello_start(void *arg1, void *arg2)
404 {
405 	struct hello_context_t *hello_context = arg1;
406 	struct spdk_bdev *bdev = NULL;
407 	struct spdk_bs_dev *bs_dev = NULL;
408 
409 	SPDK_NOTICELOG("entry\n");
410 	/*
411 	 * Get the bdev. For this example it is our malloc (RAM)
412 	 * disk configured via hello_blob.conf that was passed
413 	 * in when we started the SPDK app framework so we can
414 	 * get it via its name.
415 	 */
416 	bdev = spdk_bdev_get_by_name("Malloc0");
417 	if (bdev == NULL) {
418 		SPDK_ERRLOG("Could not find a bdev\n");
419 		spdk_app_stop(-1);
420 		return;
421 	}
422 
423 	/*
424 	 * spdk_bs_init() requires us to fill out the structure
425 	 * spdk_bs_dev with a set of callbacks. These callbacks
426 	 * implement read, write, and other operations on the
427 	 * underlying disks. As a convenience, a utility function
428 	 * is provided that creates an spdk_bs_dev that implements
429 	 * all of the callbacks by forwarding the I/O to the
430 	 * SPDK bdev layer. Other helper functions are also
431 	 * available in the blob lib in blob_bdev.c that simply
432 	 * make it easier to layer blobstore on top of a bdev.
433 	 * However blobstore can be more tightly integrated into
434 	 * any lower layer, such as NVMe for example.
435 	 */
436 	bs_dev = spdk_bdev_create_bs_dev(bdev);
437 	if (bs_dev == NULL) {
438 		SPDK_ERRLOG("Could not create blob bdev!!\n");
439 		spdk_app_stop(-1);
440 		return;
441 	}
442 
443 	spdk_bs_init(bs_dev, NULL, bs_init_complete, hello_context);
444 }
445 
446 int
447 main(int argc, char **argv)
448 {
449 	struct spdk_app_opts opts = {};
450 	int rc = 0;
451 	struct hello_context_t *hello_context = NULL;
452 
453 	SPDK_NOTICELOG("entry\n");
454 
455 	/* Set default values in opts structure. */
456 	spdk_app_opts_init(&opts);
457 
458 	/*
459 	 * Setup a few specifics before we init, for most SPDK cmd line
460 	 * apps, the config file will be passed in as an arg but to make
461 	 * this example super simple we just hardcode it. We also need to
462 	 * specify a name for the app.
463 	 */
464 	opts.name = "hello_blob";
465 	opts.config_file = "hello_blob.conf";
466 
467 
468 	/*
469 	 * Now we'll allocate and intialize the blobstore itself. We
470 	 * can pass in an spdk_bs_opts if we want something other than
471 	 * the defaults (cluster size, etc), but here we'll just take the
472 	 * defaults.  We'll also pass in a struct that we'll use for
473 	 * callbacks so we've got efficient bookeeping of what we're
474 	 * creating. This is an async operation and bs_init_complete()
475 	 * will be called when it is complete.
476 	 */
477 	hello_context = calloc(1, sizeof(struct hello_context_t));
478 	if (hello_context != NULL) {
479 		/*
480 		 * spdk_app_start() will block running hello_start() until
481 		 * spdk_app_stop() is called by someone (not simply when
482 		 * hello_start() returns)
483 		 */
484 		rc = spdk_app_start(&opts, hello_start, hello_context, NULL);
485 		if (rc) {
486 			SPDK_NOTICELOG("ERROR!\n");
487 		} else {
488 			SPDK_NOTICELOG("SUCCCESS!\n");
489 		}
490 		/* Free up memory that we allocated */
491 		hello_cleanup(hello_context);
492 	} else {
493 		SPDK_ERRLOG("Could not alloc hello_context struct!!\n");
494 		rc = -ENOMEM;
495 	}
496 
497 	/* Gracefully close out all of the SPDK subsystems. */
498 	spdk_app_fini();
499 	return rc;
500 }
501