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