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