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