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 allcoate an SPDK event and use 388 * spdk_event_call() to schedule it if we wanted to keep 389 * our events as limited as possible wrt the amount of 390 * work that they do. 391 */ 392 create_blob(hello_context); 393 } 394 395 /* 396 * Our initial event that kicks off everything from main(). 397 */ 398 static void 399 hello_start(void *arg1, void *arg2) 400 { 401 struct hello_context_t *hello_context = arg1; 402 struct spdk_bdev *bdev = NULL; 403 struct spdk_bs_dev *bs_dev = NULL; 404 405 SPDK_NOTICELOG("entry\n"); 406 /* 407 * Get the bdev. For this example it is our malloc (RAM) 408 * disk configured via hello_blob.conf that was passed 409 * in when we started the SPDK app framework so we can 410 * get it via its name. 411 */ 412 bdev = spdk_bdev_get_by_name("Malloc0"); 413 if (bdev == NULL) { 414 SPDK_ERRLOG("Could not find a bdev\n"); 415 spdk_app_stop(-1); 416 return; 417 } 418 419 /* 420 * spdk_bs_init() requires us to fill out the structure 421 * spdk_bs_dev with a set of callbacks. These callbacks 422 * implement read, write, and other operations on the 423 * underlying disks. As a convenience, a utility function 424 * is provided that creates an spdk_bs_dev that implements 425 * all of the callbacks by forwarding the I/O to the 426 * SPDK bdev layer. Other helper functions are also 427 * available in the blob lib in blob_bdev.c that simply 428 * make it easier to layer blobstore on top of a bdev. 429 * However blobstore can be more tightly integrated into 430 * any lower layer, such as NVMe for example. 431 */ 432 bs_dev = spdk_bdev_create_bs_dev(bdev, NULL, NULL); 433 if (bs_dev == NULL) { 434 SPDK_ERRLOG("Could not create blob bdev!!\n"); 435 spdk_app_stop(-1); 436 return; 437 } 438 439 spdk_bs_init(bs_dev, NULL, bs_init_complete, hello_context); 440 } 441 442 int 443 main(int argc, char **argv) 444 { 445 struct spdk_app_opts opts = {}; 446 int rc = 0; 447 struct hello_context_t *hello_context = NULL; 448 449 SPDK_NOTICELOG("entry\n"); 450 451 /* Set default values in opts structure. */ 452 spdk_app_opts_init(&opts); 453 454 /* 455 * Setup a few specifics before we init, for most SPDK cmd line 456 * apps, the config file will be passed in as an arg but to make 457 * this example super simple we just hardcode it. We also need to 458 * specify a name for the app. 459 */ 460 opts.name = "hello_blob"; 461 opts.config_file = "hello_blob.conf"; 462 463 464 /* 465 * Now we'll allocate and intialize the blobstore itself. We 466 * can pass in an spdk_bs_opts if we want something other than 467 * the defaults (cluster size, etc), but here we'll just take the 468 * defaults. We'll also pass in a struct that we'll use for 469 * callbacks so we've got efficient bookeeping of what we're 470 * creating. This is an async operation and bs_init_complete() 471 * will be called when it is complete. 472 */ 473 hello_context = calloc(1, sizeof(struct hello_context_t)); 474 if (hello_context != NULL) { 475 /* 476 * spdk_app_start() will block running hello_start() until 477 * spdk_app_stop() is called by someone (not simply when 478 * hello_start() returns), or if an error occurs during 479 * spdk_app_start() before hello_start() runs. 480 */ 481 rc = spdk_app_start(&opts, hello_start, hello_context, NULL); 482 if (rc) { 483 SPDK_NOTICELOG("ERROR!\n"); 484 } else { 485 SPDK_NOTICELOG("SUCCCESS!\n"); 486 } 487 /* Free up memory that we allocated */ 488 hello_cleanup(hello_context); 489 } else { 490 SPDK_ERRLOG("Could not alloc hello_context struct!!\n"); 491 rc = -ENOMEM; 492 } 493 494 /* Gracefully close out all of the SPDK subsystems. */ 495 spdk_app_fini(); 496 return rc; 497 } 498