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 :
651 53 : 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 53 : return 0;
661 : }
662 :
663 : static void
664 52 : setup_lvs_opts(struct spdk_bs_opts *bs_opts, struct spdk_lvs_opts *o, uint32_t total_clusters,
665 : void *esnap_ctx)
666 : {
667 52 : assert(o != NULL);
668 52 : lvs_bs_opts_init(bs_opts);
669 52 : bs_opts->cluster_sz = o->cluster_sz;
670 52 : bs_opts->clear_method = (enum bs_clear_method)o->clear_method;
671 52 : bs_opts->num_md_pages = (o->num_md_pages_per_cluster_ratio * total_clusters) / 100;
672 52 : bs_opts->esnap_bs_dev_create = o->esnap_bs_dev_create;
673 52 : bs_opts->esnap_ctx = esnap_ctx;
674 52 : snprintf(bs_opts->bstype.bstype, sizeof(bs_opts->bstype.bstype), "LVOLSTORE");
675 52 : }
676 :
677 : int
678 53 : 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 53 : struct spdk_bs_opts opts = {};
684 53 : struct spdk_lvs_opts lvs_opts;
685 : uint32_t total_clusters;
686 : int rc;
687 :
688 53 : if (bs_dev == NULL) {
689 1 : SPDK_ERRLOG("Blobstore device does not exist\n");
690 1 : return -ENODEV;
691 : }
692 :
693 52 : if (o == NULL) {
694 0 : SPDK_ERRLOG("spdk_lvs_opts not specified\n");
695 0 : return -EINVAL;
696 : }
697 :
698 52 : spdk_lvs_opts_init(&lvs_opts);
699 52 : if (lvs_opts_copy(o, &lvs_opts) != 0) {
700 0 : SPDK_ERRLOG("spdk_lvs_opts invalid\n");
701 0 : return -EINVAL;
702 : }
703 :
704 52 : if (lvs_opts.cluster_sz < bs_dev->blocklen) {
705 0 : SPDK_ERRLOG("Cluster size %" PRIu32 " is smaller than blocklen %" PRIu32 "\n",
706 : lvs_opts.cluster_sz, bs_dev->blocklen);
707 0 : return -EINVAL;
708 : }
709 52 : total_clusters = bs_dev->blockcnt / (lvs_opts.cluster_sz / bs_dev->blocklen);
710 :
711 52 : lvs = lvs_alloc();
712 52 : if (!lvs) {
713 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store base pointer\n");
714 0 : return -ENOMEM;
715 : }
716 :
717 52 : setup_lvs_opts(&opts, o, total_clusters, lvs);
718 :
719 52 : if (strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX) == SPDK_LVS_NAME_MAX) {
720 1 : SPDK_ERRLOG("Name has no null terminator.\n");
721 1 : lvs_free(lvs);
722 1 : return -EINVAL;
723 : }
724 :
725 51 : if (strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX) == 0) {
726 1 : SPDK_ERRLOG("No name specified.\n");
727 1 : lvs_free(lvs);
728 1 : return -EINVAL;
729 : }
730 :
731 50 : spdk_uuid_generate(&lvs->uuid);
732 50 : snprintf(lvs->name, sizeof(lvs->name), "%s", lvs_opts.name);
733 :
734 50 : rc = add_lvs_to_list(lvs);
735 50 : if (rc) {
736 1 : SPDK_ERRLOG("lvolstore with name %s already exists\n", lvs->name);
737 1 : lvs_free(lvs);
738 1 : return -EEXIST;
739 : }
740 :
741 49 : lvs_req = calloc(1, sizeof(*lvs_req));
742 49 : 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 49 : assert(cb_fn != NULL);
749 49 : lvs_req->cb_fn = cb_fn;
750 49 : lvs_req->cb_arg = cb_arg;
751 49 : lvs_req->lvol_store = lvs;
752 49 : lvs->bs_dev = bs_dev;
753 :
754 49 : SPDK_INFOLOG(lvol, "Initializing lvol store\n");
755 49 : spdk_bs_init(bs_dev, &opts, lvs_init_cb, lvs_req);
756 :
757 49 : return 0;
758 : }
759 :
760 : static void
761 2 : lvs_rename_cb(void *cb_arg, int lvolerrno)
762 : {
763 2 : struct spdk_lvs_req *req = cb_arg;
764 :
765 2 : if (lvolerrno != 0) {
766 1 : req->lvserrno = lvolerrno;
767 : }
768 2 : if (req->lvserrno != 0) {
769 1 : 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 1 : snprintf(req->lvol_store->new_name,
773 : sizeof(req->lvol_store->new_name),
774 1 : "%s", req->lvol_store->name);
775 : } else {
776 : /* Update lvs name with new_name */
777 1 : snprintf(req->lvol_store->name,
778 : sizeof(req->lvol_store->name),
779 1 : "%s", req->lvol_store->new_name);
780 : }
781 :
782 2 : req->cb_fn(req->cb_arg, req->lvserrno);
783 2 : free(req);
784 2 : }
785 :
786 : static void
787 1 : lvs_rename_sync_cb(void *cb_arg, int lvolerrno)
788 : {
789 1 : struct spdk_lvs_req *req = cb_arg;
790 1 : struct spdk_blob *blob = req->lvol_store->super_blob;
791 :
792 1 : if (lvolerrno < 0) {
793 0 : req->lvserrno = lvolerrno;
794 : }
795 :
796 1 : spdk_blob_close(blob, lvs_rename_cb, req);
797 1 : }
798 :
799 : static void
800 2 : lvs_rename_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
801 : {
802 2 : struct spdk_lvs_req *req = cb_arg;
803 : int rc;
804 :
805 2 : if (lvolerrno < 0) {
806 1 : lvs_rename_cb(cb_arg, lvolerrno);
807 1 : return;
808 : }
809 :
810 1 : rc = spdk_blob_set_xattr(blob, "name", req->lvol_store->new_name,
811 1 : strlen(req->lvol_store->new_name) + 1);
812 1 : if (rc < 0) {
813 0 : req->lvserrno = rc;
814 0 : lvs_rename_sync_cb(req, rc);
815 0 : return;
816 : }
817 :
818 1 : req->lvol_store->super_blob = blob;
819 :
820 1 : spdk_blob_sync_md(blob, lvs_rename_sync_cb, req);
821 : }
822 :
823 : void
824 5 : 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 5 : if (strncmp(lvs->name, new_name, SPDK_LVS_NAME_MAX) == 0) {
833 1 : cb_fn(cb_arg, 0);
834 1 : return;
835 : }
836 :
837 : /* Check if new or new_name is already used in other lvs */
838 4 : pthread_mutex_lock(&g_lvol_stores_mutex);
839 9 : TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
840 7 : if (!strncmp(new_name, tmp->name, SPDK_LVS_NAME_MAX) ||
841 6 : !strncmp(new_name, tmp->new_name, SPDK_LVS_NAME_MAX)) {
842 2 : pthread_mutex_unlock(&g_lvol_stores_mutex);
843 2 : cb_fn(cb_arg, -EEXIST);
844 2 : return;
845 : }
846 : }
847 2 : pthread_mutex_unlock(&g_lvol_stores_mutex);
848 :
849 2 : req = calloc(1, sizeof(*req));
850 2 : 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 2 : snprintf(lvs->new_name, sizeof(lvs->new_name), "%s", new_name);
856 2 : req->lvol_store = lvs;
857 2 : req->cb_fn = cb_fn;
858 2 : req->cb_arg = cb_arg;
859 :
860 2 : spdk_bs_open_blob(lvs->blobstore, lvs->super_blob_id, lvs_rename_open_cb, req);
861 : }
862 :
863 : static void
864 27 : _lvs_unload_cb(void *cb_arg, int lvserrno)
865 : {
866 27 : struct spdk_lvs_req *lvs_req = cb_arg;
867 :
868 27 : SPDK_INFOLOG(lvol, "Lvol store unloaded\n");
869 27 : assert(lvs_req->cb_fn != NULL);
870 27 : lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
871 27 : free(lvs_req);
872 27 : }
873 :
874 : int
875 29 : 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 29 : if (lvs == NULL) {
882 1 : SPDK_ERRLOG("Lvol store is NULL\n");
883 1 : return -ENODEV;
884 : }
885 :
886 52 : TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
887 25 : 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 25 : } else if (lvol->ref_count != 0) {
892 1 : SPDK_ERRLOG("Lvols still open on lvol store\n");
893 1 : cb_fn(cb_arg, -EBUSY);
894 1 : return -EBUSY;
895 : }
896 : }
897 :
898 51 : TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
899 24 : spdk_lvs_esnap_missing_remove(lvol);
900 24 : TAILQ_REMOVE(&lvs->lvols, lvol, link);
901 24 : lvol_free(lvol);
902 : }
903 :
904 27 : lvs_req = calloc(1, sizeof(*lvs_req));
905 27 : if (!lvs_req) {
906 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
907 0 : return -ENOMEM;
908 : }
909 :
910 27 : lvs_req->cb_fn = cb_fn;
911 27 : lvs_req->cb_arg = cb_arg;
912 :
913 27 : SPDK_INFOLOG(lvol, "Unloading lvol store\n");
914 27 : spdk_bs_unload(lvs->blobstore, _lvs_unload_cb, lvs_req);
915 27 : lvs_free(lvs);
916 :
917 27 : return 0;
918 : }
919 :
920 : static void
921 28 : _lvs_destroy_cb(void *cb_arg, int lvserrno)
922 : {
923 28 : struct spdk_lvs_destroy_req *lvs_req = cb_arg;
924 :
925 28 : SPDK_INFOLOG(lvol, "Lvol store destroyed\n");
926 28 : assert(lvs_req->cb_fn != NULL);
927 28 : lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
928 28 : free(lvs_req);
929 28 : }
930 :
931 : static void
932 28 : _lvs_destroy_super_cb(void *cb_arg, int bserrno)
933 : {
934 28 : struct spdk_lvs_destroy_req *lvs_req = cb_arg;
935 28 : struct spdk_lvol_store *lvs = lvs_req->lvs;
936 :
937 28 : assert(lvs != NULL);
938 :
939 28 : SPDK_INFOLOG(lvol, "Destroying lvol store\n");
940 28 : spdk_bs_destroy(lvs->blobstore, _lvs_destroy_cb, lvs_req);
941 28 : lvs_free(lvs);
942 28 : }
943 :
944 : int
945 29 : 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 29 : if (lvs == NULL) {
952 0 : SPDK_ERRLOG("Lvol store is NULL\n");
953 0 : return -ENODEV;
954 : }
955 :
956 32 : TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
957 4 : 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 4 : } else if (iter_lvol->ref_count != 0) {
962 1 : SPDK_ERRLOG("Lvols still open on lvol store\n");
963 1 : cb_fn(cb_arg, -EBUSY);
964 1 : return -EBUSY;
965 : }
966 : }
967 :
968 31 : TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
969 3 : free(iter_lvol);
970 : }
971 :
972 28 : lvs_req = calloc(1, sizeof(*lvs_req));
973 28 : if (!lvs_req) {
974 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
975 0 : return -ENOMEM;
976 : }
977 :
978 28 : lvs_req->cb_fn = cb_fn;
979 28 : lvs_req->cb_arg = cb_arg;
980 28 : lvs_req->lvs = lvs;
981 :
982 28 : SPDK_INFOLOG(lvol, "Deleting super blob\n");
983 28 : spdk_bs_delete_blob(lvs->blobstore, lvs->super_blob_id, _lvs_destroy_super_cb, lvs_req);
984 :
985 28 : return 0;
986 : }
987 :
988 : static void
989 80 : lvol_close_blob_cb(void *cb_arg, int lvolerrno)
990 : {
991 80 : struct spdk_lvol_req *req = cb_arg;
992 80 : struct spdk_lvol *lvol = req->lvol;
993 :
994 80 : if (lvolerrno < 0) {
995 1 : SPDK_ERRLOG("Could not close blob on lvol\n");
996 1 : goto end;
997 : }
998 :
999 79 : lvol->ref_count--;
1000 79 : lvol->blob = NULL;
1001 79 : SPDK_INFOLOG(lvol, "Lvol %s closed\n", lvol->unique_id);
1002 :
1003 79 : end:
1004 80 : lvol->action_in_progress = false;
1005 80 : req->cb_fn(req->cb_arg, lvolerrno);
1006 80 : free(req);
1007 80 : }
1008 :
1009 : bool
1010 0 : spdk_lvol_deletable(struct spdk_lvol *lvol)
1011 : {
1012 0 : size_t count = 0;
1013 :
1014 0 : spdk_blob_get_clones(lvol->lvol_store->blobstore, lvol->blob_id, NULL, &count);
1015 0 : return (count == 0);
1016 : }
1017 :
1018 : static void
1019 56 : lvol_delete_blob_cb(void *cb_arg, int lvolerrno)
1020 : {
1021 56 : struct spdk_lvol_req *req = cb_arg;
1022 56 : struct spdk_lvol *lvol = req->lvol;
1023 56 : struct spdk_lvol *clone_lvol = req->clone_lvol;
1024 :
1025 56 : if (lvolerrno < 0) {
1026 1 : SPDK_ERRLOG("Could not remove blob on lvol gracefully - forced removal\n");
1027 : } else {
1028 55 : SPDK_INFOLOG(lvol, "Lvol %s deleted\n", lvol->unique_id);
1029 : }
1030 :
1031 56 : if (lvol->degraded_set != NULL) {
1032 12 : 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 1 : struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
1039 :
1040 1 : lvs_degraded_lvol_set_remove(degraded_set, lvol);
1041 1 : lvs_degraded_lvol_set_add(degraded_set, clone_lvol);
1042 : } else {
1043 11 : spdk_lvs_esnap_missing_remove(lvol);
1044 : }
1045 : }
1046 :
1047 56 : TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link);
1048 56 : lvol_free(lvol);
1049 56 : req->cb_fn(req->cb_arg, lvolerrno);
1050 56 : free(req);
1051 56 : }
1052 :
1053 : static void
1054 75 : lvol_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
1055 : {
1056 75 : struct spdk_lvol_with_handle_req *req = cb_arg;
1057 75 : struct spdk_lvol *lvol = req->lvol;
1058 :
1059 75 : TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
1060 :
1061 75 : 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 75 : lvol->blob = blob;
1069 75 : lvol->blob_id = spdk_blob_get_id(blob);
1070 :
1071 75 : TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link);
1072 :
1073 75 : lvol->ref_count++;
1074 :
1075 75 : assert(req->cb_fn != NULL);
1076 75 : req->cb_fn(req->cb_arg, req->lvol, lvolerrno);
1077 75 : free(req);
1078 : }
1079 :
1080 : static void
1081 76 : lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
1082 : {
1083 76 : struct spdk_lvol_with_handle_req *req = cb_arg;
1084 : struct spdk_blob_store *bs;
1085 76 : struct spdk_blob_open_opts opts;
1086 :
1087 76 : if (lvolerrno < 0) {
1088 1 : TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
1089 1 : lvol_free(req->lvol);
1090 1 : assert(req->cb_fn != NULL);
1091 1 : req->cb_fn(req->cb_arg, NULL, lvolerrno);
1092 1 : free(req);
1093 1 : return;
1094 : }
1095 :
1096 75 : spdk_blob_open_opts_init(&opts, sizeof(opts));
1097 75 : 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 75 : opts.esnap_ctx = req->lvol;
1108 75 : bs = req->lvol->lvol_store->blobstore;
1109 :
1110 75 : 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 1 : struct spdk_lvs_degraded_lvol_set *degraded_set = req->origlvol->degraded_set;
1117 :
1118 1 : lvs_degraded_lvol_set_remove(degraded_set, req->origlvol);
1119 1 : lvs_degraded_lvol_set_add(degraded_set, req->lvol);
1120 : }
1121 :
1122 75 : spdk_bs_open_blob_ext(bs, blobid, &opts, lvol_create_open_cb, req);
1123 : }
1124 :
1125 : static void
1126 2 : lvol_get_xattr_value(void *xattr_ctx, const char *name,
1127 : const void **value, size_t *value_len)
1128 : {
1129 2 : struct spdk_lvol *lvol = xattr_ctx;
1130 :
1131 2 : if (!strcmp(LVOL_NAME, name)) {
1132 1 : *value = lvol->name;
1133 1 : *value_len = SPDK_LVOL_NAME_MAX;
1134 1 : return;
1135 : }
1136 1 : if (!strcmp("uuid", name)) {
1137 0 : *value = lvol->uuid_str;
1138 0 : *value_len = sizeof(lvol->uuid_str);
1139 0 : return;
1140 : }
1141 1 : *value = NULL;
1142 1 : *value_len = 0;
1143 : }
1144 :
1145 : static int
1146 95 : lvs_verify_lvol_name(struct spdk_lvol_store *lvs, const char *name)
1147 : {
1148 : struct spdk_lvol *tmp;
1149 :
1150 95 : if (name == NULL || strnlen(name, SPDK_LVOL_NAME_MAX) == 0) {
1151 7 : SPDK_INFOLOG(lvol, "lvol name not provided.\n");
1152 7 : return -EINVAL;
1153 : }
1154 :
1155 88 : if (strnlen(name, SPDK_LVOL_NAME_MAX) == SPDK_LVOL_NAME_MAX) {
1156 2 : SPDK_ERRLOG("Name has no null terminator.\n");
1157 2 : return -EINVAL;
1158 : }
1159 :
1160 130 : TAILQ_FOREACH(tmp, &lvs->lvols, link) {
1161 52 : if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
1162 8 : SPDK_ERRLOG("lvol with name %s already exists\n", name);
1163 8 : return -EEXIST;
1164 : }
1165 : }
1166 :
1167 78 : TAILQ_FOREACH(tmp, &lvs->pending_lvols, link) {
1168 1 : if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
1169 1 : SPDK_ERRLOG("lvol with name %s is being already created\n", name);
1170 1 : return -EEXIST;
1171 : }
1172 : }
1173 :
1174 77 : return 0;
1175 : }
1176 :
1177 : int
1178 42 : 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 42 : struct spdk_blob_opts opts;
1186 42 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1187 : int rc;
1188 :
1189 42 : if (lvs == NULL) {
1190 1 : SPDK_ERRLOG("lvol store does not exist\n");
1191 1 : return -EINVAL;
1192 : }
1193 :
1194 41 : rc = lvs_verify_lvol_name(lvs, name);
1195 41 : if (rc < 0) {
1196 7 : return rc;
1197 : }
1198 :
1199 34 : bs = lvs->blobstore;
1200 :
1201 34 : req = calloc(1, sizeof(*req));
1202 34 : if (!req) {
1203 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1204 0 : return -ENOMEM;
1205 : }
1206 34 : req->cb_fn = cb_fn;
1207 34 : req->cb_arg = cb_arg;
1208 :
1209 34 : lvol = lvol_alloc(lvs, name, thin_provision, clear_method);
1210 34 : 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 34 : req->lvol = lvol;
1217 34 : spdk_blob_opts_init(&opts, sizeof(opts));
1218 34 : opts.thin_provision = thin_provision;
1219 34 : opts.num_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(bs));
1220 34 : opts.clear_method = lvol->clear_method;
1221 34 : opts.xattrs.count = SPDK_COUNTOF(xattr_names);
1222 34 : opts.xattrs.names = xattr_names;
1223 34 : opts.xattrs.ctx = lvol;
1224 34 : opts.xattrs.get_value = lvol_get_xattr_value;
1225 :
1226 34 : spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
1227 :
1228 34 : return 0;
1229 : }
1230 :
1231 : int
1232 38 : 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 38 : struct spdk_blob_opts opts;
1240 : uint64_t cluster_sz;
1241 38 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1242 : int rc;
1243 :
1244 38 : if (lvs == NULL) {
1245 1 : SPDK_ERRLOG("lvol store does not exist\n");
1246 1 : return -EINVAL;
1247 : }
1248 :
1249 37 : rc = lvs_verify_lvol_name(lvs, clone_name);
1250 37 : if (rc < 0) {
1251 5 : return rc;
1252 : }
1253 :
1254 32 : bs = lvs->blobstore;
1255 :
1256 32 : cluster_sz = spdk_bs_get_cluster_size(bs);
1257 32 : if ((size_bytes % cluster_sz) != 0) {
1258 1 : 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 1 : return -EINVAL;
1262 : }
1263 :
1264 31 : req = calloc(1, sizeof(*req));
1265 31 : if (!req) {
1266 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1267 0 : return -ENOMEM;
1268 : }
1269 31 : req->cb_fn = cb_fn;
1270 31 : req->cb_arg = cb_arg;
1271 :
1272 31 : lvol = lvol_alloc(lvs, clone_name, true, LVOL_CLEAR_WITH_DEFAULT);
1273 31 : if (!lvol) {
1274 0 : free(req);
1275 0 : SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
1276 0 : return -ENOMEM;
1277 : }
1278 31 : req->lvol = lvol;
1279 :
1280 31 : spdk_blob_opts_init(&opts, sizeof(opts));
1281 31 : opts.esnap_id = esnap_id;
1282 31 : opts.esnap_id_len = id_len;
1283 31 : opts.thin_provision = true;
1284 31 : opts.num_clusters = spdk_divide_round_up(size_bytes, cluster_sz);
1285 31 : opts.clear_method = lvol->clear_method;
1286 31 : opts.xattrs.count = SPDK_COUNTOF(xattr_names);
1287 31 : opts.xattrs.names = xattr_names;
1288 31 : opts.xattrs.ctx = lvol;
1289 31 : opts.xattrs.get_value = lvol_get_xattr_value;
1290 :
1291 31 : spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
1292 :
1293 31 : return 0;
1294 : }
1295 :
1296 : void
1297 11 : 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 11 : struct spdk_blob_xattr_opts snapshot_xattrs;
1305 11 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1306 : int rc;
1307 :
1308 11 : if (origlvol == NULL) {
1309 1 : SPDK_INFOLOG(lvol, "Lvol not provided.\n");
1310 1 : cb_fn(cb_arg, NULL, -EINVAL);
1311 1 : return;
1312 : }
1313 :
1314 10 : origblob = origlvol->blob;
1315 10 : lvs = origlvol->lvol_store;
1316 10 : 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 10 : rc = lvs_verify_lvol_name(lvs, snapshot_name);
1323 10 : if (rc < 0) {
1324 3 : cb_fn(cb_arg, NULL, rc);
1325 3 : return;
1326 : }
1327 :
1328 7 : req = calloc(1, sizeof(*req));
1329 7 : 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 7 : newlvol = lvol_alloc(origlvol->lvol_store, snapshot_name, true,
1336 7 : (enum lvol_clear_method)origlvol->clear_method);
1337 7 : 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 7 : snapshot_xattrs.count = SPDK_COUNTOF(xattr_names);
1345 7 : snapshot_xattrs.ctx = newlvol;
1346 7 : snapshot_xattrs.names = xattr_names;
1347 7 : snapshot_xattrs.get_value = lvol_get_xattr_value;
1348 7 : req->lvol = newlvol;
1349 7 : req->origlvol = origlvol;
1350 7 : req->cb_fn = cb_fn;
1351 7 : req->cb_arg = cb_arg;
1352 :
1353 7 : spdk_bs_create_snapshot(lvs->blobstore, spdk_blob_get_id(origblob), &snapshot_xattrs,
1354 : lvol_create_cb, req);
1355 : }
1356 :
1357 : void
1358 8 : 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 8 : struct spdk_blob_xattr_opts clone_xattrs;
1366 8 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1367 : int rc;
1368 :
1369 8 : if (origlvol == NULL) {
1370 1 : SPDK_INFOLOG(lvol, "Lvol not provided.\n");
1371 1 : cb_fn(cb_arg, NULL, -EINVAL);
1372 1 : return;
1373 : }
1374 :
1375 7 : origblob = origlvol->blob;
1376 7 : lvs = origlvol->lvol_store;
1377 7 : 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 7 : rc = lvs_verify_lvol_name(lvs, clone_name);
1384 7 : if (rc < 0) {
1385 3 : cb_fn(cb_arg, NULL, rc);
1386 3 : return;
1387 : }
1388 :
1389 4 : req = calloc(1, sizeof(*req));
1390 4 : 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 4 : newlvol = lvol_alloc(lvs, clone_name, true, (enum lvol_clear_method)origlvol->clear_method);
1397 4 : 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 4 : clone_xattrs.count = SPDK_COUNTOF(xattr_names);
1405 4 : clone_xattrs.ctx = newlvol;
1406 4 : clone_xattrs.names = xattr_names;
1407 4 : clone_xattrs.get_value = lvol_get_xattr_value;
1408 4 : req->lvol = newlvol;
1409 4 : req->cb_fn = cb_fn;
1410 4 : req->cb_arg = cb_arg;
1411 :
1412 4 : 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 4 : lvol_resize_done(void *cb_arg, int lvolerrno)
1419 : {
1420 4 : struct spdk_lvol_req *req = cb_arg;
1421 :
1422 4 : req->cb_fn(req->cb_arg, lvolerrno);
1423 4 : free(req);
1424 4 : }
1425 :
1426 : static void
1427 6 : lvol_blob_resize_cb(void *cb_arg, int bserrno)
1428 : {
1429 6 : struct spdk_lvol_req *req = cb_arg;
1430 6 : struct spdk_lvol *lvol = req->lvol;
1431 :
1432 6 : if (bserrno != 0) {
1433 2 : req->cb_fn(req->cb_arg, bserrno);
1434 2 : free(req);
1435 2 : return;
1436 : }
1437 :
1438 4 : spdk_blob_sync_md(lvol->blob, lvol_resize_done, req);
1439 : }
1440 :
1441 : void
1442 6 : spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz,
1443 : spdk_lvol_op_complete cb_fn, void *cb_arg)
1444 : {
1445 6 : struct spdk_blob *blob = lvol->blob;
1446 6 : struct spdk_lvol_store *lvs = lvol->lvol_store;
1447 : struct spdk_lvol_req *req;
1448 6 : uint64_t new_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(lvs->blobstore));
1449 :
1450 6 : req = calloc(1, sizeof(*req));
1451 6 : 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 6 : req->cb_fn = cb_fn;
1457 6 : req->cb_arg = cb_arg;
1458 6 : req->lvol = lvol;
1459 :
1460 6 : spdk_blob_resize(blob, new_clusters, lvol_blob_resize_cb, req);
1461 : }
1462 :
1463 : static void
1464 1 : lvol_set_read_only_cb(void *cb_arg, int lvolerrno)
1465 : {
1466 1 : struct spdk_lvol_req *req = cb_arg;
1467 :
1468 1 : req->cb_fn(req->cb_arg, lvolerrno);
1469 1 : free(req);
1470 1 : }
1471 :
1472 : void
1473 1 : 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 1 : req = calloc(1, sizeof(*req));
1478 1 : 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 1 : req->cb_fn = cb_fn;
1484 1 : req->cb_arg = cb_arg;
1485 :
1486 1 : spdk_blob_set_read_only(lvol->blob);
1487 1 : spdk_blob_sync_md(lvol->blob, lvol_set_read_only_cb, req);
1488 : }
1489 :
1490 : static void
1491 1 : lvol_rename_cb(void *cb_arg, int lvolerrno)
1492 : {
1493 1 : struct spdk_lvol_req *req = cb_arg;
1494 :
1495 1 : if (lvolerrno != 0) {
1496 0 : SPDK_ERRLOG("Lvol rename operation failed\n");
1497 : } else {
1498 1 : snprintf(req->lvol->name, sizeof(req->lvol->name), "%s", req->name);
1499 : }
1500 :
1501 1 : req->cb_fn(req->cb_arg, lvolerrno);
1502 1 : free(req);
1503 1 : }
1504 :
1505 : void
1506 2 : 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 2 : 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 2 : 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 4 : TAILQ_FOREACH(tmp, &lvol->lvol_store->lvols, link) {
1523 3 : if (strncmp(tmp->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
1524 1 : SPDK_ERRLOG("Lvol %s already exists in lvol store %s\n", new_name, lvol->lvol_store->name);
1525 1 : cb_fn(cb_arg, -EEXIST);
1526 1 : return;
1527 : }
1528 : }
1529 :
1530 1 : req = calloc(1, sizeof(*req));
1531 1 : 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 1 : req->cb_fn = cb_fn;
1537 1 : req->cb_arg = cb_arg;
1538 1 : req->lvol = lvol;
1539 1 : snprintf(req->name, sizeof(req->name), "%s", new_name);
1540 :
1541 1 : rc = spdk_blob_set_xattr(blob, "name", new_name, strlen(new_name) + 1);
1542 1 : if (rc < 0) {
1543 0 : free(req);
1544 0 : cb_fn(cb_arg, rc);
1545 0 : return;
1546 : }
1547 :
1548 1 : spdk_blob_sync_md(blob, lvol_rename_cb, req);
1549 : }
1550 :
1551 : void
1552 57 : 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 57 : spdk_blob_id clone_id;
1558 57 : size_t count = 1;
1559 : int rc;
1560 :
1561 57 : assert(cb_fn != NULL);
1562 :
1563 57 : if (lvol == NULL) {
1564 0 : SPDK_ERRLOG("lvol does not exist\n");
1565 0 : cb_fn(cb_arg, -ENODEV);
1566 0 : return;
1567 : }
1568 :
1569 57 : lvs = lvol->lvol_store;
1570 :
1571 57 : if (lvol->ref_count != 0) {
1572 1 : SPDK_ERRLOG("Cannot destroy lvol %s because it is still open\n", lvol->unique_id);
1573 1 : cb_fn(cb_arg, -EBUSY);
1574 1 : return;
1575 : }
1576 :
1577 56 : req = calloc(1, sizeof(*req));
1578 56 : 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 56 : req->cb_fn = cb_fn;
1585 56 : req->cb_arg = cb_arg;
1586 56 : req->lvol = lvol;
1587 56 : bs = lvol->lvol_store->blobstore;
1588 :
1589 56 : rc = spdk_blob_get_clones(lvs->blobstore, lvol->blob_id, &clone_id, &count);
1590 56 : if (rc == 0 && count == 1) {
1591 1 : req->clone_lvol = lvs_get_lvol_by_blob_id(lvs, clone_id);
1592 55 : } 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 56 : lvol->action_in_progress = true;
1602 :
1603 56 : spdk_bs_delete_blob(bs, lvol->blob_id, lvol_delete_blob_cb, req);
1604 : }
1605 :
1606 : void
1607 84 : 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 84 : assert(cb_fn != NULL);
1612 :
1613 84 : if (lvol == NULL) {
1614 1 : SPDK_ERRLOG("lvol does not exist\n");
1615 1 : cb_fn(cb_arg, -ENODEV);
1616 1 : return;
1617 : }
1618 :
1619 83 : if (lvol->ref_count > 1) {
1620 1 : lvol->ref_count--;
1621 1 : cb_fn(cb_arg, 0);
1622 1 : return;
1623 82 : } else if (lvol->ref_count == 0) {
1624 2 : cb_fn(cb_arg, -EINVAL);
1625 2 : return;
1626 : }
1627 :
1628 80 : req = calloc(1, sizeof(*req));
1629 80 : 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 80 : req->cb_fn = cb_fn;
1636 80 : req->cb_arg = cb_arg;
1637 80 : req->lvol = lvol;
1638 :
1639 80 : lvol->action_in_progress = true;
1640 :
1641 80 : spdk_blob_close(lvol->blob, lvol_close_blob_cb, req);
1642 : }
1643 :
1644 : struct spdk_io_channel *
1645 0 : spdk_lvol_get_io_channel(struct spdk_lvol *lvol)
1646 : {
1647 0 : return spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
1648 : }
1649 :
1650 : static void
1651 4 : lvol_inflate_cb(void *cb_arg, int lvolerrno)
1652 : {
1653 4 : struct spdk_lvol_req *req = cb_arg;
1654 :
1655 4 : spdk_bs_free_io_channel(req->channel);
1656 :
1657 4 : if (lvolerrno < 0) {
1658 2 : SPDK_ERRLOG("Could not inflate lvol\n");
1659 : }
1660 :
1661 4 : req->cb_fn(req->cb_arg, lvolerrno);
1662 4 : free(req);
1663 4 : }
1664 :
1665 : void
1666 2 : 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 2 : assert(cb_fn != NULL);
1672 :
1673 2 : 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 2 : req = calloc(1, sizeof(*req));
1680 2 : 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 2 : req->cb_fn = cb_fn;
1687 2 : req->cb_arg = cb_arg;
1688 2 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
1689 2 : 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 2 : blob_id = spdk_blob_get_id(lvol->blob);
1697 2 : spdk_bs_inflate_blob(lvol->lvol_store->blobstore, req->channel, blob_id, lvol_inflate_cb,
1698 : req);
1699 : }
1700 :
1701 : void
1702 2 : 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 2 : assert(cb_fn != NULL);
1708 :
1709 2 : 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 2 : req = calloc(1, sizeof(*req));
1716 2 : 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 2 : req->cb_fn = cb_fn;
1723 2 : req->cb_arg = cb_arg;
1724 2 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
1725 2 : 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 2 : blob_id = spdk_blob_get_id(lvol->blob);
1733 2 : spdk_bs_blob_decouple_parent(lvol->lvol_store->blobstore, req->channel, blob_id,
1734 : lvol_inflate_cb, req);
1735 : }
1736 :
1737 : static void
1738 0 : lvs_grow_live_cb(void *cb_arg, int lvolerrno)
1739 : {
1740 0 : struct spdk_lvs_req *req = (struct spdk_lvs_req *)cb_arg;
1741 :
1742 0 : if (req->cb_fn) {
1743 0 : req->cb_fn(req->cb_arg, lvolerrno);
1744 : }
1745 0 : free(req);
1746 0 : return;
1747 : }
1748 :
1749 : void
1750 0 : 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 0 : req = calloc(1, sizeof(*req));
1755 0 : 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 0 : req->cb_fn = cb_fn;
1764 0 : req->cb_arg = cb_arg;
1765 0 : req->lvol_store = lvs;
1766 :
1767 0 : 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 5 : lvs_get_lvol_by_blob_id(struct spdk_lvol_store *lvs, spdk_blob_id blob_id)
1810 : {
1811 : struct spdk_lvol *lvol;
1812 :
1813 7 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
1814 7 : if (lvol->blob_id == blob_id) {
1815 5 : return lvol;
1816 : }
1817 : }
1818 0 : return NULL;
1819 : }
1820 :
1821 : static int
1822 6 : 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 6 : struct spdk_lvol_store *lvs = bs_ctx;
1827 6 : struct spdk_lvol *lvol = blob_ctx;
1828 6 : spdk_blob_id blob_id = spdk_blob_get_id(blob);
1829 :
1830 6 : if (lvs == NULL) {
1831 2 : if (lvol == NULL || lvol->lvol_store == NULL) {
1832 1 : SPDK_ERRLOG("Blob 0x%" PRIx64 ": no lvs context nor lvol context\n",
1833 : blob_id);
1834 1 : return -EINVAL;
1835 : }
1836 1 : 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 5 : if (!lvs->load_esnaps) {
1847 4 : *bs_dev = NULL;
1848 4 : return 0;
1849 : }
1850 :
1851 1 : if (lvol == NULL) {
1852 0 : 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 0 : lvol = lvs_get_lvol_by_blob_id(lvs, blob_id);
1860 0 : 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 1 : 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 93 : lvs_esnap_name_cmp(struct spdk_lvs_degraded_lvol_set *m1, struct spdk_lvs_degraded_lvol_set *m2)
1893 : {
1894 93 : if (m1->id_len == m2->id_len) {
1895 93 : 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 240 : RB_GENERATE_STATIC(degraded_lvol_sets_tree, spdk_lvs_degraded_lvol_set, node, lvs_esnap_name_cmp)
1901 :
1902 : static void
1903 38 : lvs_degraded_lvol_set_add(struct spdk_lvs_degraded_lvol_set *degraded_set, struct spdk_lvol *lvol)
1904 : {
1905 38 : assert(lvol->lvol_store->thread == spdk_get_thread());
1906 :
1907 38 : lvol->degraded_set = degraded_set;
1908 38 : TAILQ_INSERT_TAIL(°raded_set->lvols, lvol, degraded_link);
1909 38 : }
1910 :
1911 : static void
1912 13 : lvs_degraded_lvol_set_remove(struct spdk_lvs_degraded_lvol_set *degraded_set,
1913 : struct spdk_lvol *lvol)
1914 : {
1915 13 : assert(lvol->lvol_store->thread == spdk_get_thread());
1916 :
1917 13 : lvol->degraded_set = NULL;
1918 13 : 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 13 : }
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 36 : 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 36 : struct spdk_lvs_degraded_lvol_set find, *degraded_set;
1932 :
1933 36 : assert(lvs->thread == spdk_get_thread());
1934 :
1935 36 : find.esnap_id = esnap_id;
1936 36 : find.id_len = id_len;
1937 36 : degraded_set = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
1938 36 : if (degraded_set == NULL) {
1939 16 : degraded_set = calloc(1, sizeof(*degraded_set));
1940 16 : 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 16 : degraded_set->esnap_id = calloc(1, id_len);
1946 16 : 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 16 : memcpy((void *)degraded_set->esnap_id, esnap_id, id_len);
1953 16 : degraded_set->id_len = id_len;
1954 16 : degraded_set->lvol_store = lvs;
1955 16 : TAILQ_INIT(°raded_set->lvols);
1956 16 : RB_INSERT(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
1957 : }
1958 :
1959 36 : lvs_degraded_lvol_set_add(degraded_set, lvol);
1960 :
1961 36 : return 0;
1962 : }
1963 :
1964 : /*
1965 : * Remove the record of the specified lvol needing a degraded_set bdev.
1966 : */
1967 : void
1968 35 : spdk_lvs_esnap_missing_remove(struct spdk_lvol *lvol)
1969 : {
1970 35 : struct spdk_lvol_store *lvs = lvol->lvol_store;
1971 35 : struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
1972 :
1973 35 : assert(lvs->thread == spdk_get_thread());
1974 :
1975 35 : if (degraded_set == NULL) {
1976 24 : return;
1977 : }
1978 :
1979 11 : lvs_degraded_lvol_set_remove(degraded_set, lvol);
1980 :
1981 11 : if (!TAILQ_EMPTY(°raded_set->lvols)) {
1982 1 : return;
1983 : }
1984 :
1985 10 : RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
1986 :
1987 10 : free((char *)degraded_set->esnap_id);
1988 10 : 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 25 : lvs_esnap_hotplug_done(void *cb_arg, int bserrno)
1999 : {
2000 25 : struct lvs_esnap_hotplug_req *req = cb_arg;
2001 25 : struct spdk_lvol *lvol = req->lvol;
2002 25 : struct spdk_lvol_store *lvs = lvol->lvol_store;
2003 :
2004 25 : 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 25 : req->cb_fn(req->cb_arg, lvol, bserrno);
2009 25 : free(req);
2010 25 : }
2011 :
2012 : static void
2013 15 : 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 15 : struct spdk_lvol_store *lvs = degraded_set->lvol_store;
2017 : struct spdk_lvol *lvol, *tmp, *last_missing;
2018 15 : struct spdk_bs_dev *bs_dev;
2019 15 : const void *esnap_id = degraded_set->esnap_id;
2020 15 : uint32_t id_len = degraded_set->id_len;
2021 : struct lvs_esnap_hotplug_req *req;
2022 : int rc;
2023 :
2024 15 : 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 15 : last_missing = TAILQ_LAST(°raded_set->lvols, degraded_lvols);
2039 :
2040 28 : TAILQ_FOREACH_SAFE(lvol, °raded_set->lvols, degraded_link, tmp) {
2041 28 : req = calloc(1, sizeof(*req));
2042 28 : 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 28 : TAILQ_REMOVE(°raded_set->lvols, lvol, degraded_link);
2057 28 : lvol->degraded_set = NULL;
2058 :
2059 28 : bs_dev = NULL;
2060 28 : rc = lvs->esnap_bs_dev_create(lvs, lvol, lvol->blob, esnap_id, id_len, &bs_dev);
2061 28 : if (rc != 0) {
2062 3 : SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: error %d\n",
2063 : lvol->unique_id, rc);
2064 3 : lvol->degraded_set = degraded_set;
2065 3 : TAILQ_INSERT_TAIL(°raded_set->lvols, lvol, degraded_link);
2066 3 : cb_fn(cb_arg, lvol, rc);
2067 3 : free(req);
2068 3 : goto next;
2069 : }
2070 :
2071 25 : req->lvol = lvol;
2072 25 : req->cb_fn = cb_fn;
2073 25 : req->cb_arg = cb_arg;
2074 25 : spdk_blob_set_esnap_bs_dev(lvol->blob, bs_dev, lvs_esnap_hotplug_done, req);
2075 :
2076 28 : next:
2077 28 : 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 15 : break;
2083 : }
2084 : }
2085 :
2086 15 : if (TAILQ_EMPTY(°raded_set->lvols)) {
2087 6 : RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
2088 6 : free((void *)degraded_set->esnap_id);
2089 6 : free(degraded_set);
2090 : }
2091 15 : }
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 15 : 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 15 : struct spdk_lvs_degraded_lvol_set find = { 0 };
2103 : struct spdk_lvol_store *lvs;
2104 15 : struct spdk_thread *thread = spdk_get_thread();
2105 15 : bool ret = false;
2106 :
2107 15 : find.esnap_id = esnap_id;
2108 15 : find.id_len = id_len;
2109 :
2110 15 : pthread_mutex_lock(&g_lvol_stores_mutex);
2111 30 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
2112 15 : 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 15 : found = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
2127 15 : if (found == NULL) {
2128 0 : continue;
2129 : }
2130 :
2131 15 : ret = true;
2132 15 : lvs_esnap_degraded_hotplug(found, cb_fn, cb_arg);
2133 : }
2134 15 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2135 :
2136 15 : return ret;
2137 : }
2138 :
2139 : int
2140 4 : spdk_lvol_iter_immediate_clones(struct spdk_lvol *lvol, spdk_lvol_iter_cb cb_fn, void *cb_arg)
2141 : {
2142 4 : struct spdk_lvol_store *lvs = lvol->lvol_store;
2143 4 : struct spdk_blob_store *bs = lvs->blobstore;
2144 : struct spdk_lvol *clone;
2145 : spdk_blob_id *ids;
2146 4 : size_t id_cnt = 0;
2147 : size_t i;
2148 : int rc;
2149 :
2150 4 : rc = spdk_blob_get_clones(bs, lvol->blob_id, NULL, &id_cnt);
2151 4 : if (rc != -ENOMEM) {
2152 : /* -ENOMEM says id_cnt is valid, no other errors should be returned. */
2153 1 : assert(rc == 0);
2154 1 : return rc;
2155 : }
2156 :
2157 3 : ids = calloc(id_cnt, sizeof(*ids));
2158 3 : 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 3 : rc = spdk_blob_get_clones(bs, lvol->blob_id, ids, &id_cnt);
2164 3 : 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 6 : for (i = 0; i < id_cnt; i++) {
2171 4 : clone = lvs_get_lvol_by_blob_id(lvs, ids[i]);
2172 4 : 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 4 : rc = cb_fn(cb_arg, clone);
2178 4 : if (rc != 0) {
2179 1 : 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 1 : break;
2183 : }
2184 : }
2185 :
2186 3 : free(ids);
2187 3 : return rc;
2188 : }
2189 :
2190 : struct spdk_lvol *
2191 2 : spdk_lvol_get_by_uuid(const struct spdk_uuid *uuid)
2192 : {
2193 : struct spdk_lvol_store *lvs;
2194 : struct spdk_lvol *lvol;
2195 :
2196 2 : pthread_mutex_lock(&g_lvol_stores_mutex);
2197 :
2198 2 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
2199 2 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
2200 2 : if (spdk_uuid_compare(uuid, &lvol->uuid) == 0) {
2201 2 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2202 2 : 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 12 : 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 12 : pthread_mutex_lock(&g_lvol_stores_mutex);
2218 :
2219 17 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
2220 13 : if (strcmp(lvs_name, lvs->name) != 0) {
2221 3 : continue;
2222 : }
2223 15 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
2224 13 : if (strcmp(lvol_name, lvol->name) == 0) {
2225 8 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2226 8 : return lvol;
2227 : }
2228 : }
2229 : }
2230 :
2231 4 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2232 4 : return NULL;
2233 : }
2234 :
2235 : bool
2236 0 : spdk_lvol_is_degraded(const struct spdk_lvol *lvol)
2237 : {
2238 0 : struct spdk_blob *blob = lvol->blob;
2239 :
2240 0 : if (blob == NULL) {
2241 0 : return true;
2242 : }
2243 0 : return spdk_blob_is_degraded(blob);
2244 : }
2245 :
2246 : static void
2247 1 : lvol_shallow_copy_cb(void *cb_arg, int lvolerrno)
2248 : {
2249 1 : struct spdk_lvol_copy_req *req = cb_arg;
2250 1 : struct spdk_lvol *lvol = req->lvol;
2251 :
2252 1 : spdk_bs_free_io_channel(req->channel);
2253 :
2254 1 : 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 1 : req->cb_fn(req->cb_arg, lvolerrno);
2259 1 : free(req);
2260 1 : }
2261 :
2262 : int
2263 3 : 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 3 : assert(cb_fn != NULL);
2272 :
2273 3 : if (lvol == NULL) {
2274 1 : SPDK_ERRLOG("lvol must not be NULL\n");
2275 1 : return -EINVAL;
2276 : }
2277 :
2278 2 : assert(lvol->lvol_store->thread == spdk_get_thread());
2279 :
2280 2 : if (ext_dev == NULL) {
2281 1 : SPDK_ERRLOG("lvol %s shallow copy, ext_dev must not be NULL\n", lvol->unique_id);
2282 1 : return -EINVAL;
2283 : }
2284 :
2285 1 : req = calloc(1, sizeof(*req));
2286 1 : 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 1 : req->lvol = lvol;
2292 1 : req->cb_fn = cb_fn;
2293 1 : req->cb_arg = cb_arg;
2294 1 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
2295 1 : 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 1 : blob_id = spdk_blob_get_id(lvol->blob);
2302 :
2303 1 : 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 1 : 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 1 : return rc;
2313 : }
2314 :
2315 : static void
2316 1 : lvol_set_parent_cb(void *cb_arg, int lvolerrno)
2317 : {
2318 1 : struct spdk_lvol_req *req = cb_arg;
2319 :
2320 1 : if (lvolerrno < 0) {
2321 0 : SPDK_ERRLOG("could not set parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
2322 : }
2323 :
2324 1 : req->cb_fn(req->cb_arg, lvolerrno);
2325 1 : free(req);
2326 1 : }
2327 :
2328 : void
2329 3 : 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 3 : assert(cb_fn != NULL);
2336 :
2337 3 : if (lvol == NULL) {
2338 1 : SPDK_ERRLOG("lvol must not be NULL\n");
2339 1 : cb_fn(cb_arg, -EINVAL);
2340 1 : return;
2341 : }
2342 :
2343 2 : if (snapshot == NULL) {
2344 1 : SPDK_ERRLOG("snapshot must not be NULL\n");
2345 1 : cb_fn(cb_arg, -EINVAL);
2346 1 : return;
2347 : }
2348 :
2349 1 : req = calloc(1, sizeof(*req));
2350 1 : 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 1 : req->lvol = lvol;
2357 1 : req->cb_fn = cb_fn;
2358 1 : req->cb_arg = cb_arg;
2359 :
2360 1 : blob_id = spdk_blob_get_id(lvol->blob);
2361 1 : snapshot_id = spdk_blob_get_id(snapshot->blob);
2362 :
2363 1 : 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 1 : lvol_set_external_parent_cb(void *cb_arg, int lvolerrno)
2369 : {
2370 1 : struct spdk_lvol_bs_dev_req *req = cb_arg;
2371 :
2372 1 : if (lvolerrno < 0) {
2373 0 : SPDK_ERRLOG("could not set external parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
2374 0 : req->bs_dev->destroy(req->bs_dev);
2375 : }
2376 :
2377 1 : req->cb_fn(req->cb_arg, lvolerrno);
2378 1 : free(req);
2379 1 : }
2380 :
2381 : void
2382 4 : 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 4 : struct spdk_bs_dev *bs_dev;
2387 : spdk_blob_id blob_id;
2388 : int rc;
2389 :
2390 4 : assert(cb_fn != NULL);
2391 :
2392 4 : if (lvol == NULL) {
2393 1 : SPDK_ERRLOG("lvol must not be NULL\n");
2394 1 : cb_fn(cb_arg, -EINVAL);
2395 1 : return;
2396 : }
2397 :
2398 3 : if (esnap_id == NULL) {
2399 1 : SPDK_ERRLOG("snapshot must not be NULL\n");
2400 1 : cb_fn(cb_arg, -EINVAL);
2401 1 : return;
2402 : }
2403 :
2404 2 : if (esnap_id_len == sizeof(lvol->uuid_str) &&
2405 2 : memcmp(esnap_id, lvol->uuid_str, esnap_id_len) == 0) {
2406 1 : SPDK_ERRLOG("lvol %s and esnap have the same UUID\n", lvol->name);
2407 1 : cb_fn(cb_arg, -EINVAL);
2408 1 : return;
2409 : }
2410 :
2411 1 : rc = lvs_esnap_bs_dev_create(lvol->lvol_store, lvol, lvol->blob, esnap_id, esnap_id_len, &bs_dev);
2412 1 : if (rc < 0) {
2413 0 : cb_fn(cb_arg, rc);
2414 0 : return;
2415 : }
2416 :
2417 1 : req = calloc(1, sizeof(*req));
2418 1 : 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 1 : req->lvol = lvol;
2425 1 : req->bs_dev = bs_dev;
2426 1 : req->cb_fn = cb_fn;
2427 1 : req->cb_arg = cb_arg;
2428 :
2429 1 : blob_id = spdk_blob_get_id(lvol->blob);
2430 :
2431 1 : 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 : }
|