LCOV - code coverage report
Current view: top level - lib/blob - blob_bs_dev.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 101 121 83.5 %
Date: 2024-11-05 10:06:02 Functions: 11 17 64.7 %

          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         546 : blob_bs_dev_read_cpl(void *cb_arg, int bserrno)
      63             : {
      64         546 :         struct spdk_bs_dev_cb_args *cb_args = (struct spdk_bs_dev_cb_args *)cb_arg;
      65             : 
      66         546 :         cb_args->cb_fn(cb_args->channel, cb_args->cb_arg, bserrno);
      67         546 : }
      68             : 
      69             : static inline void
      70         546 : 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         546 :         if (spdk_likely(lba + *lba_count <= b->bs_dev.blockcnt)) {
      81         506 :                 return;
      82             :         }
      83             : 
      84             :         /* Figure out how many bytes in the payload will need to be zeroed. */
      85          40 :         zero_lba_count = spdk_min(*lba_count, lba + *lba_count - b->bs_dev.blockcnt);
      86          40 :         zero_bytes = zero_lba_count * (uint64_t)b->bs_dev.blocklen;
      87             : 
      88          40 :         payload_bytes = *lba_count * (uint64_t)b->bs_dev.blocklen;
      89          40 :         valid_bytes = payload_bytes - zero_bytes;
      90             : 
      91          40 :         i = iov;
      92          80 :         while (zero_bytes > 0) {
      93          40 :                 if (i->iov_len > valid_bytes) {
      94          40 :                         zero_start = i->iov_base + valid_bytes;
      95          40 :                         zero_len = spdk_min(payload_bytes, i->iov_len - valid_bytes);
      96          40 :                         memset(zero_start, 0, zero_bytes);
      97          40 :                         valid_bytes = 0;
      98          40 :                         zero_bytes -= zero_len;
      99             :                 }
     100          40 :                 valid_bytes -= spdk_min(valid_bytes, i->iov_len);
     101          40 :                 payload_bytes -= spdk_min(payload_bytes, i->iov_len);
     102          40 :                 i++;
     103             :         }
     104             : 
     105          40 :         *lba_count -= zero_lba_count;
     106             : }
     107             : 
     108             : static inline void
     109         394 : 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         394 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     113         394 :         struct iovec iov;
     114             : 
     115         394 :         iov.iov_base = payload;
     116         394 :         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         394 :         zero_trailing_bytes(b, &iov, 1, lba, &lba_count);
     119             : 
     120         394 :         spdk_blob_io_read(b->blob, channel, payload, lba, lba_count,
     121             :                           blob_bs_dev_read_cpl, cb_args);
     122         394 : }
     123             : 
     124             : static inline void
     125          80 : 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          80 :         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          80 :         zero_trailing_bytes(b, iov, iovcnt, lba, &lba_count);
     133             : 
     134          80 :         spdk_blob_io_readv(b->blob, channel, iov, iovcnt, lba, lba_count,
     135             :                            blob_bs_dev_read_cpl, cb_args);
     136          80 : }
     137             : 
     138             : static inline void
     139          72 : 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          72 :         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          72 :         zero_trailing_bytes(b, iov, iovcnt, lba, &lba_count);
     148             : 
     149          72 :         spdk_blob_io_readv_ext(b->blob, channel, iov, iovcnt, lba, lba_count,
     150             :                                blob_bs_dev_read_cpl, cb_args, ext_opts);
     151          72 : }
     152             : 
     153             : static void
     154         684 : blob_bs_dev_destroy_cpl(void *cb_arg, int bserrno)
     155             : {
     156         684 :         if (bserrno != 0) {
     157           0 :                 SPDK_ERRLOG("Error on blob_bs_dev destroy: %d", bserrno);
     158             :         }
     159             : 
     160             :         /* Free blob_bs_dev */
     161         684 :         free(cb_arg);
     162         684 : }
     163             : 
     164             : static void
     165         684 : blob_bs_dev_destroy(struct spdk_bs_dev *bs_dev)
     166             : {
     167         684 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)bs_dev;
     168             : 
     169         684 :         spdk_blob_close(b->blob, blob_bs_dev_destroy_cpl, b);
     170         684 : }
     171             : 
     172             : static bool
     173         492 : blob_bs_is_zeroes(struct spdk_bs_dev *dev, uint64_t lba, uint64_t lba_count)
     174             : {
     175         492 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     176         492 :         struct spdk_blob *blob = b->blob;
     177             :         bool is_valid_range;
     178             : 
     179         492 :         assert(lba == bs_cluster_to_lba(blob->bs, bs_lba_to_cluster(blob->bs, lba)));
     180         492 :         assert(lba_count == bs_dev_byte_to_lba(dev, blob->bs->cluster_sz));
     181             : 
     182         492 :         if (bs_io_unit_is_allocated(blob, lba)) {
     183         260 :                 return false;
     184             :         }
     185             : 
     186         232 :         assert(blob->back_bs_dev != NULL);
     187         232 :         is_valid_range = blob->back_bs_dev->is_range_valid(blob->back_bs_dev, lba, lba_count);
     188         232 :         return is_valid_range && blob->back_bs_dev->is_zeroes(blob->back_bs_dev,
     189             :                         bs_io_unit_to_back_dev_lba(blob, lba),
     190             :                         bs_io_unit_to_back_dev_lba(blob, lba_count));
     191             : }
     192             : 
     193             : static bool
     194         578 : blob_bs_is_range_valid(struct spdk_bs_dev *dev, uint64_t lba, uint64_t lba_count)
     195             : {
     196         578 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     197         578 :         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         578 :         assert(lba_count == blob->bs->cluster_sz / dev->blocklen);
     204         578 :         assert(lba % lba_count == 0);
     205             : 
     206         578 :         pages_per_cluster = blob->bs->pages_per_cluster;
     207         578 :         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         578 :         return page < blob->active.num_clusters * pages_per_cluster;
     218             : }
     219             : 
     220             : static bool
     221         246 : blob_bs_translate_lba(struct spdk_bs_dev *dev, uint64_t lba, uint64_t *base_lba)
     222             : {
     223         246 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     224         246 :         struct spdk_blob *blob = b->blob;
     225             :         bool is_valid_range;
     226             : 
     227         246 :         assert(base_lba != NULL);
     228         246 :         if (bs_io_unit_is_allocated(blob, lba)) {
     229         130 :                 *base_lba = bs_blob_io_unit_to_lba(blob, lba);
     230         130 :                 return true;
     231             :         }
     232             : 
     233         116 :         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         232 :         is_valid_range = blob->back_bs_dev->is_range_valid(blob->back_bs_dev, lba,
     238         116 :                          bs_dev_byte_to_lba(blob->back_bs_dev, blob->bs->cluster_sz));
     239         116 :         return is_valid_range && blob->back_bs_dev->translate_lba(blob->back_bs_dev,
     240             :                         bs_io_unit_to_back_dev_lba(blob, lba),
     241             :                         base_lba);
     242             : }
     243             : 
     244             : static bool
     245           0 : blob_bs_is_degraded(struct spdk_bs_dev *dev)
     246             : {
     247           0 :         struct spdk_blob_bs_dev *b = (struct spdk_blob_bs_dev *)dev;
     248             : 
     249           0 :         return spdk_blob_is_degraded(b->blob);
     250             : }
     251             : 
     252             : struct spdk_bs_dev *
     253         684 : bs_create_blob_bs_dev(struct spdk_blob *blob)
     254             : {
     255             :         struct spdk_blob_bs_dev  *b;
     256             : 
     257         684 :         b = calloc(1, sizeof(*b));
     258         684 :         if (b == NULL) {
     259           0 :                 return NULL;
     260             :         }
     261             :         /* snapshot blob */
     262        1368 :         b->bs_dev.blockcnt = blob->active.num_clusters *
     263         684 :                              blob->bs->pages_per_cluster * bs_io_unit_per_page(blob->bs);
     264         684 :         b->bs_dev.blocklen = spdk_bs_get_io_unit_size(blob->bs);
     265         684 :         b->bs_dev.create_channel = NULL;
     266         684 :         b->bs_dev.destroy_channel = NULL;
     267         684 :         b->bs_dev.destroy = blob_bs_dev_destroy;
     268         684 :         b->bs_dev.write = blob_bs_dev_write;
     269         684 :         b->bs_dev.writev = blob_bs_dev_writev;
     270         684 :         b->bs_dev.writev_ext = blob_bs_dev_writev_ext;
     271         684 :         b->bs_dev.read = blob_bs_dev_read;
     272         684 :         b->bs_dev.readv = blob_bs_dev_readv;
     273         684 :         b->bs_dev.readv_ext = blob_bs_dev_readv_ext;
     274         684 :         b->bs_dev.write_zeroes = blob_bs_dev_write_zeroes;
     275         684 :         b->bs_dev.unmap = blob_bs_dev_unmap;
     276         684 :         b->bs_dev.is_zeroes = blob_bs_is_zeroes;
     277         684 :         b->bs_dev.is_range_valid = blob_bs_is_range_valid;
     278         684 :         b->bs_dev.translate_lba = blob_bs_translate_lba;
     279         684 :         b->bs_dev.is_degraded = blob_bs_is_degraded;
     280         684 :         b->blob = blob;
     281             : 
     282         684 :         return &b->bs_dev;
     283             : }

Generated by: LCOV version 1.15