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