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 io_unit_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_free(hello_context->read_buff); 65 spdk_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->io_unit_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_malloc(hello_context->io_unit_size, 183 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, 184 SPDK_MALLOC_DMA); 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_blob_io_read(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 * transfer 1 io_unit of 4K aligned data at offset 0 in the blob. 227 */ 228 hello_context->write_buff = spdk_malloc(hello_context->io_unit_size, 229 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, 230 SPDK_MALLOC_DMA); 231 if (hello_context->write_buff == NULL) { 232 unload_bs(hello_context, "Error in allocating memory", 233 -ENOMEM); 234 return; 235 } 236 memset(hello_context->write_buff, 0x5a, hello_context->io_unit_size); 237 238 /* Now we have to allocate a channel. */ 239 hello_context->channel = spdk_bs_alloc_io_channel(hello_context->bs); 240 if (hello_context->channel == NULL) { 241 unload_bs(hello_context, "Error in allocating channel", 242 -ENOMEM); 243 return; 244 } 245 246 /* Let's perform the write, 1 io_unit at offset 0. */ 247 spdk_blob_io_write(hello_context->blob, hello_context->channel, 248 hello_context->write_buff, 249 0, 1, write_complete, hello_context); 250 } 251 252 /* 253 * Callback function for sync'ing metadata. 254 */ 255 static void 256 sync_complete(void *arg1, int bserrno) 257 { 258 struct hello_context_t *hello_context = arg1; 259 260 SPDK_NOTICELOG("entry\n"); 261 if (bserrno) { 262 unload_bs(hello_context, "Error in sync callback", 263 bserrno); 264 return; 265 } 266 267 /* Blob has been created & sized & MD sync'd, let's write to it. */ 268 blob_write(hello_context); 269 } 270 271 static void 272 resize_complete(void *cb_arg, int bserrno) 273 { 274 struct hello_context_t *hello_context = cb_arg; 275 uint64_t total = 0; 276 277 if (bserrno) { 278 unload_bs(hello_context, "Error in blob resize", bserrno); 279 return; 280 } 281 282 total = spdk_blob_get_num_clusters(hello_context->blob); 283 SPDK_NOTICELOG("resized blob now has USED clusters of %" PRIu64 "\n", 284 total); 285 286 /* 287 * Metadata is stored in volatile memory for performance 288 * reasons and therefore needs to be synchronized with 289 * non-volatile storage to make it persistent. This can be 290 * done manually, as shown here, or if not it will be done 291 * automatically when the blob is closed. It is always a 292 * good idea to sync after making metadata changes unless 293 * it has an unacceptable impact on application performance. 294 */ 295 spdk_blob_sync_md(hello_context->blob, sync_complete, hello_context); 296 } 297 298 /* 299 * Callback function for opening a blob. 300 */ 301 static void 302 open_complete(void *cb_arg, struct spdk_blob *blob, int bserrno) 303 { 304 struct hello_context_t *hello_context = cb_arg; 305 uint64_t free = 0; 306 307 SPDK_NOTICELOG("entry\n"); 308 if (bserrno) { 309 unload_bs(hello_context, "Error in open completion", 310 bserrno); 311 return; 312 } 313 314 315 hello_context->blob = blob; 316 free = spdk_bs_free_cluster_count(hello_context->bs); 317 SPDK_NOTICELOG("blobstore has FREE clusters of %" PRIu64 "\n", 318 free); 319 320 /* 321 * Before we can use our new blob, we have to resize it 322 * as the initial size is 0. For this example we'll use the 323 * full size of the blobstore but it would be expected that 324 * there'd usually be many blobs of various sizes. The resize 325 * unit is a cluster. 326 */ 327 spdk_blob_resize(hello_context->blob, free, resize_complete, hello_context); 328 } 329 330 /* 331 * Callback function for creating a blob. 332 */ 333 static void 334 blob_create_complete(void *arg1, spdk_blob_id blobid, int bserrno) 335 { 336 struct hello_context_t *hello_context = arg1; 337 338 SPDK_NOTICELOG("entry\n"); 339 if (bserrno) { 340 unload_bs(hello_context, "Error in blob create callback", 341 bserrno); 342 return; 343 } 344 345 hello_context->blobid = blobid; 346 SPDK_NOTICELOG("new blob id %" PRIu64 "\n", hello_context->blobid); 347 348 /* We have to open the blob before we can do things like resize. */ 349 spdk_bs_open_blob(hello_context->bs, hello_context->blobid, 350 open_complete, hello_context); 351 } 352 353 /* 354 * Function for creating a blob. 355 */ 356 static void 357 create_blob(struct hello_context_t *hello_context) 358 { 359 SPDK_NOTICELOG("entry\n"); 360 spdk_bs_create_blob(hello_context->bs, blob_create_complete, hello_context); 361 } 362 363 /* 364 * Callback function for initializing the blobstore. 365 */ 366 static void 367 bs_init_complete(void *cb_arg, struct spdk_blob_store *bs, 368 int bserrno) 369 { 370 struct hello_context_t *hello_context = cb_arg; 371 372 SPDK_NOTICELOG("entry\n"); 373 if (bserrno) { 374 unload_bs(hello_context, "Error init'ing the blobstore", 375 bserrno); 376 return; 377 } 378 379 hello_context->bs = bs; 380 SPDK_NOTICELOG("blobstore: %p\n", hello_context->bs); 381 /* 382 * We will use the io_unit size in allocating buffers, etc., later 383 * so we'll just save it in out context buffer here. 384 */ 385 hello_context->io_unit_size = spdk_bs_get_io_unit_size(hello_context->bs); 386 387 /* 388 * The blobstore has been initialized, let's create a blob. 389 * Note that we could pass a message back to ourselves using 390 * spdk_thread_send_msg() if we wanted to keep our processing 391 * time limited. 392 */ 393 create_blob(hello_context); 394 } 395 396 /* 397 * Our initial event that kicks off everything from main(). 398 */ 399 static void 400 hello_start(void *arg1) 401 { 402 struct hello_context_t *hello_context = arg1; 403 struct spdk_bdev *bdev = NULL; 404 struct spdk_bs_dev *bs_dev = NULL; 405 406 SPDK_NOTICELOG("entry\n"); 407 /* 408 * Get the bdev. For this example it is our malloc (RAM) 409 * disk configured via hello_blob.conf that was passed 410 * in when we started the SPDK app framework so we can 411 * get it via its name. 412 */ 413 bdev = spdk_bdev_get_by_name("Malloc0"); 414 if (bdev == NULL) { 415 SPDK_ERRLOG("Could not find a bdev\n"); 416 spdk_app_stop(-1); 417 return; 418 } 419 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 bs_dev = spdk_bdev_create_bs_dev(bdev, NULL, NULL); 434 if (bs_dev == NULL) { 435 SPDK_ERRLOG("Could not create blob bdev!!\n"); 436 spdk_app_stop(-1); 437 return; 438 } 439 440 spdk_bs_init(bs_dev, NULL, bs_init_complete, hello_context); 441 } 442 443 int 444 main(int argc, char **argv) 445 { 446 struct spdk_app_opts opts = {}; 447 int rc = 0; 448 struct hello_context_t *hello_context = NULL; 449 450 SPDK_NOTICELOG("entry\n"); 451 452 /* Set default values in opts structure. */ 453 spdk_app_opts_init(&opts); 454 455 /* 456 * Setup a few specifics before we init, for most SPDK cmd line 457 * apps, the config file will be passed in as an arg but to make 458 * this example super simple we just hardcode it. We also need to 459 * specify a name for the app. 460 */ 461 opts.name = "hello_blob"; 462 opts.json_config_file = argv[1]; 463 464 465 /* 466 * Now we'll allocate and initialize the blobstore itself. We 467 * can pass in an spdk_bs_opts if we want something other than 468 * the defaults (cluster size, etc), but here we'll just take the 469 * defaults. We'll also pass in a struct that we'll use for 470 * callbacks so we've got efficient bookeeping of what we're 471 * creating. This is an async operation and bs_init_complete() 472 * will be called when it is complete. 473 */ 474 hello_context = calloc(1, sizeof(struct hello_context_t)); 475 if (hello_context != NULL) { 476 /* 477 * spdk_app_start() will block running hello_start() until 478 * spdk_app_stop() is called by someone (not simply when 479 * hello_start() returns), or if an error occurs during 480 * spdk_app_start() before hello_start() runs. 481 */ 482 rc = spdk_app_start(&opts, hello_start, hello_context); 483 if (rc) { 484 SPDK_NOTICELOG("ERROR!\n"); 485 } else { 486 SPDK_NOTICELOG("SUCCESS!\n"); 487 } 488 /* Free up memory that we allocated */ 489 hello_cleanup(hello_context); 490 } else { 491 SPDK_ERRLOG("Could not alloc hello_context struct!!\n"); 492 rc = -ENOMEM; 493 } 494 495 /* Gracefully close out all of the SPDK subsystems. */ 496 spdk_app_fini(); 497 return rc; 498 } 499