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