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