LCOV - code coverage report
Current view: top level - spdk/lib/blob - blob_bs_dev.c (source / functions) Hit Total Coverage
Test: Combined Lines: 116 134 86.6 %
Date: 2024-11-20 10:55:39 Functions: 12 17 70.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 40 552 7.2 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2018 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  *   Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "spdk/stdinc.h"
       8                 :            : #include "spdk/blob.h"
       9                 :            : #include "spdk/log.h"
      10                 :            : #include "spdk/likely.h"
      11                 :            : #include "blobstore.h"
      12                 :            : 
      13                 :            : static void
      14                 :          0 : blob_bs_dev_write(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload,
      15                 :            :                   uint64_t lba, uint32_t lba_count,
      16                 :            :                   struct spdk_bs_dev_cb_args *cb_args)
      17                 :            : {
      18   [ #  #  #  #  :          0 :         cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, -EPERM);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      19         [ #  # ]:          0 :         assert(false);
      20                 :            : }
      21                 :            : 
      22                 :            : static void
      23                 :          0 : blob_bs_dev_writev(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
      24                 :            :                    struct iovec *iov, int iovcnt,
      25                 :            :                    uint64_t lba, uint32_t lba_count,
      26                 :            :                    struct spdk_bs_dev_cb_args *cb_args)
      27                 :            : {
      28   [ #  #  #  #  :          0 :         cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, -EPERM);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      29         [ #  # ]:          0 :         assert(false);
      30                 :            : }
      31                 :            : 
      32                 :            : static void
      33                 :          0 : blob_bs_dev_writev_ext(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
      34                 :            :                        struct iovec *iov, int iovcnt,
      35                 :            :                        uint64_t lba, uint32_t lba_count,
      36                 :            :                        struct spdk_bs_dev_cb_args *cb_args,
      37                 :            :                        struct spdk_blob_ext_io_opts *ext_opts)
      38                 :            : {
      39   [ #  #  #  #  :          0 :         cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, -EPERM);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      40         [ #  # ]:          0 :         assert(false);
      41                 :            : }
      42                 :            : 
      43                 :            : static void
      44                 :          0 : blob_bs_dev_write_zeroes(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
      45                 :            :                          uint64_t lba, uint64_t lba_count,
      46                 :            :                          struct spdk_bs_dev_cb_args *cb_args)
      47                 :            : {
      48   [ #  #  #  #  :          0 :         cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, -EPERM);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      49         [ #  # ]:          0 :         assert(false);
      50                 :            : }
      51                 :            : 
      52                 :            : static void
      53                 :          0 : blob_bs_dev_unmap(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
      54                 :            :                   uint64_t lba, uint64_t lba_count,
      55                 :            :                   struct spdk_bs_dev_cb_args *cb_args)
      56                 :            : {
      57   [ #  #  #  #  :          0 :         cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, -EPERM);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      58         [ #  # ]:          0 :         assert(false);
      59                 :            : }
      60                 :            : 
      61                 :            : static void
      62                 :      25460 : blob_bs_dev_read_cpl(void *cb_arg, int bserrno)
      63                 :            : {
      64                 :      25460 :         struct spdk_bs_dev_cb_args *cb_args = (struct spdk_bs_dev_cb_args *)cb_arg;
      65                 :            : 
      66   [ #  #  #  #  :      25460 :         cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, bserrno);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      67                 :      25460 : }
      68                 :            : 
      69                 :            : static inline void
      70                 :      25460 : zero_trailing_bytes(struct spdk_blob_bs_dev *b, struct iovec *iov, int iovcnt,
      71                 :            :                     uint64_t lba, uint32_t *lba_count)
      72                 :            : {
      73                 :            :         uint32_t zero_lba_count;
      74                 :            :         uint64_t zero_bytes, zero_len;
      75                 :            :         uint64_t payload_bytes;
      76                 :            :         uint64_t valid_bytes;
      77                 :            :         void *zero_start;
      78                 :            :         struct iovec *i;
      79                 :            : 
      80   [ +  +  #  #  :      25460 :         if (spdk_likely(lba + *lba_count <= b->bs_dev.blockcnt)) {
          #  #  #  #  #  
                      # ]
      81                 :      25300 :                 return;
      82                 :            :         }
      83                 :            : 
      84                 :            :         /* Figure out how many bytes in the payload will need to be zeroed. */
      85   [ +  +  #  #  :        160 :         zero_lba_count = spdk_min(*lba_count, lba + *lba_count - b->bs_dev.blockcnt);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
      86   [ #  #  #  #  :        160 :         zero_bytes = zero_lba_count * (uint64_t)b->bs_dev.blocklen;
                   #  # ]
      87                 :            : 
      88   [ #  #  #  #  :        160 :         payload_bytes = *lba_count * (uint64_t)b->bs_dev.blocklen;
             #  #  #  # ]
      89                 :        160 :         valid_bytes = payload_bytes - zero_bytes;
      90                 :            : 
      91                 :        160 :         i = iov;
      92         [ +  + ]:        320 :         while (zero_bytes > 0) {
      93   [ +  +  #  #  :        160 :                 if (i->iov_len > valid_bytes) {
                   #  # ]
      94   [ #  #  #  # ]:        160 :                         zero_start = i->iov_base + valid_bytes;
      95   [ -  +  #  #  :        160 :                         zero_len = spdk_min(payload_bytes, i->iov_len - valid_bytes);
          #  #  #  #  #  
                      # ]
      96         [ -  + ]:        160 :                         memset(zero_start, 0, zero_bytes);
      97                 :        160 :                         valid_bytes = 0;
      98                 :        160 :                         zero_bytes -= zero_len;
      99                 :         40 :                 }
     100   [ +  -  #  #  :        160 :                 valid_bytes -= spdk_min(valid_bytes, i->iov_len);
          #  #  #  #  #  
                      # ]
     101   [ -  +  #  #  :        160 :                 payload_bytes -= spdk_min(payload_bytes, i->iov_len);
          #  #  #  #  #  
                      # ]
     102         [ #  # ]:        160 :                 i++;
     103                 :            :         }
     104                 :            : 
     105         [ #  # ]:        160 :         *lba_count -= zero_lba_count;
     106                 :        555 : }
     107                 :            : 
     108                 :            : static inline void
     109                 :       1645 : blob_bs_dev_read(struct spdk_bs_dev *dev, struct spdk_io_channel *channel, void *payload,
     110                 :            :                  uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args)
     111                 :            : {
     112                 :       1645 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     113                 :       1182 :         struct iovec iov;
     114                 :            : 
     115                 :       1645 :         iov.iov_base = payload;
     116   [ #  #  #  #  :       1645 :         iov.iov_len = lba_count * b->bs_dev.blocklen;
             #  #  #  # ]
     117                 :            :         /* The backing blob may be smaller than this blob, so zero any trailing bytes. */
     118                 :       1645 :         zero_trailing_bytes(b, &iov, 1, lba, &lba_count);
     119                 :            : 
     120   [ #  #  #  # ]:       2039 :         spdk_blob_io_read(b->blob, channel, payload, lba, lba_count,
     121                 :        394 :                           blob_bs_dev_read_cpl, cb_args);
     122                 :       1645 : }
     123                 :            : 
     124                 :            : static inline void
     125                 :        320 : blob_bs_dev_readv(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
     126                 :            :                   struct iovec *iov, int iovcnt,
     127                 :            :                   uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args)
     128                 :            : {
     129                 :        320 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     130                 :            : 
     131                 :            :         /* The backing blob may be smaller than this blob, so zero any trailing bytes. */
     132                 :        320 :         zero_trailing_bytes(b, iov, iovcnt, lba, &lba_count);
     133                 :            : 
     134   [ #  #  #  # ]:        400 :         spdk_blob_io_readv(b->blob, channel, iov, iovcnt, lba, lba_count,
     135                 :         80 :                            blob_bs_dev_read_cpl, cb_args);
     136                 :        320 : }
     137                 :            : 
     138                 :            : static inline void
     139                 :      23495 : blob_bs_dev_readv_ext(struct spdk_bs_dev *dev, struct spdk_io_channel *channel,
     140                 :            :                       struct iovec *iov, int iovcnt,
     141                 :            :                       uint64_t lba, uint32_t lba_count, struct spdk_bs_dev_cb_args *cb_args,
     142                 :            :                       struct spdk_blob_ext_io_opts *ext_opts)
     143                 :            : {
     144                 :      23495 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     145                 :            : 
     146                 :            :         /* The backing blob may be smaller than this blob, so zero any trailing bytes. */
     147                 :      23495 :         zero_trailing_bytes(b, iov, iovcnt, lba, &lba_count);
     148                 :            : 
     149   [ #  #  #  # ]:      23576 :         spdk_blob_io_readv_ext(b->blob, channel, iov, iovcnt, lba, lba_count,
     150                 :         81 :                                blob_bs_dev_read_cpl, cb_args, ext_opts);
     151                 :      23495 : }
     152                 :            : 
     153                 :            : static void
     154                 :       2933 : blob_bs_dev_destroy_cpl(void *cb_arg, int bserrno)
     155                 :            : {
     156         [ -  + ]:       2933 :         if (bserrno != 0) {
     157                 :          0 :                 SPDK_ERRLOG("Error on blob_bs_dev destroy: %d", bserrno);
     158                 :          0 :         }
     159                 :            : 
     160                 :            :         /* Free blob_bs_dev */
     161                 :       2933 :         free(cb_arg);
     162                 :       2933 : }
     163                 :            : 
     164                 :            : static void
     165                 :       2933 : blob_bs_dev_destroy(struct spdk_bs_dev *bs_dev)
     166                 :            : {
     167                 :       2933 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)bs_dev;
     168                 :            : 
     169   [ #  #  #  # ]:       2933 :         spdk_blob_close(b->blob, blob_bs_dev_destroy_cpl, b);
     170                 :       2933 : }
     171                 :            : 
     172                 :            : static bool
     173                 :       2097 : blob_bs_is_zeroes(struct spdk_bs_dev *dev, uint64_t lba, uint64_t lba_count)
     174                 :            : {
     175                 :       2097 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     176   [ #  #  #  # ]:       2097 :         struct spdk_blob *blob = b->blob;
     177                 :            :         bool is_valid_range;
     178                 :            : 
     179   [ +  +  #  #  :       2097 :         assert(lba == bs_cluster_to_lba(blob->bs, bs_lba_to_cluster(blob->bs, lba)));
          #  #  #  #  #  
                #  #  # ]
     180   [ +  +  #  #  :       2097 :         assert(lba_count == bs_dev_byte_to_lba(dev, blob->bs->cluster_sz));
          #  #  #  #  #  
                #  #  # ]
     181                 :            : 
     182         [ +  + ]:       2097 :         if (bs_io_unit_is_allocated(blob, lba)) {
     183                 :       1163 :                 return false;
     184                 :            :         }
     185                 :            : 
     186   [ -  +  #  #  :        934 :         assert(blob->back_bs_dev != NULL);
             #  #  #  # ]
     187   [ #  #  #  #  :        934 :         is_valid_range = blob->back_bs_dev->is_range_valid(blob->back_bs_dev, lba, lba_count);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     188   [ +  +  +  +  :        934 :         return is_valid_range && blob->back_bs_dev->is_zeroes(blob->back_bs_dev,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     189                 :        192 :                         bs_io_unit_to_back_dev_lba(blob, lba),
     190                 :        192 :                         bs_io_unit_to_back_dev_lba(blob, lba_count));
     191                 :        492 : }
     192                 :            : 
     193                 :            : static bool
     194                 :       2443 : blob_bs_is_range_valid(struct spdk_bs_dev *dev, uint64_t lba, uint64_t lba_count)
     195                 :            : {
     196                 :       2443 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     197   [ #  #  #  # ]:       2443 :         struct spdk_blob *blob = b->blob;
     198                 :            :         uint64_t        page;
     199                 :            :         uint64_t        pages_per_cluster;
     200                 :            : 
     201                 :            :         /* The lba here is supposed to be the first lba of cluster. lba_count
     202                 :            :          * will typically be fixed e.g. 8192 for 4MiB cluster. */
     203   [ +  +  -  +  :       2443 :         assert(lba_count == blob->bs->cluster_sz / dev->blocklen);
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     204   [ +  +  -  +  :       2443 :         assert(lba % lba_count == 0);
                   #  # ]
     205                 :            : 
     206   [ #  #  #  #  :       2443 :         pages_per_cluster = blob->bs->pages_per_cluster;
             #  #  #  # ]
     207   [ #  #  #  # ]:       2443 :         page = bs_io_unit_to_page(blob->bs, lba);
     208                 :            : 
     209                 :            :         /* A blob will either have:
     210                 :            :         * - no backing bs_bdev (normal thick blob), or
     211                 :            :         * - zeroes backing bs_bdev (thin provisioned blob), or
     212                 :            :         * - blob backing bs_bdev (e.g snapshot)
     213                 :            :         * It may be possible that backing bs_bdev has lesser number of clusters
     214                 :            :         * than the child lvol blob because lvol blob has been expanded after
     215                 :            :         * taking snapshot. In such a case, page will be outside the cluster page
     216                 :            :         * range of the backing dev. Always return true for zeroes backing bdev. */
     217   [ #  #  #  #  :       2443 :         return page < blob->active.num_clusters * pages_per_cluster;
                   #  # ]
     218                 :            : }
     219                 :            : 
     220                 :            : static bool
     221                 :       1044 : blob_bs_translate_lba(struct spdk_bs_dev *dev, uint64_t lba, uint64_t *base_lba)
     222                 :            : {
     223                 :       1044 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     224   [ #  #  #  # ]:       1044 :         struct spdk_blob *blob = b->blob;
     225                 :            :         bool is_valid_range;
     226                 :            : 
     227   [ +  +  #  # ]:       1044 :         assert(base_lba != NULL);
     228         [ +  + ]:       1044 :         if (bs_io_unit_is_allocated(blob, lba)) {
     229         [ #  # ]:        574 :                 *base_lba = bs_blob_io_unit_to_lba(blob, lba);
     230                 :        574 :                 return true;
     231                 :            :         }
     232                 :            : 
     233   [ -  +  #  #  :        470 :         assert(blob->back_bs_dev != NULL);
             #  #  #  # ]
     234                 :            :         /* Since here we don't get lba_count directly, passing lba_count derived
     235                 :            :          * from cluster_sz which typically happens for other calls like is_zeroes
     236                 :            :          * in CoW path. */
     237   [ #  #  #  #  :        824 :         is_valid_range = blob->back_bs_dev->is_range_valid(blob->back_bs_dev, lba,
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     238   [ #  #  #  #  :        470 :                          bs_dev_byte_to_lba(blob->back_bs_dev, blob->bs->cluster_sz));
          #  #  #  #  #  
                #  #  # ]
     239   [ +  +  +  +  :        470 :         return is_valid_range && blob->back_bs_dev->translate_lba(blob->back_bs_dev,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
     240                 :         96 :                         bs_io_unit_to_back_dev_lba(blob, lba),
     241                 :         96 :                         base_lba);
     242                 :        246 : }
     243                 :            : 
     244                 :            : static bool
     245                 :        107 : blob_bs_is_degraded(struct spdk_bs_dev *dev)
     246                 :            : {
     247                 :        107 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     248                 :            : 
     249   [ #  #  #  # ]:        107 :         return spdk_blob_is_degraded(b->blob);
     250                 :            : }
     251                 :            : 
     252                 :            : struct spdk_bs_dev *
     253                 :       2933 : bs_create_blob_bs_dev(struct spdk_blob *blob)
     254                 :            : {
     255                 :            :         struct spdk_blob_bs_dev  *b;
     256                 :            : 
     257                 :       2933 :         b = calloc(1, sizeof(*b));
     258         [ -  + ]:       2933 :         if (b == NULL) {
     259                 :          0 :                 return NULL;
     260                 :            :         }
     261                 :            :         /* snapshot blob */
     262   [ #  #  #  #  :       6561 :         b->bs_dev.blockcnt = blob->active.num_clusters *
          #  #  #  #  #  
                #  #  # ]
     263   [ #  #  #  #  :       3628 :                              blob->bs->pages_per_cluster * bs_io_unit_per_page(blob->bs);
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     264   [ #  #  #  #  :       2933 :         b->bs_dev.blocklen = spdk_bs_get_io_unit_size(blob->bs);
          #  #  #  #  #  
                      # ]
     265   [ #  #  #  #  :       2933 :         b->bs_dev.create_channel = NULL;
                   #  # ]
     266   [ #  #  #  #  :       2933 :         b->bs_dev.destroy_channel = NULL;
                   #  # ]
     267   [ #  #  #  #  :       2933 :         b->bs_dev.destroy = blob_bs_dev_destroy;
                   #  # ]
     268   [ #  #  #  #  :       2933 :         b->bs_dev.write = blob_bs_dev_write;
                   #  # ]
     269   [ #  #  #  #  :       2933 :         b->bs_dev.writev = blob_bs_dev_writev;
                   #  # ]
     270   [ #  #  #  #  :       2933 :         b->bs_dev.writev_ext = blob_bs_dev_writev_ext;
                   #  # ]
     271   [ #  #  #  #  :       2933 :         b->bs_dev.read = blob_bs_dev_read;
                   #  # ]
     272   [ #  #  #  #  :       2933 :         b->bs_dev.readv = blob_bs_dev_readv;
                   #  # ]
     273   [ #  #  #  #  :       2933 :         b->bs_dev.readv_ext = blob_bs_dev_readv_ext;
                   #  # ]
     274   [ #  #  #  #  :       2933 :         b->bs_dev.write_zeroes = blob_bs_dev_write_zeroes;
                   #  # ]
     275   [ #  #  #  #  :       2933 :         b->bs_dev.unmap = blob_bs_dev_unmap;
                   #  # ]
     276   [ #  #  #  #  :       2933 :         b->bs_dev.is_zeroes = blob_bs_is_zeroes;
                   #  # ]
     277   [ #  #  #  #  :       2933 :         b->bs_dev.is_range_valid = blob_bs_is_range_valid;
                   #  # ]
     278   [ #  #  #  #  :       2933 :         b->bs_dev.translate_lba = blob_bs_translate_lba;
                   #  # ]
     279   [ #  #  #  #  :       2933 :         b->bs_dev.is_degraded = blob_bs_is_degraded;
                   #  # ]
     280   [ #  #  #  # ]:       2933 :         b->blob = blob;
     281                 :            : 
     282         [ #  # ]:       2933 :         return &b->bs_dev;
     283                 :        695 : }

Generated by: LCOV version 1.15