xref: /spdk/examples/blob/hello_world/hello_blob.c (revision 552e21cce6cccbf833ed9109827e08337377d7ce)
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 	spdk_dma_free(hello_context->read_buff);
65 	spdk_dma_free(hello_context->write_buff);
66 	free(hello_context);
67 }
68 
69 /*
70  * Callback routine for the blobstore unload.
71  */
72 static void
73 unload_complete(void *cb_arg, int bserrno)
74 {
75 	struct hello_context_t *hello_context = cb_arg;
76 
77 	SPDK_NOTICELOG("entry\n");
78 	if (bserrno) {
79 		SPDK_ERRLOG("Error %d unloading the bobstore\n", bserrno);
80 		hello_context->rc = bserrno;
81 	}
82 
83 	spdk_app_stop(hello_context->rc);
84 }
85 
86 /*
87  * Unload the blobstore, cleaning up as needed.
88  */
89 static void
90 unload_bs(struct hello_context_t *hello_context, char *msg, int bserrno)
91 {
92 	if (bserrno) {
93 		SPDK_ERRLOG("%s (err %d)\n", msg, bserrno);
94 		hello_context->rc = bserrno;
95 	}
96 	if (hello_context->bs) {
97 		if (hello_context->channel) {
98 			spdk_bs_free_io_channel(hello_context->channel);
99 		}
100 		spdk_bs_unload(hello_context->bs, unload_complete, hello_context);
101 	} else {
102 		spdk_app_stop(bserrno);
103 	}
104 }
105 
106 /*
107  * Callback routine for the deletion of a blob.
108  */
109 static void
110 delete_complete(void *arg1, int bserrno)
111 {
112 	struct hello_context_t *hello_context = arg1;
113 
114 	SPDK_NOTICELOG("entry\n");
115 	if (bserrno) {
116 		unload_bs(hello_context, "Error in delete completion",
117 			  bserrno);
118 		return;
119 	}
120 
121 	/* We're all done, we can unload the blobstore. */
122 	unload_bs(hello_context, "", 0);
123 }
124 
125 /*
126  * Function for deleting a blob.
127  */
128 static void
129 delete_blob(void *arg1, int bserrno)
130 {
131 	struct hello_context_t *hello_context = arg1;
132 
133 	SPDK_NOTICELOG("entry\n");
134 	if (bserrno) {
135 		unload_bs(hello_context, "Error in close completion",
136 			  bserrno);
137 		return;
138 	}
139 
140 	spdk_bs_delete_blob(hello_context->bs, hello_context->blobid,
141 			    delete_complete, hello_context);
142 }
143 
144 /*
145  * Callback function for reading a blob.
146  */
147 static void
148 read_complete(void *arg1, int bserrno)
149 {
150 	struct hello_context_t *hello_context = arg1;
151 	int match_res = -1;
152 
153 	SPDK_NOTICELOG("entry\n");
154 	if (bserrno) {
155 		unload_bs(hello_context, "Error in read completion",
156 			  bserrno);
157 		return;
158 	}
159 
160 	/* Now let's make sure things match. */
161 	match_res = memcmp(hello_context->write_buff, hello_context->read_buff,
162 			   hello_context->page_size);
163 	if (match_res) {
164 		unload_bs(hello_context, "Error in data compare", -1);
165 		return;
166 	} else {
167 		SPDK_NOTICELOG("read SUCCESS and data matches!\n");
168 	}
169 
170 	/* Now let's close it and delete the blob in the callback. */
171 	spdk_blob_close(hello_context->blob, delete_blob, hello_context);
172 }
173 
174 /*
175  * Function for reading a blob.
176  */
177 static void
178 read_blob(struct hello_context_t *hello_context)
179 {
180 	SPDK_NOTICELOG("entry\n");
181 
182 	hello_context->read_buff = spdk_dma_malloc(hello_context->page_size,
183 				   0x1000, NULL);
184 	if (hello_context->read_buff == NULL) {
185 		unload_bs(hello_context, "Error in memory allocation",
186 			  -ENOMEM);
187 		return;
188 	}
189 
190 	/* Issue the read and compare the results in the callback. */
191 	spdk_blob_io_read(hello_context->blob, hello_context->channel,
192 			  hello_context->read_buff, 0, 1, read_complete,
193 			  hello_context);
194 }
195 
196 /*
197  * Callback function for writing a blob.
198  */
199 static void
200 write_complete(void *arg1, int bserrno)
201 {
202 	struct hello_context_t *hello_context = arg1;
203 
204 	SPDK_NOTICELOG("entry\n");
205 	if (bserrno) {
206 		unload_bs(hello_context, "Error in write completion",
207 			  bserrno);
208 		return;
209 	}
210 
211 	/* Now let's read back what we wrote and make sure it matches. */
212 	read_blob(hello_context);
213 }
214 
215 /*
216  * Function for writing to a blob.
217  */
218 static void
219 blob_write(struct hello_context_t *hello_context)
220 {
221 	SPDK_NOTICELOG("entry\n");
222 
223 	/*
224 	 * Buffers for data transfer need to be allocated via SPDK. We will
225 	 * tranfer 1 page of 4K aligned data at offset 0 in the blob.
226 	 */
227 	hello_context->write_buff = spdk_dma_malloc(hello_context->page_size,
228 				    0x1000, NULL);
229 	if (hello_context->write_buff == NULL) {
230 		unload_bs(hello_context, "Error in allocating memory",
231 			  -ENOMEM);
232 		return;
233 	}
234 	memset(hello_context->write_buff, 0x5a, hello_context->page_size);
235 
236 	/* Now we have to allocate a channel. */
237 	hello_context->channel = spdk_bs_alloc_io_channel(hello_context->bs);
238 	if (hello_context->channel == NULL) {
239 		unload_bs(hello_context, "Error in allocating channel",
240 			  -ENOMEM);
241 		return;
242 	}
243 
244 	/* Let's perform the write, 1 page at offset 0. */
245 	spdk_blob_io_write(hello_context->blob, hello_context->channel,
246 			   hello_context->write_buff,
247 			   0, 1, write_complete, hello_context);
248 }
249 
250 /*
251  * Callback function for sync'ing metadata.
252  */
253 static void
254 sync_complete(void *arg1, int bserrno)
255 {
256 	struct hello_context_t *hello_context = arg1;
257 
258 	SPDK_NOTICELOG("entry\n");
259 	if (bserrno) {
260 		unload_bs(hello_context, "Error in sync callback",
261 			  bserrno);
262 		return;
263 	}
264 
265 	/* Blob has been created & sized & MD sync'd, let's write to it. */
266 	blob_write(hello_context);
267 }
268 
269 static void
270 resize_complete(void *cb_arg, int bserrno)
271 {
272 	struct hello_context_t *hello_context = cb_arg;
273 	uint64_t total = 0;
274 
275 	if (bserrno) {
276 		unload_bs(hello_context, "Error in blob resize", bserrno);
277 		return;
278 	}
279 
280 	total = spdk_blob_get_num_clusters(hello_context->blob);
281 	SPDK_NOTICELOG("resized blob now has USED clusters of %" PRIu64 "\n",
282 		       total);
283 
284 	/*
285 	 * Metadata is stored in volatile memory for performance
286 	 * reasons and therefore needs to be synchronized with
287 	 * non-volatile storage to make it persistent. This can be
288 	 * done manually, as shown here, or if not it will be done
289 	 * automatically when the blob is closed. It is always a
290 	 * good idea to sync after making metadata changes unless
291 	 * it has an unacceptable impact on application performance.
292 	 */
293 	spdk_blob_sync_md(hello_context->blob, sync_complete, hello_context);
294 }
295 
296 /*
297  * Callback function for opening a blob.
298  */
299 static void
300 open_complete(void *cb_arg, struct spdk_blob *blob, int bserrno)
301 {
302 	struct hello_context_t *hello_context = cb_arg;
303 	uint64_t free = 0;
304 
305 	SPDK_NOTICELOG("entry\n");
306 	if (bserrno) {
307 		unload_bs(hello_context, "Error in open completion",
308 			  bserrno);
309 		return;
310 	}
311 
312 
313 	hello_context->blob = blob;
314 	free = spdk_bs_free_cluster_count(hello_context->bs);
315 	SPDK_NOTICELOG("blobstore has FREE clusters of %" PRIu64 "\n",
316 		       free);
317 
318 	/*
319 	 * Before we can use our new blob, we have to resize it
320 	 * as the initial size is 0. For this example we'll use the
321 	 * full size of the blobstore but it would be expected that
322 	 * there'd usually be many blobs of various sizes. The resize
323 	 * unit is a cluster.
324 	 */
325 	spdk_blob_resize(hello_context->blob, free, resize_complete, hello_context);
326 }
327 
328 /*
329  * Callback function for creating a blob.
330  */
331 static void
332 blob_create_complete(void *arg1, spdk_blob_id blobid, int bserrno)
333 {
334 	struct hello_context_t *hello_context = arg1;
335 
336 	SPDK_NOTICELOG("entry\n");
337 	if (bserrno) {
338 		unload_bs(hello_context, "Error in blob create callback",
339 			  bserrno);
340 		return;
341 	}
342 
343 	hello_context->blobid = blobid;
344 	SPDK_NOTICELOG("new blob id %" PRIu64 "\n", hello_context->blobid);
345 
346 	/* We have to open the blob before we can do things like resize. */
347 	spdk_bs_open_blob(hello_context->bs, hello_context->blobid,
348 			  open_complete, hello_context);
349 }
350 
351 /*
352  * Function for creating a blob.
353  */
354 static void
355 create_blob(struct hello_context_t *hello_context)
356 {
357 	SPDK_NOTICELOG("entry\n");
358 	spdk_bs_create_blob(hello_context->bs, blob_create_complete, hello_context);
359 }
360 
361 /*
362  * Callback function for initializing the blobstore.
363  */
364 static void
365 bs_init_complete(void *cb_arg, struct spdk_blob_store *bs,
366 		 int bserrno)
367 {
368 	struct hello_context_t *hello_context = cb_arg;
369 
370 	SPDK_NOTICELOG("entry\n");
371 	if (bserrno) {
372 		unload_bs(hello_context, "Error init'ing the blobstore",
373 			  bserrno);
374 		return;
375 	}
376 
377 	hello_context->bs = bs;
378 	SPDK_NOTICELOG("blobstore: %p\n", hello_context->bs);
379 	/*
380 	 * We will use the page size in allocating buffers, etc., later
381 	 * so we'll just save it in out context buffer here.
382 	 */
383 	hello_context->page_size = spdk_bs_get_page_size(hello_context->bs);
384 
385 	/*
386 	 * The blostore has been initialized, let's create a blob.
387 	 * Note that we could pass a message back to ourselves using
388 	 * spdk_thread_send_msg() if we wanted to keep our processing
389 	 * time limited.
390 	 */
391 	create_blob(hello_context);
392 }
393 
394 /*
395  * Our initial event that kicks off everything from main().
396  */
397 static void
398 hello_start(void *arg1, void *arg2)
399 {
400 	struct hello_context_t *hello_context = arg1;
401 	struct spdk_bdev *bdev = NULL;
402 	struct spdk_bs_dev *bs_dev = NULL;
403 
404 	SPDK_NOTICELOG("entry\n");
405 	/*
406 	 * Get the bdev. For this example it is our malloc (RAM)
407 	 * disk configured via hello_blob.conf that was passed
408 	 * in when we started the SPDK app framework so we can
409 	 * get it via its name.
410 	 */
411 	bdev = spdk_bdev_get_by_name("Malloc0");
412 	if (bdev == NULL) {
413 		SPDK_ERRLOG("Could not find a bdev\n");
414 		spdk_app_stop(-1);
415 		return;
416 	}
417 
418 	/*
419 	 * spdk_bs_init() requires us to fill out the structure
420 	 * spdk_bs_dev with a set of callbacks. These callbacks
421 	 * implement read, write, and other operations on the
422 	 * underlying disks. As a convenience, a utility function
423 	 * is provided that creates an spdk_bs_dev that implements
424 	 * all of the callbacks by forwarding the I/O to the
425 	 * SPDK bdev layer. Other helper functions are also
426 	 * available in the blob lib in blob_bdev.c that simply
427 	 * make it easier to layer blobstore on top of a bdev.
428 	 * However blobstore can be more tightly integrated into
429 	 * any lower layer, such as NVMe for example.
430 	 */
431 	bs_dev = spdk_bdev_create_bs_dev(bdev, NULL, NULL);
432 	if (bs_dev == NULL) {
433 		SPDK_ERRLOG("Could not create blob bdev!!\n");
434 		spdk_app_stop(-1);
435 		return;
436 	}
437 
438 	spdk_bs_init(bs_dev, NULL, bs_init_complete, hello_context);
439 }
440 
441 int
442 main(int argc, char **argv)
443 {
444 	struct spdk_app_opts opts = {};
445 	int rc = 0;
446 	struct hello_context_t *hello_context = NULL;
447 
448 	SPDK_NOTICELOG("entry\n");
449 
450 	/* Set default values in opts structure. */
451 	spdk_app_opts_init(&opts);
452 
453 	/*
454 	 * Setup a few specifics before we init, for most SPDK cmd line
455 	 * apps, the config file will be passed in as an arg but to make
456 	 * this example super simple we just hardcode it. We also need to
457 	 * specify a name for the app.
458 	 */
459 	opts.name = "hello_blob";
460 	opts.config_file = "hello_blob.conf";
461 
462 
463 	/*
464 	 * Now we'll allocate and intialize the blobstore itself. We
465 	 * can pass in an spdk_bs_opts if we want something other than
466 	 * the defaults (cluster size, etc), but here we'll just take the
467 	 * defaults.  We'll also pass in a struct that we'll use for
468 	 * callbacks so we've got efficient bookeeping of what we're
469 	 * creating. This is an async operation and bs_init_complete()
470 	 * will be called when it is complete.
471 	 */
472 	hello_context = calloc(1, sizeof(struct hello_context_t));
473 	if (hello_context != NULL) {
474 		/*
475 		 * spdk_app_start() will block running hello_start() until
476 		 * spdk_app_stop() is called by someone (not simply when
477 		 * hello_start() returns), or if an error occurs during
478 		 * spdk_app_start() before hello_start() runs.
479 		 */
480 		rc = spdk_app_start(&opts, hello_start, hello_context, NULL);
481 		if (rc) {
482 			SPDK_NOTICELOG("ERROR!\n");
483 		} else {
484 			SPDK_NOTICELOG("SUCCCESS!\n");
485 		}
486 		/* Free up memory that we allocated */
487 		hello_cleanup(hello_context);
488 	} else {
489 		SPDK_ERRLOG("Could not alloc hello_context struct!!\n");
490 		rc = -ENOMEM;
491 	}
492 
493 	/* Gracefully close out all of the SPDK subsystems. */
494 	spdk_app_fini();
495 	return rc;
496 }
497