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