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); 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