LCOV - code coverage report
Current view: top level - spdk/lib/blob - blobstore.c (source / functions) Hit Total Coverage
Test: Combined Lines: 4509 5455 82.7 %
Date: 2024-12-15 00:31:35 Functions: 306 326 93.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 10231 22785 44.9 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2017 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  *   Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "spdk/stdinc.h"
       8                 :            : 
       9                 :            : #include "spdk/blob.h"
      10                 :            : #include "spdk/crc32.h"
      11                 :            : #include "spdk/env.h"
      12                 :            : #include "spdk/queue.h"
      13                 :            : #include "spdk/thread.h"
      14                 :            : #include "spdk/bit_array.h"
      15                 :            : #include "spdk/bit_pool.h"
      16                 :            : #include "spdk/likely.h"
      17                 :            : #include "spdk/util.h"
      18                 :            : #include "spdk/string.h"
      19                 :            : 
      20                 :            : #include "spdk_internal/assert.h"
      21                 :            : #include "spdk/log.h"
      22                 :            : 
      23                 :            : #include "blobstore.h"
      24                 :            : 
      25                 :            : #define BLOB_CRC32C_INITIAL    0xffffffffUL
      26                 :            : 
      27                 :            : static int bs_register_md_thread(struct spdk_blob_store *bs);
      28                 :            : static int bs_unregister_md_thread(struct spdk_blob_store *bs);
      29                 :            : static void blob_close_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno);
      30                 :            : static void blob_insert_cluster_on_md_thread(struct spdk_blob *blob, uint32_t cluster_num,
      31                 :            :                 uint64_t cluster, uint32_t extent, struct spdk_blob_md_page *page,
      32                 :            :                 spdk_blob_op_complete cb_fn, void *cb_arg);
      33                 :            : 
      34                 :            : static int blob_set_xattr(struct spdk_blob *blob, const char *name, const void *value,
      35                 :            :                           uint16_t value_len, bool internal);
      36                 :            : static int blob_get_xattr_value(struct spdk_blob *blob, const char *name,
      37                 :            :                                 const void **value, size_t *value_len, bool internal);
      38                 :            : static int blob_remove_xattr(struct spdk_blob *blob, const char *name, bool internal);
      39                 :            : 
      40                 :            : static void blob_write_extent_page(struct spdk_blob *blob, uint32_t extent, uint64_t cluster_num,
      41                 :            :                                    struct spdk_blob_md_page *page, spdk_blob_op_complete cb_fn, void *cb_arg);
      42                 :            : 
      43                 :            : /*
      44                 :            :  * External snapshots require a channel per thread per esnap bdev.  The tree
      45                 :            :  * is populated lazily as blob IOs are handled by the back_bs_dev. When this
      46                 :            :  * channel is destroyed, all the channels in the tree are destroyed.
      47                 :            :  */
      48                 :            : 
      49                 :            : struct blob_esnap_channel {
      50                 :            :         RB_ENTRY(blob_esnap_channel)    node;
      51                 :            :         spdk_blob_id                    blob_id;
      52                 :            :         struct spdk_io_channel          *channel;
      53                 :            : };
      54                 :            : 
      55                 :            : static int blob_esnap_channel_compare(struct blob_esnap_channel *c1, struct blob_esnap_channel *c2);
      56                 :            : static void blob_esnap_destroy_bs_dev_channels(struct spdk_blob *blob, bool abort_io,
      57                 :            :                 spdk_blob_op_with_handle_complete cb_fn, void *cb_arg);
      58                 :            : static void blob_esnap_destroy_bs_channel(struct spdk_bs_channel *ch);
      59   [ +  +  +  +  :      42084 : RB_GENERATE_STATIC(blob_esnap_channel_tree, blob_esnap_channel, node, blob_esnap_channel_compare)
          +  +  +  -  +  
          +  +  -  -  +  
          -  +  -  +  -  
          -  -  -  +  -  
          +  -  -  +  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  -  +  
          +  -  +  -  +  
          -  +  -  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          -  +  #  #  #  
          #  #  #  #  #  
          #  #  #  #  -  
          +  -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  +  +  -  
          +  +  -  +  -  
          +  -  #  #  #  
          #  #  #  +  -  
          +  -  +  -  -  
          +  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  -  
          +  #  #  #  #  
          #  #  +  -  +  
                -  +  - ]
      60                 :            : 
      61                 :            : static inline bool
      62                 :   22617338 : blob_is_esnap_clone(const struct spdk_blob *blob)
      63                 :            : {
      64   [ +  +  #  # ]:   22617338 :         assert(blob != NULL);
      65   [ +  -  +  -  :   22617338 :         return !!(blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT);
                   +  - ]
      66                 :            : }
      67                 :            : 
      68                 :            : static int
      69                 :     114756 : blob_id_cmp(struct spdk_blob *blob1, struct spdk_blob *blob2)
      70                 :            : {
      71   [ +  -  +  - ]:     114756 :         assert(blob1 != NULL && blob2 != NULL);
      72   [ +  +  +  -  :     114756 :         return (blob1->id < blob2->id ? -1 : blob1->id > blob2->id);
          +  -  +  -  +  
          +  +  -  +  -  
             +  -  +  - ]
      73                 :            : }
      74                 :            : 
      75   [ +  +  +  +  :     302333 : RB_GENERATE_STATIC(spdk_blob_tree, spdk_blob, link, blob_id_cmp);
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          -  +  +  +  +  
          +  +  +  +  +  
          +  +  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          +  +  +  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  +  +  +  
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  +  
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  #  #  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  +  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          +  -  +  -  +  
          -  -  +  -  +  
          +  -  +  -  +  
          +  +  +  +  -  
          +  -  +  -  +  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  +  +  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  +  +  
          -  +  -  +  +  
          -  +  -  +  -  
          +  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  +  +  -  +  
          -  +  -  +  +  
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  #  
          #  #  #  #  #  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  #  
          #  #  #  #  #  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  -  + ]
      76                 :            : 
      77                 :            : static void
      78                 :    3517482 : blob_verify_md_op(struct spdk_blob *blob)
      79                 :            : {
      80   [ +  +  #  # ]:    3517482 :         assert(blob != NULL);
      81   [ +  +  +  -  :    3517482 :         assert(spdk_get_thread() == blob->bs->md_thread);
          +  -  +  -  +  
                -  #  # ]
      82   [ +  +  +  -  :    3517482 :         assert(blob->state != SPDK_BLOB_STATE_LOADING);
             +  -  #  # ]
      83                 :    3517482 : }
      84                 :            : 
      85                 :            : static struct spdk_blob_list *
      86                 :      27654 : bs_get_snapshot_entry(struct spdk_blob_store *bs, spdk_blob_id blobid)
      87                 :            : {
      88                 :      27654 :         struct spdk_blob_list *snapshot_entry = NULL;
      89                 :            : 
      90   [ +  +  +  -  :      32267 :         TAILQ_FOREACH(snapshot_entry, &bs->snapshots, link) {
          +  -  +  +  +  
             -  +  -  +  
                      - ]
      91   [ +  +  +  -  :       9027 :                 if (snapshot_entry->id == blobid) {
                   +  + ]
      92                 :       4414 :                         break;
      93                 :            :                 }
      94                 :        720 :         }
      95                 :            : 
      96                 :      31250 :         return snapshot_entry;
      97                 :       3596 : }
      98                 :            : 
      99                 :            : static void
     100                 :      28628 : bs_claim_md_page(struct spdk_blob_store *bs, uint32_t page)
     101                 :            : {
     102   [ +  +  +  -  :      28628 :         assert(spdk_spin_held(&bs->used_lock));
                   #  # ]
     103   [ +  +  +  -  :      28628 :         assert(page < spdk_bit_array_capacity(bs->used_md_pages));
             +  -  #  # ]
     104   [ +  +  +  -  :      28628 :         assert(spdk_bit_array_get(bs->used_md_pages, page) == false);
             +  -  #  # ]
     105                 :            : 
     106   [ +  -  +  - ]:      28628 :         spdk_bit_array_set(bs->used_md_pages, page);
     107                 :      28628 : }
     108                 :            : 
     109                 :            : static void
     110                 :      21179 : bs_release_md_page(struct spdk_blob_store *bs, uint32_t page)
     111                 :            : {
     112   [ +  +  +  -  :      21179 :         assert(spdk_spin_held(&bs->used_lock));
                   #  # ]
     113   [ +  +  +  -  :      21179 :         assert(page < spdk_bit_array_capacity(bs->used_md_pages));
             +  -  #  # ]
     114   [ +  +  +  -  :      21179 :         assert(spdk_bit_array_get(bs->used_md_pages, page) == true);
             +  -  #  # ]
     115                 :            : 
     116   [ +  -  +  - ]:      21179 :         spdk_bit_array_clear(bs->used_md_pages, page);
     117                 :      21179 : }
     118                 :            : 
     119                 :            : static uint32_t
     120                 :    2465713 : bs_claim_cluster(struct spdk_blob_store *bs)
     121                 :            : {
     122                 :       7976 :         uint32_t cluster_num;
     123                 :            : 
     124   [ +  +  +  -  :    2465713 :         assert(spdk_spin_held(&bs->used_lock));
                   #  # ]
     125                 :            : 
     126   [ +  -  +  - ]:    2465713 :         cluster_num = spdk_bit_pool_allocate_bit(bs->used_clusters);
     127         [ +  + ]:    2465713 :         if (cluster_num == UINT32_MAX) {
     128                 :          1 :                 return UINT32_MAX;
     129                 :            :         }
     130                 :            : 
     131   [ +  +  +  +  :    2465712 :         SPDK_DEBUGLOG(blob, "Claiming cluster %u\n", cluster_num);
                   +  - ]
     132         [ +  - ]:    2465712 :         bs->num_free_clusters--;
     133                 :            : 
     134                 :    2465712 :         return cluster_num;
     135                 :       7976 : }
     136                 :            : 
     137                 :            : static void
     138                 :    2303075 : bs_release_cluster(struct spdk_blob_store *bs, uint32_t cluster_num)
     139                 :            : {
     140   [ +  +  +  -  :    2303075 :         assert(spdk_spin_held(&bs->used_lock));
                   #  # ]
     141   [ +  +  +  -  :    2303075 :         assert(cluster_num < spdk_bit_pool_capacity(bs->used_clusters));
             +  -  #  # ]
     142   [ +  +  +  -  :    2303075 :         assert(spdk_bit_pool_is_allocated(bs->used_clusters, cluster_num) == true);
             +  -  #  # ]
     143   [ +  +  +  -  :    2303075 :         assert(bs->num_free_clusters < bs->total_clusters);
          +  -  +  -  +  
                -  #  # ]
     144                 :            : 
     145   [ +  +  +  +  :    2303075 :         SPDK_DEBUGLOG(blob, "Releasing cluster %u\n", cluster_num);
                   +  - ]
     146                 :            : 
     147   [ +  -  +  - ]:    2303075 :         spdk_bit_pool_free_bit(bs->used_clusters, cluster_num);
     148         [ +  - ]:    2303075 :         bs->num_free_clusters++;
     149                 :    2303075 : }
     150                 :            : 
     151                 :            : static int
     152                 :    2465712 : blob_insert_cluster(struct spdk_blob *blob, uint32_t cluster_num, uint64_t cluster)
     153                 :            : {
     154   [ +  -  +  -  :    2465712 :         uint64_t *cluster_lba = &blob->active.clusters[cluster_num];
             +  -  +  - ]
     155                 :            : 
     156                 :    2465712 :         blob_verify_md_op(blob);
     157                 :            : 
     158   [ +  +  +  + ]:    2465712 :         if (*cluster_lba != 0) {
     159                 :         35 :                 return -EEXIST;
     160                 :            :         }
     161                 :            : 
     162   [ +  -  +  -  :    2465677 :         *cluster_lba = bs_cluster_to_lba(blob->bs, cluster);
                   +  - ]
     163                 :    2465677 :         return 0;
     164                 :       7976 : }
     165                 :            : 
     166                 :            : static int
     167                 :    2465713 : bs_allocate_cluster(struct spdk_blob *blob, uint32_t cluster_num,
     168                 :            :                     uint64_t *cluster, uint32_t *lowest_free_md_page, bool update_map)
     169                 :            : {
     170                 :    2465713 :         uint32_t *extent_page = 0;
     171                 :            : 
     172   [ +  +  +  -  :    2465713 :         assert(spdk_spin_held(&blob->bs->used_lock));
          +  -  +  -  #  
                      # ]
     173                 :            : 
     174   [ +  -  +  -  :    2465713 :         *cluster = bs_claim_cluster(blob->bs);
                   +  - ]
     175   [ +  +  -  + ]:    2465713 :         if (*cluster == UINT32_MAX) {
     176                 :            :                 /* No more free clusters. Cannot satisfy the request */
     177                 :          1 :                 return -ENOSPC;
     178                 :            :         }
     179                 :            : 
     180   [ +  +  +  +  :    2465712 :         if (blob->use_extent_table) {
             +  -  +  + ]
     181                 :    2442132 :                 extent_page = bs_cluster_to_extent_page(blob, cluster_num);
     182   [ +  +  +  + ]:    2442132 :                 if (*extent_page == 0) {
     183                 :            :                         /* Extent page shall never occupy md_page so start the search from 1 */
     184   [ +  +  +  + ]:      12308 :                         if (*lowest_free_md_page == 0) {
     185         [ +  - ]:       8158 :                                 *lowest_free_md_page = 1;
     186                 :        712 :                         }
     187                 :            :                         /* No extent_page is allocated for the cluster */
     188   [ +  -  +  -  :      12308 :                         *lowest_free_md_page = spdk_bit_array_find_first_clear(blob->bs->used_md_pages,
          +  -  +  -  +  
                      - ]
     189         [ +  - ]:        714 :                                                *lowest_free_md_page);
     190   [ +  +  +  - ]:      12308 :                         if (*lowest_free_md_page == UINT32_MAX) {
     191                 :            :                                 /* No more free md pages. Cannot satisfy the request */
     192   [ #  #  #  #  :          0 :                                 bs_release_cluster(blob->bs, *cluster);
                   #  # ]
     193                 :          0 :                                 return -ENOSPC;
     194                 :            :                         }
     195   [ +  -  +  -  :      12308 :                         bs_claim_md_page(blob->bs, *lowest_free_md_page);
                   +  - ]
     196                 :        714 :                 }
     197                 :       4046 :         }
     198                 :            : 
     199   [ +  +  +  +  :    2465712 :         SPDK_DEBUGLOG(blob, "Claiming cluster %" PRIu64 " for blob 0x%" PRIx64 "\n", *cluster,
          +  -  #  #  #  
                #  #  # ]
     200                 :            :                       blob->id);
     201                 :            : 
     202   [ +  +  +  + ]:    2465712 :         if (update_map) {
     203         [ +  - ]:    2438424 :                 blob_insert_cluster(blob, cluster_num, *cluster);
     204   [ +  +  +  +  :    2438424 :                 if (blob->use_extent_table && *extent_page == 0) {
          +  +  +  +  +  
                -  +  + ]
     205   [ +  -  +  - ]:      10921 :                         *extent_page = *lowest_free_md_page;
     206                 :        642 :                 }
     207                 :       7364 :         }
     208                 :            : 
     209                 :    2465712 :         return 0;
     210                 :       7976 : }
     211                 :            : 
     212                 :            : static void
     213                 :      38741 : blob_xattrs_init(struct spdk_blob_xattr_opts *xattrs)
     214                 :            : {
     215   [ +  -  +  - ]:      38741 :         xattrs->count = 0;
     216   [ +  -  +  - ]:      38741 :         xattrs->names = NULL;
     217   [ +  -  +  - ]:      38741 :         xattrs->ctx = NULL;
     218   [ +  -  +  - ]:      38741 :         xattrs->get_value = NULL;
     219                 :      38741 : }
     220                 :            : 
     221                 :            : void
     222                 :      24730 : spdk_blob_opts_init(struct spdk_blob_opts *opts, size_t opts_size)
     223                 :            : {
     224         [ +  + ]:      24730 :         if (!opts) {
     225                 :          0 :                 SPDK_ERRLOG("opts should not be NULL\n");
     226                 :          0 :                 return;
     227                 :            :         }
     228                 :            : 
     229         [ +  + ]:      24730 :         if (!opts_size) {
     230                 :          0 :                 SPDK_ERRLOG("opts_size should not be zero value\n");
     231                 :          0 :                 return;
     232                 :            :         }
     233                 :            : 
     234         [ +  + ]:      24730 :         memset(opts, 0, opts_size);
     235   [ +  -  +  - ]:      24730 :         opts->opts_size = opts_size;
     236                 :            : 
     237                 :            : #define FIELD_OK(field) \
     238                 :            :         offsetof(struct spdk_blob_opts, field) + sizeof(opts->field) <= opts_size
     239                 :            : 
     240                 :            : #define SET_FIELD(field, value) \
     241                 :            :         if (FIELD_OK(field)) { \
     242                 :            :                 opts->field = value; \
     243                 :            :         } \
     244                 :            : 
     245   [ +  +  +  -  :      24730 :         SET_FIELD(num_clusters, 0);
                   +  - ]
     246   [ +  +  +  -  :      24730 :         SET_FIELD(thin_provision, false);
                   +  - ]
     247   [ +  +  +  -  :      24730 :         SET_FIELD(clear_method, BLOB_CLEAR_WITH_DEFAULT);
                   +  - ]
     248                 :            : 
     249         [ +  + ]:      24730 :         if (FIELD_OK(xattrs)) {
     250         [ +  - ]:      24730 :                 blob_xattrs_init(&opts->xattrs);
     251                 :       3504 :         }
     252                 :            : 
     253   [ +  +  +  -  :      24730 :         SET_FIELD(use_extent_table, true);
                   +  - ]
     254                 :            : 
     255                 :            : #undef FIELD_OK
     256                 :            : #undef SET_FIELD
     257                 :       3504 : }
     258                 :            : 
     259                 :            : void
     260                 :      40775 : spdk_blob_open_opts_init(struct spdk_blob_open_opts *opts, size_t opts_size)
     261                 :            : {
     262         [ +  + ]:      40775 :         if (!opts) {
     263                 :          0 :                 SPDK_ERRLOG("opts should not be NULL\n");
     264                 :          0 :                 return;
     265                 :            :         }
     266                 :            : 
     267         [ +  + ]:      40775 :         if (!opts_size) {
     268                 :          0 :                 SPDK_ERRLOG("opts_size should not be zero value\n");
     269                 :          0 :                 return;
     270                 :            :         }
     271                 :            : 
     272         [ +  + ]:      40775 :         memset(opts, 0, opts_size);
     273   [ +  -  +  - ]:      40775 :         opts->opts_size = opts_size;
     274                 :            : 
     275                 :            : #define FIELD_OK(field) \
     276                 :            :         offsetof(struct spdk_blob_open_opts, field) + sizeof(opts->field) <= opts_size
     277                 :            : 
     278                 :            : #define SET_FIELD(field, value) \
     279                 :            :         if (FIELD_OK(field)) { \
     280                 :            :                 opts->field = value; \
     281                 :            :         } \
     282                 :            : 
     283   [ +  +  +  -  :      40775 :         SET_FIELD(clear_method, BLOB_CLEAR_WITH_DEFAULT);
                   +  - ]
     284                 :            : 
     285                 :            : #undef FIELD_OK
     286                 :            : #undef SET_FILED
     287                 :       3282 : }
     288                 :            : 
     289                 :            : static struct spdk_blob *
     290                 :      54170 : blob_alloc(struct spdk_blob_store *bs, spdk_blob_id id)
     291                 :            : {
     292                 :       5080 :         struct spdk_blob *blob;
     293                 :            : 
     294                 :      54170 :         blob = calloc(1, sizeof(*blob));
     295         [ +  + ]:      54170 :         if (!blob) {
     296                 :          0 :                 return NULL;
     297                 :            :         }
     298                 :            : 
     299   [ +  -  +  - ]:      54170 :         blob->id = id;
     300   [ +  -  +  - ]:      54170 :         blob->bs = bs;
     301                 :            : 
     302   [ +  -  +  - ]:      54170 :         blob->parent_id = SPDK_BLOBID_INVALID;
     303                 :            : 
     304   [ +  -  +  - ]:      54170 :         blob->state = SPDK_BLOB_STATE_DIRTY;
     305   [ +  -  +  - ]:      54170 :         blob->extent_rle_found = false;
     306   [ +  -  +  - ]:      54170 :         blob->extent_table_found = false;
     307   [ +  -  +  -  :      54170 :         blob->active.num_pages = 1;
                   +  - ]
     308   [ +  -  +  -  :      54170 :         blob->active.pages = calloc(1, sizeof(*blob->active.pages));
                   +  - ]
     309   [ +  +  +  -  :      54170 :         if (!blob->active.pages) {
             +  -  +  - ]
     310                 :          0 :                 free(blob);
     311                 :          0 :                 return NULL;
     312                 :            :         }
     313                 :            : 
     314   [ +  -  +  -  :      54170 :         blob->active.pages[0] = bs_blobid_to_page(id);
          +  -  +  -  +  
                      - ]
     315                 :            : 
     316   [ +  -  +  -  :      54170 :         TAILQ_INIT(&blob->xattrs);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     317   [ +  -  +  -  :      54170 :         TAILQ_INIT(&blob->xattrs_internal);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     318   [ +  -  +  -  :      54170 :         TAILQ_INIT(&blob->pending_persists);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     319   [ +  -  +  -  :      54170 :         TAILQ_INIT(&blob->persists_to_complete);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     320                 :            : 
     321                 :      54170 :         return blob;
     322                 :       5080 : }
     323                 :            : 
     324                 :            : static void
     325                 :     108340 : xattrs_free(struct spdk_xattr_tailq *xattrs)
     326                 :            : {
     327                 :      10160 :         struct spdk_xattr       *xattr, *xattr_tmp;
     328                 :            : 
     329   [ +  +  +  -  :     160191 :         TAILQ_FOREACH_SAFE(xattr, xattrs, link, xattr_tmp) {
          +  +  +  -  +  
             -  +  -  +  
                      + ]
     330   [ +  +  +  -  :      51851 :                 TAILQ_REMOVE(xattrs, xattr, link);
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     331   [ +  -  +  - ]:      51851 :                 free(xattr->name);
     332   [ +  -  +  - ]:      51851 :                 free(xattr->value);
     333                 :      51851 :                 free(xattr);
     334                 :       1602 :         }
     335                 :     108340 : }
     336                 :            : 
     337                 :            : static void
     338                 :      54170 : blob_free(struct spdk_blob *blob)
     339                 :            : {
     340   [ +  +  #  # ]:      54170 :         assert(blob != NULL);
     341   [ +  +  +  -  :      54170 :         assert(TAILQ_EMPTY(&blob->pending_persists));
          +  -  +  -  #  
                      # ]
     342   [ +  +  +  -  :      54170 :         assert(TAILQ_EMPTY(&blob->persists_to_complete));
          +  -  +  -  #  
                      # ]
     343                 :            : 
     344   [ +  -  +  -  :      54170 :         free(blob->active.extent_pages);
                   +  - ]
     345   [ +  -  +  -  :      54170 :         free(blob->clean.extent_pages);
                   +  - ]
     346   [ +  -  +  -  :      54170 :         free(blob->active.clusters);
                   +  - ]
     347   [ +  -  +  -  :      54170 :         free(blob->clean.clusters);
                   +  - ]
     348   [ +  -  +  -  :      54170 :         free(blob->active.pages);
                   +  - ]
     349   [ +  -  +  -  :      54170 :         free(blob->clean.pages);
                   +  - ]
     350                 :            : 
     351         [ +  - ]:      54170 :         xattrs_free(&blob->xattrs);
     352         [ +  - ]:      54170 :         xattrs_free(&blob->xattrs_internal);
     353                 :            : 
     354   [ +  +  +  -  :      54170 :         if (blob->back_bs_dev) {
                   +  + ]
     355   [ +  -  +  -  :       6011 :                 blob->back_bs_dev->destroy(blob->back_bs_dev);
          +  -  +  -  -  
          +  +  -  +  -  
                   +  - ]
     356                 :        944 :         }
     357                 :            : 
     358                 :      54170 :         free(blob);
     359                 :      54170 : }
     360                 :            : 
     361                 :            : static void
     362                 :       1771 : blob_back_bs_destroy_esnap_done(void *ctx, struct spdk_blob *blob, int bserrno)
     363                 :            : {
     364                 :       1771 :         struct spdk_bs_dev      *bs_dev = ctx;
     365                 :            : 
     366         [ +  + ]:       1771 :         if (bserrno != 0) {
     367                 :            :                 /*
     368                 :            :                  * This is probably due to a memory allocation failure when creating the
     369                 :            :                  * blob_esnap_destroy_ctx before iterating threads.
     370                 :            :                  */
     371   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 ": Unable to destroy bs dev channels: error %d\n",
     372                 :            :                             blob->id, bserrno);
     373         [ #  # ]:          0 :                 assert(false);
     374                 :            :         }
     375                 :            : 
     376         [ +  + ]:       1771 :         if (bs_dev == NULL) {
     377                 :            :                 /*
     378                 :            :                  * This check exists to make scanbuild happy.
     379                 :            :                  *
     380                 :            :                  * blob->back_bs_dev for an esnap is NULL during the first iteration of blobs while
     381                 :            :                  * the blobstore is being loaded. It could also be NULL if there was an error
     382                 :            :                  * opening the esnap device. In each of these cases, no channels could have been
     383                 :            :                  * created because back_bs_dev->create_channel() would have led to a NULL pointer
     384                 :            :                  * deref.
     385                 :            :                  */
     386         [ #  # ]:          0 :                 assert(false);
     387                 :            :                 return;
     388                 :            :         }
     389                 :            : 
     390   [ +  +  +  +  :       1771 :         SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": calling destroy on back_bs_dev\n", blob->id);
          +  -  #  #  #  
                      # ]
     391   [ +  -  +  -  :       1771 :         bs_dev->destroy(bs_dev);
             -  +  +  - ]
     392                 :        288 : }
     393                 :            : 
     394                 :            : static void
     395                 :       1771 : blob_back_bs_destroy(struct spdk_blob *blob)
     396                 :            : {
     397   [ +  +  +  +  :       1771 :         SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": preparing to destroy back_bs_dev\n",
          +  -  #  #  #  
                      # ]
     398                 :            :                       blob->id);
     399                 :            : 
     400                 :       2059 :         blob_esnap_destroy_bs_dev_channels(blob, false, blob_back_bs_destroy_esnap_done,
     401   [ +  -  +  - ]:       1771 :                                            blob->back_bs_dev);
     402   [ +  -  +  - ]:       1771 :         blob->back_bs_dev = NULL;
     403                 :       1771 : }
     404                 :            : 
     405                 :            : struct freeze_io_ctx {
     406                 :            :         struct spdk_bs_cpl cpl;
     407                 :            :         struct spdk_blob *blob;
     408                 :            : };
     409                 :            : 
     410                 :            : static void
     411                 :     117048 : blob_io_sync(struct spdk_io_channel_iter *i)
     412                 :            : {
     413                 :     117048 :         spdk_for_each_channel_continue(i, 0);
     414                 :     117048 : }
     415                 :            : 
     416                 :            : static void
     417                 :     116976 : blob_execute_queued_io(struct spdk_io_channel_iter *i)
     418                 :            : {
     419                 :     116976 :         struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
     420                 :     116976 :         struct spdk_bs_channel *ch = spdk_io_channel_get_ctx(_ch);
     421                 :     116976 :         struct freeze_io_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
     422                 :        446 :         struct spdk_bs_request_set      *set;
     423                 :        446 :         struct spdk_bs_user_op_args     *args;
     424                 :        446 :         spdk_bs_user_op_t *op, *tmp;
     425                 :            : 
     426   [ +  +  +  -  :     118272 :         TAILQ_FOREACH_SAFE(op, &ch->queued_io, link, tmp) {
          +  -  +  +  +  
          -  +  -  +  -  
                   +  + ]
     427                 :       1296 :                 set = (struct spdk_bs_request_set *)op;
     428   [ +  -  +  - ]:       1296 :                 args = &set->u.user_op;
     429                 :            : 
     430   [ +  +  +  -  :       1296 :                 if (args->blob == ctx->blob) {
          +  -  +  -  -  
                      + ]
     431   [ +  +  +  -  :       1291 :                         TAILQ_REMOVE(&ch->queued_io, op, link);
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
     432                 :       1291 :                         bs_user_op_execute(op);
     433                 :          4 :                 }
     434                 :          4 :         }
     435                 :            : 
     436                 :     116976 :         spdk_for_each_channel_continue(i, 0);
     437                 :     116976 : }
     438                 :            : 
     439                 :            : static void
     440                 :     233784 : blob_io_cpl(struct spdk_io_channel_iter *i, int status)
     441                 :            : {
     442                 :     233784 :         struct freeze_io_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
     443                 :            : 
     444   [ +  -  +  -  :     233784 :         ctx->cpl.u.blob_basic.cb_fn(ctx->cpl.u.blob_basic.cb_arg, 0);
          +  -  +  -  +  
          -  -  +  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     445                 :            : 
     446                 :     233784 :         free(ctx);
     447                 :     233784 : }
     448                 :            : 
     449                 :            : static void
     450                 :     116928 : blob_freeze_io(struct spdk_blob *blob, spdk_blob_op_complete cb_fn, void *cb_arg)
     451                 :            : {
     452                 :        442 :         struct freeze_io_ctx *ctx;
     453                 :            : 
     454                 :     116928 :         blob_verify_md_op(blob);
     455                 :            : 
     456                 :     116928 :         ctx = calloc(1, sizeof(*ctx));
     457         [ +  + ]:     116928 :         if (!ctx) {
     458   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
     459                 :          0 :                 return;
     460                 :            :         }
     461                 :            : 
     462   [ +  -  +  -  :     116928 :         ctx->cpl.type = SPDK_BS_CPL_TYPE_BS_BASIC;
                   +  - ]
     463   [ +  -  +  -  :     116928 :         ctx->cpl.u.blob_basic.cb_fn = cb_fn;
          +  -  +  -  +  
                      - ]
     464   [ +  -  +  -  :     116928 :         ctx->cpl.u.blob_basic.cb_arg = cb_arg;
          +  -  +  -  +  
                      - ]
     465   [ +  -  +  - ]:     116928 :         ctx->blob = blob;
     466                 :            : 
     467                 :            :         /* Freeze I/O on blob */
     468         [ +  - ]:     116928 :         blob->frozen_refcnt++;
     469                 :            : 
     470   [ +  -  +  - ]:     116928 :         spdk_for_each_channel(blob->bs, blob_io_sync, ctx, blob_io_cpl);
     471         [ -  + ]:        442 : }
     472                 :            : 
     473                 :            : static void
     474                 :     116856 : blob_unfreeze_io(struct spdk_blob *blob, spdk_blob_op_complete cb_fn, void *cb_arg)
     475                 :            : {
     476                 :        430 :         struct freeze_io_ctx *ctx;
     477                 :            : 
     478                 :     116856 :         blob_verify_md_op(blob);
     479                 :            : 
     480                 :     116856 :         ctx = calloc(1, sizeof(*ctx));
     481         [ +  + ]:     116856 :         if (!ctx) {
     482   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
     483                 :          0 :                 return;
     484                 :            :         }
     485                 :            : 
     486   [ +  -  +  -  :     116856 :         ctx->cpl.type = SPDK_BS_CPL_TYPE_BS_BASIC;
                   +  - ]
     487   [ +  -  +  -  :     116856 :         ctx->cpl.u.blob_basic.cb_fn = cb_fn;
          +  -  +  -  +  
                      - ]
     488   [ +  -  +  -  :     116856 :         ctx->cpl.u.blob_basic.cb_arg = cb_arg;
          +  -  +  -  +  
                      - ]
     489   [ +  -  +  - ]:     116856 :         ctx->blob = blob;
     490                 :            : 
     491   [ +  +  +  -  :     116856 :         assert(blob->frozen_refcnt > 0);
             +  -  #  # ]
     492                 :            : 
     493         [ +  - ]:     116856 :         blob->frozen_refcnt--;
     494                 :            : 
     495   [ +  -  +  - ]:     116856 :         spdk_for_each_channel(blob->bs, blob_execute_queued_io, ctx, blob_io_cpl);
     496         [ -  + ]:        430 : }
     497                 :            : 
     498                 :            : static int
     499                 :     224555 : blob_mark_clean(struct spdk_blob *blob)
     500                 :            : {
     501                 :     224555 :         uint32_t *extent_pages = NULL;
     502                 :     224555 :         uint64_t *clusters = NULL;
     503                 :     224555 :         uint32_t *pages = NULL;
     504                 :            : 
     505   [ +  +  #  # ]:     224555 :         assert(blob != NULL);
     506                 :            : 
     507   [ +  +  +  -  :     224555 :         if (blob->active.num_extent_pages) {
             +  -  +  + ]
     508   [ +  +  +  -  :     186575 :                 assert(blob->active.extent_pages);
          +  -  +  -  #  
                      # ]
     509   [ +  -  +  -  :     186575 :                 extent_pages = calloc(blob->active.num_extent_pages, sizeof(*blob->active.extent_pages));
                   +  - ]
     510         [ +  + ]:     186575 :                 if (!extent_pages) {
     511                 :          0 :                         return -ENOMEM;
     512                 :            :                 }
     513   [ +  +  +  +  :     189306 :                 memcpy(extent_pages, blob->active.extent_pages,
          +  -  +  -  +  
                      - ]
     514   [ +  -  +  -  :     186575 :                        blob->active.num_extent_pages * sizeof(*extent_pages));
                   +  - ]
     515                 :       2731 :         }
     516                 :            : 
     517   [ +  +  +  -  :     224555 :         if (blob->active.num_clusters) {
             +  -  +  + ]
     518   [ +  +  +  -  :     203633 :                 assert(blob->active.clusters);
          +  -  +  -  #  
                      # ]
     519   [ +  -  +  -  :     203633 :                 clusters = calloc(blob->active.num_clusters, sizeof(*blob->active.clusters));
                   +  - ]
     520         [ +  + ]:     203633 :                 if (!clusters) {
     521                 :          0 :                         free(extent_pages);
     522                 :          0 :                         return -ENOMEM;
     523                 :            :                 }
     524   [ +  +  +  +  :     203633 :                 memcpy(clusters, blob->active.clusters, blob->active.num_clusters * sizeof(*blob->active.clusters));
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     525                 :       5574 :         }
     526                 :            : 
     527   [ +  +  +  -  :     224555 :         if (blob->active.num_pages) {
             +  -  +  + ]
     528   [ +  +  +  -  :     214590 :                 assert(blob->active.pages);
          +  -  +  -  #  
                      # ]
     529   [ +  -  +  -  :     214590 :                 pages = calloc(blob->active.num_pages, sizeof(*blob->active.pages));
                   +  - ]
     530         [ +  + ]:     214590 :                 if (!pages) {
     531                 :          0 :                         free(extent_pages);
     532                 :          0 :                         free(clusters);
     533                 :          0 :                         return -ENOMEM;
     534                 :            :                 }
     535   [ +  +  +  +  :     214590 :                 memcpy(pages, blob->active.pages, blob->active.num_pages * sizeof(*blob->active.pages));
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     536                 :       6422 :         }
     537                 :            : 
     538   [ +  -  +  -  :     224555 :         free(blob->clean.extent_pages);
                   +  - ]
     539   [ +  -  +  -  :     224555 :         free(blob->clean.clusters);
                   +  - ]
     540   [ +  -  +  -  :     224555 :         free(blob->clean.pages);
                   +  - ]
     541                 :            : 
     542   [ +  -  +  -  :     224555 :         blob->clean.num_extent_pages = blob->active.num_extent_pages;
          +  -  +  -  +  
                -  +  - ]
     543   [ +  -  +  -  :     224555 :         blob->clean.extent_pages = blob->active.extent_pages;
          +  -  +  -  +  
                -  +  - ]
     544   [ +  -  +  -  :     224555 :         blob->clean.num_clusters = blob->active.num_clusters;
          +  -  +  -  +  
                -  +  - ]
     545   [ +  -  +  -  :     224555 :         blob->clean.clusters = blob->active.clusters;
          +  -  +  -  +  
                -  +  - ]
     546   [ +  -  +  -  :     224555 :         blob->clean.num_pages = blob->active.num_pages;
          +  -  +  -  +  
                -  +  - ]
     547   [ +  -  +  -  :     224555 :         blob->clean.pages = blob->active.pages;
          +  -  +  -  +  
                -  +  - ]
     548                 :            : 
     549   [ +  -  +  -  :     224555 :         blob->active.extent_pages = extent_pages;
                   +  - ]
     550   [ +  -  +  -  :     224555 :         blob->active.clusters = clusters;
                   +  - ]
     551   [ +  -  +  -  :     224555 :         blob->active.pages = pages;
                   +  - ]
     552                 :            : 
     553                 :            :         /* If the metadata was dirtied again while the metadata was being written to disk,
     554                 :            :          *  we do not want to revert the DIRTY state back to CLEAN here.
     555                 :            :          */
     556   [ +  +  +  -  :     224555 :         if (blob->state == SPDK_BLOB_STATE_LOADING) {
                   +  + ]
     557   [ +  -  +  - ]:      39775 :                 blob->state = SPDK_BLOB_STATE_CLEAN;
     558                 :       3214 :         }
     559                 :            : 
     560                 :     224555 :         return 0;
     561                 :       7838 : }
     562                 :            : 
     563                 :            : static int
     564                 :      42844 : blob_deserialize_xattr(struct spdk_blob *blob,
     565                 :            :                        struct spdk_blob_md_descriptor_xattr *desc_xattr, bool internal)
     566                 :            : {
     567                 :       1176 :         struct spdk_xattr                       *xattr;
     568                 :            : 
     569   [ +  -  +  -  :      44020 :         if (desc_xattr->length != sizeof(desc_xattr->name_length) +
                   -  + ]
     570                 :       1176 :             sizeof(desc_xattr->value_length) +
     571   [ +  +  +  -  :      42844 :             desc_xattr->name_length + desc_xattr->value_length) {
          +  -  +  -  +  
                      - ]
     572                 :          0 :                 return -EINVAL;
     573                 :            :         }
     574                 :            : 
     575                 :      42844 :         xattr = calloc(1, sizeof(*xattr));
     576         [ +  + ]:      42844 :         if (xattr == NULL) {
     577                 :          0 :                 return -ENOMEM;
     578                 :            :         }
     579                 :            : 
     580   [ +  -  +  -  :      42844 :         xattr->name = malloc(desc_xattr->name_length + 1);
          +  -  +  -  +  
                      - ]
     581   [ +  +  +  -  :      42844 :         if (xattr->name == NULL) {
                   +  - ]
     582                 :          0 :                 free(xattr);
     583                 :          0 :                 return -ENOMEM;
     584                 :            :         }
     585                 :            : 
     586   [ +  -  +  -  :      42844 :         xattr->value = malloc(desc_xattr->value_length);
             +  -  +  - ]
     587   [ +  +  +  -  :      42844 :         if (xattr->value == NULL) {
                   +  - ]
     588   [ #  #  #  # ]:          0 :                 free(xattr->name);
     589                 :          0 :                 free(xattr);
     590                 :          0 :                 return -ENOMEM;
     591                 :            :         }
     592                 :            : 
     593   [ +  +  +  +  :      42844 :         memcpy(xattr->name, desc_xattr->name, desc_xattr->name_length);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     594   [ +  -  +  -  :      42844 :         xattr->name[desc_xattr->name_length] = '\0';
          +  -  +  -  +  
                -  +  - ]
     595   [ +  -  +  -  :      42844 :         xattr->value_len = desc_xattr->value_length;
             +  -  +  - ]
     596   [ +  +  +  +  :      44020 :         memcpy(xattr->value,
             +  -  +  - ]
     597   [ +  -  +  -  :      42844 :                (void *)((uintptr_t)desc_xattr->name + desc_xattr->name_length),
                   +  - ]
     598   [ +  -  +  - ]:      42844 :                desc_xattr->value_length);
     599                 :            : 
     600   [ +  +  +  +  :      42844 :         TAILQ_INSERT_TAIL(internal ? &blob->xattrs_internal : &blob->xattrs, xattr, link);
          +  +  +  -  +  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  +  +  -  +  
             -  +  -  +  
                      - ]
     601                 :            : 
     602                 :      42844 :         return 0;
     603                 :       1176 : }
     604                 :            : 
     605                 :            : 
     606                 :            : static int
     607                 :      73249 : blob_parse_page(const struct spdk_blob_md_page *page, struct spdk_blob *blob)
     608                 :            : {
     609                 :       4372 :         struct spdk_blob_md_descriptor *desc;
     610                 :      73249 :         size_t  cur_desc = 0;
     611                 :       4372 :         void *tmp;
     612                 :            : 
     613         [ +  - ]:      73249 :         desc = (struct spdk_blob_md_descriptor *)page->descriptors;
     614         [ +  - ]:     227057 :         while (cur_desc < sizeof(page->descriptors)) {
     615   [ +  +  +  -  :     227057 :                 if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_PADDING) {
                   +  + ]
     616   [ +  +  -  +  :      72969 :                         if (desc->length == 0) {
                   -  + ]
     617                 :            :                                 /* If padding and length are 0, this terminates the page */
     618                 :      72969 :                                 break;
     619                 :            :                         }
     620   [ +  +  +  -  :     154088 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_FLAGS) {
                   +  + ]
     621                 :       3246 :                         struct spdk_blob_md_descriptor_flags    *desc_flags;
     622                 :            : 
     623                 :      39967 :                         desc_flags = (struct spdk_blob_md_descriptor_flags *)desc;
     624                 :            : 
     625   [ +  +  +  -  :      39967 :                         if (desc_flags->length != sizeof(*desc_flags) - sizeof(*desc)) {
                   -  + ]
     626                 :          0 :                                 return -EINVAL;
     627                 :            :                         }
     628                 :            : 
     629   [ +  +  +  -  :      43213 :                         if ((desc_flags->invalid_flags | SPDK_BLOB_INVALID_FLAGS_MASK) !=
          +  -  +  -  +  
             -  +  -  +  
                      + ]
     630   [ +  -  +  -  :       3246 :                             SPDK_BLOB_INVALID_FLAGS_MASK) {
             +  -  +  - ]
     631                 :         48 :                                 return -EINVAL;
     632                 :            :                         }
     633                 :            : 
     634   [ +  +  -  +  :      39919 :                         if ((desc_flags->data_ro_flags | SPDK_BLOB_DATA_RO_FLAGS_MASK) !=
             -  +  +  + ]
     635         [ -  + ]:       3238 :                             SPDK_BLOB_DATA_RO_FLAGS_MASK) {
     636   [ -  +  -  + ]:         72 :                                 blob->data_ro = true;
     637   [ -  +  -  + ]:         72 :                                 blob->md_ro = true;
     638                 :         12 :                         }
     639                 :            : 
     640   [ +  +  -  +  :      39919 :                         if ((desc_flags->md_ro_flags | SPDK_BLOB_MD_RO_FLAGS_MASK) !=
             -  +  +  + ]
     641         [ -  + ]:       3238 :                             SPDK_BLOB_MD_RO_FLAGS_MASK) {
     642   [ -  +  -  + ]:         72 :                                 blob->md_ro = true;
     643                 :         12 :                         }
     644                 :            : 
     645   [ +  +  -  +  :      39919 :                         if ((desc_flags->data_ro_flags & SPDK_BLOB_READ_ONLY)) {
             -  +  +  + ]
     646   [ -  +  -  + ]:       3191 :                                 blob->data_ro = true;
     647   [ -  +  -  + ]:       3191 :                                 blob->md_ro = true;
     648                 :        514 :                         }
     649                 :            : 
     650   [ -  +  -  +  :      39919 :                         blob->invalid_flags = desc_flags->invalid_flags;
             -  +  -  + ]
     651   [ -  +  -  +  :      39919 :                         blob->data_ro_flags = desc_flags->data_ro_flags;
             -  +  -  + ]
     652   [ -  +  -  +  :      39919 :                         blob->md_ro_flags = desc_flags->md_ro_flags;
             -  +  -  + ]
     653                 :            : 
     654   [ +  +  +  -  :     117367 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_RLE) {
                   +  + ]
     655                 :       1346 :                         struct spdk_blob_md_descriptor_extent_rle       *desc_extent_rle;
     656                 :       1346 :                         unsigned int                            i, j;
     657   [ +  -  +  -  :       8076 :                         unsigned int                            cluster_count = blob->active.num_clusters;
                   +  - ]
     658                 :            : 
     659   [ +  +  +  +  :       8076 :                         if (blob->extent_table_found) {
             +  -  -  + ]
     660                 :            :                                 /* Extent Table already present in the md,
     661                 :            :                                  * both descriptors should never be at the same time. */
     662                 :          0 :                                 return -EINVAL;
     663                 :            :                         }
     664   [ -  +  -  + ]:       8076 :                         blob->extent_rle_found = true;
     665                 :            : 
     666                 :       8076 :                         desc_extent_rle = (struct spdk_blob_md_descriptor_extent_rle *)desc;
     667                 :            : 
     668   [ +  +  -  +  :       9422 :                         if (desc_extent_rle->length == 0 ||
             +  -  -  + ]
     669   [ -  +  -  +  :       8076 :                             (desc_extent_rle->length % sizeof(desc_extent_rle->extents[0]) != 0)) {
                   -  + ]
     670                 :          0 :                                 return -EINVAL;
     671                 :            :                         }
     672                 :            : 
     673   [ +  +  +  -  :      17124 :                         for (i = 0; i < desc_extent_rle->length / sizeof(desc_extent_rle->extents[0]); i++) {
             +  -  +  + ]
     674   [ +  +  +  -  :     112616 :                                 for (j = 0; j < desc_extent_rle->extents[i].length; j++) {
          +  -  +  -  +  
                      + ]
     675   [ +  +  +  -  :     103568 :                                         if (desc_extent_rle->extents[i].cluster_idx != 0) {
             +  -  +  - ]
     676   [ -  +  -  +  :      46466 :                                                 if (!spdk_bit_pool_is_allocated(blob->bs->used_clusters,
          -  +  -  +  +  
                      - ]
     677   [ -  +  -  +  :      39828 :                                                                                 desc_extent_rle->extents[i].cluster_idx + j)) {
             -  +  -  + ]
     678                 :          0 :                                                         return -EINVAL;
     679                 :            :                                                 }
     680                 :       6638 :                                         }
     681                 :     103568 :                                         cluster_count++;
     682                 :       6638 :                                 }
     683                 :       1508 :                         }
     684                 :            : 
     685         [ -  + ]:       8076 :                         if (cluster_count == 0) {
     686                 :          0 :                                 return -EINVAL;
     687                 :            :                         }
     688   [ -  +  -  +  :       8076 :                         tmp = realloc(blob->active.clusters, cluster_count * sizeof(*blob->active.clusters));
                   -  + ]
     689         [ -  + ]:       8076 :                         if (tmp == NULL) {
     690                 :          0 :                                 return -ENOMEM;
     691                 :            :                         }
     692   [ +  -  +  -  :       8076 :                         blob->active.clusters = tmp;
                   +  - ]
     693   [ +  -  +  -  :       8076 :                         blob->active.cluster_array_size = cluster_count;
                   +  - ]
     694                 :            : 
     695   [ +  +  +  -  :      17124 :                         for (i = 0; i < desc_extent_rle->length / sizeof(desc_extent_rle->extents[0]); i++) {
             +  -  +  + ]
     696   [ +  +  +  -  :     125364 :                                 for (j = 0; j < desc_extent_rle->extents[i].length; j++) {
          +  -  +  -  +  
                      + ]
     697   [ +  +  +  -  :     116316 :                                         if (desc_extent_rle->extents[i].cluster_idx != 0) {
          +  -  +  -  +  
                      + ]
     698   [ +  -  +  -  :      46466 :                                                 blob->active.clusters[blob->active.num_clusters++] = bs_cluster_to_lba(blob->bs,
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     699   [ +  -  +  -  :      39828 :                                                                 desc_extent_rle->extents[i].cluster_idx + j);
             +  -  +  - ]
     700         [ +  - ]:      83126 :                                         } else if (spdk_blob_is_thin_provisioned(blob)) {
     701   [ +  -  +  -  :      76488 :                                                 blob->active.clusters[blob->active.num_clusters++] = 0;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     702                 :      12748 :                                         } else {
     703                 :          0 :                                                 return -EINVAL;
     704                 :            :                                         }
     705                 :      19386 :                                 }
     706                 :       1508 :                         }
     707   [ +  +  +  -  :     107391 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_TABLE) {
                   +  + ]
     708                 :       1670 :                         struct spdk_blob_md_descriptor_extent_table *desc_extent_table;
     709   [ -  +  -  +  :      30516 :                         uint32_t num_extent_pages = blob->active.num_extent_pages;
                   -  + ]
     710                 :       1670 :                         uint32_t i, j;
     711                 :       1670 :                         size_t extent_pages_length;
     712                 :            : 
     713                 :      30516 :                         desc_extent_table = (struct spdk_blob_md_descriptor_extent_table *)desc;
     714   [ -  +  -  + ]:      30516 :                         extent_pages_length = desc_extent_table->length - sizeof(desc_extent_table->num_clusters);
     715                 :            : 
     716   [ -  +  -  +  :      30516 :                         if (blob->extent_rle_found) {
             -  +  -  + ]
     717                 :            :                                 /* This means that Extent RLE is present in MD,
     718                 :            :                                  * both should never be at the same time. */
     719                 :          0 :                                 return -EINVAL;
     720   [ -  +  +  +  :      30516 :                         } else if (blob->extent_table_found &&
          -  +  -  +  #  
                      # ]
     721   [ -  +  #  #  :          5 :                                    desc_extent_table->num_clusters != blob->remaining_clusters_in_et) {
             #  #  #  # ]
     722                 :            :                                 /* Number of clusters in this ET does not match number
     723                 :            :                                  * from previously read EXTENT_TABLE. */
     724                 :          0 :                                 return -EINVAL;
     725                 :            :                         }
     726                 :            : 
     727   [ +  +  -  +  :      32186 :                         if (desc_extent_table->length == 0 ||
             +  -  -  + ]
     728         [ -  + ]:      30516 :                             (extent_pages_length % sizeof(desc_extent_table->extent_page[0]) != 0)) {
     729                 :          0 :                                 return -EINVAL;
     730                 :            :                         }
     731                 :            : 
     732   [ +  -  +  - ]:      30516 :                         blob->extent_table_found = true;
     733                 :            : 
     734   [ +  +  +  + ]:      65918 :                         for (i = 0; i < extent_pages_length / sizeof(desc_extent_table->extent_page[0]); i++) {
     735   [ +  -  +  -  :      35402 :                                 num_extent_pages += desc_extent_table->extent_page[i].num_pages;
             +  -  +  - ]
     736                 :       1428 :                         }
     737                 :            : 
     738         [ +  + ]:      30516 :                         if (num_extent_pages > 0) {
     739   [ -  +  -  +  :      25971 :                                 tmp = realloc(blob->active.extent_pages, num_extent_pages * sizeof(uint32_t));
                   -  + ]
     740         [ -  + ]:      25971 :                                 if (tmp == NULL) {
     741                 :          0 :                                         return -ENOMEM;
     742                 :            :                                 }
     743   [ -  +  -  +  :      25971 :                                 blob->active.extent_pages = tmp;
                   -  + ]
     744                 :       1412 :                         }
     745   [ +  -  +  -  :      30516 :                         blob->active.extent_pages_array_size = num_extent_pages;
                   +  - ]
     746                 :            : 
     747   [ +  -  +  -  :      30516 :                         blob->remaining_clusters_in_et = desc_extent_table->num_clusters;
             +  -  +  - ]
     748                 :            : 
     749                 :            :                         /* Extent table entries contain md page numbers for extent pages.
     750                 :            :                          * Zeroes represent unallocated extent pages, those are run-length-encoded.
     751                 :            :                          */
     752   [ +  +  +  + ]:      65918 :                         for (i = 0; i < extent_pages_length / sizeof(desc_extent_table->extent_page[0]); i++) {
     753   [ +  +  +  -  :      35402 :                                 if (desc_extent_table->extent_page[i].page_idx != 0) {
          +  -  +  -  +  
                      + ]
     754   [ +  +  +  -  :      32721 :                                         assert(desc_extent_table->extent_page[i].num_pages == 1);
          +  -  +  -  +  
                -  #  # ]
     755   [ -  +  -  +  :      63343 :                                         blob->active.extent_pages[blob->active.num_extent_pages++] =
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     756   [ -  +  -  +  :      32721 :                                                 desc_extent_table->extent_page[i].page_idx;
             -  +  -  + ]
     757         [ +  - ]:       3721 :                                 } else if (spdk_blob_is_thin_provisioned(blob)) {
     758   [ +  +  +  -  :       9590 :                                         for (j = 0; j < desc_extent_table->extent_page[i].num_pages; j++) {
          +  -  +  -  +  
                      + ]
     759   [ -  +  -  +  :       6909 :                                                 blob->active.extent_pages[blob->active.num_extent_pages++] = 0;
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     760                 :        388 :                                         }
     761                 :        388 :                                 } else {
     762                 :          0 :                                         return -EINVAL;
     763                 :            :                                 }
     764                 :       1428 :                         }
     765   [ +  +  +  -  :      77199 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_PAGE) {
                   +  + ]
     766                 :       1034 :                         struct spdk_blob_md_descriptor_extent_page      *desc_extent;
     767                 :       1034 :                         unsigned int                                    i;
     768                 :      32685 :                         unsigned int                                    cluster_count = 0;
     769                 :       1034 :                         size_t                                          cluster_idx_length;
     770                 :            : 
     771   [ -  +  -  +  :      32685 :                         if (blob->extent_rle_found) {
             -  +  -  + ]
     772                 :            :                                 /* This means that Extent RLE is present in MD,
     773                 :            :                                  * both should never be at the same time. */
     774                 :          0 :                                 return -EINVAL;
     775                 :            :                         }
     776                 :            : 
     777                 :      32685 :                         desc_extent = (struct spdk_blob_md_descriptor_extent_page *)desc;
     778   [ -  +  -  + ]:      32685 :                         cluster_idx_length = desc_extent->length - sizeof(desc_extent->start_cluster_idx);
     779                 :            : 
     780   [ +  +  -  +  :      33719 :                         if (desc_extent->length <= sizeof(desc_extent->start_cluster_idx) ||
             +  -  -  + ]
     781         [ +  + ]:      32685 :                             (cluster_idx_length % sizeof(desc_extent->cluster_idx[0]) != 0)) {
     782                 :          0 :                                 return -EINVAL;
     783                 :            :                         }
     784                 :            : 
     785   [ +  +  +  + ]:    6227630 :                         for (i = 0; i < cluster_idx_length / sizeof(desc_extent->cluster_idx[0]); i++) {
     786   [ +  +  +  -  :    6194945 :                                 if (desc_extent->cluster_idx[i] != 0) {
             +  -  +  + ]
     787   [ +  +  +  -  :    5657454 :                                         if (!spdk_bit_pool_is_allocated(blob->bs->used_clusters, desc_extent->cluster_idx[i])) {
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     788                 :          0 :                                                 return -EINVAL;
     789                 :            :                                         }
     790                 :       6908 :                                 }
     791                 :    6194945 :                                 cluster_count++;
     792                 :      15232 :                         }
     793                 :            : 
     794         [ -  + ]:      32685 :                         if (cluster_count == 0) {
     795                 :          0 :                                 return -EINVAL;
     796                 :            :                         }
     797                 :            : 
     798                 :            :                         /* When reading extent pages sequentially starting cluster idx should match
     799                 :            :                          * current size of a blob.
     800                 :            :                          * If changed to batch reading, this check shall be removed. */
     801   [ -  +  -  +  :      32685 :                         if (desc_extent->start_cluster_idx != blob->active.num_clusters) {
          -  +  -  +  -  
                +  -  + ]
     802                 :          0 :                                 return -EINVAL;
     803                 :            :                         }
     804                 :            : 
     805   [ +  -  +  -  :      33719 :                         tmp = realloc(blob->active.clusters,
                   +  - ]
     806   [ +  -  +  -  :      32685 :                                       (cluster_count + blob->active.num_clusters) * sizeof(*blob->active.clusters));
                   +  - ]
     807         [ -  + ]:      32685 :                         if (tmp == NULL) {
     808                 :          0 :                                 return -ENOMEM;
     809                 :            :                         }
     810   [ -  +  -  +  :      32685 :                         blob->active.clusters = tmp;
                   -  + ]
     811   [ -  +  -  +  :      32685 :                         blob->active.cluster_array_size = (cluster_count + blob->active.num_clusters);
          -  +  -  +  -  
                +  -  + ]
     812                 :            : 
     813   [ +  +  +  + ]:    6227630 :                         for (i = 0; i < cluster_idx_length / sizeof(desc_extent->cluster_idx[0]); i++) {
     814   [ +  +  +  -  :    6194945 :                                 if (desc_extent->cluster_idx[i] != 0) {
             +  -  +  + ]
     815   [ +  -  +  -  :    5664362 :                                         blob->active.clusters[blob->active.num_clusters++] = bs_cluster_to_lba(blob->bs,
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     816   [ +  -  +  -  :       6908 :                                                         desc_extent->cluster_idx[i]);
                   +  - ]
     817         [ +  + ]:     544399 :                                 } else if (spdk_blob_is_thin_provisioned(blob)) {
     818   [ +  -  +  -  :     537491 :                                         blob->active.clusters[blob->active.num_clusters++] = 0;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     819                 :       8324 :                                 } else {
     820                 :          0 :                                         return -EINVAL;
     821                 :            :                                 }
     822                 :      15232 :                         }
     823   [ +  +  +  -  :      32685 :                         assert(desc_extent->start_cluster_idx + cluster_count == blob->active.num_clusters);
          +  -  +  -  +  
             -  +  -  #  
                      # ]
     824   [ -  +  -  +  :      32685 :                         assert(blob->remaining_clusters_in_et >= cluster_count);
             +  -  #  # ]
     825   [ -  +  -  + ]:      32685 :                         blob->remaining_clusters_in_et -= cluster_count;
     826   [ +  +  +  -  :      43878 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_XATTR) {
             +  -  +  + ]
     827                 :        394 :                         int rc;
     828                 :            : 
     829                 :      38315 :                         rc = blob_deserialize_xattr(blob,
     830                 :        394 :                                                     (struct spdk_blob_md_descriptor_xattr *) desc, false);
     831         [ +  + ]:      37921 :                         if (rc != 0) {
     832                 :          0 :                                 return rc;
     833                 :            :                         }
     834   [ +  +  +  -  :       5317 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_XATTR_INTERNAL) {
             +  -  +  - ]
     835                 :        782 :                         int rc;
     836                 :            : 
     837                 :       5705 :                         rc = blob_deserialize_xattr(blob,
     838                 :        782 :                                                     (struct spdk_blob_md_descriptor_xattr *) desc, true);
     839         [ -  + ]:       4923 :                         if (rc != 0) {
     840                 :          0 :                                 return rc;
     841                 :            :                         }
     842         [ -  + ]:        782 :                 } else {
     843                 :            :                         /* Unrecognized descriptor type.  Do not fail - just continue to the
     844                 :            :                          *  next descriptor.  If this descriptor is associated with some feature
     845                 :            :                          *  defined in a newer version of blobstore, that version of blobstore
     846                 :            :                          *  should create and set an associated feature flag to specify if this
     847                 :            :                          *  blob can be loaded or not.
     848                 :            :                          */
     849                 :            :                 }
     850                 :            : 
     851                 :            :                 /* Advance to the next descriptor */
     852   [ +  -  +  - ]:     154048 :                 cur_desc += sizeof(*desc) + desc->length;
     853         [ +  + ]:     154048 :                 if (cur_desc + sizeof(*desc) > sizeof(page->descriptors)) {
     854                 :        240 :                         break;
     855                 :            :                 }
     856         [ -  + ]:     153808 :                 desc = (struct spdk_blob_md_descriptor *)((uintptr_t)page->descriptors + cur_desc);
     857                 :            :         }
     858                 :            : 
     859                 :      73209 :         return 0;
     860                 :       4372 : }
     861                 :            : 
     862                 :            : static bool bs_load_cur_extent_page_valid(struct spdk_blob_md_page *page);
     863                 :            : 
     864                 :            : static int
     865                 :      32685 : blob_parse_extent_page(struct spdk_blob_md_page *extent_page, struct spdk_blob *blob)
     866                 :            : {
     867   [ +  +  #  # ]:      32685 :         assert(blob != NULL);
     868   [ +  +  +  -  :      32685 :         assert(blob->state == SPDK_BLOB_STATE_LOADING);
             +  -  #  # ]
     869                 :            : 
     870         [ +  + ]:      32685 :         if (bs_load_cur_extent_page_valid(extent_page) == false) {
     871                 :          0 :                 return -ENOENT;
     872                 :            :         }
     873                 :            : 
     874                 :      32685 :         return blob_parse_page(extent_page, blob);
     875                 :       1034 : }
     876                 :            : 
     877                 :            : static int
     878                 :      39991 : blob_parse(const struct spdk_blob_md_page *pages, uint32_t page_count,
     879                 :            :            struct spdk_blob *blob)
     880                 :            : {
     881                 :       3250 :         const struct spdk_blob_md_page *page;
     882                 :       3250 :         uint32_t i;
     883                 :       3250 :         int rc;
     884                 :       3250 :         void *tmp;
     885                 :            : 
     886   [ +  +  #  # ]:      39991 :         assert(page_count > 0);
     887   [ +  +  +  -  :      39991 :         assert(pages[0].sequence_num == 0);
          +  -  +  -  #  
                      # ]
     888   [ +  +  #  # ]:      39991 :         assert(blob != NULL);
     889   [ +  +  +  -  :      39991 :         assert(blob->state == SPDK_BLOB_STATE_LOADING);
             +  -  #  # ]
     890   [ +  +  +  -  :      39991 :         assert(blob->active.clusters == NULL);
          +  -  +  -  #  
                      # ]
     891                 :            : 
     892                 :            :         /* The blobid provided doesn't match what's in the MD, this can
     893                 :            :          * happen for example if a bogus blobid is passed in through open.
     894                 :            :          */
     895   [ +  +  +  -  :      39991 :         if (blob->id != pages[0].id) {
          +  -  +  -  +  
                -  +  + ]
     896   [ +  -  +  -  :         24 :                 SPDK_ERRLOG("Blobid (0x%" PRIx64 ") doesn't match what's in metadata "
          +  -  +  -  +  
                      - ]
     897                 :            :                             "(0x%" PRIx64 ")\n", blob->id, pages[0].id);
     898                 :         24 :                 return -ENOENT;
     899                 :            :         }
     900                 :            : 
     901   [ +  -  +  -  :      39967 :         tmp = realloc(blob->active.pages, page_count * sizeof(*blob->active.pages));
                   +  - ]
     902         [ +  + ]:      39967 :         if (!tmp) {
     903                 :          0 :                 return -ENOMEM;
     904                 :            :         }
     905   [ +  -  +  -  :      39967 :         blob->active.pages = tmp;
                   +  - ]
     906                 :            : 
     907   [ +  -  +  -  :      39967 :         blob->active.pages[0] = pages[0].id;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     908                 :            : 
     909         [ +  + ]:      40572 :         for (i = 1; i < page_count; i++) {
     910   [ +  +  +  -  :        605 :                 assert(spdk_bit_array_get(blob->bs->used_md_pages, pages[i - 1].next));
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  #  # ]
     911   [ +  -  +  -  :        605 :                 blob->active.pages[i] = pages[i - 1].next;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     912                 :        100 :         }
     913   [ +  -  +  -  :      39967 :         blob->active.num_pages = page_count;
                   +  - ]
     914                 :            : 
     915         [ +  + ]:      80491 :         for (i = 0; i < page_count; i++) {
     916         [ +  - ]:      40572 :                 page = &pages[i];
     917                 :            : 
     918   [ +  +  +  -  :      40572 :                 assert(page->id == blob->id);
          +  -  +  -  +  
                -  #  # ]
     919   [ +  +  +  -  :      40572 :                 assert(page->sequence_num == i);
             +  -  #  # ]
     920                 :            : 
     921                 :      40572 :                 rc = blob_parse_page(page, blob);
     922         [ +  + ]:      40572 :                 if (rc != 0) {
     923                 :         48 :                         return rc;
     924                 :            :                 }
     925                 :       3338 :         }
     926                 :            : 
     927                 :      39919 :         return 0;
     928                 :       3250 : }
     929                 :            : 
     930                 :            : static int
     931                 :     298928 : blob_serialize_add_page(const struct spdk_blob *blob,
     932                 :            :                         struct spdk_blob_md_page **pages,
     933                 :            :                         uint32_t *page_count,
     934                 :            :                         struct spdk_blob_md_page **last_page)
     935                 :            : {
     936                 :       3994 :         struct spdk_blob_md_page *page, *tmp_pages;
     937                 :            : 
     938   [ +  +  #  # ]:     298928 :         assert(pages != NULL);
     939   [ +  +  #  # ]:     298928 :         assert(page_count != NULL);
     940                 :            : 
     941         [ +  - ]:     298928 :         *last_page = NULL;
     942   [ +  +  +  + ]:     298928 :         if (*page_count == 0) {
     943   [ +  +  +  -  :     297793 :                 assert(*pages == NULL);
                   #  # ]
     944         [ +  - ]:     297793 :                 *pages = spdk_malloc(SPDK_BS_PAGE_SIZE, 0,
     945                 :            :                                      NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
     946   [ +  +  +  - ]:     297793 :                 if (*pages == NULL) {
     947                 :          0 :                         return -ENOMEM;
     948                 :            :                 }
     949         [ +  - ]:     297793 :                 *page_count = 1;
     950                 :       3906 :         } else {
     951   [ +  +  +  -  :       1135 :                 assert(*pages != NULL);
                   #  # ]
     952   [ +  -  +  - ]:       1135 :                 tmp_pages = spdk_realloc(*pages, SPDK_BS_PAGE_SIZE * (*page_count + 1), 0);
     953         [ +  + ]:       1135 :                 if (tmp_pages == NULL) {
     954                 :          0 :                         return -ENOMEM;
     955                 :            :                 }
     956                 :       1135 :                 (*page_count)++;
     957         [ +  - ]:       1135 :                 *pages = tmp_pages;
     958                 :            :         }
     959                 :            : 
     960   [ +  -  +  -  :     298928 :         page = &(*pages)[*page_count - 1];
                   +  - ]
     961         [ +  + ]:     298928 :         memset(page, 0, sizeof(*page));
     962   [ +  -  +  -  :     298928 :         page->id = blob->id;
             +  -  +  - ]
     963   [ +  -  +  -  :     298928 :         page->sequence_num = *page_count - 1;
                   +  - ]
     964   [ +  -  +  - ]:     298928 :         page->next = SPDK_INVALID_MD_PAGE;
     965         [ +  - ]:     298928 :         *last_page = page;
     966                 :            : 
     967                 :     298928 :         return 0;
     968                 :       3994 : }
     969                 :            : 
     970                 :            : /* Transform the in-memory representation 'xattr' into an on-disk xattr descriptor.
     971                 :            :  * Update required_sz on both success and failure.
     972                 :            :  *
     973                 :            :  */
     974                 :            : static int
     975                 :     315299 : blob_serialize_xattr(const struct spdk_xattr *xattr,
     976                 :            :                      uint8_t *buf, size_t buf_sz,
     977                 :            :                      size_t *required_sz, bool internal)
     978                 :            : {
     979                 :       1561 :         struct spdk_blob_md_descriptor_xattr    *desc;
     980                 :            : 
     981         [ +  - ]:     628991 :         *required_sz = sizeof(struct spdk_blob_md_descriptor_xattr) +
     982   [ +  +  +  -  :     316860 :                        strlen(xattr->name) +
                   +  - ]
     983   [ +  -  +  - ]:     315299 :                        xattr->value_len;
     984                 :            : 
     985   [ +  +  +  + ]:     315299 :         if (buf_sz < *required_sz) {
     986                 :        288 :                 return -1;
     987                 :            :         }
     988                 :            : 
     989                 :     315011 :         desc = (struct spdk_blob_md_descriptor_xattr *)buf;
     990                 :            : 
     991   [ +  +  +  -  :     315011 :         desc->type = internal ? SPDK_MD_DESCRIPTOR_TYPE_XATTR_INTERNAL : SPDK_MD_DESCRIPTOR_TYPE_XATTR;
                   +  - ]
     992   [ +  -  +  - ]:     315011 :         desc->length = sizeof(desc->name_length) +
     993                 :       1513 :                        sizeof(desc->value_length) +
     994   [ +  +  +  -  :     316524 :                        strlen(xattr->name) +
                   +  - ]
     995   [ +  -  +  - ]:     315011 :                        xattr->value_len;
     996   [ +  +  +  -  :     315011 :         desc->name_length = strlen(xattr->name);
          +  -  +  -  +  
                      - ]
     997   [ +  -  +  -  :     315011 :         desc->value_length = xattr->value_len;
             +  -  +  - ]
     998                 :            : 
     999   [ +  +  +  +  :     315011 :         memcpy(desc->name, xattr->name, desc->name_length);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    1000   [ +  +  +  +  :     316524 :         memcpy((void *)((uintptr_t)desc->name + desc->name_length),
          +  -  +  -  +  
                      - ]
    1001   [ +  -  +  - ]:     315011 :                xattr->value,
    1002   [ +  -  +  - ]:     315011 :                desc->value_length);
    1003                 :            : 
    1004                 :     315011 :         return 0;
    1005                 :       1561 : }
    1006                 :            : 
    1007                 :            : static void
    1008                 :     165588 : blob_serialize_extent_table_entry(const struct spdk_blob *blob,
    1009                 :            :                                   uint64_t start_ep, uint64_t *next_ep,
    1010                 :            :                                   uint8_t **buf, size_t *remaining_sz)
    1011                 :            : {
    1012                 :       1569 :         struct spdk_blob_md_descriptor_extent_table *desc;
    1013                 :       1569 :         size_t cur_sz;
    1014                 :       1569 :         uint64_t i, et_idx;
    1015                 :       1569 :         uint32_t extent_page, ep_len;
    1016                 :            : 
    1017                 :            :         /* The buffer must have room for at least num_clusters entry */
    1018                 :     165588 :         cur_sz = sizeof(struct spdk_blob_md_descriptor) + sizeof(desc->num_clusters);
    1019   [ +  +  +  + ]:     165588 :         if (*remaining_sz < cur_sz) {
    1020         [ +  - ]:        120 :                 *next_ep = start_ep;
    1021                 :        120 :                 return;
    1022                 :            :         }
    1023                 :            : 
    1024         [ +  - ]:     165468 :         desc = (struct spdk_blob_md_descriptor_extent_table *)*buf;
    1025   [ +  -  +  - ]:     165468 :         desc->type = SPDK_MD_DESCRIPTOR_TYPE_EXTENT_TABLE;
    1026                 :            : 
    1027   [ +  -  +  -  :     165468 :         desc->num_clusters = blob->active.num_clusters;
          +  -  +  -  +  
                      - ]
    1028                 :            : 
    1029                 :     165468 :         ep_len = 1;
    1030                 :     165468 :         et_idx = 0;
    1031   [ +  +  +  -  :    1137263 :         for (i = start_ep; i < blob->active.num_extent_pages; i++) {
             +  -  +  + ]
    1032   [ +  +  +  - ]:     972402 :                 if (*remaining_sz < cur_sz  + sizeof(desc->extent_page[0])) {
    1033                 :            :                         /* If we ran out of buffer space, return */
    1034                 :        607 :                         break;
    1035                 :            :                 }
    1036                 :            : 
    1037   [ +  -  +  -  :     971795 :                 extent_page = blob->active.extent_pages[i];
          +  -  +  -  +  
                      - ]
    1038                 :            :                 /* Verify that next extent_page is unallocated */
    1039   [ +  +  +  - ]:     972873 :                 if (extent_page == 0 &&
    1040   [ +  +  +  +  :     409721 :                     (i + 1 < blob->active.num_extent_pages && blob->active.extent_pages[i + 1] == 0)) {
          +  -  +  +  +  
          -  +  -  +  -  
             +  -  +  - ]
    1041                 :     268109 :                         ep_len++;
    1042                 :     268109 :                         continue;
    1043                 :            :                 }
    1044   [ +  -  +  -  :     703686 :                 desc->extent_page[et_idx].page_idx = extent_page;
             +  -  +  - ]
    1045   [ +  -  +  -  :     703686 :                 desc->extent_page[et_idx].num_pages = ep_len;
             +  -  +  - ]
    1046                 :     703686 :                 et_idx++;
    1047                 :            : 
    1048                 :     703686 :                 ep_len = 1;
    1049                 :     703686 :                 cur_sz += sizeof(desc->extent_page[et_idx]);
    1050                 :       1425 :         }
    1051         [ +  - ]:     165468 :         *next_ep = i;
    1052                 :            : 
    1053   [ +  -  +  - ]:     165468 :         desc->length = sizeof(desc->num_clusters) + sizeof(desc->extent_page[0]) * et_idx;
    1054   [ +  -  +  -  :     165468 :         *remaining_sz -= sizeof(struct spdk_blob_md_descriptor) + desc->length;
                   +  - ]
    1055   [ +  -  +  -  :     165468 :         *buf += sizeof(struct spdk_blob_md_descriptor) + desc->length;
             +  -  +  - ]
    1056         [ -  + ]:       1569 : }
    1057                 :            : 
    1058                 :            : static int
    1059                 :     164873 : blob_serialize_extent_table(const struct spdk_blob *blob,
    1060                 :            :                             struct spdk_blob_md_page **pages,
    1061                 :            :                             struct spdk_blob_md_page *cur_page,
    1062                 :            :                             uint32_t *page_count, uint8_t **buf,
    1063                 :            :                             size_t *remaining_sz)
    1064                 :            : {
    1065                 :     162810 :         uint64_t                                last_extent_page;
    1066                 :       1551 :         int                                     rc;
    1067                 :            : 
    1068                 :     164873 :         last_extent_page = 0;
    1069                 :            :         /* At least single extent table entry has to be always persisted.
    1070                 :            :          * Such case occurs with num_extent_pages == 0. */
    1071   [ +  -  +  -  :     165588 :         while (last_extent_page <= blob->active.num_extent_pages) {
             +  -  -  + ]
    1072                 :     167157 :                 blob_serialize_extent_table_entry(blob, last_extent_page, &last_extent_page, buf,
    1073                 :       1569 :                                                   remaining_sz);
    1074                 :            : 
    1075   [ +  +  +  -  :     165588 :                 if (last_extent_page == blob->active.num_extent_pages) {
             +  -  +  + ]
    1076                 :     164873 :                         break;
    1077                 :            :                 }
    1078                 :            : 
    1079                 :        715 :                 rc = blob_serialize_add_page(blob, pages, page_count, &cur_page);
    1080         [ +  + ]:        715 :                 if (rc < 0) {
    1081                 :          0 :                         return rc;
    1082                 :            :                 }
    1083                 :            : 
    1084   [ +  -  +  - ]:        715 :                 *buf = (uint8_t *)cur_page->descriptors;
    1085         [ +  - ]:        715 :                 *remaining_sz = sizeof(cur_page->descriptors);
    1086                 :            :         }
    1087                 :            : 
    1088                 :     164873 :         return 0;
    1089                 :       1551 : }
    1090                 :            : 
    1091                 :            : static void
    1092                 :       9318 : blob_serialize_extent_rle(const struct spdk_blob *blob,
    1093                 :            :                           uint64_t start_cluster, uint64_t *next_cluster,
    1094                 :            :                           uint8_t **buf, size_t *buf_sz)
    1095                 :            : {
    1096                 :       1553 :         struct spdk_blob_md_descriptor_extent_rle *desc_extent_rle;
    1097                 :       1553 :         size_t cur_sz;
    1098                 :       1553 :         uint64_t i, extent_idx;
    1099                 :       1553 :         uint64_t lba, lba_per_cluster, lba_count;
    1100                 :            : 
    1101                 :            :         /* The buffer must have room for at least one extent */
    1102                 :       9318 :         cur_sz = sizeof(struct spdk_blob_md_descriptor) + sizeof(desc_extent_rle->extents[0]);
    1103   [ +  +  +  + ]:       9318 :         if (*buf_sz < cur_sz) {
    1104         [ +  - ]:        108 :                 *next_cluster = start_cluster;
    1105                 :        108 :                 return;
    1106                 :            :         }
    1107                 :            : 
    1108         [ +  - ]:       9210 :         desc_extent_rle = (struct spdk_blob_md_descriptor_extent_rle *)*buf;
    1109   [ +  -  +  - ]:       9210 :         desc_extent_rle->type = SPDK_MD_DESCRIPTOR_TYPE_EXTENT_RLE;
    1110                 :            : 
    1111   [ +  -  +  - ]:       9210 :         lba_per_cluster = bs_cluster_to_lba(blob->bs, 1);
    1112                 :            :         /* Assert for scan-build false positive */
    1113   [ +  +  #  # ]:       9210 :         assert(lba_per_cluster > 0);
    1114                 :            : 
    1115   [ +  -  +  -  :       9210 :         lba = blob->active.clusters[start_cluster];
          +  -  +  -  +  
                      - ]
    1116                 :       9210 :         lba_count = lba_per_cluster;
    1117                 :       9210 :         extent_idx = 0;
    1118   [ +  +  +  -  :    4067088 :         for (i = start_cluster + 1; i < blob->active.num_clusters; i++) {
             +  -  +  + ]
    1119   [ +  +  +  +  :    4057902 :                 if ((lba + lba_count) == blob->active.clusters[i] && lba != 0) {
          +  -  +  -  +  
             -  +  +  +  
                      + ]
    1120                 :            :                         /* Run-length encode sequential non-zero LBA */
    1121                 :      40236 :                         lba_count += lba_per_cluster;
    1122                 :      40236 :                         continue;
    1123   [ +  +  +  +  :    4017666 :                 } else if (lba == 0 && blob->active.clusters[i] == 0) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    1124                 :            :                         /* Run-length encode unallocated clusters */
    1125                 :    4013796 :                         lba_count += lba_per_cluster;
    1126                 :    4013796 :                         continue;
    1127                 :            :                 }
    1128   [ +  +  +  -  :       3870 :                 desc_extent_rle->extents[extent_idx].cluster_idx = lba / lba_per_cluster;
          +  -  +  -  +  
                      - ]
    1129   [ +  +  +  -  :       3870 :                 desc_extent_rle->extents[extent_idx].length = lba_count / lba_per_cluster;
          +  -  +  -  +  
                      - ]
    1130                 :       3870 :                 extent_idx++;
    1131                 :            : 
    1132                 :       3870 :                 cur_sz += sizeof(desc_extent_rle->extents[extent_idx]);
    1133                 :            : 
    1134   [ +  +  +  + ]:       3870 :                 if (*buf_sz < cur_sz) {
    1135                 :            :                         /* If we ran out of buffer space, return */
    1136         [ +  - ]:         24 :                         *next_cluster = i;
    1137                 :         24 :                         break;
    1138                 :            :                 }
    1139                 :            : 
    1140   [ +  -  +  -  :       3846 :                 lba = blob->active.clusters[i];
          +  -  +  -  +  
                      - ]
    1141                 :       3846 :                 lba_count = lba_per_cluster;
    1142                 :        641 :         }
    1143                 :            : 
    1144   [ +  +  +  + ]:       9210 :         if (*buf_sz >= cur_sz) {
    1145   [ +  +  +  -  :       9186 :                 desc_extent_rle->extents[extent_idx].cluster_idx = lba / lba_per_cluster;
          +  -  +  -  +  
                      - ]
    1146   [ +  +  +  -  :       9186 :                 desc_extent_rle->extents[extent_idx].length = lba_count / lba_per_cluster;
          +  -  +  -  +  
                      - ]
    1147                 :       9186 :                 extent_idx++;
    1148                 :            : 
    1149   [ +  -  +  -  :       9186 :                 *next_cluster = blob->active.num_clusters;
             +  -  +  - ]
    1150                 :       1531 :         }
    1151                 :            : 
    1152   [ +  -  +  - ]:       9210 :         desc_extent_rle->length = sizeof(desc_extent_rle->extents[0]) * extent_idx;
    1153   [ +  -  +  -  :       9210 :         *buf_sz -= sizeof(struct spdk_blob_md_descriptor) + desc_extent_rle->length;
                   +  - ]
    1154   [ +  -  +  -  :       9210 :         *buf += sizeof(struct spdk_blob_md_descriptor) + desc_extent_rle->length;
             +  -  +  - ]
    1155         [ -  + ]:       1553 : }
    1156                 :            : 
    1157                 :            : static int
    1158                 :      10182 : blob_serialize_extents_rle(const struct spdk_blob *blob,
    1159                 :            :                            struct spdk_blob_md_page **pages,
    1160                 :            :                            struct spdk_blob_md_page *cur_page,
    1161                 :            :                            uint32_t *page_count, uint8_t **buf,
    1162                 :            :                            size_t *remaining_sz)
    1163                 :            : {
    1164                 :       8485 :         uint64_t                                last_cluster;
    1165                 :       1697 :         int                                     rc;
    1166                 :            : 
    1167                 :      10182 :         last_cluster = 0;
    1168   [ +  +  +  -  :      10314 :         while (last_cluster < blob->active.num_clusters) {
             +  -  +  + ]
    1169                 :       9318 :                 blob_serialize_extent_rle(blob, last_cluster, &last_cluster, buf, remaining_sz);
    1170                 :            : 
    1171   [ +  +  +  -  :       9318 :                 if (last_cluster == blob->active.num_clusters) {
             +  -  +  + ]
    1172                 :       9186 :                         break;
    1173                 :            :                 }
    1174                 :            : 
    1175                 :        132 :                 rc = blob_serialize_add_page(blob, pages, page_count, &cur_page);
    1176         [ +  + ]:        132 :                 if (rc < 0) {
    1177                 :          0 :                         return rc;
    1178                 :            :                 }
    1179                 :            : 
    1180   [ +  -  +  - ]:        132 :                 *buf = (uint8_t *)cur_page->descriptors;
    1181         [ +  - ]:        132 :                 *remaining_sz = sizeof(cur_page->descriptors);
    1182                 :            :         }
    1183                 :            : 
    1184                 :      10182 :         return 0;
    1185                 :       1697 : }
    1186                 :            : 
    1187                 :            : static void
    1188                 :     148182 : blob_serialize_extent_page(const struct spdk_blob *blob,
    1189                 :            :                            uint64_t cluster, struct spdk_blob_md_page *page)
    1190                 :            : {
    1191                 :        964 :         struct spdk_blob_md_descriptor_extent_page *desc_extent;
    1192                 :        964 :         uint64_t i, extent_idx;
    1193                 :        964 :         uint64_t lba, lba_per_cluster;
    1194   [ +  +  +  -  :     148182 :         uint64_t start_cluster_idx = (cluster / SPDK_EXTENTS_PER_EP) * SPDK_EXTENTS_PER_EP;
                   +  - ]
    1195                 :            : 
    1196         [ +  - ]:     148182 :         desc_extent = (struct spdk_blob_md_descriptor_extent_page *) page->descriptors;
    1197   [ +  -  +  - ]:     148182 :         desc_extent->type = SPDK_MD_DESCRIPTOR_TYPE_EXTENT_PAGE;
    1198                 :            : 
    1199   [ +  -  +  - ]:     148182 :         lba_per_cluster = bs_cluster_to_lba(blob->bs, 1);
    1200                 :            : 
    1201   [ +  -  +  - ]:     148182 :         desc_extent->start_cluster_idx = start_cluster_idx;
    1202                 :     148182 :         extent_idx = 0;
    1203   [ +  +  +  -  :   19726278 :         for (i = start_cluster_idx; i < blob->active.num_clusters; i++) {
             +  -  +  + ]
    1204   [ +  -  +  -  :   19605694 :                 lba = blob->active.clusters[i];
          +  -  +  -  +  
                      - ]
    1205   [ +  +  +  -  :   19605694 :                 desc_extent->cluster_idx[extent_idx++] = lba / lba_per_cluster;
             +  -  +  - ]
    1206   [ +  +  +  + ]:   19605694 :                 if (extent_idx >= SPDK_EXTENTS_PER_EP) {
    1207                 :      27598 :                         break;
    1208                 :            :                 }
    1209                 :      23822 :         }
    1210   [ +  -  +  - ]:     148182 :         desc_extent->length = sizeof(desc_extent->start_cluster_idx) +
    1211                 :        964 :                               sizeof(desc_extent->cluster_idx[0]) * extent_idx;
    1212                 :     148182 : }
    1213                 :            : 
    1214                 :            : static void
    1215                 :     175055 : blob_serialize_flags(const struct spdk_blob *blob,
    1216                 :            :                      uint8_t *buf, size_t *buf_sz)
    1217                 :            : {
    1218                 :       3248 :         struct spdk_blob_md_descriptor_flags *desc;
    1219                 :            : 
    1220                 :            :         /*
    1221                 :            :          * Flags get serialized first, so we should always have room for the flags
    1222                 :            :          *  descriptor.
    1223                 :            :          */
    1224   [ +  +  +  -  :     175055 :         assert(*buf_sz >= sizeof(*desc));
                   #  # ]
    1225                 :            : 
    1226                 :     175055 :         desc = (struct spdk_blob_md_descriptor_flags *)buf;
    1227   [ +  -  +  - ]:     175055 :         desc->type = SPDK_MD_DESCRIPTOR_TYPE_FLAGS;
    1228   [ +  -  +  - ]:     175055 :         desc->length = sizeof(*desc) - sizeof(struct spdk_blob_md_descriptor);
    1229   [ +  -  +  -  :     175055 :         desc->invalid_flags = blob->invalid_flags;
             +  -  +  - ]
    1230   [ +  -  +  -  :     175055 :         desc->data_ro_flags = blob->data_ro_flags;
             +  -  +  - ]
    1231   [ +  -  +  -  :     175055 :         desc->md_ro_flags = blob->md_ro_flags;
             +  -  +  - ]
    1232                 :            : 
    1233         [ +  - ]:     175055 :         *buf_sz -= sizeof(*desc);
    1234                 :     175055 : }
    1235                 :            : 
    1236                 :            : static int
    1237                 :     350110 : blob_serialize_xattrs(const struct spdk_blob *blob,
    1238                 :            :                       const struct spdk_xattr_tailq *xattrs, bool internal,
    1239                 :            :                       struct spdk_blob_md_page **pages,
    1240                 :            :                       struct spdk_blob_md_page *cur_page,
    1241                 :            :                       uint32_t *page_count, uint8_t **buf,
    1242                 :            :                       size_t *remaining_sz)
    1243                 :            : {
    1244                 :       6496 :         const struct spdk_xattr *xattr;
    1245                 :       6496 :         int     rc;
    1246                 :            : 
    1247   [ +  +  +  -  :     665121 :         TAILQ_FOREACH(xattr, xattrs, link) {
          +  +  +  -  +  
                -  +  - ]
    1248                 :     315011 :                 size_t required_sz = 0;
    1249                 :            : 
    1250                 :     316524 :                 rc = blob_serialize_xattr(xattr,
    1251   [ +  -  +  - ]:       1513 :                                           *buf, *remaining_sz,
    1252         [ +  - ]:       1513 :                                           &required_sz, internal);
    1253         [ +  + ]:     315011 :                 if (rc < 0) {
    1254                 :            :                         /* Need to add a new page to the chain */
    1255                 :        288 :                         rc = blob_serialize_add_page(blob, pages, page_count,
    1256                 :            :                                                      &cur_page);
    1257         [ +  + ]:        288 :                         if (rc < 0) {
    1258         [ #  # ]:          0 :                                 spdk_free(*pages);
    1259         [ #  # ]:          0 :                                 *pages = NULL;
    1260         [ #  # ]:          0 :                                 *page_count = 0;
    1261                 :          0 :                                 return rc;
    1262                 :            :                         }
    1263                 :            : 
    1264   [ +  -  +  - ]:        288 :                         *buf = (uint8_t *)cur_page->descriptors;
    1265         [ +  - ]:        288 :                         *remaining_sz = sizeof(cur_page->descriptors);
    1266                 :            : 
    1267                 :            :                         /* Try again */
    1268                 :        288 :                         required_sz = 0;
    1269                 :        336 :                         rc = blob_serialize_xattr(xattr,
    1270   [ +  -  +  - ]:         48 :                                                   *buf, *remaining_sz,
    1271         [ +  - ]:         48 :                                                   &required_sz, internal);
    1272                 :            : 
    1273         [ +  + ]:        288 :                         if (rc < 0) {
    1274         [ #  # ]:          0 :                                 spdk_free(*pages);
    1275         [ #  # ]:          0 :                                 *pages = NULL;
    1276         [ #  # ]:          0 :                                 *page_count = 0;
    1277                 :          0 :                                 return rc;
    1278                 :            :                         }
    1279                 :         48 :                 }
    1280                 :            : 
    1281         [ +  - ]:     315011 :                 *remaining_sz -= required_sz;
    1282   [ +  -  +  - ]:     315011 :                 *buf += required_sz;
    1283         [ -  + ]:       1513 :         }
    1284                 :            : 
    1285                 :     350110 :         return 0;
    1286                 :       6496 : }
    1287                 :            : 
    1288                 :            : static int
    1289                 :     175055 : blob_serialize(const struct spdk_blob *blob, struct spdk_blob_md_page **pages,
    1290                 :            :                uint32_t *page_count)
    1291                 :            : {
    1292                 :     171295 :         struct spdk_blob_md_page                *cur_page;
    1293                 :       3248 :         int                                     rc;
    1294                 :     171295 :         uint8_t                                 *buf;
    1295                 :     171295 :         size_t                                  remaining_sz;
    1296                 :            : 
    1297   [ +  +  #  # ]:     175055 :         assert(pages != NULL);
    1298   [ +  +  #  # ]:     175055 :         assert(page_count != NULL);
    1299   [ +  +  #  # ]:     175055 :         assert(blob != NULL);
    1300   [ +  +  +  -  :     175055 :         assert(blob->state == SPDK_BLOB_STATE_DIRTY);
             +  -  #  # ]
    1301                 :            : 
    1302         [ +  - ]:     175055 :         *pages = NULL;
    1303         [ +  - ]:     175055 :         *page_count = 0;
    1304                 :            : 
    1305                 :            :         /* A blob always has at least 1 page, even if it has no descriptors */
    1306                 :     175055 :         rc = blob_serialize_add_page(blob, pages, page_count, &cur_page);
    1307         [ +  + ]:     175055 :         if (rc < 0) {
    1308                 :          0 :                 return rc;
    1309                 :            :         }
    1310                 :            : 
    1311         [ +  - ]:     175055 :         buf = (uint8_t *)cur_page->descriptors;
    1312                 :     175055 :         remaining_sz = sizeof(cur_page->descriptors);
    1313                 :            : 
    1314                 :            :         /* Serialize flags */
    1315                 :     175055 :         blob_serialize_flags(blob, buf, &remaining_sz);
    1316         [ +  - ]:     175055 :         buf += sizeof(struct spdk_blob_md_descriptor_flags);
    1317                 :            : 
    1318                 :            :         /* Serialize xattrs */
    1319         [ +  - ]:     175055 :         rc = blob_serialize_xattrs(blob, &blob->xattrs, false,
    1320                 :       3248 :                                    pages, cur_page, page_count, &buf, &remaining_sz);
    1321         [ +  + ]:     175055 :         if (rc < 0) {
    1322                 :          0 :                 return rc;
    1323                 :            :         }
    1324                 :            : 
    1325                 :            :         /* Serialize internal xattrs */
    1326         [ +  - ]:     175055 :         rc = blob_serialize_xattrs(blob, &blob->xattrs_internal, true,
    1327                 :       3248 :                                    pages, cur_page, page_count, &buf, &remaining_sz);
    1328         [ +  + ]:     175055 :         if (rc < 0) {
    1329                 :          0 :                 return rc;
    1330                 :            :         }
    1331                 :            : 
    1332   [ +  +  +  +  :     175055 :         if (blob->use_extent_table) {
             +  -  +  + ]
    1333                 :            :                 /* Serialize extent table */
    1334                 :     164873 :                 rc = blob_serialize_extent_table(blob, pages, cur_page, page_count, &buf, &remaining_sz);
    1335                 :       1551 :         } else {
    1336                 :            :                 /* Serialize extents */
    1337                 :      10182 :                 rc = blob_serialize_extents_rle(blob, pages, cur_page, page_count, &buf, &remaining_sz);
    1338                 :            :         }
    1339                 :            : 
    1340                 :     175055 :         return rc;
    1341                 :       3248 : }
    1342                 :            : 
    1343                 :            : struct spdk_blob_load_ctx {
    1344                 :            :         struct spdk_blob                *blob;
    1345                 :            : 
    1346                 :            :         struct spdk_blob_md_page        *pages;
    1347                 :            :         uint32_t                        num_pages;
    1348                 :            :         uint32_t                        next_extent_page;
    1349                 :            :         spdk_bs_sequence_t              *seq;
    1350                 :            : 
    1351                 :            :         spdk_bs_sequence_cpl            cb_fn;
    1352                 :            :         void                            *cb_arg;
    1353                 :            : };
    1354                 :            : 
    1355                 :            : static uint32_t
    1356                 :     489844 : blob_md_page_calc_crc(void *page)
    1357                 :            : {
    1358                 :      19150 :         uint32_t                crc;
    1359                 :            : 
    1360                 :     489844 :         crc = BLOB_CRC32C_INITIAL;
    1361                 :     489844 :         crc = spdk_crc32c_update(page, SPDK_BS_PAGE_SIZE - 4, crc);
    1362                 :     489844 :         crc ^= BLOB_CRC32C_INITIAL;
    1363                 :            : 
    1364                 :     508994 :         return crc;
    1365                 :            : 
    1366                 :      19150 : }
    1367                 :            : 
    1368                 :            : static void
    1369                 :      40159 : blob_load_final(struct spdk_blob_load_ctx *ctx, int bserrno)
    1370                 :            : {
    1371   [ +  -  +  - ]:      40159 :         struct spdk_blob                *blob = ctx->blob;
    1372                 :            : 
    1373         [ +  + ]:      40159 :         if (bserrno == 0) {
    1374                 :      39775 :                 blob_mark_clean(blob);
    1375                 :       3214 :         }
    1376                 :            : 
    1377   [ +  -  +  -  :      40159 :         ctx->cb_fn(ctx->seq, ctx->cb_arg, bserrno);
          -  +  +  -  +  
          -  +  -  +  -  
                   +  - ]
    1378                 :            : 
    1379                 :            :         /* Free the memory */
    1380   [ +  -  +  - ]:      40159 :         spdk_free(ctx->pages);
    1381                 :      40159 :         free(ctx);
    1382                 :      40159 : }
    1383                 :            : 
    1384                 :            : static void
    1385                 :       2588 : blob_load_snapshot_cpl(void *cb_arg, struct spdk_blob *snapshot, int bserrno)
    1386                 :            : {
    1387                 :       2588 :         struct spdk_blob_load_ctx       *ctx = cb_arg;
    1388   [ +  -  +  - ]:       2588 :         struct spdk_blob                *blob = ctx->blob;
    1389                 :            : 
    1390         [ +  + ]:       2588 :         if (bserrno == 0) {
    1391   [ +  -  +  - ]:       2552 :                 blob->back_bs_dev = bs_create_blob_bs_dev(snapshot);
    1392   [ +  +  +  -  :       2552 :                 if (blob->back_bs_dev == NULL) {
                   +  - ]
    1393                 :          0 :                         bserrno = -ENOMEM;
    1394                 :          0 :                 }
    1395                 :        404 :         }
    1396         [ +  + ]:       2588 :         if (bserrno != 0) {
    1397                 :         36 :                 SPDK_ERRLOG("Snapshot fail\n");
    1398                 :          6 :         }
    1399                 :            : 
    1400                 :       2588 :         blob_load_final(ctx, bserrno);
    1401                 :       2588 : }
    1402                 :            : 
    1403                 :            : static void blob_update_clear_method(struct spdk_blob *blob);
    1404                 :            : 
    1405                 :            : static int
    1406                 :        647 : blob_load_esnap(struct spdk_blob *blob, void *blob_ctx)
    1407                 :            : {
    1408   [ +  -  +  - ]:        647 :         struct spdk_blob_store *bs = blob->bs;
    1409                 :        647 :         struct spdk_bs_dev *bs_dev = NULL;
    1410                 :        647 :         const void *esnap_id = NULL;
    1411                 :        647 :         size_t id_len = 0;
    1412                 :         96 :         int rc;
    1413                 :            : 
    1414   [ +  +  +  -  :        647 :         if (bs->esnap_bs_dev_create == NULL) {
                   +  + ]
    1415   [ +  -  +  - ]:         48 :                 SPDK_NOTICELOG("blob 0x%" PRIx64 " is an esnap clone but the blobstore was opened "
    1416                 :            :                                "without support for esnap clones\n", blob->id);
    1417                 :         48 :                 return -ENOTSUP;
    1418                 :            :         }
    1419   [ +  +  +  -  :        599 :         assert(blob->back_bs_dev == NULL);
             +  -  #  # ]
    1420                 :            : 
    1421                 :        599 :         rc = blob_get_xattr_value(blob, BLOB_EXTERNAL_SNAPSHOT_ID, &esnap_id, &id_len, true);
    1422         [ -  + ]:        599 :         if (rc != 0) {
    1423   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 " is an esnap clone but has no esnap ID\n", blob->id);
    1424                 :          0 :                 return -EINVAL;
    1425                 :            :         }
    1426   [ +  -  +  - ]:        599 :         assert(id_len > 0 && id_len < UINT32_MAX);
    1427                 :            : 
    1428   [ +  +  +  +  :        599 :         SPDK_INFOLOG(blob, "Creating external snapshot device\n");
                   +  - ]
    1429                 :            : 
    1430   [ +  -  +  -  :        599 :         rc = bs->esnap_bs_dev_create(bs->esnap_ctx, blob_ctx, blob, esnap_id, (uint32_t)id_len,
          -  +  +  -  +  
                -  +  - ]
    1431                 :            :                                      &bs_dev);
    1432         [ -  + ]:        599 :         if (rc != 0) {
    1433   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": failed to load back_bs_dev "
          #  #  #  #  #  
                      # ]
    1434                 :            :                               "with error %d\n", blob->id, rc);
    1435                 :          0 :                 return rc;
    1436                 :            :         }
    1437                 :            : 
    1438                 :            :         /*
    1439                 :            :          * Note: bs_dev might be NULL if the consumer chose to not open the external snapshot.
    1440                 :            :          * This especially might happen during spdk_bs_load() iteration.
    1441                 :            :          */
    1442         [ +  + ]:        599 :         if (bs_dev != NULL) {
    1443   [ +  +  +  +  :        555 :                 SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": loaded back_bs_dev\n", blob->id);
          +  -  #  #  #  
                      # ]
    1444   [ +  +  +  +  :        555 :                 if ((bs->io_unit_size % bs_dev->blocklen) != 0) {
          +  -  +  -  +  
                -  +  + ]
    1445   [ +  -  +  -  :         24 :                         SPDK_NOTICELOG("blob 0x%" PRIx64 " external snapshot device block size %u "
          +  -  +  -  +  
                -  +  - ]
    1446                 :            :                                        "is not compatible with blobstore block size %u\n",
    1447                 :            :                                        blob->id, bs_dev->blocklen, bs->io_unit_size);
    1448   [ +  -  +  -  :         24 :                         bs_dev->destroy(bs_dev);
             -  +  +  - ]
    1449                 :         24 :                         return -EINVAL;
    1450                 :            :                 }
    1451                 :         84 :         }
    1452                 :            : 
    1453   [ +  -  +  - ]:        575 :         blob->back_bs_dev = bs_dev;
    1454   [ +  -  +  - ]:        575 :         blob->parent_id = SPDK_BLOBID_EXTERNAL_SNAPSHOT;
    1455                 :            : 
    1456                 :        575 :         return 0;
    1457                 :         96 : }
    1458                 :            : 
    1459                 :            : static void
    1460                 :      39883 : blob_load_backing_dev(spdk_bs_sequence_t *seq, void *cb_arg)
    1461                 :            : {
    1462                 :      39883 :         struct spdk_blob_load_ctx       *ctx = cb_arg;
    1463   [ +  -  +  - ]:      39883 :         struct spdk_blob                *blob = ctx->blob;
    1464                 :      36015 :         const void                      *value;
    1465                 :      36015 :         size_t                          len;
    1466                 :       3232 :         int                             rc;
    1467                 :            : 
    1468         [ +  + ]:      39883 :         if (blob_is_esnap_clone(blob)) {
    1469   [ +  -  +  -  :        647 :                 rc = blob_load_esnap(blob, seq->cpl.u.blob_handle.esnap_ctx);
          +  -  +  -  +  
                      - ]
    1470                 :        647 :                 blob_load_final(ctx, rc);
    1471                 :       1079 :                 return;
    1472                 :            :         }
    1473                 :            : 
    1474         [ +  + ]:      39236 :         if (spdk_blob_is_thin_provisioned(blob)) {
    1475                 :       5814 :                 rc = blob_get_xattr_value(blob, BLOB_SNAPSHOT, &value, &len, true);
    1476         [ +  + ]:       5814 :                 if (rc == 0) {
    1477         [ -  + ]:       2588 :                         if (len != sizeof(spdk_blob_id)) {
    1478                 :          0 :                                 blob_load_final(ctx, -EINVAL);
    1479                 :          0 :                                 return;
    1480                 :            :                         }
    1481                 :            :                         /* open snapshot blob and continue in the callback function */
    1482   [ +  -  +  -  :       2588 :                         blob->parent_id = *(spdk_blob_id *)value;
                   +  - ]
    1483   [ +  -  +  -  :       2588 :                         spdk_bs_open_blob(blob->bs, blob->parent_id,
             +  -  +  - ]
    1484                 :        410 :                                           blob_load_snapshot_cpl, ctx);
    1485                 :       2588 :                         return;
    1486                 :            :                 } else {
    1487                 :            :                         /* add zeroes_dev for thin provisioned blob */
    1488   [ +  -  +  - ]:       3226 :                         blob->back_bs_dev = bs_create_zeroes_dev();
    1489                 :            :                 }
    1490                 :        504 :         } else {
    1491                 :            :                 /* standard blob */
    1492   [ +  -  +  - ]:      33422 :                 blob->back_bs_dev = NULL;
    1493                 :            :         }
    1494                 :      36648 :         blob_load_final(ctx, 0);
    1495         [ -  + ]:       3232 : }
    1496                 :            : 
    1497                 :            : static void
    1498                 :      63232 : blob_load_cpl_extents_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    1499                 :            : {
    1500                 :      63232 :         struct spdk_blob_load_ctx       *ctx = cb_arg;
    1501   [ +  -  +  - ]:      63232 :         struct spdk_blob                *blob = ctx->blob;
    1502                 :       2710 :         struct spdk_blob_md_page        *page;
    1503                 :       2710 :         uint64_t                        i;
    1504                 :       2710 :         uint32_t                        crc;
    1505                 :       2710 :         uint64_t                        lba;
    1506                 :       2710 :         void                            *tmp;
    1507                 :       2710 :         uint64_t                        sz;
    1508                 :            : 
    1509         [ +  + ]:      63232 :         if (bserrno) {
    1510                 :         36 :                 SPDK_ERRLOG("Extent page read failed: %d\n", bserrno);
    1511                 :         36 :                 blob_load_final(ctx, bserrno);
    1512                 :         36 :                 return;
    1513                 :            :         }
    1514                 :            : 
    1515   [ +  +  +  -  :      63196 :         if (ctx->pages == NULL) {
                   +  + ]
    1516                 :            :                 /* First iteration of this function, allocate buffer for single EXTENT_PAGE */
    1517   [ +  -  +  - ]:      30511 :                 ctx->pages = spdk_zmalloc(SPDK_BS_PAGE_SIZE, 0,
    1518                 :            :                                           NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    1519   [ +  +  +  -  :      30511 :                 if (!ctx->pages) {
                   +  - ]
    1520                 :          0 :                         blob_load_final(ctx, -ENOMEM);
    1521                 :          0 :                         return;
    1522                 :            :                 }
    1523   [ +  -  +  - ]:      30511 :                 ctx->num_pages = 1;
    1524   [ +  -  +  - ]:      30511 :                 ctx->next_extent_page = 0;
    1525                 :       1670 :         } else {
    1526   [ +  -  +  -  :      32685 :                 page = &ctx->pages[0];
                   +  - ]
    1527                 :      32685 :                 crc = blob_md_page_calc_crc(page);
    1528   [ +  +  +  -  :      32685 :                 if (crc != page->crc) {
                   -  + ]
    1529                 :          0 :                         blob_load_final(ctx, -EINVAL);
    1530                 :          0 :                         return;
    1531                 :            :                 }
    1532                 :            : 
    1533   [ +  +  +  -  :      32685 :                 if (page->next != SPDK_INVALID_MD_PAGE) {
                   -  + ]
    1534                 :          0 :                         blob_load_final(ctx, -EINVAL);
    1535                 :          0 :                         return;
    1536                 :            :                 }
    1537                 :            : 
    1538                 :      32685 :                 bserrno = blob_parse_extent_page(page, blob);
    1539         [ -  + ]:      32685 :                 if (bserrno) {
    1540                 :          0 :                         blob_load_final(ctx, bserrno);
    1541                 :          0 :                         return;
    1542                 :            :                 }
    1543                 :            :         }
    1544                 :            : 
    1545   [ +  +  +  -  :      70105 :         for (i = ctx->next_extent_page; i < blob->active.num_extent_pages; i++) {
          +  -  +  -  +  
                -  +  + ]
    1546   [ +  +  +  -  :      39630 :                 if (blob->active.extent_pages[i] != 0) {
          +  -  +  -  +  
                -  +  + ]
    1547                 :            :                         /* Extent page was allocated, read and parse it. */
    1548   [ +  -  +  -  :      32721 :                         lba = bs_md_page_to_lba(blob->bs, blob->active.extent_pages[i]);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    1549   [ +  -  +  - ]:      32721 :                         ctx->next_extent_page = i + 1;
    1550                 :            : 
    1551   [ +  -  +  -  :      33761 :                         bs_sequence_read_dev(seq, &ctx->pages[0], lba,
                   +  - ]
    1552   [ +  -  +  - ]:      32721 :                                              bs_byte_to_lba(blob->bs, SPDK_BS_PAGE_SIZE),
    1553                 :       1040 :                                              blob_load_cpl_extents_cpl, ctx);
    1554                 :      32721 :                         return;
    1555                 :            :                 } else {
    1556                 :            :                         /* Thin provisioned blobs can point to unallocated extent pages.
    1557                 :            :                          * In this case blob size should be increased by up to the amount left in remaining_clusters_in_et. */
    1558                 :            : 
    1559   [ +  +  +  -  :       6909 :                         sz = spdk_min(blob->remaining_clusters_in_et, SPDK_EXTENTS_PER_EP);
          +  -  +  +  +  
             -  +  -  +  
                      - ]
    1560   [ +  -  +  -  :       6909 :                         blob->active.num_clusters += sz;
                   +  - ]
    1561   [ +  -  +  - ]:       6909 :                         blob->remaining_clusters_in_et -= sz;
    1562                 :            : 
    1563   [ +  +  #  # ]:       6909 :                         assert(spdk_blob_is_thin_provisioned(blob));
    1564   [ +  +  +  +  :       6909 :                         assert(i + 1 < blob->active.num_extent_pages || blob->remaining_clusters_in_et == 0);
          +  -  +  -  +  
          -  +  -  -  +  
                   #  # ]
    1565                 :            : 
    1566   [ +  -  +  -  :       6909 :                         tmp = realloc(blob->active.clusters, blob->active.num_clusters * sizeof(*blob->active.clusters));
          +  -  +  -  +  
                -  +  - ]
    1567         [ -  + ]:       6909 :                         if (tmp == NULL) {
    1568                 :          0 :                                 blob_load_final(ctx, -ENOMEM);
    1569                 :          0 :                                 return;
    1570                 :            :                         }
    1571   [ +  +  +  -  :       7297 :                         memset(tmp + sizeof(*blob->active.clusters) * blob->active.cluster_array_size, 0,
             +  -  +  - ]
    1572   [ +  -  +  -  :       6909 :                                sizeof(*blob->active.clusters) * (blob->active.num_clusters - blob->active.cluster_array_size));
          +  -  +  -  +  
                -  +  - ]
    1573   [ +  -  +  -  :       6909 :                         blob->active.clusters = tmp;
                   +  - ]
    1574   [ +  -  +  -  :       6909 :                         blob->active.cluster_array_size = blob->active.num_clusters;
          +  -  +  -  +  
                -  +  - ]
    1575                 :            :                 }
    1576                 :        388 :         }
    1577                 :            : 
    1578                 :      30475 :         blob_load_backing_dev(seq, ctx);
    1579         [ -  + ]:       2710 : }
    1580                 :            : 
    1581                 :            : static void
    1582                 :      40764 : blob_load_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    1583                 :            : {
    1584                 :      40764 :         struct spdk_blob_load_ctx       *ctx = cb_arg;
    1585   [ +  -  +  - ]:      40764 :         struct spdk_blob                *blob = ctx->blob;
    1586                 :       3378 :         struct spdk_blob_md_page        *page;
    1587                 :       3378 :         int                             rc;
    1588                 :       3378 :         uint32_t                        crc;
    1589                 :       3378 :         uint32_t                        current_page;
    1590                 :            : 
    1591   [ +  +  +  -  :      40764 :         if (ctx->num_pages == 1) {
                   +  + ]
    1592   [ +  -  +  - ]:      40159 :                 current_page = bs_blobid_to_page(blob->id);
    1593                 :       3278 :         } else {
    1594   [ +  +  +  -  :        605 :                 assert(ctx->num_pages != 0);
             +  -  #  # ]
    1595   [ +  -  +  -  :        605 :                 page = &ctx->pages[ctx->num_pages - 2];
          +  -  +  -  +  
                      - ]
    1596   [ +  -  +  - ]:        605 :                 current_page = page->next;
    1597                 :            :         }
    1598                 :            : 
    1599         [ +  + ]:      40764 :         if (bserrno) {
    1600   [ +  -  +  - ]:        120 :                 SPDK_ERRLOG("Metadata page %d read failed for blobid 0x%" PRIx64 ": %d\n",
    1601                 :            :                             current_page, blob->id, bserrno);
    1602                 :        120 :                 blob_load_final(ctx, bserrno);
    1603                 :        120 :                 return;
    1604                 :            :         }
    1605                 :            : 
    1606   [ -  +  -  +  :      40644 :         page = &ctx->pages[ctx->num_pages - 1];
          -  +  -  +  -  
                      + ]
    1607                 :      40644 :         crc = blob_md_page_calc_crc(page);
    1608   [ +  +  -  +  :      40644 :         if (crc != page->crc) {
                   +  + ]
    1609   [ -  +  -  + ]:         48 :                 SPDK_ERRLOG("Metadata page %d crc mismatch for blobid 0x%" PRIx64 "\n",
    1610                 :            :                             current_page, blob->id);
    1611                 :         48 :                 blob_load_final(ctx, -EINVAL);
    1612                 :         48 :                 return;
    1613                 :            :         }
    1614                 :            : 
    1615   [ +  +  -  +  :      40596 :         if (page->next != SPDK_INVALID_MD_PAGE) {
                   +  + ]
    1616                 :        100 :                 struct spdk_blob_md_page *tmp_pages;
    1617   [ +  -  +  - ]:        605 :                 uint32_t next_page = page->next;
    1618   [ +  -  +  - ]:        605 :                 uint64_t next_lba = bs_md_page_to_lba(blob->bs, next_page);
    1619                 :            : 
    1620                 :            :                 /* Read the next page */
    1621   [ +  -  +  -  :        605 :                 tmp_pages = spdk_realloc(ctx->pages, (sizeof(*page) * (ctx->num_pages + 1)), 0);
             +  -  +  - ]
    1622         [ +  + ]:        605 :                 if (tmp_pages == NULL) {
    1623                 :          0 :                         blob_load_final(ctx, -ENOMEM);
    1624                 :          0 :                         return;
    1625                 :            :                 }
    1626         [ +  - ]:        605 :                 ctx->num_pages++;
    1627   [ +  -  +  - ]:        605 :                 ctx->pages = tmp_pages;
    1628                 :            : 
    1629   [ +  -  +  -  :        705 :                 bs_sequence_read_dev(seq, &ctx->pages[ctx->num_pages - 1],
          +  -  +  -  +  
                      - ]
    1630                 :        100 :                                      next_lba,
    1631   [ +  -  +  - ]:        605 :                                      bs_byte_to_lba(blob->bs, sizeof(*page)),
    1632                 :        100 :                                      blob_load_cpl, ctx);
    1633                 :        605 :                 return;
    1634                 :        100 :         }
    1635                 :            : 
    1636                 :            :         /* Parse the pages */
    1637   [ +  -  +  -  :      39991 :         rc = blob_parse(ctx->pages, ctx->num_pages, blob);
             +  -  +  - ]
    1638         [ +  + ]:      39991 :         if (rc) {
    1639                 :         72 :                 blob_load_final(ctx, rc);
    1640                 :         72 :                 return;
    1641                 :            :         }
    1642                 :            : 
    1643   [ +  +  +  +  :      39919 :         if (blob->extent_table_found == true) {
             +  -  +  + ]
    1644                 :            :                 /* If EXTENT_TABLE was found, that means support for it should be enabled. */
    1645   [ +  +  +  +  :      30511 :                 assert(blob->extent_rle_found == false);
          +  -  +  -  #  
                      # ]
    1646   [ +  -  +  - ]:      30511 :                 blob->use_extent_table = true;
    1647                 :       1670 :         } else {
    1648                 :            :                 /* If EXTENT_RLE or no extent_* descriptor was found disable support
    1649                 :            :                  * for extent table. No extent_* descriptors means that blob has length of 0
    1650                 :            :                  * and no extent_rle descriptors were persisted for it.
    1651                 :            :                  * EXTENT_TABLE if used, is always present in metadata regardless of length. */
    1652   [ +  -  +  - ]:       9408 :                 blob->use_extent_table = false;
    1653                 :            :         }
    1654                 :            : 
    1655                 :            :         /* Check the clear_method stored in metadata vs what may have been passed
    1656                 :            :          * via spdk_bs_open_blob_ext() and update accordingly.
    1657                 :            :          */
    1658                 :      39919 :         blob_update_clear_method(blob);
    1659                 :            : 
    1660   [ +  -  +  - ]:      39919 :         spdk_free(ctx->pages);
    1661   [ +  -  +  - ]:      39919 :         ctx->pages = NULL;
    1662                 :            : 
    1663   [ +  +  +  +  :      39919 :         if (blob->extent_table_found) {
             +  -  +  + ]
    1664                 :      30511 :                 blob_load_cpl_extents_cpl(seq, ctx, 0);
    1665                 :       1670 :         } else {
    1666                 :       9408 :                 blob_load_backing_dev(seq, ctx);
    1667                 :            :         }
    1668         [ -  + ]:       3378 : }
    1669                 :            : 
    1670                 :            : /* Load a blob from disk given a blobid */
    1671                 :            : static void
    1672                 :      40159 : blob_load(spdk_bs_sequence_t *seq, struct spdk_blob *blob,
    1673                 :            :           spdk_bs_sequence_cpl cb_fn, void *cb_arg)
    1674                 :            : {
    1675                 :       3278 :         struct spdk_blob_load_ctx *ctx;
    1676                 :       3278 :         struct spdk_blob_store *bs;
    1677                 :       3278 :         uint32_t page_num;
    1678                 :       3278 :         uint64_t lba;
    1679                 :            : 
    1680                 :      40159 :         blob_verify_md_op(blob);
    1681                 :            : 
    1682   [ +  -  +  - ]:      40159 :         bs = blob->bs;
    1683                 :            : 
    1684                 :      40159 :         ctx = calloc(1, sizeof(*ctx));
    1685         [ +  + ]:      40159 :         if (!ctx) {
    1686   [ #  #  #  # ]:          0 :                 cb_fn(seq, cb_arg, -ENOMEM);
    1687                 :          0 :                 return;
    1688                 :            :         }
    1689                 :            : 
    1690   [ +  -  +  - ]:      40159 :         ctx->blob = blob;
    1691   [ +  -  +  -  :      40159 :         ctx->pages = spdk_realloc(ctx->pages, SPDK_BS_PAGE_SIZE, 0);
             +  -  +  - ]
    1692   [ +  +  +  -  :      40159 :         if (!ctx->pages) {
                   +  - ]
    1693                 :          0 :                 free(ctx);
    1694   [ #  #  #  # ]:          0 :                 cb_fn(seq, cb_arg, -ENOMEM);
    1695                 :          0 :                 return;
    1696                 :            :         }
    1697   [ +  -  +  - ]:      40159 :         ctx->num_pages = 1;
    1698   [ +  -  +  - ]:      40159 :         ctx->cb_fn = cb_fn;
    1699   [ +  -  +  - ]:      40159 :         ctx->cb_arg = cb_arg;
    1700   [ +  -  +  - ]:      40159 :         ctx->seq = seq;
    1701                 :            : 
    1702   [ +  -  +  - ]:      40159 :         page_num = bs_blobid_to_page(blob->id);
    1703   [ +  -  +  - ]:      40159 :         lba = bs_md_page_to_lba(blob->bs, page_num);
    1704                 :            : 
    1705   [ +  -  +  - ]:      40159 :         blob->state = SPDK_BLOB_STATE_LOADING;
    1706                 :            : 
    1707   [ +  -  +  -  :      40159 :         bs_sequence_read_dev(seq, &ctx->pages[0], lba,
                   +  - ]
    1708                 :      40159 :                              bs_byte_to_lba(bs, SPDK_BS_PAGE_SIZE),
    1709                 :       3278 :                              blob_load_cpl, ctx);
    1710         [ -  + ]:       3278 : }
    1711                 :            : 
    1712                 :            : struct spdk_blob_persist_ctx {
    1713                 :            :         struct spdk_blob                *blob;
    1714                 :            : 
    1715                 :            :         struct spdk_blob_md_page        *pages;
    1716                 :            :         uint32_t                        next_extent_page;
    1717                 :            :         struct spdk_blob_md_page        *extent_page;
    1718                 :            : 
    1719                 :            :         spdk_bs_sequence_t              *seq;
    1720                 :            :         spdk_bs_sequence_cpl            cb_fn;
    1721                 :            :         void                            *cb_arg;
    1722                 :            :         TAILQ_ENTRY(spdk_blob_persist_ctx) link;
    1723                 :            : };
    1724                 :            : 
    1725                 :            : static void
    1726                 :      34235 : bs_batch_clear_dev(struct spdk_blob_persist_ctx *ctx, spdk_bs_batch_t *batch, uint64_t lba,
    1727                 :            :                    uint64_t lba_count)
    1728                 :            : {
    1729   [ +  -  +  -  :      34235 :         switch (ctx->blob->clear_method) {
          +  -  +  -  +  
                -  -  - ]
    1730                 :      32992 :         case BLOB_CLEAR_WITH_DEFAULT:
    1731                 :            :         case BLOB_CLEAR_WITH_UNMAP:
    1732                 :      34234 :                 bs_batch_unmap_dev(batch, lba, lba_count);
    1733                 :      34234 :                 break;
    1734                 :          0 :         case BLOB_CLEAR_WITH_WRITE_ZEROES:
    1735                 :          0 :                 bs_batch_write_zeroes_dev(batch, lba, lba_count);
    1736                 :          0 :                 break;
    1737                 :          1 :         case BLOB_CLEAR_WITH_NONE:
    1738                 :            :         default:
    1739                 :          1 :                 break;
    1740                 :            :         }
    1741                 :      34235 : }
    1742                 :            : 
    1743                 :            : static int
    1744                 :      12479 : bs_super_validate(struct spdk_bs_super_block *super, struct spdk_blob_store *bs)
    1745                 :            : {
    1746                 :       1124 :         uint32_t        crc;
    1747                 :            :         static const char zeros[SPDK_BLOBSTORE_TYPE_LENGTH];
    1748                 :            : 
    1749   [ +  +  +  -  :      13644 :         if (super->version > SPDK_BS_VERSION ||
             +  +  +  + ]
    1750   [ +  +  +  - ]:      11842 :             super->version < SPDK_BS_INITIAL_VERSION) {
    1751                 :       5017 :                 return -EILSEQ;
    1752                 :            :         }
    1753                 :            : 
    1754   [ +  +  +  +  :       7462 :         if (memcmp(super->signature, SPDK_BS_SUPER_BLOCK_SIG,
          +  -  -  +  -  
                      + ]
    1755                 :       1116 :                    sizeof(super->signature)) != 0) {
    1756                 :        300 :                 return -EILSEQ;
    1757                 :            :         }
    1758                 :            : 
    1759                 :       7162 :         crc = blob_md_page_calc_crc(super);
    1760   [ +  +  +  -  :       7162 :         if (crc != super->crc) {
                   +  + ]
    1761                 :         24 :                 return -EILSEQ;
    1762                 :            :         }
    1763                 :            : 
    1764   [ +  +  +  +  :       7138 :         if (memcmp(&bs->bstype, &super->bstype, SPDK_BLOBSTORE_TYPE_LENGTH) == 0) {
          +  +  +  -  +  
                      + ]
    1765   [ +  +  +  +  :       7036 :                 SPDK_DEBUGLOG(blob, "Bstype matched - loading blobstore\n");
                   +  - ]
    1766   [ +  +  +  +  :       1200 :         } else if (memcmp(&bs->bstype, zeros, SPDK_BLOBSTORE_TYPE_LENGTH) == 0) {
             +  -  +  + ]
    1767   [ +  +  +  +  :         46 :                 SPDK_DEBUGLOG(blob, "Bstype wildcard used - loading blobstore regardless bstype\n");
                   +  - ]
    1768                 :          6 :         } else {
    1769   [ +  +  +  +  :         56 :                 SPDK_DEBUGLOG(blob, "Unexpected bstype\n");
                   +  - ]
    1770   [ +  +  +  +  :         56 :                 SPDK_LOGDUMP(blob, "Expected:", bs->bstype.bstype, SPDK_BLOBSTORE_TYPE_LENGTH);
          +  -  #  #  #  
                      # ]
    1771   [ +  +  +  +  :         56 :                 SPDK_LOGDUMP(blob, "Found:", super->bstype.bstype, SPDK_BLOBSTORE_TYPE_LENGTH);
          +  -  #  #  #  
                      # ]
    1772                 :         56 :                 return -ENXIO;
    1773                 :            :         }
    1774                 :            : 
    1775   [ +  +  +  -  :       7082 :         if (super->size > bs->dev->blockcnt * bs->dev->blocklen) {
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  + ]
    1776   [ +  -  +  -  :         48 :                 SPDK_NOTICELOG("Size mismatch, dev size: %" PRIu64 ", blobstore size: %" PRIu64 "\n",
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    1777                 :            :                                bs->dev->blockcnt * bs->dev->blocklen, super->size);
    1778                 :         48 :                 return -EILSEQ;
    1779                 :            :         }
    1780                 :            : 
    1781                 :       7034 :         return 0;
    1782                 :       1169 : }
    1783                 :            : 
    1784                 :            : static void bs_mark_dirty(spdk_bs_sequence_t *seq, struct spdk_blob_store *bs,
    1785                 :            :                           spdk_bs_sequence_cpl cb_fn, void *cb_arg);
    1786                 :            : 
    1787                 :            : static void
    1788                 :     185092 : blob_persist_complete_cb(void *arg)
    1789                 :            : {
    1790                 :     185092 :         struct spdk_blob_persist_ctx *ctx = arg;
    1791                 :            : 
    1792                 :            :         /* Call user callback */
    1793   [ +  -  +  -  :     185092 :         ctx->cb_fn(ctx->seq, ctx->cb_arg, 0);
          -  +  +  -  +  
          -  +  -  +  -  
                   +  - ]
    1794                 :            : 
    1795                 :            :         /* Free the memory */
    1796   [ +  -  +  - ]:     185092 :         spdk_free(ctx->pages);
    1797                 :     185092 :         free(ctx);
    1798                 :     185092 : }
    1799                 :            : 
    1800                 :            : static void blob_persist_start(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno);
    1801                 :            : 
    1802                 :            : static void
    1803                 :     185092 : blob_persist_complete(spdk_bs_sequence_t *seq, struct spdk_blob_persist_ctx *ctx, int bserrno)
    1804                 :            : {
    1805                 :       4676 :         struct spdk_blob_persist_ctx    *next_persist, *tmp;
    1806   [ +  -  +  - ]:     185092 :         struct spdk_blob                *blob = ctx->blob;
    1807                 :            : 
    1808         [ +  + ]:     185092 :         if (bserrno == 0) {
    1809                 :     184780 :                 blob_mark_clean(blob);
    1810                 :       4624 :         }
    1811                 :            : 
    1812   [ +  +  +  -  :     185092 :         assert(ctx == TAILQ_FIRST(&blob->persists_to_complete));
          +  -  +  -  #  
                      # ]
    1813                 :            : 
    1814                 :            :         /* Complete all persists that were pending when the current persist started */
    1815   [ +  +  +  -  :     370184 :         TAILQ_FOREACH_SAFE(next_persist, &blob->persists_to_complete, link, tmp) {
          +  -  +  +  +  
          -  +  -  +  -  
                   +  + ]
    1816   [ +  +  +  -  :     185092 :                 TAILQ_REMOVE(&blob->persists_to_complete, next_persist, link);
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    1817                 :     185092 :                 spdk_thread_send_msg(spdk_get_thread(), blob_persist_complete_cb, next_persist);
    1818                 :       4676 :         }
    1819                 :            : 
    1820   [ +  +  +  -  :     185092 :         if (TAILQ_EMPTY(&blob->pending_persists)) {
             +  -  +  + ]
    1821                 :     184965 :                 return;
    1822                 :            :         }
    1823                 :            : 
    1824                 :            :         /* Queue up all pending persists for completion and start blob persist with first one */
    1825   [ +  -  +  +  :        127 :         TAILQ_SWAP(&blob->persists_to_complete, &blob->pending_persists, spdk_blob_persist_ctx, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  -  +  
          #  #  #  #  #  
          #  #  #  #  #  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    1826   [ +  -  +  -  :        127 :         next_persist = TAILQ_FIRST(&blob->persists_to_complete);
                   +  - ]
    1827                 :            : 
    1828   [ +  -  +  - ]:        127 :         blob->state = SPDK_BLOB_STATE_DIRTY;
    1829   [ +  -  +  - ]:        127 :         bs_mark_dirty(seq, blob->bs, blob_persist_start, next_persist);
    1830         [ -  + ]:       4676 : }
    1831                 :            : 
    1832                 :            : static void
    1833                 :     184780 : blob_persist_clear_extents_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    1834                 :            : {
    1835                 :     184780 :         struct spdk_blob_persist_ctx    *ctx = cb_arg;
    1836   [ +  -  +  - ]:     184780 :         struct spdk_blob                *blob = ctx->blob;
    1837   [ +  -  +  - ]:     184780 :         struct spdk_blob_store          *bs = blob->bs;
    1838                 :       4624 :         size_t                          i;
    1839                 :            : 
    1840         [ -  + ]:     184780 :         if (bserrno != 0) {
    1841                 :          0 :                 blob_persist_complete(seq, ctx, bserrno);
    1842                 :          0 :                 return;
    1843                 :            :         }
    1844                 :            : 
    1845         [ +  - ]:     184780 :         spdk_spin_lock(&bs->used_lock);
    1846                 :            : 
    1847                 :            :         /* Release all extent_pages that were truncated */
    1848   [ +  +  +  -  :     201693 :         for (i = blob->active.num_extent_pages; i < blob->active.extent_pages_array_size; i++) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    1849                 :            :                 /* Nothing to release if it was not allocated */
    1850   [ +  +  +  -  :      16913 :                 if (blob->active.extent_pages[i] != 0) {
          +  -  +  -  +  
                -  +  + ]
    1851   [ -  +  -  +  :      10085 :                         bs_release_md_page(bs, blob->active.extent_pages[i]);
          -  +  -  +  -  
                      + ]
    1852                 :        620 :                 }
    1853                 :       1718 :         }
    1854                 :            : 
    1855         [ +  - ]:     184780 :         spdk_spin_unlock(&bs->used_lock);
    1856                 :            : 
    1857   [ +  +  +  -  :     184780 :         if (blob->active.num_extent_pages == 0) {
             +  -  +  + ]
    1858   [ +  -  +  -  :      24075 :                 free(blob->active.extent_pages);
                   +  - ]
    1859   [ +  -  +  -  :      24075 :                 blob->active.extent_pages = NULL;
                   +  - ]
    1860   [ +  -  +  -  :      24075 :                 blob->active.extent_pages_array_size = 0;
                   +  - ]
    1861   [ +  +  +  -  :     163994 :         } else if (blob->active.num_extent_pages != blob->active.extent_pages_array_size) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    1862                 :            : #ifndef __clang_analyzer__
    1863                 :          2 :                 void *tmp;
    1864                 :            : 
    1865                 :            :                 /* scan-build really can't figure reallocs, workaround it */
    1866   [ +  -  +  -  :         12 :                 tmp = realloc(blob->active.extent_pages, sizeof(uint32_t) * blob->active.num_extent_pages);
          +  -  +  -  +  
                -  +  - ]
    1867   [ +  +  #  # ]:         12 :                 assert(tmp != NULL);
    1868   [ +  -  +  -  :         12 :                 blob->active.extent_pages = tmp;
                   +  - ]
    1869                 :            : #endif
    1870   [ +  -  +  -  :         12 :                 blob->active.extent_pages_array_size = blob->active.num_extent_pages;
          +  -  +  -  +  
                -  +  - ]
    1871                 :          2 :         }
    1872                 :            : 
    1873                 :     184780 :         blob_persist_complete(seq, ctx, bserrno);
    1874         [ -  + ]:       4624 : }
    1875                 :            : 
    1876                 :            : static void
    1877                 :     184780 : blob_persist_clear_extents(spdk_bs_sequence_t *seq, struct spdk_blob_persist_ctx *ctx)
    1878                 :            : {
    1879   [ +  -  +  - ]:     184780 :         struct spdk_blob                *blob = ctx->blob;
    1880   [ +  -  +  - ]:     184780 :         struct spdk_blob_store          *bs = blob->bs;
    1881                 :       4624 :         size_t                          i;
    1882                 :       4624 :         uint64_t                        lba;
    1883                 :       4624 :         uint64_t                        lba_count;
    1884                 :       4624 :         spdk_bs_batch_t                 *batch;
    1885                 :            : 
    1886                 :     184780 :         batch = bs_sequence_to_batch(seq, blob_persist_clear_extents_cpl, ctx);
    1887                 :     184780 :         lba_count = bs_byte_to_lba(bs, SPDK_BS_PAGE_SIZE);
    1888                 :            : 
    1889                 :            :         /* Clear all extent_pages that were truncated */
    1890   [ +  +  +  -  :     201693 :         for (i = blob->active.num_extent_pages; i < blob->active.extent_pages_array_size; i++) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    1891                 :            :                 /* Nothing to clear if it was not allocated */
    1892   [ +  +  +  -  :      16913 :                 if (blob->active.extent_pages[i] != 0) {
          +  -  +  -  +  
                -  +  + ]
    1893   [ +  -  +  -  :      10085 :                         lba = bs_md_page_to_lba(bs, blob->active.extent_pages[i]);
          +  -  +  -  +  
                      - ]
    1894                 :      10085 :                         bs_batch_write_zeroes_dev(batch, lba, lba_count);
    1895                 :        620 :                 }
    1896                 :       1718 :         }
    1897                 :            : 
    1898                 :     184780 :         bs_batch_close(batch);
    1899                 :     184780 : }
    1900                 :            : 
    1901                 :            : static void
    1902                 :     184780 : blob_persist_clear_clusters_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    1903                 :            : {
    1904                 :     184780 :         struct spdk_blob_persist_ctx    *ctx = cb_arg;
    1905   [ +  -  +  - ]:     184780 :         struct spdk_blob                *blob = ctx->blob;
    1906   [ +  -  +  - ]:     184780 :         struct spdk_blob_store          *bs = blob->bs;
    1907                 :       4624 :         size_t                          i;
    1908                 :            : 
    1909         [ -  + ]:     184780 :         if (bserrno != 0) {
    1910                 :          0 :                 blob_persist_complete(seq, ctx, bserrno);
    1911                 :          0 :                 return;
    1912                 :            :         }
    1913                 :            : 
    1914         [ +  - ]:     184780 :         spdk_spin_lock(&bs->used_lock);
    1915                 :            :         /* Release all clusters that were truncated */
    1916   [ +  +  +  -  :    9431384 :         for (i = blob->active.num_clusters; i < blob->active.cluster_array_size; i++) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    1917   [ +  -  +  -  :    9246604 :                 uint32_t cluster_num = bs_lba_to_cluster(bs, blob->active.clusters[i]);
          +  -  +  -  +  
                      - ]
    1918                 :            : 
    1919                 :            :                 /* Nothing to release if it was not allocated */
    1920   [ +  +  +  -  :    9246604 :                 if (blob->active.clusters[i] != 0) {
          +  -  +  -  +  
                -  +  + ]
    1921                 :    2303040 :                         bs_release_cluster(bs, cluster_num);
    1922                 :       2311 :                 }
    1923                 :    1068851 :         }
    1924         [ +  - ]:     184780 :         spdk_spin_unlock(&bs->used_lock);
    1925                 :            : 
    1926   [ +  +  +  -  :     184780 :         if (blob->active.num_clusters == 0) {
             +  -  +  + ]
    1927   [ +  -  +  -  :      14997 :                 free(blob->active.clusters);
                   +  - ]
    1928   [ +  -  +  -  :      14997 :                 blob->active.clusters = NULL;
                   +  - ]
    1929   [ +  -  +  -  :      14997 :                 blob->active.cluster_array_size = 0;
                   +  - ]
    1930   [ +  +  +  -  :     171559 :         } else if (blob->active.num_clusters != blob->active.cluster_array_size) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    1931                 :            : #ifndef __clang_analyzer__
    1932                 :         10 :                 void *tmp;
    1933                 :            : 
    1934                 :            :                 /* scan-build really can't figure reallocs, workaround it */
    1935   [ +  -  +  -  :         63 :                 tmp = realloc(blob->active.clusters, sizeof(*blob->active.clusters) * blob->active.num_clusters);
          +  -  +  -  +  
                -  +  - ]
    1936   [ +  +  #  # ]:         63 :                 assert(tmp != NULL);
    1937   [ +  -  +  -  :         63 :                 blob->active.clusters = tmp;
                   +  - ]
    1938                 :            : 
    1939                 :            : #endif
    1940   [ +  -  +  -  :         63 :                 blob->active.cluster_array_size = blob->active.num_clusters;
          +  -  +  -  +  
                -  +  - ]
    1941                 :         10 :         }
    1942                 :            : 
    1943                 :            :         /* Move on to clearing extent pages */
    1944                 :     184780 :         blob_persist_clear_extents(seq, ctx);
    1945         [ -  + ]:       4624 : }
    1946                 :            : 
    1947                 :            : static void
    1948                 :     184780 : blob_persist_clear_clusters(spdk_bs_sequence_t *seq, struct spdk_blob_persist_ctx *ctx)
    1949                 :            : {
    1950   [ +  -  +  - ]:     184780 :         struct spdk_blob                *blob = ctx->blob;
    1951   [ +  -  +  - ]:     184780 :         struct spdk_blob_store          *bs = blob->bs;
    1952                 :       4624 :         spdk_bs_batch_t                 *batch;
    1953                 :       4624 :         size_t                          i;
    1954                 :       4624 :         uint64_t                        lba;
    1955                 :       4624 :         uint64_t                        lba_count;
    1956                 :            : 
    1957                 :            :         /* Clusters don't move around in blobs. The list shrinks or grows
    1958                 :            :          * at the end, but no changes ever occur in the middle of the list.
    1959                 :            :          */
    1960                 :            : 
    1961                 :     184780 :         batch = bs_sequence_to_batch(seq, blob_persist_clear_clusters_cpl, ctx);
    1962                 :            : 
    1963                 :            :         /* Clear all clusters that were truncated */
    1964                 :     184780 :         lba = 0;
    1965                 :     184780 :         lba_count = 0;
    1966   [ +  +  +  -  :    9431384 :         for (i = blob->active.num_clusters; i < blob->active.cluster_array_size; i++) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    1967   [ +  -  +  -  :    9246604 :                 uint64_t next_lba = blob->active.clusters[i];
          +  -  +  -  +  
                      - ]
    1968                 :    9246604 :                 uint64_t next_lba_count = bs_cluster_to_lba(bs, 1);
    1969                 :            : 
    1970   [ +  +  +  + ]:    9246604 :                 if (next_lba > 0 && (lba + lba_count) == next_lba) {
    1971                 :            :                         /* This cluster is contiguous with the previous one. */
    1972                 :    2268805 :                         lba_count += next_lba_count;
    1973                 :    2268805 :                         continue;
    1974         [ +  + ]:    6977799 :                 } else if (next_lba == 0) {
    1975                 :    6943564 :                         continue;
    1976                 :            :                 }
    1977                 :            : 
    1978                 :            :                 /* This cluster is not contiguous with the previous one. */
    1979                 :            : 
    1980                 :            :                 /* If a run of LBAs previously existing, clear them now */
    1981         [ +  + ]:      34235 :                 if (lba_count > 0) {
    1982                 :      25678 :                         bs_batch_clear_dev(ctx, batch, lba, lba_count);
    1983                 :         36 :                 }
    1984                 :            : 
    1985                 :            :                 /* Start building the next batch */
    1986                 :      34235 :                 lba = next_lba;
    1987         [ +  - ]:      34235 :                 if (next_lba > 0) {
    1988                 :      34235 :                         lba_count = next_lba_count;
    1989                 :       1242 :                 } else {
    1990                 :          0 :                         lba_count = 0;
    1991                 :            :                 }
    1992      [ -  +  + ]:    1068851 :         }
    1993                 :            : 
    1994                 :            :         /* If we ended with a contiguous set of LBAs, clear them now */
    1995         [ +  + ]:     184780 :         if (lba_count > 0) {
    1996                 :       8557 :                 bs_batch_clear_dev(ctx, batch, lba, lba_count);
    1997                 :       1206 :         }
    1998                 :            : 
    1999                 :     184780 :         bs_batch_close(batch);
    2000                 :     184780 : }
    2001                 :            : 
    2002                 :            : static void
    2003                 :     184804 : blob_persist_zero_pages_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2004                 :            : {
    2005                 :     184804 :         struct spdk_blob_persist_ctx    *ctx = cb_arg;
    2006   [ +  -  +  - ]:     184804 :         struct spdk_blob                *blob = ctx->blob;
    2007   [ +  -  +  - ]:     184804 :         struct spdk_blob_store          *bs = blob->bs;
    2008                 :       4628 :         size_t                          i;
    2009                 :            : 
    2010         [ +  + ]:     184804 :         if (bserrno != 0) {
    2011                 :         24 :                 blob_persist_complete(seq, ctx, bserrno);
    2012                 :         24 :                 return;
    2013                 :            :         }
    2014                 :            : 
    2015         [ +  - ]:     184780 :         spdk_spin_lock(&bs->used_lock);
    2016                 :            : 
    2017                 :            :         /* This loop starts at 1 because the first page is special and handled
    2018                 :            :          * below. The pages (except the first) are never written in place,
    2019                 :            :          * so any pages in the clean list must be zeroed.
    2020                 :            :          */
    2021   [ +  +  +  -  :     185795 :         for (i = 1; i < blob->clean.num_pages; i++) {
             +  -  +  + ]
    2022   [ +  -  +  -  :       1015 :                 bs_release_md_page(bs, blob->clean.pages[i]);
          +  -  +  -  +  
                      - ]
    2023                 :         68 :         }
    2024                 :            : 
    2025   [ +  +  +  -  :     184780 :         if (blob->active.num_pages == 0) {
             +  -  +  + ]
    2026                 :       1416 :                 uint32_t page_num;
    2027                 :            : 
    2028   [ +  -  +  - ]:       9965 :                 page_num = bs_blobid_to_page(blob->id);
    2029                 :       9965 :                 bs_release_md_page(bs, page_num);
    2030                 :       1416 :         }
    2031                 :            : 
    2032         [ +  - ]:     184780 :         spdk_spin_unlock(&bs->used_lock);
    2033                 :            : 
    2034                 :            :         /* Move on to clearing clusters */
    2035                 :     184780 :         blob_persist_clear_clusters(seq, ctx);
    2036         [ -  + ]:       4628 : }
    2037                 :            : 
    2038                 :            : static void
    2039                 :     185044 : blob_persist_zero_pages(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2040                 :            : {
    2041                 :     185044 :         struct spdk_blob_persist_ctx    *ctx = cb_arg;
    2042   [ +  -  +  - ]:     185044 :         struct spdk_blob                *blob = ctx->blob;
    2043   [ +  -  +  - ]:     185044 :         struct spdk_blob_store          *bs = blob->bs;
    2044                 :       4668 :         uint64_t                        lba;
    2045                 :       4668 :         uint64_t                        lba_count;
    2046                 :       4668 :         spdk_bs_batch_t                 *batch;
    2047                 :       4668 :         size_t                          i;
    2048                 :            : 
    2049         [ +  + ]:     185044 :         if (bserrno != 0) {
    2050                 :        240 :                 blob_persist_complete(seq, ctx, bserrno);
    2051                 :        240 :                 return;
    2052                 :            :         }
    2053                 :            : 
    2054                 :     184804 :         batch = bs_sequence_to_batch(seq, blob_persist_zero_pages_cpl, ctx);
    2055                 :            : 
    2056                 :     184804 :         lba_count = bs_byte_to_lba(bs, SPDK_BS_PAGE_SIZE);
    2057                 :            : 
    2058                 :            :         /* This loop starts at 1 because the first page is special and handled
    2059                 :            :          * below. The pages (except the first) are never written in place,
    2060                 :            :          * so any pages in the clean list must be zeroed.
    2061                 :            :          */
    2062   [ +  +  +  -  :     185819 :         for (i = 1; i < blob->clean.num_pages; i++) {
             +  -  +  + ]
    2063   [ +  -  +  -  :       1015 :                 lba = bs_md_page_to_lba(bs, blob->clean.pages[i]);
          +  -  +  -  +  
                      - ]
    2064                 :            : 
    2065                 :       1015 :                 bs_batch_write_zeroes_dev(batch, lba, lba_count);
    2066                 :         68 :         }
    2067                 :            : 
    2068                 :            :         /* The first page will only be zeroed if this is a delete. */
    2069   [ +  +  +  -  :     184804 :         if (blob->active.num_pages == 0) {
             +  -  +  + ]
    2070                 :       1420 :                 uint32_t page_num;
    2071                 :            : 
    2072                 :            :                 /* The first page in the metadata goes where the blobid indicates */
    2073   [ +  -  +  - ]:       9989 :                 page_num = bs_blobid_to_page(blob->id);
    2074                 :       9989 :                 lba = bs_md_page_to_lba(bs, page_num);
    2075                 :            : 
    2076                 :       9989 :                 bs_batch_write_zeroes_dev(batch, lba, lba_count);
    2077                 :       1420 :         }
    2078                 :            : 
    2079                 :     184804 :         bs_batch_close(batch);
    2080         [ -  + ]:       4668 : }
    2081                 :            : 
    2082                 :            : static void
    2083                 :     175055 : blob_persist_write_page_root(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2084                 :            : {
    2085                 :     175055 :         struct spdk_blob_persist_ctx    *ctx = cb_arg;
    2086   [ +  -  +  - ]:     175055 :         struct spdk_blob                *blob = ctx->blob;
    2087   [ +  -  +  - ]:     175055 :         struct spdk_blob_store          *bs = blob->bs;
    2088                 :       3248 :         uint64_t                        lba;
    2089                 :       3248 :         uint32_t                        lba_count;
    2090                 :       3248 :         struct spdk_blob_md_page        *page;
    2091                 :            : 
    2092         [ -  + ]:     175055 :         if (bserrno != 0) {
    2093                 :          0 :                 blob_persist_complete(seq, ctx, bserrno);
    2094                 :          0 :                 return;
    2095                 :            :         }
    2096                 :            : 
    2097   [ +  +  +  -  :     175055 :         if (blob->active.num_pages == 0) {
             +  -  +  - ]
    2098                 :            :                 /* Move on to the next step */
    2099                 :          0 :                 blob_persist_zero_pages(seq, ctx, 0);
    2100                 :          0 :                 return;
    2101                 :            :         }
    2102                 :            : 
    2103                 :     175055 :         lba_count = bs_byte_to_lba(bs, sizeof(*page));
    2104                 :            : 
    2105   [ +  -  +  -  :     175055 :         page = &ctx->pages[0];
                   +  - ]
    2106                 :            :         /* The first page in the metadata goes where the blobid indicates */
    2107   [ +  -  +  - ]:     175055 :         lba = bs_md_page_to_lba(bs, bs_blobid_to_page(blob->id));
    2108                 :            : 
    2109                 :     178303 :         bs_sequence_write_dev(seq, page, lba, lba_count,
    2110                 :       3248 :                               blob_persist_zero_pages, ctx);
    2111         [ -  + ]:       3248 : }
    2112                 :            : 
    2113                 :            : static void
    2114                 :     175055 : blob_persist_write_page_chain(spdk_bs_sequence_t *seq, struct spdk_blob_persist_ctx *ctx)
    2115                 :            : {
    2116   [ +  -  +  - ]:     175055 :         struct spdk_blob                *blob = ctx->blob;
    2117   [ +  -  +  - ]:     175055 :         struct spdk_blob_store          *bs = blob->bs;
    2118                 :       3248 :         uint64_t                        lba;
    2119                 :       3248 :         uint32_t                        lba_count;
    2120                 :       3248 :         struct spdk_blob_md_page        *page;
    2121                 :       3248 :         spdk_bs_batch_t                 *batch;
    2122                 :       3248 :         size_t                          i;
    2123                 :            : 
    2124                 :            :         /* Clusters don't move around in blobs. The list shrinks or grows
    2125                 :            :          * at the end, but no changes ever occur in the middle of the list.
    2126                 :            :          */
    2127                 :            : 
    2128                 :     175055 :         lba_count = bs_byte_to_lba(bs, sizeof(*page));
    2129                 :            : 
    2130                 :     175055 :         batch = bs_sequence_to_batch(seq, blob_persist_write_page_root, ctx);
    2131                 :            : 
    2132                 :            :         /* This starts at 1. The root page is not written until
    2133                 :            :          * all of the others are finished
    2134                 :            :          */
    2135   [ +  +  +  -  :     176190 :         for (i = 1; i < blob->active.num_pages; i++) {
             +  -  +  + ]
    2136   [ +  -  +  -  :       1135 :                 page = &ctx->pages[i];
                   +  - ]
    2137   [ +  +  +  -  :       1135 :                 assert(page->sequence_num == i);
             +  -  #  # ]
    2138                 :            : 
    2139   [ +  -  +  -  :       1135 :                 lba = bs_md_page_to_lba(bs, blob->active.pages[i]);
          +  -  +  -  +  
                      - ]
    2140                 :            : 
    2141                 :       1135 :                 bs_batch_write_dev(batch, page, lba, lba_count);
    2142                 :         88 :         }
    2143                 :            : 
    2144                 :     175055 :         bs_batch_close(batch);
    2145                 :     175055 : }
    2146                 :            : 
    2147                 :            : static int
    2148                 :     139257 : blob_resize(struct spdk_blob *blob, uint64_t sz)
    2149                 :            : {
    2150                 :       3392 :         uint64_t        i;
    2151                 :       3392 :         uint64_t        *tmp;
    2152                 :     135317 :         uint64_t        cluster;
    2153                 :     135317 :         uint32_t        lfmd; /*  lowest free md page */
    2154                 :       3392 :         uint64_t        num_clusters;
    2155                 :       3392 :         uint32_t        *ep_tmp;
    2156                 :     139257 :         uint64_t        new_num_ep = 0, current_num_ep = 0;
    2157                 :       3392 :         struct spdk_blob_store *bs;
    2158                 :       3392 :         int             rc;
    2159                 :            : 
    2160   [ +  -  +  - ]:     139257 :         bs = blob->bs;
    2161                 :            : 
    2162                 :     139257 :         blob_verify_md_op(blob);
    2163                 :            : 
    2164   [ +  +  +  -  :     139257 :         if (blob->active.num_clusters == sz) {
             +  -  +  + ]
    2165                 :       5063 :                 return 0;
    2166                 :            :         }
    2167                 :            : 
    2168   [ +  +  +  -  :     134194 :         if (blob->active.num_clusters < blob->active.cluster_array_size) {
          +  -  +  -  +  
             -  +  -  -  
                      + ]
    2169                 :            :                 /* If this blob was resized to be larger, then smaller, then
    2170                 :            :                  * larger without syncing, then the cluster array already
    2171                 :            :                  * contains spare assigned clusters we can use.
    2172                 :            :                  */
    2173   [ #  #  #  #  :          0 :                 num_clusters = spdk_min(blob->active.cluster_array_size,
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    2174                 :            :                                         sz);
    2175                 :          0 :         } else {
    2176   [ +  -  +  -  :     134194 :                 num_clusters = blob->active.num_clusters;
                   +  - ]
    2177                 :            :         }
    2178                 :            : 
    2179   [ +  +  +  +  :     134194 :         if (blob->use_extent_table) {
             +  -  +  + ]
    2180                 :            :                 /* Round up since every cluster beyond current Extent Table size,
    2181                 :            :                  * requires new extent page. */
    2182         [ +  - ]:     125278 :                 new_num_ep = spdk_divide_round_up(sz, SPDK_EXTENTS_PER_EP);
    2183         [ +  - ]:     125278 :                 current_num_ep = spdk_divide_round_up(num_clusters, SPDK_EXTENTS_PER_EP);
    2184                 :       1530 :         }
    2185                 :            : 
    2186   [ +  +  +  -  :     134194 :         assert(!spdk_spin_held(&bs->used_lock));
                   #  # ]
    2187                 :            : 
    2188                 :            :         /* Check first that we have enough clusters and md pages before we start claiming them.
    2189                 :            :          * bs->used_lock is held to ensure that clusters we think are free are still free when we go
    2190                 :            :          * to claim them later in this function.
    2191                 :            :          */
    2192   [ +  +  +  + ]:     134194 :         if (sz > num_clusters && spdk_blob_is_thin_provisioned(blob) == false) {
    2193         [ +  - ]:     122424 :                 spdk_spin_lock(&bs->used_lock);
    2194   [ +  +  +  -  :     122424 :                 if ((sz - num_clusters) > bs->num_free_clusters) {
                   +  + ]
    2195                 :         51 :                         rc = -ENOSPC;
    2196                 :         51 :                         goto out;
    2197                 :            :                 }
    2198                 :     122373 :                 lfmd = 0;
    2199         [ +  + ]:     133294 :                 for (i = current_num_ep; i < new_num_ep ; i++) {
    2200   [ +  -  +  -  :      10921 :                         lfmd = spdk_bit_array_find_first_clear(blob->bs->used_md_pages, lfmd);
             +  -  +  - ]
    2201         [ -  + ]:      10921 :                         if (lfmd == UINT32_MAX) {
    2202                 :            :                                 /* No more free md pages. Cannot satisfy the request */
    2203                 :          0 :                                 rc = -ENOSPC;
    2204                 :          0 :                                 goto out;
    2205                 :            :                         }
    2206                 :        642 :                 }
    2207                 :       1290 :         }
    2208                 :            : 
    2209         [ +  + ]:     134143 :         if (sz > num_clusters) {
    2210                 :            :                 /* Expand the cluster array if necessary.
    2211                 :            :                  * We only shrink the array when persisting.
    2212                 :            :                  */
    2213   [ +  -  +  -  :     124588 :                 tmp = realloc(blob->active.clusters, sizeof(*blob->active.clusters) * sz);
                   +  - ]
    2214   [ +  -  +  + ]:     124588 :                 if (sz > 0 && tmp == NULL) {
    2215                 :          0 :                         rc = -ENOMEM;
    2216                 :          0 :                         goto out;
    2217                 :            :                 }
    2218   [ +  +  +  -  :     126230 :                 memset(tmp + blob->active.cluster_array_size, 0,
          +  -  +  -  +  
                      - ]
    2219   [ +  -  +  -  :     124588 :                        sizeof(*blob->active.clusters) * (sz - blob->active.cluster_array_size));
                   +  - ]
    2220   [ +  -  +  -  :     124588 :                 blob->active.clusters = tmp;
                   +  - ]
    2221   [ +  -  +  -  :     124588 :                 blob->active.cluster_array_size = sz;
                   +  - ]
    2222                 :            : 
    2223                 :            :                 /* Expand the extents table, only if enough clusters were added */
    2224   [ +  +  +  +  :     124588 :                 if (new_num_ep > current_num_ep && blob->use_extent_table) {
          +  -  +  -  -  
                      + ]
    2225   [ +  -  +  -  :       7913 :                         ep_tmp = realloc(blob->active.extent_pages, sizeof(*blob->active.extent_pages) * new_num_ep);
                   +  - ]
    2226   [ +  -  +  + ]:       7913 :                         if (new_num_ep > 0 && ep_tmp == NULL) {
    2227                 :          0 :                                 rc = -ENOMEM;
    2228                 :          0 :                                 goto out;
    2229                 :            :                         }
    2230   [ +  +  +  -  :       8727 :                         memset(ep_tmp + blob->active.extent_pages_array_size, 0,
          +  -  +  -  +  
                      - ]
    2231   [ +  -  +  -  :       7913 :                                sizeof(*blob->active.extent_pages) * (new_num_ep - blob->active.extent_pages_array_size));
                   +  - ]
    2232   [ +  -  +  -  :       7913 :                         blob->active.extent_pages = ep_tmp;
                   +  - ]
    2233   [ +  -  +  -  :       7913 :                         blob->active.extent_pages_array_size = new_num_ep;
                   +  - ]
    2234                 :        814 :                 }
    2235                 :       1642 :         }
    2236                 :            : 
    2237   [ +  -  +  - ]:     134143 :         blob->state = SPDK_BLOB_STATE_DIRTY;
    2238                 :            : 
    2239         [ +  + ]:     134143 :         if (spdk_blob_is_thin_provisioned(blob) == false) {
    2240                 :     130457 :                 cluster = 0;
    2241                 :     130457 :                 lfmd = 0;
    2242         [ +  + ]:    2568881 :                 for (i = num_clusters; i < sz; i++) {
    2243                 :    2438424 :                         bs_allocate_cluster(blob, i, &cluster, &lfmd, true);
    2244                 :            :                         /* Do not increment lfmd here.  lfmd will get updated
    2245                 :            :                          * to the md_page allocated (if any) when a new extent
    2246                 :            :                          * page is needed.  Just pass that value again,
    2247                 :            :                          * bs_allocate_cluster will just start at that index
    2248                 :            :                          * to find the next free md_page when needed.
    2249                 :            :                          */
    2250                 :       7364 :                 }
    2251                 :       2424 :         }
    2252                 :            : 
    2253   [ +  -  +  -  :     134143 :         blob->active.num_clusters = sz;
                   +  - ]
    2254   [ +  -  +  -  :     134143 :         blob->active.num_extent_pages = new_num_ep;
                   +  - ]
    2255                 :            : 
    2256                 :     134143 :         rc = 0;
    2257                 :     131178 : out:
    2258   [ +  +  +  + ]:     134194 :         if (spdk_spin_held(&bs->used_lock)) {
    2259         [ +  - ]:     122424 :                 spdk_spin_unlock(&bs->used_lock);
    2260                 :       1298 :         }
    2261                 :            : 
    2262                 :     134194 :         return rc;
    2263                 :       3392 : }
    2264                 :            : 
    2265                 :            : static void
    2266                 :     175055 : blob_persist_generate_new_md(struct spdk_blob_persist_ctx *ctx)
    2267                 :            : {
    2268   [ +  -  +  - ]:     175055 :         spdk_bs_sequence_t *seq = ctx->seq;
    2269   [ +  -  +  - ]:     175055 :         struct spdk_blob *blob = ctx->blob;
    2270   [ +  -  +  - ]:     175055 :         struct spdk_blob_store *bs = blob->bs;
    2271                 :       3248 :         uint64_t i;
    2272                 :       3248 :         uint32_t page_num;
    2273                 :       3248 :         void *tmp;
    2274                 :       3248 :         int rc;
    2275                 :            : 
    2276                 :            :         /* Generate the new metadata */
    2277   [ +  -  +  -  :     175055 :         rc = blob_serialize(blob, &ctx->pages, &blob->active.num_pages);
                   +  - ]
    2278         [ +  + ]:     175055 :         if (rc < 0) {
    2279                 :          0 :                 blob_persist_complete(seq, ctx, rc);
    2280                 :          0 :                 return;
    2281                 :            :         }
    2282                 :            : 
    2283   [ +  +  +  -  :     175055 :         assert(blob->active.num_pages >= 1);
          +  -  +  -  #  
                      # ]
    2284                 :            : 
    2285                 :            :         /* Resize the cache of page indices */
    2286   [ +  -  +  -  :     175055 :         tmp = realloc(blob->active.pages, blob->active.num_pages * sizeof(*blob->active.pages));
          +  -  +  -  +  
                -  +  - ]
    2287         [ +  + ]:     175055 :         if (!tmp) {
    2288                 :          0 :                 blob_persist_complete(seq, ctx, -ENOMEM);
    2289                 :          0 :                 return;
    2290                 :            :         }
    2291   [ +  -  +  -  :     175055 :         blob->active.pages = tmp;
                   +  - ]
    2292                 :            : 
    2293                 :            :         /* Assign this metadata to pages. This requires two passes - one to verify that there are
    2294                 :            :          * enough pages and a second to actually claim them. The used_lock is held across
    2295                 :            :          * both passes to ensure things don't change in the middle.
    2296                 :            :          */
    2297         [ +  - ]:     175055 :         spdk_spin_lock(&bs->used_lock);
    2298                 :     175055 :         page_num = 0;
    2299                 :            :         /* Note that this loop starts at one. The first page location is fixed by the blobid. */
    2300   [ +  +  +  -  :     176190 :         for (i = 1; i < blob->active.num_pages; i++) {
             +  -  +  + ]
    2301   [ +  -  +  - ]:       1135 :                 page_num = spdk_bit_array_find_first_clear(bs->used_md_pages, page_num);
    2302         [ -  + ]:       1135 :                 if (page_num == UINT32_MAX) {
    2303         [ #  # ]:          0 :                         spdk_spin_unlock(&bs->used_lock);
    2304                 :          0 :                         blob_persist_complete(seq, ctx, -ENOMEM);
    2305                 :          0 :                         return;
    2306                 :            :                 }
    2307                 :       1135 :                 page_num++;
    2308                 :         88 :         }
    2309                 :            : 
    2310                 :     175055 :         page_num = 0;
    2311   [ +  -  +  -  :     175055 :         blob->active.pages[0] = bs_blobid_to_page(blob->id);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    2312   [ +  +  +  -  :     176190 :         for (i = 1; i < blob->active.num_pages; i++) {
             +  -  +  + ]
    2313   [ +  -  +  - ]:       1135 :                 page_num = spdk_bit_array_find_first_clear(bs->used_md_pages, page_num);
    2314   [ +  -  +  -  :       1135 :                 ctx->pages[i - 1].next = page_num;
          +  -  +  -  +  
                      - ]
    2315                 :            :                 /* Now that previous metadata page is complete, calculate the crc for it. */
    2316   [ +  -  +  -  :       1135 :                 ctx->pages[i - 1].crc = blob_md_page_calc_crc(&ctx->pages[i - 1]);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    2317   [ +  -  +  -  :       1135 :                 blob->active.pages[i] = page_num;
          +  -  +  -  +  
                      - ]
    2318                 :       1135 :                 bs_claim_md_page(bs, page_num);
    2319   [ +  +  +  +  :       1135 :                 SPDK_DEBUGLOG(blob, "Claiming page %u for blob 0x%" PRIx64 "\n", page_num,
          +  -  #  #  #  
                      # ]
    2320                 :            :                               blob->id);
    2321                 :       1135 :                 page_num++;
    2322                 :         88 :         }
    2323         [ +  - ]:     175055 :         spdk_spin_unlock(&bs->used_lock);
    2324   [ +  -  +  -  :     175055 :         ctx->pages[i - 1].crc = blob_md_page_calc_crc(&ctx->pages[i - 1]);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    2325                 :            :         /* Start writing the metadata from last page to first */
    2326   [ +  -  +  - ]:     175055 :         blob->state = SPDK_BLOB_STATE_CLEAN;
    2327                 :     175055 :         blob_persist_write_page_chain(seq, ctx);
    2328         [ -  + ]:       3248 : }
    2329                 :            : 
    2330                 :            : static void
    2331                 :     247223 : blob_persist_write_extent_pages(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2332                 :            : {
    2333                 :     247223 :         struct spdk_blob_persist_ctx    *ctx = cb_arg;
    2334   [ +  -  +  - ]:     247223 :         struct spdk_blob                *blob = ctx->blob;
    2335                 :       2282 :         size_t                          i;
    2336                 :       2282 :         uint32_t                        extent_page_id;
    2337                 :     247223 :         uint32_t                        page_count = 0;
    2338                 :       2282 :         int                             rc;
    2339                 :            : 
    2340   [ +  +  +  -  :     247223 :         if (ctx->extent_page != NULL) {
                   +  + ]
    2341   [ +  -  +  - ]:     122738 :                 spdk_free(ctx->extent_page);
    2342   [ +  -  +  - ]:     122738 :                 ctx->extent_page = NULL;
    2343                 :        658 :         }
    2344                 :            : 
    2345         [ -  + ]:     247223 :         if (bserrno != 0) {
    2346                 :          0 :                 blob_persist_complete(seq, ctx, bserrno);
    2347                 :       2400 :                 return;
    2348                 :            :         }
    2349                 :            : 
    2350                 :            :         /* Only write out Extent Pages when blob was resized. */
    2351   [ +  +  +  -  :     261806 :         for (i = ctx->next_extent_page; i < blob->active.extent_pages_array_size; i++) {
          +  -  +  -  +  
                -  +  + ]
    2352   [ +  -  +  -  :     137321 :                 extent_page_id = blob->active.extent_pages[i];
          +  -  +  -  +  
                      - ]
    2353         [ +  + ]:     137321 :                 if (extent_page_id == 0) {
    2354                 :            :                         /* No Extent Page to persist */
    2355   [ +  +  #  # ]:      14583 :                         assert(spdk_blob_is_thin_provisioned(blob));
    2356                 :      14583 :                         continue;
    2357                 :            :                 }
    2358   [ +  +  +  -  :     122738 :                 assert(spdk_bit_array_get(blob->bs->used_md_pages, extent_page_id));
          +  -  +  -  +  
                -  #  # ]
    2359   [ +  -  +  - ]:     122738 :                 ctx->next_extent_page = i + 1;
    2360   [ +  -  +  -  :     122738 :                 rc = blob_serialize_add_page(ctx->blob, &ctx->extent_page, &page_count, &ctx->extent_page);
             +  -  +  - ]
    2361         [ +  + ]:     122738 :                 if (rc < 0) {
    2362                 :          0 :                         blob_persist_complete(seq, ctx, rc);
    2363                 :          0 :                         return;
    2364                 :            :                 }
    2365                 :            : 
    2366   [ +  -  +  - ]:     122738 :                 blob->state = SPDK_BLOB_STATE_DIRTY;
    2367   [ +  -  +  -  :     122738 :                 blob_serialize_extent_page(blob, i * SPDK_EXTENTS_PER_EP, ctx->extent_page);
                   +  - ]
    2368                 :            : 
    2369   [ +  -  +  -  :     122738 :                 ctx->extent_page->crc = blob_md_page_calc_crc(ctx->extent_page);
          +  -  +  -  +  
                -  +  - ]
    2370                 :            : 
    2371   [ +  -  +  -  :     123396 :                 bs_sequence_write_dev(seq, ctx->extent_page, bs_md_page_to_lba(blob->bs, extent_page_id),
             +  -  +  - ]
    2372   [ +  -  +  - ]:     122738 :                                       bs_byte_to_lba(blob->bs, SPDK_BS_PAGE_SIZE),
    2373                 :        658 :                                       blob_persist_write_extent_pages, ctx);
    2374                 :     122738 :                 return;
    2375                 :            :         }
    2376                 :            : 
    2377                 :     124485 :         blob_persist_generate_new_md(ctx);
    2378         [ -  + ]:       2282 : }
    2379                 :            : 
    2380                 :            : static void
    2381                 :     185092 : blob_persist_start(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2382                 :            : {
    2383                 :     185092 :         struct spdk_blob_persist_ctx *ctx = cb_arg;
    2384   [ +  -  +  - ]:     185092 :         struct spdk_blob *blob = ctx->blob;
    2385                 :            : 
    2386         [ +  + ]:     185092 :         if (bserrno != 0) {
    2387                 :         48 :                 blob_persist_complete(seq, ctx, bserrno);
    2388                 :         48 :                 return;
    2389                 :            :         }
    2390                 :            : 
    2391   [ +  +  +  -  :     185044 :         if (blob->active.num_pages == 0) {
             +  -  +  + ]
    2392                 :            :                 /* This is the signal that the blob should be deleted.
    2393                 :            :                  * Immediately jump to the clean up routine. */
    2394   [ +  +  +  -  :       9989 :                 assert(blob->clean.num_pages > 0);
          +  -  +  -  #  
                      # ]
    2395   [ +  -  +  - ]:       9989 :                 blob->state = SPDK_BLOB_STATE_CLEAN;
    2396                 :       9989 :                 blob_persist_zero_pages(seq, ctx, 0);
    2397                 :       9989 :                 return;
    2398                 :            : 
    2399                 :            :         }
    2400                 :            : 
    2401   [ +  +  +  -  :     175055 :         if (blob->clean.num_clusters < blob->active.num_clusters) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    2402                 :            :                 /* Blob was resized up */
    2403   [ +  +  +  -  :     124420 :                 assert(blob->clean.num_extent_pages <= blob->active.num_extent_pages);
          +  -  +  -  +  
          -  +  -  +  -  
                   #  # ]
    2404   [ +  +  +  -  :     124420 :                 ctx->next_extent_page = spdk_max(1, blob->clean.num_extent_pages) - 1;
          +  -  +  +  +  
          -  +  -  +  -  
             +  -  +  - ]
    2405   [ +  +  +  -  :      52249 :         } else if (blob->active.num_clusters < blob->active.cluster_array_size) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    2406                 :            :                 /* Blob was resized down */
    2407   [ +  +  +  -  :         65 :                 assert(blob->clean.num_extent_pages >= blob->active.num_extent_pages);
          +  -  +  -  +  
          -  +  -  +  -  
                   #  # ]
    2408   [ +  +  +  -  :         65 :                 ctx->next_extent_page = spdk_max(1, blob->active.num_extent_pages) - 1;
          +  -  +  +  +  
          -  +  -  +  -  
             +  -  +  - ]
    2409                 :         10 :         } else {
    2410                 :            :                 /* No change in size occurred */
    2411                 :      50570 :                 blob_persist_generate_new_md(ctx);
    2412                 :      50570 :                 return;
    2413                 :            :         }
    2414                 :            : 
    2415                 :     124485 :         blob_persist_write_extent_pages(seq, ctx, 0);
    2416         [ -  + ]:       4676 : }
    2417                 :            : 
    2418                 :            : struct spdk_bs_mark_dirty {
    2419                 :            :         struct spdk_blob_store          *bs;
    2420                 :            :         struct spdk_bs_super_block      *super;
    2421                 :            :         spdk_bs_sequence_cpl            cb_fn;
    2422                 :            :         void                            *cb_arg;
    2423                 :            : };
    2424                 :            : 
    2425                 :            : static void
    2426                 :        990 : bs_mark_dirty_write_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2427                 :            : {
    2428                 :        990 :         struct spdk_bs_mark_dirty *ctx = cb_arg;
    2429                 :            : 
    2430         [ +  + ]:        990 :         if (bserrno == 0) {
    2431   [ +  -  +  -  :        942 :                 ctx->bs->clean = 0;
             +  -  +  - ]
    2432                 :        150 :         }
    2433                 :            : 
    2434   [ +  -  +  -  :        990 :         ctx->cb_fn(seq, ctx->cb_arg, bserrno);
          -  +  +  -  +  
                -  +  - ]
    2435                 :            : 
    2436   [ +  -  +  - ]:        990 :         spdk_free(ctx->super);
    2437                 :        990 :         free(ctx);
    2438                 :        990 : }
    2439                 :            : 
    2440                 :            : static void bs_write_super(spdk_bs_sequence_t *seq, struct spdk_blob_store *bs,
    2441                 :            :                            struct spdk_bs_super_block *super, spdk_bs_sequence_cpl cb_fn, void *cb_arg);
    2442                 :            : 
    2443                 :            : 
    2444                 :            : static void
    2445                 :        990 : bs_mark_dirty_write(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2446                 :            : {
    2447                 :        990 :         struct spdk_bs_mark_dirty *ctx = cb_arg;
    2448                 :        158 :         int rc;
    2449                 :            : 
    2450         [ +  + ]:        990 :         if (bserrno != 0) {
    2451                 :         24 :                 bs_mark_dirty_write_cpl(seq, ctx, bserrno);
    2452                 :         24 :                 return;
    2453                 :            :         }
    2454                 :            : 
    2455   [ +  -  +  -  :        966 :         rc = bs_super_validate(ctx->super, ctx->bs);
             +  -  +  - ]
    2456         [ -  + ]:        966 :         if (rc != 0) {
    2457                 :          0 :                 bs_mark_dirty_write_cpl(seq, ctx, rc);
    2458                 :          0 :                 return;
    2459                 :            :         }
    2460                 :            : 
    2461   [ +  -  +  -  :        966 :         ctx->super->clean = 0;
             +  -  +  - ]
    2462   [ +  +  +  -  :        966 :         if (ctx->super->size == 0) {
          +  -  +  -  +  
                      + ]
    2463   [ +  -  +  -  :         24 :                 ctx->super->size = ctx->bs->dev->blockcnt * ctx->bs->dev->blocklen;
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    2464                 :          4 :         }
    2465                 :            : 
    2466   [ +  -  +  -  :        966 :         bs_write_super(seq, ctx->bs, ctx->super, bs_mark_dirty_write_cpl, ctx);
             +  -  +  - ]
    2467         [ -  + ]:        158 : }
    2468                 :            : 
    2469                 :            : static void
    2470                 :     210536 : bs_mark_dirty(spdk_bs_sequence_t *seq, struct spdk_blob_store *bs,
    2471                 :            :               spdk_bs_sequence_cpl cb_fn, void *cb_arg)
    2472                 :            : {
    2473                 :       4982 :         struct spdk_bs_mark_dirty *ctx;
    2474                 :            : 
    2475                 :            :         /* Blobstore is already marked dirty */
    2476   [ +  +  +  +  :     210536 :         if (bs->clean == 0) {
             +  -  +  + ]
    2477   [ -  +  +  - ]:     209546 :                 cb_fn(seq, cb_arg, 0);
    2478                 :     209546 :                 return;
    2479                 :            :         }
    2480                 :            : 
    2481                 :        990 :         ctx = calloc(1, sizeof(*ctx));
    2482         [ +  + ]:        990 :         if (!ctx) {
    2483   [ #  #  #  # ]:          0 :                 cb_fn(seq, cb_arg, -ENOMEM);
    2484                 :          0 :                 return;
    2485                 :            :         }
    2486   [ +  -  +  - ]:        990 :         ctx->bs = bs;
    2487   [ +  -  +  - ]:        990 :         ctx->cb_fn = cb_fn;
    2488   [ +  -  +  - ]:        990 :         ctx->cb_arg = cb_arg;
    2489                 :            : 
    2490   [ +  -  +  - ]:        990 :         ctx->super = spdk_zmalloc(sizeof(*ctx->super), 0x1000, NULL,
    2491                 :            :                                   SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    2492   [ +  +  +  -  :        990 :         if (!ctx->super) {
                   +  - ]
    2493                 :          0 :                 free(ctx);
    2494   [ #  #  #  # ]:          0 :                 cb_fn(seq, cb_arg, -ENOMEM);
    2495                 :          0 :                 return;
    2496                 :            :         }
    2497                 :            : 
    2498   [ +  -  +  - ]:        990 :         bs_sequence_read_dev(seq, ctx->super, bs_page_to_lba(bs, 0),
    2499                 :        990 :                              bs_byte_to_lba(bs, sizeof(*ctx->super)),
    2500                 :        158 :                              bs_mark_dirty_write, ctx);
    2501         [ -  + ]:       4982 : }
    2502                 :            : 
    2503                 :            : /* Write a blob to disk */
    2504                 :            : static void
    2505                 :     225365 : blob_persist(spdk_bs_sequence_t *seq, struct spdk_blob *blob,
    2506                 :            :              spdk_bs_sequence_cpl cb_fn, void *cb_arg)
    2507                 :            : {
    2508                 :       8364 :         struct spdk_blob_persist_ctx *ctx;
    2509                 :            : 
    2510                 :     225365 :         blob_verify_md_op(blob);
    2511                 :            : 
    2512   [ +  +  +  +  :     225365 :         if (blob->state == SPDK_BLOB_STATE_CLEAN && TAILQ_EMPTY(&blob->persists_to_complete)) {
          +  +  +  -  +  
             -  +  -  +  
                      + ]
    2513   [ -  +  +  - ]:      40273 :                 cb_fn(seq, cb_arg, 0);
    2514                 :      40273 :                 return;
    2515                 :            :         }
    2516                 :            : 
    2517                 :     185092 :         ctx = calloc(1, sizeof(*ctx));
    2518         [ +  + ]:     185092 :         if (!ctx) {
    2519   [ #  #  #  # ]:          0 :                 cb_fn(seq, cb_arg, -ENOMEM);
    2520                 :          0 :                 return;
    2521                 :            :         }
    2522   [ +  -  +  - ]:     185092 :         ctx->blob = blob;
    2523   [ +  -  +  - ]:     185092 :         ctx->seq = seq;
    2524   [ +  -  +  - ]:     185092 :         ctx->cb_fn = cb_fn;
    2525   [ +  -  +  - ]:     185092 :         ctx->cb_arg = cb_arg;
    2526                 :            : 
    2527                 :            :         /* Multiple blob persists can affect one another, via blob->state or
    2528                 :            :          * blob mutable data changes. To prevent it, queue up the persists. */
    2529   [ +  +  +  -  :     185092 :         if (!TAILQ_EMPTY(&blob->persists_to_complete)) {
             +  -  +  + ]
    2530   [ +  -  +  -  :        127 :                 TAILQ_INSERT_TAIL(&blob->pending_persists, ctx, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    2531                 :        127 :                 return;
    2532                 :            :         }
    2533   [ +  +  +  -  :     184965 :         TAILQ_INSERT_HEAD(&blob->persists_to_complete, ctx, link);
          +  -  +  -  +  
          -  +  -  -  +  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    2534                 :            : 
    2535   [ +  -  +  - ]:     184965 :         bs_mark_dirty(seq, blob->bs, blob_persist_start, ctx);
    2536         [ -  + ]:       8364 : }
    2537                 :            : 
    2538                 :            : struct spdk_blob_copy_cluster_ctx {
    2539                 :            :         struct spdk_blob *blob;
    2540                 :            :         uint8_t *buf;
    2541                 :            :         uint64_t page;
    2542                 :            :         uint64_t new_cluster;
    2543                 :            :         uint32_t new_extent_page;
    2544                 :            :         spdk_bs_sequence_t *seq;
    2545                 :            :         struct spdk_blob_md_page *new_cluster_page;
    2546                 :            : };
    2547                 :            : 
    2548                 :            : static void
    2549                 :      27264 : blob_allocate_and_copy_cluster_cpl(void *cb_arg, int bserrno)
    2550                 :            : {
    2551                 :      27264 :         struct spdk_blob_copy_cluster_ctx *ctx = cb_arg;
    2552   [ +  -  +  - ]:      27264 :         struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)ctx->seq;
    2553                 :      26498 :         TAILQ_HEAD(, spdk_bs_request_set) requests;
    2554                 :        608 :         spdk_bs_user_op_t *op;
    2555                 :            : 
    2556         [ +  - ]:      27264 :         TAILQ_INIT(&requests);
    2557   [ +  +  +  -  :      27264 :         TAILQ_SWAP(&set->channel->need_cluster_alloc, &requests, spdk_bs_request_set, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  -  
          +  +  -  +  -  
             +  -  #  # ]
    2558                 :            : 
    2559         [ +  + ]:     172234 :         while (!TAILQ_EMPTY(&requests)) {
    2560                 :     144970 :                 op = TAILQ_FIRST(&requests);
    2561   [ +  +  +  -  :     144970 :                 TAILQ_REMOVE(&requests, op, link);
          +  -  +  -  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
    2562         [ +  - ]:     144970 :                 if (bserrno == 0) {
    2563                 :     144970 :                         bs_user_op_execute(op);
    2564                 :        608 :                 } else {
    2565                 :          0 :                         bs_user_op_abort(op, bserrno);
    2566                 :            :                 }
    2567                 :            :         }
    2568                 :            : 
    2569   [ +  -  +  - ]:      27264 :         spdk_free(ctx->buf);
    2570                 :      27264 :         free(ctx);
    2571                 :      27264 : }
    2572                 :            : 
    2573                 :            : static void
    2574                 :      27264 : blob_insert_cluster_cpl(void *cb_arg, int bserrno)
    2575                 :            : {
    2576                 :      27264 :         struct spdk_blob_copy_cluster_ctx *ctx = cb_arg;
    2577                 :            : 
    2578         [ +  + ]:      27264 :         if (bserrno) {
    2579         [ +  + ]:         35 :                 if (bserrno == -EEXIST) {
    2580                 :            :                         /* The metadata insert failed because another thread
    2581                 :            :                          * allocated the cluster first. Free our cluster
    2582                 :            :                          * but continue without error. */
    2583                 :         35 :                         bserrno = 0;
    2584                 :          4 :                 }
    2585   [ +  -  +  -  :         35 :                 spdk_spin_lock(&ctx->blob->bs->used_lock);
          +  -  +  -  +  
                      - ]
    2586   [ +  -  +  -  :         35 :                 bs_release_cluster(ctx->blob->bs, ctx->new_cluster);
          +  -  +  -  +  
                -  +  - ]
    2587   [ +  +  +  -  :         35 :                 if (ctx->new_extent_page != 0) {
                   +  + ]
    2588   [ +  -  +  -  :         14 :                         bs_release_md_page(ctx->blob->bs, ctx->new_extent_page);
          +  -  +  -  +  
                -  +  - ]
    2589                 :          2 :                 }
    2590   [ +  -  +  -  :         35 :                 spdk_spin_unlock(&ctx->blob->bs->used_lock);
          +  -  +  -  +  
                      - ]
    2591                 :          4 :         }
    2592                 :            : 
    2593   [ +  -  +  - ]:      27264 :         bs_sequence_finish(ctx->seq, bserrno);
    2594                 :      27264 : }
    2595                 :            : 
    2596                 :            : static void
    2597                 :       1877 : blob_write_copy_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2598                 :            : {
    2599                 :       1877 :         struct spdk_blob_copy_cluster_ctx *ctx = cb_arg;
    2600                 :        296 :         uint32_t cluster_number;
    2601                 :            : 
    2602         [ -  + ]:       1877 :         if (bserrno) {
    2603                 :            :                 /* The write failed, so jump to the final completion handler */
    2604                 :          0 :                 bs_sequence_finish(seq, bserrno);
    2605                 :          0 :                 return;
    2606                 :            :         }
    2607                 :            : 
    2608   [ +  -  +  -  :       1877 :         cluster_number = bs_page_to_cluster(ctx->blob->bs, ctx->page);
          +  -  +  -  +  
                -  +  - ]
    2609                 :            : 
    2610   [ +  -  +  -  :       2173 :         blob_insert_cluster_on_md_thread(ctx->blob, cluster_number, ctx->new_cluster,
             +  -  +  - ]
    2611   [ +  -  +  -  :        296 :                                          ctx->new_extent_page, ctx->new_cluster_page, blob_insert_cluster_cpl, ctx);
             +  -  +  - ]
    2612         [ -  + ]:        296 : }
    2613                 :            : 
    2614                 :            : static void
    2615                 :       1181 : blob_write_copy(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    2616                 :            : {
    2617                 :       1181 :         struct spdk_blob_copy_cluster_ctx *ctx = cb_arg;
    2618                 :            : 
    2619         [ -  + ]:       1181 :         if (bserrno != 0) {
    2620                 :            :                 /* The read failed, so jump to the final completion handler */
    2621                 :          0 :                 bs_sequence_finish(seq, bserrno);
    2622                 :          0 :                 return;
    2623                 :            :         }
    2624                 :            : 
    2625                 :            :         /* Write whole cluster */
    2626   [ +  -  +  - ]:       1369 :         bs_sequence_write_dev(seq, ctx->buf,
    2627   [ +  -  +  -  :       1181 :                               bs_cluster_to_lba(ctx->blob->bs, ctx->new_cluster),
          +  -  +  -  +  
                -  +  - ]
    2628   [ +  -  +  -  :       1181 :                               bs_cluster_to_lba(ctx->blob->bs, 1),
             +  -  +  - ]
    2629                 :        188 :                               blob_write_copy_cpl, ctx);
    2630         [ -  + ]:        188 : }
    2631                 :            : 
    2632                 :            : static bool
    2633                 :      27265 : blob_can_copy(struct spdk_blob *blob, uint32_t cluster_start_page, uint64_t *base_lba)
    2634                 :            : {
    2635   [ +  -  +  - ]:      27265 :         uint64_t lba = bs_dev_page_to_lba(blob->back_bs_dev, cluster_start_page);
    2636                 :            : 
    2637   [ +  +  +  +  :      30245 :         return (!blob_is_esnap_clone(blob) && blob->bs->dev->copy != NULL) &&
          +  +  +  -  +  
          -  +  -  +  -  
                   +  + ]
    2638   [ +  -  +  -  :       2980 :                blob->back_bs_dev->translate_lba(blob->back_bs_dev, lba, base_lba);
          +  -  +  -  -  
          +  +  -  +  -  
                   +  - ]
    2639                 :        608 : }
    2640                 :            : 
    2641                 :            : static void
    2642                 :        696 : blob_copy(struct spdk_blob_copy_cluster_ctx *ctx, spdk_bs_user_op_t *op, uint64_t src_lba)
    2643                 :            : {
    2644   [ +  -  +  - ]:        696 :         struct spdk_blob *blob = ctx->blob;
    2645   [ +  -  +  -  :        696 :         uint64_t lba_count = bs_dev_byte_to_lba(blob->back_bs_dev, blob->bs->cluster_sz);
          +  -  +  -  +  
                -  +  - ]
    2646                 :            : 
    2647   [ +  -  +  - ]:        804 :         bs_sequence_copy_dev(ctx->seq,
    2648   [ +  -  +  -  :        696 :                              bs_cluster_to_lba(blob->bs, ctx->new_cluster),
             +  -  +  - ]
    2649                 :        108 :                              src_lba,
    2650                 :        108 :                              lba_count,
    2651                 :        108 :                              blob_write_copy_cpl, ctx);
    2652                 :        696 : }
    2653                 :            : 
    2654                 :            : static void
    2655                 :     144971 : bs_allocate_and_copy_cluster(struct spdk_blob *blob,
    2656                 :            :                              struct spdk_io_channel *_ch,
    2657                 :            :                              uint64_t io_unit, spdk_bs_user_op_t *op)
    2658                 :            : {
    2659                 :     140758 :         struct spdk_bs_cpl cpl;
    2660                 :        608 :         struct spdk_bs_channel *ch;
    2661                 :        608 :         struct spdk_blob_copy_cluster_ctx *ctx;
    2662                 :        608 :         uint32_t cluster_start_page;
    2663                 :        608 :         uint32_t cluster_number;
    2664                 :        608 :         bool is_zeroes;
    2665                 :        608 :         bool can_copy;
    2666                 :     140758 :         uint64_t copy_src_lba;
    2667                 :        608 :         int rc;
    2668                 :            : 
    2669                 :     144971 :         ch = spdk_io_channel_get_ctx(_ch);
    2670                 :            : 
    2671   [ +  +  +  -  :     144971 :         if (!TAILQ_EMPTY(&ch->need_cluster_alloc)) {
             +  -  -  + ]
    2672                 :            :                 /* There are already operations pending. Queue this user op
    2673                 :            :                  * and return because it will be re-executed when the outstanding
    2674                 :            :                  * cluster allocation completes. */
    2675   [ #  #  #  #  :     117706 :                 TAILQ_INSERT_TAIL(&ch->need_cluster_alloc, op, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    2676                 :     117706 :                 return;
    2677                 :            :         }
    2678                 :            : 
    2679                 :            :         /* Round the io_unit offset down to the first page in the cluster */
    2680                 :      27265 :         cluster_start_page = bs_io_unit_to_cluster_start(blob, io_unit);
    2681                 :            : 
    2682                 :            :         /* Calculate which index in the metadata cluster array the corresponding
    2683                 :            :          * cluster is supposed to be at. */
    2684                 :      27265 :         cluster_number = bs_io_unit_to_cluster_number(blob, io_unit);
    2685                 :            : 
    2686                 :      27265 :         ctx = calloc(1, sizeof(*ctx));
    2687         [ +  + ]:      27265 :         if (!ctx) {
    2688                 :          0 :                 bs_user_op_abort(op, -ENOMEM);
    2689                 :          0 :                 return;
    2690                 :            :         }
    2691                 :            : 
    2692   [ +  +  +  +  :      27265 :         assert(blob->bs->cluster_sz % blob->back_bs_dev->blocklen == 0);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  #  # ]
    2693                 :            : 
    2694   [ +  -  +  - ]:      27265 :         ctx->blob = blob;
    2695   [ +  -  +  - ]:      27265 :         ctx->page = cluster_start_page;
    2696   [ +  -  +  -  :      27265 :         ctx->new_cluster_page = ch->new_cluster_page;
             +  -  +  - ]
    2697   [ +  +  +  -  :      27265 :         memset(ctx->new_cluster_page, 0, SPDK_BS_PAGE_SIZE);
                   +  - ]
    2698                 :      27265 :         can_copy = blob_can_copy(blob, cluster_start_page, &copy_src_lba);
    2699                 :            : 
    2700   [ +  -  +  -  :      53919 :         is_zeroes = blob->back_bs_dev->is_zeroes(blob->back_bs_dev,
          +  -  +  -  -  
          +  +  -  +  -  
                   +  - ]
    2701   [ +  -  +  - ]:        608 :                         bs_dev_page_to_lba(blob->back_bs_dev, cluster_start_page),
    2702   [ +  -  +  -  :      27265 :                         bs_dev_byte_to_lba(blob->back_bs_dev, blob->bs->cluster_sz));
          +  -  +  -  +  
                -  +  - ]
    2703   [ +  +  +  +  :      27265 :         if (blob->parent_id != SPDK_BLOBID_INVALID && !is_zeroes && !can_copy) {
          +  +  +  -  +  
             +  +  -  +  
                      + ]
    2704   [ +  -  +  -  :       1181 :                 ctx->buf = spdk_malloc(blob->bs->cluster_sz, blob->back_bs_dev->blocklen,
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    2705                 :            :                                        NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    2706   [ +  +  +  -  :       1181 :                 if (!ctx->buf) {
                   +  - ]
    2707   [ #  #  #  #  :          0 :                         SPDK_ERRLOG("DMA allocation for cluster of size = %" PRIu32 " failed.\n",
             #  #  #  # ]
    2708                 :            :                                     blob->bs->cluster_sz);
    2709                 :          0 :                         free(ctx);
    2710                 :          0 :                         bs_user_op_abort(op, -ENOMEM);
    2711                 :          0 :                         return;
    2712                 :            :                 }
    2713                 :        188 :         }
    2714                 :            : 
    2715   [ +  -  +  -  :      27265 :         spdk_spin_lock(&blob->bs->used_lock);
                   +  - ]
    2716   [ +  -  +  - ]:      27265 :         rc = bs_allocate_cluster(blob, cluster_number, &ctx->new_cluster, &ctx->new_extent_page,
    2717                 :            :                                  false);
    2718   [ +  -  +  -  :      27265 :         spdk_spin_unlock(&blob->bs->used_lock);
                   +  - ]
    2719         [ +  + ]:      27265 :         if (rc != 0) {
    2720   [ #  #  #  # ]:          1 :                 spdk_free(ctx->buf);
    2721                 :          1 :                 free(ctx);
    2722                 :          1 :                 bs_user_op_abort(op, rc);
    2723                 :          1 :                 return;
    2724                 :            :         }
    2725                 :            : 
    2726                 :      27264 :         cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    2727   [ +  -  +  -  :      27264 :         cpl.u.blob_basic.cb_fn = blob_allocate_and_copy_cluster_cpl;
                   +  - ]
    2728   [ +  -  +  -  :      27264 :         cpl.u.blob_basic.cb_arg = ctx;
                   +  - ]
    2729                 :            : 
    2730   [ +  -  +  - ]:      27264 :         ctx->seq = bs_sequence_start_blob(_ch, &cpl, blob);
    2731   [ +  +  +  -  :      27264 :         if (!ctx->seq) {
                   +  - ]
    2732   [ #  #  #  #  :          0 :                 spdk_spin_lock(&blob->bs->used_lock);
                   #  # ]
    2733   [ #  #  #  #  :          0 :                 bs_release_cluster(blob->bs, ctx->new_cluster);
             #  #  #  # ]
    2734   [ #  #  #  #  :          0 :                 spdk_spin_unlock(&blob->bs->used_lock);
                   #  # ]
    2735   [ #  #  #  # ]:          0 :                 spdk_free(ctx->buf);
    2736                 :          0 :                 free(ctx);
    2737                 :          0 :                 bs_user_op_abort(op, -ENOMEM);
    2738                 :          0 :                 return;
    2739                 :            :         }
    2740                 :            : 
    2741                 :            :         /* Queue the user op to block other incoming operations */
    2742   [ +  -  +  -  :      27264 :         TAILQ_INSERT_TAIL(&ch->need_cluster_alloc, op, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    2743                 :            : 
    2744   [ +  +  +  +  :      27264 :         if (blob->parent_id != SPDK_BLOBID_INVALID && !is_zeroes) {
          +  +  +  -  +  
                      + ]
    2745   [ +  +  +  + ]:       1877 :                 if (can_copy) {
    2746                 :        696 :                         blob_copy(ctx, op, copy_src_lba);
    2747                 :        108 :                 } else {
    2748                 :            :                         /* Read cluster from backing device */
    2749   [ +  -  +  -  :       1369 :                         bs_sequence_read_bs_dev(ctx->seq, blob->back_bs_dev, ctx->buf,
          +  -  +  -  +  
                -  +  - ]
    2750   [ +  -  +  - ]:        188 :                                                 bs_dev_page_to_lba(blob->back_bs_dev, cluster_start_page),
    2751   [ +  -  +  -  :       1181 :                                                 bs_dev_byte_to_lba(blob->back_bs_dev, blob->bs->cluster_sz),
          +  -  +  -  +  
                -  +  - ]
    2752                 :        188 :                                                 blob_write_copy, ctx);
    2753                 :            :                 }
    2754                 :            : 
    2755                 :        296 :         } else {
    2756   [ +  -  +  -  :      25699 :                 blob_insert_cluster_on_md_thread(ctx->blob, cluster_number, ctx->new_cluster,
             +  -  +  - ]
    2757   [ +  -  +  -  :        312 :                                                  ctx->new_extent_page, ctx->new_cluster_page, blob_insert_cluster_cpl, ctx);
             +  -  +  - ]
    2758                 :            :         }
    2759         [ -  + ]:        608 : }
    2760                 :            : 
    2761                 :            : static inline bool
    2762                 :   22608427 : blob_calculate_lba_and_lba_count(struct spdk_blob *blob, uint64_t io_unit, uint64_t length,
    2763                 :            :                                  uint64_t *lba, uint64_t *lba_count)
    2764                 :            : {
    2765         [ +  - ]:   22608427 :         *lba_count = length;
    2766                 :            : 
    2767         [ +  + ]:   22608427 :         if (!bs_io_unit_is_allocated(blob, io_unit)) {
    2768   [ +  +  +  -  :     977915 :                 assert(blob->back_bs_dev != NULL);
             +  -  #  # ]
    2769         [ +  - ]:     977915 :                 *lba = bs_io_unit_to_back_dev_lba(blob, io_unit);
    2770   [ +  -  +  - ]:     977915 :                 *lba_count = bs_io_unit_to_back_dev_lba(blob, *lba_count);
    2771                 :     977915 :                 return false;
    2772                 :            :         } else {
    2773         [ +  - ]:   21630512 :                 *lba = bs_blob_io_unit_to_lba(blob, io_unit);
    2774                 :   21630512 :                 return true;
    2775                 :            :         }
    2776                 :      27542 : }
    2777                 :            : 
    2778                 :            : struct op_split_ctx {
    2779                 :            :         struct spdk_blob *blob;
    2780                 :            :         struct spdk_io_channel *channel;
    2781                 :            :         uint64_t io_unit_offset;
    2782                 :            :         uint64_t io_units_remaining;
    2783                 :            :         void *curr_payload;
    2784                 :            :         enum spdk_blob_op_type op_type;
    2785                 :            :         spdk_bs_sequence_t *seq;
    2786                 :            :         bool in_submit_ctx;
    2787                 :            :         bool completed_in_submit_ctx;
    2788                 :            :         bool done;
    2789                 :            : };
    2790                 :            : 
    2791                 :            : static void
    2792                 :      58900 : blob_request_submit_op_split_next(void *cb_arg, int bserrno)
    2793                 :            : {
    2794                 :      58900 :         struct op_split_ctx     *ctx = cb_arg;
    2795   [ +  -  +  - ]:      58900 :         struct spdk_blob        *blob = ctx->blob;
    2796   [ +  -  +  - ]:      58900 :         struct spdk_io_channel  *ch = ctx->channel;
    2797   [ +  -  +  - ]:      58900 :         enum spdk_blob_op_type  op_type = ctx->op_type;
    2798                 :        758 :         uint8_t                 *buf;
    2799                 :        758 :         uint64_t                offset;
    2800                 :        758 :         uint64_t                length;
    2801                 :        758 :         uint64_t                op_length;
    2802                 :            : 
    2803   [ +  -  +  +  :      58900 :         if (bserrno != 0 || ctx->io_units_remaining == 0) {
             +  -  +  + ]
    2804   [ +  -  +  - ]:       3067 :                 bs_sequence_finish(ctx->seq, bserrno);
    2805   [ +  +  +  +  :       3067 :                 if (ctx->in_submit_ctx) {
             +  -  +  + ]
    2806                 :            :                         /* Defer freeing of the ctx object, since it will be
    2807                 :            :                          * accessed when this unwinds back to the submisison
    2808                 :            :                          * context.
    2809                 :            :                          */
    2810   [ +  -  +  - ]:        240 :                         ctx->done = true;
    2811                 :         40 :                 } else {
    2812                 :       2827 :                         free(ctx);
    2813                 :            :                 }
    2814                 :       3067 :                 return;
    2815                 :            :         }
    2816                 :            : 
    2817   [ +  +  +  +  :      55833 :         if (ctx->in_submit_ctx) {
             +  -  +  + ]
    2818                 :            :                 /* If this split operation completed in the context
    2819                 :            :                  * of its submission, mark the flag and return immediately
    2820                 :            :                  * to avoid recursion.
    2821                 :            :                  */
    2822   [ +  -  +  - ]:        408 :                 ctx->completed_in_submit_ctx = true;
    2823                 :        408 :                 return;
    2824                 :            :         }
    2825                 :            : 
    2826                 :        584 :         while (true) {
    2827   [ +  -  +  - ]:      55833 :                 ctx->completed_in_submit_ctx = false;
    2828                 :            : 
    2829   [ +  -  +  - ]:      55833 :                 offset = ctx->io_unit_offset;
    2830   [ +  -  +  - ]:      55833 :                 length = ctx->io_units_remaining;
    2831   [ +  -  +  - ]:      55833 :                 buf = ctx->curr_payload;
    2832         [ +  + ]:      55833 :                 op_length = spdk_min(length, bs_num_io_units_to_cluster_boundary(blob,
    2833                 :            :                                      offset));
    2834                 :            : 
    2835                 :            :                 /* Update length and payload for next operation */
    2836   [ +  -  +  - ]:      55833 :                 ctx->io_units_remaining -= op_length;
    2837   [ +  -  +  - ]:      55833 :                 ctx->io_unit_offset += op_length;
    2838   [ +  +  +  + ]:      55833 :                 if (op_type == SPDK_BLOB_WRITE || op_type == SPDK_BLOB_READ) {
    2839   [ +  -  +  -  :       3260 :                         ctx->curr_payload += op_length * blob->bs->io_unit_size;
          +  -  +  -  +  
                -  +  - ]
    2840                 :        528 :                 }
    2841                 :            : 
    2842   [ +  +  +  +  :      55833 :                 assert(!ctx->in_submit_ctx);
          +  -  -  +  #  
                      # ]
    2843   [ +  -  +  - ]:      55833 :                 ctx->in_submit_ctx = true;
    2844                 :            : 
    2845   [ +  +  +  +  :      55833 :                 switch (op_type) {
                   +  + ]
    2846                 :       2136 :                 case SPDK_BLOB_READ:
    2847                 :       2972 :                         spdk_blob_io_read(blob, ch, buf, offset, op_length,
    2848                 :        418 :                                           blob_request_submit_op_split_next, ctx);
    2849                 :       2554 :                         break;
    2850                 :        596 :                 case SPDK_BLOB_WRITE:
    2851                 :        816 :                         spdk_blob_io_write(blob, ch, buf, offset, op_length,
    2852                 :        110 :                                            blob_request_submit_op_split_next, ctx);
    2853                 :        706 :                         break;
    2854                 :      52221 :                 case SPDK_BLOB_UNMAP:
    2855                 :      52269 :                         spdk_blob_io_unmap(blob, ch, offset, op_length,
    2856                 :         24 :                                            blob_request_submit_op_split_next, ctx);
    2857                 :      52245 :                         break;
    2858                 :        296 :                 case SPDK_BLOB_WRITE_ZEROES:
    2859                 :        360 :                         spdk_blob_io_write_zeroes(blob, ch, offset, op_length,
    2860                 :         32 :                                                   blob_request_submit_op_split_next, ctx);
    2861                 :        328 :                         break;
    2862                 :          0 :                 case SPDK_BLOB_READV:
    2863                 :            :                 case SPDK_BLOB_WRITEV:
    2864                 :          0 :                         SPDK_ERRLOG("readv/write not valid\n");
    2865   [ #  #  #  # ]:          0 :                         bs_sequence_finish(ctx->seq, -EINVAL);
    2866                 :          0 :                         free(ctx);
    2867                 :          0 :                         return;
    2868                 :            :                 }
    2869                 :            : 
    2870                 :            : #ifndef __clang_analyzer__
    2871                 :            :                 /* scan-build reports a false positive around accessing the ctx here. It
    2872                 :            :                  * forms a path that recursively calls this function, but then says
    2873                 :            :                  * "assuming ctx->in_submit_ctx is false", when that isn't possible.
    2874                 :            :                  * This path does free(ctx), returns to here, and reports a use-after-free
    2875                 :            :                  * bug.  Wrapping this bit of code so that scan-build doesn't see it
    2876                 :            :                  * works around the scan-build bug.
    2877                 :            :                  */
    2878   [ +  +  +  +  :      55833 :                 assert(ctx->in_submit_ctx);
          +  -  -  +  #  
                      # ]
    2879   [ +  -  +  - ]:      55833 :                 ctx->in_submit_ctx = false;
    2880                 :            : 
    2881                 :            :                 /* If the operation completed immediately, loop back and submit the
    2882                 :            :                  * next operation.  Otherwise we can return and the next split
    2883                 :            :                  * operation will get submitted when this current operation is
    2884                 :            :                  * later completed asynchronously.
    2885                 :            :                  */
    2886   [ +  +  +  +  :      55833 :                 if (ctx->completed_in_submit_ctx) {
             +  -  +  + ]
    2887                 :        408 :                         continue;
    2888   [ +  +  +  +  :      55425 :                 } else if (ctx->done) {
             +  -  +  + ]
    2889                 :        240 :                         free(ctx);
    2890                 :         40 :                 }
    2891                 :            : #endif
    2892                 :      55425 :                 break;
    2893                 :            :         }
    2894         [ -  + ]:        758 : }
    2895                 :            : 
    2896                 :            : static void
    2897                 :       3067 : blob_request_submit_op_split(struct spdk_io_channel *ch, struct spdk_blob *blob,
    2898                 :            :                              void *payload, uint64_t offset, uint64_t length,
    2899                 :            :                              spdk_blob_op_complete cb_fn, void *cb_arg, enum spdk_blob_op_type op_type)
    2900                 :            : {
    2901                 :        174 :         struct op_split_ctx *ctx;
    2902                 :        174 :         spdk_bs_sequence_t *seq;
    2903                 :       2868 :         struct spdk_bs_cpl cpl;
    2904                 :            : 
    2905   [ +  +  #  # ]:       3067 :         assert(blob != NULL);
    2906                 :            : 
    2907                 :       3067 :         ctx = calloc(1, sizeof(struct op_split_ctx));
    2908         [ +  + ]:       3067 :         if (ctx == NULL) {
    2909   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    2910                 :          0 :                 return;
    2911                 :            :         }
    2912                 :            : 
    2913                 :       3067 :         cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    2914   [ +  -  +  -  :       3067 :         cpl.u.blob_basic.cb_fn = cb_fn;
                   +  - ]
    2915   [ +  -  +  -  :       3067 :         cpl.u.blob_basic.cb_arg = cb_arg;
                   +  - ]
    2916                 :            : 
    2917                 :       3067 :         seq = bs_sequence_start_blob(ch, &cpl, blob);
    2918         [ +  + ]:       3067 :         if (!seq) {
    2919                 :          0 :                 free(ctx);
    2920   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    2921                 :          0 :                 return;
    2922                 :            :         }
    2923                 :            : 
    2924   [ +  -  +  - ]:       3067 :         ctx->blob = blob;
    2925   [ +  -  +  - ]:       3067 :         ctx->channel = ch;
    2926   [ +  -  +  - ]:       3067 :         ctx->curr_payload = payload;
    2927   [ +  -  +  - ]:       3067 :         ctx->io_unit_offset = offset;
    2928   [ +  -  +  - ]:       3067 :         ctx->io_units_remaining = length;
    2929   [ +  -  +  - ]:       3067 :         ctx->op_type = op_type;
    2930   [ +  -  +  - ]:       3067 :         ctx->seq = seq;
    2931                 :            : 
    2932                 :       3067 :         blob_request_submit_op_split_next(ctx, 0);
    2933         [ -  + ]:        174 : }
    2934                 :            : 
    2935                 :            : static void
    2936                 :    6139632 : blob_request_submit_op_single(struct spdk_io_channel *_ch, struct spdk_blob *blob,
    2937                 :            :                               void *payload, uint64_t offset, uint64_t length,
    2938                 :            :                               spdk_blob_op_complete cb_fn, void *cb_arg, enum spdk_blob_op_type op_type)
    2939                 :            : {
    2940                 :    6081439 :         struct spdk_bs_cpl cpl;
    2941                 :    6081439 :         uint64_t lba;
    2942                 :    6081439 :         uint64_t lba_count;
    2943                 :      25170 :         bool is_allocated;
    2944                 :            : 
    2945   [ +  +  #  # ]:    6139632 :         assert(blob != NULL);
    2946                 :            : 
    2947                 :    6139632 :         cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    2948   [ +  -  +  -  :    6139632 :         cpl.u.blob_basic.cb_fn = cb_fn;
                   +  - ]
    2949   [ +  -  +  -  :    6139632 :         cpl.u.blob_basic.cb_arg = cb_arg;
                   +  - ]
    2950                 :            : 
    2951   [ +  +  +  -  :    6139632 :         if (blob->frozen_refcnt) {
                   +  + ]
    2952                 :            :                 /* This blob I/O is frozen */
    2953                 :          4 :                 spdk_bs_user_op_t *op;
    2954                 :        163 :                 struct spdk_bs_channel *bs_channel = spdk_io_channel_get_ctx(_ch);
    2955                 :            : 
    2956                 :        163 :                 op = bs_user_op_alloc(_ch, &cpl, op_type, blob, payload, 0, offset, length);
    2957         [ +  + ]:        163 :                 if (!op) {
    2958   [ #  #  #  # ]:          0 :                         cb_fn(cb_arg, -ENOMEM);
    2959                 :         57 :                         return;
    2960                 :            :                 }
    2961                 :            : 
    2962   [ +  -  +  -  :        163 :                 TAILQ_INSERT_TAIL(&bs_channel->queued_io, op, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    2963                 :            : 
    2964                 :        163 :                 return;
    2965                 :          4 :         }
    2966                 :            : 
    2967                 :    6139469 :         is_allocated = blob_calculate_lba_and_lba_count(blob, offset, length, &lba, &lba_count);
    2968                 :            : 
    2969   [ +  +  +  +  :    6139469 :         switch (op_type) {
                      + ]
    2970                 :    5054846 :         case SPDK_BLOB_READ: {
    2971                 :      13707 :                 spdk_bs_batch_t *batch;
    2972                 :            : 
    2973                 :    5068553 :                 batch = bs_batch_open(_ch, &cpl, blob);
    2974         [ +  + ]:    5068553 :                 if (!batch) {
    2975   [ #  #  #  # ]:          0 :                         cb_fn(cb_arg, -ENOMEM);
    2976                 :          0 :                         return;
    2977                 :            :                 }
    2978                 :            : 
    2979   [ +  +  +  + ]:    5068553 :                 if (is_allocated) {
    2980                 :            :                         /* Read from the blob */
    2981                 :    5062625 :                         bs_batch_read_dev(batch, payload, lba, lba_count);
    2982                 :      12719 :                 } else {
    2983                 :            :                         /* Read from the backing block device */
    2984   [ +  -  +  - ]:       5928 :                         bs_batch_read_bs_dev(batch, blob->back_bs_dev, payload, lba, lba_count);
    2985                 :            :                 }
    2986                 :            : 
    2987                 :    5068553 :                 bs_batch_close(batch);
    2988                 :    5068553 :                 break;
    2989                 :      13707 :         }
    2990                 :     863537 :         case SPDK_BLOB_WRITE:
    2991                 :            :         case SPDK_BLOB_WRITE_ZEROES: {
    2992   [ +  +  +  + ]:     874972 :                 if (is_allocated) {
    2993                 :            :                         /* Write to the blob */
    2994                 :      11223 :                         spdk_bs_batch_t *batch;
    2995                 :            : 
    2996         [ +  + ]:     873700 :                         if (lba_count == 0) {
    2997   [ #  #  #  # ]:          0 :                                 cb_fn(cb_arg, 0);
    2998                 :          0 :                                 return;
    2999                 :            :                         }
    3000                 :            : 
    3001                 :     873700 :                         batch = bs_batch_open(_ch, &cpl, blob);
    3002         [ +  + ]:     873700 :                         if (!batch) {
    3003   [ #  #  #  # ]:         53 :                                 cb_fn(cb_arg, -ENOMEM);
    3004                 :         53 :                                 return;
    3005                 :            :                         }
    3006                 :            : 
    3007         [ +  + ]:     873647 :                         if (op_type == SPDK_BLOB_WRITE) {
    3008                 :     871817 :                                 bs_batch_write_dev(batch, payload, lba, lba_count);
    3009                 :      11191 :                         } else {
    3010                 :       1830 :                                 bs_batch_write_zeroes_dev(batch, lba, lba_count);
    3011                 :            :                         }
    3012                 :            : 
    3013                 :     873647 :                         bs_batch_close(batch);
    3014         [ -  + ]:      11223 :                 } else {
    3015                 :            :                         /* Queue this operation and allocate the cluster */
    3016                 :        212 :                         spdk_bs_user_op_t *op;
    3017                 :            : 
    3018                 :       1272 :                         op = bs_user_op_alloc(_ch, &cpl, op_type, blob, payload, 0, offset, length);
    3019         [ +  + ]:       1272 :                         if (!op) {
    3020   [ #  #  #  # ]:          0 :                                 cb_fn(cb_arg, -ENOMEM);
    3021                 :          0 :                                 return;
    3022                 :            :                         }
    3023                 :            : 
    3024                 :       1272 :                         bs_allocate_and_copy_cluster(blob, _ch, offset, op);
    3025         [ -  + ]:        212 :                 }
    3026                 :     874919 :                 break;
    3027                 :            :         }
    3028                 :     195920 :         case SPDK_BLOB_UNMAP: {
    3029                 :         24 :                 spdk_bs_batch_t *batch;
    3030                 :            : 
    3031                 :     195944 :                 batch = bs_batch_open(_ch, &cpl, blob);
    3032         [ +  + ]:     195944 :                 if (!batch) {
    3033   [ #  #  #  # ]:          0 :                         cb_fn(cb_arg, -ENOMEM);
    3034                 :          0 :                         return;
    3035                 :            :                 }
    3036                 :            : 
    3037   [ +  -  -  + ]:     195944 :                 if (is_allocated) {
    3038                 :     195944 :                         bs_batch_unmap_dev(batch, lba, lba_count);
    3039                 :         24 :                 }
    3040                 :            : 
    3041                 :     195944 :                 bs_batch_close(batch);
    3042                 :     195944 :                 break;
    3043         [ +  + ]:         24 :         }
    3044                 :          0 :         case SPDK_BLOB_READV:
    3045                 :            :         case SPDK_BLOB_WRITEV:
    3046                 :          0 :                 SPDK_ERRLOG("readv/write not valid\n");
    3047   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -EINVAL);
    3048                 :          0 :                 break;
    3049                 :            :         }
    3050         [ -  + ]:      52584 : }
    3051                 :            : 
    3052                 :            : static void
    3053                 :    6145175 : blob_request_submit_op(struct spdk_blob *blob, struct spdk_io_channel *_channel,
    3054                 :            :                        void *payload, uint64_t offset, uint64_t length,
    3055                 :            :                        spdk_blob_op_complete cb_fn, void *cb_arg, enum spdk_blob_op_type op_type)
    3056                 :            : {
    3057   [ +  +  #  # ]:    6145175 :         assert(blob != NULL);
    3058                 :            : 
    3059   [ +  +  +  +  :    6145175 :         if (blob->data_ro && op_type != SPDK_BLOB_READ) {
          +  +  +  +  +  
                      + ]
    3060   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, -EPERM);
    3061                 :         24 :                 return;
    3062                 :            :         }
    3063                 :            : 
    3064         [ +  + ]:    6145151 :         if (length == 0) {
    3065   [ -  +  +  - ]:       2308 :                 cb_fn(cb_arg, 0);
    3066                 :       2308 :                 return;
    3067                 :            :         }
    3068                 :            : 
    3069   [ +  +  +  -  :    6142843 :         if (offset + length > bs_cluster_to_lba(blob->bs, blob->active.num_clusters)) {
          +  -  +  -  +  
                -  +  + ]
    3070   [ -  +  +  - ]:        144 :                 cb_fn(cb_arg, -EINVAL);
    3071                 :        144 :                 return;
    3072                 :            :         }
    3073         [ +  + ]:    6142699 :         if (length <= bs_num_io_units_to_cluster_boundary(blob, offset)) {
    3074                 :    6164802 :                 blob_request_submit_op_single(_channel, blob, payload, offset, length,
    3075                 :      25170 :                                               cb_fn, cb_arg, op_type);
    3076                 :      25170 :         } else {
    3077                 :       3241 :                 blob_request_submit_op_split(_channel, blob, payload, offset, length,
    3078                 :        174 :                                              cb_fn, cb_arg, op_type);
    3079                 :            :         }
    3080                 :      25752 : }
    3081                 :            : 
    3082                 :            : struct rw_iov_ctx {
    3083                 :            :         struct spdk_blob *blob;
    3084                 :            :         struct spdk_io_channel *channel;
    3085                 :            :         spdk_blob_op_complete cb_fn;
    3086                 :            :         void *cb_arg;
    3087                 :            :         bool read;
    3088                 :            :         int iovcnt;
    3089                 :            :         struct iovec *orig_iov;
    3090                 :            :         uint64_t io_unit_offset;
    3091                 :            :         uint64_t io_units_remaining;
    3092                 :            :         uint64_t io_units_done;
    3093                 :            :         struct spdk_blob_ext_io_opts *ext_io_opts;
    3094                 :            :         struct iovec iov[0];
    3095                 :            : };
    3096                 :            : 
    3097                 :            : static void
    3098                 :   16252908 : rw_iov_done(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    3099                 :            : {
    3100   [ +  +  #  # ]:   16252908 :         assert(cb_arg == NULL);
    3101                 :   16252908 :         bs_sequence_finish(seq, bserrno);
    3102                 :   16252908 : }
    3103                 :            : 
    3104                 :            : static void
    3105                 :       4464 : rw_iov_split_next(void *cb_arg, int bserrno)
    3106                 :            : {
    3107                 :       4464 :         struct rw_iov_ctx *ctx = cb_arg;
    3108   [ +  -  +  - ]:       4464 :         struct spdk_blob *blob = ctx->blob;
    3109                 :        744 :         struct iovec *iov, *orig_iov;
    3110                 :        744 :         int iovcnt;
    3111                 :        744 :         size_t orig_iovoff;
    3112                 :        744 :         uint64_t io_units_count, io_units_to_boundary, io_unit_offset;
    3113                 :        744 :         uint64_t byte_count;
    3114                 :            : 
    3115   [ +  -  +  +  :       4464 :         if (bserrno != 0 || ctx->io_units_remaining == 0) {
             +  -  +  + ]
    3116   [ +  -  +  -  :       1224 :                 ctx->cb_fn(ctx->cb_arg, bserrno);
          -  +  +  -  +  
                -  +  - ]
    3117                 :       1224 :                 free(ctx);
    3118                 :       1224 :                 return;
    3119                 :            :         }
    3120                 :            : 
    3121   [ +  -  +  - ]:       3240 :         io_unit_offset = ctx->io_unit_offset;
    3122                 :       3240 :         io_units_to_boundary = bs_num_io_units_to_cluster_boundary(blob, io_unit_offset);
    3123   [ +  -  +  -  :       3240 :         io_units_count = spdk_min(ctx->io_units_remaining, io_units_to_boundary);
          +  +  +  -  +  
                      - ]
    3124                 :            :         /*
    3125                 :            :          * Get index and offset into the original iov array for our current position in the I/O sequence.
    3126                 :            :          *  byte_count will keep track of how many bytes remaining until orig_iov and orig_iovoff will
    3127                 :            :          *  point to the current position in the I/O sequence.
    3128                 :            :          */
    3129   [ +  -  +  -  :       3240 :         byte_count = ctx->io_units_done * blob->bs->io_unit_size;
          +  -  +  -  +  
                -  +  - ]
    3130   [ +  -  +  -  :       3240 :         orig_iov = &ctx->orig_iov[0];
                   +  - ]
    3131                 :       3240 :         orig_iovoff = 0;
    3132         [ +  + ]:       6888 :         while (byte_count > 0) {
    3133   [ +  +  +  -  :       3648 :                 if (byte_count >= orig_iov->iov_len) {
                   +  + ]
    3134   [ +  -  +  - ]:       2112 :                         byte_count -= orig_iov->iov_len;
    3135         [ +  - ]:       2112 :                         orig_iov++;
    3136                 :        352 :                 } else {
    3137                 :       1536 :                         orig_iovoff = byte_count;
    3138                 :       1536 :                         byte_count = 0;
    3139                 :            :                 }
    3140                 :            :         }
    3141                 :            : 
    3142                 :            :         /*
    3143                 :            :          * Build an iov array for the next I/O in the sequence.  byte_count will keep track of how many
    3144                 :            :          *  bytes of this next I/O remain to be accounted for in the new iov array.
    3145                 :            :          */
    3146   [ +  -  +  -  :       3240 :         byte_count = io_units_count * blob->bs->io_unit_size;
             +  -  +  - ]
    3147   [ +  -  +  - ]:       3240 :         iov = &ctx->iov[0];
    3148                 :       3240 :         iovcnt = 0;
    3149         [ +  + ]:       8280 :         while (byte_count > 0) {
    3150   [ +  +  +  -  :       5040 :                 assert(iovcnt < ctx->iovcnt);
             +  -  #  # ]
    3151   [ +  -  +  -  :       5040 :                 iov->iov_len = spdk_min(byte_count, orig_iov->iov_len - orig_iovoff);
          +  +  +  -  +  
             -  +  -  +  
                      - ]
    3152   [ +  -  +  -  :       5040 :                 iov->iov_base = orig_iov->iov_base + orig_iovoff;
             +  -  +  - ]
    3153   [ +  -  +  - ]:       5040 :                 byte_count -= iov->iov_len;
    3154                 :       5040 :                 orig_iovoff = 0;
    3155         [ +  - ]:       5040 :                 orig_iov++;
    3156         [ +  - ]:       5040 :                 iov++;
    3157         [ +  - ]:       5040 :                 iovcnt++;
    3158                 :            :         }
    3159                 :            : 
    3160   [ +  -  +  - ]:       3240 :         ctx->io_unit_offset += io_units_count;
    3161   [ +  -  +  - ]:       3240 :         ctx->io_units_remaining -= io_units_count;
    3162   [ +  -  +  - ]:       3240 :         ctx->io_units_done += io_units_count;
    3163   [ +  -  +  - ]:       3240 :         iov = &ctx->iov[0];
    3164                 :            : 
    3165   [ +  +  +  +  :       3240 :         if (ctx->read) {
             +  -  +  + ]
    3166   [ +  -  +  -  :       2856 :                 spdk_blob_io_readv_ext(ctx->blob, ctx->channel, iov, iovcnt, io_unit_offset,
             +  -  +  - ]
    3167   [ +  -  +  - ]:        408 :                                        io_units_count, rw_iov_split_next, ctx, ctx->ext_io_opts);
    3168                 :        408 :         } else {
    3169   [ +  -  +  -  :        924 :                 spdk_blob_io_writev_ext(ctx->blob, ctx->channel, iov, iovcnt, io_unit_offset,
             +  -  +  - ]
    3170   [ +  -  +  - ]:        132 :                                         io_units_count, rw_iov_split_next, ctx, ctx->ext_io_opts);
    3171                 :            :         }
    3172         [ -  + ]:        744 : }
    3173                 :            : 
    3174                 :            : static void
    3175                 :   16471392 : blob_request_submit_rw_iov(struct spdk_blob *blob, struct spdk_io_channel *_channel,
    3176                 :            :                            struct iovec *iov, int iovcnt,
    3177                 :            :                            uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg, bool read,
    3178                 :            :                            struct spdk_blob_ext_io_opts *ext_io_opts)
    3179                 :            : {
    3180                 :    4824868 :         struct spdk_bs_cpl      cpl;
    3181                 :            : 
    3182   [ +  +  #  # ]:   16471392 :         assert(blob != NULL);
    3183                 :            : 
    3184   [ +  +  +  +  :   16471392 :         if (!read && blob->data_ro) {
          +  +  +  -  +  
                -  +  + ]
    3185   [ -  +  +  - ]:         58 :                 cb_fn(cb_arg, -EPERM);
    3186                 :       8144 :                 return;
    3187                 :            :         }
    3188                 :            : 
    3189         [ +  + ]:   16471334 :         if (length == 0) {
    3190   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, 0);
    3191                 :          0 :                 return;
    3192                 :            :         }
    3193                 :            : 
    3194   [ +  +  +  -  :   16471334 :         if (offset + length > bs_cluster_to_lba(blob->bs, blob->active.num_clusters)) {
          +  -  +  -  +  
                -  -  + ]
    3195   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -EINVAL);
    3196                 :          0 :                 return;
    3197                 :            :         }
    3198                 :            : 
    3199                 :            :         /*
    3200                 :            :          * For now, we implement readv/writev using a sequence (instead of a batch) to account for having
    3201                 :            :          *  to split a request that spans a cluster boundary.  For I/O that do not span a cluster boundary,
    3202                 :            :          *  there will be no noticeable difference compared to using a batch.  For I/O that do span a cluster
    3203                 :            :          *  boundary, the target LBAs (after blob offset to LBA translation) may not be contiguous, so we need
    3204                 :            :          *  to allocate a separate iov array and split the I/O such that none of the resulting
    3205                 :            :          *  smaller I/O cross a cluster boundary.  These smaller I/O will be issued in sequence (not in parallel)
    3206                 :            :          *  but since this case happens very infrequently, any performance impact will be negligible.
    3207                 :            :          *
    3208                 :            :          * This could be optimized in the future to allocate a big enough iov array to account for all of the iovs
    3209                 :            :          *  for all of the smaller I/Os, pre-build all of the iov arrays for the smaller I/Os, then issue them
    3210                 :            :          *  in a batch.  That would also require creating an intermediate spdk_bs_cpl that would get called
    3211                 :            :          *  when the batch was completed, to allow for freeing the memory for the iov arrays.
    3212                 :            :          */
    3213         [ +  + ]:   16471334 :         if (spdk_likely(length <= bs_num_io_units_to_cluster_boundary(blob, offset))) {
    3214                 :    4823774 :                 uint64_t lba_count;
    3215                 :    4823774 :                 uint64_t lba;
    3216                 :       2376 :                 bool is_allocated;
    3217                 :            : 
    3218                 :   16470086 :                 cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    3219   [ +  -  +  -  :   16470086 :                 cpl.u.blob_basic.cb_fn = cb_fn;
                   +  - ]
    3220   [ +  -  +  -  :   16470086 :                 cpl.u.blob_basic.cb_arg = cb_arg;
                   +  - ]
    3221                 :            : 
    3222   [ +  +  +  -  :   16470086 :                 if (blob->frozen_refcnt) {
                   -  + ]
    3223                 :            :                         /* This blob I/O is frozen */
    3224                 :          0 :                         enum spdk_blob_op_type op_type;
    3225                 :          0 :                         spdk_bs_user_op_t *op;
    3226                 :       1128 :                         struct spdk_bs_channel *bs_channel = spdk_io_channel_get_ctx(_channel);
    3227                 :            : 
    3228         [ -  + ]:       1128 :                         op_type = read ? SPDK_BLOB_READV : SPDK_BLOB_WRITEV;
    3229                 :       1128 :                         op = bs_user_op_alloc(_channel, &cpl, op_type, blob, iov, iovcnt, offset, length);
    3230         [ -  + ]:       1128 :                         if (!op) {
    3231   [ #  #  #  # ]:          0 :                                 cb_fn(cb_arg, -ENOMEM);
    3232                 :       8082 :                                 return;
    3233                 :            :                         }
    3234                 :            : 
    3235   [ #  #  #  #  :       1128 :                         TAILQ_INSERT_TAIL(&bs_channel->queued_io, op, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    3236                 :            : 
    3237                 :       1128 :                         return;
    3238                 :          0 :                 }
    3239                 :            : 
    3240                 :   16468958 :                 is_allocated = blob_calculate_lba_and_lba_count(blob, offset, length, &lba, &lba_count);
    3241                 :            : 
    3242   [ +  +  +  + ]:   16468958 :                 if (read) {
    3243                 :       2084 :                         spdk_bs_sequence_t *seq;
    3244                 :            : 
    3245                 :    7841242 :                         seq = bs_sequence_start_blob(_channel, &cpl, blob);
    3246         [ +  + ]:    7841242 :                         if (!seq) {
    3247   [ #  #  #  # ]:        747 :                                 cb_fn(cb_arg, -ENOMEM);
    3248                 :        747 :                                 return;
    3249                 :            :                         }
    3250                 :            : 
    3251   [ +  -  +  - ]:    7840495 :                         seq->ext_io_opts = ext_io_opts;
    3252                 :            : 
    3253   [ +  +  +  + ]:    7840495 :                         if (is_allocated) {
    3254                 :    7011171 :                                 bs_sequence_readv_dev(seq, iov, iovcnt, lba, lba_count, rw_iov_done, NULL);
    3255                 :        540 :                         } else {
    3256   [ +  -  +  - ]:     829324 :                                 bs_sequence_readv_bs_dev(seq, blob->back_bs_dev, iov, iovcnt, lba, lba_count,
    3257                 :            :                                                          rw_iov_done, NULL);
    3258                 :            :                         }
    3259         [ -  + ]:       2084 :                 } else {
    3260   [ +  +  +  + ]:    8627716 :                         if (is_allocated) {
    3261                 :        276 :                                 spdk_bs_sequence_t *seq;
    3262                 :            : 
    3263                 :    8486325 :                                 seq = bs_sequence_start_blob(_channel, &cpl, blob);
    3264         [ +  + ]:    8486325 :                                 if (!seq) {
    3265   [ #  #  #  # ]:      73912 :                                         cb_fn(cb_arg, -ENOMEM);
    3266                 :      73912 :                                         return;
    3267                 :            :                                 }
    3268                 :            : 
    3269   [ +  -  +  - ]:    8412413 :                                 seq->ext_io_opts = ext_io_opts;
    3270                 :            : 
    3271                 :    8412413 :                                 bs_sequence_writev_dev(seq, iov, iovcnt, lba, lba_count, rw_iov_done, NULL);
    3272         [ -  + ]:        276 :                         } else {
    3273                 :            :                                 /* Queue this operation and allocate the cluster */
    3274                 :         16 :                                 spdk_bs_user_op_t *op;
    3275                 :            : 
    3276                 :     141407 :                                 op = bs_user_op_alloc(_channel, &cpl, SPDK_BLOB_WRITEV, blob, iov, iovcnt, offset,
    3277                 :         16 :                                                       length);
    3278         [ +  + ]:     141391 :                                 if (!op) {
    3279   [ #  #  #  # ]:          0 :                                         cb_fn(cb_arg, -ENOMEM);
    3280                 :          0 :                                         return;
    3281                 :            :                                 }
    3282                 :            : 
    3283   [ +  -  +  - ]:     141391 :                                 op->ext_io_opts = ext_io_opts;
    3284                 :            : 
    3285                 :     141391 :                                 bs_allocate_and_copy_cluster(blob, _channel, offset, op);
    3286         [ -  + ]:         16 :                         }
    3287                 :            :                 }
    3288         [ -  + ]:       2376 :         } else {
    3289                 :        208 :                 struct rw_iov_ctx *ctx;
    3290                 :            : 
    3291                 :       1248 :                 ctx = calloc(1, sizeof(struct rw_iov_ctx) + iovcnt * sizeof(struct iovec));
    3292         [ +  + ]:       1248 :                 if (ctx == NULL) {
    3293   [ -  +  +  - ]:         24 :                         cb_fn(cb_arg, -ENOMEM);
    3294                 :         24 :                         return;
    3295                 :            :                 }
    3296                 :            : 
    3297   [ +  -  +  - ]:       1224 :                 ctx->blob = blob;
    3298   [ +  -  +  - ]:       1224 :                 ctx->channel = _channel;
    3299   [ +  -  +  - ]:       1224 :                 ctx->cb_fn = cb_fn;
    3300   [ +  -  +  - ]:       1224 :                 ctx->cb_arg = cb_arg;
    3301   [ +  -  +  -  :       1224 :                 ctx->read = read;
                   +  - ]
    3302   [ +  -  +  - ]:       1224 :                 ctx->orig_iov = iov;
    3303   [ +  -  +  - ]:       1224 :                 ctx->iovcnt = iovcnt;
    3304   [ +  -  +  - ]:       1224 :                 ctx->io_unit_offset = offset;
    3305   [ +  -  +  - ]:       1224 :                 ctx->io_units_remaining = length;
    3306   [ +  -  +  - ]:       1224 :                 ctx->io_units_done = 0;
    3307   [ +  -  +  - ]:       1224 :                 ctx->ext_io_opts = ext_io_opts;
    3308                 :            : 
    3309                 :       1224 :                 rw_iov_split_next(ctx, 0);
    3310         [ +  + ]:        208 :         }
    3311         [ -  + ]:       2588 : }
    3312                 :            : 
    3313                 :            : static struct spdk_blob *
    3314                 :      84353 : blob_lookup(struct spdk_blob_store *bs, spdk_blob_id blobid)
    3315                 :            : {
    3316                 :      75849 :         struct spdk_blob find;
    3317                 :            : 
    3318   [ +  +  +  -  :      84353 :         if (spdk_bit_array_get(bs->open_blobids, blobid) == 0) {
                   +  + ]
    3319                 :      80306 :                 return NULL;
    3320                 :            :         }
    3321                 :            : 
    3322         [ +  - ]:       4047 :         find.id = blobid;
    3323         [ +  - ]:       4047 :         return RB_FIND(spdk_blob_tree, &bs->open_blobs, &find);
    3324                 :       7197 : }
    3325                 :            : 
    3326                 :            : static void
    3327                 :      11574 : blob_get_snapshot_and_clone_entries(struct spdk_blob *blob,
    3328                 :            :                                     struct spdk_blob_list **snapshot_entry, struct spdk_blob_list **clone_entry)
    3329                 :            : {
    3330   [ +  +  #  # ]:      11574 :         assert(blob != NULL);
    3331         [ +  - ]:      11574 :         *snapshot_entry = NULL;
    3332         [ +  - ]:      11574 :         *clone_entry = NULL;
    3333                 :            : 
    3334   [ +  +  +  -  :      11574 :         if (blob->parent_id == SPDK_BLOBID_INVALID) {
                   +  + ]
    3335                 :      10221 :                 return;
    3336                 :            :         }
    3337                 :            : 
    3338   [ +  +  +  -  :       1912 :         TAILQ_FOREACH(*snapshot_entry, &blob->bs->snapshots, link) {
          +  -  +  -  +  
          -  +  -  +  -  
          +  +  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3339   [ +  +  +  -  :       1684 :                 if ((*snapshot_entry)->id == blob->parent_id) {
          +  -  +  -  +  
                -  +  + ]
    3340                 :       1125 :                         break;
    3341                 :            :                 }
    3342                 :         92 :         }
    3343                 :            : 
    3344   [ +  +  +  + ]:       1353 :         if (*snapshot_entry != NULL) {
    3345   [ +  -  +  -  :       1353 :                 TAILQ_FOREACH(*clone_entry, &(*snapshot_entry)->clones, link) {
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    3346   [ +  +  +  -  :       1353 :                         if ((*clone_entry)->id == blob->id) {
          +  -  +  -  +  
                -  +  + ]
    3347                 :       1125 :                                 break;
    3348                 :            :                         }
    3349                 :         36 :                 }
    3350                 :            : 
    3351   [ +  +  +  -  :       1125 :                 assert(*clone_entry != NULL);
                   #  # ]
    3352                 :        180 :         }
    3353                 :       1678 : }
    3354                 :            : 
    3355                 :            : static int
    3356                 :      10322 : bs_channel_create(void *io_device, void *ctx_buf)
    3357                 :            : {
    3358                 :      10322 :         struct spdk_blob_store          *bs = io_device;
    3359                 :      10322 :         struct spdk_bs_channel          *channel = ctx_buf;
    3360                 :        768 :         struct spdk_bs_dev              *dev;
    3361   [ +  -  +  - ]:      10322 :         uint32_t                        max_ops = bs->max_channel_ops;
    3362                 :        768 :         uint32_t                        i;
    3363                 :            : 
    3364   [ +  -  +  - ]:      10322 :         dev = bs->dev;
    3365                 :            : 
    3366   [ +  -  +  - ]:      10322 :         channel->req_mem = calloc(max_ops, sizeof(struct spdk_bs_request_set));
    3367   [ +  +  +  -  :      10322 :         if (!channel->req_mem) {
                   +  - ]
    3368                 :          0 :                 return -1;
    3369                 :            :         }
    3370                 :            : 
    3371   [ +  -  +  -  :      10322 :         TAILQ_INIT(&channel->reqs);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3372                 :            : 
    3373         [ +  + ]:    5295186 :         for (i = 0; i < max_ops; i++) {
    3374   [ +  -  +  -  :    5284864 :                 TAILQ_INSERT_TAIL(&channel->reqs, &channel->req_mem[i], link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    3375                 :     416256 :         }
    3376                 :            : 
    3377   [ +  -  +  - ]:      10322 :         channel->bs = bs;
    3378   [ +  -  +  - ]:      10322 :         channel->dev = dev;
    3379   [ +  -  +  -  :      10322 :         channel->dev_channel = dev->create_channel(dev);
          -  +  +  -  +  
                -  +  - ]
    3380                 :            : 
    3381   [ +  +  +  -  :      10322 :         if (!channel->dev_channel) {
                   +  - ]
    3382                 :          0 :                 SPDK_ERRLOG("Failed to create device channel.\n");
    3383   [ #  #  #  # ]:          0 :                 free(channel->req_mem);
    3384                 :          0 :                 return -1;
    3385                 :            :         }
    3386                 :            : 
    3387   [ +  -  +  - ]:      10322 :         channel->new_cluster_page = spdk_zmalloc(SPDK_BS_PAGE_SIZE, 0, NULL, SPDK_ENV_SOCKET_ID_ANY,
    3388                 :            :                                     SPDK_MALLOC_DMA);
    3389   [ +  +  +  -  :      10322 :         if (!channel->new_cluster_page) {
                   +  - ]
    3390                 :          0 :                 SPDK_ERRLOG("Failed to allocate new cluster page\n");
    3391   [ #  #  #  # ]:          0 :                 free(channel->req_mem);
    3392   [ #  #  #  #  :          0 :                 channel->dev->destroy_channel(channel->dev, channel->dev_channel);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
    3393                 :          0 :                 return -1;
    3394                 :            :         }
    3395                 :            : 
    3396   [ +  -  +  -  :      10322 :         TAILQ_INIT(&channel->need_cluster_alloc);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3397   [ +  -  +  -  :      10322 :         TAILQ_INIT(&channel->queued_io);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3398   [ +  -  +  -  :      10322 :         RB_INIT(&channel->esnap_channels);
                   +  - ]
    3399                 :            : 
    3400                 :      10322 :         return 0;
    3401                 :        813 : }
    3402                 :            : 
    3403                 :            : static void
    3404                 :      10322 : bs_channel_destroy(void *io_device, void *ctx_buf)
    3405                 :            : {
    3406                 :      10322 :         struct spdk_bs_channel *channel = ctx_buf;
    3407                 :        768 :         spdk_bs_user_op_t *op;
    3408                 :            : 
    3409   [ +  +  +  -  :      10322 :         while (!TAILQ_EMPTY(&channel->need_cluster_alloc)) {
             +  -  -  + ]
    3410   [ #  #  #  #  :          0 :                 op = TAILQ_FIRST(&channel->need_cluster_alloc);
                   #  # ]
    3411   [ #  #  #  #  :          0 :                 TAILQ_REMOVE(&channel->need_cluster_alloc, op, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    3412                 :          0 :                 bs_user_op_abort(op, -EIO);
    3413                 :            :         }
    3414                 :            : 
    3415   [ +  +  +  -  :      10322 :         while (!TAILQ_EMPTY(&channel->queued_io)) {
             +  -  +  - ]
    3416   [ #  #  #  #  :          0 :                 op = TAILQ_FIRST(&channel->queued_io);
                   #  # ]
    3417   [ #  #  #  #  :          0 :                 TAILQ_REMOVE(&channel->queued_io, op, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    3418                 :          0 :                 bs_user_op_abort(op, -EIO);
    3419                 :            :         }
    3420                 :            : 
    3421                 :      10322 :         blob_esnap_destroy_bs_channel(channel);
    3422                 :            : 
    3423   [ +  -  +  - ]:      10322 :         free(channel->req_mem);
    3424   [ +  -  +  - ]:      10322 :         spdk_free(channel->new_cluster_page);
    3425   [ +  -  +  -  :      10322 :         channel->dev->destroy_channel(channel->dev, channel->dev_channel);
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
                      - ]
    3426                 :      10322 : }
    3427                 :            : 
    3428                 :            : static void
    3429                 :      10055 : bs_dev_destroy(void *io_device)
    3430                 :            : {
    3431                 :      10055 :         struct spdk_blob_store *bs = io_device;
    3432                 :        752 :         struct spdk_blob        *blob, *blob_tmp;
    3433                 :            : 
    3434   [ +  -  +  -  :      10055 :         bs->dev->destroy(bs->dev);
          +  -  +  -  -  
          +  +  -  +  -  
                   +  - ]
    3435                 :            : 
    3436   [ +  +  +  -  :      10055 :         RB_FOREACH_SAFE(blob, spdk_blob_tree, &bs->open_blobs, blob_tmp) {
                   +  - ]
    3437         [ #  # ]:          0 :                 RB_REMOVE(spdk_blob_tree, &bs->open_blobs, blob);
    3438   [ #  #  #  #  :          0 :                 spdk_bit_array_clear(bs->open_blobids, blob->id);
             #  #  #  # ]
    3439                 :          0 :                 blob_free(blob);
    3440                 :          0 :         }
    3441                 :            : 
    3442         [ +  - ]:      10055 :         spdk_spin_destroy(&bs->used_lock);
    3443                 :            : 
    3444         [ +  - ]:      10055 :         spdk_bit_array_free(&bs->open_blobids);
    3445         [ +  - ]:      10055 :         spdk_bit_array_free(&bs->used_blobids);
    3446         [ +  - ]:      10055 :         spdk_bit_array_free(&bs->used_md_pages);
    3447         [ +  - ]:      10055 :         spdk_bit_pool_free(&bs->used_clusters);
    3448                 :            :         /*
    3449                 :            :          * If this function is called for any reason except a successful unload,
    3450                 :            :          * the unload_cpl type will be NONE and this will be a nop.
    3451                 :            :          */
    3452   [ +  -  +  -  :      10055 :         bs_call_cpl(&bs->unload_cpl, bs->unload_err);
                   +  - ]
    3453                 :            : 
    3454                 :      10055 :         free(bs);
    3455                 :      10055 : }
    3456                 :            : 
    3457                 :            : static int
    3458                 :      11870 : bs_blob_list_add(struct spdk_blob *blob)
    3459                 :            : {
    3460                 :        820 :         spdk_blob_id snapshot_id;
    3461                 :      11870 :         struct spdk_blob_list *snapshot_entry = NULL;
    3462                 :      11870 :         struct spdk_blob_list *clone_entry = NULL;
    3463                 :            : 
    3464   [ +  +  #  # ]:      11870 :         assert(blob != NULL);
    3465                 :            : 
    3466   [ +  -  +  - ]:      11870 :         snapshot_id = blob->parent_id;
    3467   [ +  +  +  + ]:      11870 :         if (snapshot_id == SPDK_BLOBID_INVALID ||
    3468                 :        388 :             snapshot_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT) {
    3469                 :       9637 :                 return 0;
    3470                 :            :         }
    3471                 :            : 
    3472   [ +  -  +  - ]:       2233 :         snapshot_entry = bs_get_snapshot_entry(blob->bs, snapshot_id);
    3473         [ +  + ]:       2233 :         if (snapshot_entry == NULL) {
    3474                 :            :                 /* Snapshot not found */
    3475                 :       1580 :                 snapshot_entry = calloc(1, sizeof(struct spdk_blob_list));
    3476         [ +  + ]:       1580 :                 if (snapshot_entry == NULL) {
    3477                 :          0 :                         return -ENOMEM;
    3478                 :            :                 }
    3479   [ +  -  +  - ]:       1580 :                 snapshot_entry->id = snapshot_id;
    3480   [ +  -  +  -  :       1580 :                 TAILQ_INIT(&snapshot_entry->clones);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3481   [ +  -  +  -  :       1580 :                 TAILQ_INSERT_TAIL(&blob->bs->snapshots, snapshot_entry, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
    3482                 :        256 :         } else {
    3483   [ +  +  +  -  :       1039 :                 TAILQ_FOREACH(clone_entry, &snapshot_entry->clones, link) {
          +  -  +  +  +  
             -  +  -  +  
                      - ]
    3484   [ +  +  +  -  :        386 :                         if (clone_entry->id == blob->id) {
          +  -  +  -  -  
                      + ]
    3485                 :          0 :                                 break;
    3486                 :            :                         }
    3487                 :         60 :                 }
    3488                 :            :         }
    3489                 :            : 
    3490         [ +  + ]:       2233 :         if (clone_entry == NULL) {
    3491                 :            :                 /* Clone not found */
    3492                 :       2233 :                 clone_entry = calloc(1, sizeof(struct spdk_blob_list));
    3493         [ +  + ]:       2233 :                 if (clone_entry == NULL) {
    3494                 :          0 :                         return -ENOMEM;
    3495                 :            :                 }
    3496   [ +  -  +  -  :       2233 :                 clone_entry->id = blob->id;
             +  -  +  - ]
    3497   [ +  -  +  -  :       2233 :                 TAILQ_INIT(&clone_entry->clones);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3498   [ +  -  +  -  :       2233 :                 TAILQ_INSERT_TAIL(&snapshot_entry->clones, clone_entry, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3499         [ +  - ]:       2233 :                 snapshot_entry->clone_count++;
    3500                 :        360 :         }
    3501                 :            : 
    3502                 :       2233 :         return 0;
    3503                 :        820 : }
    3504                 :            : 
    3505                 :            : static void
    3506                 :      11098 : bs_blob_list_remove(struct spdk_blob *blob)
    3507                 :            : {
    3508                 :      11098 :         struct spdk_blob_list *snapshot_entry = NULL;
    3509                 :      11098 :         struct spdk_blob_list *clone_entry = NULL;
    3510                 :            : 
    3511                 :      11098 :         blob_get_snapshot_and_clone_entries(blob, &snapshot_entry, &clone_entry);
    3512                 :            : 
    3513         [ +  + ]:      11098 :         if (snapshot_entry == NULL) {
    3514                 :      10071 :                 return;
    3515                 :            :         }
    3516                 :            : 
    3517   [ +  -  +  - ]:       1027 :         blob->parent_id = SPDK_BLOBID_INVALID;
    3518   [ +  +  +  -  :       1027 :         TAILQ_REMOVE(&snapshot_entry->clones, clone_entry, link);
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    3519                 :       1027 :         free(clone_entry);
    3520                 :            : 
    3521         [ +  - ]:       1027 :         snapshot_entry->clone_count--;
    3522         [ -  + ]:       1600 : }
    3523                 :            : 
    3524                 :            : static int
    3525                 :      10055 : bs_blob_list_free(struct spdk_blob_store *bs)
    3526                 :            : {
    3527                 :        752 :         struct spdk_blob_list *snapshot_entry;
    3528                 :        752 :         struct spdk_blob_list *snapshot_entry_tmp;
    3529                 :        752 :         struct spdk_blob_list *clone_entry;
    3530                 :        752 :         struct spdk_blob_list *clone_entry_tmp;
    3531                 :            : 
    3532   [ +  +  +  -  :      10863 :         TAILQ_FOREACH_SAFE(snapshot_entry, &bs->snapshots, link, snapshot_entry_tmp) {
          +  -  +  +  +  
          -  +  -  +  -  
                   +  + ]
    3533   [ +  +  +  -  :       1719 :                 TAILQ_FOREACH_SAFE(clone_entry, &snapshot_entry->clones, link, clone_entry_tmp) {
          +  -  +  +  +  
          -  +  -  +  -  
                   +  + ]
    3534   [ +  +  +  -  :        911 :                         TAILQ_REMOVE(&snapshot_entry->clones, clone_entry, link);
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    3535                 :        911 :                         free(clone_entry);
    3536                 :        148 :                 }
    3537   [ +  +  +  -  :        808 :                 TAILQ_REMOVE(&bs->snapshots, snapshot_entry, link);
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    3538                 :        808 :                 free(snapshot_entry);
    3539                 :        132 :         }
    3540                 :            : 
    3541                 :      10055 :         return 0;
    3542                 :        752 : }
    3543                 :            : 
    3544                 :            : static void
    3545                 :      10055 : bs_free(struct spdk_blob_store *bs)
    3546                 :            : {
    3547                 :      10055 :         bs_blob_list_free(bs);
    3548                 :            : 
    3549                 :      10055 :         bs_unregister_md_thread(bs);
    3550                 :      10055 :         spdk_io_device_unregister(bs, bs_dev_destroy);
    3551                 :      10055 : }
    3552                 :            : 
    3553                 :            : void
    3554                 :      17198 : spdk_bs_opts_init(struct spdk_bs_opts *opts, size_t opts_size)
    3555                 :            : {
    3556                 :            : 
    3557         [ +  + ]:      17198 :         if (!opts) {
    3558                 :          0 :                 SPDK_ERRLOG("opts should not be NULL\n");
    3559                 :          0 :                 return;
    3560                 :            :         }
    3561                 :            : 
    3562         [ +  + ]:      17198 :         if (!opts_size) {
    3563                 :          0 :                 SPDK_ERRLOG("opts_size should not be zero value\n");
    3564                 :          0 :                 return;
    3565                 :            :         }
    3566                 :            : 
    3567         [ +  + ]:      17198 :         memset(opts, 0, opts_size);
    3568   [ +  -  +  - ]:      17198 :         opts->opts_size = opts_size;
    3569                 :            : 
    3570                 :            : #define FIELD_OK(field) \
    3571                 :            :         offsetof(struct spdk_bs_opts, field) + sizeof(opts->field) <= opts_size
    3572                 :            : 
    3573                 :            : #define SET_FIELD(field, value) \
    3574                 :            :         if (FIELD_OK(field)) { \
    3575                 :            :                 opts->field = value; \
    3576                 :            :         } \
    3577                 :            : 
    3578   [ +  +  +  -  :      17198 :         SET_FIELD(cluster_sz, SPDK_BLOB_OPTS_CLUSTER_SZ);
                   +  - ]
    3579   [ +  +  +  -  :      17198 :         SET_FIELD(num_md_pages, SPDK_BLOB_OPTS_NUM_MD_PAGES);
                   +  - ]
    3580   [ +  +  +  -  :      17198 :         SET_FIELD(max_md_ops, SPDK_BLOB_OPTS_NUM_MD_PAGES);
                   +  - ]
    3581   [ +  +  +  -  :      17198 :         SET_FIELD(max_channel_ops, SPDK_BLOB_OPTS_DEFAULT_CHANNEL_OPS);
                   +  - ]
    3582   [ +  +  +  -  :      17198 :         SET_FIELD(clear_method,  BS_CLEAR_WITH_UNMAP);
                   +  - ]
    3583                 :            : 
    3584         [ +  + ]:      17198 :         if (FIELD_OK(bstype)) {
    3585   [ +  +  +  - ]:      17198 :                 memset(&opts->bstype, 0, sizeof(opts->bstype));
    3586                 :       1098 :         }
    3587                 :            : 
    3588   [ +  +  +  -  :      17198 :         SET_FIELD(iter_cb_fn, NULL);
                   +  - ]
    3589   [ +  +  +  -  :      17198 :         SET_FIELD(iter_cb_arg, NULL);
                   +  - ]
    3590   [ +  +  +  -  :      17198 :         SET_FIELD(force_recover, false);
                   +  - ]
    3591   [ +  +  +  -  :      17198 :         SET_FIELD(esnap_bs_dev_create, NULL);
                   +  - ]
    3592   [ +  +  +  -  :      17198 :         SET_FIELD(esnap_ctx, NULL);
                   +  - ]
    3593                 :            : 
    3594                 :            : #undef FIELD_OK
    3595                 :            : #undef SET_FIELD
    3596                 :       1098 : }
    3597                 :            : 
    3598                 :            : static int
    3599                 :       2919 : bs_opts_verify(struct spdk_bs_opts *opts)
    3600                 :            : {
    3601   [ +  +  +  -  :       3371 :         if (opts->cluster_sz == 0 || opts->num_md_pages == 0 || opts->max_md_ops == 0 ||
          +  +  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    3602   [ +  +  +  - ]:       2895 :             opts->max_channel_ops == 0) {
    3603                 :         24 :                 SPDK_ERRLOG("Blobstore options cannot be set to 0\n");
    3604                 :         24 :                 return -1;
    3605                 :            :         }
    3606                 :            : 
    3607                 :       2895 :         return 0;
    3608                 :        456 : }
    3609                 :            : 
    3610                 :            : /* START spdk_bs_load */
    3611                 :            : 
    3612                 :            : /* spdk_bs_load_ctx is used for init, load, unload and dump code paths. */
    3613                 :            : 
    3614                 :            : struct spdk_bs_load_ctx {
    3615                 :            :         struct spdk_blob_store          *bs;
    3616                 :            :         struct spdk_bs_super_block      *super;
    3617                 :            : 
    3618                 :            :         struct spdk_bs_md_mask          *mask;
    3619                 :            :         bool                            in_page_chain;
    3620                 :            :         uint32_t                        page_index;
    3621                 :            :         uint32_t                        cur_page;
    3622                 :            :         struct spdk_blob_md_page        *page;
    3623                 :            : 
    3624                 :            :         uint64_t                        num_extent_pages;
    3625                 :            :         uint32_t                        *extent_page_num;
    3626                 :            :         struct spdk_blob_md_page        *extent_pages;
    3627                 :            :         struct spdk_bit_array           *used_clusters;
    3628                 :            : 
    3629                 :            :         spdk_bs_sequence_t                      *seq;
    3630                 :            :         spdk_blob_op_with_handle_complete       iter_cb_fn;
    3631                 :            :         void                                    *iter_cb_arg;
    3632                 :            :         struct spdk_blob                        *blob;
    3633                 :            :         spdk_blob_id                            blobid;
    3634                 :            : 
    3635                 :            :         bool                                    force_recover;
    3636                 :            : 
    3637                 :            :         /* These fields are used in the spdk_bs_dump path. */
    3638                 :            :         bool                                    dumping;
    3639                 :            :         FILE                                    *fp;
    3640                 :            :         spdk_bs_dump_print_xattr                print_xattr_fn;
    3641                 :            :         char                                    xattr_name[4096];
    3642                 :            : };
    3643                 :            : 
    3644                 :            : static int
    3645                 :      10129 : bs_alloc(struct spdk_bs_dev *dev, struct spdk_bs_opts *opts, struct spdk_blob_store **_bs,
    3646                 :            :          struct spdk_bs_load_ctx **_ctx)
    3647                 :            : {
    3648                 :        756 :         struct spdk_blob_store  *bs;
    3649                 :        756 :         struct spdk_bs_load_ctx *ctx;
    3650                 :        756 :         uint64_t dev_size;
    3651                 :        756 :         int rc;
    3652                 :            : 
    3653   [ +  -  +  -  :      10129 :         dev_size = dev->blocklen * dev->blockcnt;
             +  -  +  - ]
    3654   [ +  +  +  -  :      10129 :         if (dev_size < opts->cluster_sz) {
                   +  + ]
    3655                 :            :                 /* Device size cannot be smaller than cluster size of blobstore */
    3656   [ +  +  +  +  :         50 :                 SPDK_INFOLOG(blob, "Device size %" PRIu64 " is smaller than cluster size %" PRIu32 "\n",
          +  -  #  #  #  
                      # ]
    3657                 :            :                              dev_size, opts->cluster_sz);
    3658                 :         50 :                 return -ENOSPC;
    3659                 :            :         }
    3660   [ +  +  +  -  :      10079 :         if (opts->cluster_sz < SPDK_BS_PAGE_SIZE) {
                   +  + ]
    3661                 :            :                 /* Cluster size cannot be smaller than page size */
    3662   [ +  -  +  - ]:         24 :                 SPDK_ERRLOG("Cluster size %" PRIu32 " is smaller than page size %d\n",
    3663                 :            :                             opts->cluster_sz, SPDK_BS_PAGE_SIZE);
    3664                 :         24 :                 return -EINVAL;
    3665                 :            :         }
    3666                 :      10055 :         bs = calloc(1, sizeof(struct spdk_blob_store));
    3667         [ +  + ]:      10055 :         if (!bs) {
    3668                 :          0 :                 return -ENOMEM;
    3669                 :            :         }
    3670                 :            : 
    3671                 :      10055 :         ctx = calloc(1, sizeof(struct spdk_bs_load_ctx));
    3672         [ +  + ]:      10055 :         if (!ctx) {
    3673                 :          0 :                 free(bs);
    3674                 :          0 :                 return -ENOMEM;
    3675                 :            :         }
    3676                 :            : 
    3677   [ +  -  +  - ]:      10055 :         ctx->bs = bs;
    3678   [ +  -  +  -  :      10055 :         ctx->iter_cb_fn = opts->iter_cb_fn;
             +  -  +  - ]
    3679   [ +  -  +  -  :      10055 :         ctx->iter_cb_arg = opts->iter_cb_arg;
             +  -  +  - ]
    3680   [ +  -  +  -  :      10055 :         ctx->force_recover = opts->force_recover;
             +  -  +  - ]
    3681                 :            : 
    3682   [ +  -  +  - ]:      10055 :         ctx->super = spdk_zmalloc(sizeof(*ctx->super), 0x1000, NULL,
    3683                 :            :                                   SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    3684   [ +  +  +  -  :      10055 :         if (!ctx->super) {
                   +  - ]
    3685                 :          0 :                 free(ctx);
    3686                 :          0 :                 free(bs);
    3687                 :          0 :                 return -ENOMEM;
    3688                 :            :         }
    3689                 :            : 
    3690   [ +  -  +  -  :      10055 :         RB_INIT(&bs->open_blobs);
                   +  - ]
    3691   [ +  -  +  -  :      10055 :         TAILQ_INIT(&bs->snapshots);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3692   [ +  -  +  - ]:      10055 :         bs->dev = dev;
    3693   [ +  -  +  - ]:      10055 :         bs->md_thread = spdk_get_thread();
    3694   [ +  +  +  -  :      10055 :         assert(bs->md_thread != NULL);
             +  -  #  # ]
    3695                 :            : 
    3696                 :            :         /*
    3697                 :            :          * Do not use bs_lba_to_cluster() here since blockcnt may not be an
    3698                 :            :          *  even multiple of the cluster size.
    3699                 :            :          */
    3700   [ +  -  +  -  :      10055 :         bs->cluster_sz = opts->cluster_sz;
             +  -  +  - ]
    3701   [ +  +  +  +  :      10055 :         bs->total_clusters = dev->blockcnt / (bs->cluster_sz / dev->blocklen);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    3702   [ +  -  +  -  :      10055 :         ctx->used_clusters = spdk_bit_array_create(bs->total_clusters);
             +  -  +  - ]
    3703   [ +  +  +  -  :      10055 :         if (!ctx->used_clusters) {
                   +  - ]
    3704   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    3705                 :          0 :                 free(ctx);
    3706                 :          0 :                 free(bs);
    3707                 :          0 :                 return -ENOMEM;
    3708                 :            :         }
    3709                 :            : 
    3710   [ +  -  +  -  :      10055 :         bs->pages_per_cluster = bs->cluster_sz / SPDK_BS_PAGE_SIZE;
          +  -  +  -  +  
                      - ]
    3711   [ +  -  +  -  :      10055 :         if (spdk_u32_is_pow2(bs->pages_per_cluster)) {
                   -  + ]
    3712   [ +  -  +  -  :      10055 :                 bs->pages_per_cluster_shift = spdk_u32log2(bs->pages_per_cluster);
             +  -  +  - ]
    3713                 :        797 :         }
    3714   [ +  -  +  -  :      10055 :         bs->num_free_clusters = bs->total_clusters;
             +  -  +  - ]
    3715   [ +  -  +  -  :      10055 :         bs->io_unit_size = dev->blocklen;
             +  -  +  - ]
    3716                 :            : 
    3717   [ +  -  +  -  :      10055 :         bs->max_channel_ops = opts->max_channel_ops;
             +  -  +  - ]
    3718   [ +  -  +  - ]:      10055 :         bs->super_blob = SPDK_BLOBID_INVALID;
    3719   [ +  -  +  -  :      10055 :         memcpy(&bs->bstype, &opts->bstype, sizeof(opts->bstype));
             +  -  +  - ]
    3720   [ +  -  +  -  :      10055 :         bs->esnap_bs_dev_create = opts->esnap_bs_dev_create;
             +  -  +  - ]
    3721   [ +  -  +  -  :      10055 :         bs->esnap_ctx = opts->esnap_ctx;
             +  -  +  - ]
    3722                 :            : 
    3723                 :            :         /* The metadata is assumed to be at least 1 page */
    3724   [ +  -  +  - ]:      10055 :         bs->used_md_pages = spdk_bit_array_create(1);
    3725   [ +  -  +  - ]:      10055 :         bs->used_blobids = spdk_bit_array_create(0);
    3726   [ +  -  +  - ]:      10055 :         bs->open_blobids = spdk_bit_array_create(0);
    3727                 :            : 
    3728         [ +  - ]:      10055 :         spdk_spin_init(&bs->used_lock);
    3729                 :            : 
    3730                 :      10055 :         spdk_io_device_register(bs, bs_channel_create, bs_channel_destroy,
    3731                 :            :                                 sizeof(struct spdk_bs_channel), "blobstore");
    3732                 :      10055 :         rc = bs_register_md_thread(bs);
    3733         [ +  + ]:      10055 :         if (rc == -1) {
    3734                 :          0 :                 spdk_io_device_unregister(bs, NULL);
    3735         [ #  # ]:          0 :                 spdk_spin_destroy(&bs->used_lock);
    3736         [ #  # ]:          0 :                 spdk_bit_array_free(&bs->open_blobids);
    3737         [ #  # ]:          0 :                 spdk_bit_array_free(&bs->used_blobids);
    3738         [ #  # ]:          0 :                 spdk_bit_array_free(&bs->used_md_pages);
    3739         [ #  # ]:          0 :                 spdk_bit_array_free(&ctx->used_clusters);
    3740   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    3741                 :          0 :                 free(ctx);
    3742                 :          0 :                 free(bs);
    3743                 :            :                 /* FIXME: this is a lie but don't know how to get a proper error code here */
    3744                 :          0 :                 return -ENOMEM;
    3745                 :            :         }
    3746                 :            : 
    3747         [ +  - ]:      10055 :         *_ctx = ctx;
    3748         [ +  - ]:      10055 :         *_bs = bs;
    3749                 :      10055 :         return 0;
    3750                 :        803 : }
    3751                 :            : 
    3752                 :            : static void
    3753                 :       5421 : bs_load_ctx_fail(struct spdk_bs_load_ctx *ctx, int bserrno)
    3754                 :            : {
    3755   [ +  +  #  # ]:       5421 :         assert(bserrno != 0);
    3756                 :            : 
    3757   [ +  -  +  - ]:       5421 :         spdk_free(ctx->super);
    3758   [ +  -  +  - ]:       5421 :         bs_sequence_finish(ctx->seq, bserrno);
    3759   [ +  -  +  - ]:       5421 :         bs_free(ctx->bs);
    3760         [ +  - ]:       5421 :         spdk_bit_array_free(&ctx->used_clusters);
    3761                 :       5421 :         free(ctx);
    3762                 :       5421 : }
    3763                 :            : 
    3764                 :            : static void
    3765                 :       5151 : bs_write_super(spdk_bs_sequence_t *seq, struct spdk_blob_store *bs,
    3766                 :            :                struct spdk_bs_super_block *super, spdk_bs_sequence_cpl cb_fn, void *cb_arg)
    3767                 :            : {
    3768                 :            :         /* Update the values in the super block */
    3769   [ +  -  +  -  :       5151 :         super->super_blob = bs->super_blob;
             +  -  +  - ]
    3770   [ +  -  +  -  :       5151 :         memcpy(&super->bstype, &bs->bstype, sizeof(bs->bstype));
             +  -  +  - ]
    3771   [ +  -  +  - ]:       5151 :         super->crc = blob_md_page_calc_crc(super);
    3772                 :       5947 :         bs_sequence_write_dev(seq, super, bs_page_to_lba(bs, 0),
    3773                 :       5151 :                               bs_byte_to_lba(bs, sizeof(*super)),
    3774                 :        796 :                               cb_fn, cb_arg);
    3775                 :       5151 : }
    3776                 :            : 
    3777                 :            : static void
    3778                 :       4549 : bs_write_used_clusters(spdk_bs_sequence_t *seq, void *arg, spdk_bs_sequence_cpl cb_fn)
    3779                 :            : {
    3780                 :       4549 :         struct spdk_bs_load_ctx *ctx = arg;
    3781                 :        732 :         uint64_t        mask_size, lba, lba_count;
    3782                 :            : 
    3783                 :            :         /* Write out the used clusters mask */
    3784   [ +  -  +  -  :       4549 :         mask_size = ctx->super->used_cluster_mask_len * SPDK_BS_PAGE_SIZE;
             +  -  +  - ]
    3785   [ +  -  +  - ]:       4549 :         ctx->mask = spdk_zmalloc(mask_size, 0x1000, NULL,
    3786                 :            :                                  SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    3787   [ +  +  +  -  :       4549 :         if (!ctx->mask) {
                   +  - ]
    3788                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    3789                 :          0 :                 return;
    3790                 :            :         }
    3791                 :            : 
    3792   [ +  -  +  -  :       4549 :         ctx->mask->type = SPDK_MD_MASK_TYPE_USED_CLUSTERS;
             +  -  +  - ]
    3793   [ +  -  +  -  :       4549 :         ctx->mask->length = ctx->bs->total_clusters;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3794                 :            :         /* We could get here through the normal unload path, or through dirty
    3795                 :            :          * shutdown recovery.  For the normal unload path, we use the mask from
    3796                 :            :          * the bit pool.  For dirty shutdown recovery, we don't have a bit pool yet -
    3797                 :            :          * only the bit array from the load ctx.
    3798                 :            :          */
    3799   [ +  +  +  -  :       4549 :         if (ctx->bs->used_clusters) {
          +  -  +  -  +  
                      + ]
    3800   [ +  +  +  -  :       3908 :                 assert(ctx->mask->length == spdk_bit_pool_capacity(ctx->bs->used_clusters));
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    3801   [ +  -  +  -  :       3908 :                 spdk_bit_pool_store_mask(ctx->bs->used_clusters, ctx->mask->mask);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    3802                 :        626 :         } else {
    3803   [ +  +  +  -  :        641 :                 assert(ctx->mask->length == spdk_bit_array_capacity(ctx->used_clusters));
          +  -  +  -  +  
          -  +  -  +  -  
                   #  # ]
    3804   [ +  -  +  -  :        641 :                 spdk_bit_array_store_mask(ctx->used_clusters, ctx->mask->mask);
          +  -  +  -  +  
                      - ]
    3805                 :            :         }
    3806   [ +  -  +  -  :       4549 :         lba = bs_page_to_lba(ctx->bs, ctx->super->used_cluster_mask_start);
          +  -  +  -  +  
                -  +  - ]
    3807   [ +  -  +  -  :       4549 :         lba_count = bs_page_to_lba(ctx->bs, ctx->super->used_cluster_mask_len);
          +  -  +  -  +  
                -  +  - ]
    3808   [ +  -  +  - ]:       4549 :         bs_sequence_write_dev(seq, ctx->mask, lba, lba_count, cb_fn, arg);
    3809         [ -  + ]:        732 : }
    3810                 :            : 
    3811                 :            : static void
    3812                 :       4549 : bs_write_used_md(spdk_bs_sequence_t *seq, void *arg, spdk_bs_sequence_cpl cb_fn)
    3813                 :            : {
    3814                 :       4549 :         struct spdk_bs_load_ctx *ctx = arg;
    3815                 :        732 :         uint64_t        mask_size, lba, lba_count;
    3816                 :            : 
    3817   [ +  -  +  -  :       4549 :         mask_size = ctx->super->used_page_mask_len * SPDK_BS_PAGE_SIZE;
             +  -  +  - ]
    3818   [ +  -  +  - ]:       4549 :         ctx->mask = spdk_zmalloc(mask_size, 0x1000, NULL,
    3819                 :            :                                  SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    3820   [ +  +  +  -  :       4549 :         if (!ctx->mask) {
                   +  - ]
    3821                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    3822                 :          0 :                 return;
    3823                 :            :         }
    3824                 :            : 
    3825   [ +  -  +  -  :       4549 :         ctx->mask->type = SPDK_MD_MASK_TYPE_USED_PAGES;
             +  -  +  - ]
    3826   [ +  -  +  -  :       4549 :         ctx->mask->length = ctx->super->md_len;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3827   [ +  +  +  -  :       4549 :         assert(ctx->mask->length == spdk_bit_array_capacity(ctx->bs->used_md_pages));
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    3828                 :            : 
    3829   [ +  -  +  -  :       4549 :         spdk_bit_array_store_mask(ctx->bs->used_md_pages, ctx->mask->mask);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    3830   [ +  -  +  -  :       4549 :         lba = bs_page_to_lba(ctx->bs, ctx->super->used_page_mask_start);
          +  -  +  -  +  
                -  +  - ]
    3831   [ +  -  +  -  :       4549 :         lba_count = bs_page_to_lba(ctx->bs, ctx->super->used_page_mask_len);
          +  -  +  -  +  
                -  +  - ]
    3832   [ +  -  +  - ]:       4549 :         bs_sequence_write_dev(seq, ctx->mask, lba, lba_count, cb_fn, arg);
    3833         [ -  + ]:        732 : }
    3834                 :            : 
    3835                 :            : static void
    3836                 :       4549 : bs_write_used_blobids(spdk_bs_sequence_t *seq, void *arg, spdk_bs_sequence_cpl cb_fn)
    3837                 :            : {
    3838                 :       4549 :         struct spdk_bs_load_ctx *ctx = arg;
    3839                 :        732 :         uint64_t        mask_size, lba, lba_count;
    3840                 :            : 
    3841   [ +  +  +  -  :       4549 :         if (ctx->super->used_blobid_mask_len == 0) {
          +  -  +  -  +  
                      + ]
    3842                 :            :                 /*
    3843                 :            :                  * This is a pre-v3 on-disk format where the blobid mask does not get
    3844                 :            :                  *  written to disk.
    3845                 :            :                  */
    3846   [ -  +  +  - ]:        144 :                 cb_fn(seq, arg, 0);
    3847                 :        144 :                 return;
    3848                 :            :         }
    3849                 :            : 
    3850   [ +  -  +  -  :       4405 :         mask_size = ctx->super->used_blobid_mask_len * SPDK_BS_PAGE_SIZE;
             +  -  +  - ]
    3851   [ +  -  +  - ]:       4405 :         ctx->mask = spdk_zmalloc(mask_size, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY,
    3852                 :            :                                  SPDK_MALLOC_DMA);
    3853   [ +  +  +  -  :       4405 :         if (!ctx->mask) {
                   +  - ]
    3854                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    3855                 :          0 :                 return;
    3856                 :            :         }
    3857                 :            : 
    3858   [ +  -  +  -  :       4405 :         ctx->mask->type = SPDK_MD_MASK_TYPE_USED_BLOBIDS;
             +  -  +  - ]
    3859   [ +  -  +  -  :       4405 :         ctx->mask->length = ctx->super->md_len;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    3860   [ +  +  +  -  :       4405 :         assert(ctx->mask->length == spdk_bit_array_capacity(ctx->bs->used_blobids));
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    3861                 :            : 
    3862   [ +  -  +  -  :       4405 :         spdk_bit_array_store_mask(ctx->bs->used_blobids, ctx->mask->mask);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    3863   [ +  -  +  -  :       4405 :         lba = bs_page_to_lba(ctx->bs, ctx->super->used_blobid_mask_start);
          +  -  +  -  +  
                -  +  - ]
    3864   [ +  -  +  -  :       4405 :         lba_count = bs_page_to_lba(ctx->bs, ctx->super->used_blobid_mask_len);
          +  -  +  -  +  
                -  +  - ]
    3865   [ +  -  +  - ]:       4405 :         bs_sequence_write_dev(seq, ctx->mask, lba, lba_count, cb_fn, arg);
    3866         [ -  + ]:        732 : }
    3867                 :            : 
    3868                 :            : static void
    3869                 :       3742 : blob_set_thin_provision(struct spdk_blob *blob)
    3870                 :            : {
    3871                 :       3742 :         blob_verify_md_op(blob);
    3872   [ +  -  +  -  :       3742 :         blob->invalid_flags |= SPDK_BLOB_THIN_PROV;
                   +  - ]
    3873   [ +  -  +  - ]:       3742 :         blob->state = SPDK_BLOB_STATE_DIRTY;
    3874                 :       3742 : }
    3875                 :            : 
    3876                 :            : static void
    3877                 :      15048 : blob_set_clear_method(struct spdk_blob *blob, enum blob_clear_method clear_method)
    3878                 :            : {
    3879                 :      15048 :         blob_verify_md_op(blob);
    3880   [ +  -  +  - ]:      15048 :         blob->clear_method = clear_method;
    3881   [ +  -  +  -  :      15048 :         blob->md_ro_flags |= (clear_method << SPDK_BLOB_CLEAR_METHOD_SHIFT);
                   +  - ]
    3882   [ +  -  +  - ]:      15048 :         blob->state = SPDK_BLOB_STATE_DIRTY;
    3883                 :      15048 : }
    3884                 :            : 
    3885                 :            : static void bs_load_iter(void *arg, struct spdk_blob *blob, int bserrno);
    3886                 :            : 
    3887                 :            : static void
    3888                 :        144 : bs_delete_corrupted_blob_cpl(void *cb_arg, int bserrno)
    3889                 :            : {
    3890                 :        144 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    3891                 :         24 :         spdk_blob_id id;
    3892                 :         24 :         int64_t page_num;
    3893                 :            : 
    3894                 :            :         /* Iterate to next blob (we can't use spdk_bs_iter_next function as our
    3895                 :            :          * last blob has been removed */
    3896   [ +  -  +  - ]:        144 :         page_num = bs_blobid_to_page(ctx->blobid);
    3897         [ +  - ]:        144 :         page_num++;
    3898   [ +  -  +  -  :        144 :         page_num = spdk_bit_array_find_first_set(ctx->bs->used_blobids, page_num);
             +  -  +  - ]
    3899   [ +  -  +  -  :        144 :         if (page_num >= spdk_bit_array_capacity(ctx->bs->used_blobids)) {
          +  -  +  -  +  
                      - ]
    3900                 :        144 :                 bs_load_iter(ctx, NULL, -ENOENT);
    3901                 :        144 :                 return;
    3902                 :            :         }
    3903                 :            : 
    3904                 :          0 :         id = bs_page_to_blobid(page_num);
    3905                 :            : 
    3906   [ #  #  #  # ]:          0 :         spdk_bs_open_blob(ctx->bs, id, bs_load_iter, ctx);
    3907         [ -  + ]:         24 : }
    3908                 :            : 
    3909                 :            : static void
    3910                 :        144 : bs_delete_corrupted_close_cb(void *cb_arg, int bserrno)
    3911                 :            : {
    3912                 :        144 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    3913                 :            : 
    3914         [ -  + ]:        144 :         if (bserrno != 0) {
    3915                 :          0 :                 SPDK_ERRLOG("Failed to close corrupted blob\n");
    3916   [ #  #  #  #  :          0 :                 spdk_bs_iter_next(ctx->bs, ctx->blob, bs_load_iter, ctx);
             #  #  #  # ]
    3917                 :          0 :                 return;
    3918                 :            :         }
    3919                 :            : 
    3920   [ +  -  +  -  :        144 :         spdk_bs_delete_blob(ctx->bs, ctx->blobid, bs_delete_corrupted_blob_cpl, ctx);
             +  -  +  - ]
    3921         [ -  + ]:         24 : }
    3922                 :            : 
    3923                 :            : static void
    3924                 :        144 : bs_delete_corrupted_blob(void *cb_arg, int bserrno)
    3925                 :            : {
    3926                 :        144 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    3927                 :         24 :         uint64_t i;
    3928                 :            : 
    3929         [ -  + ]:        144 :         if (bserrno != 0) {
    3930                 :          0 :                 SPDK_ERRLOG("Failed to close clone of a corrupted blob\n");
    3931   [ #  #  #  #  :          0 :                 spdk_bs_iter_next(ctx->bs, ctx->blob, bs_load_iter, ctx);
             #  #  #  # ]
    3932                 :          0 :                 return;
    3933                 :            :         }
    3934                 :            : 
    3935                 :            :         /* Snapshot and clone have the same copy of cluster map and extent pages
    3936                 :            :          * at this point. Let's clear both for snapshot now,
    3937                 :            :          * so that it won't be cleared for clone later when we remove snapshot.
    3938                 :            :          * Also set thin provision to pass data corruption check */
    3939   [ +  +  +  -  :       1584 :         for (i = 0; i < ctx->blob->active.num_clusters; i++) {
          +  -  +  -  +  
                -  +  + ]
    3940   [ +  -  +  -  :       1440 :                 ctx->blob->active.clusters[i] = 0;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    3941                 :        240 :         }
    3942   [ +  +  +  -  :        216 :         for (i = 0; i < ctx->blob->active.num_extent_pages; i++) {
          +  -  +  -  +  
                -  +  + ]
    3943   [ +  -  +  -  :         72 :                 ctx->blob->active.extent_pages[i] = 0;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    3944                 :         12 :         }
    3945                 :            : 
    3946   [ +  -  +  -  :        144 :         ctx->blob->md_ro = false;
             +  -  +  - ]
    3947                 :            : 
    3948   [ +  -  +  - ]:        144 :         blob_set_thin_provision(ctx->blob);
    3949                 :            : 
    3950   [ +  -  +  -  :        144 :         ctx->blobid = ctx->blob->id;
          +  -  +  -  +  
                -  +  - ]
    3951                 :            : 
    3952   [ +  -  +  - ]:        144 :         spdk_blob_close(ctx->blob, bs_delete_corrupted_close_cb, ctx);
    3953         [ -  + ]:         24 : }
    3954                 :            : 
    3955                 :            : static void
    3956                 :         72 : bs_update_corrupted_blob(void *cb_arg, int bserrno)
    3957                 :            : {
    3958                 :         72 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    3959                 :            : 
    3960         [ -  + ]:         72 :         if (bserrno != 0) {
    3961                 :          0 :                 SPDK_ERRLOG("Failed to close clone of a corrupted blob\n");
    3962   [ #  #  #  #  :          0 :                 spdk_bs_iter_next(ctx->bs, ctx->blob, bs_load_iter, ctx);
             #  #  #  # ]
    3963                 :          0 :                 return;
    3964                 :            :         }
    3965                 :            : 
    3966   [ +  -  +  -  :         72 :         ctx->blob->md_ro = false;
             +  -  +  - ]
    3967   [ +  -  +  - ]:         72 :         blob_remove_xattr(ctx->blob, SNAPSHOT_PENDING_REMOVAL, true);
    3968   [ +  -  +  - ]:         72 :         blob_remove_xattr(ctx->blob, SNAPSHOT_IN_PROGRESS, true);
    3969   [ +  -  +  - ]:         72 :         spdk_blob_set_read_only(ctx->blob);
    3970                 :            : 
    3971   [ +  +  +  -  :         72 :         if (ctx->iter_cb_fn) {
                   +  - ]
    3972   [ #  #  #  #  :          0 :                 ctx->iter_cb_fn(ctx->iter_cb_arg, ctx->blob, 0);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    3973                 :          0 :         }
    3974   [ +  -  +  - ]:         72 :         bs_blob_list_add(ctx->blob);
    3975                 :            : 
    3976   [ +  -  +  -  :         72 :         spdk_bs_iter_next(ctx->bs, ctx->blob, bs_load_iter, ctx);
             +  -  +  - ]
    3977         [ -  + ]:         12 : }
    3978                 :            : 
    3979                 :            : static void
    3980                 :        216 : bs_examine_clone(void *cb_arg, struct spdk_blob *blob, int bserrno)
    3981                 :            : {
    3982                 :        216 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    3983                 :            : 
    3984         [ -  + ]:        216 :         if (bserrno != 0) {
    3985                 :          0 :                 SPDK_ERRLOG("Failed to open clone of a corrupted blob\n");
    3986   [ #  #  #  #  :          0 :                 spdk_bs_iter_next(ctx->bs, ctx->blob, bs_load_iter, ctx);
             #  #  #  # ]
    3987                 :          0 :                 return;
    3988                 :            :         }
    3989                 :            : 
    3990   [ +  +  +  -  :        216 :         if (blob->parent_id == ctx->blob->id) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    3991                 :            :                 /* Power failure occurred before updating clone (snapshot delete case)
    3992                 :            :                  * or after updating clone (creating snapshot case) - keep snapshot */
    3993                 :         72 :                 spdk_blob_close(blob, bs_update_corrupted_blob, ctx);
    3994                 :         12 :         } else {
    3995                 :            :                 /* Power failure occurred after updating clone (snapshot delete case)
    3996                 :            :                  * or before updating clone (creating snapshot case) - remove snapshot */
    3997                 :        144 :                 spdk_blob_close(blob, bs_delete_corrupted_blob, ctx);
    3998                 :            :         }
    3999         [ -  + ]:         36 : }
    4000                 :            : 
    4001                 :            : static void
    4002                 :      11274 : bs_load_iter(void *arg, struct spdk_blob *blob, int bserrno)
    4003                 :            : {
    4004                 :      11274 :         struct spdk_bs_load_ctx *ctx = arg;
    4005                 :      10514 :         const void *value;
    4006                 :      10514 :         size_t len;
    4007                 :      11274 :         int rc = 0;
    4008                 :            : 
    4009         [ +  + ]:      11274 :         if (bserrno == 0) {
    4010                 :            :                 /* Examine blob if it is corrupted after power failure. Fix
    4011                 :            :                  * the ones that can be fixed and remove any other corrupted
    4012                 :            :                  * ones. If it is not corrupted just process it */
    4013                 :       9511 :                 rc = blob_get_xattr_value(blob, SNAPSHOT_PENDING_REMOVAL, &value, &len, true);
    4014         [ +  + ]:       9511 :                 if (rc != 0) {
    4015                 :       9391 :                         rc = blob_get_xattr_value(blob, SNAPSHOT_IN_PROGRESS, &value, &len, true);
    4016         [ +  + ]:       9391 :                         if (rc != 0) {
    4017                 :            :                                 /* Not corrupted - process it and continue with iterating through blobs */
    4018   [ +  +  +  -  :       9295 :                                 if (ctx->iter_cb_fn) {
                   +  + ]
    4019   [ +  -  +  -  :       5490 :                                         ctx->iter_cb_fn(ctx->iter_cb_arg, blob, 0);
          -  +  +  -  +  
                -  +  - ]
    4020                 :         34 :                                 }
    4021                 :       9295 :                                 bs_blob_list_add(blob);
    4022   [ +  -  +  - ]:       9295 :                                 spdk_bs_iter_next(ctx->bs, blob, bs_load_iter, ctx);
    4023                 :       9331 :                                 return;
    4024                 :            :                         }
    4025                 :            : 
    4026                 :         16 :                 }
    4027                 :            : 
    4028   [ +  +  #  # ]:        216 :                 assert(len == sizeof(spdk_blob_id));
    4029                 :            : 
    4030   [ +  -  +  - ]:        216 :                 ctx->blob = blob;
    4031                 :            : 
    4032                 :            :                 /* Open clone to check if we are able to fix this blob or should we remove it */
    4033   [ +  -  +  -  :        216 :                 spdk_bs_open_blob(ctx->bs, *(spdk_blob_id *)value, bs_examine_clone, ctx);
                   +  - ]
    4034                 :        216 :                 return;
    4035         [ +  - ]:       1763 :         } else if (bserrno == -ENOENT) {
    4036                 :       1763 :                 bserrno = 0;
    4037                 :        280 :         } else {
    4038                 :            :                 /*
    4039                 :            :                  * This case needs to be looked at further.  Same problem
    4040                 :            :                  *  exists with applications that rely on explicit blob
    4041                 :            :                  *  iteration.  We should just skip the blob that failed
    4042                 :            :                  *  to load and continue on to the next one.
    4043                 :            :                  */
    4044                 :          0 :                 SPDK_ERRLOG("Error in iterating blobs\n");
    4045                 :            :         }
    4046                 :            : 
    4047   [ +  -  +  - ]:       1763 :         ctx->iter_cb_fn = NULL;
    4048                 :            : 
    4049   [ +  -  +  - ]:       1763 :         spdk_free(ctx->super);
    4050   [ +  -  +  - ]:       1763 :         spdk_free(ctx->mask);
    4051   [ +  -  +  - ]:       1763 :         bs_sequence_finish(ctx->seq, bserrno);
    4052                 :       1763 :         free(ctx);
    4053         [ -  + ]:        720 : }
    4054                 :            : 
    4055                 :            : static void bs_dump_read_md_page(spdk_bs_sequence_t *seq, void *cb_arg);
    4056                 :            : 
    4057                 :            : static void
    4058                 :       1763 : bs_load_complete(struct spdk_bs_load_ctx *ctx)
    4059                 :            : {
    4060   [ +  -  +  -  :       1763 :         ctx->bs->used_clusters = spdk_bit_pool_create_from_array(ctx->used_clusters);
          +  -  +  -  +  
                -  +  - ]
    4061   [ +  +  +  +  :       1763 :         if (ctx->dumping) {
             +  -  -  + ]
    4062   [ #  #  #  # ]:          0 :                 bs_dump_read_md_page(ctx->seq, ctx);
    4063                 :          0 :                 return;
    4064                 :            :         }
    4065   [ +  -  +  - ]:       1763 :         spdk_bs_iter_first(ctx->bs, bs_load_iter, ctx);
    4066                 :        280 : }
    4067                 :            : 
    4068                 :            : static void
    4069                 :       1122 : bs_load_used_blobids_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4070                 :            : {
    4071                 :       1122 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4072                 :        174 :         int rc;
    4073                 :            : 
    4074                 :            :         /* The type must be correct */
    4075   [ +  +  +  -  :       1122 :         assert(ctx->mask->type == SPDK_MD_MASK_TYPE_USED_BLOBIDS);
          +  -  +  -  +  
                -  #  # ]
    4076                 :            : 
    4077                 :            :         /* The length of the mask (in bits) must not be greater than
    4078                 :            :          * the length of the buffer (converted to bits) */
    4079   [ +  +  +  -  :       1122 :         assert(ctx->mask->length <= (ctx->super->used_blobid_mask_len * SPDK_BS_PAGE_SIZE * 8));
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    4080                 :            : 
    4081                 :            :         /* The length of the mask must be exactly equal to the size
    4082                 :            :          * (in pages) of the metadata region */
    4083   [ +  +  +  -  :       1122 :         assert(ctx->mask->length == ctx->super->md_len);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    4084                 :            : 
    4085   [ +  -  +  -  :       1122 :         rc = spdk_bit_array_resize(&ctx->bs->used_blobids, ctx->mask->length);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4086         [ +  + ]:       1122 :         if (rc < 0) {
    4087   [ #  #  #  # ]:          0 :                 spdk_free(ctx->mask);
    4088                 :          0 :                 bs_load_ctx_fail(ctx, rc);
    4089                 :          0 :                 return;
    4090                 :            :         }
    4091                 :            : 
    4092   [ +  -  +  -  :       1122 :         spdk_bit_array_load_mask(ctx->bs->used_blobids, ctx->mask->mask);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4093                 :       1122 :         bs_load_complete(ctx);
    4094         [ -  + ]:        174 : }
    4095                 :            : 
    4096                 :            : static void
    4097                 :       1122 : bs_load_used_clusters_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4098                 :            : {
    4099                 :       1122 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4100                 :        174 :         uint64_t                lba, lba_count, mask_size;
    4101                 :        174 :         int                     rc;
    4102                 :            : 
    4103         [ -  + ]:       1122 :         if (bserrno != 0) {
    4104                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    4105                 :          0 :                 return;
    4106                 :            :         }
    4107                 :            : 
    4108                 :            :         /* The type must be correct */
    4109   [ +  +  +  -  :       1122 :         assert(ctx->mask->type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
          +  -  +  -  +  
                -  #  # ]
    4110                 :            :         /* The length of the mask (in bits) must not be greater than the length of the buffer (converted to bits) */
    4111   [ +  +  +  -  :       1122 :         assert(ctx->mask->length <= (ctx->super->used_cluster_mask_len * sizeof(
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    4112                 :            :                                              struct spdk_blob_md_page) * 8));
    4113                 :            :         /*
    4114                 :            :          * The length of the mask must be equal to or larger than the total number of clusters. It may be
    4115                 :            :          * larger than the total number of clusters due to a failure spdk_bs_grow.
    4116                 :            :          */
    4117   [ +  +  +  -  :       1122 :         assert(ctx->mask->length >= ctx->bs->total_clusters);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    4118   [ +  +  +  -  :       1122 :         if (ctx->mask->length > ctx->bs->total_clusters) {
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  + ]
    4119                 :         24 :                 SPDK_WARNLOG("Shrink the used_custers mask length to total_clusters");
    4120   [ +  -  +  -  :         24 :                 ctx->mask->length = ctx->bs->total_clusters;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4121                 :          4 :         }
    4122                 :            : 
    4123   [ +  -  +  -  :       1122 :         rc = spdk_bit_array_resize(&ctx->used_clusters, ctx->mask->length);
          +  -  +  -  +  
                      - ]
    4124         [ +  + ]:       1122 :         if (rc < 0) {
    4125   [ #  #  #  # ]:          0 :                 spdk_free(ctx->mask);
    4126                 :          0 :                 bs_load_ctx_fail(ctx, rc);
    4127                 :          0 :                 return;
    4128                 :            :         }
    4129                 :            : 
    4130   [ +  -  +  -  :       1122 :         spdk_bit_array_load_mask(ctx->used_clusters, ctx->mask->mask);
          +  -  +  -  +  
                      - ]
    4131   [ +  -  +  -  :       1122 :         ctx->bs->num_free_clusters = spdk_bit_array_count_clear(ctx->used_clusters);
          +  -  +  -  +  
                -  +  - ]
    4132   [ +  +  +  -  :       1122 :         assert(ctx->bs->num_free_clusters <= ctx->bs->total_clusters);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    4133                 :            : 
    4134   [ +  -  +  - ]:       1122 :         spdk_free(ctx->mask);
    4135                 :            : 
    4136                 :            :         /* Read the used blobids mask */
    4137   [ +  -  +  -  :       1122 :         mask_size = ctx->super->used_blobid_mask_len * SPDK_BS_PAGE_SIZE;
             +  -  +  - ]
    4138   [ +  -  +  - ]:       1122 :         ctx->mask = spdk_zmalloc(mask_size, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY,
    4139                 :            :                                  SPDK_MALLOC_DMA);
    4140   [ +  +  +  -  :       1122 :         if (!ctx->mask) {
                   +  - ]
    4141                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4142                 :          0 :                 return;
    4143                 :            :         }
    4144   [ +  -  +  -  :       1122 :         lba = bs_page_to_lba(ctx->bs, ctx->super->used_blobid_mask_start);
          +  -  +  -  +  
                -  +  - ]
    4145   [ +  -  +  -  :       1122 :         lba_count = bs_page_to_lba(ctx->bs, ctx->super->used_blobid_mask_len);
          +  -  +  -  +  
                -  +  - ]
    4146   [ +  -  +  - ]:       1122 :         bs_sequence_read_dev(seq, ctx->mask, lba, lba_count,
    4147                 :        174 :                              bs_load_used_blobids_cpl, ctx);
    4148         [ -  + ]:        174 : }
    4149                 :            : 
    4150                 :            : static void
    4151                 :       1122 : bs_load_used_pages_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4152                 :            : {
    4153                 :       1122 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4154                 :        174 :         uint64_t                lba, lba_count, mask_size;
    4155                 :        174 :         int                     rc;
    4156                 :            : 
    4157         [ -  + ]:       1122 :         if (bserrno != 0) {
    4158                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    4159                 :          0 :                 return;
    4160                 :            :         }
    4161                 :            : 
    4162                 :            :         /* The type must be correct */
    4163   [ +  +  +  -  :       1122 :         assert(ctx->mask->type == SPDK_MD_MASK_TYPE_USED_PAGES);
          +  -  +  -  +  
                -  #  # ]
    4164                 :            :         /* The length of the mask (in bits) must not be greater than the length of the buffer (converted to bits) */
    4165   [ +  +  +  -  :       1122 :         assert(ctx->mask->length <= (ctx->super->used_page_mask_len * SPDK_BS_PAGE_SIZE *
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    4166                 :            :                                      8));
    4167                 :            :         /* The length of the mask must be exactly equal to the size (in pages) of the metadata region */
    4168   [ +  +  +  -  :       1122 :         if (ctx->mask->length != ctx->super->md_len) {
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
    4169   [ #  #  #  #  :          0 :                 SPDK_ERRLOG("mismatched md_len in used_pages mask: "
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    4170                 :            :                             "mask->length=%" PRIu32 " super->md_len=%" PRIu32 "\n",
    4171                 :            :                             ctx->mask->length, ctx->super->md_len);
    4172         [ #  # ]:          0 :                 assert(false);
    4173                 :            :         }
    4174                 :            : 
    4175   [ +  -  +  -  :       1122 :         rc = spdk_bit_array_resize(&ctx->bs->used_md_pages, ctx->mask->length);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4176         [ +  + ]:       1122 :         if (rc < 0) {
    4177   [ #  #  #  # ]:          0 :                 spdk_free(ctx->mask);
    4178                 :          0 :                 bs_load_ctx_fail(ctx, rc);
    4179                 :          0 :                 return;
    4180                 :            :         }
    4181                 :            : 
    4182   [ +  -  +  -  :       1122 :         spdk_bit_array_load_mask(ctx->bs->used_md_pages, ctx->mask->mask);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4183   [ +  -  +  - ]:       1122 :         spdk_free(ctx->mask);
    4184                 :            : 
    4185                 :            :         /* Read the used clusters mask */
    4186   [ +  -  +  -  :       1122 :         mask_size = ctx->super->used_cluster_mask_len * SPDK_BS_PAGE_SIZE;
             +  -  +  - ]
    4187   [ +  -  +  - ]:       1122 :         ctx->mask = spdk_zmalloc(mask_size, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY,
    4188                 :            :                                  SPDK_MALLOC_DMA);
    4189   [ +  +  +  -  :       1122 :         if (!ctx->mask) {
                   +  - ]
    4190                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4191                 :          0 :                 return;
    4192                 :            :         }
    4193   [ +  -  +  -  :       1122 :         lba = bs_page_to_lba(ctx->bs, ctx->super->used_cluster_mask_start);
          +  -  +  -  +  
                -  +  - ]
    4194   [ +  -  +  -  :       1122 :         lba_count = bs_page_to_lba(ctx->bs, ctx->super->used_cluster_mask_len);
          +  -  +  -  +  
                -  +  - ]
    4195   [ +  -  +  - ]:       1122 :         bs_sequence_read_dev(seq, ctx->mask, lba, lba_count,
    4196                 :        174 :                              bs_load_used_clusters_cpl, ctx);
    4197         [ -  + ]:        174 : }
    4198                 :            : 
    4199                 :            : static void
    4200                 :       1122 : bs_load_read_used_pages(struct spdk_bs_load_ctx *ctx)
    4201                 :            : {
    4202                 :        174 :         uint64_t lba, lba_count, mask_size;
    4203                 :            : 
    4204                 :            :         /* Read the used pages mask */
    4205   [ +  -  +  -  :       1122 :         mask_size = ctx->super->used_page_mask_len * SPDK_BS_PAGE_SIZE;
             +  -  +  - ]
    4206   [ +  -  +  - ]:       1122 :         ctx->mask = spdk_zmalloc(mask_size, 0x1000, NULL,
    4207                 :            :                                  SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    4208   [ +  +  +  -  :       1122 :         if (!ctx->mask) {
                   +  - ]
    4209                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4210                 :          0 :                 return;
    4211                 :            :         }
    4212                 :            : 
    4213   [ +  -  +  -  :       1122 :         lba = bs_page_to_lba(ctx->bs, ctx->super->used_page_mask_start);
          +  -  +  -  +  
                -  +  - ]
    4214   [ +  -  +  -  :       1122 :         lba_count = bs_page_to_lba(ctx->bs, ctx->super->used_page_mask_len);
          +  -  +  -  +  
                -  +  - ]
    4215   [ +  -  +  -  :       1122 :         bs_sequence_read_dev(ctx->seq, ctx->mask, lba, lba_count,
             +  -  +  - ]
    4216                 :        174 :                              bs_load_used_pages_cpl, ctx);
    4217         [ -  + ]:        174 : }
    4218                 :            : 
    4219                 :            : static int
    4220                 :       1492 : bs_load_replay_md_parse_page(struct spdk_bs_load_ctx *ctx, struct spdk_blob_md_page *page)
    4221                 :            : {
    4222   [ +  -  +  - ]:       1492 :         struct spdk_blob_store *bs = ctx->bs;
    4223                 :        246 :         struct spdk_blob_md_descriptor *desc;
    4224                 :       1492 :         size_t  cur_desc = 0;
    4225                 :            : 
    4226         [ +  - ]:       1492 :         desc = (struct spdk_blob_md_descriptor *)page->descriptors;
    4227         [ +  + ]:       4370 :         while (cur_desc < sizeof(page->descriptors)) {
    4228   [ +  +  +  -  :       4370 :                 if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_PADDING) {
                   +  + ]
    4229   [ +  -  +  -  :       1372 :                         if (desc->length == 0) {
                   +  - ]
    4230                 :            :                                 /* If padding and length are 0, this terminates the page */
    4231                 :       1372 :                                 break;
    4232                 :            :                         }
    4233   [ +  +  +  -  :       2998 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_RLE) {
                   +  + ]
    4234                 :         68 :                         struct spdk_blob_md_descriptor_extent_rle       *desc_extent_rle;
    4235                 :         68 :                         unsigned int                            i, j;
    4236                 :        408 :                         unsigned int                            cluster_count = 0;
    4237                 :         68 :                         uint32_t                                cluster_idx;
    4238                 :            : 
    4239                 :        408 :                         desc_extent_rle = (struct spdk_blob_md_descriptor_extent_rle *)desc;
    4240                 :            : 
    4241   [ +  +  +  -  :        816 :                         for (i = 0; i < desc_extent_rle->length / sizeof(desc_extent_rle->extents[0]); i++) {
             +  -  +  + ]
    4242   [ +  +  +  -  :       4968 :                                 for (j = 0; j < desc_extent_rle->extents[i].length; j++) {
          +  -  +  -  +  
                      + ]
    4243   [ +  -  +  -  :       4560 :                                         cluster_idx = desc_extent_rle->extents[i].cluster_idx;
             +  -  +  - ]
    4244                 :            :                                         /*
    4245                 :            :                                          * cluster_idx = 0 means an unallocated cluster - don't mark that
    4246                 :            :                                          * in the used cluster map.
    4247                 :            :                                          */
    4248         [ +  + ]:       4560 :                                         if (cluster_idx != 0) {
    4249                 :       3240 :                                                 SPDK_NOTICELOG("Recover: cluster %" PRIu32 "\n", cluster_idx + j);
    4250   [ +  -  +  - ]:       3240 :                                                 spdk_bit_array_set(ctx->used_clusters, cluster_idx + j);
    4251   [ +  +  +  -  :       3240 :                                                 if (bs->num_free_clusters == 0) {
                   +  - ]
    4252                 :          0 :                                                         return -ENOSPC;
    4253                 :            :                                                 }
    4254         [ +  - ]:       3240 :                                                 bs->num_free_clusters--;
    4255                 :        540 :                                         }
    4256                 :       4560 :                                         cluster_count++;
    4257                 :        760 :                                 }
    4258                 :         68 :                         }
    4259         [ +  + ]:        408 :                         if (cluster_count == 0) {
    4260                 :          0 :                                 return -EINVAL;
    4261                 :            :                         }
    4262   [ +  +  +  -  :       2658 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_PAGE) {
             +  -  +  + ]
    4263                 :         52 :                         struct spdk_blob_md_descriptor_extent_page      *desc_extent;
    4264                 :         52 :                         uint32_t                                        i;
    4265                 :        318 :                         uint32_t                                        cluster_count = 0;
    4266                 :         52 :                         uint32_t                                        cluster_idx;
    4267                 :         52 :                         size_t                                          cluster_idx_length;
    4268                 :            : 
    4269                 :        318 :                         desc_extent = (struct spdk_blob_md_descriptor_extent_page *)desc;
    4270   [ +  -  +  - ]:        318 :                         cluster_idx_length = desc_extent->length - sizeof(desc_extent->start_cluster_idx);
    4271                 :            : 
    4272   [ +  -  +  -  :        370 :                         if (desc_extent->length <= sizeof(desc_extent->start_cluster_idx) ||
             +  -  -  + ]
    4273         [ +  + ]:        318 :                             (cluster_idx_length % sizeof(desc_extent->cluster_idx[0]) != 0)) {
    4274                 :          0 :                                 return -EINVAL;
    4275                 :            :                         }
    4276                 :            : 
    4277   [ +  +  +  + ]:       4838 :                         for (i = 0; i < cluster_idx_length / sizeof(desc_extent->cluster_idx[0]); i++) {
    4278   [ +  -  +  -  :       4520 :                                 cluster_idx = desc_extent->cluster_idx[i];
                   +  - ]
    4279                 :            :                                 /*
    4280                 :            :                                  * cluster_idx = 0 means an unallocated cluster - don't mark that
    4281                 :            :                                  * in the used cluster map.
    4282                 :            :                                  */
    4283         [ +  + ]:       4520 :                                 if (cluster_idx != 0) {
    4284   [ +  +  +  -  :       3754 :                                         if (cluster_idx < desc_extent->start_cluster_idx &&
             -  +  #  # ]
    4285   [ -  +  #  # ]:          1 :                                             cluster_idx >= desc_extent->start_cluster_idx + cluster_count) {
    4286                 :          0 :                                                 return -EINVAL;
    4287                 :            :                                         }
    4288   [ +  -  +  - ]:       3754 :                                         spdk_bit_array_set(ctx->used_clusters, cluster_idx);
    4289   [ +  +  +  -  :       3754 :                                         if (bs->num_free_clusters == 0) {
                   +  - ]
    4290                 :          0 :                                                 return -ENOSPC;
    4291                 :            :                                         }
    4292         [ +  - ]:       3754 :                                         bs->num_free_clusters--;
    4293                 :        600 :                                 }
    4294                 :       4520 :                                 cluster_count++;
    4295                 :        600 :                         }
    4296                 :            : 
    4297         [ +  + ]:        318 :                         if (cluster_count == 0) {
    4298                 :          0 :                                 return -EINVAL;
    4299                 :            :                         }
    4300   [ +  +  +  -  :       2324 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_XATTR) {
             +  -  +  + ]
    4301                 :            :                         /* Skip this item */
    4302   [ +  +  +  -  :       1872 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_XATTR_INTERNAL) {
                   +  + ]
    4303                 :            :                         /* Skip this item */
    4304   [ +  +  +  -  :       1496 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_FLAGS) {
                   +  + ]
    4305                 :            :                         /* Skip this item */
    4306   [ +  -  +  -  :        656 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_TABLE) {
                   +  - ]
    4307                 :         82 :                         struct spdk_blob_md_descriptor_extent_table *desc_extent_table;
    4308   [ +  -  +  - ]:        502 :                         uint32_t num_extent_pages = ctx->num_extent_pages;
    4309                 :         82 :                         uint32_t i;
    4310                 :         82 :                         size_t extent_pages_length;
    4311                 :         82 :                         void *tmp;
    4312                 :            : 
    4313                 :        502 :                         desc_extent_table = (struct spdk_blob_md_descriptor_extent_table *)desc;
    4314   [ +  -  +  - ]:        502 :                         extent_pages_length = desc_extent_table->length - sizeof(desc_extent_table->num_clusters);
    4315                 :            : 
    4316   [ +  -  +  -  :        584 :                         if (desc_extent_table->length == 0 ||
             +  -  -  + ]
    4317         [ +  + ]:        502 :                             (extent_pages_length % sizeof(desc_extent_table->extent_page[0]) != 0)) {
    4318                 :          0 :                                 return -EINVAL;
    4319                 :            :                         }
    4320                 :            : 
    4321   [ +  +  +  + ]:        977 :                         for (i = 0; i < extent_pages_length / sizeof(desc_extent_table->extent_page[0]); i++) {
    4322   [ +  +  +  -  :        475 :                                 if (desc_extent_table->extent_page[i].page_idx != 0) {
          +  -  +  -  +  
                      + ]
    4323   [ +  +  +  -  :        318 :                                         if (desc_extent_table->extent_page[i].num_pages != 1) {
          +  -  +  -  +  
                      - ]
    4324                 :          0 :                                                 return -EINVAL;
    4325                 :            :                                         }
    4326                 :        318 :                                         num_extent_pages += 1;
    4327                 :         52 :                                 }
    4328                 :         78 :                         }
    4329                 :            : 
    4330         [ +  + ]:        502 :                         if (num_extent_pages > 0) {
    4331   [ +  -  +  - ]:        317 :                                 tmp = realloc(ctx->extent_page_num, num_extent_pages * sizeof(uint32_t));
    4332         [ +  + ]:        317 :                                 if (tmp == NULL) {
    4333                 :          0 :                                         return -ENOMEM;
    4334                 :            :                                 }
    4335   [ +  -  +  - ]:        317 :                                 ctx->extent_page_num = tmp;
    4336                 :            : 
    4337                 :            :                                 /* Extent table entries contain md page numbers for extent pages.
    4338                 :            :                                  * Zeroes represent unallocated extent pages, those are run-length-encoded.
    4339                 :            :                                  */
    4340   [ +  +  +  + ]:        636 :                                 for (i = 0; i < extent_pages_length / sizeof(desc_extent_table->extent_page[0]); i++) {
    4341   [ +  +  +  -  :        319 :                                         if (desc_extent_table->extent_page[i].page_idx != 0) {
          +  -  +  -  -  
                      + ]
    4342   [ +  -  +  -  :        318 :                                                 ctx->extent_page_num[ctx->num_extent_pages] = desc_extent_table->extent_page[i].page_idx;
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    4343   [ +  -  +  - ]:        318 :                                                 ctx->num_extent_pages += 1;
    4344                 :         52 :                                         }
    4345                 :         52 :                                 }
    4346                 :         52 :                         }
    4347         [ -  + ]:         82 :                 } else {
    4348                 :            :                         /* Error */
    4349                 :          0 :                         return -EINVAL;
    4350                 :            :                 }
    4351                 :            :                 /* Advance to the next descriptor */
    4352   [ +  -  +  - ]:       2998 :                 cur_desc += sizeof(*desc) + desc->length;
    4353         [ +  + ]:       2998 :                 if (cur_desc + sizeof(*desc) > sizeof(page->descriptors)) {
    4354                 :        120 :                         break;
    4355                 :            :                 }
    4356         [ +  - ]:       2878 :                 desc = (struct spdk_blob_md_descriptor *)((uintptr_t)page->descriptors + cur_desc);
    4357                 :            :         }
    4358                 :       1492 :         return 0;
    4359                 :        246 : }
    4360                 :            : 
    4361                 :            : static bool
    4362                 :      34201 : bs_load_cur_extent_page_valid(struct spdk_blob_md_page *page)
    4363                 :            : {
    4364                 :       1284 :         uint32_t crc;
    4365         [ +  - ]:      34201 :         struct spdk_blob_md_descriptor *desc = (struct spdk_blob_md_descriptor *)page->descriptors;
    4366                 :       1284 :         size_t desc_len;
    4367                 :            : 
    4368                 :      34201 :         crc = blob_md_page_calc_crc(page);
    4369   [ +  +  +  -  :      34201 :         if (crc != page->crc) {
                   -  + ]
    4370                 :          0 :                 return false;
    4371                 :            :         }
    4372                 :            : 
    4373                 :            :         /* Extent page should always be of sequence num 0. */
    4374   [ +  +  +  -  :      34201 :         if (page->sequence_num != 0) {
                   +  + ]
    4375                 :        264 :                 return false;
    4376                 :            :         }
    4377                 :            : 
    4378                 :            :         /* Descriptor type must be EXTENT_PAGE. */
    4379   [ +  +  +  -  :      33937 :         if (desc->type != SPDK_MD_DESCRIPTOR_TYPE_EXTENT_PAGE) {
                   +  + ]
    4380                 :        934 :                 return false;
    4381                 :            :         }
    4382                 :            : 
    4383                 :            :         /* Descriptor length cannot exceed the page. */
    4384   [ +  -  +  - ]:      33003 :         desc_len = sizeof(*desc) + desc->length;
    4385         [ -  + ]:      33003 :         if (desc_len > sizeof(page->descriptors)) {
    4386                 :          0 :                 return false;
    4387                 :            :         }
    4388                 :            : 
    4389                 :            :         /* It has to be the only descriptor in the page. */
    4390         [ +  + ]:      33003 :         if (desc_len + sizeof(*desc) <= sizeof(page->descriptors)) {
    4391         [ +  - ]:      33003 :                 desc = (struct spdk_blob_md_descriptor *)((uintptr_t)page->descriptors + desc_len);
    4392   [ +  +  +  -  :      33003 :                 if (desc->length != 0) {
                   -  + ]
    4393                 :          0 :                         return false;
    4394                 :            :                 }
    4395                 :       1086 :         }
    4396                 :            : 
    4397                 :      33003 :         return true;
    4398                 :       1284 : }
    4399                 :            : 
    4400                 :            : static bool
    4401                 :      42398 : bs_load_cur_md_page_valid(struct spdk_bs_load_ctx *ctx)
    4402                 :            : {
    4403                 :       6754 :         uint32_t crc;
    4404   [ +  -  +  - ]:      42398 :         struct spdk_blob_md_page *page = ctx->page;
    4405                 :            : 
    4406                 :      42398 :         crc = blob_md_page_calc_crc(page);
    4407   [ +  +  +  -  :      42398 :         if (crc != page->crc) {
                   +  + ]
    4408                 :      41092 :                 return false;
    4409                 :            :         }
    4410                 :            : 
    4411                 :            :         /* First page of a sequence should match the blobid. */
    4412   [ +  +  +  -  :       1478 :         if (page->sequence_num == 0 &&
             +  +  +  + ]
    4413   [ +  +  +  -  :       1042 :             bs_page_to_blobid(ctx->cur_page) != page->id) {
             +  -  +  - ]
    4414                 :        108 :                 return false;
    4415                 :            :         }
    4416   [ +  +  #  # ]:       1198 :         assert(bs_load_cur_extent_page_valid(page) == false);
    4417                 :            : 
    4418                 :       1198 :         return true;
    4419                 :       6754 : }
    4420                 :            : 
    4421                 :            : static void bs_load_replay_cur_md_page(struct spdk_bs_load_ctx *ctx);
    4422                 :            : 
    4423                 :            : static void
    4424                 :        641 : bs_load_write_used_clusters_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4425                 :            : {
    4426                 :        641 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4427                 :            : 
    4428         [ -  + ]:        641 :         if (bserrno != 0) {
    4429                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    4430                 :          0 :                 return;
    4431                 :            :         }
    4432                 :            : 
    4433                 :        641 :         bs_load_complete(ctx);
    4434         [ -  + ]:        106 : }
    4435                 :            : 
    4436                 :            : static void
    4437                 :        641 : bs_load_write_used_blobids_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4438                 :            : {
    4439                 :        641 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4440                 :            : 
    4441   [ +  -  +  - ]:        641 :         spdk_free(ctx->mask);
    4442   [ +  -  +  - ]:        641 :         ctx->mask = NULL;
    4443                 :            : 
    4444         [ -  + ]:        641 :         if (bserrno != 0) {
    4445                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    4446                 :          0 :                 return;
    4447                 :            :         }
    4448                 :            : 
    4449                 :        641 :         bs_write_used_clusters(seq, ctx, bs_load_write_used_clusters_cpl);
    4450         [ -  + ]:        106 : }
    4451                 :            : 
    4452                 :            : static void
    4453                 :        641 : bs_load_write_used_pages_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4454                 :            : {
    4455                 :        641 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4456                 :            : 
    4457   [ +  -  +  - ]:        641 :         spdk_free(ctx->mask);
    4458   [ +  -  +  - ]:        641 :         ctx->mask = NULL;
    4459                 :            : 
    4460         [ -  + ]:        641 :         if (bserrno != 0) {
    4461                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    4462                 :          0 :                 return;
    4463                 :            :         }
    4464                 :            : 
    4465                 :        641 :         bs_write_used_blobids(seq, ctx, bs_load_write_used_blobids_cpl);
    4466         [ -  + ]:        106 : }
    4467                 :            : 
    4468                 :            : static void
    4469                 :        641 : bs_load_write_used_md(struct spdk_bs_load_ctx *ctx)
    4470                 :            : {
    4471   [ +  -  +  - ]:        641 :         bs_write_used_md(ctx->seq, ctx, bs_load_write_used_pages_cpl);
    4472                 :        641 : }
    4473                 :            : 
    4474                 :            : static void
    4475                 :      42158 : bs_load_replay_md_chain_cpl(struct spdk_bs_load_ctx *ctx)
    4476                 :            : {
    4477                 :       6714 :         uint64_t num_md_clusters;
    4478                 :       6714 :         uint64_t i;
    4479                 :            : 
    4480   [ +  -  +  - ]:      42158 :         ctx->in_page_chain = false;
    4481                 :            : 
    4482                 :       6714 :         do {
    4483         [ +  - ]:      42584 :                 ctx->page_index++;
    4484   [ +  +  +  -  :      42584 :         } while (spdk_bit_array_get(ctx->bs->used_md_pages, ctx->page_index) == true);
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    4485                 :            : 
    4486   [ +  +  +  -  :      42158 :         if (ctx->page_index < ctx->super->md_len) {
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    4487   [ +  -  +  -  :      41517 :                 ctx->cur_page = ctx->page_index;
             +  -  +  - ]
    4488                 :      41517 :                 bs_load_replay_cur_md_page(ctx);
    4489                 :       6608 :         } else {
    4490                 :            :                 /* Claim all of the clusters used by the metadata */
    4491                 :        641 :                 num_md_clusters = spdk_divide_round_up(
    4492   [ +  -  +  -  :       1070 :                                           ctx->super->md_start + ctx->super->md_len, ctx->bs->pages_per_cluster);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4493         [ +  + ]:       2891 :                 for (i = 0; i < num_md_clusters; i++) {
    4494   [ +  -  +  - ]:       2250 :                         spdk_bit_array_set(ctx->used_clusters, i);
    4495                 :        374 :                 }
    4496   [ +  -  +  -  :        641 :                 ctx->bs->num_free_clusters -= num_md_clusters;
             +  -  +  - ]
    4497   [ +  -  +  - ]:        641 :                 spdk_free(ctx->page);
    4498                 :        641 :                 bs_load_write_used_md(ctx);
    4499                 :            :         }
    4500                 :      42158 : }
    4501                 :            : 
    4502                 :            : static void
    4503                 :        317 : bs_load_replay_extent_page_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4504                 :            : {
    4505                 :        317 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4506                 :         52 :         uint32_t page_num;
    4507                 :         52 :         uint64_t i;
    4508                 :            : 
    4509         [ -  + ]:        317 :         if (bserrno != 0) {
    4510   [ #  #  #  # ]:          0 :                 spdk_free(ctx->extent_pages);
    4511                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    4512                 :          0 :                 return;
    4513                 :            :         }
    4514                 :            : 
    4515   [ +  +  +  -  :        635 :         for (i = 0; i < ctx->num_extent_pages; i++) {
                   +  + ]
    4516                 :            :                 /* Extent pages are only read when present within in chain md.
    4517                 :            :                  * Integrity of md is not right if that page was not a valid extent page. */
    4518   [ +  +  +  -  :        318 :                 if (bs_load_cur_extent_page_valid(&ctx->extent_pages[i]) != true) {
             +  -  -  + ]
    4519   [ #  #  #  # ]:          0 :                         spdk_free(ctx->extent_pages);
    4520                 :          0 :                         bs_load_ctx_fail(ctx, -EILSEQ);
    4521                 :          0 :                         return;
    4522                 :            :                 }
    4523                 :            : 
    4524   [ +  -  +  -  :        318 :                 page_num = ctx->extent_page_num[i];
             +  -  +  - ]
    4525   [ +  -  +  -  :        318 :                 spdk_bit_array_set(ctx->bs->used_md_pages, page_num);
             +  -  +  - ]
    4526   [ +  +  +  -  :        318 :                 if (bs_load_replay_md_parse_page(ctx, &ctx->extent_pages[i])) {
             +  -  -  + ]
    4527   [ #  #  #  # ]:          0 :                         spdk_free(ctx->extent_pages);
    4528                 :          0 :                         bs_load_ctx_fail(ctx, -EILSEQ);
    4529                 :          0 :                         return;
    4530                 :            :                 }
    4531                 :         52 :         }
    4532                 :            : 
    4533   [ +  -  +  - ]:        317 :         spdk_free(ctx->extent_pages);
    4534   [ +  -  +  - ]:        317 :         free(ctx->extent_page_num);
    4535   [ +  -  +  - ]:        317 :         ctx->extent_page_num = NULL;
    4536   [ +  -  +  - ]:        317 :         ctx->num_extent_pages = 0;
    4537                 :            : 
    4538                 :        317 :         bs_load_replay_md_chain_cpl(ctx);
    4539         [ -  + ]:         52 : }
    4540                 :            : 
    4541                 :            : static void
    4542                 :        317 : bs_load_replay_extent_pages(struct spdk_bs_load_ctx *ctx)
    4543                 :            : {
    4544                 :         52 :         spdk_bs_batch_t *batch;
    4545                 :         52 :         uint32_t page;
    4546                 :         52 :         uint64_t lba;
    4547                 :         52 :         uint64_t i;
    4548                 :            : 
    4549   [ +  -  +  -  :        317 :         ctx->extent_pages = spdk_zmalloc(SPDK_BS_PAGE_SIZE * ctx->num_extent_pages, 0,
             +  -  +  - ]
    4550                 :            :                                          NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    4551   [ +  +  +  -  :        317 :         if (!ctx->extent_pages) {
                   +  - ]
    4552                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4553                 :          0 :                 return;
    4554                 :            :         }
    4555                 :            : 
    4556   [ +  -  +  - ]:        317 :         batch = bs_sequence_to_batch(ctx->seq, bs_load_replay_extent_page_cpl, ctx);
    4557                 :            : 
    4558   [ +  +  +  -  :        635 :         for (i = 0; i < ctx->num_extent_pages; i++) {
                   +  + ]
    4559   [ +  -  +  -  :        318 :                 page = ctx->extent_page_num[i];
             +  -  +  - ]
    4560   [ +  +  +  -  :        318 :                 assert(page < ctx->super->md_len);
          +  -  +  -  +  
                -  #  # ]
    4561   [ +  -  +  - ]:        318 :                 lba = bs_md_page_to_lba(ctx->bs, page);
    4562   [ +  -  +  -  :        370 :                 bs_batch_read_dev(batch, &ctx->extent_pages[i], lba,
                   +  - ]
    4563   [ +  -  +  - ]:        318 :                                   bs_byte_to_lba(ctx->bs, SPDK_BS_PAGE_SIZE));
    4564                 :         52 :         }
    4565                 :            : 
    4566                 :        317 :         bs_batch_close(batch);
    4567         [ -  + ]:         52 : }
    4568                 :            : 
    4569                 :            : static void
    4570                 :      42398 : bs_load_replay_md_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4571                 :            : {
    4572                 :      42398 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4573                 :       6754 :         uint32_t page_num;
    4574                 :       6754 :         struct spdk_blob_md_page *page;
    4575                 :            : 
    4576         [ -  + ]:      42398 :         if (bserrno != 0) {
    4577                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    4578                 :          0 :                 return;
    4579                 :            :         }
    4580                 :            : 
    4581   [ +  -  +  - ]:      42398 :         page_num = ctx->cur_page;
    4582   [ +  -  +  - ]:      42398 :         page = ctx->page;
    4583         [ +  + ]:      42398 :         if (bs_load_cur_md_page_valid(ctx) == true) {
    4584   [ +  +  +  +  :       1198 :                 if (page->sequence_num == 0 || ctx->in_page_chain == true) {
          +  +  +  -  +  
             -  +  -  +  
                      + ]
    4585   [ +  -  +  -  :       1174 :                         spdk_spin_lock(&ctx->bs->used_lock);
                   +  - ]
    4586   [ +  -  +  - ]:       1174 :                         bs_claim_md_page(ctx->bs, page_num);
    4587   [ +  -  +  -  :       1174 :                         spdk_spin_unlock(&ctx->bs->used_lock);
                   +  - ]
    4588   [ +  +  +  -  :       1174 :                         if (page->sequence_num == 0) {
                   +  + ]
    4589                 :        934 :                                 SPDK_NOTICELOG("Recover: blob 0x%" PRIx32 "\n", page_num);
    4590   [ +  -  +  -  :        934 :                                 spdk_bit_array_set(ctx->bs->used_blobids, page_num);
             +  -  +  - ]
    4591                 :        154 :                         }
    4592         [ -  + ]:       1174 :                         if (bs_load_replay_md_parse_page(ctx, page)) {
    4593                 :          0 :                                 bs_load_ctx_fail(ctx, -EILSEQ);
    4594                 :          0 :                                 return;
    4595                 :            :                         }
    4596   [ +  +  +  -  :       1174 :                         if (page->next != SPDK_INVALID_MD_PAGE) {
                   +  + ]
    4597   [ +  -  +  - ]:        240 :                                 ctx->in_page_chain = true;
    4598   [ +  -  +  -  :        240 :                                 ctx->cur_page = page->next;
             +  -  +  - ]
    4599                 :        240 :                                 bs_load_replay_cur_md_page(ctx);
    4600                 :        240 :                                 return;
    4601                 :            :                         }
    4602   [ +  +  +  -  :        934 :                         if (ctx->num_extent_pages != 0) {
                   +  + ]
    4603                 :        317 :                                 bs_load_replay_extent_pages(ctx);
    4604                 :        317 :                                 return;
    4605                 :            :                         }
    4606                 :        102 :                 }
    4607                 :        106 :         }
    4608                 :      41841 :         bs_load_replay_md_chain_cpl(ctx);
    4609         [ -  + ]:       6754 : }
    4610                 :            : 
    4611                 :            : static void
    4612                 :      42398 : bs_load_replay_cur_md_page(struct spdk_bs_load_ctx *ctx)
    4613                 :            : {
    4614                 :       6754 :         uint64_t lba;
    4615                 :            : 
    4616   [ +  +  +  -  :      42398 :         assert(ctx->cur_page < ctx->super->md_len);
          +  -  +  -  +  
          -  +  -  +  -  
                   #  # ]
    4617   [ +  -  +  -  :      42398 :         lba = bs_md_page_to_lba(ctx->bs, ctx->cur_page);
             +  -  +  - ]
    4618   [ +  -  +  -  :      49152 :         bs_sequence_read_dev(ctx->seq, ctx->page, lba,
             +  -  +  - ]
    4619   [ +  -  +  - ]:      42398 :                              bs_byte_to_lba(ctx->bs, SPDK_BS_PAGE_SIZE),
    4620                 :       6754 :                              bs_load_replay_md_cpl, ctx);
    4621                 :      42398 : }
    4622                 :            : 
    4623                 :            : static void
    4624                 :        641 : bs_load_replay_md(struct spdk_bs_load_ctx *ctx)
    4625                 :            : {
    4626   [ +  -  +  - ]:        641 :         ctx->page_index = 0;
    4627   [ +  -  +  - ]:        641 :         ctx->cur_page = 0;
    4628   [ +  -  +  - ]:        641 :         ctx->page = spdk_zmalloc(SPDK_BS_PAGE_SIZE, 0,
    4629                 :            :                                  NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    4630   [ +  +  +  -  :        641 :         if (!ctx->page) {
                   +  - ]
    4631                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4632                 :          0 :                 return;
    4633                 :            :         }
    4634                 :        641 :         bs_load_replay_cur_md_page(ctx);
    4635                 :        106 : }
    4636                 :            : 
    4637                 :            : static void
    4638                 :        641 : bs_recover(struct spdk_bs_load_ctx *ctx)
    4639                 :            : {
    4640                 :        106 :         int             rc;
    4641                 :            : 
    4642                 :        641 :         SPDK_NOTICELOG("Performing recovery on blobstore\n");
    4643   [ +  -  +  -  :        641 :         rc = spdk_bit_array_resize(&ctx->bs->used_md_pages, ctx->super->md_len);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4644         [ +  + ]:        641 :         if (rc < 0) {
    4645                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4646                 :          0 :                 return;
    4647                 :            :         }
    4648                 :            : 
    4649   [ +  -  +  -  :        641 :         rc = spdk_bit_array_resize(&ctx->bs->used_blobids, ctx->super->md_len);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4650         [ +  + ]:        641 :         if (rc < 0) {
    4651                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4652                 :          0 :                 return;
    4653                 :            :         }
    4654                 :            : 
    4655   [ +  -  +  -  :        641 :         rc = spdk_bit_array_resize(&ctx->used_clusters, ctx->bs->total_clusters);
          +  -  +  -  +  
                      - ]
    4656         [ +  + ]:        641 :         if (rc < 0) {
    4657                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4658                 :          0 :                 return;
    4659                 :            :         }
    4660                 :            : 
    4661   [ +  -  +  -  :        641 :         rc = spdk_bit_array_resize(&ctx->bs->open_blobids, ctx->super->md_len);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4662         [ +  + ]:        641 :         if (rc < 0) {
    4663                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    4664                 :          0 :                 return;
    4665                 :            :         }
    4666                 :            : 
    4667   [ +  -  +  -  :        641 :         ctx->bs->num_free_clusters = ctx->bs->total_clusters;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4668                 :        641 :         bs_load_replay_md(ctx);
    4669         [ -  + ]:        106 : }
    4670                 :            : 
    4671                 :            : static int
    4672                 :       1739 : bs_parse_super(struct spdk_bs_load_ctx *ctx)
    4673                 :            : {
    4674                 :        276 :         int rc;
    4675                 :            : 
    4676   [ +  +  +  -  :       1739 :         if (ctx->super->size == 0) {
          +  -  +  -  +  
                      + ]
    4677   [ +  -  +  -  :         48 :                 ctx->super->size = ctx->bs->dev->blockcnt * ctx->bs->dev->blocklen;
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    4678                 :          8 :         }
    4679                 :            : 
    4680   [ +  +  +  -  :       1739 :         if (ctx->super->io_unit_size == 0) {
          +  -  +  -  +  
                      + ]
    4681   [ +  -  +  -  :         48 :                 ctx->super->io_unit_size = SPDK_BS_PAGE_SIZE;
             +  -  +  - ]
    4682                 :          8 :         }
    4683                 :            : 
    4684   [ +  -  +  -  :       1739 :         ctx->bs->clean = 1;
             +  -  +  - ]
    4685   [ +  -  +  -  :       1739 :         ctx->bs->cluster_sz = ctx->super->cluster_size;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4686   [ +  +  +  -  :       1739 :         ctx->bs->total_clusters = ctx->super->size / ctx->super->cluster_size;
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4687   [ +  -  +  -  :       1739 :         ctx->bs->pages_per_cluster = ctx->bs->cluster_sz / SPDK_BS_PAGE_SIZE;
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
    4688   [ +  -  +  -  :       1739 :         if (spdk_u32_is_pow2(ctx->bs->pages_per_cluster)) {
          +  -  +  -  -  
                      + ]
    4689   [ +  -  +  -  :       1739 :                 ctx->bs->pages_per_cluster_shift = spdk_u32log2(ctx->bs->pages_per_cluster);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4690                 :        276 :         }
    4691   [ +  -  +  -  :       1739 :         ctx->bs->io_unit_size = ctx->super->io_unit_size;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4692   [ +  -  +  -  :       1739 :         rc = spdk_bit_array_resize(&ctx->used_clusters, ctx->bs->total_clusters);
          +  -  +  -  +  
                      - ]
    4693         [ -  + ]:       1739 :         if (rc < 0) {
    4694                 :          0 :                 return -ENOMEM;
    4695                 :            :         }
    4696   [ +  -  +  -  :       1739 :         ctx->bs->md_start = ctx->super->md_start;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4697   [ +  -  +  -  :       1739 :         ctx->bs->md_len = ctx->super->md_len;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4698   [ +  -  +  -  :       1739 :         rc = spdk_bit_array_resize(&ctx->bs->open_blobids, ctx->bs->md_len);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4699         [ -  + ]:       1739 :         if (rc < 0) {
    4700                 :          0 :                 return -ENOMEM;
    4701                 :            :         }
    4702                 :            : 
    4703   [ +  -  +  -  :       4662 :         ctx->bs->total_data_clusters = ctx->bs->total_clusters - spdk_divide_round_up(
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4704   [ +  -  +  -  :       2923 :                                                ctx->bs->md_start + ctx->bs->md_len, ctx->bs->pages_per_cluster);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    4705   [ +  -  +  -  :       1739 :         ctx->bs->super_blob = ctx->super->super_blob;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4706   [ +  -  +  -  :       1739 :         memcpy(&ctx->bs->bstype, &ctx->super->bstype, sizeof(ctx->super->bstype));
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    4707                 :            : 
    4708                 :       1739 :         return 0;
    4709                 :        276 : }
    4710                 :            : 
    4711                 :            : static void
    4712                 :       7160 : bs_load_super_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    4713                 :            : {
    4714                 :       7160 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    4715                 :        300 :         int rc;
    4716                 :            : 
    4717   [ +  -  +  -  :       7160 :         rc = bs_super_validate(ctx->super, ctx->bs);
             +  -  +  - ]
    4718         [ +  + ]:       7160 :         if (rc != 0) {
    4719                 :       5421 :                 bs_load_ctx_fail(ctx, rc);
    4720                 :       5421 :                 return;
    4721                 :            :         }
    4722                 :            : 
    4723                 :       1739 :         rc = bs_parse_super(ctx);
    4724         [ +  + ]:       1739 :         if (rc < 0) {
    4725                 :          0 :                 bs_load_ctx_fail(ctx, rc);
    4726                 :          0 :                 return;
    4727                 :            :         }
    4728                 :            : 
    4729   [ +  +  +  +  :       1739 :         if (ctx->super->used_blobid_mask_len == 0 || ctx->super->clean == 0 || ctx->force_recover) {
          +  +  +  +  +  
          +  +  -  +  -  
          +  -  +  -  +  
          +  +  -  +  -  
             +  -  -  + ]
    4730                 :        641 :                 bs_recover(ctx);
    4731                 :        106 :         } else {
    4732                 :       1098 :                 bs_load_read_used_pages(ctx);
    4733                 :            :         }
    4734         [ -  + ]:        345 : }
    4735                 :            : 
    4736                 :            : static inline int
    4737                 :       7332 : bs_opts_copy(struct spdk_bs_opts *src, struct spdk_bs_opts *dst)
    4738                 :            : {
    4739                 :            : 
    4740   [ +  +  +  -  :       7332 :         if (!src->opts_size) {
                   +  - ]
    4741                 :          0 :                 SPDK_ERRLOG("opts_size should not be zero value\n");
    4742                 :          0 :                 return -1;
    4743                 :            :         }
    4744                 :            : 
    4745                 :            : #define FIELD_OK(field) \
    4746                 :            :         offsetof(struct spdk_bs_opts, field) + sizeof(src->field) <= src->opts_size
    4747                 :            : 
    4748                 :            : #define SET_FIELD(field) \
    4749                 :            :         if (FIELD_OK(field)) { \
    4750                 :            :                 dst->field = src->field; \
    4751                 :            :         } \
    4752                 :            : 
    4753   [ +  -  +  -  :       7332 :         SET_FIELD(cluster_sz);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4754   [ +  -  +  -  :       7332 :         SET_FIELD(num_md_pages);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4755   [ +  -  +  -  :       7332 :         SET_FIELD(max_md_ops);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4756   [ +  -  +  -  :       7332 :         SET_FIELD(max_channel_ops);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4757   [ +  -  +  -  :       7332 :         SET_FIELD(clear_method);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4758                 :            : 
    4759   [ +  -  +  -  :       7332 :         if (FIELD_OK(bstype)) {
                   -  + ]
    4760   [ -  +  -  +  :       7332 :                 memcpy(&dst->bstype, &src->bstype, sizeof(dst->bstype));
             -  +  -  + ]
    4761                 :        339 :         }
    4762   [ +  -  +  -  :       7332 :         SET_FIELD(iter_cb_fn);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4763   [ +  -  +  -  :       7332 :         SET_FIELD(iter_cb_arg);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4764   [ +  -  +  -  :       7332 :         SET_FIELD(force_recover);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4765   [ +  -  +  -  :       7332 :         SET_FIELD(esnap_bs_dev_create);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4766   [ +  -  +  -  :       7332 :         SET_FIELD(esnap_ctx);
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    4767                 :            : 
    4768   [ +  -  +  -  :       7332 :         dst->opts_size = src->opts_size;
             +  -  +  - ]
    4769                 :            : 
    4770                 :            :         /* You should not remove this statement, but need to update the assert statement
    4771                 :            :          * if you add a new field, and also add a corresponding SET_FIELD statement */
    4772                 :            :         SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_opts) == 88, "Incorrect size");
    4773                 :            : 
    4774                 :            : #undef FIELD_OK
    4775                 :            : #undef SET_FIELD
    4776                 :            : 
    4777                 :       7332 :         return 0;
    4778                 :        339 : }
    4779                 :            : 
    4780                 :            : void
    4781                 :       7282 : spdk_bs_load(struct spdk_bs_dev *dev, struct spdk_bs_opts *o,
    4782                 :            :              spdk_bs_op_with_handle_complete cb_fn, void *cb_arg)
    4783                 :            : {
    4784                 :       4517 :         struct spdk_blob_store  *bs;
    4785                 :       4517 :         struct spdk_bs_cpl      cpl;
    4786                 :       4517 :         struct spdk_bs_load_ctx *ctx;
    4787                 :       7282 :         struct spdk_bs_opts     opts = {};
    4788                 :        312 :         int err;
    4789                 :            : 
    4790   [ +  +  +  +  :       7282 :         SPDK_DEBUGLOG(blob, "Loading blobstore from dev %p\n", dev);
                   +  - ]
    4791                 :            : 
    4792   [ +  +  +  +  :       7282 :         if ((SPDK_BS_PAGE_SIZE % dev->blocklen) != 0) {
             +  -  +  + ]
    4793   [ +  +  +  +  :         24 :                 SPDK_DEBUGLOG(blob, "unsupported dev block length of %d\n", dev->blocklen);
          +  -  #  #  #  
                      # ]
    4794   [ +  -  +  -  :         24 :                 dev->destroy(dev);
             -  +  +  - ]
    4795   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, NULL, -EINVAL);
    4796                 :         54 :                 return;
    4797                 :            :         }
    4798                 :            : 
    4799                 :       7258 :         spdk_bs_opts_init(&opts, sizeof(opts));
    4800         [ +  + ]:       7258 :         if (o) {
    4801         [ -  + ]:       6131 :                 if (bs_opts_copy(o, &opts)) {
    4802                 :          0 :                         return;
    4803                 :            :                 }
    4804                 :        169 :         }
    4805                 :            : 
    4806   [ +  +  +  + ]:       7258 :         if (opts.max_md_ops == 0 || opts.max_channel_ops == 0) {
    4807   [ +  -  +  -  :         48 :                 dev->destroy(dev);
             -  +  +  - ]
    4808   [ -  +  +  - ]:         48 :                 cb_fn(cb_arg, NULL, -EINVAL);
    4809                 :         48 :                 return;
    4810                 :            :         }
    4811                 :            : 
    4812                 :       7210 :         err = bs_alloc(dev, &opts, &bs, &ctx);
    4813         [ +  + ]:       7210 :         if (err) {
    4814   [ +  -  +  -  :         50 :                 dev->destroy(dev);
             -  +  +  - ]
    4815   [ -  +  +  - ]:         50 :                 cb_fn(cb_arg, NULL, err);
    4816                 :         50 :                 return;
    4817                 :            :         }
    4818                 :            : 
    4819                 :       7160 :         cpl.type = SPDK_BS_CPL_TYPE_BS_HANDLE;
    4820   [ +  -  +  -  :       7160 :         cpl.u.bs_handle.cb_fn = cb_fn;
                   +  - ]
    4821   [ +  -  +  -  :       7160 :         cpl.u.bs_handle.cb_arg = cb_arg;
                   +  - ]
    4822   [ +  -  +  -  :       7160 :         cpl.u.bs_handle.bs = bs;
                   +  - ]
    4823                 :            : 
    4824   [ +  -  +  -  :       7160 :         ctx->seq = bs_sequence_start_bs(bs->md_channel, &cpl);
             +  -  +  - ]
    4825   [ +  +  +  -  :       7160 :         if (!ctx->seq) {
                   +  + ]
    4826   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    4827                 :          0 :                 free(ctx);
    4828                 :          0 :                 bs_free(bs);
    4829   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    4830                 :          0 :                 return;
    4831                 :            :         }
    4832                 :            : 
    4833                 :            :         /* Read the super block */
    4834   [ +  -  +  -  :       7160 :         bs_sequence_read_dev(ctx->seq, ctx->super, bs_page_to_lba(bs, 0),
             +  -  +  - ]
    4835                 :       7160 :                              bs_byte_to_lba(bs, sizeof(*ctx->super)),
    4836                 :        345 :                              bs_load_super_cpl, ctx);
    4837         [ -  + ]:        359 : }
    4838                 :            : 
    4839                 :            : /* END spdk_bs_load */
    4840                 :            : 
    4841                 :            : /* START spdk_bs_dump */
    4842                 :            : 
    4843                 :            : static void
    4844                 :          0 : bs_dump_finish(spdk_bs_sequence_t *seq, struct spdk_bs_load_ctx *ctx, int bserrno)
    4845                 :            : {
    4846   [ #  #  #  # ]:          0 :         spdk_free(ctx->super);
    4847                 :            : 
    4848                 :            :         /*
    4849                 :            :          * We need to defer calling bs_call_cpl() until after
    4850                 :            :          * dev destruction, so tuck these away for later use.
    4851                 :            :          */
    4852   [ #  #  #  #  :          0 :         ctx->bs->unload_err = bserrno;
             #  #  #  # ]
    4853   [ #  #  #  #  :          0 :         memcpy(&ctx->bs->unload_cpl, &seq->cpl, sizeof(struct spdk_bs_cpl));
          #  #  #  #  #  
                #  #  # ]
    4854   [ #  #  #  #  :          0 :         seq->cpl.type = SPDK_BS_CPL_TYPE_NONE;
                   #  # ]
    4855                 :            : 
    4856                 :          0 :         bs_sequence_finish(seq, 0);
    4857   [ #  #  #  # ]:          0 :         bs_free(ctx->bs);
    4858                 :          0 :         free(ctx);
    4859                 :          0 : }
    4860                 :            : 
    4861                 :            : static void
    4862                 :          0 : bs_dump_print_xattr(struct spdk_bs_load_ctx *ctx, struct spdk_blob_md_descriptor *desc)
    4863                 :            : {
    4864                 :          0 :         struct spdk_blob_md_descriptor_xattr *desc_xattr;
    4865                 :          0 :         uint32_t i;
    4866                 :          0 :         const char *type;
    4867                 :            : 
    4868                 :          0 :         desc_xattr = (struct spdk_blob_md_descriptor_xattr *)desc;
    4869                 :            : 
    4870   [ #  #  #  #  :          0 :         if (desc_xattr->length !=
                   #  # ]
    4871                 :          0 :             sizeof(desc_xattr->name_length) + sizeof(desc_xattr->value_length) +
    4872   [ #  #  #  #  :          0 :             desc_xattr->name_length + desc_xattr->value_length) {
          #  #  #  #  #  
                      # ]
    4873                 :          0 :         }
    4874                 :            : 
    4875   [ #  #  #  #  :          0 :         memcpy(ctx->xattr_name, desc_xattr->name, desc_xattr->name_length);
          #  #  #  #  #  
                #  #  # ]
    4876   [ #  #  #  #  :          0 :         ctx->xattr_name[desc_xattr->name_length] = '\0';
          #  #  #  #  #  
                      # ]
    4877   [ #  #  #  #  :          0 :         if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_XATTR) {
                   #  # ]
    4878                 :          0 :                 type = "XATTR";
    4879   [ #  #  #  #  :          0 :         } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_XATTR_INTERNAL) {
                   #  # ]
    4880                 :          0 :                 type = "XATTR_INTERNAL";
    4881                 :          0 :         } else {
    4882         [ #  # ]:          0 :                 assert(false);
    4883                 :            :                 type = "XATTR_?";
    4884                 :            :         }
    4885   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "%s: name = \"%s\"\n", type, ctx->xattr_name);
                   #  # ]
    4886   [ #  #  #  # ]:          0 :         fprintf(ctx->fp, "       value = \"");
    4887   [ #  #  #  #  :          0 :         ctx->print_xattr_fn(ctx->fp, ctx->super->bstype.bstype, ctx->xattr_name,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    4888   [ #  #  #  #  :          0 :                             (void *)((uintptr_t)desc_xattr->name + desc_xattr->name_length),
                   #  # ]
    4889   [ #  #  #  # ]:          0 :                             desc_xattr->value_length);
    4890   [ #  #  #  # ]:          0 :         fprintf(ctx->fp, "\"\n");
    4891   [ #  #  #  #  :          0 :         for (i = 0; i < desc_xattr->value_length; i++) {
                   #  # ]
    4892   [ #  #  #  # ]:          0 :                 if (i % 16 == 0) {
    4893   [ #  #  #  # ]:          0 :                         fprintf(ctx->fp, "               ");
    4894                 :          0 :                 }
    4895   [ #  #  #  #  :          0 :                 fprintf(ctx->fp, "%02" PRIx8 " ", *((uint8_t *)desc_xattr->name + desc_xattr->name_length + i));
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    4896   [ #  #  #  # ]:          0 :                 if ((i + 1) % 16 == 0) {
    4897   [ #  #  #  # ]:          0 :                         fprintf(ctx->fp, "\n");
    4898                 :          0 :                 }
    4899                 :          0 :         }
    4900   [ #  #  #  # ]:          0 :         if (i % 16 != 0) {
    4901   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, "\n");
    4902                 :          0 :         }
    4903                 :          0 : }
    4904                 :            : 
    4905                 :            : struct type_flag_desc {
    4906                 :            :         uint64_t mask;
    4907                 :            :         uint64_t val;
    4908                 :            :         const char *name;
    4909                 :            : };
    4910                 :            : 
    4911                 :            : static void
    4912                 :          0 : bs_dump_print_type_bits(struct spdk_bs_load_ctx *ctx, uint64_t flags,
    4913                 :            :                         struct type_flag_desc *desc, size_t numflags)
    4914                 :            : {
    4915                 :          0 :         uint64_t covered = 0;
    4916                 :          0 :         size_t i;
    4917                 :            : 
    4918         [ #  # ]:          0 :         for (i = 0; i < numflags; i++) {
    4919   [ #  #  #  #  :          0 :                 if ((desc[i].mask & flags) != desc[i].val) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    4920                 :          0 :                         continue;
    4921                 :            :                 }
    4922   [ #  #  #  #  :          0 :                 fprintf(ctx->fp, "\t\t 0x%016" PRIx64 " %s", desc[i].val, desc[i].name);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    4923   [ #  #  #  #  :          0 :                 if (desc[i].mask != desc[i].val) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    4924   [ #  #  #  # ]:          0 :                         fprintf(ctx->fp, " (mask 0x%" PRIx64 " value 0x%" PRIx64 ")",
    4925   [ #  #  #  #  :          0 :                                 desc[i].mask, desc[i].val);
          #  #  #  #  #  
                #  #  # ]
    4926                 :          0 :                 }
    4927   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, "\n");
    4928   [ #  #  #  #  :          0 :                 covered |= desc[i].mask;
                   #  # ]
    4929                 :          0 :         }
    4930         [ #  # ]:          0 :         if ((flags & ~covered) != 0) {
    4931   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, "\t\t 0x%016" PRIx64 " Unknown\n", flags & ~covered);
    4932                 :          0 :         }
    4933                 :          0 : }
    4934                 :            : 
    4935                 :            : static void
    4936                 :          0 : bs_dump_print_type_flags(struct spdk_bs_load_ctx *ctx, struct spdk_blob_md_descriptor *desc)
    4937                 :            : {
    4938                 :          0 :         struct spdk_blob_md_descriptor_flags *type_desc;
    4939                 :            : #define ADD_FLAG(f) { f, f, #f }
    4940                 :            : #define ADD_MASK_VAL(m, v) { m, v, #v }
    4941                 :            :         static struct type_flag_desc invalid[] = {
    4942                 :            :                 ADD_FLAG(SPDK_BLOB_THIN_PROV),
    4943                 :            :                 ADD_FLAG(SPDK_BLOB_INTERNAL_XATTR),
    4944                 :            :                 ADD_FLAG(SPDK_BLOB_EXTENT_TABLE),
    4945                 :            :         };
    4946                 :            :         static struct type_flag_desc data_ro[] = {
    4947                 :            :                 ADD_FLAG(SPDK_BLOB_READ_ONLY),
    4948                 :            :         };
    4949                 :            :         static struct type_flag_desc md_ro[] = {
    4950                 :            :                 ADD_MASK_VAL(SPDK_BLOB_MD_RO_FLAGS_MASK, BLOB_CLEAR_WITH_DEFAULT),
    4951                 :            :                 ADD_MASK_VAL(SPDK_BLOB_MD_RO_FLAGS_MASK, BLOB_CLEAR_WITH_NONE),
    4952                 :            :                 ADD_MASK_VAL(SPDK_BLOB_MD_RO_FLAGS_MASK, BLOB_CLEAR_WITH_UNMAP),
    4953                 :            :                 ADD_MASK_VAL(SPDK_BLOB_MD_RO_FLAGS_MASK, BLOB_CLEAR_WITH_WRITE_ZEROES),
    4954                 :            :         };
    4955                 :            : #undef ADD_FLAG
    4956                 :            : #undef ADD_MASK_VAL
    4957                 :            : 
    4958                 :          0 :         type_desc = (struct spdk_blob_md_descriptor_flags *)desc;
    4959   [ #  #  #  # ]:          0 :         fprintf(ctx->fp, "Flags:\n");
    4960   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "\tinvalid: 0x%016" PRIx64 "\n", type_desc->invalid_flags);
             #  #  #  # ]
    4961   [ #  #  #  # ]:          0 :         bs_dump_print_type_bits(ctx, type_desc->invalid_flags, invalid,
    4962                 :            :                                 SPDK_COUNTOF(invalid));
    4963   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "\tdata_ro: 0x%016" PRIx64 "\n", type_desc->data_ro_flags);
             #  #  #  # ]
    4964   [ #  #  #  # ]:          0 :         bs_dump_print_type_bits(ctx, type_desc->data_ro_flags, data_ro,
    4965                 :            :                                 SPDK_COUNTOF(data_ro));
    4966   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "\t  md_ro: 0x%016" PRIx64 "\n", type_desc->md_ro_flags);
             #  #  #  # ]
    4967   [ #  #  #  # ]:          0 :         bs_dump_print_type_bits(ctx, type_desc->md_ro_flags, md_ro,
    4968                 :            :                                 SPDK_COUNTOF(md_ro));
    4969                 :          0 : }
    4970                 :            : 
    4971                 :            : static void
    4972                 :          0 : bs_dump_print_extent_table(struct spdk_bs_load_ctx *ctx, struct spdk_blob_md_descriptor *desc)
    4973                 :            : {
    4974                 :          0 :         struct spdk_blob_md_descriptor_extent_table *et_desc;
    4975                 :          0 :         uint64_t num_extent_pages;
    4976                 :          0 :         uint32_t et_idx;
    4977                 :            : 
    4978                 :          0 :         et_desc = (struct spdk_blob_md_descriptor_extent_table *)desc;
    4979   [ #  #  #  #  :          0 :         num_extent_pages = (et_desc->length - sizeof(et_desc->num_clusters)) /
                   #  # ]
    4980                 :            :                            sizeof(et_desc->extent_page[0]);
    4981                 :            : 
    4982   [ #  #  #  # ]:          0 :         fprintf(ctx->fp, "Extent table:\n");
    4983         [ #  # ]:          0 :         for (et_idx = 0; et_idx < num_extent_pages; et_idx++) {
    4984   [ #  #  #  #  :          0 :                 if (et_desc->extent_page[et_idx].page_idx == 0) {
          #  #  #  #  #  
                      # ]
    4985                 :            :                         /* Zeroes represent unallocated extent pages. */
    4986                 :          0 :                         continue;
    4987                 :            :                 }
    4988   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, "\tExtent page: %5" PRIu32 " length %3" PRIu32
    4989   [ #  #  #  #  :          0 :                         " at LBA %" PRIu64 "\n", et_desc->extent_page[et_idx].page_idx,
             #  #  #  # ]
    4990   [ #  #  #  #  :          0 :                         et_desc->extent_page[et_idx].num_pages,
             #  #  #  # ]
    4991   [ #  #  #  #  :          0 :                         bs_md_page_to_lba(ctx->bs, et_desc->extent_page[et_idx].page_idx));
          #  #  #  #  #  
                #  #  # ]
    4992                 :          0 :         }
    4993                 :          0 : }
    4994                 :            : 
    4995                 :            : static void
    4996                 :          0 : bs_dump_print_md_page(struct spdk_bs_load_ctx *ctx)
    4997                 :            : {
    4998   [ #  #  #  # ]:          0 :         uint32_t page_idx = ctx->cur_page;
    4999   [ #  #  #  # ]:          0 :         struct spdk_blob_md_page *page = ctx->page;
    5000                 :          0 :         struct spdk_blob_md_descriptor *desc;
    5001                 :          0 :         size_t cur_desc = 0;
    5002                 :          0 :         uint32_t crc;
    5003                 :            : 
    5004   [ #  #  #  # ]:          0 :         fprintf(ctx->fp, "=========\n");
    5005   [ #  #  #  # ]:          0 :         fprintf(ctx->fp, "Metadata Page Index: %" PRIu32 " (0x%" PRIx32 ")\n", page_idx, page_idx);
    5006   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Start LBA: %" PRIu64 "\n", bs_md_page_to_lba(ctx->bs, page_idx));
             #  #  #  # ]
    5007   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Blob ID: 0x%" PRIx64 "\n", page->id);
             #  #  #  # ]
    5008   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Sequence: %" PRIu32 "\n", page->sequence_num);
             #  #  #  # ]
    5009   [ #  #  #  #  :          0 :         if (page->next == SPDK_INVALID_MD_PAGE) {
                   #  # ]
    5010   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, "Next: None\n");
    5011                 :          0 :         } else {
    5012   [ #  #  #  #  :          0 :                 fprintf(ctx->fp, "Next: %" PRIu32 "\n", page->next);
             #  #  #  # ]
    5013                 :            :         }
    5014   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "In used bit array%s:", ctx->super->clean ? "" : " (not clean: dubious)");
          #  #  #  #  #  
                #  #  # ]
    5015   [ #  #  #  #  :          0 :         if (spdk_bit_array_get(ctx->bs->used_md_pages, page_idx)) {
          #  #  #  #  #  
                      # ]
    5016   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, " md");
    5017                 :          0 :         }
    5018   [ #  #  #  #  :          0 :         if (spdk_bit_array_get(ctx->bs->used_blobids, page_idx)) {
          #  #  #  #  #  
                      # ]
    5019   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, " blob");
    5020                 :          0 :         }
    5021   [ #  #  #  # ]:          0 :         fprintf(ctx->fp, "\n");
    5022                 :            : 
    5023                 :          0 :         crc = blob_md_page_calc_crc(page);
    5024   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "CRC: 0x%" PRIx32 " (%s)\n", page->crc, crc == page->crc ? "OK" : "Mismatch");
          #  #  #  #  #  
                #  #  # ]
    5025                 :            : 
    5026         [ #  # ]:          0 :         desc = (struct spdk_blob_md_descriptor *)page->descriptors;
    5027         [ #  # ]:          0 :         while (cur_desc < sizeof(page->descriptors)) {
    5028   [ #  #  #  #  :          0 :                 if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_PADDING) {
                   #  # ]
    5029   [ #  #  #  #  :          0 :                         if (desc->length == 0) {
                   #  # ]
    5030                 :            :                                 /* If padding and length are 0, this terminates the page */
    5031                 :          0 :                                 break;
    5032                 :            :                         }
    5033   [ #  #  #  #  :          0 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_RLE) {
                   #  # ]
    5034                 :          0 :                         struct spdk_blob_md_descriptor_extent_rle       *desc_extent_rle;
    5035                 :          0 :                         unsigned int                            i;
    5036                 :            : 
    5037                 :          0 :                         desc_extent_rle = (struct spdk_blob_md_descriptor_extent_rle *)desc;
    5038                 :            : 
    5039   [ #  #  #  #  :          0 :                         for (i = 0; i < desc_extent_rle->length / sizeof(desc_extent_rle->extents[0]); i++) {
             #  #  #  # ]
    5040   [ #  #  #  #  :          0 :                                 if (desc_extent_rle->extents[i].cluster_idx != 0) {
          #  #  #  #  #  
                      # ]
    5041   [ #  #  #  # ]:          0 :                                         fprintf(ctx->fp, "Allocated Extent - Start: %" PRIu32,
    5042   [ #  #  #  #  :          0 :                                                 desc_extent_rle->extents[i].cluster_idx);
             #  #  #  # ]
    5043                 :          0 :                                 } else {
    5044   [ #  #  #  # ]:          0 :                                         fprintf(ctx->fp, "Unallocated Extent - ");
    5045                 :            :                                 }
    5046   [ #  #  #  #  :          0 :                                 fprintf(ctx->fp, " Length: %" PRIu32, desc_extent_rle->extents[i].length);
          #  #  #  #  #  
                #  #  # ]
    5047   [ #  #  #  # ]:          0 :                                 fprintf(ctx->fp, "\n");
    5048                 :          0 :                         }
    5049   [ #  #  #  #  :          0 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_PAGE) {
                   #  # ]
    5050                 :          0 :                         struct spdk_blob_md_descriptor_extent_page      *desc_extent;
    5051                 :          0 :                         unsigned int                                    i;
    5052                 :            : 
    5053                 :          0 :                         desc_extent = (struct spdk_blob_md_descriptor_extent_page *)desc;
    5054                 :            : 
    5055   [ #  #  #  #  :          0 :                         for (i = 0; i < desc_extent->length / sizeof(desc_extent->cluster_idx[0]); i++) {
             #  #  #  # ]
    5056   [ #  #  #  #  :          0 :                                 if (desc_extent->cluster_idx[i] != 0) {
             #  #  #  # ]
    5057   [ #  #  #  # ]:          0 :                                         fprintf(ctx->fp, "Allocated Extent - Start: %" PRIu32,
    5058   [ #  #  #  #  :          0 :                                                 desc_extent->cluster_idx[i]);
                   #  # ]
    5059                 :          0 :                                 } else {
    5060   [ #  #  #  # ]:          0 :                                         fprintf(ctx->fp, "Unallocated Extent");
    5061                 :            :                                 }
    5062   [ #  #  #  # ]:          0 :                                 fprintf(ctx->fp, "\n");
    5063                 :          0 :                         }
    5064   [ #  #  #  #  :          0 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_XATTR) {
                   #  # ]
    5065                 :          0 :                         bs_dump_print_xattr(ctx, desc);
    5066   [ #  #  #  #  :          0 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_XATTR_INTERNAL) {
                   #  # ]
    5067                 :          0 :                         bs_dump_print_xattr(ctx, desc);
    5068   [ #  #  #  #  :          0 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_FLAGS) {
                   #  # ]
    5069                 :          0 :                         bs_dump_print_type_flags(ctx, desc);
    5070   [ #  #  #  #  :          0 :                 } else if (desc->type == SPDK_MD_DESCRIPTOR_TYPE_EXTENT_TABLE) {
                   #  # ]
    5071                 :          0 :                         bs_dump_print_extent_table(ctx, desc);
    5072                 :          0 :                 } else {
    5073                 :            :                         /* Error */
    5074   [ #  #  #  #  :          0 :                         fprintf(ctx->fp, "Unknown descriptor type %" PRIu8 "\n", desc->type);
             #  #  #  # ]
    5075                 :            :                 }
    5076                 :            :                 /* Advance to the next descriptor */
    5077   [ #  #  #  # ]:          0 :                 cur_desc += sizeof(*desc) + desc->length;
    5078         [ #  # ]:          0 :                 if (cur_desc + sizeof(*desc) > sizeof(page->descriptors)) {
    5079                 :          0 :                         break;
    5080                 :            :                 }
    5081         [ #  # ]:          0 :                 desc = (struct spdk_blob_md_descriptor *)((uintptr_t)page->descriptors + cur_desc);
    5082                 :            :         }
    5083                 :          0 : }
    5084                 :            : 
    5085                 :            : static void
    5086                 :          0 : bs_dump_read_md_page_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5087                 :            : {
    5088                 :          0 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5089                 :            : 
    5090         [ #  # ]:          0 :         if (bserrno != 0) {
    5091                 :          0 :                 bs_dump_finish(seq, ctx, bserrno);
    5092                 :          0 :                 return;
    5093                 :            :         }
    5094                 :            : 
    5095   [ #  #  #  #  :          0 :         if (ctx->page->id != 0) {
          #  #  #  #  #  
                      # ]
    5096                 :          0 :                 bs_dump_print_md_page(ctx);
    5097                 :          0 :         }
    5098                 :            : 
    5099         [ #  # ]:          0 :         ctx->cur_page++;
    5100                 :            : 
    5101   [ #  #  #  #  :          0 :         if (ctx->cur_page < ctx->super->md_len) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    5102                 :          0 :                 bs_dump_read_md_page(seq, ctx);
    5103                 :          0 :         } else {
    5104   [ #  #  #  # ]:          0 :                 spdk_free(ctx->page);
    5105                 :          0 :                 bs_dump_finish(seq, ctx, 0);
    5106                 :            :         }
    5107         [ #  # ]:          0 : }
    5108                 :            : 
    5109                 :            : static void
    5110                 :          0 : bs_dump_read_md_page(spdk_bs_sequence_t *seq, void *cb_arg)
    5111                 :            : {
    5112                 :          0 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5113                 :          0 :         uint64_t lba;
    5114                 :            : 
    5115   [ #  #  #  #  :          0 :         assert(ctx->cur_page < ctx->super->md_len);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    5116   [ #  #  #  #  :          0 :         lba = bs_page_to_lba(ctx->bs, ctx->super->md_start + ctx->cur_page);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    5117   [ #  #  #  # ]:          0 :         bs_sequence_read_dev(seq, ctx->page, lba,
    5118   [ #  #  #  # ]:          0 :                              bs_byte_to_lba(ctx->bs, SPDK_BS_PAGE_SIZE),
    5119                 :          0 :                              bs_dump_read_md_page_cpl, ctx);
    5120                 :          0 : }
    5121                 :            : 
    5122                 :            : static void
    5123                 :          0 : bs_dump_super_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5124                 :            : {
    5125                 :          0 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5126                 :          0 :         int rc;
    5127                 :            : 
    5128   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Signature: \"%.8s\" ", ctx->super->signature);
          #  #  #  #  #  
                      # ]
    5129   [ #  #  #  #  :          0 :         if (memcmp(ctx->super->signature, SPDK_BS_SUPER_BLOCK_SIG,
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    5130                 :          0 :                    sizeof(ctx->super->signature)) != 0) {
    5131   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, "(Mismatch)\n");
    5132                 :          0 :                 bs_dump_finish(seq, ctx, bserrno);
    5133                 :          0 :                 return;
    5134                 :            :         } else {
    5135   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, "(OK)\n");
    5136                 :            :         }
    5137   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Version: %" PRIu32 "\n", ctx->super->version);
          #  #  #  #  #  
                #  #  # ]
    5138   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "CRC: 0x%x (%s)\n", ctx->super->crc,
          #  #  #  #  #  
                #  #  # ]
    5139   [ #  #  #  #  :          0 :                 (ctx->super->crc == blob_md_page_calc_crc(ctx->super)) ? "OK" : "Mismatch");
          #  #  #  #  #  
                #  #  # ]
    5140   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Blobstore Type: %.*s\n", SPDK_BLOBSTORE_TYPE_LENGTH, ctx->super->bstype.bstype);
          #  #  #  #  #  
                #  #  # ]
    5141   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Cluster Size: %" PRIu32 "\n", ctx->super->cluster_size);
          #  #  #  #  #  
                #  #  # ]
    5142   [ #  #  #  # ]:          0 :         fprintf(ctx->fp, "Super Blob ID: ");
    5143   [ #  #  #  #  :          0 :         if (ctx->super->super_blob == SPDK_BLOBID_INVALID) {
          #  #  #  #  #  
                      # ]
    5144   [ #  #  #  # ]:          0 :                 fprintf(ctx->fp, "(None)\n");
    5145                 :          0 :         } else {
    5146   [ #  #  #  #  :          0 :                 fprintf(ctx->fp, "0x%" PRIx64 "\n", ctx->super->super_blob);
          #  #  #  #  #  
                #  #  # ]
    5147                 :            :         }
    5148   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Clean: %" PRIu32 "\n", ctx->super->clean);
          #  #  #  #  #  
                #  #  # ]
    5149   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Used Metadata Page Mask Start: %" PRIu32 "\n", ctx->super->used_page_mask_start);
          #  #  #  #  #  
                #  #  # ]
    5150   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Used Metadata Page Mask Length: %" PRIu32 "\n", ctx->super->used_page_mask_len);
          #  #  #  #  #  
                #  #  # ]
    5151   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Used Cluster Mask Start: %" PRIu32 "\n", ctx->super->used_cluster_mask_start);
          #  #  #  #  #  
                #  #  # ]
    5152   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Used Cluster Mask Length: %" PRIu32 "\n", ctx->super->used_cluster_mask_len);
          #  #  #  #  #  
                #  #  # ]
    5153   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Used Blob ID Mask Start: %" PRIu32 "\n", ctx->super->used_blobid_mask_start);
          #  #  #  #  #  
                #  #  # ]
    5154   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Used Blob ID Mask Length: %" PRIu32 "\n", ctx->super->used_blobid_mask_len);
          #  #  #  #  #  
                #  #  # ]
    5155   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Metadata Start: %" PRIu32 "\n", ctx->super->md_start);
          #  #  #  #  #  
                #  #  # ]
    5156   [ #  #  #  #  :          0 :         fprintf(ctx->fp, "Metadata Length: %" PRIu32 "\n", ctx->super->md_len);
          #  #  #  #  #  
                #  #  # ]
    5157                 :            : 
    5158   [ #  #  #  # ]:          0 :         ctx->cur_page = 0;
    5159   [ #  #  #  # ]:          0 :         ctx->page = spdk_zmalloc(SPDK_BS_PAGE_SIZE, 0,
    5160                 :            :                                  NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    5161   [ #  #  #  #  :          0 :         if (!ctx->page) {
                   #  # ]
    5162                 :          0 :                 bs_dump_finish(seq, ctx, -ENOMEM);
    5163                 :          0 :                 return;
    5164                 :            :         }
    5165                 :            : 
    5166                 :          0 :         rc = bs_parse_super(ctx);
    5167         [ #  # ]:          0 :         if (rc < 0) {
    5168                 :          0 :                 bs_load_ctx_fail(ctx, rc);
    5169                 :          0 :                 return;
    5170                 :            :         }
    5171                 :            : 
    5172                 :          0 :         bs_load_read_used_pages(ctx);
    5173         [ #  # ]:          0 : }
    5174                 :            : 
    5175                 :            : void
    5176                 :          0 : spdk_bs_dump(struct spdk_bs_dev *dev, FILE *fp, spdk_bs_dump_print_xattr print_xattr_fn,
    5177                 :            :              spdk_bs_op_complete cb_fn, void *cb_arg)
    5178                 :            : {
    5179                 :          0 :         struct spdk_blob_store  *bs;
    5180                 :          0 :         struct spdk_bs_cpl      cpl;
    5181                 :          0 :         struct spdk_bs_load_ctx *ctx;
    5182                 :          0 :         struct spdk_bs_opts     opts = {};
    5183                 :          0 :         int err;
    5184                 :            : 
    5185   [ #  #  #  #  :          0 :         SPDK_DEBUGLOG(blob, "Dumping blobstore from dev %p\n", dev);
                   #  # ]
    5186                 :            : 
    5187                 :          0 :         spdk_bs_opts_init(&opts, sizeof(opts));
    5188                 :            : 
    5189                 :          0 :         err = bs_alloc(dev, &opts, &bs, &ctx);
    5190         [ #  # ]:          0 :         if (err) {
    5191   [ #  #  #  #  :          0 :                 dev->destroy(dev);
             #  #  #  # ]
    5192   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, err);
    5193                 :          0 :                 return;
    5194                 :            :         }
    5195                 :            : 
    5196   [ #  #  #  # ]:          0 :         ctx->dumping = true;
    5197   [ #  #  #  # ]:          0 :         ctx->fp = fp;
    5198   [ #  #  #  # ]:          0 :         ctx->print_xattr_fn = print_xattr_fn;
    5199                 :            : 
    5200                 :          0 :         cpl.type = SPDK_BS_CPL_TYPE_BS_BASIC;
    5201   [ #  #  #  #  :          0 :         cpl.u.bs_basic.cb_fn = cb_fn;
                   #  # ]
    5202   [ #  #  #  #  :          0 :         cpl.u.bs_basic.cb_arg = cb_arg;
                   #  # ]
    5203                 :            : 
    5204   [ #  #  #  #  :          0 :         ctx->seq = bs_sequence_start_bs(bs->md_channel, &cpl);
             #  #  #  # ]
    5205   [ #  #  #  #  :          0 :         if (!ctx->seq) {
                   #  # ]
    5206   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5207                 :          0 :                 free(ctx);
    5208                 :          0 :                 bs_free(bs);
    5209   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5210                 :          0 :                 return;
    5211                 :            :         }
    5212                 :            : 
    5213                 :            :         /* Read the super block */
    5214   [ #  #  #  #  :          0 :         bs_sequence_read_dev(ctx->seq, ctx->super, bs_page_to_lba(bs, 0),
             #  #  #  # ]
    5215                 :          0 :                              bs_byte_to_lba(bs, sizeof(*ctx->super)),
    5216                 :          0 :                              bs_dump_super_cpl, ctx);
    5217         [ #  # ]:          0 : }
    5218                 :            : 
    5219                 :            : /* END spdk_bs_dump */
    5220                 :            : 
    5221                 :            : /* START spdk_bs_init */
    5222                 :            : 
    5223                 :            : static void
    5224                 :       2846 : bs_init_persist_super_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5225                 :            : {
    5226                 :       2846 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5227                 :            : 
    5228   [ +  -  +  -  :       2846 :         ctx->bs->used_clusters = spdk_bit_pool_create_from_array(ctx->used_clusters);
          +  -  +  -  +  
                -  +  - ]
    5229   [ +  -  +  - ]:       2846 :         spdk_free(ctx->super);
    5230                 :       2846 :         free(ctx);
    5231                 :            : 
    5232                 :       2846 :         bs_sequence_finish(seq, bserrno);
    5233                 :       2846 : }
    5234                 :            : 
    5235                 :            : static void
    5236                 :       2846 : bs_init_trim_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5237                 :            : {
    5238                 :       2846 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5239                 :            : 
    5240                 :            :         /* Write super block */
    5241   [ +  -  +  -  :       3290 :         bs_sequence_write_dev(seq, ctx->super, bs_page_to_lba(ctx->bs, 0),
             +  -  +  - ]
    5242   [ +  -  +  - ]:       2846 :                               bs_byte_to_lba(ctx->bs, sizeof(*ctx->super)),
    5243                 :        444 :                               bs_init_persist_super_cpl, ctx);
    5244                 :       2846 : }
    5245                 :            : 
    5246                 :            : void
    5247                 :       2943 : spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o,
    5248                 :            :              spdk_bs_op_with_handle_complete cb_fn, void *cb_arg)
    5249                 :            : {
    5250                 :       2411 :         struct spdk_bs_load_ctx *ctx;
    5251                 :       2411 :         struct spdk_blob_store  *bs;
    5252                 :       2411 :         struct spdk_bs_cpl      cpl;
    5253                 :        460 :         spdk_bs_sequence_t      *seq;
    5254                 :        460 :         spdk_bs_batch_t         *batch;
    5255                 :        460 :         uint64_t                num_md_lba;
    5256                 :        460 :         uint64_t                num_md_pages;
    5257                 :        460 :         uint64_t                num_md_clusters;
    5258                 :        460 :         uint64_t                max_used_cluster_mask_len;
    5259                 :        460 :         uint32_t                i;
    5260                 :       2943 :         struct spdk_bs_opts     opts = {};
    5261                 :        460 :         int                     rc;
    5262                 :        460 :         uint64_t                lba, lba_count;
    5263                 :            : 
    5264   [ +  +  +  +  :       2943 :         SPDK_DEBUGLOG(blob, "Initializing blobstore on dev %p\n", dev);
                   +  - ]
    5265                 :            : 
    5266   [ +  +  +  +  :       2943 :         if ((SPDK_BS_PAGE_SIZE % dev->blocklen) != 0) {
             +  -  +  + ]
    5267   [ +  -  +  - ]:         24 :                 SPDK_ERRLOG("unsupported dev block length of %d\n",
    5268                 :            :                             dev->blocklen);
    5269   [ +  -  +  -  :         24 :                 dev->destroy(dev);
             -  +  +  - ]
    5270   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, NULL, -EINVAL);
    5271                 :         36 :                 return;
    5272                 :            :         }
    5273                 :            : 
    5274                 :       2919 :         spdk_bs_opts_init(&opts, sizeof(opts));
    5275         [ +  + ]:       2919 :         if (o) {
    5276         [ -  + ]:       1177 :                 if (bs_opts_copy(o, &opts)) {
    5277                 :          0 :                         return;
    5278                 :            :                 }
    5279                 :        166 :         }
    5280                 :            : 
    5281         [ +  + ]:       2919 :         if (bs_opts_verify(&opts) != 0) {
    5282   [ +  -  +  -  :         24 :                 dev->destroy(dev);
             -  +  +  - ]
    5283   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, NULL, -EINVAL);
    5284                 :         24 :                 return;
    5285                 :            :         }
    5286                 :            : 
    5287                 :       2895 :         rc = bs_alloc(dev, &opts, &bs, &ctx);
    5288         [ +  + ]:       2895 :         if (rc) {
    5289   [ +  -  +  -  :         24 :                 dev->destroy(dev);
             -  +  +  - ]
    5290   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, NULL, rc);
    5291                 :         24 :                 return;
    5292                 :            :         }
    5293                 :            : 
    5294         [ +  + ]:       2871 :         if (opts.num_md_pages == SPDK_BLOB_OPTS_NUM_MD_PAGES) {
    5295                 :            :                 /* By default, allocate 1 page per cluster.
    5296                 :            :                  * Technically, this over-allocates metadata
    5297                 :            :                  * because more metadata will reduce the number
    5298                 :            :                  * of usable clusters. This can be addressed with
    5299                 :            :                  * more complex math in the future.
    5300                 :            :                  */
    5301   [ +  -  +  -  :       2645 :                 bs->md_len = bs->total_clusters;
             +  -  +  - ]
    5302                 :        440 :         } else {
    5303   [ +  -  +  - ]:        226 :                 bs->md_len = opts.num_md_pages;
    5304                 :            :         }
    5305   [ +  -  +  -  :       2871 :         rc = spdk_bit_array_resize(&bs->used_md_pages, bs->md_len);
                   +  - ]
    5306         [ +  + ]:       2871 :         if (rc < 0) {
    5307   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5308                 :          0 :                 free(ctx);
    5309                 :          0 :                 bs_free(bs);
    5310   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    5311                 :          0 :                 return;
    5312                 :            :         }
    5313                 :            : 
    5314   [ +  -  +  -  :       2871 :         rc = spdk_bit_array_resize(&bs->used_blobids, bs->md_len);
                   +  - ]
    5315         [ +  + ]:       2871 :         if (rc < 0) {
    5316   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5317                 :          0 :                 free(ctx);
    5318                 :          0 :                 bs_free(bs);
    5319   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    5320                 :          0 :                 return;
    5321                 :            :         }
    5322                 :            : 
    5323   [ +  -  +  -  :       2871 :         rc = spdk_bit_array_resize(&bs->open_blobids, bs->md_len);
                   +  - ]
    5324         [ +  + ]:       2871 :         if (rc < 0) {
    5325   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5326                 :          0 :                 free(ctx);
    5327                 :          0 :                 bs_free(bs);
    5328   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    5329                 :          0 :                 return;
    5330                 :            :         }
    5331                 :            : 
    5332   [ +  +  +  +  :       2871 :         memcpy(ctx->super->signature, SPDK_BS_SUPER_BLOCK_SIG,
          +  -  +  -  +  
                      - ]
    5333                 :            :                sizeof(ctx->super->signature));
    5334   [ +  -  +  -  :       2871 :         ctx->super->version = SPDK_BS_VERSION;
             +  -  +  - ]
    5335   [ +  -  +  -  :       2871 :         ctx->super->length = sizeof(*ctx->super);
             +  -  +  - ]
    5336   [ +  -  +  -  :       2871 :         ctx->super->super_blob = bs->super_blob;
          +  -  +  -  +  
                -  +  - ]
    5337   [ +  -  +  -  :       2871 :         ctx->super->clean = 0;
             +  -  +  - ]
    5338   [ +  -  +  -  :       2871 :         ctx->super->cluster_size = bs->cluster_sz;
          +  -  +  -  +  
                -  +  - ]
    5339   [ +  -  +  -  :       2871 :         ctx->super->io_unit_size = bs->io_unit_size;
          +  -  +  -  +  
                -  +  - ]
    5340   [ +  -  +  -  :       2871 :         memcpy(&ctx->super->bstype, &bs->bstype, sizeof(bs->bstype));
          +  -  +  -  +  
                -  +  - ]
    5341                 :            : 
    5342                 :            :         /* Calculate how many pages the metadata consumes at the front
    5343                 :            :          * of the disk.
    5344                 :            :          */
    5345                 :            : 
    5346                 :            :         /* The super block uses 1 page */
    5347                 :       2871 :         num_md_pages = 1;
    5348                 :            : 
    5349                 :            :         /* The used_md_pages mask requires 1 bit per metadata page, rounded
    5350                 :            :          * up to the nearest page, plus a header.
    5351                 :            :          */
    5352   [ +  -  +  -  :       2871 :         ctx->super->used_page_mask_start = num_md_pages;
             +  -  +  - ]
    5353   [ +  -  +  -  :       2871 :         ctx->super->used_page_mask_len = spdk_divide_round_up(sizeof(struct spdk_bs_md_mask) +
             +  -  +  - ]
    5354   [ +  -  +  - ]:       2871 :                                          spdk_divide_round_up(bs->md_len, 8),
    5355                 :            :                                          SPDK_BS_PAGE_SIZE);
    5356   [ +  -  +  -  :       2871 :         num_md_pages += ctx->super->used_page_mask_len;
             +  -  +  - ]
    5357                 :            : 
    5358                 :            :         /* The used_clusters mask requires 1 bit per cluster, rounded
    5359                 :            :          * up to the nearest page, plus a header.
    5360                 :            :          */
    5361   [ +  -  +  -  :       2871 :         ctx->super->used_cluster_mask_start = num_md_pages;
             +  -  +  - ]
    5362   [ +  -  +  -  :       2871 :         ctx->super->used_cluster_mask_len = spdk_divide_round_up(sizeof(struct spdk_bs_md_mask) +
             +  -  +  - ]
    5363   [ +  -  +  - ]:       2871 :                                             spdk_divide_round_up(bs->total_clusters, 8),
    5364                 :            :                                             SPDK_BS_PAGE_SIZE);
    5365                 :            :         /* The blobstore might be extended, then the used_cluster bitmap will need more space.
    5366                 :            :          * Here we calculate the max clusters we can support according to the
    5367                 :            :          * num_md_pages (bs->md_len).
    5368                 :            :          */
    5369                 :       2871 :         max_used_cluster_mask_len = spdk_divide_round_up(sizeof(struct spdk_bs_md_mask) +
    5370   [ +  -  +  - ]:       2871 :                                     spdk_divide_round_up(bs->md_len, 8),
    5371                 :            :                                     SPDK_BS_PAGE_SIZE);
    5372   [ +  -  +  -  :       2871 :         max_used_cluster_mask_len = spdk_max(max_used_cluster_mask_len,
          +  -  +  -  -  
          +  +  -  +  -  
             +  -  +  - ]
    5373                 :            :                                              ctx->super->used_cluster_mask_len);
    5374                 :       2871 :         num_md_pages += max_used_cluster_mask_len;
    5375                 :            : 
    5376                 :            :         /* The used_blobids mask requires 1 bit per metadata page, rounded
    5377                 :            :          * up to the nearest page, plus a header.
    5378                 :            :          */
    5379   [ +  -  +  -  :       2871 :         ctx->super->used_blobid_mask_start = num_md_pages;
             +  -  +  - ]
    5380   [ +  -  +  -  :       2871 :         ctx->super->used_blobid_mask_len = spdk_divide_round_up(sizeof(struct spdk_bs_md_mask) +
             +  -  +  - ]
    5381   [ +  -  +  - ]:       2871 :                                            spdk_divide_round_up(bs->md_len, 8),
    5382                 :            :                                            SPDK_BS_PAGE_SIZE);
    5383   [ +  -  +  -  :       2871 :         num_md_pages += ctx->super->used_blobid_mask_len;
             +  -  +  - ]
    5384                 :            : 
    5385                 :            :         /* The metadata region size was chosen above */
    5386   [ +  -  +  -  :       2871 :         ctx->super->md_start = bs->md_start = num_md_pages;
          +  -  +  -  +  
                -  +  - ]
    5387   [ +  -  +  -  :       2871 :         ctx->super->md_len = bs->md_len;
          +  -  +  -  +  
                -  +  - ]
    5388   [ +  -  +  - ]:       2871 :         num_md_pages += bs->md_len;
    5389                 :            : 
    5390                 :       2871 :         num_md_lba = bs_page_to_lba(bs, num_md_pages);
    5391                 :            : 
    5392   [ +  -  +  -  :       2871 :         ctx->super->size = dev->blockcnt * dev->blocklen;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    5393                 :            : 
    5394   [ +  -  +  -  :       2871 :         ctx->super->crc = blob_md_page_calc_crc(ctx->super);
          +  -  +  -  +  
                -  +  - ]
    5395                 :            : 
    5396   [ +  -  +  - ]:       2871 :         num_md_clusters = spdk_divide_round_up(num_md_pages, bs->pages_per_cluster);
    5397   [ +  +  +  -  :       2871 :         if (num_md_clusters > bs->total_clusters) {
                   +  + ]
    5398                 :         25 :                 SPDK_ERRLOG("Blobstore metadata cannot use more clusters than is available, "
    5399                 :            :                             "please decrease number of pages reserved for metadata "
    5400                 :            :                             "or increase cluster size.\n");
    5401   [ +  -  +  - ]:         25 :                 spdk_free(ctx->super);
    5402         [ +  - ]:         25 :                 spdk_bit_array_free(&ctx->used_clusters);
    5403                 :         25 :                 free(ctx);
    5404                 :         25 :                 bs_free(bs);
    5405   [ -  +  +  - ]:         25 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    5406                 :         25 :                 return;
    5407                 :            :         }
    5408                 :            :         /* Claim all of the clusters used by the metadata */
    5409         [ +  + ]:     459820 :         for (i = 0; i < num_md_clusters; i++) {
    5410   [ +  -  +  - ]:     456974 :                 spdk_bit_array_set(ctx->used_clusters, i);
    5411                 :      62912 :         }
    5412                 :            : 
    5413   [ +  -  +  - ]:       2846 :         bs->num_free_clusters -= num_md_clusters;
    5414   [ +  -  +  -  :       2846 :         bs->total_data_clusters = bs->num_free_clusters;
             +  -  +  - ]
    5415                 :            : 
    5416                 :       2846 :         cpl.type = SPDK_BS_CPL_TYPE_BS_HANDLE;
    5417   [ +  -  +  -  :       2846 :         cpl.u.bs_handle.cb_fn = cb_fn;
                   +  - ]
    5418   [ +  -  +  -  :       2846 :         cpl.u.bs_handle.cb_arg = cb_arg;
                   +  - ]
    5419   [ +  -  +  -  :       2846 :         cpl.u.bs_handle.bs = bs;
                   +  - ]
    5420                 :            : 
    5421   [ +  -  +  - ]:       2846 :         seq = bs_sequence_start_bs(bs->md_channel, &cpl);
    5422         [ +  + ]:       2846 :         if (!seq) {
    5423   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5424                 :          0 :                 free(ctx);
    5425                 :          0 :                 bs_free(bs);
    5426   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    5427                 :          0 :                 return;
    5428                 :            :         }
    5429                 :            : 
    5430                 :       2846 :         batch = bs_sequence_to_batch(seq, bs_init_trim_cpl, ctx);
    5431                 :            : 
    5432                 :            :         /* Clear metadata space */
    5433                 :       2846 :         bs_batch_write_zeroes_dev(batch, 0, num_md_lba);
    5434                 :            : 
    5435                 :       2846 :         lba = num_md_lba;
    5436   [ +  -  +  -  :       2846 :         lba_count = ctx->bs->dev->blockcnt - lba;
          +  -  +  -  +  
                -  +  - ]
    5437   [ +  +  +  + ]:       2846 :         switch (opts.clear_method) {
    5438                 :       2303 :         case BS_CLEAR_WITH_UNMAP:
    5439                 :            :                 /* Trim data clusters */
    5440                 :       2731 :                 bs_batch_unmap_dev(batch, lba, lba_count);
    5441                 :       2731 :                 break;
    5442                 :          1 :         case BS_CLEAR_WITH_WRITE_ZEROES:
    5443                 :            :                 /* Write_zeroes to data clusters */
    5444                 :          1 :                 bs_batch_write_zeroes_dev(batch, lba, lba_count);
    5445                 :          1 :                 break;
    5446                 :        114 :         case BS_CLEAR_WITH_NONE:
    5447                 :            :         default:
    5448                 :        114 :                 break;
    5449                 :            :         }
    5450                 :            : 
    5451                 :       2846 :         bs_batch_close(batch);
    5452         [ -  + ]:        460 : }
    5453                 :            : 
    5454                 :            : /* END spdk_bs_init */
    5455                 :            : 
    5456                 :            : /* START spdk_bs_destroy */
    5457                 :            : 
    5458                 :            : static void
    5459                 :        137 : bs_destroy_trim_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5460                 :            : {
    5461                 :        137 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5462   [ +  -  +  - ]:        137 :         struct spdk_blob_store *bs = ctx->bs;
    5463                 :            : 
    5464                 :            :         /*
    5465                 :            :          * We need to defer calling bs_call_cpl() until after
    5466                 :            :          * dev destruction, so tuck these away for later use.
    5467                 :            :          */
    5468   [ +  -  +  - ]:        137 :         bs->unload_err = bserrno;
    5469   [ +  +  +  +  :        137 :         memcpy(&bs->unload_cpl, &seq->cpl, sizeof(struct spdk_bs_cpl));
             +  -  +  - ]
    5470   [ +  -  +  -  :        137 :         seq->cpl.type = SPDK_BS_CPL_TYPE_NONE;
                   +  - ]
    5471                 :            : 
    5472                 :        137 :         bs_sequence_finish(seq, bserrno);
    5473                 :            : 
    5474                 :        137 :         bs_free(bs);
    5475                 :        137 :         free(ctx);
    5476                 :        137 : }
    5477                 :            : 
    5478                 :            : void
    5479                 :        137 : spdk_bs_destroy(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn,
    5480                 :            :                 void *cb_arg)
    5481                 :            : {
    5482                 :         92 :         struct spdk_bs_cpl      cpl;
    5483                 :          4 :         spdk_bs_sequence_t      *seq;
    5484                 :          4 :         struct spdk_bs_load_ctx *ctx;
    5485                 :            : 
    5486   [ +  +  +  +  :        137 :         SPDK_DEBUGLOG(blob, "Destroying blobstore\n");
                   +  - ]
    5487                 :            : 
    5488   [ +  +  +  -  :        137 :         if (!RB_EMPTY(&bs->open_blobs)) {
             +  -  -  + ]
    5489                 :          0 :                 SPDK_ERRLOG("Blobstore still has open blobs\n");
    5490   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -EBUSY);
    5491                 :          0 :                 return;
    5492                 :            :         }
    5493                 :            : 
    5494                 :        137 :         cpl.type = SPDK_BS_CPL_TYPE_BS_BASIC;
    5495   [ +  -  +  -  :        137 :         cpl.u.bs_basic.cb_fn = cb_fn;
                   +  - ]
    5496   [ +  -  +  -  :        137 :         cpl.u.bs_basic.cb_arg = cb_arg;
                   +  - ]
    5497                 :            : 
    5498                 :        137 :         ctx = calloc(1, sizeof(*ctx));
    5499         [ +  + ]:        137 :         if (!ctx) {
    5500   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5501                 :          0 :                 return;
    5502                 :            :         }
    5503                 :            : 
    5504   [ +  -  +  - ]:        137 :         ctx->bs = bs;
    5505                 :            : 
    5506   [ +  -  +  - ]:        137 :         seq = bs_sequence_start_bs(bs->md_channel, &cpl);
    5507         [ +  + ]:        137 :         if (!seq) {
    5508                 :          0 :                 free(ctx);
    5509   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5510                 :          0 :                 return;
    5511                 :            :         }
    5512                 :            : 
    5513                 :            :         /* Write zeroes to the super block */
    5514                 :        141 :         bs_sequence_write_zeroes_dev(seq,
    5515                 :          4 :                                      bs_page_to_lba(bs, 0),
    5516                 :          4 :                                      bs_byte_to_lba(bs, sizeof(struct spdk_bs_super_block)),
    5517                 :          4 :                                      bs_destroy_trim_cpl, ctx);
    5518         [ -  + ]:          4 : }
    5519                 :            : 
    5520                 :            : /* END spdk_bs_destroy */
    5521                 :            : 
    5522                 :            : /* START spdk_bs_unload */
    5523                 :            : 
    5524                 :            : static void
    5525                 :       3908 : bs_unload_finish(struct spdk_bs_load_ctx *ctx, int bserrno)
    5526                 :            : {
    5527   [ +  -  +  - ]:       3908 :         spdk_bs_sequence_t *seq = ctx->seq;
    5528                 :            : 
    5529   [ +  -  +  - ]:       3908 :         spdk_free(ctx->super);
    5530                 :            : 
    5531                 :            :         /*
    5532                 :            :          * We need to defer calling bs_call_cpl() until after
    5533                 :            :          * dev destruction, so tuck these away for later use.
    5534                 :            :          */
    5535   [ +  -  +  -  :       3908 :         ctx->bs->unload_err = bserrno;
             +  -  +  - ]
    5536   [ +  +  +  +  :       3908 :         memcpy(&ctx->bs->unload_cpl, &seq->cpl, sizeof(struct spdk_bs_cpl));
          +  -  +  -  +  
                -  +  - ]
    5537   [ +  -  +  -  :       3908 :         seq->cpl.type = SPDK_BS_CPL_TYPE_NONE;
                   +  - ]
    5538                 :            : 
    5539                 :       3908 :         bs_sequence_finish(seq, bserrno);
    5540                 :            : 
    5541   [ +  -  +  - ]:       3908 :         bs_free(ctx->bs);
    5542                 :       3908 :         free(ctx);
    5543                 :       3908 : }
    5544                 :            : 
    5545                 :            : static void
    5546                 :       3908 : bs_unload_write_super_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5547                 :            : {
    5548                 :       3908 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5549                 :            : 
    5550                 :       3908 :         bs_unload_finish(ctx, bserrno);
    5551                 :       3908 : }
    5552                 :            : 
    5553                 :            : static void
    5554                 :       3908 : bs_unload_write_used_clusters_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5555                 :            : {
    5556                 :       3908 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5557                 :            : 
    5558   [ +  -  +  - ]:       3908 :         spdk_free(ctx->mask);
    5559                 :            : 
    5560         [ -  + ]:       3908 :         if (bserrno != 0) {
    5561                 :          0 :                 bs_unload_finish(ctx, bserrno);
    5562                 :          0 :                 return;
    5563                 :            :         }
    5564                 :            : 
    5565   [ +  -  +  -  :       3908 :         ctx->super->clean = 1;
             +  -  +  - ]
    5566                 :            : 
    5567   [ +  -  +  -  :       3908 :         bs_write_super(seq, ctx->bs, ctx->super, bs_unload_write_super_cpl, ctx);
             +  -  +  - ]
    5568         [ -  + ]:        626 : }
    5569                 :            : 
    5570                 :            : static void
    5571                 :       3908 : bs_unload_write_used_blobids_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5572                 :            : {
    5573                 :       3908 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5574                 :            : 
    5575   [ +  -  +  - ]:       3908 :         spdk_free(ctx->mask);
    5576   [ +  -  +  - ]:       3908 :         ctx->mask = NULL;
    5577                 :            : 
    5578         [ -  + ]:       3908 :         if (bserrno != 0) {
    5579                 :          0 :                 bs_unload_finish(ctx, bserrno);
    5580                 :          0 :                 return;
    5581                 :            :         }
    5582                 :            : 
    5583                 :       3908 :         bs_write_used_clusters(seq, ctx, bs_unload_write_used_clusters_cpl);
    5584         [ -  + ]:        626 : }
    5585                 :            : 
    5586                 :            : static void
    5587                 :       3908 : bs_unload_write_used_pages_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5588                 :            : {
    5589                 :       3908 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5590                 :            : 
    5591   [ +  -  +  - ]:       3908 :         spdk_free(ctx->mask);
    5592   [ +  -  +  - ]:       3908 :         ctx->mask = NULL;
    5593                 :            : 
    5594         [ -  + ]:       3908 :         if (bserrno != 0) {
    5595                 :          0 :                 bs_unload_finish(ctx, bserrno);
    5596                 :          0 :                 return;
    5597                 :            :         }
    5598                 :            : 
    5599                 :       3908 :         bs_write_used_blobids(seq, ctx, bs_unload_write_used_blobids_cpl);
    5600         [ -  + ]:        626 : }
    5601                 :            : 
    5602                 :            : static void
    5603                 :       3908 : bs_unload_read_super_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5604                 :            : {
    5605                 :       3908 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    5606                 :        626 :         int rc;
    5607                 :            : 
    5608         [ -  + ]:       3908 :         if (bserrno != 0) {
    5609                 :          0 :                 bs_unload_finish(ctx, bserrno);
    5610                 :          0 :                 return;
    5611                 :            :         }
    5612                 :            : 
    5613   [ +  -  +  -  :       3908 :         rc = bs_super_validate(ctx->super, ctx->bs);
             +  -  +  - ]
    5614         [ -  + ]:       3908 :         if (rc != 0) {
    5615                 :          0 :                 bs_unload_finish(ctx, rc);
    5616                 :          0 :                 return;
    5617                 :            :         }
    5618                 :            : 
    5619                 :       3908 :         bs_write_used_md(seq, cb_arg, bs_unload_write_used_pages_cpl);
    5620         [ -  + ]:        626 : }
    5621                 :            : 
    5622                 :            : void
    5623                 :       3972 : spdk_bs_unload(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn, void *cb_arg)
    5624                 :            : {
    5625                 :       3294 :         struct spdk_bs_cpl      cpl;
    5626                 :        634 :         struct spdk_bs_load_ctx *ctx;
    5627                 :            : 
    5628   [ +  +  +  +  :       3972 :         SPDK_DEBUGLOG(blob, "Syncing blobstore\n");
                   +  - ]
    5629                 :            : 
    5630                 :            :         /*
    5631                 :            :          * If external snapshot channels are being destroyed while the blobstore is unloaded, the
    5632                 :            :          * unload is deferred until after the channel destruction completes.
    5633                 :            :          */
    5634   [ +  +  +  -  :       3972 :         if (bs->esnap_channels_unloading != 0) {
                   +  + ]
    5635   [ +  +  +  -  :         40 :                 if (bs->esnap_unload_cb_fn != NULL) {
                   -  + ]
    5636                 :          0 :                         SPDK_ERRLOG("Blobstore unload in progress\n");
    5637   [ #  #  #  # ]:          0 :                         cb_fn(cb_arg, -EBUSY);
    5638                 :          8 :                         return;
    5639                 :            :                 }
    5640   [ +  +  +  +  :         40 :                 SPDK_DEBUGLOG(blob_esnap, "Blobstore unload deferred: %" PRIu32
          +  -  #  #  #  
                      # ]
    5641                 :            :                               " esnap clones are unloading\n", bs->esnap_channels_unloading);
    5642   [ +  -  +  - ]:         40 :                 bs->esnap_unload_cb_fn = cb_fn;
    5643   [ +  -  +  - ]:         40 :                 bs->esnap_unload_cb_arg = cb_arg;
    5644                 :         40 :                 return;
    5645                 :            :         }
    5646   [ +  +  +  -  :       3932 :         if (bs->esnap_unload_cb_fn != NULL) {
                   +  + ]
    5647   [ +  +  +  +  :         40 :                 SPDK_DEBUGLOG(blob_esnap, "Blobstore deferred unload progressing\n");
                   +  - ]
    5648   [ +  +  +  -  :         40 :                 assert(bs->esnap_unload_cb_fn == cb_fn);
             +  -  #  # ]
    5649   [ +  +  +  -  :         40 :                 assert(bs->esnap_unload_cb_arg == cb_arg);
             +  -  #  # ]
    5650   [ +  -  +  - ]:         40 :                 bs->esnap_unload_cb_fn = NULL;
    5651   [ +  -  +  - ]:         40 :                 bs->esnap_unload_cb_arg = NULL;
    5652                 :          4 :         }
    5653                 :            : 
    5654   [ +  +  +  -  :       3932 :         if (!RB_EMPTY(&bs->open_blobs)) {
             +  -  +  + ]
    5655                 :         24 :                 SPDK_ERRLOG("Blobstore still has open blobs\n");
    5656   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, -EBUSY);
    5657                 :         24 :                 return;
    5658                 :            :         }
    5659                 :            : 
    5660                 :       3908 :         ctx = calloc(1, sizeof(*ctx));
    5661         [ -  + ]:       3908 :         if (!ctx) {
    5662   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5663                 :          0 :                 return;
    5664                 :            :         }
    5665                 :            : 
    5666   [ +  -  +  - ]:       3908 :         ctx->bs = bs;
    5667                 :            : 
    5668   [ +  -  +  - ]:       3908 :         ctx->super = spdk_zmalloc(sizeof(*ctx->super), 0x1000, NULL,
    5669                 :            :                                   SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    5670   [ +  +  +  -  :       3908 :         if (!ctx->super) {
                   -  + ]
    5671                 :          0 :                 free(ctx);
    5672   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5673                 :          0 :                 return;
    5674                 :            :         }
    5675                 :            : 
    5676                 :       3908 :         cpl.type = SPDK_BS_CPL_TYPE_BS_BASIC;
    5677   [ +  -  +  -  :       3908 :         cpl.u.bs_basic.cb_fn = cb_fn;
                   +  - ]
    5678   [ +  -  +  -  :       3908 :         cpl.u.bs_basic.cb_arg = cb_arg;
                   +  - ]
    5679                 :            : 
    5680   [ +  -  +  -  :       3908 :         ctx->seq = bs_sequence_start_bs(bs->md_channel, &cpl);
             +  -  +  - ]
    5681   [ +  +  +  -  :       3908 :         if (!ctx->seq) {
                   +  - ]
    5682   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5683                 :          0 :                 free(ctx);
    5684   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5685                 :          0 :                 return;
    5686                 :            :         }
    5687                 :            : 
    5688                 :            :         /* Read super block */
    5689   [ +  -  +  -  :       3908 :         bs_sequence_read_dev(ctx->seq, ctx->super, bs_page_to_lba(bs, 0),
             +  -  +  - ]
    5690                 :       3908 :                              bs_byte_to_lba(bs, sizeof(*ctx->super)),
    5691                 :        626 :                              bs_unload_read_super_cpl, ctx);
    5692         [ -  + ]:        634 : }
    5693                 :            : 
    5694                 :            : /* END spdk_bs_unload */
    5695                 :            : 
    5696                 :            : /* START spdk_bs_set_super */
    5697                 :            : 
    5698                 :            : struct spdk_bs_set_super_ctx {
    5699                 :            :         struct spdk_blob_store          *bs;
    5700                 :            :         struct spdk_bs_super_block      *super;
    5701                 :            : };
    5702                 :            : 
    5703                 :            : static void
    5704                 :        227 : bs_set_super_write_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5705                 :            : {
    5706                 :        227 :         struct spdk_bs_set_super_ctx    *ctx = cb_arg;
    5707                 :            : 
    5708         [ +  + ]:        227 :         if (bserrno != 0) {
    5709                 :          0 :                 SPDK_ERRLOG("Unable to write to super block of blobstore\n");
    5710                 :          0 :         }
    5711                 :            : 
    5712   [ +  -  +  - ]:        227 :         spdk_free(ctx->super);
    5713                 :            : 
    5714                 :        227 :         bs_sequence_finish(seq, bserrno);
    5715                 :            : 
    5716                 :        227 :         free(ctx);
    5717                 :        227 : }
    5718                 :            : 
    5719                 :            : static void
    5720                 :        227 : bs_set_super_read_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5721                 :            : {
    5722                 :        227 :         struct spdk_bs_set_super_ctx    *ctx = cb_arg;
    5723                 :          8 :         int rc;
    5724                 :            : 
    5725         [ -  + ]:        227 :         if (bserrno != 0) {
    5726                 :          0 :                 SPDK_ERRLOG("Unable to read super block of blobstore\n");
    5727   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5728                 :          0 :                 bs_sequence_finish(seq, bserrno);
    5729                 :          0 :                 free(ctx);
    5730                 :          0 :                 return;
    5731                 :            :         }
    5732                 :            : 
    5733   [ +  -  +  -  :        227 :         rc = bs_super_validate(ctx->super, ctx->bs);
             +  -  +  - ]
    5734         [ -  + ]:        227 :         if (rc != 0) {
    5735                 :          0 :                 SPDK_ERRLOG("Not a valid super block\n");
    5736   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5737                 :          0 :                 bs_sequence_finish(seq, rc);
    5738                 :          0 :                 free(ctx);
    5739                 :          0 :                 return;
    5740                 :            :         }
    5741                 :            : 
    5742   [ +  -  +  -  :        227 :         bs_write_super(seq, ctx->bs, ctx->super, bs_set_super_write_cpl, ctx);
             +  -  +  - ]
    5743         [ -  + ]:          8 : }
    5744                 :            : 
    5745                 :            : void
    5746                 :        227 : spdk_bs_set_super(struct spdk_blob_store *bs, spdk_blob_id blobid,
    5747                 :            :                   spdk_bs_op_complete cb_fn, void *cb_arg)
    5748                 :            : {
    5749                 :        147 :         struct spdk_bs_cpl              cpl;
    5750                 :          8 :         spdk_bs_sequence_t              *seq;
    5751                 :          8 :         struct spdk_bs_set_super_ctx    *ctx;
    5752                 :            : 
    5753   [ +  +  +  +  :        227 :         SPDK_DEBUGLOG(blob, "Setting super blob id on blobstore\n");
                   +  - ]
    5754                 :            : 
    5755                 :        227 :         ctx = calloc(1, sizeof(*ctx));
    5756         [ +  + ]:        227 :         if (!ctx) {
    5757   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5758                 :          0 :                 return;
    5759                 :            :         }
    5760                 :            : 
    5761   [ +  -  +  - ]:        227 :         ctx->bs = bs;
    5762                 :            : 
    5763   [ +  -  +  - ]:        227 :         ctx->super = spdk_zmalloc(sizeof(*ctx->super), 0x1000, NULL,
    5764                 :            :                                   SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    5765   [ +  +  +  -  :        227 :         if (!ctx->super) {
                   +  - ]
    5766                 :          0 :                 free(ctx);
    5767   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5768                 :          0 :                 return;
    5769                 :            :         }
    5770                 :            : 
    5771                 :        227 :         cpl.type = SPDK_BS_CPL_TYPE_BS_BASIC;
    5772   [ +  -  +  -  :        227 :         cpl.u.bs_basic.cb_fn = cb_fn;
                   +  - ]
    5773   [ +  -  +  -  :        227 :         cpl.u.bs_basic.cb_arg = cb_arg;
                   +  - ]
    5774                 :            : 
    5775   [ +  -  +  - ]:        227 :         seq = bs_sequence_start_bs(bs->md_channel, &cpl);
    5776         [ +  + ]:        227 :         if (!seq) {
    5777   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    5778                 :          0 :                 free(ctx);
    5779   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    5780                 :          0 :                 return;
    5781                 :            :         }
    5782                 :            : 
    5783   [ +  -  +  - ]:        227 :         bs->super_blob = blobid;
    5784                 :            : 
    5785                 :            :         /* Read super block */
    5786   [ +  -  +  - ]:        227 :         bs_sequence_read_dev(seq, ctx->super, bs_page_to_lba(bs, 0),
    5787                 :        227 :                              bs_byte_to_lba(bs, sizeof(*ctx->super)),
    5788                 :          8 :                              bs_set_super_read_cpl, ctx);
    5789         [ -  + ]:          8 : }
    5790                 :            : 
    5791                 :            : /* END spdk_bs_set_super */
    5792                 :            : 
    5793                 :            : void
    5794                 :        137 : spdk_bs_get_super(struct spdk_blob_store *bs,
    5795                 :            :                   spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
    5796                 :            : {
    5797   [ +  +  +  -  :        137 :         if (bs->super_blob == SPDK_BLOBID_INVALID) {
                   +  + ]
    5798   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, SPDK_BLOBID_INVALID, -ENOENT);
    5799                 :          4 :         } else {
    5800   [ -  +  +  -  :        113 :                 cb_fn(cb_arg, bs->super_blob, 0);
             +  -  +  - ]
    5801                 :            :         }
    5802                 :        137 : }
    5803                 :            : 
    5804                 :            : uint64_t
    5805                 :       2407 : spdk_bs_get_cluster_size(struct spdk_blob_store *bs)
    5806                 :            : {
    5807   [ +  -  +  - ]:       2407 :         return bs->cluster_sz;
    5808                 :            : }
    5809                 :            : 
    5810                 :            : uint64_t
    5811                 :        371 : spdk_bs_get_page_size(struct spdk_blob_store *bs)
    5812                 :            : {
    5813                 :        371 :         return SPDK_BS_PAGE_SIZE;
    5814                 :            : }
    5815                 :            : 
    5816                 :            : uint64_t
    5817                 :    5791596 : spdk_bs_get_io_unit_size(struct spdk_blob_store *bs)
    5818                 :            : {
    5819   [ +  -  +  - ]:    5791596 :         return bs->io_unit_size;
    5820                 :            : }
    5821                 :            : 
    5822                 :            : uint64_t
    5823                 :       2486 : spdk_bs_free_cluster_count(struct spdk_blob_store *bs)
    5824                 :            : {
    5825   [ +  -  +  - ]:       2486 :         return bs->num_free_clusters;
    5826                 :            : }
    5827                 :            : 
    5828                 :            : uint64_t
    5829                 :        755 : spdk_bs_total_data_cluster_count(struct spdk_blob_store *bs)
    5830                 :            : {
    5831   [ +  -  +  - ]:        755 :         return bs->total_data_clusters;
    5832                 :            : }
    5833                 :            : 
    5834                 :            : static int
    5835                 :      10055 : bs_register_md_thread(struct spdk_blob_store *bs)
    5836                 :            : {
    5837   [ +  -  +  - ]:      10055 :         bs->md_channel = spdk_get_io_channel(bs);
    5838   [ +  +  +  -  :      10055 :         if (!bs->md_channel) {
                   +  - ]
    5839                 :          0 :                 SPDK_ERRLOG("Failed to get IO channel.\n");
    5840                 :          0 :                 return -1;
    5841                 :            :         }
    5842                 :            : 
    5843                 :      10055 :         return 0;
    5844                 :        797 : }
    5845                 :            : 
    5846                 :            : static int
    5847                 :      10055 : bs_unregister_md_thread(struct spdk_blob_store *bs)
    5848                 :            : {
    5849   [ +  -  +  - ]:      10055 :         spdk_put_io_channel(bs->md_channel);
    5850                 :            : 
    5851                 :      10055 :         return 0;
    5852                 :            : }
    5853                 :            : 
    5854                 :            : spdk_blob_id
    5855                 :       9119 : spdk_blob_get_id(struct spdk_blob *blob)
    5856                 :            : {
    5857   [ +  +  #  # ]:       9119 :         assert(blob != NULL);
    5858                 :            : 
    5859   [ +  -  +  - ]:       9119 :         return blob->id;
    5860                 :            : }
    5861                 :            : 
    5862                 :            : uint64_t
    5863                 :        177 : spdk_blob_get_num_pages(struct spdk_blob *blob)
    5864                 :            : {
    5865   [ +  +  #  # ]:        177 :         assert(blob != NULL);
    5866                 :            : 
    5867   [ +  -  +  -  :        177 :         return bs_cluster_to_page(blob->bs, blob->active.num_clusters);
          +  -  +  -  +  
                      - ]
    5868                 :            : }
    5869                 :            : 
    5870                 :            : uint64_t
    5871                 :        176 : spdk_blob_get_num_io_units(struct spdk_blob *blob)
    5872                 :            : {
    5873   [ +  +  #  # ]:        176 :         assert(blob != NULL);
    5874                 :            : 
    5875   [ +  -  +  - ]:        176 :         return spdk_blob_get_num_pages(blob) * bs_io_unit_per_page(blob->bs);
    5876                 :            : }
    5877                 :            : 
    5878                 :            : uint64_t
    5879                 :     986968 : spdk_blob_get_num_clusters(struct spdk_blob *blob)
    5880                 :            : {
    5881   [ +  +  #  # ]:     986968 :         assert(blob != NULL);
    5882                 :            : 
    5883   [ +  -  +  -  :     986968 :         return blob->active.num_clusters;
                   +  - ]
    5884                 :            : }
    5885                 :            : 
    5886                 :            : static uint64_t
    5887                 :        174 : blob_find_io_unit(struct spdk_blob *blob, uint64_t offset, bool is_allocated)
    5888                 :            : {
    5889                 :        174 :         uint64_t blob_io_unit_num = spdk_blob_get_num_io_units(blob);
    5890                 :            : 
    5891         [ +  + ]:        339 :         while (offset < blob_io_unit_num) {
    5892   [ +  +  +  + ]:        310 :                 if (bs_io_unit_is_allocated(blob, offset) == is_allocated) {
    5893                 :        145 :                         return offset;
    5894                 :            :                 }
    5895                 :            : 
    5896                 :        165 :                 offset += bs_num_io_units_to_cluster_boundary(blob, offset);
    5897                 :            :         }
    5898                 :            : 
    5899                 :         29 :         return UINT64_MAX;
    5900                 :         24 : }
    5901                 :            : 
    5902                 :            : uint64_t
    5903                 :         87 : spdk_blob_get_next_allocated_io_unit(struct spdk_blob *blob, uint64_t offset)
    5904                 :            : {
    5905                 :         87 :         return blob_find_io_unit(blob, offset, true);
    5906                 :            : }
    5907                 :            : 
    5908                 :            : uint64_t
    5909                 :         87 : spdk_blob_get_next_unallocated_io_unit(struct spdk_blob *blob, uint64_t offset)
    5910                 :            : {
    5911                 :         87 :         return blob_find_io_unit(blob, offset, false);
    5912                 :            : }
    5913                 :            : 
    5914                 :            : /* START spdk_bs_create_blob */
    5915                 :            : 
    5916                 :            : static void
    5917                 :      13913 : bs_create_blob_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    5918                 :            : {
    5919                 :      13913 :         struct spdk_blob *blob = cb_arg;
    5920   [ +  -  +  - ]:      13913 :         uint32_t page_idx = bs_blobid_to_page(blob->id);
    5921                 :            : 
    5922         [ -  + ]:      13913 :         if (bserrno != 0) {
    5923   [ #  #  #  #  :          0 :                 spdk_spin_lock(&blob->bs->used_lock);
                   #  # ]
    5924   [ #  #  #  #  :          0 :                 spdk_bit_array_clear(blob->bs->used_blobids, page_idx);
             #  #  #  # ]
    5925   [ #  #  #  # ]:          0 :                 bs_release_md_page(blob->bs, page_idx);
    5926   [ #  #  #  #  :          0 :                 spdk_spin_unlock(&blob->bs->used_lock);
                   #  # ]
    5927                 :          0 :         }
    5928                 :            : 
    5929                 :      13913 :         blob_free(blob);
    5930                 :            : 
    5931                 :      13913 :         bs_sequence_finish(seq, bserrno);
    5932                 :      13913 : }
    5933                 :            : 
    5934                 :            : static int
    5935                 :      27950 : blob_set_xattrs(struct spdk_blob *blob, const struct spdk_blob_xattr_opts *xattrs,
    5936                 :            :                 bool internal)
    5937                 :            : {
    5938                 :       3592 :         uint64_t i;
    5939                 :      27950 :         size_t value_len = 0;
    5940                 :       3592 :         int rc;
    5941                 :      27950 :         const void *value = NULL;
    5942   [ +  +  +  +  :      27950 :         if (xattrs->count > 0 && xattrs->get_value == NULL) {
          +  +  +  -  +  
                -  +  + ]
    5943                 :         48 :                 return -EINVAL;
    5944                 :            :         }
    5945   [ +  +  +  -  :      30645 :         for (i = 0; i < xattrs->count; i++) {
                   +  + ]
    5946   [ +  -  +  -  :       2767 :                 xattrs->get_value(xattrs->ctx, xattrs->names[i], &value, &value_len);
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    5947   [ +  +  -  + ]:       2767 :                 if (value == NULL || value_len == 0) {
    5948                 :         24 :                         return -EINVAL;
    5949                 :            :                 }
    5950   [ +  -  +  -  :       2743 :                 rc = blob_set_xattr(blob, xattrs->names[i], value, value_len, internal);
          +  -  +  -  +  
                      - ]
    5951         [ +  + ]:       2743 :                 if (rc < 0) {
    5952                 :          0 :                         return rc;
    5953                 :            :                 }
    5954                 :        280 :         }
    5955                 :      27878 :         return 0;
    5956                 :       3592 : }
    5957                 :            : 
    5958                 :            : static void
    5959                 :      11127 : blob_opts_copy(const struct spdk_blob_opts *src, struct spdk_blob_opts *dst)
    5960                 :            : {
    5961                 :            : #define FIELD_OK(field) \
    5962                 :            :         offsetof(struct spdk_blob_opts, field) + sizeof(src->field) <= src->opts_size
    5963                 :            : 
    5964                 :            : #define SET_FIELD(field) \
    5965                 :            :         if (FIELD_OK(field)) { \
    5966                 :            :                 dst->field = src->field; \
    5967                 :            :         } \
    5968                 :            : 
    5969   [ +  -  +  -  :      11127 :         SET_FIELD(num_clusters);
          -  +  +  -  +  
             -  +  -  +  
                      - ]
    5970   [ +  -  +  +  :      11127 :         SET_FIELD(thin_provision);
          -  +  +  -  +  
          -  +  -  +  -  
                   +  - ]
    5971   [ +  -  +  -  :      11127 :         SET_FIELD(clear_method);
          -  +  +  -  +  
             -  +  -  +  
                      - ]
    5972                 :            : 
    5973   [ +  -  +  -  :      11127 :         if (FIELD_OK(xattrs)) {
                   -  + ]
    5974   [ +  +  +  +  :      11127 :                 memcpy(&dst->xattrs, &src->xattrs, sizeof(src->xattrs));
             +  -  +  - ]
    5975                 :       1770 :         }
    5976                 :            : 
    5977   [ +  -  +  +  :      11127 :         SET_FIELD(use_extent_table);
          -  +  +  -  +  
          -  +  -  +  -  
                   +  - ]
    5978   [ +  -  +  -  :      11127 :         SET_FIELD(esnap_id);
          -  +  +  -  +  
             -  +  -  +  
                      - ]
    5979   [ +  -  +  -  :      11127 :         SET_FIELD(esnap_id_len);
          -  +  +  -  +  
             -  +  -  +  
                      - ]
    5980                 :            : 
    5981   [ +  -  +  -  :      11127 :         dst->opts_size = src->opts_size;
             +  -  +  - ]
    5982                 :            : 
    5983                 :            :         /* You should not remove this statement, but need to update the assert statement
    5984                 :            :          * if you add a new field, and also add a corresponding SET_FIELD statement */
    5985                 :            :         SPDK_STATIC_ASSERT(sizeof(struct spdk_blob_opts) == 80, "Incorrect size");
    5986                 :            : 
    5987                 :            : #undef FIELD_OK
    5988                 :            : #undef SET_FIELD
    5989                 :      11127 : }
    5990                 :            : 
    5991                 :            : static void
    5992                 :      14011 : bs_create_blob(struct spdk_blob_store *bs,
    5993                 :            :                const struct spdk_blob_opts *opts,
    5994                 :            :                const struct spdk_blob_xattr_opts *internal_xattrs,
    5995                 :            :                spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
    5996                 :            : {
    5997                 :       1802 :         struct spdk_blob        *blob;
    5998                 :       1802 :         uint32_t                page_idx;
    5999                 :      11816 :         struct spdk_bs_cpl      cpl;
    6000                 :      11816 :         struct spdk_blob_opts   opts_local;
    6001                 :      11816 :         struct spdk_blob_xattr_opts internal_xattrs_default;
    6002                 :       1802 :         spdk_bs_sequence_t      *seq;
    6003                 :       1802 :         spdk_blob_id            id;
    6004                 :       1802 :         int rc;
    6005                 :            : 
    6006   [ +  +  +  -  :      14011 :         assert(spdk_get_thread() == bs->md_thread);
             +  -  #  # ]
    6007                 :            : 
    6008         [ +  - ]:      14011 :         spdk_spin_lock(&bs->used_lock);
    6009   [ +  -  +  - ]:      14011 :         page_idx = spdk_bit_array_find_first_clear(bs->used_md_pages, 0);
    6010         [ +  + ]:      14011 :         if (page_idx == UINT32_MAX) {
    6011         [ #  # ]:          0 :                 spdk_spin_unlock(&bs->used_lock);
    6012   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, 0, -ENOMEM);
    6013                 :       2179 :                 return;
    6014                 :            :         }
    6015   [ +  -  +  - ]:      14011 :         spdk_bit_array_set(bs->used_blobids, page_idx);
    6016                 :      14011 :         bs_claim_md_page(bs, page_idx);
    6017         [ +  - ]:      14011 :         spdk_spin_unlock(&bs->used_lock);
    6018                 :            : 
    6019                 :      14011 :         id = bs_page_to_blobid(page_idx);
    6020                 :            : 
    6021   [ +  +  +  +  :      14011 :         SPDK_DEBUGLOG(blob, "Creating blob with id 0x%" PRIx64 " at page %u\n", id, page_idx);
                   +  - ]
    6022                 :            : 
    6023                 :      14011 :         spdk_blob_opts_init(&opts_local, sizeof(opts_local));
    6024         [ +  + ]:      14011 :         if (opts) {
    6025                 :      11127 :                 blob_opts_copy(opts, &opts_local);
    6026                 :       1770 :         }
    6027                 :            : 
    6028                 :      14011 :         blob = blob_alloc(bs, id);
    6029         [ +  + ]:      14011 :         if (!blob) {
    6030                 :          0 :                 rc = -ENOMEM;
    6031                 :          0 :                 goto error;
    6032                 :            :         }
    6033                 :            : 
    6034   [ +  +  +  -  :      14011 :         blob->use_extent_table = opts_local.use_extent_table;
             +  -  +  - ]
    6035   [ +  +  +  +  :      14011 :         if (blob->use_extent_table) {
             +  -  +  + ]
    6036   [ +  -  +  -  :       8731 :                 blob->invalid_flags |= SPDK_BLOB_EXTENT_TABLE;
                   +  - ]
    6037                 :        922 :         }
    6038                 :            : 
    6039         [ +  + ]:      14011 :         if (!internal_xattrs) {
    6040                 :      12546 :                 blob_xattrs_init(&internal_xattrs_default);
    6041                 :      12546 :                 internal_xattrs = &internal_xattrs_default;
    6042                 :       1566 :         }
    6043                 :            : 
    6044                 :      14011 :         rc = blob_set_xattrs(blob, &opts_local.xattrs, false);
    6045         [ +  + ]:      14011 :         if (rc < 0) {
    6046                 :         72 :                 goto error;
    6047                 :            :         }
    6048                 :            : 
    6049                 :      13939 :         rc = blob_set_xattrs(blob, internal_xattrs, true);
    6050         [ +  + ]:      13939 :         if (rc < 0) {
    6051                 :          0 :                 goto error;
    6052                 :            :         }
    6053                 :            : 
    6054   [ +  +  +  +  :      13939 :         if (opts_local.thin_provision) {
                   +  + ]
    6055                 :       1874 :                 blob_set_thin_provision(blob);
    6056                 :        296 :         }
    6057                 :            : 
    6058         [ +  - ]:      13939 :         blob_set_clear_method(blob, opts_local.clear_method);
    6059                 :            : 
    6060   [ +  +  +  + ]:      13939 :         if (opts_local.esnap_id != NULL) {
    6061   [ +  +  -  + ]:        296 :                 if (opts_local.esnap_id_len > UINT16_MAX) {
    6062         [ #  # ]:          0 :                         SPDK_ERRLOG("esnap id length %" PRIu64 "is too long\n",
    6063                 :            :                                     opts_local.esnap_id_len);
    6064                 :          0 :                         rc = -EINVAL;
    6065                 :          0 :                         goto error;
    6066                 :            : 
    6067                 :            :                 }
    6068                 :        296 :                 blob_set_thin_provision(blob);
    6069   [ +  -  +  -  :        296 :                 blob->invalid_flags |= SPDK_BLOB_EXTERNAL_SNAPSHOT;
                   +  - ]
    6070                 :        344 :                 rc = blob_set_xattr(blob, BLOB_EXTERNAL_SNAPSHOT_ID,
    6071   [ +  -  +  - ]:        296 :                                     opts_local.esnap_id, opts_local.esnap_id_len, true);
    6072         [ -  + ]:        296 :                 if (rc != 0) {
    6073                 :          0 :                         goto error;
    6074                 :            :                 }
    6075                 :         48 :         }
    6076                 :            : 
    6077                 :      13939 :         rc = blob_resize(blob, opts_local.num_clusters);
    6078         [ +  + ]:      13939 :         if (rc < 0) {
    6079                 :         26 :                 goto error;
    6080                 :            :         }
    6081                 :      13913 :         cpl.type = SPDK_BS_CPL_TYPE_BLOBID;
    6082   [ +  -  +  -  :      13913 :         cpl.u.blobid.cb_fn = cb_fn;
                   +  - ]
    6083   [ +  -  +  -  :      13913 :         cpl.u.blobid.cb_arg = cb_arg;
                   +  - ]
    6084   [ +  -  +  -  :      13913 :         cpl.u.blobid.blobid = blob->id;
          +  -  +  -  +  
                      - ]
    6085                 :            : 
    6086   [ +  -  +  - ]:      13913 :         seq = bs_sequence_start_bs(bs->md_channel, &cpl);
    6087         [ +  + ]:      13913 :         if (!seq) {
    6088                 :          0 :                 rc = -ENOMEM;
    6089                 :          0 :                 goto error;
    6090                 :            :         }
    6091                 :            : 
    6092                 :      13913 :         blob_persist(seq, blob, bs_create_blob_cpl, blob);
    6093                 :      13913 :         return;
    6094                 :            : 
    6095                 :         82 : error:
    6096                 :         98 :         SPDK_ERRLOG("Failed to create blob: %s, size in clusters/size: %lu (clusters)\n",
    6097                 :            :                     spdk_strerror(rc), opts_local.num_clusters);
    6098         [ +  + ]:         98 :         if (blob != NULL) {
    6099                 :         98 :                 blob_free(blob);
    6100                 :         16 :         }
    6101         [ +  - ]:         98 :         spdk_spin_lock(&bs->used_lock);
    6102   [ +  -  +  - ]:         98 :         spdk_bit_array_clear(bs->used_blobids, page_idx);
    6103                 :         98 :         bs_release_md_page(bs, page_idx);
    6104         [ +  - ]:         98 :         spdk_spin_unlock(&bs->used_lock);
    6105   [ -  +  +  - ]:         98 :         cb_fn(cb_arg, 0, rc);
    6106         [ -  + ]:       1802 : }
    6107                 :            : 
    6108                 :            : void
    6109                 :       2788 : spdk_bs_create_blob(struct spdk_blob_store *bs,
    6110                 :            :                     spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
    6111                 :            : {
    6112                 :       2788 :         bs_create_blob(bs, NULL, NULL, cb_fn, cb_arg);
    6113                 :       2788 : }
    6114                 :            : 
    6115                 :            : void
    6116                 :       9710 : spdk_bs_create_blob_ext(struct spdk_blob_store *bs, const struct spdk_blob_opts *opts,
    6117                 :            :                         spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
    6118                 :            : {
    6119                 :       9710 :         bs_create_blob(bs, opts, NULL, cb_fn, cb_arg);
    6120                 :       9710 : }
    6121                 :            : 
    6122                 :            : /* END spdk_bs_create_blob */
    6123                 :            : 
    6124                 :            : /* START blob_cleanup */
    6125                 :            : 
    6126                 :            : struct spdk_clone_snapshot_ctx {
    6127                 :            :         struct spdk_bs_cpl      cpl;
    6128                 :            :         int bserrno;
    6129                 :            :         bool frozen;
    6130                 :            : 
    6131                 :            :         struct spdk_io_channel *channel;
    6132                 :            : 
    6133                 :            :         /* Current cluster for inflate operation */
    6134                 :            :         uint64_t cluster;
    6135                 :            : 
    6136                 :            :         /* For inflation force allocation of all unallocated clusters and remove
    6137                 :            :          * thin-provisioning. Otherwise only decouple parent and keep clone thin. */
    6138                 :            :         bool allocate_all;
    6139                 :            : 
    6140                 :            :         struct {
    6141                 :            :                 spdk_blob_id id;
    6142                 :            :                 struct spdk_blob *blob;
    6143                 :            :                 bool md_ro;
    6144                 :            :         } original;
    6145                 :            :         struct {
    6146                 :            :                 spdk_blob_id id;
    6147                 :            :                 struct spdk_blob *blob;
    6148                 :            :         } new;
    6149                 :            : 
    6150                 :            :         /* xattrs specified for snapshot/clones only. They have no impact on
    6151                 :            :          * the original blobs xattrs. */
    6152                 :            :         const struct spdk_blob_xattr_opts *xattrs;
    6153                 :            : };
    6154                 :            : 
    6155                 :            : static void
    6156                 :       1872 : bs_clone_snapshot_cleanup_finish(void *cb_arg, int bserrno)
    6157                 :            : {
    6158                 :       1872 :         struct spdk_clone_snapshot_ctx *ctx = cb_arg;
    6159         [ +  - ]:       1872 :         struct spdk_bs_cpl *cpl = &ctx->cpl;
    6160                 :            : 
    6161         [ +  + ]:       1872 :         if (bserrno != 0) {
    6162   [ +  +  +  -  :         36 :                 if (ctx->bserrno != 0) {
                   -  + ]
    6163                 :          0 :                         SPDK_ERRLOG("Cleanup error %d\n", bserrno);
    6164                 :          0 :                 } else {
    6165   [ +  -  +  - ]:         36 :                         ctx->bserrno = bserrno;
    6166                 :            :                 }
    6167                 :          6 :         }
    6168                 :            : 
    6169   [ +  +  +  -  :       1872 :         switch (cpl->type) {
                -  +  + ]
    6170                 :       1282 :         case SPDK_BS_CPL_TYPE_BLOBID:
    6171   [ +  -  +  -  :       1528 :                 cpl->u.blobid.cb_fn(cpl->u.blobid.cb_arg, cpl->u.blobid.blobid, ctx->bserrno);
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    6172                 :       1528 :                 break;
    6173                 :        288 :         case SPDK_BS_CPL_TYPE_BLOB_BASIC:
    6174   [ +  -  +  -  :        344 :                 cpl->u.blob_basic.cb_fn(cpl->u.blob_basic.cb_arg, ctx->bserrno);
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    6175                 :        344 :                 break;
    6176                 :          0 :         default:
    6177         [ #  # ]:          0 :                 SPDK_UNREACHABLE();
    6178                 :            :                 break;
    6179                 :            :         }
    6180                 :            : 
    6181                 :       1872 :         free(ctx);
    6182                 :       1872 : }
    6183                 :            : 
    6184                 :            : static void
    6185                 :       1785 : bs_snapshot_unfreeze_cpl(void *cb_arg, int bserrno)
    6186                 :            : {
    6187                 :       1785 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6188   [ +  -  +  -  :       1785 :         struct spdk_blob *origblob = ctx->original.blob;
                   +  - ]
    6189                 :            : 
    6190         [ +  + ]:       1785 :         if (bserrno != 0) {
    6191   [ #  #  #  #  :          0 :                 if (ctx->bserrno != 0) {
                   #  # ]
    6192                 :          0 :                         SPDK_ERRLOG("Unfreeze error %d\n", bserrno);
    6193                 :          0 :                 } else {
    6194   [ #  #  #  # ]:          0 :                         ctx->bserrno = bserrno;
    6195                 :            :                 }
    6196                 :          0 :         }
    6197                 :            : 
    6198   [ +  -  +  -  :       1785 :         ctx->original.id = origblob->id;
          +  -  +  -  +  
                      - ]
    6199   [ +  -  +  - ]:       1785 :         origblob->locked_operation_in_progress = false;
    6200                 :            : 
    6201                 :            :         /* Revert md_ro to original state */
    6202   [ +  +  +  -  :       1785 :         origblob->md_ro = ctx->original.md_ro;
          +  -  +  -  +  
                -  +  - ]
    6203                 :            : 
    6204                 :       1785 :         spdk_blob_close(origblob, bs_clone_snapshot_cleanup_finish, ctx);
    6205                 :       1785 : }
    6206                 :            : 
    6207                 :            : static void
    6208                 :       1785 : bs_clone_snapshot_origblob_cleanup(void *cb_arg, int bserrno)
    6209                 :            : {
    6210                 :       1785 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6211   [ +  -  +  -  :       1785 :         struct spdk_blob *origblob = ctx->original.blob;
                   +  - ]
    6212                 :            : 
    6213         [ +  + ]:       1785 :         if (bserrno != 0) {
    6214   [ +  +  +  -  :        145 :                 if (ctx->bserrno != 0) {
                   +  + ]
    6215                 :         24 :                         SPDK_ERRLOG("Cleanup error %d\n", bserrno);
    6216                 :          4 :                 } else {
    6217   [ +  -  +  - ]:        121 :                         ctx->bserrno = bserrno;
    6218                 :            :                 }
    6219                 :         24 :         }
    6220                 :            : 
    6221   [ +  +  +  +  :       1785 :         if (ctx->frozen) {
             +  -  +  + ]
    6222                 :            :                 /* Unfreeze any outstanding I/O */
    6223                 :       1109 :                 blob_unfreeze_io(origblob, bs_snapshot_unfreeze_cpl, ctx);
    6224                 :        180 :         } else {
    6225                 :        676 :                 bs_snapshot_unfreeze_cpl(ctx, 0);
    6226                 :            :         }
    6227                 :            : 
    6228                 :       1785 : }
    6229                 :            : 
    6230                 :            : static void
    6231                 :         24 : bs_clone_snapshot_newblob_cleanup(struct spdk_clone_snapshot_ctx *ctx, int bserrno)
    6232                 :            : {
    6233   [ +  -  +  -  :         24 :         struct spdk_blob *newblob = ctx->new.blob;
                   +  - ]
    6234                 :            : 
    6235         [ +  + ]:         24 :         if (bserrno != 0) {
    6236   [ +  +  +  -  :         24 :                 if (ctx->bserrno != 0) {
                   +  - ]
    6237                 :          0 :                         SPDK_ERRLOG("Cleanup error %d\n", bserrno);
    6238                 :          0 :                 } else {
    6239   [ +  -  +  - ]:         24 :                         ctx->bserrno = bserrno;
    6240                 :            :                 }
    6241                 :          4 :         }
    6242                 :            : 
    6243   [ +  -  +  -  :         24 :         ctx->new.id = newblob->id;
          +  -  +  -  +  
                      - ]
    6244                 :         24 :         spdk_blob_close(newblob, bs_clone_snapshot_origblob_cleanup, ctx);
    6245                 :         24 : }
    6246                 :            : 
    6247                 :            : /* END blob_cleanup */
    6248                 :            : 
    6249                 :            : /* START spdk_bs_create_snapshot */
    6250                 :            : 
    6251                 :            : static void
    6252                 :       1157 : bs_snapshot_swap_cluster_maps(struct spdk_blob *blob1, struct spdk_blob *blob2)
    6253                 :            : {
    6254                 :        188 :         uint64_t *cluster_temp;
    6255                 :        188 :         uint32_t *extent_page_temp;
    6256                 :            : 
    6257   [ +  -  +  -  :       1157 :         cluster_temp = blob1->active.clusters;
                   +  - ]
    6258   [ +  -  +  -  :       1157 :         blob1->active.clusters = blob2->active.clusters;
          +  -  +  -  +  
                -  +  - ]
    6259   [ +  -  +  -  :       1157 :         blob2->active.clusters = cluster_temp;
                   +  - ]
    6260                 :            : 
    6261   [ +  -  +  -  :       1157 :         extent_page_temp = blob1->active.extent_pages;
                   +  - ]
    6262   [ +  -  +  -  :       1157 :         blob1->active.extent_pages = blob2->active.extent_pages;
          +  -  +  -  +  
                -  +  - ]
    6263   [ +  -  +  -  :       1157 :         blob2->active.extent_pages = extent_page_temp;
                   +  - ]
    6264                 :       1157 : }
    6265                 :            : 
    6266                 :            : /* Copies an internal xattr */
    6267                 :            : static int
    6268                 :        128 : bs_snapshot_copy_xattr(struct spdk_blob *toblob, struct spdk_blob *fromblob, const char *name)
    6269                 :            : {
    6270                 :        128 :         const void      *val = NULL;
    6271                 :        108 :         size_t          len;
    6272                 :         20 :         int             bserrno;
    6273                 :            : 
    6274                 :        128 :         bserrno = blob_get_xattr_value(fromblob, name, &val, &len, true);
    6275         [ -  + ]:        128 :         if (bserrno != 0) {
    6276   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 " missing %s XATTR\n", fromblob->id, name);
    6277                 :          0 :                 return bserrno;
    6278                 :            :         }
    6279                 :            : 
    6280                 :        128 :         bserrno = blob_set_xattr(toblob, name, val, len, true);
    6281         [ -  + ]:        128 :         if (bserrno != 0) {
    6282   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("could not set %s XATTR on blob 0x%" PRIx64 "\n",
    6283                 :            :                             name, toblob->id);
    6284                 :          0 :                 return bserrno;
    6285                 :            :         }
    6286                 :        128 :         return 0;
    6287                 :         20 : }
    6288                 :            : 
    6289                 :            : static void
    6290                 :       1085 : bs_snapshot_origblob_sync_cpl(void *cb_arg, int bserrno)
    6291                 :            : {
    6292                 :       1085 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6293   [ +  -  +  -  :       1085 :         struct spdk_blob *origblob = ctx->original.blob;
                   +  - ]
    6294   [ +  -  +  -  :       1085 :         struct spdk_blob *newblob = ctx->new.blob;
                   +  - ]
    6295                 :            : 
    6296         [ +  + ]:       1085 :         if (bserrno != 0) {
    6297                 :         24 :                 bs_snapshot_swap_cluster_maps(newblob, origblob);
    6298         [ +  + ]:         24 :                 if (blob_is_esnap_clone(newblob)) {
    6299                 :          0 :                         bs_snapshot_copy_xattr(origblob, newblob, BLOB_EXTERNAL_SNAPSHOT_ID);
    6300   [ #  #  #  #  :          0 :                         origblob->invalid_flags |= SPDK_BLOB_EXTERNAL_SNAPSHOT;
                   #  # ]
    6301                 :          0 :                 }
    6302                 :         24 :                 bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
    6303                 :         24 :                 return;
    6304                 :            :         }
    6305                 :            : 
    6306                 :            :         /* Remove metadata descriptor SNAPSHOT_IN_PROGRESS */
    6307                 :       1061 :         bserrno = blob_remove_xattr(newblob, SNAPSHOT_IN_PROGRESS, true);
    6308         [ -  + ]:       1061 :         if (bserrno != 0) {
    6309                 :          0 :                 bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
    6310                 :          0 :                 return;
    6311                 :            :         }
    6312                 :            : 
    6313   [ +  -  +  -  :       1061 :         bs_blob_list_add(ctx->original.blob);
                   +  - ]
    6314                 :            : 
    6315                 :       1061 :         spdk_blob_set_read_only(newblob);
    6316                 :            : 
    6317                 :            :         /* sync snapshot metadata */
    6318                 :       1061 :         spdk_blob_sync_md(newblob, bs_clone_snapshot_origblob_cleanup, ctx);
    6319         [ -  + ]:        176 : }
    6320                 :            : 
    6321                 :            : static void
    6322                 :       1109 : bs_snapshot_newblob_sync_cpl(void *cb_arg, int bserrno)
    6323                 :            : {
    6324                 :       1109 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6325   [ +  -  +  -  :       1109 :         struct spdk_blob *origblob = ctx->original.blob;
                   +  - ]
    6326   [ +  -  +  -  :       1109 :         struct spdk_blob *newblob = ctx->new.blob;
                   +  - ]
    6327                 :            : 
    6328         [ +  + ]:       1109 :         if (bserrno != 0) {
    6329                 :            :                 /* return cluster map back to original */
    6330                 :         24 :                 bs_snapshot_swap_cluster_maps(newblob, origblob);
    6331                 :            : 
    6332                 :            :                 /* Newblob md sync failed. Valid clusters are only present in origblob.
    6333                 :            :                  * Since I/O is frozen on origblob, not changes to zeroed out cluster map should have occurred.
    6334                 :            :                  * Newblob needs to be reverted to thin_provisioned state at creation to properly close. */
    6335                 :         24 :                 blob_set_thin_provision(newblob);
    6336   [ +  +  +  -  :         24 :                 assert(spdk_mem_all_zero(newblob->active.clusters,
          +  -  +  -  +  
          -  +  -  +  -  
                   #  # ]
    6337                 :            :                                          newblob->active.num_clusters * sizeof(*newblob->active.clusters)));
    6338   [ +  +  +  -  :         24 :                 assert(spdk_mem_all_zero(newblob->active.extent_pages,
          +  -  +  -  +  
          -  +  -  +  -  
                   #  # ]
    6339                 :            :                                          newblob->active.num_extent_pages * sizeof(*newblob->active.extent_pages)));
    6340                 :            : 
    6341                 :         24 :                 bs_clone_snapshot_newblob_cleanup(ctx, bserrno);
    6342                 :         24 :                 return;
    6343                 :            :         }
    6344                 :            : 
    6345                 :            :         /* Set internal xattr for snapshot id */
    6346         [ +  - ]:       1085 :         bserrno = blob_set_xattr(origblob, BLOB_SNAPSHOT, &newblob->id, sizeof(spdk_blob_id), true);
    6347         [ -  + ]:       1085 :         if (bserrno != 0) {
    6348                 :            :                 /* return cluster map back to original */
    6349                 :          0 :                 bs_snapshot_swap_cluster_maps(newblob, origblob);
    6350                 :          0 :                 blob_set_thin_provision(newblob);
    6351                 :          0 :                 bs_clone_snapshot_newblob_cleanup(ctx, bserrno);
    6352                 :          0 :                 return;
    6353                 :            :         }
    6354                 :            : 
    6355                 :            :         /* Create new back_bs_dev for snapshot */
    6356   [ +  -  +  - ]:       1085 :         origblob->back_bs_dev = bs_create_blob_bs_dev(newblob);
    6357   [ +  +  +  -  :       1085 :         if (origblob->back_bs_dev == NULL) {
                   +  - ]
    6358                 :            :                 /* return cluster map back to original */
    6359                 :          0 :                 bs_snapshot_swap_cluster_maps(newblob, origblob);
    6360                 :          0 :                 blob_set_thin_provision(newblob);
    6361                 :          0 :                 bs_clone_snapshot_newblob_cleanup(ctx, -EINVAL);
    6362                 :          0 :                 return;
    6363                 :            :         }
    6364                 :            : 
    6365                 :            :         /* Remove the xattr that references an external snapshot */
    6366         [ +  + ]:       1085 :         if (blob_is_esnap_clone(origblob)) {
    6367   [ +  -  +  -  :         76 :                 origblob->invalid_flags &= ~SPDK_BLOB_EXTERNAL_SNAPSHOT;
                   +  - ]
    6368                 :         76 :                 bserrno = blob_remove_xattr(origblob, BLOB_EXTERNAL_SNAPSHOT_ID, true);
    6369         [ -  + ]:         76 :                 if (bserrno != 0) {
    6370         [ #  # ]:          0 :                         if (bserrno == -ENOENT) {
    6371   [ #  #  #  # ]:          0 :                                 SPDK_ERRLOG("blob 0x%" PRIx64 " has no " BLOB_EXTERNAL_SNAPSHOT_ID
    6372                 :            :                                             " xattr to remove\n", origblob->id);
    6373         [ #  # ]:          0 :                                 assert(false);
    6374                 :            :                         } else {
    6375                 :            :                                 /* return cluster map back to original */
    6376                 :          0 :                                 bs_snapshot_swap_cluster_maps(newblob, origblob);
    6377                 :          0 :                                 blob_set_thin_provision(newblob);
    6378                 :          0 :                                 bs_clone_snapshot_newblob_cleanup(ctx, bserrno);
    6379                 :          0 :                                 return;
    6380                 :            :                         }
    6381                 :            :                 }
    6382                 :         12 :         }
    6383                 :            : 
    6384                 :       1085 :         bs_blob_list_remove(origblob);
    6385   [ +  -  +  -  :       1085 :         origblob->parent_id = newblob->id;
             +  -  +  - ]
    6386                 :            :         /* set clone blob as thin provisioned */
    6387                 :       1085 :         blob_set_thin_provision(origblob);
    6388                 :            : 
    6389                 :       1085 :         bs_blob_list_add(newblob);
    6390                 :            : 
    6391                 :            :         /* sync clone metadata */
    6392                 :       1085 :         spdk_blob_sync_md(origblob, bs_snapshot_origblob_sync_cpl, ctx);
    6393         [ -  + ]:        180 : }
    6394                 :            : 
    6395                 :            : static void
    6396                 :       1109 : bs_snapshot_freeze_cpl(void *cb_arg, int rc)
    6397                 :            : {
    6398                 :       1109 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6399   [ +  -  +  -  :       1109 :         struct spdk_blob *origblob = ctx->original.blob;
                   +  - ]
    6400   [ +  -  +  -  :       1109 :         struct spdk_blob *newblob = ctx->new.blob;
                   +  - ]
    6401                 :        180 :         int bserrno;
    6402                 :            : 
    6403         [ -  + ]:       1109 :         if (rc != 0) {
    6404                 :          0 :                 bs_clone_snapshot_newblob_cleanup(ctx, rc);
    6405                 :          0 :                 return;
    6406                 :            :         }
    6407                 :            : 
    6408   [ +  -  +  - ]:       1109 :         ctx->frozen = true;
    6409                 :            : 
    6410         [ +  + ]:       1109 :         if (blob_is_esnap_clone(origblob)) {
    6411                 :            :                 /* Clean up any channels associated with the original blob id because future IO will
    6412                 :            :                  * perform IO using the snapshot blob_id.
    6413                 :            :                  */
    6414                 :         76 :                 blob_esnap_destroy_bs_dev_channels(origblob, false, NULL, NULL);
    6415                 :         12 :         }
    6416   [ +  -  +  -  :       1109 :         if (newblob->back_bs_dev) {
                   -  + ]
    6417                 :       1109 :                 blob_back_bs_destroy(newblob);
    6418                 :        180 :         }
    6419                 :            :         /* set new back_bs_dev for snapshot */
    6420   [ +  -  +  -  :       1109 :         newblob->back_bs_dev = origblob->back_bs_dev;
             +  -  +  - ]
    6421                 :            :         /* Set invalid flags from origblob */
    6422   [ +  -  +  -  :       1109 :         newblob->invalid_flags = origblob->invalid_flags;
             +  -  +  - ]
    6423                 :            : 
    6424                 :            :         /* inherit parent from original blob if set */
    6425   [ +  -  +  -  :       1109 :         newblob->parent_id = origblob->parent_id;
             +  -  +  - ]
    6426   [ +  +  +  -  :       1109 :         switch (origblob->parent_id) {
                +  +  + ]
    6427                 :         64 :         case SPDK_BLOBID_EXTERNAL_SNAPSHOT:
    6428                 :         76 :                 bserrno = bs_snapshot_copy_xattr(newblob, origblob, BLOB_EXTERNAL_SNAPSHOT_ID);
    6429         [ -  + ]:         76 :                 if (bserrno != 0) {
    6430                 :          0 :                         bs_clone_snapshot_newblob_cleanup(ctx, bserrno);
    6431                 :          0 :                         return;
    6432                 :            :                 }
    6433                 :         76 :                 break;
    6434                 :        640 :         case SPDK_BLOBID_INVALID:
    6435                 :        764 :                 break;
    6436                 :        225 :         default:
    6437                 :            :                 /* Set internal xattr for snapshot id */
    6438                 :        269 :                 bserrno = blob_set_xattr(newblob, BLOB_SNAPSHOT,
    6439         [ +  - ]:        269 :                                          &origblob->parent_id, sizeof(spdk_blob_id), true);
    6440         [ -  + ]:        269 :                 if (bserrno != 0) {
    6441                 :          0 :                         bs_clone_snapshot_newblob_cleanup(ctx, bserrno);
    6442                 :          0 :                         return;
    6443                 :            :                 }
    6444                 :         44 :         }
    6445                 :            : 
    6446                 :            :         /* swap cluster maps */
    6447                 :       1109 :         bs_snapshot_swap_cluster_maps(newblob, origblob);
    6448                 :            : 
    6449                 :            :         /* Set the clear method on the new blob to match the original. */
    6450   [ +  -  +  - ]:       1109 :         blob_set_clear_method(newblob, origblob->clear_method);
    6451                 :            : 
    6452                 :            :         /* sync snapshot metadata */
    6453                 :       1109 :         spdk_blob_sync_md(newblob, bs_snapshot_newblob_sync_cpl, ctx);
    6454         [ -  + ]:        180 : }
    6455                 :            : 
    6456                 :            : static void
    6457                 :       1133 : bs_snapshot_newblob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bserrno)
    6458                 :            : {
    6459                 :       1133 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6460   [ +  -  +  -  :       1133 :         struct spdk_blob *origblob = ctx->original.blob;
                   +  - ]
    6461                 :       1133 :         struct spdk_blob *newblob = _blob;
    6462                 :            : 
    6463         [ +  + ]:       1133 :         if (bserrno != 0) {
    6464                 :         24 :                 bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
    6465                 :         24 :                 return;
    6466                 :            :         }
    6467                 :            : 
    6468   [ +  -  +  -  :       1109 :         ctx->new.blob = newblob;
                   +  - ]
    6469   [ +  +  #  # ]:       1109 :         assert(spdk_blob_is_thin_provisioned(newblob));
    6470   [ +  +  +  -  :       1109 :         assert(spdk_mem_all_zero(newblob->active.clusters,
          +  -  +  -  +  
          -  +  -  +  -  
                   #  # ]
    6471                 :            :                                  newblob->active.num_clusters * sizeof(*newblob->active.clusters)));
    6472   [ +  +  +  -  :       1109 :         assert(spdk_mem_all_zero(newblob->active.extent_pages,
          +  -  +  -  +  
          -  +  -  +  -  
                   #  # ]
    6473                 :            :                                  newblob->active.num_extent_pages * sizeof(*newblob->active.extent_pages)));
    6474                 :            : 
    6475                 :       1109 :         blob_freeze_io(origblob, bs_snapshot_freeze_cpl, ctx);
    6476         [ -  + ]:        184 : }
    6477                 :            : 
    6478                 :            : static void
    6479                 :       1157 : bs_snapshot_newblob_create_cpl(void *cb_arg, spdk_blob_id blobid, int bserrno)
    6480                 :            : {
    6481                 :       1157 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6482   [ +  -  +  -  :       1157 :         struct spdk_blob *origblob = ctx->original.blob;
                   +  - ]
    6483                 :            : 
    6484         [ +  + ]:       1157 :         if (bserrno != 0) {
    6485                 :         24 :                 bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
    6486                 :         24 :                 return;
    6487                 :            :         }
    6488                 :            : 
    6489   [ +  -  +  -  :       1133 :         ctx->new.id = blobid;
                   +  - ]
    6490   [ +  -  +  -  :       1133 :         ctx->cpl.u.blobid.blobid = blobid;
          +  -  +  -  +  
                      - ]
    6491                 :            : 
    6492   [ +  -  +  -  :       1133 :         spdk_bs_open_blob(origblob->bs, ctx->new.id, bs_snapshot_newblob_open_cpl, ctx);
          +  -  +  -  +  
                      - ]
    6493         [ -  + ]:        188 : }
    6494                 :            : 
    6495                 :            : 
    6496                 :            : static void
    6497                 :       1157 : bs_xattr_snapshot(void *arg, const char *name,
    6498                 :            :                   const void **value, size_t *value_len)
    6499                 :            : {
    6500   [ +  +  +  +  :       1157 :         assert(strncmp(name, SNAPSHOT_IN_PROGRESS, sizeof(SNAPSHOT_IN_PROGRESS)) == 0);
             +  -  #  # ]
    6501                 :            : 
    6502                 :       1157 :         struct spdk_blob *blob = (struct spdk_blob *)arg;
    6503   [ +  -  +  - ]:       1157 :         *value = &blob->id;
    6504         [ +  - ]:       1157 :         *value_len = sizeof(blob->id);
    6505                 :       1157 : }
    6506                 :            : 
    6507                 :            : static void
    6508                 :       1218 : bs_snapshot_origblob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bserrno)
    6509                 :            : {
    6510                 :       1218 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6511                 :       1015 :         struct spdk_blob_opts opts;
    6512                 :       1015 :         struct spdk_blob_xattr_opts internal_xattrs;
    6513                 :       1218 :         char *xattrs_names[] = { SNAPSHOT_IN_PROGRESS };
    6514                 :            : 
    6515         [ +  + ]:       1218 :         if (bserrno != 0) {
    6516                 :         36 :                 bs_clone_snapshot_cleanup_finish(ctx, bserrno);
    6517                 :         40 :                 return;
    6518                 :            :         }
    6519                 :            : 
    6520   [ +  -  +  -  :       1182 :         ctx->original.blob = _blob;
                   +  - ]
    6521                 :            : 
    6522   [ +  +  +  +  :       1182 :         if (_blob->data_ro || _blob->md_ro) {
          +  +  +  +  +  
          -  +  -  +  -  
                   -  + ]
    6523   [ +  +  +  +  :         25 :                 SPDK_DEBUGLOG(blob, "Cannot create snapshot from read only blob with id 0x%"
          +  -  #  #  #  
                      # ]
    6524                 :            :                               PRIx64 "\n", _blob->id);
    6525   [ +  -  +  - ]:         25 :                 ctx->bserrno = -EINVAL;
    6526                 :         25 :                 spdk_blob_close(_blob, bs_clone_snapshot_cleanup_finish, ctx);
    6527                 :         25 :                 return;
    6528                 :            :         }
    6529                 :            : 
    6530   [ +  +  +  +  :       1157 :         if (_blob->locked_operation_in_progress) {
             +  -  -  + ]
    6531   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob, "Cannot create snapshot - another operation in progress\n");
                   #  # ]
    6532   [ #  #  #  # ]:          0 :                 ctx->bserrno = -EBUSY;
    6533                 :          0 :                 spdk_blob_close(_blob, bs_clone_snapshot_cleanup_finish, ctx);
    6534                 :          0 :                 return;
    6535                 :            :         }
    6536                 :            : 
    6537   [ +  -  +  - ]:       1157 :         _blob->locked_operation_in_progress = true;
    6538                 :            : 
    6539                 :       1157 :         spdk_blob_opts_init(&opts, sizeof(opts));
    6540                 :       1157 :         blob_xattrs_init(&internal_xattrs);
    6541                 :            : 
    6542                 :            :         /* Change the size of new blob to the same as in original blob,
    6543                 :            :          * but do not allocate clusters */
    6544         [ +  - ]:       1157 :         opts.thin_provision = true;
    6545                 :       1157 :         opts.num_clusters = spdk_blob_get_num_clusters(_blob);
    6546   [ +  +  +  -  :       1157 :         opts.use_extent_table = _blob->use_extent_table;
             +  -  +  - ]
    6547                 :            : 
    6548                 :            :         /* If there are any xattrs specified for snapshot, set them now */
    6549   [ +  +  +  -  :       1157 :         if (ctx->xattrs) {
                   +  + ]
    6550   [ +  +  +  +  :         53 :                 memcpy(&opts.xattrs, ctx->xattrs, sizeof(*ctx->xattrs));
             +  -  +  - ]
    6551                 :          4 :         }
    6552                 :            :         /* Set internal xattr SNAPSHOT_IN_PROGRESS */
    6553                 :       1157 :         internal_xattrs.count = 1;
    6554         [ +  - ]:       1157 :         internal_xattrs.ctx = _blob;
    6555         [ +  - ]:       1157 :         internal_xattrs.names = xattrs_names;
    6556         [ +  - ]:       1157 :         internal_xattrs.get_value = bs_xattr_snapshot;
    6557                 :            : 
    6558   [ +  -  +  - ]:       1157 :         bs_create_blob(_blob->bs, &opts, &internal_xattrs,
    6559                 :        188 :                        bs_snapshot_newblob_create_cpl, ctx);
    6560         [ -  + ]:        198 : }
    6561                 :            : 
    6562                 :            : void
    6563                 :       1218 : spdk_bs_create_snapshot(struct spdk_blob_store *bs, spdk_blob_id blobid,
    6564                 :            :                         const struct spdk_blob_xattr_opts *snapshot_xattrs,
    6565                 :            :                         spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
    6566                 :            : {
    6567                 :       1218 :         struct spdk_clone_snapshot_ctx *ctx = calloc(1, sizeof(*ctx));
    6568                 :            : 
    6569         [ +  + ]:       1218 :         if (!ctx) {
    6570   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, SPDK_BLOBID_INVALID, -ENOMEM);
    6571                 :          0 :                 return;
    6572                 :            :         }
    6573   [ +  -  +  -  :       1218 :         ctx->cpl.type = SPDK_BS_CPL_TYPE_BLOBID;
                   +  - ]
    6574   [ +  -  +  -  :       1218 :         ctx->cpl.u.blobid.cb_fn = cb_fn;
          +  -  +  -  +  
                      - ]
    6575   [ +  -  +  -  :       1218 :         ctx->cpl.u.blobid.cb_arg = cb_arg;
          +  -  +  -  +  
                      - ]
    6576   [ +  -  +  -  :       1218 :         ctx->cpl.u.blobid.blobid = SPDK_BLOBID_INVALID;
          +  -  +  -  +  
                      - ]
    6577   [ +  -  +  - ]:       1218 :         ctx->bserrno = 0;
    6578   [ +  -  +  - ]:       1218 :         ctx->frozen = false;
    6579   [ +  -  +  -  :       1218 :         ctx->original.id = blobid;
                   +  - ]
    6580   [ +  -  +  - ]:       1218 :         ctx->xattrs = snapshot_xattrs;
    6581                 :            : 
    6582   [ +  -  +  -  :       1218 :         spdk_bs_open_blob(bs, ctx->original.id, bs_snapshot_origblob_open_cpl, ctx);
                   +  - ]
    6583         [ -  + ]:        198 : }
    6584                 :            : /* END spdk_bs_create_snapshot */
    6585                 :            : 
    6586                 :            : /* START spdk_bs_create_clone */
    6587                 :            : 
    6588                 :            : static void
    6589                 :        284 : bs_xattr_clone(void *arg, const char *name,
    6590                 :            :                const void **value, size_t *value_len)
    6591                 :            : {
    6592   [ +  +  +  +  :        284 :         assert(strncmp(name, BLOB_SNAPSHOT, sizeof(BLOB_SNAPSHOT)) == 0);
             +  -  #  # ]
    6593                 :            : 
    6594                 :        284 :         struct spdk_blob *blob = (struct spdk_blob *)arg;
    6595   [ +  -  +  - ]:        284 :         *value = &blob->id;
    6596         [ +  - ]:        284 :         *value_len = sizeof(blob->id);
    6597                 :        284 : }
    6598                 :            : 
    6599                 :            : static void
    6600                 :        284 : bs_clone_newblob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bserrno)
    6601                 :            : {
    6602                 :        284 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6603                 :        284 :         struct spdk_blob *clone = _blob;
    6604                 :            : 
    6605   [ +  -  +  -  :        284 :         ctx->new.blob = clone;
                   +  - ]
    6606                 :        284 :         bs_blob_list_add(clone);
    6607                 :            : 
    6608                 :        284 :         spdk_blob_close(clone, bs_clone_snapshot_origblob_cleanup, ctx);
    6609                 :        284 : }
    6610                 :            : 
    6611                 :            : static void
    6612                 :        284 : bs_clone_newblob_create_cpl(void *cb_arg, spdk_blob_id blobid, int bserrno)
    6613                 :            : {
    6614                 :        284 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6615                 :            : 
    6616   [ +  -  +  -  :        284 :         ctx->cpl.u.blobid.blobid = blobid;
          +  -  +  -  +  
                      - ]
    6617   [ +  -  +  -  :        284 :         spdk_bs_open_blob(ctx->original.blob->bs, blobid, bs_clone_newblob_open_cpl, ctx);
          +  -  +  -  +  
                      - ]
    6618                 :        284 : }
    6619                 :            : 
    6620                 :            : static void
    6621                 :        310 : bs_clone_origblob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bserrno)
    6622                 :            : {
    6623                 :        310 :         struct spdk_clone_snapshot_ctx  *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6624                 :        257 :         struct spdk_blob_opts           opts;
    6625                 :        257 :         struct spdk_blob_xattr_opts internal_xattrs;
    6626                 :        310 :         char *xattr_names[] = { BLOB_SNAPSHOT };
    6627                 :            : 
    6628         [ -  + ]:        310 :         if (bserrno != 0) {
    6629                 :          0 :                 bs_clone_snapshot_cleanup_finish(ctx, bserrno);
    6630                 :          4 :                 return;
    6631                 :            :         }
    6632                 :            : 
    6633   [ +  -  +  -  :        310 :         ctx->original.blob = _blob;
                   +  - ]
    6634   [ +  +  +  -  :        310 :         ctx->original.md_ro = _blob->md_ro;
          +  -  +  -  +  
                -  +  - ]
    6635                 :            : 
    6636   [ +  +  +  +  :        310 :         if (!_blob->data_ro || !_blob->md_ro) {
          +  +  +  +  +  
          -  +  -  +  -  
                   -  + ]
    6637   [ +  +  +  +  :         26 :                 SPDK_DEBUGLOG(blob, "Clone not from read-only blob\n");
                   +  - ]
    6638   [ +  -  +  - ]:         26 :                 ctx->bserrno = -EINVAL;
    6639                 :         26 :                 spdk_blob_close(_blob, bs_clone_snapshot_cleanup_finish, ctx);
    6640                 :         26 :                 return;
    6641                 :            :         }
    6642                 :            : 
    6643   [ +  +  +  +  :        284 :         if (_blob->locked_operation_in_progress) {
             +  -  -  + ]
    6644   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob, "Cannot create clone - another operation in progress\n");
                   #  # ]
    6645   [ #  #  #  # ]:          0 :                 ctx->bserrno = -EBUSY;
    6646                 :          0 :                 spdk_blob_close(_blob, bs_clone_snapshot_cleanup_finish, ctx);
    6647                 :          0 :                 return;
    6648                 :            :         }
    6649                 :            : 
    6650   [ +  -  +  - ]:        284 :         _blob->locked_operation_in_progress = true;
    6651                 :            : 
    6652                 :        284 :         spdk_blob_opts_init(&opts, sizeof(opts));
    6653                 :        284 :         blob_xattrs_init(&internal_xattrs);
    6654                 :            : 
    6655         [ +  - ]:        284 :         opts.thin_provision = true;
    6656                 :        284 :         opts.num_clusters = spdk_blob_get_num_clusters(_blob);
    6657   [ +  +  +  -  :        284 :         opts.use_extent_table = _blob->use_extent_table;
             +  -  +  - ]
    6658   [ +  +  +  -  :        284 :         if (ctx->xattrs) {
                   +  + ]
    6659   [ +  +  +  +  :         44 :                 memcpy(&opts.xattrs, ctx->xattrs, sizeof(*ctx->xattrs));
             +  -  +  - ]
    6660                 :          4 :         }
    6661                 :            : 
    6662                 :            :         /* Set internal xattr BLOB_SNAPSHOT */
    6663                 :        284 :         internal_xattrs.count = 1;
    6664         [ +  - ]:        284 :         internal_xattrs.ctx = _blob;
    6665         [ +  - ]:        284 :         internal_xattrs.names = xattr_names;
    6666         [ +  - ]:        284 :         internal_xattrs.get_value = bs_xattr_clone;
    6667                 :            : 
    6668   [ +  -  +  - ]:        284 :         bs_create_blob(_blob->bs, &opts, &internal_xattrs,
    6669                 :         44 :                        bs_clone_newblob_create_cpl, ctx);
    6670         [ -  + ]:         48 : }
    6671                 :            : 
    6672                 :            : void
    6673                 :        310 : spdk_bs_create_clone(struct spdk_blob_store *bs, spdk_blob_id blobid,
    6674                 :            :                      const struct spdk_blob_xattr_opts *clone_xattrs,
    6675                 :            :                      spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
    6676                 :            : {
    6677                 :        310 :         struct spdk_clone_snapshot_ctx  *ctx = calloc(1, sizeof(*ctx));
    6678                 :            : 
    6679         [ +  + ]:        310 :         if (!ctx) {
    6680   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, SPDK_BLOBID_INVALID, -ENOMEM);
    6681                 :          0 :                 return;
    6682                 :            :         }
    6683                 :            : 
    6684   [ +  -  +  -  :        310 :         ctx->cpl.type = SPDK_BS_CPL_TYPE_BLOBID;
                   +  - ]
    6685   [ +  -  +  -  :        310 :         ctx->cpl.u.blobid.cb_fn = cb_fn;
          +  -  +  -  +  
                      - ]
    6686   [ +  -  +  -  :        310 :         ctx->cpl.u.blobid.cb_arg = cb_arg;
          +  -  +  -  +  
                      - ]
    6687   [ +  -  +  -  :        310 :         ctx->cpl.u.blobid.blobid = SPDK_BLOBID_INVALID;
          +  -  +  -  +  
                      - ]
    6688   [ +  -  +  - ]:        310 :         ctx->bserrno = 0;
    6689   [ +  -  +  - ]:        310 :         ctx->xattrs = clone_xattrs;
    6690   [ +  -  +  -  :        310 :         ctx->original.id = blobid;
                   +  - ]
    6691                 :            : 
    6692   [ +  -  +  -  :        310 :         spdk_bs_open_blob(bs, ctx->original.id, bs_clone_origblob_open_cpl, ctx);
                   +  - ]
    6693         [ -  + ]:         48 : }
    6694                 :            : 
    6695                 :            : /* END spdk_bs_create_clone */
    6696                 :            : 
    6697                 :            : /* START spdk_bs_inflate_blob */
    6698                 :            : 
    6699                 :            : static void
    6700                 :         73 : bs_inflate_blob_set_parent_cpl(void *cb_arg, struct spdk_blob *_parent, int bserrno)
    6701                 :            : {
    6702                 :         73 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6703   [ +  -  +  -  :         73 :         struct spdk_blob *_blob = ctx->original.blob;
                   +  - ]
    6704                 :            : 
    6705         [ -  + ]:         73 :         if (bserrno != 0) {
    6706                 :          0 :                 bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
    6707                 :          0 :                 return;
    6708                 :            :         }
    6709                 :            : 
    6710                 :            :         /* Temporarily override md_ro flag for MD modification */
    6711   [ +  -  +  - ]:         73 :         _blob->md_ro = false;
    6712                 :            : 
    6713         [ +  - ]:         73 :         bserrno = blob_set_xattr(_blob, BLOB_SNAPSHOT, &_parent->id, sizeof(spdk_blob_id), true);
    6714         [ -  + ]:         73 :         if (bserrno != 0) {
    6715                 :          0 :                 bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
    6716                 :          0 :                 return;
    6717                 :            :         }
    6718                 :            : 
    6719   [ +  +  #  # ]:         73 :         assert(_parent != NULL);
    6720                 :            : 
    6721                 :         73 :         bs_blob_list_remove(_blob);
    6722   [ +  -  +  -  :         73 :         _blob->parent_id = _parent->id;
             +  -  +  - ]
    6723                 :            : 
    6724                 :         73 :         blob_back_bs_destroy(_blob);
    6725   [ +  -  +  - ]:         73 :         _blob->back_bs_dev = bs_create_blob_bs_dev(_parent);
    6726                 :         73 :         bs_blob_list_add(_blob);
    6727                 :            : 
    6728                 :         73 :         spdk_blob_sync_md(_blob, bs_clone_snapshot_origblob_cleanup, ctx);
    6729         [ -  + ]:         12 : }
    6730                 :            : 
    6731                 :            : static void
    6732                 :        319 : bs_inflate_blob_done(struct spdk_clone_snapshot_ctx *ctx)
    6733                 :            : {
    6734   [ +  -  +  -  :        319 :         struct spdk_blob *_blob = ctx->original.blob;
                   +  - ]
    6735                 :         52 :         struct spdk_blob *_parent;
    6736                 :            : 
    6737   [ +  +  +  +  :        319 :         if (ctx->allocate_all) {
             +  -  +  + ]
    6738                 :            :                 /* remove thin provisioning */
    6739                 :        173 :                 bs_blob_list_remove(_blob);
    6740   [ +  +  +  -  :        173 :                 if (_blob->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT) {
                   +  + ]
    6741                 :         48 :                         blob_remove_xattr(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, true);
    6742   [ +  -  +  -  :         48 :                         _blob->invalid_flags &= ~SPDK_BLOB_EXTERNAL_SNAPSHOT;
                   +  - ]
    6743                 :          8 :                 } else {
    6744                 :        125 :                         blob_remove_xattr(_blob, BLOB_SNAPSHOT, true);
    6745                 :            :                 }
    6746   [ +  -  +  -  :        173 :                 _blob->invalid_flags = _blob->invalid_flags & ~SPDK_BLOB_THIN_PROV;
          +  -  +  -  +  
                      - ]
    6747                 :        173 :                 blob_back_bs_destroy(_blob);
    6748   [ +  -  +  - ]:        173 :                 _blob->parent_id = SPDK_BLOBID_INVALID;
    6749                 :         28 :         } else {
    6750                 :            :                 /* For now, esnap clones always have allocate_all set. */
    6751   [ +  +  #  # ]:        146 :                 assert(!blob_is_esnap_clone(_blob));
    6752                 :            : 
    6753   [ +  -  +  -  :        146 :                 _parent = ((struct spdk_blob_bs_dev *)(_blob->back_bs_dev))->blob;
             +  -  +  - ]
    6754   [ +  +  +  -  :        146 :                 if (_parent->parent_id != SPDK_BLOBID_INVALID) {
                   +  + ]
    6755                 :            :                         /* We must change the parent of the inflated blob */
    6756   [ +  -  +  -  :         73 :                         spdk_bs_open_blob(_blob->bs, _parent->parent_id,
             +  -  +  - ]
    6757                 :         12 :                                           bs_inflate_blob_set_parent_cpl, ctx);
    6758                 :         73 :                         return;
    6759                 :            :                 }
    6760                 :            : 
    6761                 :         73 :                 bs_blob_list_remove(_blob);
    6762   [ +  -  +  - ]:         73 :                 _blob->parent_id = SPDK_BLOBID_INVALID;
    6763                 :         73 :                 blob_back_bs_destroy(_blob);
    6764   [ +  -  +  - ]:         73 :                 _blob->back_bs_dev = bs_create_zeroes_dev();
    6765                 :            :         }
    6766                 :            : 
    6767                 :            :         /* Temporarily override md_ro flag for MD modification */
    6768   [ +  -  +  - ]:        246 :         _blob->md_ro = false;
    6769                 :        246 :         blob_remove_xattr(_blob, BLOB_SNAPSHOT, true);
    6770   [ +  -  +  - ]:        246 :         _blob->state = SPDK_BLOB_STATE_DIRTY;
    6771                 :            : 
    6772                 :        246 :         spdk_blob_sync_md(_blob, bs_clone_snapshot_origblob_cleanup, ctx);
    6773         [ -  + ]:         52 : }
    6774                 :            : 
    6775                 :            : /* Check if cluster needs allocation */
    6776                 :            : static inline bool
    6777                 :       6314 : bs_cluster_needs_allocation(struct spdk_blob *blob, uint64_t cluster, bool allocate_all)
    6778                 :            : {
    6779                 :       1040 :         struct spdk_blob_bs_dev *b;
    6780                 :            : 
    6781   [ +  +  #  # ]:       6314 :         assert(blob != NULL);
    6782                 :            : 
    6783   [ +  +  +  -  :       6314 :         if (blob->active.clusters[cluster] != 0) {
          +  -  +  -  +  
                -  +  + ]
    6784                 :            :                 /* Cluster is already allocated */
    6785                 :        106 :                 return false;
    6786                 :            :         }
    6787                 :            : 
    6788   [ +  +  +  -  :       6208 :         if (blob->parent_id == SPDK_BLOBID_INVALID) {
                   +  + ]
    6789                 :            :                 /* Blob have no parent blob */
    6790         [ +  - ]:        480 :                 return allocate_all;
    6791                 :            :         }
    6792                 :            : 
    6793   [ +  +  +  -  :       5728 :         if (blob->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT) {
                   +  + ]
    6794                 :        384 :                 return true;
    6795                 :            :         }
    6796                 :            : 
    6797   [ +  -  +  - ]:       5344 :         b = (struct spdk_blob_bs_dev *)blob->back_bs_dev;
    6798   [ +  +  +  +  :       5344 :         return (allocate_all || b->blob->active.clusters[cluster] != 0);
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
    6799                 :       1040 : }
    6800                 :            : 
    6801                 :            : static void
    6802                 :       2627 : bs_inflate_blob_touch_next(void *cb_arg, int bserrno)
    6803                 :            : {
    6804                 :       2627 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6805   [ +  -  +  -  :       2627 :         struct spdk_blob *_blob = ctx->original.blob;
                   +  - ]
    6806                 :       2171 :         struct spdk_bs_cpl cpl;
    6807                 :        432 :         spdk_bs_user_op_t *op;
    6808                 :        432 :         uint64_t offset;
    6809                 :            : 
    6810         [ -  + ]:       2627 :         if (bserrno != 0) {
    6811                 :          0 :                 bs_clone_snapshot_origblob_cleanup(ctx, bserrno);
    6812                 :          0 :                 return;
    6813                 :            :         }
    6814                 :            : 
    6815   [ +  +  +  -  :       3476 :         for (; ctx->cluster < _blob->active.num_clusters; ctx->cluster++) {
          +  -  +  -  +  
             -  +  +  +  
                      - ]
    6816   [ +  +  +  +  :       3157 :                 if (bs_cluster_needs_allocation(_blob, ctx->cluster, ctx->allocate_all)) {
          +  -  +  -  +  
                -  +  + ]
    6817                 :       2308 :                         break;
    6818                 :            :                 }
    6819                 :        140 :         }
    6820                 :            : 
    6821   [ +  +  +  -  :       2627 :         if (ctx->cluster < _blob->active.num_clusters) {
          +  -  +  -  +  
                -  +  + ]
    6822   [ +  -  +  -  :       2308 :                 offset = bs_cluster_to_lba(_blob->bs, ctx->cluster);
             +  -  +  - ]
    6823                 :            : 
    6824                 :            :                 /* We may safely increment a cluster before copying */
    6825         [ +  - ]:       2308 :                 ctx->cluster++;
    6826                 :            : 
    6827                 :            :                 /* Use a dummy 0B read as a context for cluster copy */
    6828                 :       2308 :                 cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    6829   [ +  -  +  -  :       2308 :                 cpl.u.blob_basic.cb_fn = bs_inflate_blob_touch_next;
                   +  - ]
    6830   [ +  -  +  -  :       2308 :                 cpl.u.blob_basic.cb_arg = ctx;
                   +  - ]
    6831                 :            : 
    6832   [ +  -  +  - ]:       2308 :                 op = bs_user_op_alloc(ctx->channel, &cpl, SPDK_BLOB_READ, _blob,
    6833                 :        380 :                                       NULL, 0, offset, 0);
    6834         [ +  + ]:       2308 :                 if (!op) {
    6835                 :          0 :                         bs_clone_snapshot_origblob_cleanup(ctx, -ENOMEM);
    6836                 :          0 :                         return;
    6837                 :            :                 }
    6838                 :            : 
    6839   [ +  -  +  - ]:       2308 :                 bs_allocate_and_copy_cluster(_blob, ctx->channel, offset, op);
    6840                 :        380 :         } else {
    6841                 :        319 :                 bs_inflate_blob_done(ctx);
    6842                 :            :         }
    6843         [ -  + ]:        432 : }
    6844                 :            : 
    6845                 :            : static void
    6846                 :        344 : bs_inflate_blob_open_cpl(void *cb_arg, struct spdk_blob *_blob, int bserrno)
    6847                 :            : {
    6848                 :        344 :         struct spdk_clone_snapshot_ctx *ctx = (struct spdk_clone_snapshot_ctx *)cb_arg;
    6849                 :         56 :         uint64_t clusters_needed;
    6850                 :         56 :         uint64_t i;
    6851                 :            : 
    6852         [ -  + ]:        344 :         if (bserrno != 0) {
    6853                 :          0 :                 bs_clone_snapshot_cleanup_finish(ctx, bserrno);
    6854                 :          0 :                 return;
    6855                 :            :         }
    6856                 :            : 
    6857   [ +  -  +  -  :        344 :         ctx->original.blob = _blob;
                   +  - ]
    6858   [ +  +  +  -  :        344 :         ctx->original.md_ro = _blob->md_ro;
          +  -  +  -  +  
                -  +  - ]
    6859                 :            : 
    6860   [ +  +  +  +  :        344 :         if (_blob->locked_operation_in_progress) {
             +  -  -  + ]
    6861   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob, "Cannot inflate blob - another operation in progress\n");
                   #  # ]
    6862   [ #  #  #  # ]:          0 :                 ctx->bserrno = -EBUSY;
    6863                 :          0 :                 spdk_blob_close(_blob, bs_clone_snapshot_cleanup_finish, ctx);
    6864                 :          0 :                 return;
    6865                 :            :         }
    6866                 :            : 
    6867   [ +  -  +  - ]:        344 :         _blob->locked_operation_in_progress = true;
    6868                 :            : 
    6869   [ +  +  +  -  :        344 :         switch (_blob->parent_id) {
                +  +  + ]
    6870                 :         41 :         case SPDK_BLOBID_INVALID:
    6871   [ +  +  +  +  :         49 :                 if (!ctx->allocate_all) {
             +  -  +  + ]
    6872                 :            :                         /* This blob has no parent, so we cannot decouple it. */
    6873                 :         25 :                         SPDK_ERRLOG("Cannot decouple parent of blob with no parent.\n");
    6874                 :         25 :                         bs_clone_snapshot_origblob_cleanup(ctx, -EINVAL);
    6875                 :         25 :                         return;
    6876                 :            :                 }
    6877                 :         24 :                 break;
    6878                 :         40 :         case SPDK_BLOBID_EXTERNAL_SNAPSHOT:
    6879                 :            :                 /*
    6880                 :            :                  * It would be better to rely on back_bs_dev->is_zeroes(), to determine which
    6881                 :            :                  * clusters require allocation. Until there is a blobstore consumer that
    6882                 :            :                  * uses esnaps with an spdk_bs_dev that implements a useful is_zeroes() it is not
    6883                 :            :                  * worth the effort.
    6884                 :            :                  */
    6885   [ +  -  +  - ]:         48 :                 ctx->allocate_all = true;
    6886                 :         48 :                 break;
    6887                 :        207 :         default:
    6888                 :        247 :                 break;
    6889                 :            :         }
    6890                 :            : 
    6891         [ +  + ]:        319 :         if (spdk_blob_is_thin_provisioned(_blob) == false) {
    6892                 :            :                 /* This is not thin provisioned blob. No need to inflate. */
    6893                 :          0 :                 bs_clone_snapshot_origblob_cleanup(ctx, 0);
    6894                 :          0 :                 return;
    6895                 :            :         }
    6896                 :            : 
    6897                 :            :         /* Do two passes - one to verify that we can obtain enough clusters
    6898                 :            :          * and another to actually claim them.
    6899                 :            :          */
    6900                 :        319 :         clusters_needed = 0;
    6901   [ +  +  +  -  :       3476 :         for (i = 0; i < _blob->active.num_clusters; i++) {
             +  -  +  + ]
    6902   [ +  +  +  +  :       3157 :                 if (bs_cluster_needs_allocation(_blob, i, ctx->allocate_all)) {
             +  -  +  + ]
    6903                 :       2308 :                         clusters_needed++;
    6904                 :        380 :                 }
    6905                 :        520 :         }
    6906                 :            : 
    6907   [ +  +  +  -  :        319 :         if (clusters_needed > _blob->bs->num_free_clusters) {
          +  -  +  -  -  
                      + ]
    6908                 :            :                 /* Not enough free clusters. Cannot satisfy the request. */
    6909                 :          0 :                 bs_clone_snapshot_origblob_cleanup(ctx, -ENOSPC);
    6910                 :          0 :                 return;
    6911                 :            :         }
    6912                 :            : 
    6913   [ +  -  +  - ]:        319 :         ctx->cluster = 0;
    6914                 :        319 :         bs_inflate_blob_touch_next(ctx, 0);
    6915         [ -  + ]:         56 : }
    6916                 :            : 
    6917                 :            : static void
    6918                 :        344 : bs_inflate_blob(struct spdk_blob_store *bs, struct spdk_io_channel *channel,
    6919                 :            :                 spdk_blob_id blobid, bool allocate_all, spdk_blob_op_complete cb_fn, void *cb_arg)
    6920                 :            : {
    6921                 :        344 :         struct spdk_clone_snapshot_ctx *ctx = calloc(1, sizeof(*ctx));
    6922                 :            : 
    6923         [ +  + ]:        344 :         if (!ctx) {
    6924   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    6925                 :          0 :                 return;
    6926                 :            :         }
    6927   [ +  -  +  -  :        344 :         ctx->cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
                   +  - ]
    6928   [ +  -  +  -  :        344 :         ctx->cpl.u.bs_basic.cb_fn = cb_fn;
          +  -  +  -  +  
                      - ]
    6929   [ +  -  +  -  :        344 :         ctx->cpl.u.bs_basic.cb_arg = cb_arg;
          +  -  +  -  +  
                      - ]
    6930   [ +  -  +  - ]:        344 :         ctx->bserrno = 0;
    6931   [ +  -  +  -  :        344 :         ctx->original.id = blobid;
                   +  - ]
    6932   [ +  -  +  - ]:        344 :         ctx->channel = channel;
    6933   [ +  -  +  -  :        344 :         ctx->allocate_all = allocate_all;
                   +  - ]
    6934                 :            : 
    6935   [ +  -  +  -  :        344 :         spdk_bs_open_blob(bs, ctx->original.id, bs_inflate_blob_open_cpl, ctx);
                   +  - ]
    6936         [ -  + ]:         56 : }
    6937                 :            : 
    6938                 :            : void
    6939                 :        149 : spdk_bs_inflate_blob(struct spdk_blob_store *bs, struct spdk_io_channel *channel,
    6940                 :            :                      spdk_blob_id blobid, spdk_blob_op_complete cb_fn, void *cb_arg)
    6941                 :            : {
    6942                 :        149 :         bs_inflate_blob(bs, channel, blobid, true, cb_fn, cb_arg);
    6943                 :        149 : }
    6944                 :            : 
    6945                 :            : void
    6946                 :        195 : spdk_bs_blob_decouple_parent(struct spdk_blob_store *bs, struct spdk_io_channel *channel,
    6947                 :            :                              spdk_blob_id blobid, spdk_blob_op_complete cb_fn, void *cb_arg)
    6948                 :            : {
    6949                 :        195 :         bs_inflate_blob(bs, channel, blobid, false, cb_fn, cb_arg);
    6950                 :        195 : }
    6951                 :            : /* END spdk_bs_inflate_blob */
    6952                 :            : 
    6953                 :            : /* START spdk_blob_resize */
    6954                 :            : struct spdk_bs_resize_ctx {
    6955                 :            :         spdk_blob_op_complete cb_fn;
    6956                 :            :         void *cb_arg;
    6957                 :            :         struct spdk_blob *blob;
    6958                 :            :         uint64_t sz;
    6959                 :            :         int rc;
    6960                 :            : };
    6961                 :            : 
    6962                 :            : static void
    6963                 :     115329 : bs_resize_unfreeze_cpl(void *cb_arg, int rc)
    6964                 :            : {
    6965                 :     115329 :         struct spdk_bs_resize_ctx *ctx = (struct spdk_bs_resize_ctx *)cb_arg;
    6966                 :            : 
    6967         [ +  + ]:     115329 :         if (rc != 0) {
    6968                 :          0 :                 SPDK_ERRLOG("Unfreeze failed, rc=%d\n", rc);
    6969                 :          0 :         }
    6970                 :            : 
    6971   [ +  +  +  -  :     115329 :         if (ctx->rc != 0) {
                   +  + ]
    6972   [ +  -  +  - ]:         25 :                 SPDK_ERRLOG("Unfreeze failed, ctx->rc=%d\n", ctx->rc);
    6973   [ +  -  +  - ]:         25 :                 rc = ctx->rc;
    6974                 :          4 :         }
    6975                 :            : 
    6976   [ +  -  +  -  :     115329 :         ctx->blob->locked_operation_in_progress = false;
             +  -  +  - ]
    6977                 :            : 
    6978   [ +  -  +  -  :     115329 :         ctx->cb_fn(ctx->cb_arg, rc);
          -  +  +  -  +  
                -  +  - ]
    6979                 :     115329 :         free(ctx);
    6980                 :     115329 : }
    6981                 :            : 
    6982                 :            : static void
    6983                 :     115329 : bs_resize_freeze_cpl(void *cb_arg, int rc)
    6984                 :            : {
    6985                 :     115329 :         struct spdk_bs_resize_ctx *ctx = (struct spdk_bs_resize_ctx *)cb_arg;
    6986                 :            : 
    6987         [ -  + ]:     115329 :         if (rc != 0) {
    6988   [ #  #  #  #  :          0 :                 ctx->blob->locked_operation_in_progress = false;
             #  #  #  # ]
    6989   [ #  #  #  #  :          0 :                 ctx->cb_fn(ctx->cb_arg, rc);
          #  #  #  #  #  
                #  #  # ]
    6990                 :          0 :                 free(ctx);
    6991                 :          0 :                 return;
    6992                 :            :         }
    6993                 :            : 
    6994   [ +  -  +  -  :     115329 :         ctx->rc = blob_resize(ctx->blob, ctx->sz);
          +  -  +  -  +  
                -  +  - ]
    6995                 :            : 
    6996   [ +  -  +  - ]:     115329 :         blob_unfreeze_io(ctx->blob, bs_resize_unfreeze_cpl, ctx);
    6997         [ -  + ]:        182 : }
    6998                 :            : 
    6999                 :            : void
    7000                 :     115413 : spdk_blob_resize(struct spdk_blob *blob, uint64_t sz, spdk_blob_op_complete cb_fn, void *cb_arg)
    7001                 :            : {
    7002                 :        196 :         struct spdk_bs_resize_ctx *ctx;
    7003                 :            : 
    7004                 :     115413 :         blob_verify_md_op(blob);
    7005                 :            : 
    7006   [ +  +  +  +  :     115413 :         SPDK_DEBUGLOG(blob, "Resizing blob 0x%" PRIx64 " to %" PRIu64 " clusters\n", blob->id, sz);
          +  -  #  #  #  
                      # ]
    7007                 :            : 
    7008   [ +  +  +  +  :     115413 :         if (blob->md_ro) {
             +  -  +  + ]
    7009   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, -EPERM);
    7010                 :         24 :                 return;
    7011                 :            :         }
    7012                 :            : 
    7013   [ +  +  +  -  :     115389 :         if (sz == blob->active.num_clusters) {
             +  -  +  + ]
    7014   [ -  +  +  - ]:         60 :                 cb_fn(cb_arg, 0);
    7015                 :         60 :                 return;
    7016                 :            :         }
    7017                 :            : 
    7018   [ +  +  +  +  :     115329 :         if (blob->locked_operation_in_progress) {
             +  -  -  + ]
    7019   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -EBUSY);
    7020                 :          0 :                 return;
    7021                 :            :         }
    7022                 :            : 
    7023                 :     115329 :         ctx = calloc(1, sizeof(*ctx));
    7024         [ +  + ]:     115329 :         if (!ctx) {
    7025   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    7026                 :          0 :                 return;
    7027                 :            :         }
    7028                 :            : 
    7029   [ +  -  +  - ]:     115329 :         blob->locked_operation_in_progress = true;
    7030   [ +  -  +  - ]:     115329 :         ctx->cb_fn = cb_fn;
    7031   [ +  -  +  - ]:     115329 :         ctx->cb_arg = cb_arg;
    7032   [ +  -  +  - ]:     115329 :         ctx->blob = blob;
    7033   [ +  -  +  - ]:     115329 :         ctx->sz = sz;
    7034                 :     115329 :         blob_freeze_io(blob, bs_resize_freeze_cpl, ctx);
    7035         [ -  + ]:        196 : }
    7036                 :            : 
    7037                 :            : /* END spdk_blob_resize */
    7038                 :            : 
    7039                 :            : 
    7040                 :            : /* START spdk_bs_delete_blob */
    7041                 :            : 
    7042                 :            : static void
    7043                 :       9989 : bs_delete_close_cpl(void *cb_arg, int bserrno)
    7044                 :            : {
    7045                 :       9989 :         spdk_bs_sequence_t *seq = cb_arg;
    7046                 :            : 
    7047                 :       9989 :         bs_sequence_finish(seq, bserrno);
    7048                 :       9989 : }
    7049                 :            : 
    7050                 :            : static void
    7051                 :       9989 : bs_delete_persist_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    7052                 :            : {
    7053                 :       9989 :         struct spdk_blob *blob = cb_arg;
    7054                 :            : 
    7055         [ -  + ]:       9989 :         if (bserrno != 0) {
    7056                 :            :                 /*
    7057                 :            :                  * We already removed this blob from the blobstore tailq, so
    7058                 :            :                  *  we need to free it here since this is the last reference
    7059                 :            :                  *  to it.
    7060                 :            :                  */
    7061                 :          0 :                 blob_free(blob);
    7062                 :          0 :                 bs_delete_close_cpl(seq, bserrno);
    7063                 :          0 :                 return;
    7064                 :            :         }
    7065                 :            : 
    7066                 :            :         /*
    7067                 :            :          * This will immediately decrement the ref_count and call
    7068                 :            :          *  the completion routine since the metadata state is clean.
    7069                 :            :          *  By calling spdk_blob_close, we reduce the number of call
    7070                 :            :          *  points into code that touches the blob->open_ref count
    7071                 :            :          *  and the blobstore's blob list.
    7072                 :            :          */
    7073                 :       9989 :         spdk_blob_close(blob, bs_delete_close_cpl, seq);
    7074         [ -  + ]:       1420 : }
    7075                 :            : 
    7076                 :            : struct delete_snapshot_ctx {
    7077                 :            :         struct spdk_blob_list *parent_snapshot_entry;
    7078                 :            :         struct spdk_blob *snapshot;
    7079                 :            :         struct spdk_blob_md_page *page;
    7080                 :            :         bool snapshot_md_ro;
    7081                 :            :         struct spdk_blob *clone;
    7082                 :            :         bool clone_md_ro;
    7083                 :            :         spdk_blob_op_with_handle_complete cb_fn;
    7084                 :            :         void *cb_arg;
    7085                 :            :         int bserrno;
    7086                 :            :         uint32_t next_extent_page;
    7087                 :            : };
    7088                 :            : 
    7089                 :            : static void
    7090                 :        667 : delete_blob_cleanup_finish(void *cb_arg, int bserrno)
    7091                 :            : {
    7092                 :        667 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7093                 :            : 
    7094         [ +  + ]:        667 :         if (bserrno != 0) {
    7095                 :          0 :                 SPDK_ERRLOG("Snapshot cleanup error %d\n", bserrno);
    7096                 :          0 :         }
    7097                 :            : 
    7098   [ +  +  #  # ]:        667 :         assert(ctx != NULL);
    7099                 :            : 
    7100   [ -  +  -  -  :        667 :         if (bserrno != 0 && ctx->bserrno == 0) {
             #  #  #  # ]
    7101   [ #  #  #  # ]:          0 :                 ctx->bserrno = bserrno;
    7102                 :          0 :         }
    7103                 :            : 
    7104   [ +  -  +  -  :        667 :         ctx->cb_fn(ctx->cb_arg, ctx->snapshot, ctx->bserrno);
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    7105   [ +  -  +  - ]:        667 :         spdk_free(ctx->page);
    7106                 :        667 :         free(ctx);
    7107                 :        667 : }
    7108                 :            : 
    7109                 :            : static void
    7110                 :        132 : delete_snapshot_cleanup_snapshot(void *cb_arg, int bserrno)
    7111                 :            : {
    7112                 :        132 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7113                 :            : 
    7114         [ +  + ]:        132 :         if (bserrno != 0) {
    7115   [ #  #  #  # ]:          0 :                 ctx->bserrno = bserrno;
    7116                 :          0 :                 SPDK_ERRLOG("Clone cleanup error %d\n", bserrno);
    7117                 :          0 :         }
    7118                 :            : 
    7119   [ +  -  +  -  :        132 :         if (ctx->bserrno != 0) {
                   -  + ]
    7120   [ +  +  +  -  :        132 :                 assert(blob_lookup(ctx->snapshot->bs, ctx->snapshot->id) == NULL);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    7121   [ +  -  +  -  :        132 :                 RB_INSERT(spdk_blob_tree, &ctx->snapshot->bs->open_blobs, ctx->snapshot);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7122   [ +  -  +  -  :        132 :                 spdk_bit_array_set(ctx->snapshot->bs->open_blobids, ctx->snapshot->id);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    7123                 :         22 :         }
    7124                 :            : 
    7125   [ +  -  +  -  :        132 :         ctx->snapshot->locked_operation_in_progress = false;
             +  -  +  - ]
    7126   [ +  +  +  -  :        132 :         ctx->snapshot->md_ro = ctx->snapshot_md_ro;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7127                 :            : 
    7128   [ +  -  +  - ]:        132 :         spdk_blob_close(ctx->snapshot, delete_blob_cleanup_finish, ctx);
    7129                 :        132 : }
    7130                 :            : 
    7131                 :            : static void
    7132                 :         72 : delete_snapshot_cleanup_clone(void *cb_arg, int bserrno)
    7133                 :            : {
    7134                 :         72 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7135                 :            : 
    7136   [ +  -  +  -  :         72 :         ctx->clone->locked_operation_in_progress = false;
             +  -  +  - ]
    7137   [ +  +  +  -  :         72 :         ctx->clone->md_ro = ctx->clone_md_ro;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7138                 :            : 
    7139   [ +  -  +  - ]:         72 :         spdk_blob_close(ctx->clone, delete_snapshot_cleanup_snapshot, ctx);
    7140                 :         72 : }
    7141                 :            : 
    7142                 :            : static void
    7143                 :        295 : delete_snapshot_unfreeze_cpl(void *cb_arg, int bserrno)
    7144                 :            : {
    7145                 :        295 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7146                 :            : 
    7147         [ -  + ]:        295 :         if (bserrno) {
    7148   [ #  #  #  # ]:          0 :                 ctx->bserrno = bserrno;
    7149                 :          0 :                 delete_snapshot_cleanup_clone(ctx, 0);
    7150                 :          0 :                 return;
    7151                 :            :         }
    7152                 :            : 
    7153   [ +  -  +  -  :        295 :         ctx->clone->locked_operation_in_progress = false;
             +  -  +  - ]
    7154   [ +  -  +  - ]:        295 :         spdk_blob_close(ctx->clone, delete_blob_cleanup_finish, ctx);
    7155         [ -  + ]:         48 : }
    7156                 :            : 
    7157                 :            : static void
    7158                 :        319 : delete_snapshot_sync_snapshot_cpl(void *cb_arg, int bserrno)
    7159                 :            : {
    7160                 :        319 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7161                 :        319 :         struct spdk_blob_list *parent_snapshot_entry = NULL;
    7162                 :        319 :         struct spdk_blob_list *snapshot_entry = NULL;
    7163                 :        319 :         struct spdk_blob_list *clone_entry = NULL;
    7164                 :        319 :         struct spdk_blob_list *snapshot_clone_entry = NULL;
    7165                 :            : 
    7166         [ +  + ]:        319 :         if (bserrno) {
    7167                 :         24 :                 SPDK_ERRLOG("Failed to sync MD on blob\n");
    7168   [ +  -  +  - ]:         24 :                 ctx->bserrno = bserrno;
    7169                 :         24 :                 delete_snapshot_cleanup_clone(ctx, 0);
    7170                 :         24 :                 return;
    7171                 :            :         }
    7172                 :            : 
    7173                 :            :         /* Get snapshot entry for the snapshot we want to remove */
    7174   [ +  -  +  -  :        295 :         snapshot_entry = bs_get_snapshot_entry(ctx->snapshot->bs, ctx->snapshot->id);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7175                 :            : 
    7176   [ +  +  #  # ]:        295 :         assert(snapshot_entry != NULL);
    7177                 :            : 
    7178                 :            :         /* Remove clone entry in this snapshot (at this point there can be only one clone) */
    7179   [ +  -  +  -  :        295 :         clone_entry = TAILQ_FIRST(&snapshot_entry->clones);
                   +  - ]
    7180   [ +  +  #  # ]:        295 :         assert(clone_entry != NULL);
    7181   [ +  +  +  -  :        295 :         TAILQ_REMOVE(&snapshot_entry->clones, clone_entry, link);
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    7182         [ +  - ]:        295 :         snapshot_entry->clone_count--;
    7183   [ +  +  +  -  :        295 :         assert(TAILQ_EMPTY(&snapshot_entry->clones));
          +  -  +  -  #  
                      # ]
    7184                 :            : 
    7185   [ +  +  +  -  :        295 :         switch (ctx->snapshot->parent_id) {
          +  -  +  -  +  
                      + ]
    7186                 :        206 :         case SPDK_BLOBID_INVALID:
    7187                 :            :         case SPDK_BLOBID_EXTERNAL_SNAPSHOT:
    7188                 :            :                 /* No parent snapshot - just remove clone entry */
    7189                 :        246 :                 free(clone_entry);
    7190                 :        246 :                 break;
    7191                 :         41 :         default:
    7192                 :            :                 /* This snapshot is at the same time a clone of another snapshot - we need to
    7193                 :            :                  * update parent snapshot (remove current clone, add new one inherited from
    7194                 :            :                  * the snapshot that is being removed) */
    7195                 :            : 
    7196                 :            :                 /* Get snapshot entry for parent snapshot and clone entry within that snapshot for
    7197                 :            :                  * snapshot that we are removing */
    7198   [ +  -  +  - ]:         49 :                 blob_get_snapshot_and_clone_entries(ctx->snapshot, &parent_snapshot_entry,
    7199                 :            :                                                     &snapshot_clone_entry);
    7200                 :            : 
    7201                 :            :                 /* Switch clone entry in parent snapshot */
    7202   [ +  -  +  -  :         49 :                 TAILQ_INSERT_TAIL(&parent_snapshot_entry->clones, clone_entry, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7203   [ +  -  +  -  :         49 :                 TAILQ_REMOVE(&parent_snapshot_entry->clones, snapshot_clone_entry, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  #  #  #  
          #  #  #  #  #  
          #  #  #  #  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
    7204                 :         49 :                 free(snapshot_clone_entry);
    7205                 :          8 :         }
    7206                 :            : 
    7207                 :            :         /* Restore md_ro flags */
    7208   [ +  +  +  -  :        295 :         ctx->clone->md_ro = ctx->clone_md_ro;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7209   [ +  +  +  -  :        295 :         ctx->snapshot->md_ro = ctx->snapshot_md_ro;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7210                 :            : 
    7211   [ +  -  +  - ]:        295 :         blob_unfreeze_io(ctx->clone, delete_snapshot_unfreeze_cpl, ctx);
    7212         [ -  + ]:         52 : }
    7213                 :            : 
    7214                 :            : static void
    7215                 :        343 : delete_snapshot_sync_clone_cpl(void *cb_arg, int bserrno)
    7216                 :            : {
    7217                 :        343 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7218                 :         56 :         uint64_t i;
    7219                 :            : 
    7220   [ +  -  +  -  :        343 :         ctx->snapshot->md_ro = false;
             +  -  +  - ]
    7221                 :            : 
    7222         [ +  + ]:        343 :         if (bserrno) {
    7223                 :         24 :                 SPDK_ERRLOG("Failed to sync MD on clone\n");
    7224   [ +  -  +  - ]:         24 :                 ctx->bserrno = bserrno;
    7225                 :            : 
    7226                 :            :                 /* Restore snapshot to previous state */
    7227   [ +  -  +  - ]:         24 :                 bserrno = blob_remove_xattr(ctx->snapshot, SNAPSHOT_PENDING_REMOVAL, true);
    7228         [ -  + ]:         24 :                 if (bserrno != 0) {
    7229                 :          0 :                         delete_snapshot_cleanup_clone(ctx, bserrno);
    7230                 :          0 :                         return;
    7231                 :            :                 }
    7232                 :            : 
    7233   [ +  -  +  - ]:         24 :                 spdk_blob_sync_md(ctx->snapshot, delete_snapshot_cleanup_clone, ctx);
    7234                 :         24 :                 return;
    7235                 :            :         }
    7236                 :            : 
    7237                 :            :         /* Clear cluster map entries for snapshot */
    7238   [ +  +  +  -  :       3540 :         for (i = 0; i < ctx->snapshot->active.num_clusters && i < ctx->clone->active.num_clusters; i++) {
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    7239   [ +  +  +  -  :       3221 :                 if (ctx->clone->active.clusters[i] == ctx->snapshot->active.clusters[i]) {
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      + ]
    7240   [ +  -  +  -  :       3159 :                         ctx->snapshot->active.clusters[i] = 0;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7241                 :        492 :                 }
    7242                 :        500 :         }
    7243   [ +  +  +  -  :        508 :         for (i = 0; i < ctx->snapshot->active.num_extent_pages &&
          +  -  +  -  +  
             -  +  +  +  
                      + ]
    7244   [ +  -  +  -  :        326 :              i < ctx->clone->active.num_extent_pages; i++) {
          +  -  +  -  +  
                      - ]
    7245   [ +  +  +  -  :        163 :                 if (ctx->clone->active.extent_pages[i] == ctx->snapshot->active.extent_pages[i]) {
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      + ]
    7246   [ +  -  +  -  :        148 :                         ctx->snapshot->active.extent_pages[i] = 0;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7247                 :         24 :                 }
    7248                 :         26 :         }
    7249                 :            : 
    7250   [ +  -  +  - ]:        319 :         blob_set_thin_provision(ctx->snapshot);
    7251   [ +  -  +  -  :        319 :         ctx->snapshot->state = SPDK_BLOB_STATE_DIRTY;
             +  -  +  - ]
    7252                 :            : 
    7253   [ +  +  +  -  :        319 :         if (ctx->parent_snapshot_entry != NULL) {
                   +  + ]
    7254   [ +  -  +  -  :         49 :                 ctx->snapshot->back_bs_dev = NULL;
             +  -  +  - ]
    7255                 :          8 :         }
    7256                 :            : 
    7257   [ +  -  +  - ]:        319 :         spdk_blob_sync_md(ctx->snapshot, delete_snapshot_sync_snapshot_cpl, ctx);
    7258         [ -  + ]:         56 : }
    7259                 :            : 
    7260                 :            : static void
    7261                 :        343 : delete_snapshot_update_extent_pages_cpl(struct delete_snapshot_ctx *ctx)
    7262                 :            : {
    7263                 :         56 :         int bserrno;
    7264                 :            : 
    7265                 :            :         /* Delete old backing bs_dev from clone (related to snapshot that will be removed) */
    7266   [ +  -  +  - ]:        343 :         blob_back_bs_destroy(ctx->clone);
    7267                 :            : 
    7268                 :            :         /* Set/remove snapshot xattr and switch parent ID and backing bs_dev on clone... */
    7269   [ +  +  +  -  :        343 :         if (ctx->snapshot->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT) {
          +  -  +  -  +  
                      + ]
    7270   [ +  -  +  -  :         52 :                 bserrno = bs_snapshot_copy_xattr(ctx->clone, ctx->snapshot,
             +  -  +  - ]
    7271                 :            :                                                  BLOB_EXTERNAL_SNAPSHOT_ID);
    7272         [ -  + ]:         52 :                 if (bserrno != 0) {
    7273   [ #  #  #  # ]:          0 :                         ctx->bserrno = bserrno;
    7274                 :            : 
    7275                 :            :                         /* Restore snapshot to previous state */
    7276   [ #  #  #  # ]:          0 :                         bserrno = blob_remove_xattr(ctx->snapshot, SNAPSHOT_PENDING_REMOVAL, true);
    7277         [ #  # ]:          0 :                         if (bserrno != 0) {
    7278                 :          0 :                                 delete_snapshot_cleanup_clone(ctx, bserrno);
    7279                 :          0 :                                 return;
    7280                 :            :                         }
    7281                 :            : 
    7282   [ #  #  #  # ]:          0 :                         spdk_blob_sync_md(ctx->snapshot, delete_snapshot_cleanup_clone, ctx);
    7283                 :          0 :                         return;
    7284                 :            :                 }
    7285   [ +  -  +  -  :         52 :                 ctx->clone->parent_id = SPDK_BLOBID_EXTERNAL_SNAPSHOT;
             +  -  +  - ]
    7286   [ +  -  +  -  :         52 :                 ctx->clone->back_bs_dev = ctx->snapshot->back_bs_dev;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7287                 :            :                 /* Do not delete the external snapshot along with this snapshot */
    7288   [ +  -  +  -  :         52 :                 ctx->snapshot->back_bs_dev = NULL;
             +  -  +  - ]
    7289   [ +  -  +  -  :         52 :                 ctx->clone->invalid_flags |= SPDK_BLOB_EXTERNAL_SNAPSHOT;
          +  -  +  -  +  
                      - ]
    7290   [ +  +  +  -  :        299 :         } else if (ctx->parent_snapshot_entry != NULL) {
                   +  + ]
    7291                 :            :                 /* ...to parent snapshot */
    7292   [ +  -  +  -  :         49 :                 ctx->clone->parent_id = ctx->parent_snapshot_entry->id;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7293   [ +  -  +  -  :         49 :                 ctx->clone->back_bs_dev = ctx->snapshot->back_bs_dev;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7294   [ +  -  +  -  :         49 :                 blob_set_xattr(ctx->clone, BLOB_SNAPSHOT, &ctx->parent_snapshot_entry->id,
          +  -  +  -  +  
                      - ]
    7295                 :            :                                sizeof(spdk_blob_id),
    7296                 :            :                                true);
    7297                 :          8 :         } else {
    7298                 :            :                 /* ...to blobid invalid and zeroes dev */
    7299   [ +  -  +  -  :        242 :                 ctx->clone->parent_id = SPDK_BLOBID_INVALID;
             +  -  +  - ]
    7300   [ +  -  +  -  :        242 :                 ctx->clone->back_bs_dev = bs_create_zeroes_dev();
             +  -  +  - ]
    7301   [ +  -  +  - ]:        242 :                 blob_remove_xattr(ctx->clone, BLOB_SNAPSHOT, true);
    7302                 :            :         }
    7303                 :            : 
    7304   [ +  -  +  - ]:        343 :         spdk_blob_sync_md(ctx->clone, delete_snapshot_sync_clone_cpl, ctx);
    7305         [ -  + ]:         56 : }
    7306                 :            : 
    7307                 :            : static void
    7308                 :        358 : delete_snapshot_update_extent_pages(void *cb_arg, int bserrno)
    7309                 :            : {
    7310                 :        358 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7311                 :         58 :         uint32_t *extent_page;
    7312                 :         58 :         uint64_t i;
    7313                 :            : 
    7314   [ +  +  +  -  :        546 :         for (i = ctx->next_extent_page; i < ctx->snapshot->active.num_extent_pages &&
          +  -  +  -  +  
          -  +  -  +  -  
             +  +  +  + ]
    7315   [ +  -  +  -  :        335 :              i < ctx->clone->active.num_extent_pages; i++) {
          +  -  +  -  +  
                      - ]
    7316   [ +  +  +  -  :        175 :                 if (ctx->snapshot->active.extent_pages[i] == 0) {
          +  -  +  -  +  
          -  +  -  +  -  
                   +  + ]
    7317                 :            :                         /* No extent page to use from snapshot */
    7318                 :         52 :                         continue;
    7319                 :            :                 }
    7320                 :            : 
    7321   [ +  -  +  -  :        123 :                 extent_page = &ctx->clone->active.extent_pages[i];
          +  -  +  -  +  
                -  +  - ]
    7322   [ +  +  +  + ]:        123 :                 if (*extent_page == 0) {
    7323                 :            :                         /* Copy extent page from snapshot when clone did not have a matching one */
    7324   [ +  -  +  -  :        108 :                         *extent_page = ctx->snapshot->active.extent_pages[i];
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7325                 :        108 :                         continue;
    7326                 :            :                 }
    7327                 :            : 
    7328                 :            :                 /* Clone and snapshot both contain partially filled matching extent pages.
    7329                 :            :                  * Update the clone extent page in place with cluster map containing the mix of both. */
    7330   [ +  -  +  - ]:         15 :                 ctx->next_extent_page = i + 1;
    7331   [ +  +  +  -  :         15 :                 memset(ctx->page, 0, SPDK_BS_PAGE_SIZE);
                   +  - ]
    7332                 :            : 
    7333   [ +  -  +  -  :         15 :                 blob_write_extent_page(ctx->clone, *extent_page, i * SPDK_EXTENTS_PER_EP, ctx->page,
          +  -  +  -  +  
                -  +  - ]
    7334                 :          2 :                                        delete_snapshot_update_extent_pages, ctx);
    7335                 :         15 :                 return;
    7336                 :            :         }
    7337                 :        343 :         delete_snapshot_update_extent_pages_cpl(ctx);
    7338         [ -  + ]:         58 : }
    7339                 :            : 
    7340                 :            : static void
    7341                 :        367 : delete_snapshot_sync_snapshot_xattr_cpl(void *cb_arg, int bserrno)
    7342                 :            : {
    7343                 :        367 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7344                 :         60 :         uint64_t i;
    7345                 :            : 
    7346                 :            :         /* Temporarily override md_ro flag for clone for MD modification */
    7347   [ +  +  +  -  :        367 :         ctx->clone_md_ro = ctx->clone->md_ro;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7348   [ +  -  +  -  :        367 :         ctx->clone->md_ro = false;
             +  -  +  - ]
    7349                 :            : 
    7350         [ +  + ]:        367 :         if (bserrno) {
    7351                 :         24 :                 SPDK_ERRLOG("Failed to sync MD with xattr on blob\n");
    7352   [ +  -  +  - ]:         24 :                 ctx->bserrno = bserrno;
    7353                 :         24 :                 delete_snapshot_cleanup_clone(ctx, 0);
    7354                 :         24 :                 return;
    7355                 :            :         }
    7356                 :            : 
    7357                 :            :         /* Copy snapshot map to clone map (only unallocated clusters in clone) */
    7358   [ +  +  +  -  :       3804 :         for (i = 0; i < ctx->snapshot->active.num_clusters && i < ctx->clone->active.num_clusters; i++) {
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      + ]
    7359   [ +  +  +  -  :       3461 :                 if (ctx->clone->active.clusters[i] == 0) {
          +  -  +  -  +  
          -  +  -  +  -  
                   +  + ]
    7360   [ +  -  +  -  :       3399 :                         ctx->clone->active.clusters[i] = ctx->snapshot->active.clusters[i];
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
    7361                 :        532 :                 }
    7362                 :        540 :         }
    7363   [ +  -  +  - ]:        343 :         ctx->next_extent_page = 0;
    7364                 :        343 :         delete_snapshot_update_extent_pages(ctx, 0);
    7365         [ -  + ]:         60 : }
    7366                 :            : 
    7367                 :            : static void
    7368                 :         52 : delete_snapshot_esnap_channels_destroyed_cb(void *cb_arg, struct spdk_blob *blob, int bserrno)
    7369                 :            : {
    7370                 :         52 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7371                 :            : 
    7372         [ -  + ]:         52 :         if (bserrno != 0) {
    7373   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 ": failed to destroy esnap channels: %d\n",
    7374                 :            :                             blob->id, bserrno);
    7375                 :            :                 /* That error should not stop us from syncing metadata. */
    7376                 :          0 :         }
    7377                 :            : 
    7378   [ +  -  +  - ]:         52 :         spdk_blob_sync_md(ctx->snapshot, delete_snapshot_sync_snapshot_xattr_cpl, ctx);
    7379                 :         52 : }
    7380                 :            : 
    7381                 :            : static void
    7382                 :        367 : delete_snapshot_freeze_io_cb(void *cb_arg, int bserrno)
    7383                 :            : {
    7384                 :        367 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7385                 :            : 
    7386         [ -  + ]:        367 :         if (bserrno) {
    7387                 :          0 :                 SPDK_ERRLOG("Failed to freeze I/O on clone\n");
    7388   [ #  #  #  # ]:          0 :                 ctx->bserrno = bserrno;
    7389                 :          0 :                 delete_snapshot_cleanup_clone(ctx, 0);
    7390                 :          0 :                 return;
    7391                 :            :         }
    7392                 :            : 
    7393                 :            :         /* Temporarily override md_ro flag for snapshot for MD modification */
    7394   [ +  +  +  -  :        367 :         ctx->snapshot_md_ro = ctx->snapshot->md_ro;
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7395   [ +  -  +  -  :        367 :         ctx->snapshot->md_ro = false;
             +  -  +  - ]
    7396                 :            : 
    7397                 :            :         /* Mark blob as pending for removal for power failure safety, use clone id for recovery */
    7398   [ +  -  +  -  :        367 :         ctx->bserrno = blob_set_xattr(ctx->snapshot, SNAPSHOT_PENDING_REMOVAL, &ctx->clone->id,
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    7399                 :            :                                       sizeof(spdk_blob_id), true);
    7400   [ +  +  +  -  :        367 :         if (ctx->bserrno != 0) {
                   -  + ]
    7401                 :          0 :                 delete_snapshot_cleanup_clone(ctx, 0);
    7402                 :          0 :                 return;
    7403                 :            :         }
    7404                 :            : 
    7405   [ +  +  +  -  :        367 :         if (blob_is_esnap_clone(ctx->snapshot)) {
                   +  + ]
    7406   [ +  -  +  - ]:         52 :                 blob_esnap_destroy_bs_dev_channels(ctx->snapshot, false,
    7407                 :            :                                                    delete_snapshot_esnap_channels_destroyed_cb,
    7408                 :          8 :                                                    ctx);
    7409                 :         52 :                 return;
    7410                 :            :         }
    7411                 :            : 
    7412   [ +  -  +  - ]:        315 :         spdk_blob_sync_md(ctx->snapshot, delete_snapshot_sync_snapshot_xattr_cpl, ctx);
    7413         [ -  + ]:         60 : }
    7414                 :            : 
    7415                 :            : static void
    7416                 :        427 : delete_snapshot_open_clone_cb(void *cb_arg, struct spdk_blob *clone, int bserrno)
    7417                 :            : {
    7418                 :        427 :         struct delete_snapshot_ctx *ctx = cb_arg;
    7419                 :            : 
    7420         [ +  + ]:        427 :         if (bserrno) {
    7421                 :         60 :                 SPDK_ERRLOG("Failed to open clone\n");
    7422   [ +  -  +  - ]:         60 :                 ctx->bserrno = bserrno;
    7423                 :         60 :                 delete_snapshot_cleanup_snapshot(ctx, 0);
    7424                 :         60 :                 return;
    7425                 :            :         }
    7426                 :            : 
    7427   [ +  -  +  - ]:        367 :         ctx->clone = clone;
    7428                 :            : 
    7429   [ +  +  +  +  :        367 :         if (clone->locked_operation_in_progress) {
             +  -  -  + ]
    7430   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob, "Cannot remove blob - another operation in progress on its clone\n");
                   #  # ]
    7431   [ #  #  #  # ]:          0 :                 ctx->bserrno = -EBUSY;
    7432   [ #  #  #  # ]:          0 :                 spdk_blob_close(ctx->clone, delete_snapshot_cleanup_snapshot, ctx);
    7433                 :          0 :                 return;
    7434                 :            :         }
    7435                 :            : 
    7436   [ +  -  +  - ]:        367 :         clone->locked_operation_in_progress = true;
    7437                 :            : 
    7438                 :        367 :         blob_freeze_io(clone, delete_snapshot_freeze_io_cb, ctx);
    7439         [ -  + ]:         70 : }
    7440                 :            : 
    7441                 :            : static void
    7442                 :        427 : update_clone_on_snapshot_deletion(struct spdk_blob *snapshot, struct delete_snapshot_ctx *ctx)
    7443                 :            : {
    7444                 :        427 :         struct spdk_blob_list *snapshot_entry = NULL;
    7445                 :        427 :         struct spdk_blob_list *clone_entry = NULL;
    7446                 :        427 :         struct spdk_blob_list *snapshot_clone_entry = NULL;
    7447                 :            : 
    7448                 :            :         /* Get snapshot entry for the snapshot we want to remove */
    7449   [ +  -  +  -  :        427 :         snapshot_entry = bs_get_snapshot_entry(snapshot->bs, snapshot->id);
             +  -  +  - ]
    7450                 :            : 
    7451   [ +  +  #  # ]:        427 :         assert(snapshot_entry != NULL);
    7452                 :            : 
    7453                 :            :         /* Get clone of the snapshot (at this point there can be only one clone) */
    7454   [ +  -  +  -  :        427 :         clone_entry = TAILQ_FIRST(&snapshot_entry->clones);
                   +  - ]
    7455   [ +  +  +  -  :        427 :         assert(snapshot_entry->clone_count == 1);
             +  -  #  # ]
    7456   [ +  +  #  # ]:        427 :         assert(clone_entry != NULL);
    7457                 :            : 
    7458                 :            :         /* Get snapshot entry for parent snapshot and clone entry within that snapshot for
    7459                 :            :          * snapshot that we are removing */
    7460         [ +  - ]:        427 :         blob_get_snapshot_and_clone_entries(snapshot, &ctx->parent_snapshot_entry,
    7461                 :            :                                             &snapshot_clone_entry);
    7462                 :            : 
    7463   [ +  -  +  -  :        427 :         spdk_bs_open_blob(snapshot->bs, clone_entry->id, delete_snapshot_open_clone_cb, ctx);
             +  -  +  - ]
    7464                 :        427 : }
    7465                 :            : 
    7466                 :            : static void
    7467                 :      10361 : bs_delete_blob_finish(void *cb_arg, struct spdk_blob *blob, int bserrno)
    7468                 :            : {
    7469                 :      10361 :         spdk_bs_sequence_t *seq = cb_arg;
    7470                 :      10361 :         struct spdk_blob_list *snapshot_entry = NULL;
    7471                 :       1482 :         uint32_t page_num;
    7472                 :            : 
    7473         [ +  + ]:      10361 :         if (bserrno) {
    7474                 :        372 :                 SPDK_ERRLOG("Failed to remove blob\n");
    7475                 :        372 :                 bs_sequence_finish(seq, bserrno);
    7476                 :        372 :                 return;
    7477                 :            :         }
    7478                 :            : 
    7479                 :            :         /* Remove snapshot from the list */
    7480   [ +  -  +  -  :       9989 :         snapshot_entry = bs_get_snapshot_entry(blob->bs, blob->id);
             +  -  +  - ]
    7481         [ +  + ]:       9989 :         if (snapshot_entry != NULL) {
    7482   [ +  +  +  -  :        772 :                 TAILQ_REMOVE(&blob->bs->snapshots, snapshot_entry, link);
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7483                 :        772 :                 free(snapshot_entry);
    7484                 :        124 :         }
    7485                 :            : 
    7486   [ +  -  +  - ]:       9989 :         page_num = bs_blobid_to_page(blob->id);
    7487   [ +  -  +  -  :       9989 :         spdk_bit_array_clear(blob->bs->used_blobids, page_num);
             +  -  +  - ]
    7488   [ +  -  +  - ]:       9989 :         blob->state = SPDK_BLOB_STATE_DIRTY;
    7489   [ +  -  +  -  :       9989 :         blob->active.num_pages = 0;
                   +  - ]
    7490                 :       9989 :         blob_resize(blob, 0);
    7491                 :            : 
    7492                 :       9989 :         blob_persist(seq, blob, bs_delete_persist_cpl, blob);
    7493         [ -  + ]:       1482 : }
    7494                 :            : 
    7495                 :            : static int
    7496                 :      10361 : bs_is_blob_deletable(struct spdk_blob *blob, bool *update_clone)
    7497                 :            : {
    7498                 :      10361 :         struct spdk_blob_list *snapshot_entry = NULL;
    7499                 :      10361 :         struct spdk_blob_list *clone_entry = NULL;
    7500                 :      10361 :         struct spdk_blob *clone = NULL;
    7501                 :      10361 :         bool has_one_clone = false;
    7502                 :            : 
    7503                 :            :         /* Check if this is a snapshot with clones */
    7504   [ +  -  +  -  :      10361 :         snapshot_entry = bs_get_snapshot_entry(blob->bs, blob->id);
             +  -  +  - ]
    7505         [ +  + ]:      10361 :         if (snapshot_entry != NULL) {
    7506   [ +  +  +  -  :       1072 :                 if (snapshot_entry->clone_count > 1) {
                   +  + ]
    7507                 :        144 :                         SPDK_ERRLOG("Cannot remove snapshot with more than one clone\n");
    7508                 :        144 :                         return -EBUSY;
    7509   [ +  +  +  -  :        928 :                 } else if (snapshot_entry->clone_count == 1) {
                   +  + ]
    7510                 :        427 :                         has_one_clone = true;
    7511                 :         70 :                 }
    7512                 :        150 :         }
    7513                 :            : 
    7514                 :            :         /* Check if someone has this blob open (besides this delete context):
    7515                 :            :          * - open_ref = 1 - only this context opened blob, so it is ok to remove it
    7516                 :            :          * - open_ref <= 2 && has_one_clone = true - clone is holding snapshot
    7517                 :            :          *      and that is ok, because we will update it accordingly */
    7518   [ +  +  +  +  :      10217 :         if (blob->open_ref <= 2 && has_one_clone) {
          +  +  +  -  +  
                      + ]
    7519   [ +  -  +  -  :        427 :                 clone_entry = TAILQ_FIRST(&snapshot_entry->clones);
                   +  - ]
    7520   [ +  +  #  # ]:        427 :                 assert(clone_entry != NULL);
    7521   [ +  -  +  -  :        427 :                 clone = blob_lookup(blob->bs, clone_entry->id);
             +  -  +  - ]
    7522                 :            : 
    7523   [ +  +  +  +  :        427 :                 if (blob->open_ref == 2 && clone == NULL) {
             +  +  +  - ]
    7524                 :            :                         /* Clone is closed and someone else opened this blob */
    7525                 :          0 :                         SPDK_ERRLOG("Cannot remove snapshot because it is open\n");
    7526                 :          0 :                         return -EBUSY;
    7527                 :            :                 }
    7528                 :            : 
    7529         [ +  - ]:        427 :                 *update_clone = true;
    7530                 :        427 :                 return 0;
    7531                 :            :         }
    7532                 :            : 
    7533   [ +  +  +  -  :       9790 :         if (blob->open_ref > 1) {
                   +  + ]
    7534                 :         96 :                 SPDK_ERRLOG("Cannot remove snapshot because it is open\n");
    7535                 :         96 :                 return -EBUSY;
    7536                 :            :         }
    7537                 :            : 
    7538   [ +  +  +  -  :       9694 :         assert(has_one_clone == false);
                   #  # ]
    7539         [ +  - ]:       9694 :         *update_clone = false;
    7540                 :       9694 :         return 0;
    7541                 :       1482 : }
    7542                 :            : 
    7543                 :            : static void
    7544                 :          0 : bs_delete_enomem_close_cpl(void *cb_arg, int bserrno)
    7545                 :            : {
    7546                 :          0 :         spdk_bs_sequence_t *seq = cb_arg;
    7547                 :            : 
    7548                 :          0 :         bs_sequence_finish(seq, -ENOMEM);
    7549                 :          0 : }
    7550                 :            : 
    7551                 :            : static void
    7552                 :      10421 : bs_delete_open_cpl(void *cb_arg, struct spdk_blob *blob, int bserrno)
    7553                 :            : {
    7554                 :      10421 :         spdk_bs_sequence_t *seq = cb_arg;
    7555                 :       1492 :         struct delete_snapshot_ctx *ctx;
    7556                 :      10421 :         bool update_clone = false;
    7557                 :            : 
    7558         [ +  + ]:      10421 :         if (bserrno != 0) {
    7559                 :         60 :                 bs_sequence_finish(seq, bserrno);
    7560                 :        100 :                 return;
    7561                 :            :         }
    7562                 :            : 
    7563                 :      10361 :         blob_verify_md_op(blob);
    7564                 :            : 
    7565                 :      10361 :         ctx = calloc(1, sizeof(*ctx));
    7566         [ +  + ]:      10361 :         if (ctx == NULL) {
    7567                 :          0 :                 spdk_blob_close(blob, bs_delete_enomem_close_cpl, seq);
    7568                 :          0 :                 return;
    7569                 :            :         }
    7570                 :            : 
    7571   [ +  -  +  - ]:      10361 :         ctx->snapshot = blob;
    7572   [ +  -  +  - ]:      10361 :         ctx->cb_fn = bs_delete_blob_finish;
    7573   [ +  -  +  - ]:      10361 :         ctx->cb_arg = seq;
    7574                 :            : 
    7575                 :            :         /* Check if blob can be removed and if it is a snapshot with clone on top of it */
    7576   [ +  -  +  - ]:      10361 :         ctx->bserrno = bs_is_blob_deletable(blob, &update_clone);
    7577   [ +  +  +  -  :      10361 :         if (ctx->bserrno) {
                   +  + ]
    7578                 :        240 :                 spdk_blob_close(blob, delete_blob_cleanup_finish, ctx);
    7579                 :        240 :                 return;
    7580                 :            :         }
    7581                 :            : 
    7582   [ +  +  +  +  :      10121 :         if (blob->locked_operation_in_progress) {
             +  -  -  + ]
    7583   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob, "Cannot remove blob - another operation in progress\n");
                   #  # ]
    7584   [ #  #  #  # ]:          0 :                 ctx->bserrno = -EBUSY;
    7585                 :          0 :                 spdk_blob_close(blob, delete_blob_cleanup_finish, ctx);
    7586                 :          0 :                 return;
    7587                 :            :         }
    7588                 :            : 
    7589   [ +  -  +  - ]:      10121 :         blob->locked_operation_in_progress = true;
    7590                 :            : 
    7591                 :            :         /*
    7592                 :            :          * Remove the blob from the blob_store list now, to ensure it does not
    7593                 :            :          *  get returned after this point by blob_lookup().
    7594                 :            :          */
    7595   [ +  -  +  -  :      10121 :         spdk_bit_array_clear(blob->bs->open_blobids, blob->id);
          +  -  +  -  +  
                -  +  - ]
    7596   [ +  -  +  -  :      10121 :         RB_REMOVE(spdk_blob_tree, &blob->bs->open_blobs, blob);
                   +  - ]
    7597                 :            : 
    7598   [ +  +  +  + ]:      10121 :         if (update_clone) {
    7599   [ +  -  +  - ]:        427 :                 ctx->page = spdk_zmalloc(SPDK_BS_PAGE_SIZE, 0, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    7600   [ +  +  +  -  :        427 :                 if (!ctx->page) {
                   +  - ]
    7601   [ #  #  #  # ]:          0 :                         ctx->bserrno = -ENOMEM;
    7602                 :          0 :                         spdk_blob_close(blob, delete_blob_cleanup_finish, ctx);
    7603                 :          0 :                         return;
    7604                 :            :                 }
    7605                 :            :                 /* This blob is a snapshot with active clone - update clone first */
    7606                 :        427 :                 update_clone_on_snapshot_deletion(blob, ctx);
    7607                 :         70 :         } else {
    7608                 :            :                 /* This blob does not have any clones - just remove it */
    7609                 :       9694 :                 bs_blob_list_remove(blob);
    7610                 :       9694 :                 bs_delete_blob_finish(seq, blob, 0);
    7611                 :       9694 :                 free(ctx);
    7612                 :            :         }
    7613         [ -  + ]:       1492 : }
    7614                 :            : 
    7615                 :            : void
    7616                 :      10421 : spdk_bs_delete_blob(struct spdk_blob_store *bs, spdk_blob_id blobid,
    7617                 :            :                     spdk_blob_op_complete cb_fn, void *cb_arg)
    7618                 :            : {
    7619                 :       8778 :         struct spdk_bs_cpl      cpl;
    7620                 :       1492 :         spdk_bs_sequence_t      *seq;
    7621                 :            : 
    7622   [ +  +  +  +  :      10421 :         SPDK_DEBUGLOG(blob, "Deleting blob 0x%" PRIx64 "\n", blobid);
                   +  - ]
    7623                 :            : 
    7624   [ +  +  +  -  :      10421 :         assert(spdk_get_thread() == bs->md_thread);
             +  -  #  # ]
    7625                 :            : 
    7626                 :      10421 :         cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    7627   [ +  -  +  -  :      10421 :         cpl.u.blob_basic.cb_fn = cb_fn;
                   +  - ]
    7628   [ +  -  +  -  :      10421 :         cpl.u.blob_basic.cb_arg = cb_arg;
                   +  - ]
    7629                 :            : 
    7630   [ +  -  +  - ]:      10421 :         seq = bs_sequence_start_bs(bs->md_channel, &cpl);
    7631         [ +  + ]:      10421 :         if (!seq) {
    7632   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    7633                 :          0 :                 return;
    7634                 :            :         }
    7635                 :            : 
    7636                 :      10421 :         spdk_bs_open_blob(bs, blobid, bs_delete_open_cpl, seq);
    7637         [ -  + ]:       1492 : }
    7638                 :            : 
    7639                 :            : /* END spdk_bs_delete_blob */
    7640                 :            : 
    7641                 :            : /* START spdk_bs_open_blob */
    7642                 :            : 
    7643                 :            : static void
    7644                 :      40159 : bs_open_blob_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    7645                 :            : {
    7646                 :      40159 :         struct spdk_blob *blob = cb_arg;
    7647                 :       3278 :         struct spdk_blob *existing;
    7648                 :            : 
    7649         [ +  + ]:      40159 :         if (bserrno != 0) {
    7650                 :        384 :                 blob_free(blob);
    7651   [ +  -  +  -  :        384 :                 seq->cpl.u.blob_handle.blob = NULL;
          +  -  +  -  +  
                      - ]
    7652                 :        384 :                 bs_sequence_finish(seq, bserrno);
    7653                 :        384 :                 return;
    7654                 :            :         }
    7655                 :            : 
    7656   [ +  -  +  -  :      39775 :         existing = blob_lookup(blob->bs, blob->id);
             +  -  +  - ]
    7657         [ +  + ]:      39775 :         if (existing) {
    7658                 :         36 :                 blob_free(blob);
    7659         [ +  - ]:         36 :                 existing->open_ref++;
    7660   [ +  -  +  -  :         36 :                 seq->cpl.u.blob_handle.blob = existing;
          +  -  +  -  +  
                      - ]
    7661                 :         36 :                 bs_sequence_finish(seq, 0);
    7662                 :         36 :                 return;
    7663                 :            :         }
    7664                 :            : 
    7665         [ +  - ]:      39739 :         blob->open_ref++;
    7666                 :            : 
    7667   [ +  -  +  -  :      39739 :         spdk_bit_array_set(blob->bs->open_blobids, blob->id);
          +  -  +  -  +  
                -  +  - ]
    7668   [ +  -  +  -  :      39739 :         RB_INSERT(spdk_blob_tree, &blob->bs->open_blobs, blob);
                   +  - ]
    7669                 :            : 
    7670                 :      39739 :         bs_sequence_finish(seq, bserrno);
    7671         [ -  + ]:       3278 : }
    7672                 :            : 
    7673                 :            : static inline void
    7674                 :        587 : blob_open_opts_copy(const struct spdk_blob_open_opts *src, struct spdk_blob_open_opts *dst)
    7675                 :            : {
    7676                 :            : #define FIELD_OK(field) \
    7677                 :            :         offsetof(struct spdk_blob_open_opts, field) + sizeof(src->field) <= src->opts_size
    7678                 :            : 
    7679                 :            : #define SET_FIELD(field) \
    7680                 :            :         if (FIELD_OK(field)) { \
    7681                 :            :                 dst->field = src->field; \
    7682                 :            :         } \
    7683                 :            : 
    7684   [ +  -  +  -  :        587 :         SET_FIELD(clear_method);
          -  +  +  -  +  
             -  +  -  +  
                      - ]
    7685   [ +  -  +  -  :        587 :         SET_FIELD(esnap_ctx);
          -  +  +  -  +  
             -  +  -  +  
                      - ]
    7686                 :            : 
    7687   [ +  -  +  -  :        587 :         dst->opts_size = src->opts_size;
             +  -  +  - ]
    7688                 :            : 
    7689                 :            :         /* You should not remove this statement, but need to update the assert statement
    7690                 :            :          * if you add a new field, and also add a corresponding SET_FIELD statement */
    7691                 :            :         SPDK_STATIC_ASSERT(sizeof(struct spdk_blob_open_opts) == 24, "Incorrect size");
    7692                 :            : 
    7693                 :            : #undef FIELD_OK
    7694                 :            : #undef SET_FIELD
    7695                 :        587 : }
    7696                 :            : 
    7697                 :            : static void
    7698                 :      44307 : bs_open_blob(struct spdk_blob_store *bs,
    7699                 :            :              spdk_blob_id blobid,
    7700                 :            :              struct spdk_blob_open_opts *opts,
    7701                 :            :              spdk_blob_op_with_handle_complete cb_fn,
    7702                 :            :              void *cb_arg)
    7703                 :            : {
    7704                 :       3939 :         struct spdk_blob                *blob;
    7705                 :      39697 :         struct spdk_bs_cpl              cpl;
    7706                 :      39697 :         struct spdk_blob_open_opts      opts_local;
    7707                 :       3939 :         spdk_bs_sequence_t              *seq;
    7708                 :       3939 :         uint32_t                        page_num;
    7709                 :            : 
    7710   [ +  +  +  +  :      44307 :         SPDK_DEBUGLOG(blob, "Opening blob 0x%" PRIx64 "\n", blobid);
                   +  - ]
    7711   [ +  +  +  -  :      44307 :         assert(spdk_get_thread() == bs->md_thread);
             +  -  #  # ]
    7712                 :            : 
    7713                 :      44307 :         page_num = bs_blobid_to_page(blobid);
    7714   [ +  +  +  -  :      44307 :         if (spdk_bit_array_get(bs->used_blobids, page_num) == false) {
                   +  + ]
    7715                 :            :                 /* Invalid blobid */
    7716   [ -  +  +  - ]:        288 :                 cb_fn(cb_arg, NULL, -ENOENT);
    7717                 :        936 :                 return;
    7718                 :            :         }
    7719                 :            : 
    7720                 :      44019 :         blob = blob_lookup(bs, blobid);
    7721         [ +  + ]:      44019 :         if (blob) {
    7722         [ +  - ]:       3860 :                 blob->open_ref++;
    7723   [ -  +  +  - ]:       3860 :                 cb_fn(cb_arg, blob, 0);
    7724                 :       3860 :                 return;
    7725                 :            :         }
    7726                 :            : 
    7727                 :      40159 :         blob = blob_alloc(bs, blobid);
    7728         [ +  + ]:      40159 :         if (!blob) {
    7729   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    7730                 :          0 :                 return;
    7731                 :            :         }
    7732                 :            : 
    7733                 :      40159 :         spdk_blob_open_opts_init(&opts_local, sizeof(opts_local));
    7734         [ +  + ]:      40159 :         if (opts) {
    7735                 :        587 :                 blob_open_opts_copy(opts, &opts_local);
    7736                 :          4 :         }
    7737                 :            : 
    7738   [ +  -  +  - ]:      40159 :         blob->clear_method = opts_local.clear_method;
    7739                 :            : 
    7740                 :      40159 :         cpl.type = SPDK_BS_CPL_TYPE_BLOB_HANDLE;
    7741   [ +  -  +  -  :      40159 :         cpl.u.blob_handle.cb_fn = cb_fn;
                   +  - ]
    7742   [ +  -  +  -  :      40159 :         cpl.u.blob_handle.cb_arg = cb_arg;
                   +  - ]
    7743   [ +  -  +  -  :      40159 :         cpl.u.blob_handle.blob = blob;
                   +  - ]
    7744   [ +  -  +  -  :      40159 :         cpl.u.blob_handle.esnap_ctx = opts_local.esnap_ctx;
             +  -  +  - ]
    7745                 :            : 
    7746   [ +  -  +  - ]:      40159 :         seq = bs_sequence_start_bs(bs->md_channel, &cpl);
    7747         [ +  + ]:      40159 :         if (!seq) {
    7748                 :          0 :                 blob_free(blob);
    7749   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    7750                 :          0 :                 return;
    7751                 :            :         }
    7752                 :            : 
    7753                 :      40159 :         blob_load(seq, blob, bs_open_blob_cpl, blob);
    7754         [ -  + ]:       3939 : }
    7755                 :            : 
    7756                 :            : void
    7757                 :      43691 : spdk_bs_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid,
    7758                 :            :                   spdk_blob_op_with_handle_complete cb_fn, void *cb_arg)
    7759                 :            : {
    7760                 :      43691 :         bs_open_blob(bs, blobid, NULL, cb_fn, cb_arg);
    7761                 :      43691 : }
    7762                 :            : 
    7763                 :            : void
    7764                 :        616 : spdk_bs_open_blob_ext(struct spdk_blob_store *bs, spdk_blob_id blobid,
    7765                 :            :                       struct spdk_blob_open_opts *opts, spdk_blob_op_with_handle_complete cb_fn, void *cb_arg)
    7766                 :            : {
    7767                 :        616 :         bs_open_blob(bs, blobid, opts, cb_fn, cb_arg);
    7768                 :        616 : }
    7769                 :            : 
    7770                 :            : /* END spdk_bs_open_blob */
    7771                 :            : 
    7772                 :            : /* START spdk_blob_set_read_only */
    7773                 :            : int
    7774                 :       1232 : spdk_blob_set_read_only(struct spdk_blob *blob)
    7775                 :            : {
    7776                 :       1232 :         blob_verify_md_op(blob);
    7777                 :            : 
    7778   [ +  -  +  -  :       1232 :         blob->data_ro_flags |= SPDK_BLOB_READ_ONLY;
                   +  - ]
    7779                 :            : 
    7780   [ +  -  +  - ]:       1232 :         blob->state = SPDK_BLOB_STATE_DIRTY;
    7781                 :       1232 :         return 0;
    7782                 :            : }
    7783                 :            : /* END spdk_blob_set_read_only */
    7784                 :            : 
    7785                 :            : /* START spdk_blob_sync_md */
    7786                 :            : 
    7787                 :            : static void
    7788                 :     157828 : blob_sync_md_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    7789                 :            : {
    7790                 :     157828 :         struct spdk_blob *blob = cb_arg;
    7791                 :            : 
    7792   [ +  -  +  +  :     157828 :         if (bserrno == 0 && (blob->data_ro_flags & SPDK_BLOB_READ_ONLY)) {
          +  -  +  -  +  
                      + ]
    7793   [ +  -  +  - ]:       2254 :                 blob->data_ro = true;
    7794   [ +  -  +  - ]:       2254 :                 blob->md_ro = true;
    7795                 :        368 :         }
    7796                 :            : 
    7797                 :     157828 :         bs_sequence_finish(seq, bserrno);
    7798                 :     157828 : }
    7799                 :            : 
    7800                 :            : static void
    7801                 :     157828 : blob_sync_md(struct spdk_blob *blob, spdk_blob_op_complete cb_fn, void *cb_arg)
    7802                 :            : {
    7803                 :     156378 :         struct spdk_bs_cpl      cpl;
    7804                 :       1331 :         spdk_bs_sequence_t      *seq;
    7805                 :            : 
    7806                 :     157828 :         cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    7807   [ +  -  +  -  :     157828 :         cpl.u.blob_basic.cb_fn = cb_fn;
                   +  - ]
    7808   [ +  -  +  -  :     157828 :         cpl.u.blob_basic.cb_arg = cb_arg;
                   +  - ]
    7809                 :            : 
    7810   [ +  -  +  -  :     157828 :         seq = bs_sequence_start_bs(blob->bs->md_channel, &cpl);
             +  -  +  - ]
    7811         [ +  + ]:     157828 :         if (!seq) {
    7812   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    7813                 :          0 :                 return;
    7814                 :            :         }
    7815                 :            : 
    7816                 :     157828 :         blob_persist(seq, blob, blob_sync_md_cpl, blob);
    7817         [ -  + ]:       1331 : }
    7818                 :            : 
    7819                 :            : void
    7820                 :     154657 : spdk_blob_sync_md(struct spdk_blob *blob, spdk_blob_op_complete cb_fn, void *cb_arg)
    7821                 :            : {
    7822                 :     154657 :         blob_verify_md_op(blob);
    7823                 :            : 
    7824   [ +  +  +  +  :     154657 :         SPDK_DEBUGLOG(blob, "Syncing blob 0x%" PRIx64 "\n", blob->id);
          +  -  #  #  #  
                      # ]
    7825                 :            : 
    7826   [ +  +  +  +  :     154657 :         if (blob->md_ro) {
             +  -  +  + ]
    7827   [ +  +  +  -  :         24 :                 assert(blob->state == SPDK_BLOB_STATE_CLEAN);
             +  -  #  # ]
    7828   [ -  +  +  - ]:         24 :                 cb_fn(cb_arg, 0);
    7829                 :         24 :                 return;
    7830                 :            :         }
    7831                 :            : 
    7832                 :     154633 :         blob_sync_md(blob, cb_fn, cb_arg);
    7833                 :        961 : }
    7834                 :            : 
    7835                 :            : /* END spdk_blob_sync_md */
    7836                 :            : 
    7837                 :            : struct spdk_blob_insert_cluster_ctx {
    7838                 :            :         struct spdk_thread      *thread;
    7839                 :            :         struct spdk_blob        *blob;
    7840                 :            :         uint32_t                cluster_num;    /* cluster index in blob */
    7841                 :            :         uint32_t                cluster;        /* cluster on disk */
    7842                 :            :         uint32_t                extent_page;    /* extent page on disk */
    7843                 :            :         struct spdk_blob_md_page *page; /* preallocated extent page */
    7844                 :            :         int                     rc;
    7845                 :            :         spdk_blob_op_complete   cb_fn;
    7846                 :            :         void                    *cb_arg;
    7847                 :            : };
    7848                 :            : 
    7849                 :            : static void
    7850                 :      27288 : blob_insert_cluster_msg_cpl(void *arg)
    7851                 :            : {
    7852                 :      27288 :         struct spdk_blob_insert_cluster_ctx *ctx = arg;
    7853                 :            : 
    7854   [ +  -  +  -  :      27288 :         ctx->cb_fn(ctx->cb_arg, ctx->rc);
          -  +  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7855                 :      27288 :         free(ctx);
    7856                 :      27288 : }
    7857                 :            : 
    7858                 :            : static void
    7859                 :      27253 : blob_insert_cluster_msg_cb(void *arg, int bserrno)
    7860                 :            : {
    7861                 :      27253 :         struct spdk_blob_insert_cluster_ctx *ctx = arg;
    7862                 :            : 
    7863   [ +  -  +  - ]:      27253 :         ctx->rc = bserrno;
    7864   [ +  -  +  - ]:      27253 :         spdk_thread_send_msg(ctx->thread, blob_insert_cluster_msg_cpl, ctx);
    7865                 :      27253 : }
    7866                 :            : 
    7867                 :            : static void
    7868                 :       1371 : blob_insert_new_ep_cb(void *arg, int bserrno)
    7869                 :            : {
    7870                 :       1371 :         struct spdk_blob_insert_cluster_ctx *ctx = arg;
    7871                 :         70 :         uint32_t *extent_page;
    7872                 :            : 
    7873   [ +  -  +  -  :       1371 :         extent_page = bs_cluster_to_extent_page(ctx->blob, ctx->cluster_num);
             +  -  +  - ]
    7874   [ +  -  +  -  :       1371 :         *extent_page = ctx->extent_page;
                   +  - ]
    7875   [ +  -  +  -  :       1371 :         ctx->blob->state = SPDK_BLOB_STATE_DIRTY;
             +  -  +  - ]
    7876   [ +  -  +  - ]:       1371 :         blob_sync_md(ctx->blob, blob_insert_cluster_msg_cb, ctx);
    7877                 :       1371 : }
    7878                 :            : 
    7879                 :            : struct spdk_blob_write_extent_page_ctx {
    7880                 :            :         struct spdk_blob_store          *bs;
    7881                 :            : 
    7882                 :            :         uint32_t                        extent;
    7883                 :            :         struct spdk_blob_md_page        *page;
    7884                 :            : };
    7885                 :            : 
    7886                 :            : static void
    7887                 :      25444 : blob_persist_extent_page_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    7888                 :            : {
    7889                 :      25444 :         struct spdk_blob_write_extent_page_ctx *ctx = cb_arg;
    7890                 :            : 
    7891                 :      25444 :         free(ctx);
    7892                 :      25444 :         bs_sequence_finish(seq, bserrno);
    7893                 :      25444 : }
    7894                 :            : 
    7895                 :            : static void
    7896                 :      25444 : blob_write_extent_page_ready(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    7897                 :            : {
    7898                 :      25444 :         struct spdk_blob_write_extent_page_ctx *ctx = cb_arg;
    7899                 :            : 
    7900         [ -  + ]:      25444 :         if (bserrno != 0) {
    7901                 :          0 :                 blob_persist_extent_page_cpl(seq, ctx, bserrno);
    7902                 :          0 :                 return;
    7903                 :            :         }
    7904   [ +  -  +  -  :      25750 :         bs_sequence_write_dev(seq, ctx->page, bs_md_page_to_lba(ctx->bs, ctx->extent),
          +  -  +  -  +  
                -  +  - ]
    7905   [ +  -  +  - ]:      25444 :                               bs_byte_to_lba(ctx->bs, SPDK_BS_PAGE_SIZE),
    7906                 :        306 :                               blob_persist_extent_page_cpl, ctx);
    7907         [ -  + ]:        306 : }
    7908                 :            : 
    7909                 :            : static void
    7910                 :      25444 : blob_write_extent_page(struct spdk_blob *blob, uint32_t extent, uint64_t cluster_num,
    7911                 :            :                        struct spdk_blob_md_page *page, spdk_blob_op_complete cb_fn, void *cb_arg)
    7912                 :            : {
    7913                 :        306 :         struct spdk_blob_write_extent_page_ctx  *ctx;
    7914                 :        306 :         spdk_bs_sequence_t                      *seq;
    7915                 :      24991 :         struct spdk_bs_cpl                      cpl;
    7916                 :            : 
    7917                 :      25444 :         ctx = calloc(1, sizeof(*ctx));
    7918         [ +  + ]:      25444 :         if (!ctx) {
    7919   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    7920                 :          0 :                 return;
    7921                 :            :         }
    7922   [ +  -  +  -  :      25444 :         ctx->bs = blob->bs;
             +  -  +  - ]
    7923   [ +  -  +  - ]:      25444 :         ctx->extent = extent;
    7924   [ +  -  +  - ]:      25444 :         ctx->page = page;
    7925                 :            : 
    7926                 :      25444 :         cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    7927   [ +  -  +  -  :      25444 :         cpl.u.blob_basic.cb_fn = cb_fn;
                   +  - ]
    7928   [ +  -  +  -  :      25444 :         cpl.u.blob_basic.cb_arg = cb_arg;
                   +  - ]
    7929                 :            : 
    7930   [ +  -  +  -  :      25444 :         seq = bs_sequence_start_bs(blob->bs->md_channel, &cpl);
             +  -  +  - ]
    7931         [ +  + ]:      25444 :         if (!seq) {
    7932                 :          0 :                 free(ctx);
    7933   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    7934                 :          0 :                 return;
    7935                 :            :         }
    7936                 :            : 
    7937   [ +  +  #  # ]:      25444 :         assert(page);
    7938   [ +  -  +  - ]:      25444 :         page->next = SPDK_INVALID_MD_PAGE;
    7939   [ +  -  +  -  :      25444 :         page->id = blob->id;
             +  -  +  - ]
    7940   [ +  -  +  - ]:      25444 :         page->sequence_num = 0;
    7941                 :            : 
    7942                 :      25444 :         blob_serialize_extent_page(blob, cluster_num, page);
    7943                 :            : 
    7944   [ +  -  +  - ]:      25444 :         page->crc = blob_md_page_calc_crc(page);
    7945                 :            : 
    7946   [ +  +  +  -  :      25444 :         assert(spdk_bit_array_get(blob->bs->used_md_pages, extent) == true);
          +  -  +  -  +  
                -  #  # ]
    7947                 :            : 
    7948   [ +  -  +  - ]:      25444 :         bs_mark_dirty(seq, blob->bs, blob_write_extent_page_ready, ctx);
    7949         [ -  + ]:        306 : }
    7950                 :            : 
    7951                 :            : static void
    7952                 :      27288 : blob_insert_cluster_msg(void *arg)
    7953                 :            : {
    7954                 :      27288 :         struct spdk_blob_insert_cluster_ctx *ctx = arg;
    7955                 :        612 :         uint32_t *extent_page;
    7956                 :            : 
    7957   [ +  -  +  -  :      27288 :         ctx->rc = blob_insert_cluster(ctx->blob, ctx->cluster_num, ctx->cluster);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7958   [ +  +  +  -  :      27288 :         if (ctx->rc != 0) {
                   +  + ]
    7959   [ +  -  +  - ]:         35 :                 spdk_thread_send_msg(ctx->thread, blob_insert_cluster_msg_cpl, ctx);
    7960                 :         35 :                 return;
    7961                 :            :         }
    7962                 :            : 
    7963   [ +  +  +  +  :      27253 :         if (ctx->blob->use_extent_table == false) {
          +  -  +  -  +  
                -  +  + ]
    7964                 :            :                 /* Extent table is not used, proceed with sync of md that will only use extents_rle. */
    7965   [ +  -  +  -  :       1824 :                 ctx->blob->state = SPDK_BLOB_STATE_DIRTY;
             +  -  +  - ]
    7966   [ +  -  +  - ]:       1824 :                 blob_sync_md(ctx->blob, blob_insert_cluster_msg_cb, ctx);
    7967                 :       1824 :                 return;
    7968                 :            :         }
    7969                 :            : 
    7970   [ +  -  +  -  :      25429 :         extent_page = bs_cluster_to_extent_page(ctx->blob, ctx->cluster_num);
             +  -  +  - ]
    7971   [ +  +  +  + ]:      25429 :         if (*extent_page == 0) {
    7972                 :            :                 /* Extent page requires allocation.
    7973                 :            :                  * It was already claimed in the used_md_pages map and placed in ctx. */
    7974   [ +  +  +  -  :       1371 :                 assert(ctx->extent_page != 0);
             +  -  #  # ]
    7975   [ +  +  +  -  :       1371 :                 assert(spdk_bit_array_get(ctx->blob->bs->used_md_pages, ctx->extent_page) == true);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    7976   [ +  -  +  -  :       1371 :                 blob_write_extent_page(ctx->blob, ctx->extent_page, ctx->cluster_num, ctx->page,
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    7977                 :         70 :                                        blob_insert_new_ep_cb, ctx);
    7978                 :         70 :         } else {
    7979                 :            :                 /* It is possible for original thread to allocate extent page for
    7980                 :            :                  * different cluster in the same extent page. In such case proceed with
    7981                 :            :                  * updating the existing extent page, but release the additional one. */
    7982   [ +  +  +  -  :      24058 :                 if (ctx->extent_page != 0) {
                   +  - ]
    7983   [ #  #  #  #  :          2 :                         spdk_spin_lock(&ctx->blob->bs->used_lock);
          #  #  #  #  #  
                      # ]
    7984   [ -  +  #  #  :          2 :                         assert(spdk_bit_array_get(ctx->blob->bs->used_md_pages, ctx->extent_page) == true);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
    7985   [ #  #  #  #  :          2 :                         bs_release_md_page(ctx->blob->bs, ctx->extent_page);
          #  #  #  #  #  
                #  #  # ]
    7986   [ #  #  #  #  :          2 :                         spdk_spin_unlock(&ctx->blob->bs->used_lock);
          #  #  #  #  #  
                      # ]
    7987   [ #  #  #  # ]:          2 :                         ctx->extent_page = 0;
    7988                 :          0 :                 }
    7989                 :            :                 /* Extent page already allocated.
    7990                 :            :                  * Every cluster allocation, requires just an update of single extent page. */
    7991   [ -  +  -  +  :      24058 :                 blob_write_extent_page(ctx->blob, *extent_page, ctx->cluster_num, ctx->page,
          -  +  -  +  -  
             +  -  +  -  
                      + ]
    7992                 :        234 :                                        blob_insert_cluster_msg_cb, ctx);
    7993                 :            :         }
    7994         [ -  + ]:        612 : }
    7995                 :            : 
    7996                 :            : static void
    7997                 :      27288 : blob_insert_cluster_on_md_thread(struct spdk_blob *blob, uint32_t cluster_num,
    7998                 :            :                                  uint64_t cluster, uint32_t extent_page, struct spdk_blob_md_page *page,
    7999                 :            :                                  spdk_blob_op_complete cb_fn, void *cb_arg)
    8000                 :            : {
    8001                 :        612 :         struct spdk_blob_insert_cluster_ctx *ctx;
    8002                 :            : 
    8003                 :      27288 :         ctx = calloc(1, sizeof(*ctx));
    8004         [ +  + ]:      27288 :         if (ctx == NULL) {
    8005   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    8006                 :          0 :                 return;
    8007                 :            :         }
    8008                 :            : 
    8009   [ +  -  +  - ]:      27288 :         ctx->thread = spdk_get_thread();
    8010   [ +  -  +  - ]:      27288 :         ctx->blob = blob;
    8011   [ +  -  +  - ]:      27288 :         ctx->cluster_num = cluster_num;
    8012   [ +  -  +  - ]:      27288 :         ctx->cluster = cluster;
    8013   [ +  -  +  - ]:      27288 :         ctx->extent_page = extent_page;
    8014   [ +  -  +  - ]:      27288 :         ctx->page = page;
    8015   [ +  -  +  - ]:      27288 :         ctx->cb_fn = cb_fn;
    8016   [ +  -  +  - ]:      27288 :         ctx->cb_arg = cb_arg;
    8017                 :            : 
    8018   [ +  -  +  -  :      27288 :         spdk_thread_send_msg(blob->bs->md_thread, blob_insert_cluster_msg, ctx);
             +  -  +  - ]
    8019         [ -  + ]:        612 : }
    8020                 :            : 
    8021                 :            : /* START spdk_blob_close */
    8022                 :            : 
    8023                 :            : static void
    8024                 :      43635 : blob_close_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    8025                 :            : {
    8026                 :      43635 :         struct spdk_blob *blob = cb_arg;
    8027                 :            : 
    8028         [ +  + ]:      43635 :         if (bserrno == 0) {
    8029         [ +  - ]:      43635 :                 blob->open_ref--;
    8030   [ +  +  +  -  :      43635 :                 if (blob->open_ref == 0) {
                   +  + ]
    8031                 :            :                         /*
    8032                 :            :                          * Blobs with active.num_pages == 0 are deleted blobs.
    8033                 :            :                          *  these blobs are removed from the blob_store list
    8034                 :            :                          *  when the deletion process starts - so don't try to
    8035                 :            :                          *  remove them again.
    8036                 :            :                          */
    8037   [ +  +  +  -  :      39739 :                         if (blob->active.num_pages > 0) {
             +  -  +  + ]
    8038   [ +  -  +  -  :      29750 :                                 spdk_bit_array_clear(blob->bs->open_blobids, blob->id);
          +  -  +  -  +  
                -  +  - ]
    8039   [ +  -  +  -  :      29750 :                                 RB_REMOVE(spdk_blob_tree, &blob->bs->open_blobs, blob);
                   +  - ]
    8040                 :       1790 :                         }
    8041                 :      39739 :                         blob_free(blob);
    8042                 :       3210 :                 }
    8043                 :       3827 :         }
    8044                 :            : 
    8045                 :      43635 :         bs_sequence_finish(seq, bserrno);
    8046                 :      43635 : }
    8047                 :            : 
    8048                 :            : static void
    8049                 :        576 : blob_close_esnap_done(void *cb_arg, struct spdk_blob *blob, int bserrno)
    8050                 :            : {
    8051                 :        576 :         spdk_bs_sequence_t      *seq = cb_arg;
    8052                 :            : 
    8053         [ -  + ]:        576 :         if (bserrno != 0) {
    8054   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": close failed with error %d\n",
          #  #  #  #  #  
                      # ]
    8055                 :            :                               blob->id, bserrno);
    8056                 :          0 :                 bs_sequence_finish(seq, bserrno);
    8057                 :          0 :                 return;
    8058                 :            :         }
    8059                 :            : 
    8060   [ +  +  +  +  :        576 :         SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": closed, syncing metadata on thread %s\n",
          +  -  #  #  #  
                      # ]
    8061                 :            :                       blob->id, spdk_thread_get_name(spdk_get_thread()));
    8062                 :            : 
    8063                 :            :         /* Sync metadata */
    8064                 :        576 :         blob_persist(seq, blob, blob_close_cpl, blob);
    8065         [ -  + ]:         84 : }
    8066                 :            : 
    8067                 :            : void
    8068                 :      43635 : spdk_blob_close(struct spdk_blob *blob, spdk_blob_op_complete cb_fn, void *cb_arg)
    8069                 :            : {
    8070                 :      39137 :         struct spdk_bs_cpl      cpl;
    8071                 :       3827 :         spdk_bs_sequence_t      *seq;
    8072                 :            : 
    8073                 :      43635 :         blob_verify_md_op(blob);
    8074                 :            : 
    8075   [ +  +  +  +  :      43635 :         SPDK_DEBUGLOG(blob, "Closing blob 0x%" PRIx64 "\n", blob->id);
          +  -  #  #  #  
                      # ]
    8076                 :            : 
    8077   [ +  +  +  -  :      43635 :         if (blob->open_ref == 0) {
                   +  - ]
    8078   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -EBADF);
    8079                 :         84 :                 return;
    8080                 :            :         }
    8081                 :            : 
    8082                 :      43635 :         cpl.type = SPDK_BS_CPL_TYPE_BLOB_BASIC;
    8083   [ +  -  +  -  :      43635 :         cpl.u.blob_basic.cb_fn = cb_fn;
                   +  - ]
    8084   [ +  -  +  -  :      43635 :         cpl.u.blob_basic.cb_arg = cb_arg;
                   +  - ]
    8085                 :            : 
    8086   [ +  -  +  -  :      43635 :         seq = bs_sequence_start_bs(blob->bs->md_channel, &cpl);
             +  -  +  - ]
    8087         [ +  + ]:      43635 :         if (!seq) {
    8088   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    8089                 :          0 :                 return;
    8090                 :            :         }
    8091                 :            : 
    8092   [ +  +  +  +  :      43635 :         if (blob->open_ref == 1 && blob_is_esnap_clone(blob)) {
             +  +  +  + ]
    8093                 :        576 :                 blob_esnap_destroy_bs_dev_channels(blob, false, blob_close_esnap_done, seq);
    8094                 :        576 :                 return;
    8095                 :            :         }
    8096                 :            : 
    8097                 :            :         /* Sync metadata */
    8098                 :      43059 :         blob_persist(seq, blob, blob_close_cpl, blob);
    8099         [ -  + ]:       3827 : }
    8100                 :            : 
    8101                 :            : /* END spdk_blob_close */
    8102                 :            : 
    8103                 :       2410 : struct spdk_io_channel *spdk_bs_alloc_io_channel(struct spdk_blob_store *bs)
    8104                 :            : {
    8105                 :       2410 :         return spdk_get_io_channel(bs);
    8106                 :            : }
    8107                 :            : 
    8108                 :            : void
    8109                 :       1298 : spdk_bs_free_io_channel(struct spdk_io_channel *channel)
    8110                 :            : {
    8111                 :       1298 :         blob_esnap_destroy_bs_channel(spdk_io_channel_get_ctx(channel));
    8112                 :       1298 :         spdk_put_io_channel(channel);
    8113                 :       1298 : }
    8114                 :            : 
    8115                 :            : void
    8116                 :     197941 : spdk_blob_io_unmap(struct spdk_blob *blob, struct spdk_io_channel *channel,
    8117                 :            :                    uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg)
    8118                 :            : {
    8119                 :     197941 :         blob_request_submit_op(blob, channel, NULL, offset, length, cb_fn, cb_arg,
    8120                 :            :                                SPDK_BLOB_UNMAP);
    8121                 :     197941 : }
    8122                 :            : 
    8123                 :            : void
    8124                 :       2031 : spdk_blob_io_write_zeroes(struct spdk_blob *blob, struct spdk_io_channel *channel,
    8125                 :            :                           uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg)
    8126                 :            : {
    8127                 :       2031 :         blob_request_submit_op(blob, channel, NULL, offset, length, cb_fn, cb_arg,
    8128                 :            :                                SPDK_BLOB_WRITE_ZEROES);
    8129                 :       2031 : }
    8130                 :            : 
    8131                 :            : void
    8132                 :     873545 : spdk_blob_io_write(struct spdk_blob *blob, struct spdk_io_channel *channel,
    8133                 :            :                    void *payload, uint64_t offset, uint64_t length,
    8134                 :            :                    spdk_blob_op_complete cb_fn, void *cb_arg)
    8135                 :            : {
    8136                 :     873545 :         blob_request_submit_op(blob, channel, payload, offset, length, cb_fn, cb_arg,
    8137                 :            :                                SPDK_BLOB_WRITE);
    8138                 :     873545 : }
    8139                 :            : 
    8140                 :            : void
    8141                 :    5071658 : spdk_blob_io_read(struct spdk_blob *blob, struct spdk_io_channel *channel,
    8142                 :            :                   void *payload, uint64_t offset, uint64_t length,
    8143                 :            :                   spdk_blob_op_complete cb_fn, void *cb_arg)
    8144                 :            : {
    8145                 :    5071658 :         blob_request_submit_op(blob, channel, payload, offset, length, cb_fn, cb_arg,
    8146                 :            :                                SPDK_BLOB_READ);
    8147                 :    5071658 : }
    8148                 :            : 
    8149                 :            : void
    8150                 :        840 : spdk_blob_io_writev(struct spdk_blob *blob, struct spdk_io_channel *channel,
    8151                 :            :                     struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
    8152                 :            :                     spdk_blob_op_complete cb_fn, void *cb_arg)
    8153                 :            : {
    8154                 :        840 :         blob_request_submit_rw_iov(blob, channel, iov, iovcnt, offset, length, cb_fn, cb_arg, false, NULL);
    8155                 :        840 : }
    8156                 :            : 
    8157                 :            : void
    8158                 :       5640 : spdk_blob_io_readv(struct spdk_blob *blob, struct spdk_io_channel *channel,
    8159                 :            :                    struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
    8160                 :            :                    spdk_blob_op_complete cb_fn, void *cb_arg)
    8161                 :            : {
    8162                 :       5640 :         blob_request_submit_rw_iov(blob, channel, iov, iovcnt, offset, length, cb_fn, cb_arg, true, NULL);
    8163                 :       5640 : }
    8164                 :            : 
    8165                 :            : void
    8166                 :    8628374 : spdk_blob_io_writev_ext(struct spdk_blob *blob, struct spdk_io_channel *channel,
    8167                 :            :                         struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
    8168                 :            :                         spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
    8169                 :            : {
    8170                 :    8628582 :         blob_request_submit_rw_iov(blob, channel, iov, iovcnt, offset, length, cb_fn, cb_arg, false,
    8171                 :        208 :                                    io_opts);
    8172                 :    8628374 : }
    8173                 :            : 
    8174                 :            : void
    8175                 :    7836538 : spdk_blob_io_readv_ext(struct spdk_blob *blob, struct spdk_io_channel *channel,
    8176                 :            :                        struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
    8177                 :            :                        spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
    8178                 :            : {
    8179                 :    7837838 :         blob_request_submit_rw_iov(blob, channel, iov, iovcnt, offset, length, cb_fn, cb_arg, true,
    8180                 :       1300 :                                    io_opts);
    8181                 :    7836538 : }
    8182                 :            : 
    8183                 :            : struct spdk_bs_iter_ctx {
    8184                 :            :         int64_t page_num;
    8185                 :            :         struct spdk_blob_store *bs;
    8186                 :            : 
    8187                 :            :         spdk_blob_op_with_handle_complete cb_fn;
    8188                 :            :         void *cb_arg;
    8189                 :            : };
    8190                 :            : 
    8191                 :            : static void
    8192                 :      21177 : bs_iter_cpl(void *cb_arg, struct spdk_blob *_blob, int bserrno)
    8193                 :            : {
    8194                 :      21177 :         struct spdk_bs_iter_ctx *ctx = cb_arg;
    8195   [ +  -  +  - ]:      21177 :         struct spdk_blob_store *bs = ctx->bs;
    8196                 :       1164 :         spdk_blob_id id;
    8197                 :            : 
    8198         [ +  + ]:      21177 :         if (bserrno == 0) {
    8199   [ +  -  +  -  :       9687 :                 ctx->cb_fn(ctx->cb_arg, _blob, bserrno);
          -  +  +  -  +  
                -  +  - ]
    8200                 :       9687 :                 free(ctx);
    8201                 :       9687 :                 return;
    8202                 :            :         }
    8203                 :            : 
    8204   [ +  -  +  - ]:      11490 :         ctx->page_num++;
    8205   [ +  -  +  -  :      11490 :         ctx->page_num = spdk_bit_array_find_first_set(bs->used_blobids, ctx->page_num);
          +  -  +  -  +  
                -  +  - ]
    8206   [ +  +  +  -  :      11490 :         if (ctx->page_num >= spdk_bit_array_capacity(bs->used_blobids)) {
          +  -  +  -  +  
                      + ]
    8207   [ +  -  +  -  :       1755 :                 ctx->cb_fn(ctx->cb_arg, NULL, -ENOENT);
          -  +  +  -  +  
                -  +  - ]
    8208                 :       1755 :                 free(ctx);
    8209                 :       1755 :                 return;
    8210                 :            :         }
    8211                 :            : 
    8212   [ +  -  +  - ]:       9735 :         id = bs_page_to_blobid(ctx->page_num);
    8213                 :            : 
    8214                 :       9735 :         spdk_bs_open_blob(bs, id, bs_iter_cpl, ctx);
    8215         [ -  + ]:       1164 : }
    8216                 :            : 
    8217                 :            : void
    8218                 :       1899 : spdk_bs_iter_first(struct spdk_blob_store *bs,
    8219                 :            :                    spdk_blob_op_with_handle_complete cb_fn, void *cb_arg)
    8220                 :            : {
    8221                 :        292 :         struct spdk_bs_iter_ctx *ctx;
    8222                 :            : 
    8223                 :       1899 :         ctx = calloc(1, sizeof(*ctx));
    8224         [ +  + ]:       1899 :         if (!ctx) {
    8225   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    8226                 :          0 :                 return;
    8227                 :            :         }
    8228                 :            : 
    8229   [ +  -  +  - ]:       1899 :         ctx->page_num = -1;
    8230   [ +  -  +  - ]:       1899 :         ctx->bs = bs;
    8231   [ +  -  +  - ]:       1899 :         ctx->cb_fn = cb_fn;
    8232   [ +  -  +  - ]:       1899 :         ctx->cb_arg = cb_arg;
    8233                 :            : 
    8234                 :       1899 :         bs_iter_cpl(ctx, NULL, -1);
    8235         [ -  + ]:        292 : }
    8236                 :            : 
    8237                 :            : static void
    8238                 :       9543 : bs_iter_close_cpl(void *cb_arg, int bserrno)
    8239                 :            : {
    8240                 :       9543 :         struct spdk_bs_iter_ctx *ctx = cb_arg;
    8241                 :            : 
    8242                 :       9543 :         bs_iter_cpl(ctx, NULL, -1);
    8243                 :       9543 : }
    8244                 :            : 
    8245                 :            : void
    8246                 :       9543 : spdk_bs_iter_next(struct spdk_blob_store *bs, struct spdk_blob *blob,
    8247                 :            :                   spdk_blob_op_with_handle_complete cb_fn, void *cb_arg)
    8248                 :            : {
    8249                 :        420 :         struct spdk_bs_iter_ctx *ctx;
    8250                 :            : 
    8251   [ +  +  #  # ]:       9543 :         assert(blob != NULL);
    8252                 :            : 
    8253                 :       9543 :         ctx = calloc(1, sizeof(*ctx));
    8254         [ +  + ]:       9543 :         if (!ctx) {
    8255   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    8256                 :          0 :                 return;
    8257                 :            :         }
    8258                 :            : 
    8259   [ +  -  +  -  :       9543 :         ctx->page_num = bs_blobid_to_page(blob->id);
             +  -  +  - ]
    8260   [ +  -  +  - ]:       9543 :         ctx->bs = bs;
    8261   [ +  -  +  - ]:       9543 :         ctx->cb_fn = cb_fn;
    8262   [ +  -  +  - ]:       9543 :         ctx->cb_arg = cb_arg;
    8263                 :            : 
    8264                 :            :         /* Close the existing blob */
    8265                 :       9543 :         spdk_blob_close(blob, bs_iter_close_cpl, ctx);
    8266         [ -  + ]:        420 : }
    8267                 :            : 
    8268                 :            : static int
    8269                 :      49778 : blob_set_xattr(struct spdk_blob *blob, const char *name, const void *value,
    8270                 :            :                uint16_t value_len, bool internal)
    8271                 :            : {
    8272                 :        843 :         struct spdk_xattr_tailq *xattrs;
    8273                 :        843 :         struct spdk_xattr       *xattr;
    8274                 :        843 :         size_t                  desc_size;
    8275                 :        843 :         void                    *tmp;
    8276                 :            : 
    8277                 :      49778 :         blob_verify_md_op(blob);
    8278                 :            : 
    8279   [ +  +  +  +  :      49778 :         if (blob->md_ro) {
             +  -  +  + ]
    8280                 :         24 :                 return -EPERM;
    8281                 :            :         }
    8282                 :            : 
    8283         [ +  + ]:      49754 :         desc_size = sizeof(struct spdk_blob_md_descriptor_xattr) + strlen(name) + value_len;
    8284         [ +  + ]:      49754 :         if (desc_size > SPDK_BS_MAX_DESC_SIZE) {
    8285   [ +  +  +  +  :         24 :                 SPDK_DEBUGLOG(blob, "Xattr '%s' of size %zu does not fix into single page %zu\n", name,
                   +  - ]
    8286                 :            :                               desc_size, SPDK_BS_MAX_DESC_SIZE);
    8287                 :         24 :                 return -ENOMEM;
    8288                 :            :         }
    8289                 :            : 
    8290   [ +  +  +  + ]:      49730 :         if (internal) {
    8291         [ +  - ]:       3852 :                 xattrs = &blob->xattrs_internal;
    8292   [ +  -  +  -  :       3852 :                 blob->invalid_flags |= SPDK_BLOB_INTERNAL_XATTR;
                   +  - ]
    8293                 :        624 :         } else {
    8294         [ +  - ]:      45878 :                 xattrs = &blob->xattrs;
    8295                 :            :         }
    8296                 :            : 
    8297   [ +  +  +  -  :      92388 :         TAILQ_FOREACH(xattr, xattrs, link) {
          +  +  +  -  +  
                -  +  - ]
    8298   [ +  +  +  +  :      81467 :                 if (!strcmp(name, xattr->name)) {
          +  +  +  -  +  
                      + ]
    8299                 :      38809 :                         tmp = malloc(value_len);
    8300         [ +  + ]:      38809 :                         if (!tmp) {
    8301                 :          0 :                                 return -ENOMEM;
    8302                 :            :                         }
    8303                 :            : 
    8304   [ +  -  +  - ]:      38809 :                         free(xattr->value);
    8305   [ +  -  +  - ]:      38809 :                         xattr->value_len = value_len;
    8306   [ +  -  +  - ]:      38809 :                         xattr->value = tmp;
    8307   [ +  +  +  +  :      38809 :                         memcpy(xattr->value, value, value_len);
             +  -  +  - ]
    8308                 :            : 
    8309   [ +  -  +  - ]:      38809 :                         blob->state = SPDK_BLOB_STATE_DIRTY;
    8310                 :            : 
    8311                 :      38809 :                         return 0;
    8312                 :            :                 }
    8313                 :        207 :         }
    8314                 :            : 
    8315                 :      10921 :         xattr = calloc(1, sizeof(*xattr));
    8316         [ +  + ]:      10921 :         if (!xattr) {
    8317                 :          0 :                 return -ENOMEM;
    8318                 :            :         }
    8319                 :            : 
    8320   [ +  +  +  -  :      10921 :         xattr->name = strdup(name);
                   +  - ]
    8321   [ +  +  +  -  :      10921 :         if (!xattr->name) {
                   +  - ]
    8322                 :          0 :                 free(xattr);
    8323                 :          0 :                 return -ENOMEM;
    8324                 :            :         }
    8325                 :            : 
    8326   [ +  -  +  - ]:      10921 :         xattr->value_len = value_len;
    8327   [ +  -  +  - ]:      10921 :         xattr->value = malloc(value_len);
    8328   [ +  +  +  -  :      10921 :         if (!xattr->value) {
                   +  - ]
    8329   [ #  #  #  # ]:          0 :                 free(xattr->name);
    8330                 :          0 :                 free(xattr);
    8331                 :          0 :                 return -ENOMEM;
    8332                 :            :         }
    8333   [ +  +  +  +  :      10921 :         memcpy(xattr->value, value, value_len);
             +  -  +  - ]
    8334   [ +  -  +  -  :      10921 :         TAILQ_INSERT_TAIL(xattrs, xattr, link);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    8335                 :            : 
    8336   [ +  -  +  - ]:      10921 :         blob->state = SPDK_BLOB_STATE_DIRTY;
    8337                 :            : 
    8338                 :      10921 :         return 0;
    8339                 :        843 : }
    8340                 :            : 
    8341                 :            : int
    8342                 :      44696 : spdk_blob_set_xattr(struct spdk_blob *blob, const char *name, const void *value,
    8343                 :            :                     uint16_t value_len)
    8344                 :            : {
    8345                 :      44696 :         return blob_set_xattr(blob, name, value, value_len, false);
    8346                 :            : }
    8347                 :            : 
    8348                 :            : static int
    8349                 :       2231 : blob_remove_xattr(struct spdk_blob *blob, const char *name, bool internal)
    8350                 :            : {
    8351                 :        364 :         struct spdk_xattr_tailq *xattrs;
    8352                 :        364 :         struct spdk_xattr       *xattr;
    8353                 :            : 
    8354                 :       2231 :         blob_verify_md_op(blob);
    8355                 :            : 
    8356   [ +  +  +  +  :       2231 :         if (blob->md_ro) {
             +  -  +  + ]
    8357                 :         24 :                 return -EPERM;
    8358                 :            :         }
    8359   [ +  +  +  +  :       2207 :         xattrs = internal ? &blob->xattrs_internal : &blob->xattrs;
             +  -  +  - ]
    8360                 :            : 
    8361   [ +  +  +  -  :       2280 :         TAILQ_FOREACH(xattr, xattrs, link) {
          +  +  +  -  +  
                -  +  - ]
    8362   [ +  +  +  +  :       1987 :                 if (!strcmp(name, xattr->name)) {
          +  +  +  -  +  
                      + ]
    8363   [ +  +  +  -  :       1914 :                         TAILQ_REMOVE(xattrs, xattr, link);
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
    8364   [ +  -  +  - ]:       1914 :                         free(xattr->value);
    8365   [ +  -  +  - ]:       1914 :                         free(xattr->name);
    8366                 :       1914 :                         free(xattr);
    8367                 :            : 
    8368   [ +  +  +  +  :       1914 :                         if (internal && TAILQ_EMPTY(&blob->xattrs_internal)) {
          +  -  +  -  +  
                -  +  + ]
    8369   [ -  +  -  +  :       1324 :                                 blob->invalid_flags &= ~SPDK_BLOB_INTERNAL_XATTR;
                   -  + ]
    8370                 :        216 :                         }
    8371   [ +  -  +  - ]:       1914 :                         blob->state = SPDK_BLOB_STATE_DIRTY;
    8372                 :            : 
    8373                 :       1914 :                         return 0;
    8374                 :            :                 }
    8375                 :         12 :         }
    8376                 :            : 
    8377                 :        293 :         return -ENOENT;
    8378                 :        364 : }
    8379                 :            : 
    8380                 :            : int
    8381                 :        217 : spdk_blob_remove_xattr(struct spdk_blob *blob, const char *name)
    8382                 :            : {
    8383                 :        217 :         return blob_remove_xattr(blob, name, false);
    8384                 :            : }
    8385                 :            : 
    8386                 :            : static int
    8387                 :      43026 : blob_get_xattr_value(struct spdk_blob *blob, const char *name,
    8388                 :            :                      const void **value, size_t *value_len, bool internal)
    8389                 :            : {
    8390                 :       2116 :         struct spdk_xattr       *xattr;
    8391                 :       2116 :         struct spdk_xattr_tailq *xattrs;
    8392                 :            : 
    8393   [ +  +  +  +  :      43026 :         xattrs = internal ? &blob->xattrs_internal : &blob->xattrs;
             +  -  +  - ]
    8394                 :            : 
    8395   [ +  +  +  -  :      62645 :         TAILQ_FOREACH(xattr, xattrs, link) {
          +  +  +  -  +  
                -  +  - ]
    8396   [ +  +  +  +  :      34739 :                 if (!strcmp(name, xattr->name)) {
          +  +  +  -  +  
                      + ]
    8397   [ -  +  -  +  :      15120 :                         *value = xattr->value;
                   -  + ]
    8398   [ -  +  -  +  :      15120 :                         *value_len = xattr->value_len;
                   -  + ]
    8399                 :      15120 :                         return 0;
    8400                 :            :                 }
    8401                 :        586 :         }
    8402                 :      27906 :         return -ENOENT;
    8403                 :       2116 : }
    8404                 :            : 
    8405                 :            : int
    8406                 :      17083 : spdk_blob_get_xattr_value(struct spdk_blob *blob, const char *name,
    8407                 :            :                           const void **value, size_t *value_len)
    8408                 :            : {
    8409                 :      17083 :         blob_verify_md_op(blob);
    8410                 :            : 
    8411                 :      17083 :         return blob_get_xattr_value(blob, name, value, value_len, false);
    8412                 :            : }
    8413                 :            : 
    8414                 :            : struct spdk_xattr_names {
    8415                 :            :         uint32_t        count;
    8416                 :            :         const char      *names[0];
    8417                 :            : };
    8418                 :            : 
    8419                 :            : static int
    8420                 :         25 : blob_get_xattr_names(struct spdk_xattr_tailq *xattrs, struct spdk_xattr_names **names)
    8421                 :            : {
    8422                 :          4 :         struct spdk_xattr       *xattr;
    8423                 :         25 :         int                     count = 0;
    8424                 :            : 
    8425   [ +  +  +  -  :         74 :         TAILQ_FOREACH(xattr, xattrs, link) {
          +  +  +  -  +  
                -  +  - ]
    8426         [ +  - ]:         49 :                 count++;
    8427                 :          8 :         }
    8428                 :            : 
    8429         [ +  - ]:         25 :         *names = calloc(1, sizeof(struct spdk_xattr_names) + count * sizeof(char *));
    8430   [ +  +  +  - ]:         25 :         if (*names == NULL) {
    8431                 :          0 :                 return -ENOMEM;
    8432                 :            :         }
    8433                 :            : 
    8434   [ +  +  +  -  :         74 :         TAILQ_FOREACH(xattr, xattrs, link) {
          +  +  +  -  +  
                -  +  - ]
    8435   [ +  -  +  -  :         49 :                 (*names)->names[(*names)->count++] = xattr->name;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8436                 :          8 :         }
    8437                 :            : 
    8438                 :         25 :         return 0;
    8439                 :          4 : }
    8440                 :            : 
    8441                 :            : int
    8442                 :         25 : spdk_blob_get_xattr_names(struct spdk_blob *blob, struct spdk_xattr_names **names)
    8443                 :            : {
    8444                 :         25 :         blob_verify_md_op(blob);
    8445                 :            : 
    8446         [ +  - ]:         25 :         return blob_get_xattr_names(&blob->xattrs, names);
    8447                 :            : }
    8448                 :            : 
    8449                 :            : uint32_t
    8450                 :         27 : spdk_xattr_names_get_count(struct spdk_xattr_names *names)
    8451                 :            : {
    8452   [ +  +  #  # ]:         27 :         assert(names != NULL);
    8453                 :            : 
    8454   [ +  -  +  - ]:         27 :         return names->count;
    8455                 :            : }
    8456                 :            : 
    8457                 :            : const char *
    8458                 :         50 : spdk_xattr_names_get_name(struct spdk_xattr_names *names, uint32_t index)
    8459                 :            : {
    8460   [ +  +  +  -  :         50 :         if (index >= names->count) {
                   -  + ]
    8461                 :          0 :                 return NULL;
    8462                 :            :         }
    8463                 :            : 
    8464   [ +  -  +  -  :         50 :         return names->names[index];
                   +  - ]
    8465                 :          8 : }
    8466                 :            : 
    8467                 :            : void
    8468                 :         25 : spdk_xattr_names_free(struct spdk_xattr_names *names)
    8469                 :            : {
    8470                 :         25 :         free(names);
    8471                 :         25 : }
    8472                 :            : 
    8473                 :            : struct spdk_bs_type
    8474                 :         23 : spdk_bs_get_bstype(struct spdk_blob_store *bs)
    8475                 :            : {
    8476         [ +  - ]:         23 :         return bs->bstype;
    8477                 :            : }
    8478                 :            : 
    8479                 :            : void
    8480                 :          0 : spdk_bs_set_bstype(struct spdk_blob_store *bs, struct spdk_bs_type bstype)
    8481                 :            : {
    8482   [ #  #  #  #  :          0 :         memcpy(&bs->bstype, &bstype, sizeof(bstype));
                   #  # ]
    8483                 :          0 : }
    8484                 :            : 
    8485                 :            : bool
    8486                 :      14796 : spdk_blob_is_read_only(struct spdk_blob *blob)
    8487                 :            : {
    8488   [ +  +  #  # ]:      14796 :         assert(blob != NULL);
    8489   [ +  +  +  +  :      14796 :         return (blob->data_ro || blob->md_ro);
          +  +  +  +  +  
             -  +  -  +  
                      - ]
    8490                 :            : }
    8491                 :            : 
    8492                 :            : bool
    8493                 :       2586 : spdk_blob_is_snapshot(struct spdk_blob *blob)
    8494                 :            : {
    8495                 :         32 :         struct spdk_blob_list *snapshot_entry;
    8496                 :            : 
    8497   [ +  +  #  # ]:       2586 :         assert(blob != NULL);
    8498                 :            : 
    8499   [ +  -  +  -  :       2586 :         snapshot_entry = bs_get_snapshot_entry(blob->bs, blob->id);
             +  -  +  - ]
    8500         [ +  + ]:       2586 :         if (snapshot_entry == NULL) {
    8501                 :       2462 :                 return false;
    8502                 :            :         }
    8503                 :            : 
    8504                 :        124 :         return true;
    8505                 :         32 : }
    8506                 :            : 
    8507                 :            : bool
    8508                 :       2634 : spdk_blob_is_clone(struct spdk_blob *blob)
    8509                 :            : {
    8510   [ +  +  #  # ]:       2634 :         assert(blob != NULL);
    8511                 :            : 
    8512   [ +  +  +  -  :       2666 :         if (blob->parent_id != SPDK_BLOBID_INVALID &&
             +  +  +  + ]
    8513   [ +  +  +  - ]:        343 :             blob->parent_id != SPDK_BLOBID_EXTERNAL_SNAPSHOT) {
    8514   [ +  +  #  # ]:        266 :                 assert(spdk_blob_is_thin_provisioned(blob));
    8515                 :        266 :                 return true;
    8516                 :            :         }
    8517                 :            : 
    8518                 :       2368 :         return false;
    8519                 :         40 : }
    8520                 :            : 
    8521                 :            : bool
    8522                 :    1919331 : spdk_blob_is_thin_provisioned(struct spdk_blob *blob)
    8523                 :            : {
    8524   [ +  +  #  # ]:    1919331 :         assert(blob != NULL);
    8525   [ +  -  +  -  :    1919331 :         return !!(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
                   +  - ]
    8526                 :            : }
    8527                 :            : 
    8528                 :            : bool
    8529                 :   22504945 : spdk_blob_is_esnap_clone(const struct spdk_blob *blob)
    8530                 :            : {
    8531                 :   22504945 :         return blob_is_esnap_clone(blob);
    8532                 :            : }
    8533                 :            : 
    8534                 :            : static void
    8535                 :      39919 : blob_update_clear_method(struct spdk_blob *blob)
    8536                 :            : {
    8537                 :       3238 :         enum blob_clear_method stored_cm;
    8538                 :            : 
    8539   [ +  +  #  # ]:      39919 :         assert(blob != NULL);
    8540                 :            : 
    8541                 :            :         /* If BLOB_CLEAR_WITH_DEFAULT was passed in, use the setting stored
    8542                 :            :          * in metadata previously.  If something other than the default was
    8543                 :            :          * specified, ignore stored value and used what was passed in.
    8544                 :            :          */
    8545   [ +  -  +  -  :      39919 :         stored_cm = ((blob->md_ro_flags & SPDK_BLOB_CLEAR_METHOD) >> SPDK_BLOB_CLEAR_METHOD_SHIFT);
             +  -  +  - ]
    8546                 :            : 
    8547   [ +  +  +  -  :      39919 :         if (blob->clear_method == BLOB_CLEAR_WITH_DEFAULT) {
                   -  + ]
    8548   [ +  -  +  - ]:      39916 :                 blob->clear_method = stored_cm;
    8549   [ -  +  #  #  :       3241 :         } else if (blob->clear_method != stored_cm) {
                   #  # ]
    8550   [ #  #  #  # ]:          0 :                 SPDK_WARNLOG("Using passed in clear method 0x%x instead of stored value of 0x%x\n",
    8551                 :            :                              blob->clear_method, stored_cm);
    8552                 :          0 :         }
    8553                 :      39919 : }
    8554                 :            : 
    8555                 :            : spdk_blob_id
    8556                 :       1352 : spdk_blob_get_parent_snapshot(struct spdk_blob_store *bs, spdk_blob_id blob_id)
    8557                 :            : {
    8558                 :       1352 :         struct spdk_blob_list *snapshot_entry = NULL;
    8559                 :       1352 :         struct spdk_blob_list *clone_entry = NULL;
    8560                 :            : 
    8561   [ +  +  +  -  :       2339 :         TAILQ_FOREACH(snapshot_entry, &bs->snapshots, link) {
          +  -  +  +  +  
             -  +  -  +  
                      - ]
    8562   [ +  +  +  -  :       3351 :                 TAILQ_FOREACH(clone_entry, &snapshot_entry->clones, link) {
          +  -  +  +  +  
             -  +  -  +  
                      - ]
    8563   [ +  +  +  -  :       2364 :                         if (clone_entry->id == blob_id) {
                   +  + ]
    8564   [ -  +  -  + ]:        932 :                                 return snapshot_entry->id;
    8565                 :            :                         }
    8566                 :        236 :                 }
    8567                 :        164 :         }
    8568                 :            : 
    8569                 :        420 :         return SPDK_BLOBID_INVALID;
    8570                 :        218 : }
    8571                 :            : 
    8572                 :            : int
    8573                 :       1763 : spdk_blob_get_clones(struct spdk_blob_store *bs, spdk_blob_id blobid, spdk_blob_id *ids,
    8574                 :            :                      size_t *count)
    8575                 :            : {
    8576                 :        184 :         struct spdk_blob_list *snapshot_entry, *clone_entry;
    8577                 :        184 :         size_t n;
    8578                 :            : 
    8579                 :       1763 :         snapshot_entry = bs_get_snapshot_entry(bs, blobid);
    8580         [ +  + ]:       1763 :         if (snapshot_entry == NULL) {
    8581         [ +  - ]:        692 :                 *count = 0;
    8582                 :        692 :                 return 0;
    8583                 :            :         }
    8584                 :            : 
    8585   [ +  +  +  +  :       1071 :         if (ids == NULL || *count < snapshot_entry->clone_count) {
          +  -  +  -  +  
                      + ]
    8586   [ +  -  +  -  :        123 :                 *count = snapshot_entry->clone_count;
                   +  - ]
    8587                 :        123 :                 return -ENOMEM;
    8588                 :            :         }
    8589   [ +  -  +  -  :        948 :         *count = snapshot_entry->clone_count;
                   +  - ]
    8590                 :            : 
    8591                 :        948 :         n = 0;
    8592   [ +  +  +  -  :       1957 :         TAILQ_FOREACH(clone_entry, &snapshot_entry->clones, link) {
          +  -  +  +  +  
             -  +  -  +  
                      - ]
    8593   [ +  -  +  -  :       1009 :                 ids[n++] = clone_entry->id;
             +  -  +  - ]
    8594                 :        160 :         }
    8595                 :            : 
    8596                 :        948 :         return 0;
    8597                 :        184 : }
    8598                 :            : 
    8599                 :            : static void
    8600                 :         24 : bs_load_grow_continue(struct spdk_bs_load_ctx *ctx)
    8601                 :            : {
    8602                 :          4 :         int rc;
    8603                 :            : 
    8604   [ +  +  +  -  :         24 :         if (ctx->super->size == 0) {
          +  -  +  -  +  
                      - ]
    8605   [ #  #  #  #  :          0 :                 ctx->super->size = ctx->bs->dev->blockcnt * ctx->bs->dev->blocklen;
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    8606                 :          0 :         }
    8607                 :            : 
    8608   [ +  +  +  -  :         24 :         if (ctx->super->io_unit_size == 0) {
          +  -  +  -  +  
                      - ]
    8609   [ #  #  #  #  :          0 :                 ctx->super->io_unit_size = SPDK_BS_PAGE_SIZE;
             #  #  #  # ]
    8610                 :          0 :         }
    8611                 :            : 
    8612                 :            :         /* Parse the super block */
    8613   [ +  -  +  -  :         24 :         ctx->bs->clean = 1;
             +  -  +  - ]
    8614   [ +  -  +  -  :         24 :         ctx->bs->cluster_sz = ctx->super->cluster_size;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8615   [ +  +  +  -  :         24 :         ctx->bs->total_clusters = ctx->super->size / ctx->super->cluster_size;
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8616   [ +  -  +  -  :         24 :         ctx->bs->pages_per_cluster = ctx->bs->cluster_sz / SPDK_BS_PAGE_SIZE;
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
    8617   [ +  -  +  -  :         24 :         if (spdk_u32_is_pow2(ctx->bs->pages_per_cluster)) {
          +  -  +  -  -  
                      + ]
    8618   [ +  -  +  -  :         24 :                 ctx->bs->pages_per_cluster_shift = spdk_u32log2(ctx->bs->pages_per_cluster);
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8619                 :          4 :         }
    8620   [ +  -  +  -  :         24 :         ctx->bs->io_unit_size = ctx->super->io_unit_size;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8621   [ +  -  +  -  :         24 :         rc = spdk_bit_array_resize(&ctx->used_clusters, ctx->bs->total_clusters);
          +  -  +  -  +  
                      - ]
    8622         [ +  + ]:         24 :         if (rc < 0) {
    8623                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    8624                 :          0 :                 return;
    8625                 :            :         }
    8626   [ +  -  +  -  :         24 :         ctx->bs->md_start = ctx->super->md_start;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8627   [ +  -  +  -  :         24 :         ctx->bs->md_len = ctx->super->md_len;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8628   [ +  -  +  -  :         24 :         rc = spdk_bit_array_resize(&ctx->bs->open_blobids, ctx->bs->md_len);
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    8629         [ +  + ]:         24 :         if (rc < 0) {
    8630                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    8631                 :          0 :                 return;
    8632                 :            :         }
    8633                 :            : 
    8634   [ +  -  +  -  :         64 :         ctx->bs->total_data_clusters = ctx->bs->total_clusters - spdk_divide_round_up(
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8635   [ +  -  +  -  :         40 :                                                ctx->bs->md_start + ctx->bs->md_len, ctx->bs->pages_per_cluster);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    8636   [ +  -  +  -  :         24 :         ctx->bs->super_blob = ctx->super->super_blob;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8637   [ +  -  +  -  :         24 :         memcpy(&ctx->bs->bstype, &ctx->super->bstype, sizeof(ctx->super->bstype));
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8638                 :            : 
    8639   [ +  -  +  +  :         24 :         if (ctx->super->used_blobid_mask_len == 0 || ctx->super->clean == 0) {
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  -  
                      + ]
    8640                 :          0 :                 SPDK_ERRLOG("Can not grow an unclean blobstore, please load it normally to clean it.\n");
    8641                 :          0 :                 bs_load_ctx_fail(ctx, -EIO);
    8642                 :          0 :                 return;
    8643                 :            :         } else {
    8644                 :         24 :                 bs_load_read_used_pages(ctx);
    8645                 :            :         }
    8646         [ -  + ]:          4 : }
    8647                 :            : 
    8648                 :            : static void
    8649                 :         24 : bs_load_grow_super_write_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    8650                 :            : {
    8651                 :         24 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    8652                 :            : 
    8653         [ -  + ]:         24 :         if (bserrno != 0) {
    8654                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    8655                 :          0 :                 return;
    8656                 :            :         }
    8657                 :         24 :         bs_load_grow_continue(ctx);
    8658         [ -  + ]:          4 : }
    8659                 :            : 
    8660                 :            : static void
    8661                 :         24 : bs_load_grow_used_clusters_write_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    8662                 :            : {
    8663                 :         24 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    8664                 :            : 
    8665         [ -  + ]:         24 :         if (bserrno != 0) {
    8666                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    8667                 :          0 :                 return;
    8668                 :            :         }
    8669                 :            : 
    8670   [ +  -  +  - ]:         24 :         spdk_free(ctx->mask);
    8671                 :            : 
    8672   [ +  -  +  -  :         28 :         bs_sequence_write_dev(ctx->seq, ctx->super, bs_page_to_lba(ctx->bs, 0),
          +  -  +  -  +  
                -  +  - ]
    8673   [ +  -  +  - ]:         24 :                               bs_byte_to_lba(ctx->bs, sizeof(*ctx->super)),
    8674                 :          4 :                               bs_load_grow_super_write_cpl, ctx);
    8675         [ -  + ]:          4 : }
    8676                 :            : 
    8677                 :            : static void
    8678                 :         24 : bs_load_grow_used_clusters_read_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    8679                 :            : {
    8680                 :         24 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    8681                 :          4 :         uint64_t                lba, lba_count;
    8682                 :          4 :         uint64_t                dev_size;
    8683                 :          4 :         uint64_t                total_clusters;
    8684                 :            : 
    8685         [ -  + ]:         24 :         if (bserrno != 0) {
    8686                 :          0 :                 bs_load_ctx_fail(ctx, bserrno);
    8687                 :          0 :                 return;
    8688                 :            :         }
    8689                 :            : 
    8690                 :            :         /* The type must be correct */
    8691   [ +  +  +  -  :         24 :         assert(ctx->mask->type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
          +  -  +  -  +  
                -  #  # ]
    8692                 :            :         /* The length of the mask (in bits) must not be greater than the length of the buffer (converted to bits) */
    8693   [ +  +  +  -  :         24 :         assert(ctx->mask->length <= (ctx->super->used_cluster_mask_len * sizeof(
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    8694                 :            :                                              struct spdk_blob_md_page) * 8));
    8695   [ +  -  +  -  :         24 :         dev_size = ctx->bs->dev->blockcnt * ctx->bs->dev->blocklen;
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    8696   [ +  +  +  -  :         24 :         total_clusters = dev_size / ctx->super->cluster_size;
          +  -  +  -  +  
                      - ]
    8697   [ +  -  +  -  :         24 :         ctx->mask->length = total_clusters;
             +  -  +  - ]
    8698                 :            : 
    8699   [ +  -  +  -  :         24 :         lba = bs_page_to_lba(ctx->bs, ctx->super->used_cluster_mask_start);
          +  -  +  -  +  
                -  +  - ]
    8700   [ +  -  +  -  :         24 :         lba_count = bs_page_to_lba(ctx->bs, ctx->super->used_cluster_mask_len);
          +  -  +  -  +  
                -  +  - ]
    8701   [ +  -  +  -  :         24 :         bs_sequence_write_dev(ctx->seq, ctx->mask, lba, lba_count,
             +  -  +  - ]
    8702                 :          4 :                               bs_load_grow_used_clusters_write_cpl, ctx);
    8703         [ -  + ]:          4 : }
    8704                 :            : 
    8705                 :            : static void
    8706                 :         24 : bs_load_try_to_grow(struct spdk_bs_load_ctx *ctx)
    8707                 :            : {
    8708                 :          4 :         uint64_t dev_size, total_clusters, used_cluster_mask_len, max_used_cluster_mask;
    8709                 :          4 :         uint64_t lba, lba_count, mask_size;
    8710                 :            : 
    8711   [ +  -  +  -  :         24 :         dev_size = ctx->bs->dev->blockcnt * ctx->bs->dev->blocklen;
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    8712   [ +  +  +  -  :         24 :         total_clusters = dev_size / ctx->super->cluster_size;
          +  -  +  -  +  
                      - ]
    8713                 :         24 :         used_cluster_mask_len = spdk_divide_round_up(sizeof(struct spdk_bs_md_mask) +
    8714                 :         24 :                                 spdk_divide_round_up(total_clusters, 8),
    8715                 :            :                                 SPDK_BS_PAGE_SIZE);
    8716   [ +  -  +  -  :         24 :         max_used_cluster_mask = ctx->super->used_blobid_mask_start - ctx->super->used_cluster_mask_start;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8717                 :            :         /* No necessary to grow or no space to grow */
    8718   [ +  -  +  +  :         24 :         if (ctx->super->size >= dev_size || used_cluster_mask_len > max_used_cluster_mask) {
          +  -  +  -  +  
                -  -  + ]
    8719   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob, "No grow\n");
                   #  # ]
    8720                 :          0 :                 bs_load_grow_continue(ctx);
    8721                 :          0 :                 return;
    8722                 :            :         }
    8723                 :            : 
    8724   [ +  +  +  +  :         24 :         SPDK_DEBUGLOG(blob, "Resize blobstore\n");
                   +  - ]
    8725                 :            : 
    8726   [ +  -  +  -  :         24 :         ctx->super->size = dev_size;
             +  -  +  - ]
    8727   [ +  -  +  -  :         24 :         ctx->super->used_cluster_mask_len = used_cluster_mask_len;
             +  -  +  - ]
    8728   [ +  -  +  -  :         24 :         ctx->super->crc = blob_md_page_calc_crc(ctx->super);
          +  -  +  -  +  
                -  +  - ]
    8729                 :            : 
    8730                 :         24 :         mask_size = used_cluster_mask_len * SPDK_BS_PAGE_SIZE;
    8731   [ +  -  +  - ]:         24 :         ctx->mask = spdk_zmalloc(mask_size, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY,
    8732                 :            :                                  SPDK_MALLOC_DMA);
    8733   [ +  +  +  -  :         24 :         if (!ctx->mask) {
                   +  - ]
    8734                 :          0 :                 bs_load_ctx_fail(ctx, -ENOMEM);
    8735                 :          0 :                 return;
    8736                 :            :         }
    8737   [ +  -  +  -  :         24 :         lba = bs_page_to_lba(ctx->bs, ctx->super->used_cluster_mask_start);
          +  -  +  -  +  
                -  +  - ]
    8738   [ +  -  +  -  :         24 :         lba_count = bs_page_to_lba(ctx->bs, ctx->super->used_cluster_mask_len);
          +  -  +  -  +  
                -  +  - ]
    8739   [ +  -  +  -  :         24 :         bs_sequence_read_dev(ctx->seq, ctx->mask, lba, lba_count,
             +  -  +  - ]
    8740                 :          4 :                              bs_load_grow_used_clusters_read_cpl, ctx);
    8741         [ -  + ]:          4 : }
    8742                 :            : 
    8743                 :            : static void
    8744                 :         24 : bs_grow_load_super_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    8745                 :            : {
    8746                 :         24 :         struct spdk_bs_load_ctx *ctx = cb_arg;
    8747                 :          4 :         int rc;
    8748                 :            : 
    8749   [ +  -  +  -  :         24 :         rc = bs_super_validate(ctx->super, ctx->bs);
             +  -  +  - ]
    8750         [ -  + ]:         24 :         if (rc != 0) {
    8751                 :          0 :                 bs_load_ctx_fail(ctx, rc);
    8752                 :          0 :                 return;
    8753                 :            :         }
    8754                 :            : 
    8755                 :         24 :         bs_load_try_to_grow(ctx);
    8756         [ -  + ]:          4 : }
    8757                 :            : 
    8758                 :            : struct spdk_bs_grow_ctx {
    8759                 :            :         struct spdk_blob_store          *bs;
    8760                 :            :         struct spdk_bs_super_block      *super;
    8761                 :            : 
    8762                 :            :         struct spdk_bit_pool            *new_used_clusters;
    8763                 :            :         struct spdk_bs_md_mask          *new_used_clusters_mask;
    8764                 :            : 
    8765                 :            :         spdk_bs_sequence_t              *seq;
    8766                 :            : };
    8767                 :            : 
    8768                 :            : static void
    8769                 :        194 : bs_grow_live_done(struct spdk_bs_grow_ctx *ctx, int bserrno)
    8770                 :            : {
    8771         [ +  + ]:        194 :         if (bserrno != 0) {
    8772         [ +  - ]:         48 :                 spdk_bit_pool_free(&ctx->new_used_clusters);
    8773                 :          8 :         }
    8774                 :            : 
    8775   [ +  -  +  - ]:        194 :         bs_sequence_finish(ctx->seq, bserrno);
    8776   [ +  -  +  - ]:        194 :         free(ctx->new_used_clusters_mask);
    8777   [ +  -  +  - ]:        194 :         spdk_free(ctx->super);
    8778                 :        194 :         free(ctx);
    8779                 :        194 : }
    8780                 :            : 
    8781                 :            : static void
    8782                 :         50 : bs_grow_live_super_write_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    8783                 :            : {
    8784                 :         50 :         struct spdk_bs_grow_ctx *ctx = cb_arg;
    8785   [ +  -  +  - ]:         50 :         struct spdk_blob_store *bs = ctx->bs;
    8786                 :          8 :         uint64_t total_clusters;
    8787                 :            : 
    8788         [ -  + ]:         50 :         if (bserrno != 0) {
    8789                 :          0 :                 bs_grow_live_done(ctx, bserrno);
    8790                 :          0 :                 return;
    8791                 :            :         }
    8792                 :            : 
    8793                 :            :         /*
    8794                 :            :          * Blobstore is not clean until unload, for now only the super block is up to date.
    8795                 :            :          * This is similar to state right after blobstore init, when bs_write_used_md() didn't
    8796                 :            :          * yet execute.
    8797                 :            :          * When cleanly unloaded, the used md pages will be written out.
    8798                 :            :          * In case of unclean shutdown, loading blobstore will go through recovery path correctly
    8799                 :            :          * filling out the used_clusters with new size and writing it out.
    8800                 :            :          */
    8801   [ +  -  +  - ]:         50 :         bs->clean = 0;
    8802                 :            : 
    8803                 :            :         /* Reverting the super->size past this point is complex, avoid any error paths
    8804                 :            :          * that require to do so. */
    8805         [ +  - ]:         50 :         spdk_spin_lock(&bs->used_lock);
    8806                 :            : 
    8807   [ +  +  +  -  :         50 :         total_clusters = ctx->super->size / ctx->super->cluster_size;
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
    8808                 :            : 
    8809   [ +  +  +  -  :         50 :         assert(total_clusters >= spdk_bit_pool_capacity(bs->used_clusters));
             +  -  #  # ]
    8810   [ +  -  +  -  :         50 :         spdk_bit_pool_store_mask(bs->used_clusters, ctx->new_used_clusters_mask);
             +  -  +  - ]
    8811                 :            : 
    8812   [ +  +  +  -  :         50 :         assert(total_clusters == spdk_bit_pool_capacity(ctx->new_used_clusters));
             +  -  #  # ]
    8813   [ +  -  +  -  :         50 :         spdk_bit_pool_load_mask(ctx->new_used_clusters, ctx->new_used_clusters_mask);
             +  -  +  - ]
    8814                 :            : 
    8815         [ +  - ]:         50 :         spdk_bit_pool_free(&bs->used_clusters);
    8816   [ +  -  +  -  :         50 :         bs->used_clusters = ctx->new_used_clusters;
             +  -  +  - ]
    8817                 :            : 
    8818   [ +  -  +  - ]:         50 :         bs->total_clusters = total_clusters;
    8819   [ +  -  +  -  :        100 :         bs->total_data_clusters = bs->total_clusters - spdk_divide_round_up(
             +  -  +  - ]
    8820   [ +  -  +  -  :         50 :                                           bs->md_start + bs->md_len, bs->pages_per_cluster);
          +  -  +  -  +  
                -  +  - ]
    8821                 :            : 
    8822   [ +  -  +  -  :         50 :         bs->num_free_clusters = spdk_bit_pool_count_free(bs->used_clusters);
             +  -  +  - ]
    8823   [ +  +  +  -  :         50 :         assert(ctx->bs->num_free_clusters <= ctx->bs->total_clusters);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  #  
                      # ]
    8824         [ +  - ]:         50 :         spdk_spin_unlock(&bs->used_lock);
    8825                 :            : 
    8826                 :         50 :         bs_grow_live_done(ctx, 0);
    8827         [ -  + ]:          8 : }
    8828                 :            : 
    8829                 :            : static void
    8830                 :        194 : bs_grow_live_load_super_cpl(spdk_bs_sequence_t *seq, void *cb_arg, int bserrno)
    8831                 :            : {
    8832                 :        194 :         struct spdk_bs_grow_ctx *ctx = cb_arg;
    8833                 :         32 :         uint64_t dev_size, total_clusters, used_cluster_mask_len, max_used_cluster_mask;
    8834                 :         32 :         int rc;
    8835                 :            : 
    8836         [ -  + ]:        194 :         if (bserrno != 0) {
    8837                 :          0 :                 bs_grow_live_done(ctx, bserrno);
    8838                 :          0 :                 return;
    8839                 :            :         }
    8840                 :            : 
    8841   [ +  -  +  -  :        194 :         rc = bs_super_validate(ctx->super, ctx->bs);
             +  -  +  - ]
    8842         [ +  + ]:        194 :         if (rc != 0) {
    8843                 :         24 :                 bs_grow_live_done(ctx, rc);
    8844                 :         24 :                 return;
    8845                 :            :         }
    8846                 :            : 
    8847   [ +  -  +  -  :        170 :         dev_size = ctx->bs->dev->blockcnt * ctx->bs->dev->blocklen;
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
    8848   [ +  +  +  -  :        170 :         total_clusters = dev_size / ctx->super->cluster_size;
          +  -  +  -  +  
                      - ]
    8849                 :        170 :         used_cluster_mask_len = spdk_divide_round_up(sizeof(struct spdk_bs_md_mask) +
    8850                 :        170 :                                 spdk_divide_round_up(total_clusters, 8),
    8851                 :            :                                 SPDK_BS_PAGE_SIZE);
    8852   [ +  -  +  -  :        170 :         max_used_cluster_mask = ctx->super->used_blobid_mask_start - ctx->super->used_cluster_mask_start;
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
    8853                 :            :         /* Only checking dev_size. Since it can change, but total_clusters remain the same. */
    8854   [ +  +  +  -  :        170 :         if (dev_size == ctx->super->size) {
          +  -  +  -  +  
                      + ]
    8855   [ +  +  +  +  :         96 :                 SPDK_DEBUGLOG(blob, "No need to grow blobstore\n");
                   +  - ]
    8856                 :         96 :                 bs_grow_live_done(ctx, 0);
    8857                 :         96 :                 return;
    8858                 :            :         }
    8859                 :            :         /*
    8860                 :            :          * Blobstore cannot be shrunk, so check before if:
    8861                 :            :          * - new size of the device is smaller than size in super_block
    8862                 :            :          * - new total number of clusters is smaller than used_clusters bit_pool
    8863                 :            :          * - there is enough space in metadata for used_cluster_mask to be written out
    8864                 :            :          */
    8865   [ +  -  +  -  :         86 :         if (dev_size < ctx->super->size ||
          +  -  +  -  +  
                -  +  + ]
    8866   [ +  -  +  +  :         74 :             total_clusters < spdk_bit_pool_capacity(ctx->bs->used_clusters) ||
          +  -  +  -  +  
                      - ]
    8867                 :         12 :             used_cluster_mask_len > max_used_cluster_mask) {
    8868   [ +  +  +  +  :         24 :                 SPDK_DEBUGLOG(blob, "No space to grow blobstore\n");
                   +  - ]
    8869                 :         24 :                 bs_grow_live_done(ctx, -ENOSPC);
    8870                 :         24 :                 return;
    8871                 :            :         }
    8872                 :            : 
    8873   [ +  +  +  +  :         50 :         SPDK_DEBUGLOG(blob, "Resizing blobstore\n");
                   +  - ]
    8874                 :            : 
    8875   [ +  -  +  - ]:         50 :         ctx->new_used_clusters_mask = calloc(1, total_clusters);
    8876   [ +  +  +  -  :         50 :         if (!ctx->new_used_clusters_mask) {
                   +  - ]
    8877                 :          0 :                 bs_grow_live_done(ctx, -ENOMEM);
    8878                 :          0 :                 return;
    8879                 :            :         }
    8880   [ +  -  +  - ]:         50 :         ctx->new_used_clusters = spdk_bit_pool_create(total_clusters);
    8881   [ +  +  +  -  :         50 :         if (!ctx->new_used_clusters) {
                   +  - ]
    8882                 :          0 :                 bs_grow_live_done(ctx, -ENOMEM);
    8883                 :          0 :                 return;
    8884                 :            :         }
    8885                 :            : 
    8886   [ +  -  +  -  :         50 :         ctx->super->clean = 0;
             +  -  +  - ]
    8887   [ +  -  +  -  :         50 :         ctx->super->size = dev_size;
             +  -  +  - ]
    8888   [ +  -  +  -  :         50 :         ctx->super->used_cluster_mask_len = used_cluster_mask_len;
             +  -  +  - ]
    8889   [ +  -  +  -  :         50 :         bs_write_super(seq, ctx->bs, ctx->super, bs_grow_live_super_write_cpl, ctx);
             +  -  +  - ]
    8890         [ -  + ]:         32 : }
    8891                 :            : 
    8892                 :            : void
    8893                 :        194 : spdk_bs_grow_live(struct spdk_blob_store *bs,
    8894                 :            :                   spdk_bs_op_complete cb_fn, void *cb_arg)
    8895                 :            : {
    8896                 :        162 :         struct spdk_bs_cpl      cpl;
    8897                 :         32 :         struct spdk_bs_grow_ctx *ctx;
    8898                 :            : 
    8899   [ +  +  +  -  :        194 :         assert(spdk_get_thread() == bs->md_thread);
             +  -  #  # ]
    8900                 :            : 
    8901   [ +  +  +  +  :        194 :         SPDK_DEBUGLOG(blob, "Growing blobstore on dev %p\n", bs->dev);
          +  -  #  #  #  
                      # ]
    8902                 :            : 
    8903                 :        194 :         cpl.type = SPDK_BS_CPL_TYPE_BS_BASIC;
    8904   [ +  -  +  -  :        194 :         cpl.u.bs_basic.cb_fn = cb_fn;
                   +  - ]
    8905   [ +  -  +  -  :        194 :         cpl.u.bs_basic.cb_arg = cb_arg;
                   +  - ]
    8906                 :            : 
    8907                 :        194 :         ctx = calloc(1, sizeof(struct spdk_bs_grow_ctx));
    8908         [ +  + ]:        194 :         if (!ctx) {
    8909   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    8910                 :          0 :                 return;
    8911                 :            :         }
    8912   [ +  -  +  - ]:        194 :         ctx->bs = bs;
    8913                 :            : 
    8914   [ +  -  +  - ]:        194 :         ctx->super = spdk_zmalloc(sizeof(*ctx->super), 0x1000, NULL,
    8915                 :            :                                   SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
    8916   [ +  +  +  -  :        194 :         if (!ctx->super) {
                   +  - ]
    8917                 :          0 :                 free(ctx);
    8918   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    8919                 :          0 :                 return;
    8920                 :            :         }
    8921                 :            : 
    8922   [ +  -  +  -  :        194 :         ctx->seq = bs_sequence_start_bs(bs->md_channel, &cpl);
             +  -  +  - ]
    8923   [ +  +  +  -  :        194 :         if (!ctx->seq) {
                   -  + ]
    8924   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    8925                 :          0 :                 free(ctx);
    8926   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    8927                 :          0 :                 return;
    8928                 :            :         }
    8929                 :            : 
    8930                 :            :         /* Read the super block */
    8931   [ +  -  +  -  :        194 :         bs_sequence_read_dev(ctx->seq, ctx->super, bs_page_to_lba(bs, 0),
             +  -  +  - ]
    8932                 :        194 :                              bs_byte_to_lba(bs, sizeof(*ctx->super)),
    8933                 :         32 :                              bs_grow_live_load_super_cpl, ctx);
    8934         [ -  + ]:         32 : }
    8935                 :            : 
    8936                 :            : void
    8937                 :         24 : spdk_bs_grow(struct spdk_bs_dev *dev, struct spdk_bs_opts *o,
    8938                 :            :              spdk_bs_op_with_handle_complete cb_fn, void *cb_arg)
    8939                 :            : {
    8940                 :         20 :         struct spdk_blob_store  *bs;
    8941                 :         20 :         struct spdk_bs_cpl      cpl;
    8942                 :         20 :         struct spdk_bs_load_ctx *ctx;
    8943                 :         24 :         struct spdk_bs_opts     opts = {};
    8944                 :          4 :         int err;
    8945                 :            : 
    8946   [ +  +  +  +  :         24 :         SPDK_DEBUGLOG(blob, "Loading blobstore from dev %p\n", dev);
                   +  - ]
    8947                 :            : 
    8948   [ +  +  +  +  :         24 :         if ((SPDK_BS_PAGE_SIZE % dev->blocklen) != 0) {
             +  -  -  + ]
    8949   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(blob, "unsupported dev block length of %d\n", dev->blocklen);
          #  #  #  #  #  
                      # ]
    8950   [ #  #  #  #  :          0 :                 dev->destroy(dev);
             #  #  #  # ]
    8951   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -EINVAL);
    8952                 :          0 :                 return;
    8953                 :            :         }
    8954                 :            : 
    8955                 :         24 :         spdk_bs_opts_init(&opts, sizeof(opts));
    8956         [ +  + ]:         24 :         if (o) {
    8957         [ -  + ]:         24 :                 if (bs_opts_copy(o, &opts)) {
    8958                 :          0 :                         return;
    8959                 :            :                 }
    8960                 :          4 :         }
    8961                 :            : 
    8962   [ +  -  -  + ]:         24 :         if (opts.max_md_ops == 0 || opts.max_channel_ops == 0) {
    8963   [ #  #  #  #  :          0 :                 dev->destroy(dev);
             #  #  #  # ]
    8964   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -EINVAL);
    8965                 :          0 :                 return;
    8966                 :            :         }
    8967                 :            : 
    8968                 :         24 :         err = bs_alloc(dev, &opts, &bs, &ctx);
    8969         [ -  + ]:         24 :         if (err) {
    8970   [ #  #  #  #  :          0 :                 dev->destroy(dev);
             #  #  #  # ]
    8971   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, err);
    8972                 :          0 :                 return;
    8973                 :            :         }
    8974                 :            : 
    8975                 :         24 :         cpl.type = SPDK_BS_CPL_TYPE_BS_HANDLE;
    8976   [ +  -  +  -  :         24 :         cpl.u.bs_handle.cb_fn = cb_fn;
                   +  - ]
    8977   [ +  -  +  -  :         24 :         cpl.u.bs_handle.cb_arg = cb_arg;
                   +  - ]
    8978   [ +  -  +  -  :         24 :         cpl.u.bs_handle.bs = bs;
                   +  - ]
    8979                 :            : 
    8980   [ +  -  +  -  :         24 :         ctx->seq = bs_sequence_start_bs(bs->md_channel, &cpl);
             +  -  +  - ]
    8981   [ +  +  +  -  :         24 :         if (!ctx->seq) {
                   +  - ]
    8982   [ #  #  #  # ]:          0 :                 spdk_free(ctx->super);
    8983                 :          0 :                 free(ctx);
    8984                 :          0 :                 bs_free(bs);
    8985   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    8986                 :          0 :                 return;
    8987                 :            :         }
    8988                 :            : 
    8989                 :            :         /* Read the super block */
    8990   [ +  -  +  -  :         24 :         bs_sequence_read_dev(ctx->seq, ctx->super, bs_page_to_lba(bs, 0),
             +  -  +  - ]
    8991                 :         24 :                              bs_byte_to_lba(bs, sizeof(*ctx->super)),
    8992                 :          4 :                              bs_grow_load_super_cpl, ctx);
    8993         [ -  + ]:          4 : }
    8994                 :            : 
    8995                 :            : int
    8996                 :         20 : spdk_blob_get_esnap_id(struct spdk_blob *blob, const void **id, size_t *len)
    8997                 :            : {
    8998         [ -  + ]:         20 :         if (!blob_is_esnap_clone(blob)) {
    8999                 :          0 :                 return -EINVAL;
    9000                 :            :         }
    9001                 :            : 
    9002                 :         20 :         return blob_get_xattr_value(blob, BLOB_EXTERNAL_SNAPSHOT_ID, id, len, true);
    9003                 :          0 : }
    9004                 :            : 
    9005                 :            : struct spdk_io_channel *
    9006                 :      28505 : blob_esnap_get_io_channel(struct spdk_io_channel *ch, struct spdk_blob *blob)
    9007                 :            : {
    9008                 :      28505 :         struct spdk_bs_channel          *bs_channel = spdk_io_channel_get_ctx(ch);
    9009   [ +  -  +  - ]:      28505 :         struct spdk_bs_dev              *bs_dev = blob->back_bs_dev;
    9010                 :      28505 :         struct blob_esnap_channel       find = {};
    9011                 :       4720 :         struct blob_esnap_channel       *esnap_channel, *existing;
    9012                 :            : 
    9013   [ +  -  +  -  :      28505 :         find.blob_id = blob->id;
                   +  - ]
    9014         [ +  - ]:      28505 :         esnap_channel = RB_FIND(blob_esnap_channel_tree, &bs_channel->esnap_channels, &find);
    9015         [ +  + ]:      28505 :         if (spdk_likely(esnap_channel != NULL)) {
    9016   [ +  +  +  +  :      28249 :                 SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": using cached channel on thread %s\n",
          +  -  #  #  #  
                      # ]
    9017                 :            :                               blob->id, spdk_thread_get_name(spdk_get_thread()));
    9018   [ +  -  +  - ]:      28249 :                 return esnap_channel->channel;
    9019                 :            :         }
    9020                 :            : 
    9021   [ +  +  +  +  :        256 :         SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": allocating channel on thread %s\n",
          +  -  #  #  #  
                      # ]
    9022                 :            :                       blob->id, spdk_thread_get_name(spdk_get_thread()));
    9023                 :            : 
    9024                 :        256 :         esnap_channel = calloc(1, sizeof(*esnap_channel));
    9025         [ +  + ]:        256 :         if (esnap_channel == NULL) {
    9026         [ #  # ]:          0 :                 SPDK_NOTICELOG("blob 0x%" PRIx64 " channel allocation failed: no memory\n",
    9027                 :            :                                find.blob_id);
    9028                 :          0 :                 return NULL;
    9029                 :            :         }
    9030   [ +  -  +  -  :        256 :         esnap_channel->channel = bs_dev->create_channel(bs_dev);
          -  +  +  -  +  
                -  +  - ]
    9031   [ +  +  +  -  :        256 :         if (esnap_channel->channel == NULL) {
                   -  + ]
    9032   [ #  #  #  # ]:          0 :                 SPDK_NOTICELOG("blob 0x%" PRIx64 " back channel allocation failed\n", blob->id);
    9033                 :          0 :                 free(esnap_channel);
    9034                 :          0 :                 return NULL;
    9035                 :            :         }
    9036   [ +  -  +  -  :        256 :         esnap_channel->blob_id = find.blob_id;
                   +  - ]
    9037         [ +  - ]:        256 :         existing = RB_INSERT(blob_esnap_channel_tree, &bs_channel->esnap_channels, esnap_channel);
    9038         [ +  + ]:        256 :         if (spdk_unlikely(existing != NULL)) {
    9039                 :            :                 /*
    9040                 :            :                  * This should be unreachable: all modifications to this tree happen on this thread.
    9041                 :            :                  */
    9042         [ #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 "lost race to allocate a channel\n", find.blob_id);
    9043         [ #  # ]:          0 :                 assert(false);
    9044                 :            : 
    9045                 :            :                 bs_dev->destroy_channel(bs_dev, esnap_channel->channel);
    9046                 :            :                 free(esnap_channel);
    9047                 :            : 
    9048                 :            :                 return existing->channel;
    9049                 :            :         }
    9050                 :            : 
    9051   [ +  -  +  - ]:        256 :         return esnap_channel->channel;
    9052                 :       4720 : }
    9053                 :            : 
    9054                 :            : static int
    9055                 :      28385 : blob_esnap_channel_compare(struct blob_esnap_channel *c1, struct blob_esnap_channel *c2)
    9056                 :            : {
    9057   [ +  -  +  -  :      28385 :         return (c1->blob_id < c2->blob_id ? -1 : c1->blob_id > c2->blob_id);
          +  -  +  -  -  
          +  +  -  +  -  
             +  -  +  - ]
    9058                 :            : }
    9059                 :            : 
    9060                 :            : struct blob_esnap_destroy_ctx {
    9061                 :            :         spdk_blob_op_with_handle_complete       cb_fn;
    9062                 :            :         void                                    *cb_arg;
    9063                 :            :         struct spdk_blob                        *blob;
    9064                 :            :         struct spdk_bs_dev                      *back_bs_dev;
    9065                 :            :         bool                                    abort_io;
    9066                 :            : };
    9067                 :            : 
    9068                 :            : static void
    9069                 :        659 : blob_esnap_destroy_channels_done(struct spdk_io_channel_iter *i, int status)
    9070                 :            : {
    9071                 :        659 :         struct blob_esnap_destroy_ctx   *ctx = spdk_io_channel_iter_get_ctx(i);
    9072   [ +  -  +  - ]:        659 :         struct spdk_blob                *blob = ctx->blob;
    9073   [ +  -  +  - ]:        659 :         struct spdk_blob_store          *bs = blob->bs;
    9074                 :            : 
    9075   [ +  +  +  +  :        659 :         SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": done destroying channels for this blob\n",
          +  -  #  #  #  
                      # ]
    9076                 :            :                       blob->id);
    9077                 :            : 
    9078   [ +  +  +  -  :        659 :         if (ctx->cb_fn != NULL) {
                   +  + ]
    9079   [ +  -  +  -  :        583 :                 ctx->cb_fn(ctx->cb_arg, blob, status);
          -  +  +  -  +  
                -  +  - ]
    9080                 :         92 :         }
    9081                 :        659 :         free(ctx);
    9082                 :            : 
    9083         [ +  - ]:        659 :         bs->esnap_channels_unloading--;
    9084   [ +  -  +  +  :        659 :         if (bs->esnap_channels_unloading == 0 && bs->esnap_unload_cb_fn != NULL) {
          +  -  +  -  +  
                -  +  + ]
    9085   [ +  -  +  -  :         40 :                 spdk_bs_unload(bs, bs->esnap_unload_cb_fn, bs->esnap_unload_cb_arg);
             +  -  +  - ]
    9086                 :          4 :         }
    9087                 :        659 : }
    9088                 :            : 
    9089                 :            : static void
    9090                 :        707 : blob_esnap_destroy_one_channel(struct spdk_io_channel_iter *i)
    9091                 :            : {
    9092                 :        707 :         struct blob_esnap_destroy_ctx   *ctx = spdk_io_channel_iter_get_ctx(i);
    9093   [ +  -  +  - ]:        707 :         struct spdk_blob                *blob = ctx->blob;
    9094   [ +  -  +  - ]:        707 :         struct spdk_bs_dev              *bs_dev = ctx->back_bs_dev;
    9095                 :        707 :         struct spdk_io_channel          *channel = spdk_io_channel_iter_get_channel(i);
    9096                 :        707 :         struct spdk_bs_channel          *bs_channel = spdk_io_channel_get_ctx(channel);
    9097                 :        112 :         struct blob_esnap_channel       *esnap_channel;
    9098                 :        707 :         struct blob_esnap_channel       find = {};
    9099                 :            : 
    9100   [ +  +  #  # ]:        707 :         assert(spdk_get_thread() == spdk_io_channel_get_thread(channel));
    9101                 :            : 
    9102   [ +  -  +  -  :        707 :         find.blob_id = blob->id;
                   +  - ]
    9103         [ +  - ]:        707 :         esnap_channel = RB_FIND(blob_esnap_channel_tree, &bs_channel->esnap_channels, &find);
    9104         [ +  + ]:        707 :         if (esnap_channel != NULL) {
    9105   [ +  +  +  +  :         88 :                 SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": destroying channel on thread %s\n",
          +  -  #  #  #  
                      # ]
    9106                 :            :                               blob->id, spdk_thread_get_name(spdk_get_thread()));
    9107         [ +  - ]:         88 :                 RB_REMOVE(blob_esnap_channel_tree, &bs_channel->esnap_channels, esnap_channel);
    9108                 :            : 
    9109   [ +  +  +  +  :         88 :                 if (ctx->abort_io) {
             +  -  +  + ]
    9110                 :          8 :                         spdk_bs_user_op_t *op, *tmp;
    9111                 :            : 
    9112   [ +  +  +  -  :         48 :                         TAILQ_FOREACH_SAFE(op, &bs_channel->queued_io, link, tmp) {
          +  -  +  -  #  
          #  #  #  #  #  
                   -  + ]
    9113   [ #  #  #  #  :          0 :                                 if (op->back_channel == esnap_channel->channel) {
          #  #  #  #  #  
                      # ]
    9114   [ #  #  #  #  :          0 :                                         TAILQ_REMOVE(&bs_channel->queued_io, op, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    9115                 :          0 :                                         bs_user_op_abort(op, -EIO);
    9116                 :          0 :                                 }
    9117                 :          0 :                         }
    9118                 :          8 :                 }
    9119                 :            : 
    9120   [ +  -  +  -  :         88 :                 bs_dev->destroy_channel(bs_dev, esnap_channel->channel);
          -  +  +  -  +  
                -  +  - ]
    9121                 :         88 :                 free(esnap_channel);
    9122                 :         12 :         }
    9123                 :            : 
    9124                 :        707 :         spdk_for_each_channel_continue(i, 0);
    9125                 :        707 : }
    9126                 :            : 
    9127                 :            : /*
    9128                 :            :  * Destroy the channels for a specific blob on each thread with a blobstore channel. This should be
    9129                 :            :  * used when closing an esnap clone blob and after decoupling from the parent.
    9130                 :            :  */
    9131                 :            : static void
    9132                 :       2526 : blob_esnap_destroy_bs_dev_channels(struct spdk_blob *blob, bool abort_io,
    9133                 :            :                                    spdk_blob_op_with_handle_complete cb_fn, void *cb_arg)
    9134                 :            : {
    9135                 :        400 :         struct blob_esnap_destroy_ctx   *ctx;
    9136                 :            : 
    9137   [ +  +  +  +  :       2526 :         if (!blob_is_esnap_clone(blob) || blob->back_bs_dev == NULL) {
             +  -  +  + ]
    9138         [ +  - ]:       1867 :                 if (cb_fn != NULL) {
    9139   [ -  +  +  - ]:       1867 :                         cb_fn(cb_arg, blob, 0);
    9140                 :        296 :                 }
    9141                 :       1867 :                 return;
    9142                 :            :         }
    9143                 :            : 
    9144                 :        659 :         ctx = calloc(1, sizeof(*ctx));
    9145         [ +  + ]:        659 :         if (ctx == NULL) {
    9146         [ #  # ]:          0 :                 if (cb_fn != NULL) {
    9147   [ #  #  #  # ]:          0 :                         cb_fn(cb_arg, blob, -ENOMEM);
    9148                 :          0 :                 }
    9149                 :          0 :                 return;
    9150                 :            :         }
    9151   [ +  -  +  - ]:        659 :         ctx->cb_fn = cb_fn;
    9152   [ +  -  +  - ]:        659 :         ctx->cb_arg = cb_arg;
    9153   [ +  -  +  - ]:        659 :         ctx->blob = blob;
    9154   [ +  -  +  -  :        659 :         ctx->back_bs_dev = blob->back_bs_dev;
             +  -  +  - ]
    9155   [ +  -  +  -  :        659 :         ctx->abort_io = abort_io;
                   +  - ]
    9156                 :            : 
    9157   [ +  +  +  +  :        659 :         SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64 ": destroying channels for this blob\n",
          +  -  #  #  #  
                      # ]
    9158                 :            :                       blob->id);
    9159                 :            : 
    9160   [ +  -  +  -  :        659 :         blob->bs->esnap_channels_unloading++;
                   +  - ]
    9161   [ +  -  +  - ]:        659 :         spdk_for_each_channel(blob->bs, blob_esnap_destroy_one_channel, ctx,
    9162                 :            :                               blob_esnap_destroy_channels_done);
    9163         [ -  + ]:        400 : }
    9164                 :            : 
    9165                 :            : /*
    9166                 :            :  * Destroy all bs_dev channels on a specific blobstore channel. This should be used when a
    9167                 :            :  * bs_channel is destroyed.
    9168                 :            :  */
    9169                 :            : static void
    9170                 :      11620 : blob_esnap_destroy_bs_channel(struct spdk_bs_channel *ch)
    9171                 :            : {
    9172                 :        977 :         struct blob_esnap_channel *esnap_channel, *esnap_channel_tmp;
    9173                 :            : 
    9174   [ +  +  #  # ]:      11620 :         assert(spdk_get_thread() == spdk_io_channel_get_thread(spdk_io_channel_from_ctx(ch)));
    9175                 :            : 
    9176   [ +  +  +  +  :      11620 :         SPDK_DEBUGLOG(blob_esnap, "destroying channels on thread %s\n",
                   +  - ]
    9177                 :            :                       spdk_thread_get_name(spdk_get_thread()));
    9178   [ +  +  +  +  :      11788 :         RB_FOREACH_SAFE(esnap_channel, blob_esnap_channel_tree, &ch->esnap_channels,
                   +  + ]
    9179                 :            :                         esnap_channel_tmp) {
    9180   [ +  +  +  +  :        168 :                 SPDK_DEBUGLOG(blob_esnap, "blob 0x%" PRIx64
          +  -  #  #  #  
                      # ]
    9181                 :            :                               ": destroying one channel in thread %s\n",
    9182                 :            :                               esnap_channel->blob_id, spdk_thread_get_name(spdk_get_thread()));
    9183         [ +  - ]:        168 :                 RB_REMOVE(blob_esnap_channel_tree, &ch->esnap_channels, esnap_channel);
    9184   [ +  -  +  - ]:        168 :                 spdk_put_io_channel(esnap_channel->channel);
    9185                 :        168 :                 free(esnap_channel);
    9186                 :         28 :         }
    9187   [ +  +  +  +  :      11620 :         SPDK_DEBUGLOG(blob_esnap, "done destroying channels on thread %s\n",
                   +  - ]
    9188                 :            :                       spdk_thread_get_name(spdk_get_thread()));
    9189                 :      11620 : }
    9190                 :            : 
    9191                 :            : struct set_bs_dev_ctx {
    9192                 :            :         struct spdk_blob        *blob;
    9193                 :            :         struct spdk_bs_dev      *back_bs_dev;
    9194                 :            :         spdk_blob_op_complete   cb_fn;
    9195                 :            :         void                    *cb_arg;
    9196                 :            :         int                     bserrno;
    9197                 :            : };
    9198                 :            : 
    9199                 :            : static void
    9200                 :         51 : blob_set_back_bs_dev_done(void *_ctx, int bserrno)
    9201                 :            : {
    9202                 :         51 :         struct set_bs_dev_ctx   *ctx = _ctx;
    9203                 :            : 
    9204         [ +  + ]:         51 :         if (bserrno != 0) {
    9205                 :            :                 /* Even though the unfreeze failed, the update may have succeed. */
    9206   [ #  #  #  #  :          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 ": unfreeze failed with error %d\n", ctx->blob->id,
             #  #  #  # ]
    9207                 :            :                             bserrno);
    9208                 :          0 :         }
    9209   [ +  -  +  -  :         51 :         ctx->cb_fn(ctx->cb_arg, ctx->bserrno);
          -  +  +  -  +  
          -  +  -  +  -  
                   +  - ]
    9210                 :         51 :         free(ctx);
    9211                 :         51 : }
    9212                 :            : 
    9213                 :            : static void
    9214                 :         51 : blob_frozen_set_back_bs_dev(void *_ctx, struct spdk_blob *blob, int bserrno)
    9215                 :            : {
    9216                 :         51 :         struct set_bs_dev_ctx   *ctx = _ctx;
    9217                 :            : 
    9218         [ -  + ]:         51 :         if (bserrno != 0) {
    9219   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 ": failed to release old back_bs_dev with error %d\n",
    9220                 :            :                             blob->id, bserrno);
    9221   [ #  #  #  # ]:          0 :                 ctx->bserrno = bserrno;
    9222                 :          0 :                 blob_unfreeze_io(blob, blob_set_back_bs_dev_done, ctx);
    9223                 :          0 :                 return;
    9224                 :            :         }
    9225                 :            : 
    9226   [ +  -  +  -  :         51 :         if (blob->back_bs_dev != NULL) {
                   -  + ]
    9227   [ +  -  +  -  :         51 :                 blob->back_bs_dev->destroy(blob->back_bs_dev);
          +  -  +  -  -  
          +  +  -  +  -  
                   +  - ]
    9228                 :          8 :         }
    9229                 :            : 
    9230   [ +  -  +  - ]:         51 :         SPDK_NOTICELOG("blob 0x%" PRIx64 ": hotplugged back_bs_dev\n", blob->id);
    9231   [ +  -  +  -  :         51 :         blob->back_bs_dev = ctx->back_bs_dev;
             +  -  +  - ]
    9232   [ +  -  +  - ]:         51 :         ctx->bserrno = 0;
    9233                 :            : 
    9234                 :         51 :         blob_unfreeze_io(blob, blob_set_back_bs_dev_done, ctx);
    9235         [ -  + ]:          8 : }
    9236                 :            : 
    9237                 :            : static void
    9238                 :         51 : blob_frozen_destroy_esnap_channels(void *_ctx, int bserrno)
    9239                 :            : {
    9240                 :         51 :         struct set_bs_dev_ctx   *ctx = _ctx;
    9241   [ +  -  +  - ]:         51 :         struct spdk_blob        *blob = ctx->blob;
    9242                 :            : 
    9243         [ -  + ]:         51 :         if (bserrno != 0) {
    9244   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 ": failed to freeze with error %d\n", blob->id,
    9245                 :            :                             bserrno);
    9246   [ #  #  #  #  :          0 :                 ctx->cb_fn(ctx->cb_arg, bserrno);
          #  #  #  #  #  
                #  #  # ]
    9247                 :          0 :                 free(ctx);
    9248                 :          0 :                 return;
    9249                 :            :         }
    9250                 :            : 
    9251                 :            :         /*
    9252                 :            :          * This does not prevent future reads from the esnap device because any future IO will
    9253                 :            :          * lazily create a new esnap IO channel.
    9254                 :            :          */
    9255                 :         51 :         blob_esnap_destroy_bs_dev_channels(blob, true, blob_frozen_set_back_bs_dev, ctx);
    9256         [ -  + ]:          8 : }
    9257                 :            : 
    9258                 :            : void
    9259                 :         51 : spdk_blob_set_esnap_bs_dev(struct spdk_blob *blob, struct spdk_bs_dev *back_bs_dev,
    9260                 :            :                            spdk_blob_op_complete cb_fn, void *cb_arg)
    9261                 :            : {
    9262                 :          8 :         struct set_bs_dev_ctx   *ctx;
    9263                 :            : 
    9264         [ +  + ]:         51 :         if (!blob_is_esnap_clone(blob)) {
    9265   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 ": not an esnap clone\n", blob->id);
    9266   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -EINVAL);
    9267                 :          0 :                 return;
    9268                 :            :         }
    9269                 :            : 
    9270                 :         51 :         ctx = calloc(1, sizeof(*ctx));
    9271         [ +  + ]:         51 :         if (ctx == NULL) {
    9272   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 ": out of memory while setting back_bs_dev\n",
    9273                 :            :                             blob->id);
    9274   [ #  #  #  # ]:          0 :                 cb_fn(cb_arg, -ENOMEM);
    9275                 :          0 :                 return;
    9276                 :            :         }
    9277   [ +  -  +  - ]:         51 :         ctx->cb_fn = cb_fn;
    9278   [ +  -  +  - ]:         51 :         ctx->cb_arg = cb_arg;
    9279   [ +  -  +  - ]:         51 :         ctx->back_bs_dev = back_bs_dev;
    9280   [ +  -  +  - ]:         51 :         ctx->blob = blob;
    9281                 :         51 :         blob_freeze_io(blob, blob_frozen_destroy_esnap_channels, ctx);
    9282         [ -  + ]:          8 : }
    9283                 :            : 
    9284                 :            : struct spdk_bs_dev *
    9285                 :        154 : spdk_blob_get_esnap_bs_dev(const struct spdk_blob *blob)
    9286                 :            : {
    9287         [ -  + ]:        154 :         if (!blob_is_esnap_clone(blob)) {
    9288   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("blob 0x%" PRIx64 ": not an esnap clone\n", blob->id);
    9289                 :          0 :                 return NULL;
    9290                 :            :         }
    9291                 :            : 
    9292   [ +  -  +  - ]:        154 :         return blob->back_bs_dev;
    9293                 :          4 : }
    9294                 :            : 
    9295                 :            : bool
    9296                 :       1134 : spdk_blob_is_degraded(const struct spdk_blob *blob)
    9297                 :            : {
    9298   [ +  +  +  +  :       1134 :         if (blob->bs->dev->is_degraded != NULL && blob->bs->dev->is_degraded(blob->bs->dev)) {
          +  -  +  -  +  
          -  +  -  +  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      + ]
    9299                 :         24 :                 return true;
    9300                 :            :         }
    9301   [ +  +  +  +  :       1110 :         if (blob->back_bs_dev == NULL || blob->back_bs_dev->is_degraded == NULL) {
          +  +  +  -  +  
          -  +  -  +  -  
                   +  + ]
    9302                 :        921 :                 return false;
    9303                 :            :         }
    9304                 :            : 
    9305   [ +  -  +  -  :        189 :         return blob->back_bs_dev->is_degraded(blob->back_bs_dev);
          +  -  +  -  -  
          +  +  -  +  -  
                   +  - ]
    9306                 :         28 : }
    9307                 :            : 
    9308                 :       1979 : SPDK_LOG_REGISTER_COMPONENT(blob)
    9309                 :       1979 : SPDK_LOG_REGISTER_COMPONENT(blob_esnap)

Generated by: LCOV version 1.15