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