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) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk_internal/lvolstore.h"
8 : : #include "spdk/log.h"
9 : : #include "spdk/string.h"
10 : : #include "spdk/thread.h"
11 : : #include "spdk/blob_bdev.h"
12 : : #include "spdk/tree.h"
13 : : #include "spdk/util.h"
14 : :
15 : : /* Default blob channel opts for lvol */
16 : : #define SPDK_LVOL_BLOB_OPTS_CHANNEL_OPS 512
17 : :
18 : : #define LVOL_NAME "name"
19 : :
20 : 2114 : SPDK_LOG_REGISTER_COMPONENT(lvol)
21 : :
22 : : struct spdk_lvs_degraded_lvol_set {
23 : : struct spdk_lvol_store *lvol_store;
24 : : const void *esnap_id;
25 : : uint32_t id_len;
26 : : TAILQ_HEAD(degraded_lvols, spdk_lvol) lvols;
27 : : RB_ENTRY(spdk_lvs_degraded_lvol_set) node;
28 : : };
29 : :
30 : : static TAILQ_HEAD(, spdk_lvol_store) g_lvol_stores = TAILQ_HEAD_INITIALIZER(g_lvol_stores);
31 : : static pthread_mutex_t g_lvol_stores_mutex = PTHREAD_MUTEX_INITIALIZER;
32 : :
33 : : static inline int lvs_opts_copy(const struct spdk_lvs_opts *src, struct spdk_lvs_opts *dst);
34 : : static int lvs_esnap_bs_dev_create(void *bs_ctx, void *blob_ctx, struct spdk_blob *blob,
35 : : const void *esnap_id, uint32_t id_len,
36 : : struct spdk_bs_dev **_bs_dev);
37 : : static struct spdk_lvol *lvs_get_lvol_by_blob_id(struct spdk_lvol_store *lvs, spdk_blob_id blob_id);
38 : : static void lvs_degraded_lvol_set_add(struct spdk_lvs_degraded_lvol_set *degraded_set,
39 : : struct spdk_lvol *lvol);
40 : : static void lvs_degraded_lvol_set_remove(struct spdk_lvs_degraded_lvol_set *degraded_set,
41 : : struct spdk_lvol *lvol);
42 : :
43 : : static int
44 : 409 : add_lvs_to_list(struct spdk_lvol_store *lvs)
45 : : {
46 : : struct spdk_lvol_store *tmp;
47 : 409 : bool name_conflict = false;
48 : :
49 [ # # ]: 409 : pthread_mutex_lock(&g_lvol_stores_mutex);
50 [ + + # # : 443 : TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
# # # # ]
51 [ + + - + : 41 : if (!strncmp(lvs->name, tmp->name, SPDK_LVS_NAME_MAX)) {
+ + # # #
# ]
52 : 7 : name_conflict = true;
53 : 7 : break;
54 : : }
55 : 0 : }
56 [ + + # # ]: 409 : if (!name_conflict) {
57 [ # # # # ]: 402 : lvs->on_list = true;
58 [ # # # # : 402 : TAILQ_INSERT_TAIL(&g_lvol_stores, lvs, link);
# # # # #
# # # # #
# # # # #
# # # #
# ]
59 : 0 : }
60 [ # # ]: 409 : pthread_mutex_unlock(&g_lvol_stores_mutex);
61 : :
62 [ + + ]: 409 : return name_conflict ? -1 : 0;
63 : : }
64 : :
65 : : static struct spdk_lvol_store *
66 : 5492 : lvs_alloc(void)
67 : : {
68 : : struct spdk_lvol_store *lvs;
69 : :
70 : 5492 : lvs = calloc(1, sizeof(*lvs));
71 [ + + ]: 5492 : if (lvs == NULL) {
72 : 0 : return NULL;
73 : : }
74 : :
75 [ + - + - : 5492 : TAILQ_INIT(&lvs->lvols);
+ - + - +
- + - + -
+ - ]
76 [ + - + - : 5492 : TAILQ_INIT(&lvs->pending_lvols);
+ - + - +
- + - + -
+ - ]
77 [ + - + - : 5492 : TAILQ_INIT(&lvs->retry_open_lvols);
+ - + - +
- + - + -
+ - ]
78 : :
79 [ + - + - ]: 5492 : lvs->load_esnaps = false;
80 [ + - + - : 5492 : RB_INIT(&lvs->degraded_lvol_sets_tree);
+ - ]
81 [ + - + - ]: 5492 : lvs->thread = spdk_get_thread();
82 : :
83 : 5492 : return lvs;
84 : 47 : }
85 : :
86 : : static void
87 : 5492 : lvs_free(struct spdk_lvol_store *lvs)
88 : : {
89 [ + + ]: 5492 : pthread_mutex_lock(&g_lvol_stores_mutex);
90 [ + + + + : 5492 : if (lvs->on_list) {
+ - + - ]
91 [ + + # # : 402 : TAILQ_REMOVE(&g_lvol_stores, lvs, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
92 : 0 : }
93 [ + + ]: 5492 : pthread_mutex_unlock(&g_lvol_stores_mutex);
94 : :
95 [ + + + - : 5492 : assert(RB_EMPTY(&lvs->degraded_lvol_sets_tree));
+ - + - #
# ]
96 : :
97 : 5492 : free(lvs);
98 : 5492 : }
99 : :
100 : : static struct spdk_lvol *
101 : 568 : lvol_alloc(struct spdk_lvol_store *lvs, const char *name, bool thin_provision,
102 : : enum lvol_clear_method clear_method)
103 : : {
104 : : struct spdk_lvol *lvol;
105 : :
106 : 568 : lvol = calloc(1, sizeof(*lvol));
107 [ - + ]: 568 : if (lvol == NULL) {
108 : 0 : return NULL;
109 : : }
110 : :
111 [ # # # # ]: 568 : lvol->lvol_store = lvs;
112 [ # # # # ]: 568 : lvol->clear_method = (enum blob_clear_method)clear_method;
113 [ - + ]: 568 : snprintf(lvol->name, sizeof(lvol->name), "%s", name);
114 [ # # ]: 568 : spdk_uuid_generate(&lvol->uuid);
115 [ # # # # ]: 568 : spdk_uuid_fmt_lower(lvol->uuid_str, sizeof(lvol->uuid_str), &lvol->uuid);
116 [ # # # # ]: 568 : spdk_uuid_fmt_lower(lvol->unique_id, sizeof(lvol->uuid_str), &lvol->uuid);
117 : :
118 [ # # # # : 568 : TAILQ_INSERT_TAIL(&lvs->pending_lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
119 : :
120 : 568 : return lvol;
121 : 0 : }
122 : :
123 : : static void
124 : 684 : lvol_free(struct spdk_lvol *lvol)
125 : : {
126 : 684 : free(lvol);
127 : 684 : }
128 : :
129 : : static void
130 : 113 : lvol_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
131 : : {
132 : 113 : struct spdk_lvol_with_handle_req *req = cb_arg;
133 [ # # # # ]: 113 : struct spdk_lvol *lvol = req->lvol;
134 : :
135 [ + + ]: 113 : if (lvolerrno != 0) {
136 [ - + - + : 9 : SPDK_INFOLOG(lvol, "Failed to open lvol %s\n", lvol->unique_id);
# # # # ]
137 : 9 : goto end;
138 : : }
139 : :
140 [ # # # # ]: 104 : lvol->ref_count++;
141 [ # # # # ]: 104 : lvol->blob = blob;
142 : 113 : end:
143 [ # # # # : 113 : req->cb_fn(req->cb_arg, lvol, lvolerrno);
# # # # #
# # # ]
144 : 113 : free(req);
145 : 113 : }
146 : :
147 : : void
148 : 116 : spdk_lvol_open(struct spdk_lvol *lvol, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
149 : : {
150 : : struct spdk_lvol_with_handle_req *req;
151 : 98 : struct spdk_blob_open_opts opts;
152 : :
153 [ - + # # ]: 116 : assert(cb_fn != NULL);
154 : :
155 [ - + ]: 116 : if (lvol == NULL) {
156 : 0 : SPDK_ERRLOG("lvol does not exist\n");
157 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENODEV);
158 : 0 : return;
159 : : }
160 : :
161 [ - + - + : 116 : if (lvol->action_in_progress == true) {
# # # # ]
162 : 0 : SPDK_ERRLOG("Cannot open lvol - operations on lvol pending\n");
163 [ # # # # ]: 0 : cb_fn(cb_arg, lvol, -EBUSY);
164 : 0 : return;
165 : : }
166 : :
167 [ + + # # : 116 : if (lvol->ref_count > 0) {
# # ]
168 [ # # # # ]: 3 : lvol->ref_count++;
169 [ # # # # ]: 3 : cb_fn(cb_arg, lvol, 0);
170 : 3 : return;
171 : : }
172 : :
173 : 113 : req = calloc(1, sizeof(*req));
174 [ - + ]: 113 : if (req == NULL) {
175 : 0 : SPDK_ERRLOG("Cannot alloc memory for request structure\n");
176 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
177 : 0 : return;
178 : : }
179 : :
180 [ # # # # ]: 113 : req->cb_fn = cb_fn;
181 [ # # # # ]: 113 : req->cb_arg = cb_arg;
182 [ # # # # ]: 113 : req->lvol = lvol;
183 : :
184 : 113 : spdk_blob_open_opts_init(&opts, sizeof(opts));
185 [ # # # # ]: 113 : opts.clear_method = lvol->clear_method;
186 : :
187 [ # # # # : 113 : spdk_bs_open_blob_ext(lvol->lvol_store->blobstore, lvol->blob_id, &opts, lvol_open_cb, req);
# # # # #
# # # ]
188 : 0 : }
189 : :
190 : : static void
191 : 24 : bs_unload_with_error_cb(void *cb_arg, int lvolerrno)
192 : : {
193 : 24 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
194 : :
195 [ # # # # : 24 : req->cb_fn(req->cb_arg, NULL, req->lvserrno);
# # # # #
# # # # #
# # ]
196 : 24 : free(req);
197 : 24 : }
198 : :
199 : : static void
200 : 317 : load_next_lvol(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
201 : : {
202 : 317 : struct spdk_lvs_with_handle_req *req = cb_arg;
203 [ # # # # ]: 317 : struct spdk_lvol_store *lvs = req->lvol_store;
204 [ # # # # ]: 317 : struct spdk_blob_store *bs = lvs->blobstore;
205 : : struct spdk_lvol *lvol, *tmp;
206 : : spdk_blob_id blob_id;
207 : 265 : const char *attr;
208 : 265 : size_t value_len;
209 : : int rc;
210 : :
211 [ + + ]: 317 : if (lvolerrno == -ENOENT) {
212 : : /* Finished iterating */
213 [ + + # # : 93 : if (req->lvserrno == 0) {
# # ]
214 [ # # # # ]: 87 : lvs->load_esnaps = true;
215 [ # # # # : 87 : req->cb_fn(req->cb_arg, lvs, req->lvserrno);
# # # # #
# # # # #
# # ]
216 : 87 : free(req);
217 : 0 : } else {
218 [ + + # # : 18 : TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
219 [ + + # # : 12 : TAILQ_REMOVE(&lvs->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
220 : 12 : lvol_free(lvol);
221 : 0 : }
222 : 6 : lvs_free(lvs);
223 : 6 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
224 : : }
225 : 110 : return;
226 [ + + ]: 224 : } else if (lvolerrno < 0) {
227 : 6 : SPDK_ERRLOG("Failed to fetch blobs list\n");
228 [ # # # # ]: 6 : req->lvserrno = lvolerrno;
229 : 6 : goto invalid;
230 : : }
231 : :
232 : 218 : blob_id = spdk_blob_get_id(blob);
233 : :
234 [ + + # # : 218 : if (blob_id == lvs->super_blob_id) {
# # ]
235 [ - + - + : 93 : SPDK_INFOLOG(lvol, "found superblob %"PRIu64"\n", (uint64_t)blob_id);
# # ]
236 : 93 : spdk_bs_iter_next(bs, blob, load_next_lvol, req);
237 : 93 : return;
238 : : }
239 : :
240 : 125 : lvol = calloc(1, sizeof(*lvol));
241 [ - + ]: 125 : if (!lvol) {
242 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
243 [ # # # # ]: 0 : req->lvserrno = -ENOMEM;
244 : 0 : goto invalid;
245 : : }
246 : :
247 : : /*
248 : : * Do not store a reference to blob now because spdk_bs_iter_next() will close it.
249 : : * Storing blob_id for future lookups is fine.
250 : : */
251 [ # # # # ]: 125 : lvol->blob_id = blob_id;
252 [ # # # # ]: 125 : lvol->lvol_store = lvs;
253 : :
254 : 125 : rc = spdk_blob_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len);
255 [ + - + - : 250 : if (rc != 0 || value_len != SPDK_UUID_STRING_LEN || attr[SPDK_UUID_STRING_LEN - 1] != '\0' ||
+ - - + #
# # # ]
256 [ # # ]: 125 : spdk_uuid_parse(&lvol->uuid, attr) != 0) {
257 [ # # # # : 0 : SPDK_INFOLOG(lvol, "Missing or corrupt lvol uuid\n");
# # ]
258 [ # # ]: 0 : spdk_uuid_set_null(&lvol->uuid);
259 : 0 : }
260 [ # # # # ]: 125 : spdk_uuid_fmt_lower(lvol->uuid_str, sizeof(lvol->uuid_str), &lvol->uuid);
261 : :
262 [ + - # # ]: 125 : if (!spdk_uuid_is_null(&lvol->uuid)) {
263 [ # # # # ]: 125 : snprintf(lvol->unique_id, sizeof(lvol->unique_id), "%s", lvol->uuid_str);
264 : 0 : } else {
265 [ # # # # : 0 : spdk_uuid_fmt_lower(lvol->unique_id, sizeof(lvol->unique_id), &lvol->lvol_store->uuid);
# # # # ]
266 [ # # # # ]: 0 : value_len = strlen(lvol->unique_id);
267 [ # # # # : 0 : snprintf(lvol->unique_id + value_len, sizeof(lvol->unique_id) - value_len, "_%"PRIu64,
# # ]
268 : 0 : (uint64_t)blob_id);
269 : : }
270 : :
271 : 125 : rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&attr, &value_len);
272 [ + - - + ]: 125 : if (rc != 0 || value_len > SPDK_LVOL_NAME_MAX) {
273 : 0 : SPDK_ERRLOG("Cannot assign lvol name\n");
274 : 0 : lvol_free(lvol);
275 [ # # # # ]: 0 : req->lvserrno = -EINVAL;
276 : 0 : goto invalid;
277 : : }
278 : :
279 [ # # ]: 125 : snprintf(lvol->name, sizeof(lvol->name), "%s", attr);
280 : :
281 [ # # # # : 125 : TAILQ_INSERT_TAIL(&lvs->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
282 : :
283 [ # # # # ]: 125 : lvs->lvol_count++;
284 : :
285 [ + + + - : 125 : SPDK_INFOLOG(lvol, "added lvol %s (%s)\n", lvol->unique_id, lvol->uuid_str);
# # # # #
# ]
286 : :
287 : 131 : invalid:
288 : 131 : spdk_bs_iter_next(bs, blob, load_next_lvol, req);
289 : 0 : }
290 : :
291 : : static void
292 : 96 : close_super_cb(void *cb_arg, int lvolerrno)
293 : : {
294 : 96 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
295 [ # # # # ]: 96 : struct spdk_lvol_store *lvs = req->lvol_store;
296 [ # # # # ]: 96 : struct spdk_blob_store *bs = lvs->blobstore;
297 : :
298 [ + + ]: 96 : if (lvolerrno != 0) {
299 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Could not close super blob\n");
# # ]
300 : 3 : lvs_free(lvs);
301 [ # # # # ]: 3 : req->lvserrno = -ENODEV;
302 : 3 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
303 : 3 : return;
304 : : }
305 : :
306 : : /* Start loading lvols */
307 [ # # # # ]: 93 : spdk_bs_iter_first(lvs->blobstore, load_next_lvol, req);
308 : 0 : }
309 : :
310 : : static void
311 : 9 : close_super_blob_with_error_cb(void *cb_arg, int lvolerrno)
312 : : {
313 : 9 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
314 [ # # # # ]: 9 : struct spdk_lvol_store *lvs = req->lvol_store;
315 [ # # # # ]: 9 : struct spdk_blob_store *bs = lvs->blobstore;
316 : :
317 : 9 : lvs_free(lvs);
318 : :
319 : 9 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
320 : 9 : }
321 : :
322 : : static void
323 : 108 : lvs_read_uuid(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
324 : : {
325 : 108 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
326 [ # # # # ]: 108 : struct spdk_lvol_store *lvs = req->lvol_store;
327 [ # # # # ]: 108 : struct spdk_blob_store *bs = lvs->blobstore;
328 : 91 : const char *attr;
329 : 91 : size_t value_len;
330 : : int rc;
331 : :
332 [ + + ]: 108 : if (lvolerrno != 0) {
333 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Could not open super blob\n");
# # ]
334 : 3 : lvs_free(lvs);
335 [ # # # # ]: 3 : req->lvserrno = -ENODEV;
336 : 3 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
337 : 3 : return;
338 : : }
339 : :
340 : 105 : rc = spdk_blob_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len);
341 [ + + + - : 105 : if (rc != 0 || value_len != SPDK_UUID_STRING_LEN || attr[SPDK_UUID_STRING_LEN - 1] != '\0') {
- + # # #
# ]
342 [ - + - + : 3 : SPDK_INFOLOG(lvol, "degraded_set or incorrect UUID\n");
# # ]
343 [ # # # # ]: 3 : req->lvserrno = -EINVAL;
344 : 3 : spdk_blob_close(blob, close_super_blob_with_error_cb, req);
345 : 3 : return;
346 : : }
347 : :
348 [ - + # # ]: 102 : if (spdk_uuid_parse(&lvs->uuid, attr)) {
349 [ # # # # : 0 : SPDK_INFOLOG(lvol, "incorrect UUID '%s'\n", attr);
# # ]
350 [ # # # # ]: 0 : req->lvserrno = -EINVAL;
351 : 0 : spdk_blob_close(blob, close_super_blob_with_error_cb, req);
352 : 0 : return;
353 : : }
354 : :
355 : 102 : rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&attr, &value_len);
356 [ + + - + ]: 102 : if (rc != 0 || value_len > SPDK_LVS_NAME_MAX) {
357 [ - + - + : 3 : SPDK_INFOLOG(lvol, "degraded_set or invalid name\n");
# # ]
358 [ # # # # ]: 3 : req->lvserrno = -EINVAL;
359 : 3 : spdk_blob_close(blob, close_super_blob_with_error_cb, req);
360 : 3 : return;
361 : : }
362 : :
363 [ - + ]: 99 : snprintf(lvs->name, sizeof(lvs->name), "%s", attr);
364 : :
365 : 99 : rc = add_lvs_to_list(lvs);
366 [ + + ]: 99 : if (rc) {
367 [ - + - + : 3 : SPDK_INFOLOG(lvol, "lvolstore with name %s already exists\n", lvs->name);
# # # # ]
368 [ # # # # ]: 3 : req->lvserrno = -EEXIST;
369 : 3 : spdk_blob_close(blob, close_super_blob_with_error_cb, req);
370 : 3 : return;
371 : : }
372 : :
373 [ # # # # ]: 96 : lvs->super_blob_id = spdk_blob_get_id(blob);
374 : :
375 : 96 : spdk_blob_close(blob, close_super_cb, req);
376 : 0 : }
377 : :
378 : : static void
379 : 111 : lvs_open_super(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
380 : : {
381 : 111 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
382 [ # # # # ]: 111 : struct spdk_lvol_store *lvs = req->lvol_store;
383 [ # # # # ]: 111 : struct spdk_blob_store *bs = lvs->blobstore;
384 : :
385 [ + + ]: 111 : if (lvolerrno != 0) {
386 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Super blob not found\n");
# # ]
387 : 3 : lvs_free(lvs);
388 [ # # # # ]: 3 : req->lvserrno = -ENODEV;
389 : 3 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
390 : 3 : return;
391 : : }
392 : :
393 : 108 : spdk_bs_open_blob(bs, blobid, lvs_read_uuid, req);
394 : 0 : }
395 : :
396 : : static void
397 : 5173 : lvs_load_cb(void *cb_arg, struct spdk_blob_store *bs, int lvolerrno)
398 : : {
399 : 5173 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
400 [ + - + - ]: 5173 : struct spdk_lvol_store *lvs = req->lvol_store;
401 : :
402 [ + + ]: 5173 : if (lvolerrno != 0) {
403 [ + - + - : 5062 : req->cb_fn(req->cb_arg, NULL, lvolerrno);
- + - + +
- + - ]
404 : 5062 : lvs_free(lvs);
405 : 5062 : free(req);
406 : 5062 : return;
407 : : }
408 : :
409 [ # # # # ]: 111 : lvs->blobstore = bs;
410 [ # # # # : 111 : lvs->bs_dev = req->bs_dev;
# # # # ]
411 : :
412 : 111 : spdk_bs_get_super(bs, lvs_open_super, req);
413 : 47 : }
414 : :
415 : : static void
416 : 5489 : lvs_bs_opts_init(struct spdk_bs_opts *opts)
417 : : {
418 : 5489 : spdk_bs_opts_init(opts, sizeof(*opts));
419 [ + - + - ]: 5489 : opts->max_channel_ops = SPDK_LVOL_BLOB_OPTS_CHANNEL_OPS;
420 : 5489 : }
421 : :
422 : : static void
423 : 5176 : lvs_load(struct spdk_bs_dev *bs_dev, const struct spdk_lvs_opts *_lvs_opts,
424 : : spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
425 : : {
426 : : struct spdk_lvs_with_handle_req *req;
427 : 5176 : struct spdk_bs_opts bs_opts = {};
428 : 2643 : struct spdk_lvs_opts lvs_opts;
429 : :
430 [ + + # # ]: 5176 : assert(cb_fn != NULL);
431 : :
432 [ + + ]: 5176 : if (bs_dev == NULL) {
433 : 0 : SPDK_ERRLOG("Blobstore device does not exist\n");
434 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENODEV);
435 : 0 : return;
436 : : }
437 : :
438 : 5176 : spdk_lvs_opts_init(&lvs_opts);
439 [ + + ]: 5176 : if (_lvs_opts != NULL) {
440 [ + + ]: 5134 : if (lvs_opts_copy(_lvs_opts, &lvs_opts) != 0) {
441 : 3 : SPDK_ERRLOG("Invalid options\n");
442 [ # # # # ]: 3 : cb_fn(cb_arg, NULL, -EINVAL);
443 : 3 : return;
444 : : }
445 : 47 : }
446 : :
447 : 5173 : req = calloc(1, sizeof(*req));
448 [ + + ]: 5173 : if (req == NULL) {
449 : 0 : SPDK_ERRLOG("Cannot alloc memory for request structure\n");
450 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
451 : 0 : return;
452 : : }
453 : :
454 [ + - + - ]: 5173 : req->lvol_store = lvs_alloc();
455 [ + + + - : 5173 : if (req->lvol_store == NULL) {
+ - ]
456 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store\n");
457 : 0 : free(req);
458 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
459 : 0 : return;
460 : : }
461 [ + - + - ]: 5173 : req->cb_fn = cb_fn;
462 [ + - + - ]: 5173 : req->cb_arg = cb_arg;
463 [ + - + - ]: 5173 : req->bs_dev = bs_dev;
464 : :
465 : 5173 : lvs_bs_opts_init(&bs_opts);
466 [ - + ]: 5173 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "LVOLSTORE");
467 : :
468 [ + + ]: 5173 : if (lvs_opts.esnap_bs_dev_create != NULL) {
469 [ + - + - : 5131 : req->lvol_store->esnap_bs_dev_create = lvs_opts.esnap_bs_dev_create;
+ - + - ]
470 : 5131 : bs_opts.esnap_bs_dev_create = lvs_esnap_bs_dev_create;
471 [ + - + - ]: 5131 : bs_opts.esnap_ctx = req->lvol_store;
472 : 47 : }
473 : :
474 : 5173 : spdk_bs_load(bs_dev, &bs_opts, lvs_load_cb, req);
475 : 47 : }
476 : :
477 : : void
478 : 42 : spdk_lvs_load(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
479 : : {
480 : 42 : lvs_load(bs_dev, NULL, cb_fn, cb_arg);
481 : 42 : }
482 : :
483 : : void
484 : 5134 : spdk_lvs_load_ext(struct spdk_bs_dev *bs_dev, const struct spdk_lvs_opts *opts,
485 : : spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
486 : : {
487 : 5134 : lvs_load(bs_dev, opts, cb_fn, cb_arg);
488 : 5134 : }
489 : :
490 : : static void
491 : 0 : remove_bs_on_error_cb(void *cb_arg, int bserrno)
492 : : {
493 : 0 : }
494 : :
495 : : static void
496 : 0 : exit_error_lvs_req(struct spdk_lvs_with_handle_req *req, struct spdk_lvol_store *lvs, int lvolerrno)
497 : : {
498 [ # # # # : 0 : req->cb_fn(req->cb_arg, NULL, lvolerrno);
# # # # #
# # # ]
499 [ # # # # ]: 0 : spdk_bs_destroy(lvs->blobstore, remove_bs_on_error_cb, NULL);
500 : 0 : lvs_free(lvs);
501 : 0 : free(req);
502 : 0 : }
503 : :
504 : : static void
505 : 306 : super_create_close_cb(void *cb_arg, int lvolerrno)
506 : : {
507 : 306 : struct spdk_lvs_with_handle_req *req = cb_arg;
508 [ # # # # ]: 306 : struct spdk_lvol_store *lvs = req->lvol_store;
509 : :
510 [ - + ]: 306 : if (lvolerrno < 0) {
511 : 0 : SPDK_ERRLOG("Lvol store init failed: could not close super blob\n");
512 : 0 : exit_error_lvs_req(req, lvs, lvolerrno);
513 : 0 : return;
514 : : }
515 : :
516 [ # # # # : 306 : req->cb_fn(req->cb_arg, lvs, lvolerrno);
# # # # #
# # # ]
517 : 306 : free(req);
518 : 0 : }
519 : :
520 : : static void
521 : 306 : super_blob_set_cb(void *cb_arg, int lvolerrno)
522 : : {
523 : 306 : struct spdk_lvs_with_handle_req *req = cb_arg;
524 [ # # # # ]: 306 : struct spdk_lvol_store *lvs = req->lvol_store;
525 [ # # # # ]: 306 : struct spdk_blob *blob = lvs->super_blob;
526 : :
527 [ - + ]: 306 : if (lvolerrno < 0) {
528 : 0 : SPDK_ERRLOG("Lvol store init failed: could not set uuid for super blob\n");
529 : 0 : exit_error_lvs_req(req, lvs, lvolerrno);
530 : 0 : return;
531 : : }
532 : :
533 : 306 : spdk_blob_close(blob, super_create_close_cb, req);
534 : 0 : }
535 : :
536 : : static void
537 : 306 : super_blob_init_cb(void *cb_arg, int lvolerrno)
538 : : {
539 : 306 : struct spdk_lvs_with_handle_req *req = cb_arg;
540 [ # # # # ]: 306 : struct spdk_lvol_store *lvs = req->lvol_store;
541 [ # # # # ]: 306 : struct spdk_blob *blob = lvs->super_blob;
542 : 256 : char uuid[SPDK_UUID_STRING_LEN];
543 : :
544 [ - + ]: 306 : if (lvolerrno < 0) {
545 : 0 : SPDK_ERRLOG("Lvol store init failed: could not set super blob\n");
546 : 0 : exit_error_lvs_req(req, lvs, lvolerrno);
547 : 0 : return;
548 : : }
549 : :
550 [ # # ]: 306 : spdk_uuid_fmt_lower(uuid, sizeof(uuid), &lvs->uuid);
551 : :
552 : 306 : spdk_blob_set_xattr(blob, "uuid", uuid, sizeof(uuid));
553 [ - + # # : 306 : spdk_blob_set_xattr(blob, "name", lvs->name, strnlen(lvs->name, SPDK_LVS_NAME_MAX) + 1);
# # ]
554 : 306 : spdk_blob_sync_md(blob, super_blob_set_cb, req);
555 : 0 : }
556 : :
557 : : static void
558 : 306 : super_blob_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
559 : : {
560 : 306 : struct spdk_lvs_with_handle_req *req = cb_arg;
561 [ # # # # ]: 306 : struct spdk_lvol_store *lvs = req->lvol_store;
562 : :
563 [ - + ]: 306 : if (lvolerrno < 0) {
564 : 0 : SPDK_ERRLOG("Lvol store init failed: could not open super blob\n");
565 : 0 : exit_error_lvs_req(req, lvs, lvolerrno);
566 : 0 : return;
567 : : }
568 : :
569 [ # # # # ]: 306 : lvs->super_blob = blob;
570 [ # # # # ]: 306 : lvs->super_blob_id = spdk_blob_get_id(blob);
571 : :
572 [ # # # # : 306 : spdk_bs_set_super(lvs->blobstore, lvs->super_blob_id, super_blob_init_cb, req);
# # # # ]
573 : 0 : }
574 : :
575 : : static void
576 : 306 : super_blob_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
577 : : {
578 : 306 : struct spdk_lvs_with_handle_req *req = cb_arg;
579 [ # # # # ]: 306 : struct spdk_lvol_store *lvs = req->lvol_store;
580 : : struct spdk_blob_store *bs;
581 : :
582 [ - + ]: 306 : if (lvolerrno < 0) {
583 : 0 : SPDK_ERRLOG("Lvol store init failed: could not create super blob\n");
584 : 0 : exit_error_lvs_req(req, lvs, lvolerrno);
585 : 0 : return;
586 : : }
587 : :
588 [ # # # # : 306 : bs = req->lvol_store->blobstore;
# # # # ]
589 : :
590 : 306 : spdk_bs_open_blob(bs, blobid, super_blob_create_open_cb, req);
591 : 0 : }
592 : :
593 : : static void
594 : 306 : lvs_init_cb(void *cb_arg, struct spdk_blob_store *bs, int lvserrno)
595 : : {
596 : 306 : struct spdk_lvs_with_handle_req *lvs_req = cb_arg;
597 [ # # # # ]: 306 : struct spdk_lvol_store *lvs = lvs_req->lvol_store;
598 : :
599 [ - + ]: 306 : if (lvserrno != 0) {
600 [ # # # # ]: 0 : assert(bs == NULL);
601 [ # # # # : 0 : lvs_req->cb_fn(lvs_req->cb_arg, NULL, lvserrno);
# # # # #
# # # ]
602 : 0 : SPDK_ERRLOG("Lvol store init failed: could not initialize blobstore\n");
603 : 0 : lvs_free(lvs);
604 : 0 : free(lvs_req);
605 : 0 : return;
606 : : }
607 : :
608 [ - + # # ]: 306 : assert(bs != NULL);
609 [ # # # # ]: 306 : lvs->blobstore = bs;
610 : :
611 [ - + - + : 306 : SPDK_INFOLOG(lvol, "Lvol store initialized\n");
# # ]
612 : :
613 : : /* create super blob */
614 [ # # # # ]: 306 : spdk_bs_create_blob(lvs->blobstore, super_blob_create_cb, lvs_req);
615 : 0 : }
616 : :
617 : : void
618 : 10936 : spdk_lvs_opts_init(struct spdk_lvs_opts *o)
619 : : {
620 [ + + ]: 10936 : memset(o, 0, sizeof(*o));
621 [ + - + - ]: 10936 : o->cluster_sz = SPDK_LVS_OPTS_CLUSTER_SZ;
622 [ + - + - ]: 10936 : o->clear_method = LVS_CLEAR_WITH_UNMAP;
623 [ + - + - ]: 10936 : o->num_md_pages_per_cluster_ratio = 100;
624 [ + - + - ]: 10936 : o->opts_size = sizeof(*o);
625 : 10936 : }
626 : :
627 : : static inline int
628 : 5452 : lvs_opts_copy(const struct spdk_lvs_opts *src, struct spdk_lvs_opts *dst)
629 : : {
630 [ + + + - : 5452 : if (src->opts_size == 0) {
+ - ]
631 : 3 : SPDK_ERRLOG("opts_size should not be zero value\n");
632 : 3 : return -1;
633 : : }
634 : : #define FIELD_OK(field) \
635 : : offsetof(struct spdk_lvs_opts, field) + sizeof(src->field) <= src->opts_size
636 : :
637 : : #define SET_FIELD(field) \
638 : : if (FIELD_OK(field)) { \
639 : : dst->field = src->field; \
640 : : } \
641 : :
642 [ + - + - : 5449 : SET_FIELD(cluster_sz);
- + + - +
- + - +
- ]
643 [ + - + - : 5449 : SET_FIELD(clear_method);
- + + - +
- + - +
- ]
644 [ + - + - : 5449 : if (FIELD_OK(name)) {
- + ]
645 [ + + + + : 5449 : memcpy(&dst->name, &src->name, sizeof(dst->name));
+ - + - ]
646 : 47 : }
647 [ + - + - : 5449 : SET_FIELD(num_md_pages_per_cluster_ratio);
- + + - +
- + - +
- ]
648 [ + - + - : 5449 : SET_FIELD(opts_size);
- + + - +
- + - +
- ]
649 [ + - + - : 5449 : SET_FIELD(esnap_bs_dev_create);
- + + - +
- + - +
- ]
650 [ + - + - : 5449 : SET_FIELD(md_page_size);
- + + - +
- + - +
- ]
651 : :
652 [ + - + - : 5449 : dst->opts_size = src->opts_size;
+ - + - ]
653 : :
654 : : /* You should not remove this statement, but need to update the assert statement
655 : : * if you add a new field, and also add a corresponding SET_FIELD statement */
656 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_lvs_opts) == 92, "Incorrect size");
657 : :
658 : : #undef FIELD_OK
659 : : #undef SET_FIELD
660 : :
661 : 5449 : return 0;
662 : 47 : }
663 : :
664 : : static void
665 : 316 : setup_lvs_opts(struct spdk_bs_opts *bs_opts, struct spdk_lvs_opts *o, uint32_t total_clusters,
666 : : void *esnap_ctx)
667 : : {
668 [ - + # # ]: 316 : assert(o != NULL);
669 : 316 : lvs_bs_opts_init(bs_opts);
670 [ # # # # : 316 : bs_opts->cluster_sz = o->cluster_sz;
# # # # ]
671 [ # # # # : 316 : bs_opts->clear_method = (enum bs_clear_method)o->clear_method;
# # # # ]
672 [ # # # # : 316 : bs_opts->num_md_pages = (o->num_md_pages_per_cluster_ratio * total_clusters) / 100;
# # # # #
# ]
673 [ # # # # : 316 : bs_opts->md_page_size = o->md_page_size;
# # # # ]
674 [ # # # # : 316 : bs_opts->esnap_bs_dev_create = o->esnap_bs_dev_create;
# # # # ]
675 [ # # # # ]: 316 : bs_opts->esnap_ctx = esnap_ctx;
676 [ - + # # ]: 316 : snprintf(bs_opts->bstype.bstype, sizeof(bs_opts->bstype.bstype), "LVOLSTORE");
677 : 316 : }
678 : :
679 : : int
680 : 321 : spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o,
681 : : spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
682 : : {
683 : : struct spdk_lvol_store *lvs;
684 : : struct spdk_lvs_with_handle_req *lvs_req;
685 : 321 : struct spdk_bs_opts opts = {};
686 : 271 : struct spdk_lvs_opts lvs_opts;
687 : : uint32_t total_clusters;
688 : : int rc;
689 : :
690 [ + + ]: 321 : if (bs_dev == NULL) {
691 : 3 : SPDK_ERRLOG("Blobstore device does not exist\n");
692 : 3 : return -ENODEV;
693 : : }
694 : :
695 [ - + ]: 318 : if (o == NULL) {
696 : 0 : SPDK_ERRLOG("spdk_lvs_opts not specified\n");
697 : 0 : return -EINVAL;
698 : : }
699 : :
700 : 318 : spdk_lvs_opts_init(&lvs_opts);
701 [ - + ]: 318 : if (lvs_opts_copy(o, &lvs_opts) != 0) {
702 : 0 : SPDK_ERRLOG("spdk_lvs_opts invalid\n");
703 : 0 : return -EINVAL;
704 : : }
705 : :
706 [ + + - + : 318 : if (lvs_opts.cluster_sz < bs_dev->blocklen || (lvs_opts.cluster_sz % bs_dev->blocklen) != 0) {
+ + # # #
# # # #
# ]
707 [ # # # # ]: 2 : SPDK_ERRLOG("Cluster size %" PRIu32 " is smaller than blocklen %" PRIu32
708 : : "Or not an integral multiple\n", lvs_opts.cluster_sz, bs_dev->blocklen);
709 : 2 : return -EINVAL;
710 : : }
711 [ - + - + : 316 : total_clusters = bs_dev->blockcnt / (lvs_opts.cluster_sz / bs_dev->blocklen);
# # # # #
# # # ]
712 : :
713 : 316 : lvs = lvs_alloc();
714 [ - + ]: 316 : if (!lvs) {
715 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store base pointer\n");
716 : 0 : return -ENOMEM;
717 : : }
718 : :
719 : 316 : setup_lvs_opts(&opts, o, total_clusters, lvs);
720 : :
721 [ + + # # ]: 316 : if (strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX) == SPDK_LVS_NAME_MAX) {
722 : 3 : SPDK_ERRLOG("Name has no null terminator.\n");
723 : 3 : lvs_free(lvs);
724 : 3 : return -EINVAL;
725 : : }
726 : :
727 [ + + # # ]: 313 : if (strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX) == 0) {
728 : 3 : SPDK_ERRLOG("No name specified.\n");
729 : 3 : lvs_free(lvs);
730 : 3 : return -EINVAL;
731 : : }
732 : :
733 [ # # ]: 310 : spdk_uuid_generate(&lvs->uuid);
734 [ # # ]: 310 : snprintf(lvs->name, sizeof(lvs->name), "%s", lvs_opts.name);
735 : :
736 : 310 : rc = add_lvs_to_list(lvs);
737 [ + + ]: 310 : if (rc) {
738 [ # # ]: 4 : SPDK_ERRLOG("lvolstore with name %s already exists\n", lvs->name);
739 : 4 : lvs_free(lvs);
740 : 4 : return -EEXIST;
741 : : }
742 : :
743 : 306 : lvs_req = calloc(1, sizeof(*lvs_req));
744 [ - + ]: 306 : if (!lvs_req) {
745 : 0 : lvs_free(lvs);
746 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
747 : 0 : return -ENOMEM;
748 : : }
749 : :
750 [ - + # # ]: 306 : assert(cb_fn != NULL);
751 [ # # # # ]: 306 : lvs_req->cb_fn = cb_fn;
752 [ # # # # ]: 306 : lvs_req->cb_arg = cb_arg;
753 [ # # # # ]: 306 : lvs_req->lvol_store = lvs;
754 [ # # # # ]: 306 : lvs->bs_dev = bs_dev;
755 : :
756 [ - + - + : 306 : SPDK_INFOLOG(lvol, "Initializing lvol store\n");
# # ]
757 : 306 : spdk_bs_init(bs_dev, &opts, lvs_init_cb, lvs_req);
758 : :
759 : 306 : return 0;
760 : 0 : }
761 : :
762 : : static void
763 : 7 : lvs_rename_cb(void *cb_arg, int lvolerrno)
764 : : {
765 : 7 : struct spdk_lvs_req *req = cb_arg;
766 : :
767 [ + + ]: 7 : if (lvolerrno != 0) {
768 [ # # # # ]: 3 : req->lvserrno = lvolerrno;
769 : 0 : }
770 [ + + # # : 7 : if (req->lvserrno != 0) {
# # ]
771 : 3 : SPDK_ERRLOG("Lvol store rename operation failed\n");
772 : : /* Lvs renaming failed, so we should 'clear' new_name.
773 : : * Otherwise it could cause a failure on the next attempt to change the name to 'new_name' */
774 [ - + # # : 3 : snprintf(req->lvol_store->new_name,
# # ]
775 : : sizeof(req->lvol_store->new_name),
776 [ # # # # : 3 : "%s", req->lvol_store->name);
# # ]
777 : 0 : } else {
778 : : /* Update lvs name with new_name */
779 [ - + # # : 4 : snprintf(req->lvol_store->name,
# # ]
780 : : sizeof(req->lvol_store->name),
781 [ # # # # : 4 : "%s", req->lvol_store->new_name);
# # ]
782 : : }
783 : :
784 [ # # # # : 7 : req->cb_fn(req->cb_arg, req->lvserrno);
# # # # #
# # # # #
# # ]
785 : 7 : free(req);
786 : 7 : }
787 : :
788 : : static void
789 : 4 : lvs_rename_sync_cb(void *cb_arg, int lvolerrno)
790 : : {
791 : 4 : struct spdk_lvs_req *req = cb_arg;
792 [ # # # # : 4 : struct spdk_blob *blob = req->lvol_store->super_blob;
# # # # ]
793 : :
794 [ - + ]: 4 : if (lvolerrno < 0) {
795 [ # # # # ]: 0 : req->lvserrno = lvolerrno;
796 : 0 : }
797 : :
798 : 4 : spdk_blob_close(blob, lvs_rename_cb, req);
799 : 4 : }
800 : :
801 : : static void
802 : 7 : lvs_rename_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
803 : : {
804 : 7 : struct spdk_lvs_req *req = cb_arg;
805 : : int rc;
806 : :
807 [ + + ]: 7 : if (lvolerrno < 0) {
808 : 3 : lvs_rename_cb(cb_arg, lvolerrno);
809 : 3 : return;
810 : : }
811 : :
812 [ # # # # : 4 : rc = spdk_blob_set_xattr(blob, "name", req->lvol_store->new_name,
# # ]
813 [ - + # # : 4 : strlen(req->lvol_store->new_name) + 1);
# # # # ]
814 [ - + ]: 4 : if (rc < 0) {
815 [ # # # # ]: 0 : req->lvserrno = rc;
816 : 0 : lvs_rename_sync_cb(req, rc);
817 : 0 : return;
818 : : }
819 : :
820 [ # # # # : 4 : req->lvol_store->super_blob = blob;
# # # # ]
821 : :
822 : 4 : spdk_blob_sync_md(blob, lvs_rename_sync_cb, req);
823 : 0 : }
824 : :
825 : : void
826 : 17 : spdk_lvs_rename(struct spdk_lvol_store *lvs, const char *new_name,
827 : : spdk_lvs_op_complete cb_fn, void *cb_arg)
828 : : {
829 : : struct spdk_lvs_req *req;
830 : : struct spdk_lvol_store *tmp;
831 : :
832 : : /* Check if new name is current lvs name.
833 : : * If so, return success immediately */
834 [ + + - + : 17 : if (strncmp(lvs->name, new_name, SPDK_LVS_NAME_MAX) == 0) {
+ + # # ]
835 [ # # # # ]: 3 : cb_fn(cb_arg, 0);
836 : 3 : return;
837 : : }
838 : :
839 : : /* Check if new or new_name is already used in other lvs */
840 [ # # ]: 14 : pthread_mutex_lock(&g_lvol_stores_mutex);
841 [ + + # # : 31 : TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
# # # # ]
842 [ + + - + : 24 : if (!strncmp(new_name, tmp->name, SPDK_LVS_NAME_MAX) ||
+ + # # #
# ]
843 [ + + - + : 20 : !strncmp(new_name, tmp->new_name, SPDK_LVS_NAME_MAX)) {
+ + ]
844 [ # # ]: 7 : pthread_mutex_unlock(&g_lvol_stores_mutex);
845 [ # # # # ]: 7 : cb_fn(cb_arg, -EEXIST);
846 : 7 : return;
847 : : }
848 : 0 : }
849 [ # # ]: 7 : pthread_mutex_unlock(&g_lvol_stores_mutex);
850 : :
851 : 7 : req = calloc(1, sizeof(*req));
852 [ - + ]: 7 : if (!req) {
853 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
854 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
855 : 0 : return;
856 : : }
857 [ # # ]: 7 : snprintf(lvs->new_name, sizeof(lvs->new_name), "%s", new_name);
858 [ # # # # ]: 7 : req->lvol_store = lvs;
859 [ # # # # ]: 7 : req->cb_fn = cb_fn;
860 [ # # # # ]: 7 : req->cb_arg = cb_arg;
861 : :
862 [ # # # # : 7 : spdk_bs_open_blob(lvs->blobstore, lvs->super_blob_id, lvs_rename_open_cb, req);
# # # # ]
863 : 0 : }
864 : :
865 : : static void
866 : 197 : _lvs_unload_cb(void *cb_arg, int lvserrno)
867 : : {
868 : 197 : struct spdk_lvs_req *lvs_req = cb_arg;
869 : :
870 [ - + - + : 197 : SPDK_INFOLOG(lvol, "Lvol store unloaded\n");
# # ]
871 [ - + # # : 197 : assert(lvs_req->cb_fn != NULL);
# # # # ]
872 [ # # # # : 197 : lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
# # # # #
# # # ]
873 : 197 : free(lvs_req);
874 : 197 : }
875 : :
876 : : int
877 : 203 : spdk_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn,
878 : : void *cb_arg)
879 : : {
880 : : struct spdk_lvs_req *lvs_req;
881 : : struct spdk_lvol *lvol, *tmp;
882 : :
883 [ + + ]: 203 : if (lvs == NULL) {
884 : 3 : SPDK_ERRLOG("Lvol store is NULL\n");
885 : 3 : return -ENODEV;
886 : : }
887 : :
888 [ + + # # : 419 : TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
889 [ - + - + : 222 : if (lvol->action_in_progress == true) {
# # # # ]
890 : 0 : SPDK_ERRLOG("Cannot unload lvol store - operations on lvols pending\n");
891 [ # # # # ]: 0 : cb_fn(cb_arg, -EBUSY);
892 : 0 : return -EBUSY;
893 [ + + # # : 222 : } else if (lvol->ref_count != 0) {
# # ]
894 : 3 : SPDK_ERRLOG("Lvols still open on lvol store\n");
895 [ # # # # ]: 3 : cb_fn(cb_arg, -EBUSY);
896 : 3 : return -EBUSY;
897 : : }
898 : 0 : }
899 : :
900 [ + + # # : 416 : TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
901 : 219 : spdk_lvs_esnap_missing_remove(lvol);
902 [ + + # # : 219 : TAILQ_REMOVE(&lvs->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
903 : 219 : lvol_free(lvol);
904 : 0 : }
905 : :
906 : 197 : lvs_req = calloc(1, sizeof(*lvs_req));
907 [ - + ]: 197 : if (!lvs_req) {
908 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
909 : 0 : return -ENOMEM;
910 : : }
911 : :
912 [ # # # # ]: 197 : lvs_req->cb_fn = cb_fn;
913 [ # # # # ]: 197 : lvs_req->cb_arg = cb_arg;
914 : :
915 [ - + - + : 197 : SPDK_INFOLOG(lvol, "Unloading lvol store\n");
# # ]
916 [ # # # # ]: 197 : spdk_bs_unload(lvs->blobstore, _lvs_unload_cb, lvs_req);
917 : 197 : lvs_free(lvs);
918 : :
919 : 197 : return 0;
920 : 0 : }
921 : :
922 : : static void
923 : 196 : _lvs_destroy_cb(void *cb_arg, int lvserrno)
924 : : {
925 : 196 : struct spdk_lvs_destroy_req *lvs_req = cb_arg;
926 : :
927 [ - + - + : 196 : SPDK_INFOLOG(lvol, "Lvol store destroyed\n");
# # ]
928 [ - + # # : 196 : assert(lvs_req->cb_fn != NULL);
# # # # ]
929 [ # # # # : 196 : lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
# # # # #
# # # ]
930 : 196 : free(lvs_req);
931 : 196 : }
932 : :
933 : : static void
934 : 196 : _lvs_destroy_super_cb(void *cb_arg, int bserrno)
935 : : {
936 : 196 : struct spdk_lvs_destroy_req *lvs_req = cb_arg;
937 [ # # # # ]: 196 : struct spdk_lvol_store *lvs = lvs_req->lvs;
938 : :
939 [ - + # # ]: 196 : assert(lvs != NULL);
940 : :
941 [ - + - + : 196 : SPDK_INFOLOG(lvol, "Destroying lvol store\n");
# # ]
942 [ # # # # ]: 196 : spdk_bs_destroy(lvs->blobstore, _lvs_destroy_cb, lvs_req);
943 : 196 : lvs_free(lvs);
944 : 196 : }
945 : :
946 : : int
947 : 199 : spdk_lvs_destroy(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn,
948 : : void *cb_arg)
949 : : {
950 : : struct spdk_lvs_destroy_req *lvs_req;
951 : : struct spdk_lvol *iter_lvol, *tmp;
952 : :
953 [ - + ]: 199 : if (lvs == NULL) {
954 : 0 : SPDK_ERRLOG("Lvol store is NULL\n");
955 : 0 : return -ENODEV;
956 : : }
957 : :
958 [ + + # # : 208 : TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
959 [ - + - + : 12 : if (iter_lvol->action_in_progress == true) {
# # # # ]
960 : 0 : SPDK_ERRLOG("Cannot destroy lvol store - operations on lvols pending\n");
961 [ # # # # ]: 0 : cb_fn(cb_arg, -EBUSY);
962 : 0 : return -EBUSY;
963 [ + + # # : 12 : } else if (iter_lvol->ref_count != 0) {
# # ]
964 : 3 : SPDK_ERRLOG("Lvols still open on lvol store\n");
965 [ # # # # ]: 3 : cb_fn(cb_arg, -EBUSY);
966 : 3 : return -EBUSY;
967 : : }
968 : 0 : }
969 : :
970 [ + + # # : 205 : TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
971 : 9 : free(iter_lvol);
972 : 0 : }
973 : :
974 : 196 : lvs_req = calloc(1, sizeof(*lvs_req));
975 [ - + ]: 196 : if (!lvs_req) {
976 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
977 : 0 : return -ENOMEM;
978 : : }
979 : :
980 [ # # # # ]: 196 : lvs_req->cb_fn = cb_fn;
981 [ # # # # ]: 196 : lvs_req->cb_arg = cb_arg;
982 [ # # # # ]: 196 : lvs_req->lvs = lvs;
983 : :
984 [ - + - + : 196 : SPDK_INFOLOG(lvol, "Deleting super blob\n");
# # ]
985 [ # # # # : 196 : spdk_bs_delete_blob(lvs->blobstore, lvs->super_blob_id, _lvs_destroy_super_cb, lvs_req);
# # # # ]
986 : :
987 : 196 : return 0;
988 : 0 : }
989 : :
990 : : static void
991 : 661 : lvol_close_blob_cb(void *cb_arg, int lvolerrno)
992 : : {
993 : 661 : struct spdk_lvol_req *req = cb_arg;
994 [ # # # # ]: 661 : struct spdk_lvol *lvol = req->lvol;
995 : :
996 [ + + ]: 661 : if (lvolerrno < 0) {
997 : 3 : SPDK_ERRLOG("Could not close blob on lvol\n");
998 : 3 : goto end;
999 : : }
1000 : :
1001 [ # # # # ]: 658 : lvol->ref_count--;
1002 [ # # # # ]: 658 : lvol->blob = NULL;
1003 [ + + + - : 658 : SPDK_INFOLOG(lvol, "Lvol %s closed\n", lvol->unique_id);
# # # # ]
1004 : :
1005 : 658 : end:
1006 [ # # # # ]: 661 : lvol->action_in_progress = false;
1007 [ # # # # : 661 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1008 : 661 : free(req);
1009 : 661 : }
1010 : :
1011 : : bool
1012 : 73 : spdk_lvol_deletable(struct spdk_lvol *lvol)
1013 : : {
1014 : 73 : size_t count = 0;
1015 : :
1016 [ # # # # : 73 : spdk_blob_get_clones(lvol->lvol_store->blobstore, lvol->blob_id, NULL, &count);
# # # # #
# # # ]
1017 : 73 : return (count == 0);
1018 : : }
1019 : :
1020 : : static void
1021 : 442 : lvol_delete_blob_cb(void *cb_arg, int lvolerrno)
1022 : : {
1023 : 442 : struct spdk_lvol_req *req = cb_arg;
1024 [ # # # # ]: 442 : struct spdk_lvol *lvol = req->lvol;
1025 [ # # # # ]: 442 : struct spdk_lvol *clone_lvol = req->clone_lvol;
1026 : :
1027 [ + + ]: 442 : if (lvolerrno < 0) {
1028 : 3 : SPDK_ERRLOG("Could not remove blob on lvol gracefully - forced removal\n");
1029 : 0 : } else {
1030 [ - + - + : 439 : SPDK_INFOLOG(lvol, "Lvol %s deleted\n", lvol->unique_id);
# # # # ]
1031 : : }
1032 : :
1033 [ + + # # : 442 : if (lvol->degraded_set != NULL) {
# # ]
1034 [ + + ]: 39 : if (clone_lvol != NULL) {
1035 : : /*
1036 : : * A degraded esnap clone that has a blob clone has been deleted. clone_lvol
1037 : : * becomes an esnap clone and needs to be associated with the
1038 : : * spdk_lvs_degraded_lvol_set.
1039 : : */
1040 [ # # # # ]: 4 : struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
1041 : :
1042 : 4 : lvs_degraded_lvol_set_remove(degraded_set, lvol);
1043 : 4 : lvs_degraded_lvol_set_add(degraded_set, clone_lvol);
1044 : 0 : } else {
1045 : 35 : spdk_lvs_esnap_missing_remove(lvol);
1046 : : }
1047 : 0 : }
1048 : :
1049 [ + + # # : 442 : TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1050 : 442 : lvol_free(lvol);
1051 [ # # # # : 442 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1052 : 442 : free(req);
1053 : 442 : }
1054 : :
1055 : : static void
1056 : 551 : lvol_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
1057 : : {
1058 : 551 : struct spdk_lvol_with_handle_req *req = cb_arg;
1059 [ # # # # ]: 551 : struct spdk_lvol *lvol = req->lvol;
1060 : :
1061 [ - + # # : 551 : TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1062 : :
1063 [ - + ]: 551 : if (lvolerrno < 0) {
1064 : 0 : lvol_free(lvol);
1065 [ # # # # : 0 : req->cb_fn(req->cb_arg, NULL, lvolerrno);
# # # # #
# # # ]
1066 : 0 : free(req);
1067 : 0 : return;
1068 : : }
1069 : :
1070 [ # # # # ]: 551 : lvol->blob = blob;
1071 [ # # # # ]: 551 : lvol->blob_id = spdk_blob_get_id(blob);
1072 : :
1073 [ # # # # : 551 : TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1074 : :
1075 [ # # # # ]: 551 : lvol->ref_count++;
1076 : :
1077 [ - + # # : 551 : assert(req->cb_fn != NULL);
# # # # ]
1078 [ # # # # : 551 : req->cb_fn(req->cb_arg, req->lvol, lvolerrno);
# # # # #
# # # # #
# # ]
1079 : 551 : free(req);
1080 : 0 : }
1081 : :
1082 : : static void
1083 : 559 : lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
1084 : : {
1085 : 559 : struct spdk_lvol_with_handle_req *req = cb_arg;
1086 : : struct spdk_blob_store *bs;
1087 : 432 : struct spdk_blob_open_opts opts;
1088 : :
1089 [ + + ]: 559 : if (lvolerrno < 0) {
1090 [ - + # # : 8 : TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1091 [ # # # # ]: 8 : lvol_free(req->lvol);
1092 [ - + # # : 8 : assert(req->cb_fn != NULL);
# # # # ]
1093 [ # # # # : 8 : req->cb_fn(req->cb_arg, NULL, lvolerrno);
# # # # #
# # # ]
1094 : 8 : free(req);
1095 : 8 : return;
1096 : : }
1097 : :
1098 : 551 : spdk_blob_open_opts_init(&opts, sizeof(opts));
1099 [ # # # # : 551 : opts.clear_method = req->lvol->clear_method;
# # # # ]
1100 : : /*
1101 : : * If the lvol that is being created is an esnap clone, the blobstore needs to be able to
1102 : : * pass the lvol to the esnap_bs_dev_create callback. In order for that to happen, we need
1103 : : * to pass it here.
1104 : : *
1105 : : * This does set ensap_ctx in cases where it's not needed, but we don't know that it's not
1106 : : * needed until after the blob is open. When the blob is not an esnap clone, a reference to
1107 : : * the value stored in opts.esnap_ctx is not retained by the blobstore.
1108 : : */
1109 [ # # # # : 551 : opts.esnap_ctx = req->lvol;
# # ]
1110 [ # # # # : 551 : bs = req->lvol->lvol_store->blobstore;
# # # # #
# # # ]
1111 : :
1112 [ + + + + : 551 : if (req->origlvol != NULL && req->origlvol->degraded_set != NULL) {
# # # # #
# # # # #
# # ]
1113 : : /*
1114 : : * A snapshot was created from a degraded esnap clone. The new snapshot is now a
1115 : : * degraded esnap clone. The previous clone is now a regular clone of a blob. Update
1116 : : * the set of directly-related clones to the missing external snapshot.
1117 : : */
1118 [ # # # # : 3 : struct spdk_lvs_degraded_lvol_set *degraded_set = req->origlvol->degraded_set;
# # # # ]
1119 : :
1120 [ # # # # ]: 3 : lvs_degraded_lvol_set_remove(degraded_set, req->origlvol);
1121 [ # # # # ]: 3 : lvs_degraded_lvol_set_add(degraded_set, req->lvol);
1122 : 0 : }
1123 : :
1124 : 551 : spdk_bs_open_blob_ext(bs, blobid, &opts, lvol_create_open_cb, req);
1125 : 0 : }
1126 : :
1127 : : static void
1128 : 662 : lvol_get_xattr_value(void *xattr_ctx, const char *name,
1129 : : const void **value, size_t *value_len)
1130 : : {
1131 : 662 : struct spdk_lvol *lvol = xattr_ctx;
1132 : :
1133 [ + + + + : 662 : if (!strcmp(LVOL_NAME, name)) {
# # ]
1134 [ # # # # ]: 331 : *value = lvol->name;
1135 [ # # ]: 331 : *value_len = SPDK_LVOL_NAME_MAX;
1136 : 331 : return;
1137 : : }
1138 [ + + + + : 331 : if (!strcmp("uuid", name)) {
# # ]
1139 [ # # # # ]: 328 : *value = lvol->uuid_str;
1140 [ # # ]: 328 : *value_len = sizeof(lvol->uuid_str);
1141 : 328 : return;
1142 : : }
1143 [ # # ]: 3 : *value = NULL;
1144 [ # # ]: 3 : *value_len = 0;
1145 : 0 : }
1146 : :
1147 : : static int
1148 : 617 : lvs_verify_lvol_name(struct spdk_lvol_store *lvs, const char *name)
1149 : : {
1150 : : struct spdk_lvol *tmp;
1151 : :
1152 [ + + + + : 617 : if (name == NULL || strnlen(name, SPDK_LVOL_NAME_MAX) == 0) {
+ + ]
1153 [ - + - + : 21 : SPDK_INFOLOG(lvol, "lvol name not provided.\n");
# # ]
1154 : 21 : return -EINVAL;
1155 : : }
1156 : :
1157 [ + + + + ]: 596 : if (strnlen(name, SPDK_LVOL_NAME_MAX) == SPDK_LVOL_NAME_MAX) {
1158 : 6 : SPDK_ERRLOG("Name has no null terminator.\n");
1159 : 6 : return -EINVAL;
1160 : : }
1161 : :
1162 [ + + # # : 1861 : TAILQ_FOREACH(tmp, &lvs->lvols, link) {
# # # # #
# # # #
# ]
1163 [ + + - + : 1296 : if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
+ + # # ]
1164 : 25 : SPDK_ERRLOG("lvol with name %s already exists\n", name);
1165 : 25 : return -EEXIST;
1166 : : }
1167 : 0 : }
1168 : :
1169 [ + + # # : 565 : TAILQ_FOREACH(tmp, &lvs->pending_lvols, link) {
# # # # #
# # # #
# ]
1170 [ + + - + : 3 : if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
+ - # # ]
1171 : 3 : SPDK_ERRLOG("lvol with name %s is being already created\n", name);
1172 : 3 : return -EEXIST;
1173 : : }
1174 : 0 : }
1175 : :
1176 : 562 : return 0;
1177 : 0 : }
1178 : :
1179 : : int
1180 : 384 : spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
1181 : : bool thin_provision, enum lvol_clear_method clear_method, spdk_lvol_op_with_handle_complete cb_fn,
1182 : : void *cb_arg)
1183 : : {
1184 : : struct spdk_lvol_with_handle_req *req;
1185 : : struct spdk_blob_store *bs;
1186 : : struct spdk_lvol *lvol;
1187 : 271 : struct spdk_blob_opts opts;
1188 : 384 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1189 : : int rc;
1190 : :
1191 [ + + ]: 384 : if (lvs == NULL) {
1192 : 3 : SPDK_ERRLOG("lvol store does not exist\n");
1193 : 3 : return -EINVAL;
1194 : : }
1195 : :
1196 : 381 : rc = lvs_verify_lvol_name(lvs, name);
1197 [ + + ]: 381 : if (rc < 0) {
1198 : 22 : return rc;
1199 : : }
1200 : :
1201 [ # # # # ]: 359 : bs = lvs->blobstore;
1202 : :
1203 : 359 : req = calloc(1, sizeof(*req));
1204 [ - + ]: 359 : if (!req) {
1205 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1206 : 0 : return -ENOMEM;
1207 : : }
1208 [ # # # # ]: 359 : req->cb_fn = cb_fn;
1209 [ # # # # ]: 359 : req->cb_arg = cb_arg;
1210 : :
1211 [ # # ]: 359 : lvol = lvol_alloc(lvs, name, thin_provision, clear_method);
1212 [ - + ]: 359 : if (!lvol) {
1213 : 0 : free(req);
1214 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
1215 : 0 : return -ENOMEM;
1216 : : }
1217 : :
1218 [ # # # # ]: 359 : req->lvol = lvol;
1219 : 359 : spdk_blob_opts_init(&opts, sizeof(opts));
1220 [ # # # # ]: 359 : opts.thin_provision = thin_provision;
1221 : 359 : opts.num_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(bs));
1222 [ # # # # : 359 : opts.clear_method = lvol->clear_method;
# # ]
1223 [ # # # # ]: 359 : opts.xattrs.count = SPDK_COUNTOF(xattr_names);
1224 [ # # # # ]: 359 : opts.xattrs.names = xattr_names;
1225 [ # # # # ]: 359 : opts.xattrs.ctx = lvol;
1226 [ # # # # ]: 359 : opts.xattrs.get_value = lvol_get_xattr_value;
1227 : :
1228 [ # # # # ]: 359 : spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
1229 : :
1230 : 359 : return 0;
1231 : 0 : }
1232 : :
1233 : : int
1234 : 124 : spdk_lvol_create_esnap_clone(const void *esnap_id, uint32_t id_len, uint64_t size_bytes,
1235 : : struct spdk_lvol_store *lvs, const char *clone_name,
1236 : : spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
1237 : : {
1238 : : struct spdk_lvol_with_handle_req *req;
1239 : : struct spdk_blob_store *bs;
1240 : : struct spdk_lvol *lvol;
1241 : 124 : struct spdk_blob_opts opts;
1242 : : uint64_t cluster_sz;
1243 : 124 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1244 : : int rc;
1245 : :
1246 [ + + ]: 124 : if (lvs == NULL) {
1247 : 3 : SPDK_ERRLOG("lvol store does not exist\n");
1248 : 3 : return -EINVAL;
1249 : : }
1250 : :
1251 : 121 : rc = lvs_verify_lvol_name(lvs, clone_name);
1252 [ + + ]: 121 : if (rc < 0) {
1253 : 15 : return rc;
1254 : : }
1255 : :
1256 [ # # # # ]: 106 : bs = lvs->blobstore;
1257 : :
1258 : 106 : cluster_sz = spdk_bs_get_cluster_size(bs);
1259 [ + + + + ]: 106 : if ((size_bytes % cluster_sz) != 0) {
1260 [ # # ]: 3 : SPDK_ERRLOG("Cannot create '%s/%s': size %" PRIu64 " is not an integer multiple of "
1261 : : "cluster size %" PRIu64 "\n", lvs->name, clone_name, size_bytes,
1262 : : cluster_sz);
1263 : 3 : return -EINVAL;
1264 : : }
1265 : :
1266 : 103 : req = calloc(1, sizeof(*req));
1267 [ - + ]: 103 : if (!req) {
1268 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1269 : 0 : return -ENOMEM;
1270 : : }
1271 [ # # # # ]: 103 : req->cb_fn = cb_fn;
1272 [ # # # # ]: 103 : req->cb_arg = cb_arg;
1273 : :
1274 : 103 : lvol = lvol_alloc(lvs, clone_name, true, LVOL_CLEAR_WITH_DEFAULT);
1275 [ - + ]: 103 : if (!lvol) {
1276 : 0 : free(req);
1277 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
1278 : 0 : return -ENOMEM;
1279 : : }
1280 [ # # # # ]: 103 : req->lvol = lvol;
1281 : :
1282 : 103 : spdk_blob_opts_init(&opts, sizeof(opts));
1283 [ # # ]: 103 : opts.esnap_id = esnap_id;
1284 [ # # ]: 103 : opts.esnap_id_len = id_len;
1285 [ # # ]: 103 : opts.thin_provision = true;
1286 : 103 : opts.num_clusters = spdk_divide_round_up(size_bytes, cluster_sz);
1287 [ # # # # : 103 : opts.clear_method = lvol->clear_method;
# # ]
1288 [ # # # # ]: 103 : opts.xattrs.count = SPDK_COUNTOF(xattr_names);
1289 [ # # # # ]: 103 : opts.xattrs.names = xattr_names;
1290 [ # # # # ]: 103 : opts.xattrs.ctx = lvol;
1291 [ # # # # ]: 103 : opts.xattrs.get_value = lvol_get_xattr_value;
1292 : :
1293 [ # # # # ]: 103 : spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
1294 : :
1295 : 103 : return 0;
1296 : 0 : }
1297 : :
1298 : : void
1299 : 72 : spdk_lvol_create_snapshot(struct spdk_lvol *origlvol, const char *snapshot_name,
1300 : : spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
1301 : : {
1302 : : struct spdk_lvol_store *lvs;
1303 : : struct spdk_lvol *newlvol;
1304 : : struct spdk_blob *origblob;
1305 : : struct spdk_lvol_with_handle_req *req;
1306 : 65 : struct spdk_blob_xattr_opts snapshot_xattrs;
1307 : 72 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1308 : : int rc;
1309 : :
1310 [ + + ]: 72 : if (origlvol == NULL) {
1311 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Lvol not provided.\n");
# # ]
1312 [ # # # # ]: 3 : cb_fn(cb_arg, NULL, -EINVAL);
1313 : 3 : return;
1314 : : }
1315 : :
1316 [ # # # # ]: 69 : origblob = origlvol->blob;
1317 [ # # # # ]: 69 : lvs = origlvol->lvol_store;
1318 [ - + ]: 69 : if (lvs == NULL) {
1319 : 0 : SPDK_ERRLOG("lvol store does not exist\n");
1320 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -EINVAL);
1321 : 0 : return;
1322 : : }
1323 : :
1324 : 69 : rc = lvs_verify_lvol_name(lvs, snapshot_name);
1325 [ + + ]: 69 : if (rc < 0) {
1326 [ # # # # ]: 9 : cb_fn(cb_arg, NULL, rc);
1327 : 9 : return;
1328 : : }
1329 : :
1330 : 60 : req = calloc(1, sizeof(*req));
1331 [ - + ]: 60 : if (!req) {
1332 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1333 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
1334 : 0 : return;
1335 : : }
1336 : :
1337 [ # # # # ]: 60 : newlvol = lvol_alloc(origlvol->lvol_store, snapshot_name, true,
1338 [ # # # # ]: 60 : (enum lvol_clear_method)origlvol->clear_method);
1339 [ - + ]: 60 : if (!newlvol) {
1340 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
1341 : 0 : free(req);
1342 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
1343 : 0 : return;
1344 : : }
1345 : :
1346 : 60 : snapshot_xattrs.count = SPDK_COUNTOF(xattr_names);
1347 [ # # ]: 60 : snapshot_xattrs.ctx = newlvol;
1348 [ # # ]: 60 : snapshot_xattrs.names = xattr_names;
1349 [ # # ]: 60 : snapshot_xattrs.get_value = lvol_get_xattr_value;
1350 [ # # # # ]: 60 : req->lvol = newlvol;
1351 [ # # # # ]: 60 : req->origlvol = origlvol;
1352 [ # # # # ]: 60 : req->cb_fn = cb_fn;
1353 [ # # # # ]: 60 : req->cb_arg = cb_arg;
1354 : :
1355 [ # # # # ]: 60 : spdk_bs_create_snapshot(lvs->blobstore, spdk_blob_get_id(origblob), &snapshot_xattrs,
1356 : 0 : lvol_create_cb, req);
1357 : 0 : }
1358 : :
1359 : : void
1360 : 49 : spdk_lvol_create_clone(struct spdk_lvol *origlvol, const char *clone_name,
1361 : : spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
1362 : : {
1363 : : struct spdk_lvol *newlvol;
1364 : : struct spdk_lvol_with_handle_req *req;
1365 : : struct spdk_lvol_store *lvs;
1366 : : struct spdk_blob *origblob;
1367 : 42 : struct spdk_blob_xattr_opts clone_xattrs;
1368 : 49 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1369 : : int rc;
1370 : :
1371 [ + + ]: 49 : if (origlvol == NULL) {
1372 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Lvol not provided.\n");
# # ]
1373 [ # # # # ]: 3 : cb_fn(cb_arg, NULL, -EINVAL);
1374 : 3 : return;
1375 : : }
1376 : :
1377 [ # # # # ]: 46 : origblob = origlvol->blob;
1378 [ # # # # ]: 46 : lvs = origlvol->lvol_store;
1379 [ - + ]: 46 : if (lvs == NULL) {
1380 : 0 : SPDK_ERRLOG("lvol store does not exist\n");
1381 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -EINVAL);
1382 : 0 : return;
1383 : : }
1384 : :
1385 : 46 : rc = lvs_verify_lvol_name(lvs, clone_name);
1386 [ + + ]: 46 : if (rc < 0) {
1387 [ # # # # ]: 9 : cb_fn(cb_arg, NULL, rc);
1388 : 9 : return;
1389 : : }
1390 : :
1391 : 37 : req = calloc(1, sizeof(*req));
1392 [ - + ]: 37 : if (!req) {
1393 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1394 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
1395 : 0 : return;
1396 : : }
1397 : :
1398 [ # # # # ]: 37 : newlvol = lvol_alloc(lvs, clone_name, true, (enum lvol_clear_method)origlvol->clear_method);
1399 [ - + ]: 37 : if (!newlvol) {
1400 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
1401 : 0 : free(req);
1402 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
1403 : 0 : return;
1404 : : }
1405 : :
1406 : 37 : clone_xattrs.count = SPDK_COUNTOF(xattr_names);
1407 [ # # ]: 37 : clone_xattrs.ctx = newlvol;
1408 [ # # ]: 37 : clone_xattrs.names = xattr_names;
1409 [ # # ]: 37 : clone_xattrs.get_value = lvol_get_xattr_value;
1410 [ # # # # ]: 37 : req->lvol = newlvol;
1411 [ # # # # ]: 37 : req->cb_fn = cb_fn;
1412 [ # # # # ]: 37 : req->cb_arg = cb_arg;
1413 : :
1414 [ # # # # ]: 37 : spdk_bs_create_clone(lvs->blobstore, spdk_blob_get_id(origblob), &clone_xattrs,
1415 : : lvol_create_cb,
1416 : 0 : req);
1417 : 0 : }
1418 : :
1419 : : static void
1420 : 35 : lvol_resize_done(void *cb_arg, int lvolerrno)
1421 : : {
1422 : 35 : struct spdk_lvol_req *req = cb_arg;
1423 : :
1424 [ # # # # : 35 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1425 : 35 : free(req);
1426 : 35 : }
1427 : :
1428 : : static void
1429 : 42 : lvol_blob_resize_cb(void *cb_arg, int bserrno)
1430 : : {
1431 : 42 : struct spdk_lvol_req *req = cb_arg;
1432 [ # # # # ]: 42 : struct spdk_lvol *lvol = req->lvol;
1433 : :
1434 [ + + ]: 42 : if (bserrno != 0) {
1435 [ # # # # : 7 : req->cb_fn(req->cb_arg, bserrno);
# # # # #
# # # ]
1436 : 7 : free(req);
1437 : 7 : return;
1438 : : }
1439 : :
1440 [ # # # # ]: 35 : spdk_blob_sync_md(lvol->blob, lvol_resize_done, req);
1441 : 0 : }
1442 : :
1443 : : void
1444 : 42 : spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz,
1445 : : spdk_lvol_op_complete cb_fn, void *cb_arg)
1446 : : {
1447 [ # # # # ]: 42 : struct spdk_blob *blob = lvol->blob;
1448 [ # # # # ]: 42 : struct spdk_lvol_store *lvs = lvol->lvol_store;
1449 : : struct spdk_lvol_req *req;
1450 [ # # # # ]: 42 : uint64_t new_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(lvs->blobstore));
1451 : :
1452 : 42 : req = calloc(1, sizeof(*req));
1453 [ - + ]: 42 : if (!req) {
1454 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1455 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1456 : 0 : return;
1457 : : }
1458 [ # # # # ]: 42 : req->cb_fn = cb_fn;
1459 [ # # # # ]: 42 : req->cb_arg = cb_arg;
1460 [ # # # # ]: 42 : req->lvol = lvol;
1461 : :
1462 : 42 : spdk_blob_resize(blob, new_clusters, lvol_blob_resize_cb, req);
1463 : 0 : }
1464 : :
1465 : : static void
1466 : 7 : lvol_set_read_only_cb(void *cb_arg, int lvolerrno)
1467 : : {
1468 : 7 : struct spdk_lvol_req *req = cb_arg;
1469 : :
1470 [ # # # # : 7 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1471 : 7 : free(req);
1472 : 7 : }
1473 : :
1474 : : void
1475 : 7 : spdk_lvol_set_read_only(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
1476 : : {
1477 : : struct spdk_lvol_req *req;
1478 : :
1479 : 7 : req = calloc(1, sizeof(*req));
1480 [ - + ]: 7 : if (!req) {
1481 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1482 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1483 : 0 : return;
1484 : : }
1485 [ # # # # ]: 7 : req->cb_fn = cb_fn;
1486 [ # # # # ]: 7 : req->cb_arg = cb_arg;
1487 : :
1488 [ # # # # ]: 7 : spdk_blob_set_read_only(lvol->blob);
1489 [ # # # # ]: 7 : spdk_blob_sync_md(lvol->blob, lvol_set_read_only_cb, req);
1490 : 0 : }
1491 : :
1492 : : static void
1493 : 7 : lvol_rename_cb(void *cb_arg, int lvolerrno)
1494 : : {
1495 : 7 : struct spdk_lvol_req *req = cb_arg;
1496 : :
1497 [ - + ]: 7 : if (lvolerrno != 0) {
1498 : 0 : SPDK_ERRLOG("Lvol rename operation failed\n");
1499 : 0 : } else {
1500 [ - + # # : 7 : snprintf(req->lvol->name, sizeof(req->lvol->name), "%s", req->name);
# # # # ]
1501 : : }
1502 : :
1503 [ # # # # : 7 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1504 : 7 : free(req);
1505 : 7 : }
1506 : :
1507 : : void
1508 : 10 : spdk_lvol_rename(struct spdk_lvol *lvol, const char *new_name,
1509 : : spdk_lvol_op_complete cb_fn, void *cb_arg)
1510 : : {
1511 : : struct spdk_lvol *tmp;
1512 [ # # # # ]: 10 : struct spdk_blob *blob = lvol->blob;
1513 : : struct spdk_lvol_req *req;
1514 : : int rc;
1515 : :
1516 : : /* Check if new name is current lvol name.
1517 : : * If so, return success immediately */
1518 [ - + - + : 10 : if (strncmp(lvol->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
- + # # ]
1519 [ # # # # ]: 0 : cb_fn(cb_arg, 0);
1520 : 0 : return;
1521 : : }
1522 : :
1523 : : /* Check if lvol with 'new_name' already exists in lvolstore */
1524 [ + + # # : 32 : TAILQ_FOREACH(tmp, &lvol->lvol_store->lvols, link) {
# # # # #
# # # # #
# # # # ]
1525 [ + + - + : 25 : if (strncmp(tmp->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
+ + # # ]
1526 [ # # # # : 3 : SPDK_ERRLOG("Lvol %s already exists in lvol store %s\n", new_name, lvol->lvol_store->name);
# # ]
1527 [ # # # # ]: 3 : cb_fn(cb_arg, -EEXIST);
1528 : 3 : return;
1529 : : }
1530 : 0 : }
1531 : :
1532 : 7 : req = calloc(1, sizeof(*req));
1533 [ - + ]: 7 : if (!req) {
1534 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1535 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1536 : 0 : return;
1537 : : }
1538 [ # # # # ]: 7 : req->cb_fn = cb_fn;
1539 [ # # # # ]: 7 : req->cb_arg = cb_arg;
1540 [ # # # # ]: 7 : req->lvol = lvol;
1541 [ # # ]: 7 : snprintf(req->name, sizeof(req->name), "%s", new_name);
1542 : :
1543 [ - + ]: 7 : rc = spdk_blob_set_xattr(blob, "name", new_name, strlen(new_name) + 1);
1544 [ - + ]: 7 : if (rc < 0) {
1545 : 0 : free(req);
1546 [ # # # # ]: 0 : cb_fn(cb_arg, rc);
1547 : 0 : return;
1548 : : }
1549 : :
1550 : 7 : spdk_blob_sync_md(blob, lvol_rename_cb, req);
1551 : 0 : }
1552 : :
1553 : : void
1554 : 445 : spdk_lvol_destroy(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
1555 : : {
1556 : : struct spdk_lvol_req *req;
1557 : : struct spdk_blob_store *bs;
1558 : : struct spdk_lvol_store *lvs;
1559 : 335 : spdk_blob_id clone_id;
1560 : 445 : size_t count = 1;
1561 : : int rc;
1562 : :
1563 [ - + # # ]: 445 : assert(cb_fn != NULL);
1564 : :
1565 [ - + ]: 445 : if (lvol == NULL) {
1566 : 0 : SPDK_ERRLOG("lvol does not exist\n");
1567 [ # # # # ]: 0 : cb_fn(cb_arg, -ENODEV);
1568 : 0 : return;
1569 : : }
1570 : :
1571 [ # # # # ]: 445 : lvs = lvol->lvol_store;
1572 : :
1573 [ + + # # : 445 : if (lvol->ref_count != 0) {
# # ]
1574 [ # # ]: 3 : SPDK_ERRLOG("Cannot destroy lvol %s because it is still open\n", lvol->unique_id);
1575 [ # # # # ]: 3 : cb_fn(cb_arg, -EBUSY);
1576 : 3 : return;
1577 : : }
1578 : :
1579 : 442 : req = calloc(1, sizeof(*req));
1580 [ - + ]: 442 : if (!req) {
1581 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1582 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1583 : 0 : return;
1584 : : }
1585 : :
1586 [ # # # # ]: 442 : req->cb_fn = cb_fn;
1587 [ # # # # ]: 442 : req->cb_arg = cb_arg;
1588 [ # # # # ]: 442 : req->lvol = lvol;
1589 [ # # # # : 442 : bs = lvol->lvol_store->blobstore;
# # # # ]
1590 : :
1591 [ # # # # : 442 : rc = spdk_blob_get_clones(lvs->blobstore, lvol->blob_id, &clone_id, &count);
# # # # ]
1592 [ + - + + ]: 442 : if (rc == 0 && count == 1) {
1593 [ # # # # ]: 11 : req->clone_lvol = lvs_get_lvol_by_blob_id(lvs, clone_id);
1594 [ - + ]: 431 : } else if (rc == -ENOMEM) {
1595 [ # # # # : 0 : SPDK_INFOLOG(lvol, "lvol %s: cannot destroy: has %" PRIu64 " clones\n",
# # # # ]
1596 : : lvol->unique_id, count);
1597 : 0 : free(req);
1598 [ # # # # ]: 0 : assert(count > 1);
1599 [ # # # # ]: 0 : cb_fn(cb_arg, -EBUSY);
1600 : 0 : return;
1601 : : }
1602 : :
1603 [ # # # # ]: 442 : lvol->action_in_progress = true;
1604 : :
1605 [ # # # # ]: 442 : spdk_bs_delete_blob(bs, lvol->blob_id, lvol_delete_blob_cb, req);
1606 : 0 : }
1607 : :
1608 : : void
1609 : 673 : spdk_lvol_close(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
1610 : : {
1611 : : struct spdk_lvol_req *req;
1612 : :
1613 [ - + # # ]: 673 : assert(cb_fn != NULL);
1614 : :
1615 [ + + ]: 673 : if (lvol == NULL) {
1616 : 3 : SPDK_ERRLOG("lvol does not exist\n");
1617 [ # # # # ]: 3 : cb_fn(cb_arg, -ENODEV);
1618 : 3 : return;
1619 : : }
1620 : :
1621 [ + + # # : 670 : if (lvol->ref_count > 1) {
# # ]
1622 [ # # # # ]: 3 : lvol->ref_count--;
1623 [ # # # # ]: 3 : cb_fn(cb_arg, 0);
1624 : 3 : return;
1625 [ + + # # : 667 : } else if (lvol->ref_count == 0) {
# # ]
1626 [ # # # # ]: 6 : cb_fn(cb_arg, -EINVAL);
1627 : 6 : return;
1628 : : }
1629 : :
1630 : 661 : req = calloc(1, sizeof(*req));
1631 [ - + ]: 661 : if (!req) {
1632 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1633 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1634 : 0 : return;
1635 : : }
1636 : :
1637 [ # # # # ]: 661 : req->cb_fn = cb_fn;
1638 [ # # # # ]: 661 : req->cb_arg = cb_arg;
1639 [ # # # # ]: 661 : req->lvol = lvol;
1640 : :
1641 [ # # # # ]: 661 : lvol->action_in_progress = true;
1642 : :
1643 [ # # # # ]: 661 : spdk_blob_close(lvol->blob, lvol_close_blob_cb, req);
1644 : 0 : }
1645 : :
1646 : : struct spdk_io_channel *
1647 : 700 : spdk_lvol_get_io_channel(struct spdk_lvol *lvol)
1648 : : {
1649 [ # # # # : 700 : return spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
# # # # ]
1650 : : }
1651 : :
1652 : : static void
1653 : 22 : lvol_inflate_cb(void *cb_arg, int lvolerrno)
1654 : : {
1655 : 22 : struct spdk_lvol_req *req = cb_arg;
1656 : :
1657 [ # # # # ]: 22 : spdk_bs_free_io_channel(req->channel);
1658 : :
1659 [ + + ]: 22 : if (lvolerrno < 0) {
1660 : 7 : SPDK_ERRLOG("Could not inflate lvol\n");
1661 : 0 : }
1662 : :
1663 [ # # # # : 22 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1664 : 22 : free(req);
1665 : 22 : }
1666 : :
1667 : : void
1668 : 13 : spdk_lvol_inflate(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
1669 : : {
1670 : : struct spdk_lvol_req *req;
1671 : : spdk_blob_id blob_id;
1672 : :
1673 [ - + # # ]: 13 : assert(cb_fn != NULL);
1674 : :
1675 [ - + ]: 13 : if (lvol == NULL) {
1676 : 0 : SPDK_ERRLOG("Lvol does not exist\n");
1677 [ # # # # ]: 0 : cb_fn(cb_arg, -ENODEV);
1678 : 0 : return;
1679 : : }
1680 : :
1681 : 13 : req = calloc(1, sizeof(*req));
1682 [ - + ]: 13 : if (!req) {
1683 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1684 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1685 : 0 : return;
1686 : : }
1687 : :
1688 [ # # # # ]: 13 : req->cb_fn = cb_fn;
1689 [ # # # # ]: 13 : req->cb_arg = cb_arg;
1690 [ # # # # : 13 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
# # # # #
# # # ]
1691 [ - + # # : 13 : if (req->channel == NULL) {
# # ]
1692 : 0 : SPDK_ERRLOG("Cannot alloc io channel for lvol inflate request\n");
1693 : 0 : free(req);
1694 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1695 : 0 : return;
1696 : : }
1697 : :
1698 [ # # # # ]: 13 : blob_id = spdk_blob_get_id(lvol->blob);
1699 [ # # # # : 13 : spdk_bs_inflate_blob(lvol->lvol_store->blobstore, req->channel, blob_id, lvol_inflate_cb,
# # # # #
# # # ]
1700 : 0 : req);
1701 : 0 : }
1702 : :
1703 : : void
1704 : 9 : spdk_lvol_decouple_parent(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
1705 : : {
1706 : : struct spdk_lvol_req *req;
1707 : : spdk_blob_id blob_id;
1708 : :
1709 [ - + # # ]: 9 : assert(cb_fn != NULL);
1710 : :
1711 [ - + ]: 9 : if (lvol == NULL) {
1712 : 0 : SPDK_ERRLOG("Lvol does not exist\n");
1713 [ # # # # ]: 0 : cb_fn(cb_arg, -ENODEV);
1714 : 0 : return;
1715 : : }
1716 : :
1717 : 9 : req = calloc(1, sizeof(*req));
1718 [ - + ]: 9 : if (!req) {
1719 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1720 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1721 : 0 : return;
1722 : : }
1723 : :
1724 [ # # # # ]: 9 : req->cb_fn = cb_fn;
1725 [ # # # # ]: 9 : req->cb_arg = cb_arg;
1726 [ # # # # : 9 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
# # # # #
# # # ]
1727 [ - + # # : 9 : if (req->channel == NULL) {
# # ]
1728 : 0 : SPDK_ERRLOG("Cannot alloc io channel for lvol inflate request\n");
1729 : 0 : free(req);
1730 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1731 : 0 : return;
1732 : : }
1733 : :
1734 [ # # # # ]: 9 : blob_id = spdk_blob_get_id(lvol->blob);
1735 [ # # # # : 9 : spdk_bs_blob_decouple_parent(lvol->lvol_store->blobstore, req->channel, blob_id,
# # # # #
# # # ]
1736 : 0 : lvol_inflate_cb, req);
1737 : 0 : }
1738 : :
1739 : : static void
1740 : 2 : lvs_grow_live_cb(void *cb_arg, int lvolerrno)
1741 : : {
1742 : 2 : struct spdk_lvs_req *req = (struct spdk_lvs_req *)cb_arg;
1743 : :
1744 [ + - # # : 2 : if (req->cb_fn) {
# # ]
1745 [ # # # # : 2 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1746 : 0 : }
1747 : 2 : free(req);
1748 : 2 : return;
1749 : : }
1750 : :
1751 : : void
1752 : 2 : spdk_lvs_grow_live(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg)
1753 : : {
1754 : : struct spdk_lvs_req *req;
1755 : :
1756 : 2 : req = calloc(1, sizeof(*req));
1757 [ - + ]: 2 : if (req == NULL) {
1758 : 0 : SPDK_ERRLOG("Cannot alloc memory for request structure\n");
1759 [ # # ]: 0 : if (cb_fn) {
1760 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
1761 : 0 : }
1762 : 0 : return;
1763 : : }
1764 : :
1765 [ # # # # ]: 2 : req->cb_fn = cb_fn;
1766 [ # # # # ]: 2 : req->cb_arg = cb_arg;
1767 [ # # # # ]: 2 : req->lvol_store = lvs;
1768 : :
1769 [ # # # # ]: 2 : spdk_bs_grow_live(lvs->blobstore, lvs_grow_live_cb, req);
1770 : 0 : }
1771 : :
1772 : : void
1773 : 0 : spdk_lvs_grow(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
1774 : : {
1775 : : struct spdk_lvs_with_handle_req *req;
1776 : 0 : struct spdk_bs_opts opts = {};
1777 : :
1778 [ # # # # ]: 0 : assert(cb_fn != NULL);
1779 : :
1780 [ # # ]: 0 : if (bs_dev == NULL) {
1781 : 0 : SPDK_ERRLOG("Blobstore device does not exist\n");
1782 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENODEV);
1783 : 0 : return;
1784 : : }
1785 : :
1786 : 0 : req = calloc(1, sizeof(*req));
1787 [ # # ]: 0 : if (req == NULL) {
1788 : 0 : SPDK_ERRLOG("Cannot alloc memory for request structure\n");
1789 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
1790 : 0 : return;
1791 : : }
1792 : :
1793 [ # # # # ]: 0 : req->lvol_store = lvs_alloc();
1794 [ # # # # : 0 : if (req->lvol_store == NULL) {
# # ]
1795 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store\n");
1796 : 0 : free(req);
1797 [ # # # # ]: 0 : cb_fn(cb_arg, NULL, -ENOMEM);
1798 : 0 : return;
1799 : : }
1800 [ # # # # ]: 0 : req->cb_fn = cb_fn;
1801 [ # # # # ]: 0 : req->cb_arg = cb_arg;
1802 [ # # # # ]: 0 : req->bs_dev = bs_dev;
1803 : :
1804 : 0 : lvs_bs_opts_init(&opts);
1805 [ # # ]: 0 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "LVOLSTORE");
1806 : :
1807 : 0 : spdk_bs_grow(bs_dev, &opts, lvs_load_cb, req);
1808 : 0 : }
1809 : :
1810 : : static struct spdk_lvol *
1811 : 43 : lvs_get_lvol_by_blob_id(struct spdk_lvol_store *lvs, spdk_blob_id blob_id)
1812 : : {
1813 : : struct spdk_lvol *lvol;
1814 : :
1815 [ + - # # : 58 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
# # # # #
# # # #
# ]
1816 [ + + # # : 58 : if (lvol->blob_id == blob_id) {
# # ]
1817 : 43 : return lvol;
1818 : : }
1819 : 0 : }
1820 : 0 : return NULL;
1821 : 0 : }
1822 : :
1823 : : static int
1824 : 86 : lvs_esnap_bs_dev_create(void *bs_ctx, void *blob_ctx, struct spdk_blob *blob,
1825 : : const void *esnap_id, uint32_t id_len,
1826 : : struct spdk_bs_dev **bs_dev)
1827 : : {
1828 : 86 : struct spdk_lvol_store *lvs = bs_ctx;
1829 : 86 : struct spdk_lvol *lvol = blob_ctx;
1830 : 86 : spdk_blob_id blob_id = spdk_blob_get_id(blob);
1831 : :
1832 [ + + ]: 86 : if (lvs == NULL) {
1833 [ + + - + : 6 : if (lvol == NULL || lvol->lvol_store == NULL) {
# # # # ]
1834 : 3 : SPDK_ERRLOG("Blob 0x%" PRIx64 ": no lvs context nor lvol context\n",
1835 : : blob_id);
1836 : 3 : return -EINVAL;
1837 : : }
1838 [ # # # # ]: 3 : lvs = lvol->lvol_store;
1839 : 0 : }
1840 : :
1841 : : /*
1842 : : * When spdk_lvs_load() is called, it iterates through all blobs in its blobstore building
1843 : : * up a list of lvols (lvs->lvols). During this initial iteration, each blob is opened,
1844 : : * passed to load_next_lvol(), then closed. There is no need to open the external snapshot
1845 : : * during this phase. Once the blobstore is loaded, lvs->load_esnaps is set to true so that
1846 : : * future lvol opens cause the external snapshot to be loaded.
1847 : : */
1848 [ + + + + : 83 : if (!lvs->load_esnaps) {
# # # # ]
1849 [ # # ]: 56 : *bs_dev = NULL;
1850 : 56 : return 0;
1851 : : }
1852 : :
1853 [ + + ]: 27 : if (lvol == NULL) {
1854 : 18 : spdk_blob_id blob_id = spdk_blob_get_id(blob);
1855 : :
1856 : : /*
1857 : : * If spdk_bs_blob_open() is used instead of spdk_bs_blob_open_ext() the lvol will
1858 : : * not have been passed in. The same is true if the open happens spontaneously due
1859 : : * to blobstore activity.
1860 : : */
1861 : 18 : lvol = lvs_get_lvol_by_blob_id(lvs, blob_id);
1862 [ - + ]: 18 : if (lvol == NULL) {
1863 [ # # ]: 0 : SPDK_ERRLOG("lvstore %s: no lvol for blob 0x%" PRIx64 "\n",
1864 : : lvs->name, blob_id);
1865 : 0 : return -ENODEV;
1866 : : }
1867 : 0 : }
1868 : :
1869 [ # # # # : 27 : return lvs->esnap_bs_dev_create(lvs, lvol, blob, esnap_id, id_len, bs_dev);
# # # # ]
1870 : 0 : }
1871 : :
1872 : : /*
1873 : : * The theory of missing external snapshots
1874 : : *
1875 : : * The lvs->esnap_bs_dev_create() callback may be unable to create an external snapshot bs_dev when
1876 : : * it is called. This can happen, for instance, as when the device containing the lvolstore is
1877 : : * examined prior to spdk_bdev_register() being called on a bdev that acts as an external snapshot.
1878 : : * In such a case, the esnap_bs_dev_create() callback will call spdk_lvs_esnap_missing_add().
1879 : : *
1880 : : * Missing external snapshots are tracked in a per-lvolstore tree, lvs->degraded_lvol_sets_tree.
1881 : : * Each tree node (struct spdk_lvs_degraded_lvol_set) contains a tailq of lvols that are missing
1882 : : * that particular external snapshot.
1883 : : *
1884 : : * When a potential missing snapshot becomes available, spdk_lvs_notify_hotplug() may be called to
1885 : : * notify this library that it is available. It will then iterate through the active lvolstores and
1886 : : * search each lvs->degraded_lvol_sets_tree for a set of degraded lvols that are missing an external
1887 : : * snapshot matching the id passed in the notification. The lvols in the tailq on each matching tree
1888 : : * node are then asked to create an external snapshot bs_dev using the esnap_bs_dev_create()
1889 : : * callback that the consumer registered with the lvolstore. If lvs->esnap_bs_dev_create() returns
1890 : : * 0, the lvol is removed from the spdk_lvs_degraded_lvol_set's lvol tailq. When this tailq becomes
1891 : : * empty, the degraded lvol set node for this missing external snapshot is removed.
1892 : : */
1893 : : static int
1894 : 282 : lvs_esnap_name_cmp(struct spdk_lvs_degraded_lvol_set *m1, struct spdk_lvs_degraded_lvol_set *m2)
1895 : : {
1896 [ + - # # : 282 : if (m1->id_len == m2->id_len) {
# # # # #
# ]
1897 [ - + - + : 282 : return memcmp(m1->esnap_id, m2->esnap_id, m1->id_len);
# # # # #
# # # # #
# # ]
1898 : : }
1899 [ # # # # : 0 : return (m1->id_len > m2->id_len) ? 1 : -1;
# # # # ]
1900 : 0 : }
1901 : :
1902 [ + + + + : 1380 : RB_GENERATE_STATIC(degraded_lvol_sets_tree, spdk_lvs_degraded_lvol_set, node, lvs_esnap_name_cmp)
+ + + + +
+ + + + +
+ + + + -
- - - - -
- + + - -
- - - - -
- - - - -
- - - - -
- - + + -
- - - - -
- - - - -
- - - # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1903 : :
1904 : : static void
1905 : 122 : lvs_degraded_lvol_set_add(struct spdk_lvs_degraded_lvol_set *degraded_set, struct spdk_lvol *lvol)
1906 : : {
1907 [ - + # # : 122 : assert(lvol->lvol_store->thread == spdk_get_thread());
# # # # #
# # # ]
1908 : :
1909 [ # # # # ]: 122 : lvol->degraded_set = degraded_set;
1910 [ # # # # : 122 : TAILQ_INSERT_TAIL(°raded_set->lvols, lvol, degraded_link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1911 : 122 : }
1912 : :
1913 : : static void
1914 : 44 : lvs_degraded_lvol_set_remove(struct spdk_lvs_degraded_lvol_set *degraded_set,
1915 : : struct spdk_lvol *lvol)
1916 : : {
1917 [ - + # # : 44 : assert(lvol->lvol_store->thread == spdk_get_thread());
# # # # #
# # # ]
1918 : :
1919 [ # # # # ]: 44 : lvol->degraded_set = NULL;
1920 [ + + # # : 44 : TAILQ_REMOVE(°raded_set->lvols, lvol, degraded_link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
1921 : : /* degraded_set->lvols may be empty. Caller should check if not immediately adding a new
1922 : : * lvol. */
1923 : 44 : }
1924 : :
1925 : : /*
1926 : : * Record in lvs->degraded_lvol_sets_tree that a bdev of the specified name is needed by the
1927 : : * specified lvol.
1928 : : */
1929 : : int
1930 : 115 : spdk_lvs_esnap_missing_add(struct spdk_lvol_store *lvs, struct spdk_lvol *lvol,
1931 : : const void *esnap_id, uint32_t id_len)
1932 : : {
1933 : 115 : struct spdk_lvs_degraded_lvol_set find, *degraded_set;
1934 : :
1935 [ - + # # : 115 : assert(lvs->thread == spdk_get_thread());
# # # # ]
1936 : :
1937 [ # # ]: 115 : find.esnap_id = esnap_id;
1938 [ # # ]: 115 : find.id_len = id_len;
1939 [ # # ]: 115 : degraded_set = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
1940 [ + + ]: 115 : if (degraded_set == NULL) {
1941 : 55 : degraded_set = calloc(1, sizeof(*degraded_set));
1942 [ - + ]: 55 : if (degraded_set == NULL) {
1943 [ # # ]: 0 : SPDK_ERRLOG("lvol %s: cannot create degraded_set node: out of memory\n",
1944 : : lvol->unique_id);
1945 : 0 : return -ENOMEM;
1946 : : }
1947 [ # # # # ]: 55 : degraded_set->esnap_id = calloc(1, id_len);
1948 [ - + # # : 55 : if (degraded_set->esnap_id == NULL) {
# # ]
1949 : 0 : free(degraded_set);
1950 [ # # ]: 0 : SPDK_ERRLOG("lvol %s: cannot create degraded_set node: out of memory\n",
1951 : : lvol->unique_id);
1952 : 0 : return -ENOMEM;
1953 : : }
1954 [ - + - + : 55 : memcpy((void *)degraded_set->esnap_id, esnap_id, id_len);
# # # # ]
1955 [ # # # # ]: 55 : degraded_set->id_len = id_len;
1956 [ # # # # ]: 55 : degraded_set->lvol_store = lvs;
1957 [ # # # # : 55 : TAILQ_INIT(°raded_set->lvols);
# # # # #
# # # # #
# # ]
1958 [ # # ]: 55 : RB_INSERT(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
1959 : 0 : }
1960 : :
1961 : 115 : lvs_degraded_lvol_set_add(degraded_set, lvol);
1962 : :
1963 : 115 : return 0;
1964 : 0 : }
1965 : :
1966 : : /*
1967 : : * Remove the record of the specified lvol needing a degraded_set bdev.
1968 : : */
1969 : : void
1970 : 254 : spdk_lvs_esnap_missing_remove(struct spdk_lvol *lvol)
1971 : : {
1972 [ # # # # ]: 254 : struct spdk_lvol_store *lvs = lvol->lvol_store;
1973 [ # # # # ]: 254 : struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
1974 : :
1975 [ - + # # : 254 : assert(lvs->thread == spdk_get_thread());
# # # # ]
1976 : :
1977 [ + + ]: 254 : if (degraded_set == NULL) {
1978 : 217 : return;
1979 : : }
1980 : :
1981 : 37 : lvs_degraded_lvol_set_remove(degraded_set, lvol);
1982 : :
1983 [ + + # # : 37 : if (!TAILQ_EMPTY(°raded_set->lvols)) {
# # # # ]
1984 : 3 : return;
1985 : : }
1986 : :
1987 [ # # ]: 34 : RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
1988 : :
1989 [ # # # # ]: 34 : free((char *)degraded_set->esnap_id);
1990 : 34 : free(degraded_set);
1991 : 0 : }
1992 : :
1993 : : struct lvs_esnap_hotplug_req {
1994 : : struct spdk_lvol *lvol;
1995 : : spdk_lvol_op_with_handle_complete cb_fn;
1996 : : void *cb_arg;
1997 : : };
1998 : :
1999 : : static void
2000 : 78 : lvs_esnap_hotplug_done(void *cb_arg, int bserrno)
2001 : : {
2002 : 78 : struct lvs_esnap_hotplug_req *req = cb_arg;
2003 [ # # # # ]: 78 : struct spdk_lvol *lvol = req->lvol;
2004 [ # # # # ]: 78 : struct spdk_lvol_store *lvs = lvol->lvol_store;
2005 : :
2006 [ - + ]: 78 : if (bserrno != 0) {
2007 [ # # # # ]: 0 : SPDK_ERRLOG("lvol %s/%s: failed to hotplug blob_bdev due to error %d\n",
2008 : : lvs->name, lvol->name, bserrno);
2009 : 0 : }
2010 [ # # # # : 78 : req->cb_fn(req->cb_arg, lvol, bserrno);
# # # # #
# # # ]
2011 : 78 : free(req);
2012 : 78 : }
2013 : :
2014 : : static void
2015 : 48 : lvs_esnap_degraded_hotplug(struct spdk_lvs_degraded_lvol_set *degraded_set,
2016 : : spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
2017 : : {
2018 [ # # # # ]: 48 : struct spdk_lvol_store *lvs = degraded_set->lvol_store;
2019 : : struct spdk_lvol *lvol, *tmp, *last_missing;
2020 : 48 : struct spdk_bs_dev *bs_dev;
2021 [ # # # # ]: 48 : const void *esnap_id = degraded_set->esnap_id;
2022 [ # # # # ]: 48 : uint32_t id_len = degraded_set->id_len;
2023 : : struct lvs_esnap_hotplug_req *req;
2024 : : int rc;
2025 : :
2026 [ - + # # : 48 : assert(lvs->thread == spdk_get_thread());
# # # # ]
2027 : :
2028 : : /*
2029 : : * When lvs->esnap_bs_bdev_create() tries to load an external snapshot, it can encounter
2030 : : * errors that lead it to calling spdk_lvs_esnap_missing_add(). This function needs to be
2031 : : * sure that such modifications do not lead to degraded_set->lvols tailqs or references
2032 : : * to memory that this function will free.
2033 : : *
2034 : : * While this function is running, no other thread can add items to degraded_set->lvols. If
2035 : : * the list is mutated, it must have been done by this function or something in its call
2036 : : * graph running on this thread.
2037 : : */
2038 : :
2039 : : /* Remember the last lvol on the list. Iteration will stop once it has been processed. */
2040 [ # # # # : 48 : last_missing = TAILQ_LAST(°raded_set->lvols, degraded_lvols);
# # # # #
# # # ]
2041 : :
2042 [ + - # # : 87 : TAILQ_FOREACH_SAFE(lvol, °raded_set->lvols, degraded_link, tmp) {
# # # # #
# # # # #
# # ]
2043 : 87 : req = calloc(1, sizeof(*req));
2044 [ - + ]: 87 : if (req == NULL) {
2045 [ # # ]: 0 : SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: out of memory\n",
2046 : : lvol->unique_id);
2047 [ # # # # ]: 0 : cb_fn(cb_arg, lvol, -ENOMEM);
2048 : : /* The next one likely won't succeed either, but keep going so that all the
2049 : : * failed hotplugs are logged.
2050 : : */
2051 : 0 : goto next;
2052 : : }
2053 : :
2054 : : /*
2055 : : * Remove the lvol from the tailq so that tailq corruption is avoided if
2056 : : * lvs->esnap_bs_dev_create() calls spdk_lvs_esnap_missing_add(lvol).
2057 : : */
2058 [ + + # # : 87 : TAILQ_REMOVE(°raded_set->lvols, lvol, degraded_link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
2059 [ # # # # ]: 87 : lvol->degraded_set = NULL;
2060 : :
2061 : 87 : bs_dev = NULL;
2062 [ # # # # : 87 : rc = lvs->esnap_bs_dev_create(lvs, lvol, lvol->blob, esnap_id, id_len, &bs_dev);
# # # # #
# # # ]
2063 [ + + ]: 87 : if (rc != 0) {
2064 [ # # ]: 9 : SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: error %d\n",
2065 : : lvol->unique_id, rc);
2066 [ # # # # ]: 9 : lvol->degraded_set = degraded_set;
2067 [ # # # # : 9 : TAILQ_INSERT_TAIL(°raded_set->lvols, lvol, degraded_link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
2068 [ # # # # ]: 9 : cb_fn(cb_arg, lvol, rc);
2069 : 9 : free(req);
2070 : 9 : goto next;
2071 : : }
2072 : :
2073 [ # # # # ]: 78 : req->lvol = lvol;
2074 [ # # # # ]: 78 : req->cb_fn = cb_fn;
2075 [ # # # # ]: 78 : req->cb_arg = cb_arg;
2076 [ # # # # ]: 78 : spdk_blob_set_esnap_bs_dev(lvol->blob, bs_dev, lvs_esnap_hotplug_done, req);
2077 : :
2078 : 87 : next:
2079 [ + + ]: 87 : if (lvol == last_missing) {
2080 : : /*
2081 : : * Anything after last_missing was added due to some problem encountered
2082 : : * while trying to create the esnap bs_dev.
2083 : : */
2084 : 48 : break;
2085 : : }
2086 : 0 : }
2087 : :
2088 [ + + # # : 48 : if (TAILQ_EMPTY(°raded_set->lvols)) {
# # # # ]
2089 [ # # ]: 21 : RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
2090 [ # # # # ]: 21 : free((void *)degraded_set->esnap_id);
2091 : 21 : free(degraded_set);
2092 : 0 : }
2093 : 48 : }
2094 : :
2095 : : /*
2096 : : * Notify each lvstore created on this thread that is missing a bdev by the specified name or uuid
2097 : : * that the bdev now exists.
2098 : : */
2099 : : bool
2100 : 5558 : spdk_lvs_notify_hotplug(const void *esnap_id, uint32_t id_len,
2101 : : spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
2102 : : {
2103 : : struct spdk_lvs_degraded_lvol_set *found;
2104 : 5558 : struct spdk_lvs_degraded_lvol_set find = { 0 };
2105 : : struct spdk_lvol_store *lvs;
2106 : 5558 : struct spdk_thread *thread = spdk_get_thread();
2107 : 5558 : bool ret = false;
2108 : :
2109 [ + - ]: 5558 : find.esnap_id = esnap_id;
2110 [ + - ]: 5558 : find.id_len = id_len;
2111 : :
2112 [ + + ]: 5558 : pthread_mutex_lock(&g_lvol_stores_mutex);
2113 [ + + # # : 6229 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
# # # # ]
2114 [ - + # # : 671 : if (thread != lvs->thread) {
# # ]
2115 : : /*
2116 : : * It is expected that this is called from vbdev_lvol's examine_config()
2117 : : * callback. The lvstore was likely loaded do a creation happening as a
2118 : : * result of an RPC call or opening of an existing lvstore via
2119 : : * examine_disk() callback. RPC calls, examine_disk(), and examine_config()
2120 : : * should all be happening only on the app thread. The "wrong thread"
2121 : : * condition will only happen when an application is doing something weird.
2122 : : */
2123 [ # # ]: 0 : SPDK_NOTICELOG("Discarded examine for lvstore %s: wrong thread\n",
2124 : : lvs->name);
2125 : 0 : continue;
2126 : : }
2127 : :
2128 [ # # ]: 671 : found = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
2129 [ + + ]: 671 : if (found == NULL) {
2130 : 623 : continue;
2131 : : }
2132 : :
2133 : 48 : ret = true;
2134 : 48 : lvs_esnap_degraded_hotplug(found, cb_fn, cb_arg);
2135 : 0 : }
2136 [ + + ]: 5558 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2137 : :
2138 [ + - ]: 5558 : return ret;
2139 : : }
2140 : :
2141 : : int
2142 : 17 : spdk_lvol_iter_immediate_clones(struct spdk_lvol *lvol, spdk_lvol_iter_cb cb_fn, void *cb_arg)
2143 : : {
2144 [ # # # # ]: 17 : struct spdk_lvol_store *lvs = lvol->lvol_store;
2145 [ # # # # ]: 17 : struct spdk_blob_store *bs = lvs->blobstore;
2146 : : struct spdk_lvol *clone;
2147 : : spdk_blob_id *ids;
2148 : 17 : size_t id_cnt = 0;
2149 : : size_t i;
2150 : : int rc;
2151 : :
2152 [ # # # # ]: 17 : rc = spdk_blob_get_clones(bs, lvol->blob_id, NULL, &id_cnt);
2153 [ + + ]: 17 : if (rc != -ENOMEM) {
2154 : : /* -ENOMEM says id_cnt is valid, no other errors should be returned. */
2155 [ - + # # ]: 6 : assert(rc == 0);
2156 : 6 : return rc;
2157 : : }
2158 : :
2159 : 11 : ids = calloc(id_cnt, sizeof(*ids));
2160 [ - + ]: 11 : if (ids == NULL) {
2161 [ # # ]: 0 : SPDK_ERRLOG("lvol %s: out of memory while iterating clones\n", lvol->unique_id);
2162 : 0 : return -ENOMEM;
2163 : : }
2164 : :
2165 [ # # # # ]: 11 : rc = spdk_blob_get_clones(bs, lvol->blob_id, ids, &id_cnt);
2166 [ - + ]: 11 : if (rc != 0) {
2167 [ # # ]: 0 : SPDK_ERRLOG("lvol %s: unable to get clone blob IDs: %d\n", lvol->unique_id, rc);
2168 : 0 : free(ids);
2169 : 0 : return rc;
2170 : : }
2171 : :
2172 [ + + ]: 22 : for (i = 0; i < id_cnt; i++) {
2173 [ # # # # ]: 14 : clone = lvs_get_lvol_by_blob_id(lvs, ids[i]);
2174 [ - + ]: 14 : if (clone == NULL) {
2175 [ # # # # : 0 : SPDK_NOTICELOG("lvol %s: unable to find clone lvol with blob id 0x%"
# # ]
2176 : : PRIx64 "\n", lvol->unique_id, ids[i]);
2177 : 0 : continue;
2178 : : }
2179 [ # # # # ]: 14 : rc = cb_fn(cb_arg, clone);
2180 [ + + ]: 14 : if (rc != 0) {
2181 [ - + - + : 3 : SPDK_DEBUGLOG(lvol, "lvol %s: iteration stopped when lvol %s (blob 0x%"
# # # # #
# # # #
# ]
2182 : : PRIx64 ") returned %d\n", lvol->unique_id, clone->unique_id,
2183 : : ids[i], rc);
2184 : 3 : break;
2185 : : }
2186 : 0 : }
2187 : :
2188 : 11 : free(ids);
2189 : 11 : return rc;
2190 : 0 : }
2191 : :
2192 : : struct spdk_lvol *
2193 : 8 : spdk_lvol_get_by_uuid(const struct spdk_uuid *uuid)
2194 : : {
2195 : : struct spdk_lvol_store *lvs;
2196 : : struct spdk_lvol *lvol;
2197 : :
2198 [ - + ]: 8 : pthread_mutex_lock(&g_lvol_stores_mutex);
2199 : :
2200 [ + - # # : 8 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
# # # # ]
2201 [ + - # # : 9 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
# # # # #
# # # #
# ]
2202 [ + + # # ]: 9 : if (spdk_uuid_compare(uuid, &lvol->uuid) == 0) {
2203 [ - + ]: 8 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2204 : 8 : return lvol;
2205 : : }
2206 : 0 : }
2207 : 0 : }
2208 : :
2209 [ # # ]: 0 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2210 : 0 : return NULL;
2211 : 0 : }
2212 : :
2213 : : struct spdk_lvol *
2214 : 229 : spdk_lvol_get_by_names(const char *lvs_name, const char *lvol_name)
2215 : : {
2216 : : struct spdk_lvol_store *lvs;
2217 : : struct spdk_lvol *lvol;
2218 : :
2219 [ # # ]: 229 : pthread_mutex_lock(&g_lvol_stores_mutex);
2220 : :
2221 [ + + # # : 320 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
# # # # ]
2222 [ + + - + : 185 : if (strcmp(lvs_name, lvs->name) != 0) {
+ + # # ]
2223 : 9 : continue;
2224 : : }
2225 [ + + # # : 198 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
# # # # #
# # # #
# ]
2226 [ + + - + : 116 : if (strcmp(lvol_name, lvol->name) == 0) {
+ + # # ]
2227 [ # # ]: 94 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2228 : 94 : return lvol;
2229 : : }
2230 : 0 : }
2231 : 0 : }
2232 : :
2233 [ # # ]: 135 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2234 : 135 : return NULL;
2235 : 0 : }
2236 : :
2237 : : bool
2238 : 700 : spdk_lvol_is_degraded(const struct spdk_lvol *lvol)
2239 : : {
2240 [ # # # # ]: 700 : struct spdk_blob *blob = lvol->blob;
2241 : :
2242 [ - + ]: 700 : if (blob == NULL) {
2243 : 0 : return true;
2244 : : }
2245 : 700 : return spdk_blob_is_degraded(blob);
2246 : 0 : }
2247 : :
2248 : : static void
2249 : 4 : lvol_shallow_copy_cb(void *cb_arg, int lvolerrno)
2250 : : {
2251 : 4 : struct spdk_lvol_copy_req *req = cb_arg;
2252 [ # # # # ]: 4 : struct spdk_lvol *lvol = req->lvol;
2253 : :
2254 [ # # # # ]: 4 : spdk_bs_free_io_channel(req->channel);
2255 : :
2256 [ - + ]: 4 : if (lvolerrno < 0) {
2257 [ # # ]: 0 : SPDK_ERRLOG("Could not make a shallow copy of lvol %s, error %d\n", lvol->unique_id, lvolerrno);
2258 : 0 : }
2259 : :
2260 [ # # # # : 4 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
2261 : 4 : free(req);
2262 : 4 : }
2263 : :
2264 : : int
2265 : 10 : spdk_lvol_shallow_copy(struct spdk_lvol *lvol, struct spdk_bs_dev *ext_dev,
2266 : : spdk_blob_shallow_copy_status status_cb_fn, void *status_cb_arg,
2267 : : spdk_lvol_op_complete cb_fn, void *cb_arg)
2268 : : {
2269 : : struct spdk_lvol_copy_req *req;
2270 : : spdk_blob_id blob_id;
2271 : : int rc;
2272 : :
2273 [ - + # # ]: 10 : assert(cb_fn != NULL);
2274 : :
2275 [ + + ]: 10 : if (lvol == NULL) {
2276 : 3 : SPDK_ERRLOG("lvol must not be NULL\n");
2277 : 3 : return -EINVAL;
2278 : : }
2279 : :
2280 [ - + # # : 7 : assert(lvol->lvol_store->thread == spdk_get_thread());
# # # # #
# # # ]
2281 : :
2282 [ + + ]: 7 : if (ext_dev == NULL) {
2283 [ # # ]: 3 : SPDK_ERRLOG("lvol %s shallow copy, ext_dev must not be NULL\n", lvol->unique_id);
2284 : 3 : return -EINVAL;
2285 : : }
2286 : :
2287 : 4 : req = calloc(1, sizeof(*req));
2288 [ - + ]: 4 : if (!req) {
2289 [ # # ]: 0 : SPDK_ERRLOG("lvol %s shallow copy, cannot alloc memory for lvol request\n", lvol->unique_id);
2290 : 0 : return -ENOMEM;
2291 : : }
2292 : :
2293 [ # # # # ]: 4 : req->lvol = lvol;
2294 [ # # # # ]: 4 : req->cb_fn = cb_fn;
2295 [ # # # # ]: 4 : req->cb_arg = cb_arg;
2296 [ # # # # : 4 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
# # # # #
# # # ]
2297 [ - + # # : 4 : if (req->channel == NULL) {
# # ]
2298 [ # # ]: 0 : SPDK_ERRLOG("lvol %s shallow copy, cannot alloc io channel for lvol request\n", lvol->unique_id);
2299 : 0 : free(req);
2300 : 0 : return -ENOMEM;
2301 : : }
2302 : :
2303 [ # # # # ]: 4 : blob_id = spdk_blob_get_id(lvol->blob);
2304 : :
2305 [ # # # # : 4 : rc = spdk_bs_blob_shallow_copy(lvol->lvol_store->blobstore, req->channel, blob_id, ext_dev,
# # # # #
# # # ]
2306 : 0 : status_cb_fn, status_cb_arg, lvol_shallow_copy_cb, req);
2307 : :
2308 [ - + ]: 4 : if (rc < 0) {
2309 [ # # ]: 0 : SPDK_ERRLOG("Could not make a shallow copy of lvol %s\n", lvol->unique_id);
2310 [ # # # # ]: 0 : spdk_bs_free_io_channel(req->channel);
2311 : 0 : free(req);
2312 : 0 : }
2313 : :
2314 : 4 : return rc;
2315 : 0 : }
2316 : :
2317 : : static void
2318 : 10 : lvol_set_parent_cb(void *cb_arg, int lvolerrno)
2319 : : {
2320 : 10 : struct spdk_lvol_req *req = cb_arg;
2321 : :
2322 [ + + ]: 10 : if (lvolerrno < 0) {
2323 [ # # # # : 4 : SPDK_ERRLOG("could not set parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
# # ]
2324 : 0 : }
2325 : :
2326 [ # # # # : 10 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
2327 : 10 : free(req);
2328 : 10 : }
2329 : :
2330 : : void
2331 : 16 : spdk_lvol_set_parent(struct spdk_lvol *lvol, struct spdk_lvol *snapshot,
2332 : : spdk_lvol_op_complete cb_fn, void *cb_arg)
2333 : : {
2334 : : struct spdk_lvol_req *req;
2335 : : spdk_blob_id blob_id, snapshot_id;
2336 : :
2337 [ - + # # ]: 16 : assert(cb_fn != NULL);
2338 : :
2339 [ + + ]: 16 : if (lvol == NULL) {
2340 : 3 : SPDK_ERRLOG("lvol must not be NULL\n");
2341 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2342 : 3 : return;
2343 : : }
2344 : :
2345 [ + + ]: 13 : if (snapshot == NULL) {
2346 : 3 : SPDK_ERRLOG("snapshot must not be NULL\n");
2347 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2348 : 3 : return;
2349 : : }
2350 : :
2351 : 10 : req = calloc(1, sizeof(*req));
2352 [ - + ]: 10 : if (!req) {
2353 : 0 : SPDK_ERRLOG("cannot alloc memory for lvol request pointer\n");
2354 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
2355 : 0 : return;
2356 : : }
2357 : :
2358 [ # # # # ]: 10 : req->lvol = lvol;
2359 [ # # # # ]: 10 : req->cb_fn = cb_fn;
2360 [ # # # # ]: 10 : req->cb_arg = cb_arg;
2361 : :
2362 [ # # # # ]: 10 : blob_id = spdk_blob_get_id(lvol->blob);
2363 [ # # # # ]: 10 : snapshot_id = spdk_blob_get_id(snapshot->blob);
2364 : :
2365 [ # # # # : 10 : spdk_bs_blob_set_parent(lvol->lvol_store->blobstore, blob_id, snapshot_id,
# # # # ]
2366 : 0 : lvol_set_parent_cb, req);
2367 : 0 : }
2368 : :
2369 : : static void
2370 : 9 : lvol_set_external_parent_cb(void *cb_arg, int lvolerrno)
2371 : : {
2372 : 9 : struct spdk_lvol_bs_dev_req *req = cb_arg;
2373 : :
2374 [ + + ]: 9 : if (lvolerrno < 0) {
2375 [ # # # # : 3 : SPDK_ERRLOG("could not set external parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
# # ]
2376 [ # # # # : 3 : req->bs_dev->destroy(req->bs_dev);
# # # # #
# # # # #
# # ]
2377 : 0 : }
2378 : :
2379 [ # # # # : 9 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
2380 : 9 : free(req);
2381 : 9 : }
2382 : :
2383 : : void
2384 : 18 : spdk_lvol_set_external_parent(struct spdk_lvol *lvol, const void *esnap_id, uint32_t esnap_id_len,
2385 : : spdk_lvol_op_complete cb_fn, void *cb_arg)
2386 : : {
2387 : : struct spdk_lvol_bs_dev_req *req;
2388 : 18 : struct spdk_bs_dev *bs_dev;
2389 : : spdk_blob_id blob_id;
2390 : : int rc;
2391 : :
2392 [ - + # # ]: 18 : assert(cb_fn != NULL);
2393 : :
2394 [ + + ]: 18 : if (lvol == NULL) {
2395 : 3 : SPDK_ERRLOG("lvol must not be NULL\n");
2396 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2397 : 3 : return;
2398 : : }
2399 : :
2400 [ + + ]: 15 : if (esnap_id == NULL) {
2401 : 3 : SPDK_ERRLOG("snapshot must not be NULL\n");
2402 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2403 : 3 : return;
2404 : : }
2405 : :
2406 [ + - # # ]: 12 : if (esnap_id_len == sizeof(lvol->uuid_str) &&
2407 [ + + - + : 12 : memcmp(esnap_id, lvol->uuid_str, esnap_id_len) == 0) {
+ + ]
2408 [ # # ]: 3 : SPDK_ERRLOG("lvol %s and esnap have the same UUID\n", lvol->name);
2409 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2410 : 3 : return;
2411 : : }
2412 : :
2413 [ # # # # : 9 : rc = lvs_esnap_bs_dev_create(lvol->lvol_store, lvol, lvol->blob, esnap_id, esnap_id_len, &bs_dev);
# # # # ]
2414 [ - + ]: 9 : if (rc < 0) {
2415 [ # # # # ]: 0 : cb_fn(cb_arg, rc);
2416 : 0 : return;
2417 : : }
2418 : :
2419 : 9 : req = calloc(1, sizeof(*req));
2420 [ - + ]: 9 : if (!req) {
2421 : 0 : SPDK_ERRLOG("cannot alloc memory for lvol request pointer\n");
2422 [ # # # # ]: 0 : cb_fn(cb_arg, -ENOMEM);
2423 : 0 : return;
2424 : : }
2425 : :
2426 [ # # # # ]: 9 : req->lvol = lvol;
2427 [ # # # # ]: 9 : req->bs_dev = bs_dev;
2428 [ # # # # ]: 9 : req->cb_fn = cb_fn;
2429 [ # # # # ]: 9 : req->cb_arg = cb_arg;
2430 : :
2431 [ # # # # ]: 9 : blob_id = spdk_blob_get_id(lvol->blob);
2432 : :
2433 [ # # # # : 9 : spdk_bs_blob_set_external_parent(lvol->lvol_store->blobstore, blob_id, bs_dev, esnap_id,
# # # # ]
2434 : 0 : esnap_id_len, lvol_set_external_parent_cb, req);
2435 : 0 : }
|