LCOV - code coverage report
Current view: top level - spdk/examples/blob/hello_world - hello_blob.c (source / functions) Hit Total Coverage
Test: Combined Lines: 121 161 75.2 %
Date: 2024-07-11 12:42:46 Functions: 17 18 94.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 23 46 50.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2017 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "spdk/bdev.h"
       9                 :            : #include "spdk/env.h"
      10                 :            : #include "spdk/event.h"
      11                 :            : #include "spdk/blob_bdev.h"
      12                 :            : #include "spdk/blob.h"
      13                 :            : #include "spdk/log.h"
      14                 :            : #include "spdk/string.h"
      15                 :            : 
      16                 :            : /*
      17                 :            :  * We'll use this struct to gather housekeeping hello_context to pass between
      18                 :            :  * our events and callbacks.
      19                 :            :  */
      20                 :            : struct hello_context_t {
      21                 :            :         struct spdk_blob_store *bs;
      22                 :            :         struct spdk_blob *blob;
      23                 :            :         spdk_blob_id blobid;
      24                 :            :         struct spdk_io_channel *channel;
      25                 :            :         uint8_t *read_buff;
      26                 :            :         uint8_t *write_buff;
      27                 :            :         uint64_t io_unit_size;
      28                 :            :         int rc;
      29                 :            : };
      30                 :            : 
      31                 :            : /*
      32                 :            :  * Free up memory that we allocated.
      33                 :            :  */
      34                 :            : static void
      35                 :          1 : hello_cleanup(struct hello_context_t *hello_context)
      36                 :            : {
      37                 :          1 :         spdk_free(hello_context->read_buff);
      38                 :          1 :         spdk_free(hello_context->write_buff);
      39                 :          1 :         free(hello_context);
      40                 :          1 : }
      41                 :            : 
      42                 :            : /*
      43                 :            :  * Callback routine for the blobstore unload.
      44                 :            :  */
      45                 :            : static void
      46                 :          1 : unload_complete(void *cb_arg, int bserrno)
      47                 :            : {
      48                 :          1 :         struct hello_context_t *hello_context = cb_arg;
      49                 :            : 
      50                 :          1 :         SPDK_NOTICELOG("entry\n");
      51         [ -  + ]:          1 :         if (bserrno) {
      52                 :          0 :                 SPDK_ERRLOG("Error %d unloading the bobstore\n", bserrno);
      53                 :          0 :                 hello_context->rc = bserrno;
      54                 :            :         }
      55                 :            : 
      56                 :          1 :         spdk_app_stop(hello_context->rc);
      57                 :          1 : }
      58                 :            : 
      59                 :            : /*
      60                 :            :  * Unload the blobstore, cleaning up as needed.
      61                 :            :  */
      62                 :            : static void
      63                 :          1 : unload_bs(struct hello_context_t *hello_context, char *msg, int bserrno)
      64                 :            : {
      65         [ -  + ]:          1 :         if (bserrno) {
      66                 :          0 :                 SPDK_ERRLOG("%s (err %d)\n", msg, bserrno);
      67                 :          0 :                 hello_context->rc = bserrno;
      68                 :            :         }
      69         [ +  - ]:          1 :         if (hello_context->bs) {
      70         [ +  - ]:          1 :                 if (hello_context->channel) {
      71                 :          1 :                         spdk_bs_free_io_channel(hello_context->channel);
      72                 :            :                 }
      73                 :          1 :                 spdk_bs_unload(hello_context->bs, unload_complete, hello_context);
      74                 :            :         } else {
      75                 :          0 :                 spdk_app_stop(bserrno);
      76                 :            :         }
      77                 :          1 : }
      78                 :            : 
      79                 :            : /*
      80                 :            :  * Callback routine for the deletion of a blob.
      81                 :            :  */
      82                 :            : static void
      83                 :          1 : delete_complete(void *arg1, int bserrno)
      84                 :            : {
      85                 :          1 :         struct hello_context_t *hello_context = arg1;
      86                 :            : 
      87                 :          1 :         SPDK_NOTICELOG("entry\n");
      88         [ -  + ]:          1 :         if (bserrno) {
      89                 :          0 :                 unload_bs(hello_context, "Error in delete completion",
      90                 :            :                           bserrno);
      91                 :          0 :                 return;
      92                 :            :         }
      93                 :            : 
      94                 :            :         /* We're all done, we can unload the blobstore. */
      95                 :          1 :         unload_bs(hello_context, "", 0);
      96                 :            : }
      97                 :            : 
      98                 :            : /*
      99                 :            :  * Function for deleting a blob.
     100                 :            :  */
     101                 :            : static void
     102                 :          1 : delete_blob(void *arg1, int bserrno)
     103                 :            : {
     104                 :          1 :         struct hello_context_t *hello_context = arg1;
     105                 :            : 
     106                 :          1 :         SPDK_NOTICELOG("entry\n");
     107         [ -  + ]:          1 :         if (bserrno) {
     108                 :          0 :                 unload_bs(hello_context, "Error in close completion",
     109                 :            :                           bserrno);
     110                 :          0 :                 return;
     111                 :            :         }
     112                 :            : 
     113                 :          1 :         spdk_bs_delete_blob(hello_context->bs, hello_context->blobid,
     114                 :            :                             delete_complete, hello_context);
     115                 :            : }
     116                 :            : 
     117                 :            : /*
     118                 :            :  * Callback function for reading a blob.
     119                 :            :  */
     120                 :            : static void
     121                 :          1 : read_complete(void *arg1, int bserrno)
     122                 :            : {
     123                 :          1 :         struct hello_context_t *hello_context = arg1;
     124                 :          1 :         int match_res = -1;
     125                 :            : 
     126                 :          1 :         SPDK_NOTICELOG("entry\n");
     127         [ -  + ]:          1 :         if (bserrno) {
     128                 :          0 :                 unload_bs(hello_context, "Error in read completion",
     129                 :            :                           bserrno);
     130                 :          0 :                 return;
     131                 :            :         }
     132                 :            : 
     133                 :            :         /* Now let's make sure things match. */
     134   [ -  +  -  + ]:          1 :         match_res = memcmp(hello_context->write_buff, hello_context->read_buff,
     135                 :            :                            hello_context->io_unit_size);
     136         [ -  + ]:          1 :         if (match_res) {
     137                 :          0 :                 unload_bs(hello_context, "Error in data compare", -1);
     138                 :          0 :                 return;
     139                 :            :         } else {
     140                 :          1 :                 SPDK_NOTICELOG("read SUCCESS and data matches!\n");
     141                 :            :         }
     142                 :            : 
     143                 :            :         /* Now let's close it and delete the blob in the callback. */
     144                 :          1 :         spdk_blob_close(hello_context->blob, delete_blob, hello_context);
     145                 :            : }
     146                 :            : 
     147                 :            : /*
     148                 :            :  * Function for reading a blob.
     149                 :            :  */
     150                 :            : static void
     151                 :          1 : read_blob(struct hello_context_t *hello_context)
     152                 :            : {
     153                 :          1 :         SPDK_NOTICELOG("entry\n");
     154                 :            : 
     155                 :          1 :         hello_context->read_buff = spdk_malloc(hello_context->io_unit_size,
     156                 :            :                                                0x1000, NULL, SPDK_ENV_LCORE_ID_ANY,
     157                 :            :                                                SPDK_MALLOC_DMA);
     158         [ -  + ]:          1 :         if (hello_context->read_buff == NULL) {
     159                 :          0 :                 unload_bs(hello_context, "Error in memory allocation",
     160                 :            :                           -ENOMEM);
     161                 :          0 :                 return;
     162                 :            :         }
     163                 :            : 
     164                 :            :         /* Issue the read and compare the results in the callback. */
     165                 :          1 :         spdk_blob_io_read(hello_context->blob, hello_context->channel,
     166                 :          1 :                           hello_context->read_buff, 0, 1, read_complete,
     167                 :            :                           hello_context);
     168                 :            : }
     169                 :            : 
     170                 :            : /*
     171                 :            :  * Callback function for writing a blob.
     172                 :            :  */
     173                 :            : static void
     174                 :          1 : write_complete(void *arg1, int bserrno)
     175                 :            : {
     176                 :          1 :         struct hello_context_t *hello_context = arg1;
     177                 :            : 
     178                 :          1 :         SPDK_NOTICELOG("entry\n");
     179         [ -  + ]:          1 :         if (bserrno) {
     180                 :          0 :                 unload_bs(hello_context, "Error in write completion",
     181                 :            :                           bserrno);
     182                 :          0 :                 return;
     183                 :            :         }
     184                 :            : 
     185                 :            :         /* Now let's read back what we wrote and make sure it matches. */
     186                 :          1 :         read_blob(hello_context);
     187                 :            : }
     188                 :            : 
     189                 :            : /*
     190                 :            :  * Function for writing to a blob.
     191                 :            :  */
     192                 :            : static void
     193                 :          1 : blob_write(struct hello_context_t *hello_context)
     194                 :            : {
     195                 :          1 :         SPDK_NOTICELOG("entry\n");
     196                 :            : 
     197                 :            :         /*
     198                 :            :          * Buffers for data transfer need to be allocated via SPDK. We will
     199                 :            :          * transfer 1 io_unit of 4K aligned data at offset 0 in the blob.
     200                 :            :          */
     201                 :          1 :         hello_context->write_buff = spdk_malloc(hello_context->io_unit_size,
     202                 :            :                                                 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY,
     203                 :            :                                                 SPDK_MALLOC_DMA);
     204         [ -  + ]:          1 :         if (hello_context->write_buff == NULL) {
     205                 :          0 :                 unload_bs(hello_context, "Error in allocating memory",
     206                 :            :                           -ENOMEM);
     207                 :          0 :                 return;
     208                 :            :         }
     209         [ -  + ]:          1 :         memset(hello_context->write_buff, 0x5a, hello_context->io_unit_size);
     210                 :            : 
     211                 :            :         /* Now we have to allocate a channel. */
     212                 :          1 :         hello_context->channel = spdk_bs_alloc_io_channel(hello_context->bs);
     213         [ -  + ]:          1 :         if (hello_context->channel == NULL) {
     214                 :          0 :                 unload_bs(hello_context, "Error in allocating channel",
     215                 :            :                           -ENOMEM);
     216                 :          0 :                 return;
     217                 :            :         }
     218                 :            : 
     219                 :            :         /* Let's perform the write, 1 io_unit at offset 0. */
     220                 :          1 :         spdk_blob_io_write(hello_context->blob, hello_context->channel,
     221                 :          1 :                            hello_context->write_buff,
     222                 :            :                            0, 1, write_complete, hello_context);
     223                 :            : }
     224                 :            : 
     225                 :            : /*
     226                 :            :  * Callback function for syncing metadata.
     227                 :            :  */
     228                 :            : static void
     229                 :          1 : sync_complete(void *arg1, int bserrno)
     230                 :            : {
     231                 :          1 :         struct hello_context_t *hello_context = arg1;
     232                 :            : 
     233                 :          1 :         SPDK_NOTICELOG("entry\n");
     234         [ -  + ]:          1 :         if (bserrno) {
     235                 :          0 :                 unload_bs(hello_context, "Error in sync callback",
     236                 :            :                           bserrno);
     237                 :          0 :                 return;
     238                 :            :         }
     239                 :            : 
     240                 :            :         /* Blob has been created & sized & MD sync'd, let's write to it. */
     241                 :          1 :         blob_write(hello_context);
     242                 :            : }
     243                 :            : 
     244                 :            : static void
     245                 :          1 : resize_complete(void *cb_arg, int bserrno)
     246                 :            : {
     247                 :          1 :         struct hello_context_t *hello_context = cb_arg;
     248                 :          1 :         uint64_t total = 0;
     249                 :            : 
     250         [ -  + ]:          1 :         if (bserrno) {
     251                 :          0 :                 unload_bs(hello_context, "Error in blob resize", bserrno);
     252                 :          0 :                 return;
     253                 :            :         }
     254                 :            : 
     255                 :          1 :         total = spdk_blob_get_num_clusters(hello_context->blob);
     256                 :          1 :         SPDK_NOTICELOG("resized blob now has USED clusters of %" PRIu64 "\n",
     257                 :            :                        total);
     258                 :            : 
     259                 :            :         /*
     260                 :            :          * Metadata is stored in volatile memory for performance
     261                 :            :          * reasons and therefore needs to be synchronized with
     262                 :            :          * non-volatile storage to make it persistent. This can be
     263                 :            :          * done manually, as shown here, or if not it will be done
     264                 :            :          * automatically when the blob is closed. It is always a
     265                 :            :          * good idea to sync after making metadata changes unless
     266                 :            :          * it has an unacceptable impact on application performance.
     267                 :            :          */
     268                 :          1 :         spdk_blob_sync_md(hello_context->blob, sync_complete, hello_context);
     269                 :            : }
     270                 :            : 
     271                 :            : /*
     272                 :            :  * Callback function for opening a blob.
     273                 :            :  */
     274                 :            : static void
     275                 :          1 : open_complete(void *cb_arg, struct spdk_blob *blob, int bserrno)
     276                 :            : {
     277                 :          1 :         struct hello_context_t *hello_context = cb_arg;
     278                 :          1 :         uint64_t free = 0;
     279                 :            : 
     280                 :          1 :         SPDK_NOTICELOG("entry\n");
     281         [ -  + ]:          1 :         if (bserrno) {
     282                 :          0 :                 unload_bs(hello_context, "Error in open completion",
     283                 :            :                           bserrno);
     284                 :          0 :                 return;
     285                 :            :         }
     286                 :            : 
     287                 :            : 
     288                 :          1 :         hello_context->blob = blob;
     289                 :          1 :         free = spdk_bs_free_cluster_count(hello_context->bs);
     290                 :          1 :         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                 :          1 :         spdk_blob_resize(hello_context->blob, free, resize_complete, hello_context);
     301                 :            : }
     302                 :            : 
     303                 :            : /*
     304                 :            :  * Callback function for creating a blob.
     305                 :            :  */
     306                 :            : static void
     307                 :          1 : blob_create_complete(void *arg1, spdk_blob_id blobid, int bserrno)
     308                 :            : {
     309                 :          1 :         struct hello_context_t *hello_context = arg1;
     310                 :            : 
     311                 :          1 :         SPDK_NOTICELOG("entry\n");
     312         [ -  + ]:          1 :         if (bserrno) {
     313                 :          0 :                 unload_bs(hello_context, "Error in blob create callback",
     314                 :            :                           bserrno);
     315                 :          0 :                 return;
     316                 :            :         }
     317                 :            : 
     318                 :          1 :         hello_context->blobid = blobid;
     319                 :          1 :         SPDK_NOTICELOG("new blob id %" PRIu64 "\n", hello_context->blobid);
     320                 :            : 
     321                 :            :         /* We have to open the blob before we can do things like resize. */
     322                 :          1 :         spdk_bs_open_blob(hello_context->bs, hello_context->blobid,
     323                 :            :                           open_complete, hello_context);
     324                 :            : }
     325                 :            : 
     326                 :            : /*
     327                 :            :  * Function for creating a blob.
     328                 :            :  */
     329                 :            : static void
     330                 :          1 : create_blob(struct hello_context_t *hello_context)
     331                 :            : {
     332                 :          1 :         SPDK_NOTICELOG("entry\n");
     333                 :          1 :         spdk_bs_create_blob(hello_context->bs, blob_create_complete, hello_context);
     334                 :          1 : }
     335                 :            : 
     336                 :            : /*
     337                 :            :  * Callback function for initializing the blobstore.
     338                 :            :  */
     339                 :            : static void
     340                 :          1 : bs_init_complete(void *cb_arg, struct spdk_blob_store *bs,
     341                 :            :                  int bserrno)
     342                 :            : {
     343                 :          1 :         struct hello_context_t *hello_context = cb_arg;
     344                 :            : 
     345                 :          1 :         SPDK_NOTICELOG("entry\n");
     346         [ -  + ]:          1 :         if (bserrno) {
     347                 :          0 :                 unload_bs(hello_context, "Error initing the blobstore",
     348                 :            :                           bserrno);
     349                 :          0 :                 return;
     350                 :            :         }
     351                 :            : 
     352                 :          1 :         hello_context->bs = bs;
     353                 :          1 :         SPDK_NOTICELOG("blobstore: %p\n", hello_context->bs);
     354                 :            :         /*
     355                 :            :          * We will use the io_unit size in allocating buffers, etc., later
     356                 :            :          * so we'll just save it in out context buffer here.
     357                 :            :          */
     358                 :          1 :         hello_context->io_unit_size = spdk_bs_get_io_unit_size(hello_context->bs);
     359                 :            : 
     360                 :            :         /*
     361                 :            :          * The blobstore has been initialized, let's create a blob.
     362                 :            :          * Note that we could pass a message back to ourselves using
     363                 :            :          * spdk_thread_send_msg() if we wanted to keep our processing
     364                 :            :          * time limited.
     365                 :            :          */
     366                 :          1 :         create_blob(hello_context);
     367                 :            : }
     368                 :            : 
     369                 :            : static void
     370                 :          0 : base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
     371                 :            :                    void *event_ctx)
     372                 :            : {
     373                 :          0 :         SPDK_WARNLOG("Unsupported bdev event: type %d\n", type);
     374                 :          0 : }
     375                 :            : 
     376                 :            : /*
     377                 :            :  * Our initial event that kicks off everything from main().
     378                 :            :  */
     379                 :            : static void
     380                 :          1 : hello_start(void *arg1)
     381                 :            : {
     382                 :          1 :         struct hello_context_t *hello_context = arg1;
     383                 :          1 :         struct spdk_bs_dev *bs_dev = NULL;
     384                 :            :         int rc;
     385                 :            : 
     386                 :          1 :         SPDK_NOTICELOG("entry\n");
     387                 :            : 
     388                 :            :         /*
     389                 :            :          * In this example, use our malloc (RAM) disk configured via
     390                 :            :          * hello_blob.json that was passed in when we started the
     391                 :            :          * SPDK app framework.
     392                 :            :          *
     393                 :            :          * spdk_bs_init() requires us to fill out the structure
     394                 :            :          * spdk_bs_dev with a set of callbacks. These callbacks
     395                 :            :          * implement read, write, and other operations on the
     396                 :            :          * underlying disks. As a convenience, a utility function
     397                 :            :          * is provided that creates an spdk_bs_dev that implements
     398                 :            :          * all of the callbacks by forwarding the I/O to the
     399                 :            :          * SPDK bdev layer. Other helper functions are also
     400                 :            :          * available in the blob lib in blob_bdev.c that simply
     401                 :            :          * make it easier to layer blobstore on top of a bdev.
     402                 :            :          * However blobstore can be more tightly integrated into
     403                 :            :          * any lower layer, such as NVMe for example.
     404                 :            :          */
     405                 :          1 :         rc = spdk_bdev_create_bs_dev_ext("Malloc0", base_bdev_event_cb, NULL, &bs_dev);
     406         [ -  + ]:          1 :         if (rc != 0) {
     407                 :          0 :                 SPDK_ERRLOG("Could not create blob bdev, %s!!\n",
     408                 :            :                             spdk_strerror(-rc));
     409                 :          0 :                 spdk_app_stop(-1);
     410                 :          0 :                 return;
     411                 :            :         }
     412                 :            : 
     413                 :          1 :         spdk_bs_init(bs_dev, NULL, bs_init_complete, hello_context);
     414                 :            : }
     415                 :            : 
     416                 :            : int
     417                 :          1 : main(int argc, char **argv)
     418                 :            : {
     419                 :          1 :         struct spdk_app_opts opts = {};
     420                 :          1 :         int rc = 0;
     421                 :          1 :         struct hello_context_t *hello_context = NULL;
     422                 :            : 
     423                 :          1 :         SPDK_NOTICELOG("entry\n");
     424                 :            : 
     425                 :            :         /* Set default values in opts structure. */
     426                 :          1 :         spdk_app_opts_init(&opts, sizeof(opts));
     427                 :            : 
     428                 :            :         /*
     429                 :            :          * Setup a few specifics before we init, for most SPDK cmd line
     430                 :            :          * apps, the config file will be passed in as an arg but to make
     431                 :            :          * this example super simple we just hardcode it. We also need to
     432                 :            :          * specify a name for the app.
     433                 :            :          */
     434                 :          1 :         opts.name = "hello_blob";
     435                 :          1 :         opts.json_config_file = argv[1];
     436                 :          1 :         opts.rpc_addr = NULL;
     437                 :            : 
     438                 :            :         /*
     439                 :            :          * Now we'll allocate and initialize the blobstore itself. We
     440                 :            :          * can pass in an spdk_bs_opts if we want something other than
     441                 :            :          * the defaults (cluster size, etc), but here we'll just take the
     442                 :            :          * defaults.  We'll also pass in a struct that we'll use for
     443                 :            :          * callbacks so we've got efficient bookkeeping of what we're
     444                 :            :          * creating. This is an async operation and bs_init_complete()
     445                 :            :          * will be called when it is complete.
     446                 :            :          */
     447                 :          1 :         hello_context = calloc(1, sizeof(struct hello_context_t));
     448         [ +  - ]:          1 :         if (hello_context != NULL) {
     449                 :            :                 /*
     450                 :            :                  * spdk_app_start() will block running hello_start() until
     451                 :            :                  * spdk_app_stop() is called by someone (not simply when
     452                 :            :                  * hello_start() returns), or if an error occurs during
     453                 :            :                  * spdk_app_start() before hello_start() runs.
     454                 :            :                  */
     455                 :          1 :                 rc = spdk_app_start(&opts, hello_start, hello_context);
     456         [ -  + ]:          1 :                 if (rc) {
     457                 :          0 :                         SPDK_NOTICELOG("ERROR!\n");
     458                 :            :                 } else {
     459                 :          1 :                         SPDK_NOTICELOG("SUCCESS!\n");
     460                 :            :                 }
     461                 :            :                 /* Free up memory that we allocated */
     462                 :          1 :                 hello_cleanup(hello_context);
     463                 :            :         } else {
     464                 :          0 :                 SPDK_ERRLOG("Could not alloc hello_context struct!!\n");
     465                 :          0 :                 rc = -ENOMEM;
     466                 :            :         }
     467                 :            : 
     468                 :            :         /* Gracefully close out all of the SPDK subsystems. */
     469                 :          1 :         spdk_app_fini();
     470                 :          1 :         return rc;
     471                 :            : }

Generated by: LCOV version 1.14