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