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