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 : 2178 : 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 : 457 : add_lvs_to_list(struct spdk_lvol_store *lvs)
45 : : {
46 : : struct spdk_lvol_store *tmp;
47 : 457 : bool name_conflict = false;
48 : :
49 [ # # ]: 457 : pthread_mutex_lock(&g_lvol_stores_mutex);
50 [ + + # # : 587 : TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
# # # # ]
51 [ + + - + : 137 : if (!strncmp(lvs->name, tmp->name, SPDK_LVS_NAME_MAX)) {
+ + # # #
# ]
52 : 7 : name_conflict = true;
53 : 7 : break;
54 : : }
55 : 0 : }
56 [ + + # # ]: 457 : if (!name_conflict) {
57 [ # # # # ]: 450 : lvs->on_list = true;
58 [ # # # # : 450 : TAILQ_INSERT_TAIL(&g_lvol_stores, lvs, link);
# # # # #
# # # # #
# # # # #
# # # #
# ]
59 : 0 : }
60 [ # # ]: 457 : pthread_mutex_unlock(&g_lvol_stores_mutex);
61 : :
62 [ + + ]: 457 : return name_conflict ? -1 : 0;
63 : : }
64 : :
65 : : static struct spdk_lvol_store *
66 : 5857 : lvs_alloc(void)
67 : : {
68 : : struct spdk_lvol_store *lvs;
69 : :
70 : 5857 : lvs = calloc(1, sizeof(*lvs));
71 [ + + ]: 5857 : if (lvs == NULL) {
72 : 0 : return NULL;
73 : : }
74 : :
75 [ + - + - : 5857 : TAILQ_INIT(&lvs->lvols);
+ - + - +
- + - + -
+ - ]
76 [ + - + - : 5857 : TAILQ_INIT(&lvs->pending_lvols);
+ - + - +
- + - + -
+ - ]
77 [ + - + - : 5857 : TAILQ_INIT(&lvs->retry_open_lvols);
+ - + - +
- + - + -
+ - ]
78 : :
79 [ + - + - ]: 5857 : lvs->load_esnaps = false;
80 [ + - + - : 5857 : RB_INIT(&lvs->degraded_lvol_sets_tree);
+ - ]
81 [ + - + - ]: 5857 : lvs->thread = spdk_get_thread();
82 : :
83 : 5857 : return lvs;
84 : 47 : }
85 : :
86 : : static void
87 : 5857 : lvs_free(struct spdk_lvol_store *lvs)
88 : : {
89 [ + + ]: 5857 : pthread_mutex_lock(&g_lvol_stores_mutex);
90 [ + + + + : 5857 : if (lvs->on_list) {
+ - + - ]
91 [ + + # # : 450 : TAILQ_REMOVE(&g_lvol_stores, lvs, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
92 : 0 : }
93 [ + + ]: 5857 : pthread_mutex_unlock(&g_lvol_stores_mutex);
94 : :
95 [ + + + - : 5857 : assert(RB_EMPTY(&lvs->degraded_lvol_sets_tree));
+ - + - #
# ]
96 : :
97 : 5857 : free(lvs);
98 : 5857 : }
99 : :
100 : : static struct spdk_lvol *
101 : 789 : 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 : 789 : lvol = calloc(1, sizeof(*lvol));
107 [ - + ]: 789 : if (lvol == NULL) {
108 : 0 : return NULL;
109 : : }
110 : :
111 [ # # # # ]: 789 : lvol->lvol_store = lvs;
112 [ # # # # ]: 789 : lvol->clear_method = (enum blob_clear_method)clear_method;
113 [ - + ]: 789 : snprintf(lvol->name, sizeof(lvol->name), "%s", name);
114 [ # # ]: 789 : spdk_uuid_generate(&lvol->uuid);
115 [ # # # # ]: 789 : spdk_uuid_fmt_lower(lvol->uuid_str, sizeof(lvol->uuid_str), &lvol->uuid);
116 [ # # # # ]: 789 : spdk_uuid_fmt_lower(lvol->unique_id, sizeof(lvol->uuid_str), &lvol->uuid);
117 : :
118 [ # # # # : 789 : TAILQ_INSERT_TAIL(&lvs->pending_lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
119 : :
120 : 789 : return lvol;
121 : 0 : }
122 : :
123 : : static void
124 : 910 : lvol_free(struct spdk_lvol *lvol)
125 : : {
126 : 910 : free(lvol);
127 : 910 : }
128 : :
129 : : static void
130 : 118 : lvol_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
131 : : {
132 : 118 : struct spdk_lvol_with_handle_req *req = cb_arg;
133 [ # # # # ]: 118 : struct spdk_lvol *lvol = req->lvol;
134 : :
135 [ + + ]: 118 : if (lvolerrno != 0) {
136 [ - + - + : 9 : SPDK_INFOLOG(lvol, "Failed to open lvol %s\n", lvol->unique_id);
# # # # ]
137 : 9 : goto end;
138 : : }
139 : :
140 [ # # # # ]: 109 : lvol->ref_count++;
141 [ # # # # ]: 109 : lvol->blob = blob;
142 : 118 : end:
143 [ # # # # : 118 : req->cb_fn(req->cb_arg, lvol, lvolerrno);
# # # # #
# # # ]
144 : 118 : free(req);
145 : 118 : }
146 : :
147 : : void
148 : 121 : 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 : 103 : struct spdk_blob_open_opts opts;
152 : :
153 [ - + # # ]: 121 : assert(cb_fn != NULL);
154 : :
155 [ - + ]: 121 : 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 [ - + - + : 121 : 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 [ + + # # : 121 : if (lvol->ref_count > 0) {
# # ]
168 [ # # # # ]: 3 : lvol->ref_count++;
169 [ # # # # ]: 3 : cb_fn(cb_arg, lvol, 0);
170 : 3 : return;
171 : : }
172 : :
173 : 118 : req = calloc(1, sizeof(*req));
174 [ - + ]: 118 : 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 [ # # # # ]: 118 : req->cb_fn = cb_fn;
181 [ # # # # ]: 118 : req->cb_arg = cb_arg;
182 [ # # # # ]: 118 : req->lvol = lvol;
183 : :
184 : 118 : spdk_blob_open_opts_init(&opts, sizeof(opts));
185 [ # # # # ]: 118 : opts.clear_method = lvol->clear_method;
186 : :
187 [ # # # # : 118 : spdk_bs_open_blob_ext(lvol->lvol_store->blobstore, lvol->blob_id, &opts, lvol_open_cb, req);
# # # # #
# # # ]
188 : 0 : }
189 : :
190 : : static void
191 : 24 : bs_unload_with_error_cb(void *cb_arg, int lvolerrno)
192 : : {
193 : 24 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
194 : :
195 [ # # # # : 24 : req->cb_fn(req->cb_arg, NULL, req->lvserrno);
# # # # #
# # # # #
# # ]
196 : 24 : free(req);
197 : 24 : }
198 : :
199 : : static void
200 : 332 : load_next_lvol(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
201 : : {
202 : 332 : struct spdk_lvs_with_handle_req *req = cb_arg;
203 [ # # # # ]: 332 : struct spdk_lvol_store *lvs = req->lvol_store;
204 [ # # # # ]: 332 : struct spdk_blob_store *bs = lvs->blobstore;
205 : : struct spdk_lvol *lvol, *tmp;
206 : : spdk_blob_id blob_id;
207 : 280 : const char *attr;
208 : 280 : size_t value_len;
209 : : int rc;
210 : :
211 [ + + ]: 332 : if (lvolerrno == -ENOENT) {
212 : : /* Finished iterating */
213 [ + + # # : 98 : if (req->lvserrno == 0) {
# # ]
214 [ # # # # ]: 92 : lvs->load_esnaps = true;
215 [ # # # # : 92 : req->cb_fn(req->cb_arg, lvs, req->lvserrno);
# # # # #
# # # # #
# # ]
216 : 92 : free(req);
217 : 0 : } else {
218 [ + + # # : 18 : TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
219 [ + + # # : 12 : TAILQ_REMOVE(&lvs->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
220 : 12 : lvol_free(lvol);
221 : 0 : }
222 : 6 : lvs_free(lvs);
223 : 6 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
224 : : }
225 : 115 : return;
226 [ + + ]: 234 : } else if (lvolerrno < 0) {
227 : 6 : SPDK_ERRLOG("Failed to fetch blobs list\n");
228 [ # # # # ]: 6 : req->lvserrno = lvolerrno;
229 : 6 : goto invalid;
230 : : }
231 : :
232 : 228 : blob_id = spdk_blob_get_id(blob);
233 : :
234 [ + + # # : 228 : if (blob_id == lvs->super_blob_id) {
# # ]
235 [ - + - + : 98 : SPDK_INFOLOG(lvol, "found superblob %"PRIu64"\n", (uint64_t)blob_id);
# # ]
236 : 98 : spdk_bs_iter_next(bs, blob, load_next_lvol, req);
237 : 98 : return;
238 : : }
239 : :
240 : 130 : lvol = calloc(1, sizeof(*lvol));
241 [ - + ]: 130 : 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 [ # # # # ]: 130 : lvol->blob_id = blob_id;
252 [ # # # # ]: 130 : lvol->lvol_store = lvs;
253 : :
254 : 130 : rc = spdk_blob_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len);
255 [ + - + - : 260 : if (rc != 0 || value_len != SPDK_UUID_STRING_LEN || attr[SPDK_UUID_STRING_LEN - 1] != '\0' ||
+ - - + #
# # # ]
256 [ # # ]: 130 : 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 [ # # # # ]: 130 : spdk_uuid_fmt_lower(lvol->uuid_str, sizeof(lvol->uuid_str), &lvol->uuid);
261 : :
262 [ + - # # ]: 130 : if (!spdk_uuid_is_null(&lvol->uuid)) {
263 [ # # # # ]: 130 : snprintf(lvol->unique_id, sizeof(lvol->unique_id), "%s", lvol->uuid_str);
264 : 0 : } 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 : 130 : rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&attr, &value_len);
272 [ + - - + ]: 130 : 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 [ # # ]: 130 : snprintf(lvol->name, sizeof(lvol->name), "%s", attr);
280 : :
281 [ # # # # : 130 : TAILQ_INSERT_TAIL(&lvs->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
282 : :
283 [ # # # # ]: 130 : lvs->lvol_count++;
284 : :
285 [ + + + - : 130 : SPDK_INFOLOG(lvol, "added lvol %s (%s)\n", lvol->unique_id, lvol->uuid_str);
# # # # #
# ]
286 : :
287 : 136 : invalid:
288 : 136 : spdk_bs_iter_next(bs, blob, load_next_lvol, req);
289 : 0 : }
290 : :
291 : : static void
292 : 101 : close_super_cb(void *cb_arg, int lvolerrno)
293 : : {
294 : 101 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
295 [ # # # # ]: 101 : struct spdk_lvol_store *lvs = req->lvol_store;
296 [ # # # # ]: 101 : struct spdk_blob_store *bs = lvs->blobstore;
297 : :
298 [ + + ]: 101 : if (lvolerrno != 0) {
299 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Could not close super blob\n");
# # ]
300 : 3 : lvs_free(lvs);
301 [ # # # # ]: 3 : req->lvserrno = -ENODEV;
302 : 3 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
303 : 3 : return;
304 : : }
305 : :
306 : : /* Start loading lvols */
307 [ # # # # ]: 98 : spdk_bs_iter_first(lvs->blobstore, load_next_lvol, req);
308 : 0 : }
309 : :
310 : : static void
311 : 9 : close_super_blob_with_error_cb(void *cb_arg, int lvolerrno)
312 : : {
313 : 9 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
314 [ # # # # ]: 9 : struct spdk_lvol_store *lvs = req->lvol_store;
315 [ # # # # ]: 9 : struct spdk_blob_store *bs = lvs->blobstore;
316 : :
317 : 9 : lvs_free(lvs);
318 : :
319 : 9 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
320 : 9 : }
321 : :
322 : : static void
323 : 113 : lvs_read_uuid(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
324 : : {
325 : 113 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
326 [ # # # # ]: 113 : struct spdk_lvol_store *lvs = req->lvol_store;
327 [ # # # # ]: 113 : struct spdk_blob_store *bs = lvs->blobstore;
328 : 96 : const char *attr;
329 : 96 : size_t value_len;
330 : : int rc;
331 : :
332 [ + + ]: 113 : if (lvolerrno != 0) {
333 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Could not open super blob\n");
# # ]
334 : 3 : lvs_free(lvs);
335 [ # # # # ]: 3 : req->lvserrno = -ENODEV;
336 : 3 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
337 : 3 : return;
338 : : }
339 : :
340 : 110 : rc = spdk_blob_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len);
341 [ + + + - : 110 : if (rc != 0 || value_len != SPDK_UUID_STRING_LEN || attr[SPDK_UUID_STRING_LEN - 1] != '\0') {
- + # # #
# ]
342 [ - + - + : 3 : SPDK_INFOLOG(lvol, "degraded_set or incorrect UUID\n");
# # ]
343 [ # # # # ]: 3 : req->lvserrno = -EINVAL;
344 : 3 : spdk_blob_close(blob, close_super_blob_with_error_cb, req);
345 : 3 : return;
346 : : }
347 : :
348 [ - + # # ]: 107 : 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 : 107 : rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&attr, &value_len);
356 [ + + - + ]: 107 : if (rc != 0 || value_len > SPDK_LVS_NAME_MAX) {
357 [ - + - + : 3 : SPDK_INFOLOG(lvol, "degraded_set or invalid name\n");
# # ]
358 [ # # # # ]: 3 : req->lvserrno = -EINVAL;
359 : 3 : spdk_blob_close(blob, close_super_blob_with_error_cb, req);
360 : 3 : return;
361 : : }
362 : :
363 [ - + ]: 104 : snprintf(lvs->name, sizeof(lvs->name), "%s", attr);
364 : :
365 : 104 : rc = add_lvs_to_list(lvs);
366 [ + + ]: 104 : if (rc) {
367 [ - + - + : 3 : SPDK_INFOLOG(lvol, "lvolstore with name %s already exists\n", lvs->name);
# # # # ]
368 [ # # # # ]: 3 : req->lvserrno = -EEXIST;
369 : 3 : spdk_blob_close(blob, close_super_blob_with_error_cb, req);
370 : 3 : return;
371 : : }
372 : :
373 [ # # # # ]: 101 : lvs->super_blob_id = spdk_blob_get_id(blob);
374 : :
375 : 101 : spdk_blob_close(blob, close_super_cb, req);
376 : 0 : }
377 : :
378 : : static void
379 : 116 : lvs_open_super(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
380 : : {
381 : 116 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
382 [ # # # # ]: 116 : struct spdk_lvol_store *lvs = req->lvol_store;
383 [ # # # # ]: 116 : struct spdk_blob_store *bs = lvs->blobstore;
384 : :
385 [ + + ]: 116 : if (lvolerrno != 0) {
386 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Super blob not found\n");
# # ]
387 : 3 : lvs_free(lvs);
388 [ # # # # ]: 3 : req->lvserrno = -ENODEV;
389 : 3 : spdk_bs_unload(bs, bs_unload_with_error_cb, req);
390 : 3 : return;
391 : : }
392 : :
393 : 113 : spdk_bs_open_blob(bs, blobid, lvs_read_uuid, req);
394 : 0 : }
395 : :
396 : : static void
397 : 5495 : lvs_load_cb(void *cb_arg, struct spdk_blob_store *bs, int lvolerrno)
398 : : {
399 : 5495 : struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
400 [ + - + - ]: 5495 : struct spdk_lvol_store *lvs = req->lvol_store;
401 : :
402 [ + + ]: 5495 : if (lvolerrno != 0) {
403 [ + - + - : 5379 : req->cb_fn(req->cb_arg, NULL, lvolerrno);
- + - + +
- + - ]
404 : 5379 : lvs_free(lvs);
405 : 5379 : free(req);
406 : 5379 : return;
407 : : }
408 : :
409 [ # # # # ]: 116 : lvs->blobstore = bs;
410 [ # # # # : 116 : lvs->bs_dev = req->bs_dev;
# # # # ]
411 : :
412 : 116 : spdk_bs_get_super(bs, lvs_open_super, req);
413 : 47 : }
414 : :
415 : : static void
416 : 5854 : lvs_bs_opts_init(struct spdk_bs_opts *opts)
417 : : {
418 : 5854 : spdk_bs_opts_init(opts, sizeof(*opts));
419 [ + - + - ]: 5854 : opts->max_channel_ops = SPDK_LVOL_BLOB_OPTS_CHANNEL_OPS;
420 : 5854 : }
421 : :
422 : : static void
423 : 5498 : 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 : 5498 : struct spdk_bs_opts bs_opts = {};
428 : 2710 : struct spdk_lvs_opts lvs_opts;
429 : :
430 [ + + # # ]: 5498 : assert(cb_fn != NULL);
431 : :
432 [ + + ]: 5498 : 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 : 5498 : spdk_lvs_opts_init(&lvs_opts);
439 [ + + ]: 5498 : if (_lvs_opts != NULL) {
440 [ + + ]: 5456 : if (lvs_opts_copy(_lvs_opts, &lvs_opts) != 0) {
441 : 3 : SPDK_ERRLOG("Invalid options\n");
442 [ # # # # ]: 3 : cb_fn(cb_arg, NULL, -EINVAL);
443 : 3 : return;
444 : : }
445 : 47 : }
446 : :
447 : 5495 : req = calloc(1, sizeof(*req));
448 [ + + ]: 5495 : 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 [ + - + - ]: 5495 : req->lvol_store = lvs_alloc();
455 [ + + + - : 5495 : 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 [ + - + - ]: 5495 : req->cb_fn = cb_fn;
462 [ + - + - ]: 5495 : req->cb_arg = cb_arg;
463 [ + - + - ]: 5495 : req->bs_dev = bs_dev;
464 : :
465 : 5495 : lvs_bs_opts_init(&bs_opts);
466 [ - + ]: 5495 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "LVOLSTORE");
467 : :
468 [ + + ]: 5495 : if (lvs_opts.esnap_bs_dev_create != NULL) {
469 [ + - + - : 5453 : req->lvol_store->esnap_bs_dev_create = lvs_opts.esnap_bs_dev_create;
+ - + - ]
470 : 5453 : bs_opts.esnap_bs_dev_create = lvs_esnap_bs_dev_create;
471 [ + - + - ]: 5453 : bs_opts.esnap_ctx = req->lvol_store;
472 : 47 : }
473 : :
474 : 5495 : spdk_bs_load(bs_dev, &bs_opts, lvs_load_cb, req);
475 : 47 : }
476 : :
477 : : void
478 : 42 : spdk_lvs_load(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
479 : : {
480 : 42 : lvs_load(bs_dev, NULL, cb_fn, cb_arg);
481 : 42 : }
482 : :
483 : : void
484 : 5456 : 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 : 5456 : lvs_load(bs_dev, opts, cb_fn, cb_arg);
488 : 5456 : }
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 : 349 : super_create_close_cb(void *cb_arg, int lvolerrno)
506 : : {
507 : 349 : struct spdk_lvs_with_handle_req *req = cb_arg;
508 [ # # # # ]: 349 : struct spdk_lvol_store *lvs = req->lvol_store;
509 : :
510 [ - + ]: 349 : 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 [ # # # # : 349 : req->cb_fn(req->cb_arg, lvs, lvolerrno);
# # # # #
# # # ]
517 : 349 : free(req);
518 : 0 : }
519 : :
520 : : static void
521 : 349 : super_blob_set_cb(void *cb_arg, int lvolerrno)
522 : : {
523 : 349 : struct spdk_lvs_with_handle_req *req = cb_arg;
524 [ # # # # ]: 349 : struct spdk_lvol_store *lvs = req->lvol_store;
525 [ # # # # ]: 349 : struct spdk_blob *blob = lvs->super_blob;
526 : :
527 [ - + ]: 349 : 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 : 349 : spdk_blob_close(blob, super_create_close_cb, req);
534 : 0 : }
535 : :
536 : : static void
537 : 349 : super_blob_init_cb(void *cb_arg, int lvolerrno)
538 : : {
539 : 349 : struct spdk_lvs_with_handle_req *req = cb_arg;
540 [ # # # # ]: 349 : struct spdk_lvol_store *lvs = req->lvol_store;
541 [ # # # # ]: 349 : struct spdk_blob *blob = lvs->super_blob;
542 : 263 : char uuid[SPDK_UUID_STRING_LEN];
543 : :
544 [ - + ]: 349 : 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 [ # # ]: 349 : spdk_uuid_fmt_lower(uuid, sizeof(uuid), &lvs->uuid);
551 : :
552 : 349 : spdk_blob_set_xattr(blob, "uuid", uuid, sizeof(uuid));
553 [ - + # # : 349 : spdk_blob_set_xattr(blob, "name", lvs->name, strnlen(lvs->name, SPDK_LVS_NAME_MAX) + 1);
# # ]
554 : 349 : spdk_blob_sync_md(blob, super_blob_set_cb, req);
555 : 0 : }
556 : :
557 : : static void
558 : 349 : super_blob_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
559 : : {
560 : 349 : struct spdk_lvs_with_handle_req *req = cb_arg;
561 [ # # # # ]: 349 : struct spdk_lvol_store *lvs = req->lvol_store;
562 : :
563 [ - + ]: 349 : 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 [ # # # # ]: 349 : lvs->super_blob = blob;
570 [ # # # # ]: 349 : lvs->super_blob_id = spdk_blob_get_id(blob);
571 : :
572 [ # # # # : 349 : spdk_bs_set_super(lvs->blobstore, lvs->super_blob_id, super_blob_init_cb, req);
# # # # ]
573 : 0 : }
574 : :
575 : : static void
576 : 349 : super_blob_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
577 : : {
578 : 349 : struct spdk_lvs_with_handle_req *req = cb_arg;
579 [ # # # # ]: 349 : struct spdk_lvol_store *lvs = req->lvol_store;
580 : : struct spdk_blob_store *bs;
581 : :
582 [ - + ]: 349 : 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 [ # # # # : 349 : bs = req->lvol_store->blobstore;
# # # # ]
589 : :
590 : 349 : spdk_bs_open_blob(bs, blobid, super_blob_create_open_cb, req);
591 : 0 : }
592 : :
593 : : static void
594 : 349 : lvs_init_cb(void *cb_arg, struct spdk_blob_store *bs, int lvserrno)
595 : : {
596 : 349 : struct spdk_lvs_with_handle_req *lvs_req = cb_arg;
597 [ # # # # ]: 349 : struct spdk_lvol_store *lvs = lvs_req->lvol_store;
598 : :
599 [ - + ]: 349 : 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 [ - + # # ]: 349 : assert(bs != NULL);
609 [ # # # # ]: 349 : lvs->blobstore = bs;
610 : :
611 [ - + - + : 349 : SPDK_INFOLOG(lvol, "Lvol store initialized\n");
# # ]
612 : :
613 : : /* create super blob */
614 [ # # # # ]: 349 : spdk_bs_create_blob(lvs->blobstore, super_blob_create_cb, lvs_req);
615 : 0 : }
616 : :
617 : : void
618 : 11666 : spdk_lvs_opts_init(struct spdk_lvs_opts *o)
619 : : {
620 [ + + ]: 11666 : memset(o, 0, sizeof(*o));
621 [ + - + - ]: 11666 : o->cluster_sz = SPDK_LVS_OPTS_CLUSTER_SZ;
622 [ + - + - ]: 11666 : o->clear_method = LVS_CLEAR_WITH_UNMAP;
623 [ + - + - ]: 11666 : o->num_md_pages_per_cluster_ratio = 100;
624 [ + - + - ]: 11666 : o->opts_size = sizeof(*o);
625 : 11666 : }
626 : :
627 : : static inline int
628 : 5817 : lvs_opts_copy(const struct spdk_lvs_opts *src, struct spdk_lvs_opts *dst)
629 : : {
630 [ + + + - : 5817 : if (src->opts_size == 0) {
+ - ]
631 : 3 : SPDK_ERRLOG("opts_size should not be zero value\n");
632 : 3 : 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 [ + - + - : 5814 : SET_FIELD(cluster_sz);
- + + - +
- + - +
- ]
643 [ + - + - : 5814 : SET_FIELD(clear_method);
- + + - +
- + - +
- ]
644 [ + - + - : 5814 : if (FIELD_OK(name)) {
- + ]
645 [ + + + + : 5814 : memcpy(&dst->name, &src->name, sizeof(dst->name));
+ - + - ]
646 : 47 : }
647 [ + - + - : 5814 : SET_FIELD(num_md_pages_per_cluster_ratio);
- + + - +
- + - +
- ]
648 [ + - + - : 5814 : SET_FIELD(opts_size);
- + + - +
- + - +
- ]
649 [ + - + - : 5814 : SET_FIELD(esnap_bs_dev_create);
- + + - +
- + - +
- ]
650 [ + - + - : 5814 : SET_FIELD(md_page_size);
- + + - +
- + - +
- ]
651 : :
652 [ + - + - : 5814 : 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 : 5814 : return 0;
662 : 47 : }
663 : :
664 : : static void
665 : 359 : setup_lvs_opts(struct spdk_bs_opts *bs_opts, struct spdk_lvs_opts *o, uint32_t total_clusters,
666 : : void *esnap_ctx)
667 : : {
668 [ - + # # ]: 359 : assert(o != NULL);
669 : 359 : lvs_bs_opts_init(bs_opts);
670 [ # # # # : 359 : bs_opts->cluster_sz = o->cluster_sz;
# # # # ]
671 [ # # # # : 359 : bs_opts->clear_method = (enum bs_clear_method)o->clear_method;
# # # # ]
672 [ # # # # : 359 : bs_opts->num_md_pages = (o->num_md_pages_per_cluster_ratio * total_clusters) / 100;
# # # # #
# ]
673 [ # # # # : 359 : bs_opts->md_page_size = o->md_page_size;
# # # # ]
674 [ # # # # : 359 : bs_opts->esnap_bs_dev_create = o->esnap_bs_dev_create;
# # # # ]
675 [ # # # # ]: 359 : bs_opts->esnap_ctx = esnap_ctx;
676 [ - + # # ]: 359 : snprintf(bs_opts->bstype.bstype, sizeof(bs_opts->bstype.bstype), "LVOLSTORE");
677 : 359 : }
678 : :
679 : : int
680 : 364 : 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 : 364 : struct spdk_bs_opts opts = {};
686 : 278 : struct spdk_lvs_opts lvs_opts;
687 : : uint32_t total_clusters;
688 : : int rc, len;
689 : :
690 [ + + ]: 364 : if (bs_dev == NULL) {
691 : 3 : SPDK_ERRLOG("Blobstore device does not exist\n");
692 : 3 : return -ENODEV;
693 : : }
694 : :
695 [ - + ]: 361 : if (o == NULL) {
696 : 0 : SPDK_ERRLOG("spdk_lvs_opts not specified\n");
697 : 0 : return -EINVAL;
698 : : }
699 : :
700 : 361 : spdk_lvs_opts_init(&lvs_opts);
701 [ - + ]: 361 : if (lvs_opts_copy(o, &lvs_opts) != 0) {
702 : 0 : SPDK_ERRLOG("spdk_lvs_opts invalid\n");
703 : 0 : return -EINVAL;
704 : : }
705 : :
706 [ + + - + : 361 : 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 [ - + - + : 359 : total_clusters = bs_dev->blockcnt / (lvs_opts.cluster_sz / bs_dev->blocklen);
# # # # #
# # # ]
712 : :
713 : 359 : lvs = lvs_alloc();
714 [ - + ]: 359 : if (!lvs) {
715 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store base pointer\n");
716 : 0 : return -ENOMEM;
717 : : }
718 : :
719 : 359 : setup_lvs_opts(&opts, o, total_clusters, lvs);
720 : :
721 [ # # ]: 359 : len = strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX);
722 [ + + + + ]: 359 : if (len == 0 || len == SPDK_LVS_NAME_MAX) {
723 : 6 : SPDK_ERRLOG("Name must be between 1 and %d characters\n", SPDK_LVS_NAME_MAX - 1);
724 : 6 : lvs_free(lvs);
725 : 6 : return -EINVAL;
726 : : }
727 : :
728 [ # # ]: 353 : spdk_uuid_generate(&lvs->uuid);
729 [ # # ]: 353 : snprintf(lvs->name, sizeof(lvs->name), "%s", lvs_opts.name);
730 : :
731 : 353 : rc = add_lvs_to_list(lvs);
732 [ + + ]: 353 : if (rc) {
733 [ # # ]: 4 : SPDK_ERRLOG("lvolstore with name %s already exists\n", lvs->name);
734 : 4 : lvs_free(lvs);
735 : 4 : return -EEXIST;
736 : : }
737 : :
738 : 349 : lvs_req = calloc(1, sizeof(*lvs_req));
739 [ - + ]: 349 : 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 [ - + # # ]: 349 : assert(cb_fn != NULL);
746 [ # # # # ]: 349 : lvs_req->cb_fn = cb_fn;
747 [ # # # # ]: 349 : lvs_req->cb_arg = cb_arg;
748 [ # # # # ]: 349 : lvs_req->lvol_store = lvs;
749 [ # # # # ]: 349 : lvs->bs_dev = bs_dev;
750 : :
751 [ - + - + : 349 : SPDK_INFOLOG(lvol, "Initializing lvol store\n");
# # ]
752 : 349 : spdk_bs_init(bs_dev, &opts, lvs_init_cb, lvs_req);
753 : :
754 : 349 : return 0;
755 : 0 : }
756 : :
757 : : static void
758 : 7 : lvs_rename_cb(void *cb_arg, int lvolerrno)
759 : : {
760 : 7 : struct spdk_lvs_req *req = cb_arg;
761 : :
762 [ + + ]: 7 : if (lvolerrno != 0) {
763 [ # # # # ]: 3 : req->lvserrno = lvolerrno;
764 : 0 : }
765 [ + + # # : 7 : if (req->lvserrno != 0) {
# # ]
766 : 3 : 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 [ - + # # : 3 : snprintf(req->lvol_store->new_name,
# # ]
770 : : sizeof(req->lvol_store->new_name),
771 [ # # # # : 3 : "%s", req->lvol_store->name);
# # ]
772 : 0 : } else {
773 : : /* Update lvs name with new_name */
774 [ - + # # : 4 : snprintf(req->lvol_store->name,
# # ]
775 : : sizeof(req->lvol_store->name),
776 [ # # # # : 4 : "%s", req->lvol_store->new_name);
# # ]
777 : : }
778 : :
779 [ # # # # : 7 : req->cb_fn(req->cb_arg, req->lvserrno);
# # # # #
# # # # #
# # ]
780 : 7 : free(req);
781 : 7 : }
782 : :
783 : : static void
784 : 4 : lvs_rename_sync_cb(void *cb_arg, int lvolerrno)
785 : : {
786 : 4 : struct spdk_lvs_req *req = cb_arg;
787 [ # # # # : 4 : struct spdk_blob *blob = req->lvol_store->super_blob;
# # # # ]
788 : :
789 [ - + ]: 4 : if (lvolerrno < 0) {
790 [ # # # # ]: 0 : req->lvserrno = lvolerrno;
791 : 0 : }
792 : :
793 : 4 : spdk_blob_close(blob, lvs_rename_cb, req);
794 : 4 : }
795 : :
796 : : static void
797 : 7 : lvs_rename_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
798 : : {
799 : 7 : struct spdk_lvs_req *req = cb_arg;
800 : : int rc;
801 : :
802 [ + + ]: 7 : if (lvolerrno < 0) {
803 : 3 : lvs_rename_cb(cb_arg, lvolerrno);
804 : 3 : return;
805 : : }
806 : :
807 [ # # # # : 4 : rc = spdk_blob_set_xattr(blob, "name", req->lvol_store->new_name,
# # ]
808 [ - + # # : 4 : strlen(req->lvol_store->new_name) + 1);
# # # # ]
809 [ - + ]: 4 : if (rc < 0) {
810 [ # # # # ]: 0 : req->lvserrno = rc;
811 : 0 : lvs_rename_sync_cb(req, rc);
812 : 0 : return;
813 : : }
814 : :
815 [ # # # # : 4 : req->lvol_store->super_blob = blob;
# # # # ]
816 : :
817 : 4 : spdk_blob_sync_md(blob, lvs_rename_sync_cb, req);
818 : 0 : }
819 : :
820 : : void
821 : 17 : 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 [ + + - + : 17 : if (strncmp(lvs->name, new_name, SPDK_LVS_NAME_MAX) == 0) {
+ + # # ]
830 [ # # # # ]: 3 : cb_fn(cb_arg, 0);
831 : 3 : return;
832 : : }
833 : :
834 : : /* Check if new or new_name is already used in other lvs */
835 [ # # ]: 14 : pthread_mutex_lock(&g_lvol_stores_mutex);
836 [ + + # # : 31 : TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
# # # # ]
837 [ + + - + : 24 : if (!strncmp(new_name, tmp->name, SPDK_LVS_NAME_MAX) ||
+ + # # #
# ]
838 [ + + - + : 20 : !strncmp(new_name, tmp->new_name, SPDK_LVS_NAME_MAX)) {
+ + ]
839 [ # # ]: 7 : pthread_mutex_unlock(&g_lvol_stores_mutex);
840 [ # # # # ]: 7 : cb_fn(cb_arg, -EEXIST);
841 : 7 : return;
842 : : }
843 : 0 : }
844 [ # # ]: 7 : pthread_mutex_unlock(&g_lvol_stores_mutex);
845 : :
846 : 7 : req = calloc(1, sizeof(*req));
847 [ - + ]: 7 : 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 [ # # ]: 7 : snprintf(lvs->new_name, sizeof(lvs->new_name), "%s", new_name);
853 [ # # # # ]: 7 : req->lvol_store = lvs;
854 [ # # # # ]: 7 : req->cb_fn = cb_fn;
855 [ # # # # ]: 7 : req->cb_arg = cb_arg;
856 : :
857 [ # # # # : 7 : spdk_bs_open_blob(lvs->blobstore, lvs->super_blob_id, lvs_rename_open_cb, req);
# # # # ]
858 : 0 : }
859 : :
860 : : static void
861 : 218 : _lvs_unload_cb(void *cb_arg, int lvserrno)
862 : : {
863 : 218 : struct spdk_lvs_req *lvs_req = cb_arg;
864 : :
865 [ - + - + : 218 : SPDK_INFOLOG(lvol, "Lvol store unloaded\n");
# # ]
866 [ - + # # : 218 : assert(lvs_req->cb_fn != NULL);
# # # # ]
867 [ # # # # : 218 : lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
# # # # #
# # # ]
868 : 218 : free(lvs_req);
869 : 218 : }
870 : :
871 : : int
872 : 224 : 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 [ + + ]: 224 : if (lvs == NULL) {
879 : 3 : SPDK_ERRLOG("Lvol store is NULL\n");
880 : 3 : return -ENODEV;
881 : : }
882 : :
883 [ + + # # : 637 : TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
884 [ - + - + : 419 : 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 [ + + # # : 419 : } else if (lvol->ref_count != 0) {
# # ]
889 : 3 : SPDK_ERRLOG("Lvols still open on lvol store\n");
890 [ # # # # ]: 3 : cb_fn(cb_arg, -EBUSY);
891 : 3 : return -EBUSY;
892 : : }
893 : 0 : }
894 : :
895 [ + + # # : 634 : TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
896 : 416 : spdk_lvs_esnap_missing_remove(lvol);
897 [ + + # # : 416 : TAILQ_REMOVE(&lvs->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
898 : 416 : lvol_free(lvol);
899 : 0 : }
900 : :
901 : 218 : lvs_req = calloc(1, sizeof(*lvs_req));
902 [ - + ]: 218 : if (!lvs_req) {
903 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
904 : 0 : return -ENOMEM;
905 : : }
906 : :
907 [ # # # # ]: 218 : lvs_req->cb_fn = cb_fn;
908 [ # # # # ]: 218 : lvs_req->cb_arg = cb_arg;
909 : :
910 [ - + - + : 218 : SPDK_INFOLOG(lvol, "Unloading lvol store\n");
# # ]
911 [ # # # # ]: 218 : spdk_bs_unload(lvs->blobstore, _lvs_unload_cb, lvs_req);
912 : 218 : lvs_free(lvs);
913 : :
914 : 218 : return 0;
915 : 0 : }
916 : :
917 : : static void
918 : 223 : _lvs_destroy_cb(void *cb_arg, int lvserrno)
919 : : {
920 : 223 : struct spdk_lvs_destroy_req *lvs_req = cb_arg;
921 : :
922 [ - + - + : 223 : SPDK_INFOLOG(lvol, "Lvol store destroyed\n");
# # ]
923 [ - + # # : 223 : assert(lvs_req->cb_fn != NULL);
# # # # ]
924 [ # # # # : 223 : lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
# # # # #
# # # ]
925 : 223 : free(lvs_req);
926 : 223 : }
927 : :
928 : : static void
929 : 223 : _lvs_destroy_super_cb(void *cb_arg, int bserrno)
930 : : {
931 : 223 : struct spdk_lvs_destroy_req *lvs_req = cb_arg;
932 [ # # # # ]: 223 : struct spdk_lvol_store *lvs = lvs_req->lvs;
933 : :
934 [ - + # # ]: 223 : assert(lvs != NULL);
935 : :
936 [ - + - + : 223 : SPDK_INFOLOG(lvol, "Destroying lvol store\n");
# # ]
937 [ # # # # ]: 223 : spdk_bs_destroy(lvs->blobstore, _lvs_destroy_cb, lvs_req);
938 : 223 : lvs_free(lvs);
939 : 223 : }
940 : :
941 : : int
942 : 226 : 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 [ - + ]: 226 : if (lvs == NULL) {
949 : 0 : SPDK_ERRLOG("Lvol store is NULL\n");
950 : 0 : return -ENODEV;
951 : : }
952 : :
953 [ + + # # : 235 : TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
954 [ - + - + : 12 : 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 [ + + # # : 12 : } else if (iter_lvol->ref_count != 0) {
# # ]
959 : 3 : SPDK_ERRLOG("Lvols still open on lvol store\n");
960 [ # # # # ]: 3 : cb_fn(cb_arg, -EBUSY);
961 : 3 : return -EBUSY;
962 : : }
963 : 0 : }
964 : :
965 [ + + # # : 232 : TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
# # # # #
# # # # #
# # ]
966 : 9 : free(iter_lvol);
967 : 0 : }
968 : :
969 : 223 : lvs_req = calloc(1, sizeof(*lvs_req));
970 [ - + ]: 223 : if (!lvs_req) {
971 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
972 : 0 : return -ENOMEM;
973 : : }
974 : :
975 [ # # # # ]: 223 : lvs_req->cb_fn = cb_fn;
976 [ # # # # ]: 223 : lvs_req->cb_arg = cb_arg;
977 [ # # # # ]: 223 : lvs_req->lvs = lvs;
978 : :
979 [ - + - + : 223 : SPDK_INFOLOG(lvol, "Deleting super blob\n");
# # ]
980 [ # # # # : 223 : spdk_bs_delete_blob(lvs->blobstore, lvs->super_blob_id, _lvs_destroy_super_cb, lvs_req);
# # # # ]
981 : :
982 : 223 : return 0;
983 : 0 : }
984 : :
985 : : static void
986 : 887 : lvol_close_blob_cb(void *cb_arg, int lvolerrno)
987 : : {
988 : 887 : struct spdk_lvol_req *req = cb_arg;
989 [ # # # # ]: 887 : struct spdk_lvol *lvol = req->lvol;
990 : :
991 [ + + ]: 887 : if (lvolerrno < 0) {
992 : 3 : SPDK_ERRLOG("Could not close blob on lvol\n");
993 : 3 : goto end;
994 : : }
995 : :
996 [ # # # # ]: 884 : lvol->ref_count--;
997 [ # # # # ]: 884 : lvol->blob = NULL;
998 [ + + + - : 884 : SPDK_INFOLOG(lvol, "Lvol %s closed\n", lvol->unique_id);
# # # # ]
999 : :
1000 : 884 : end:
1001 [ # # # # ]: 887 : lvol->action_in_progress = false;
1002 [ # # # # : 887 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1003 : 887 : free(req);
1004 : 887 : }
1005 : :
1006 : : bool
1007 : 78 : spdk_lvol_deletable(struct spdk_lvol *lvol)
1008 : : {
1009 : 78 : size_t count = 0;
1010 : :
1011 [ # # # # : 78 : spdk_blob_get_clones(lvol->lvol_store->blobstore, lvol->blob_id, NULL, &count);
# # # # #
# # # ]
1012 : 78 : return (count == 0);
1013 : : }
1014 : :
1015 : : static void
1016 : 471 : lvol_delete_blob_cb(void *cb_arg, int lvolerrno)
1017 : : {
1018 : 471 : struct spdk_lvol_req *req = cb_arg;
1019 [ # # # # ]: 471 : struct spdk_lvol *lvol = req->lvol;
1020 [ # # # # ]: 471 : struct spdk_lvol *clone_lvol = req->clone_lvol;
1021 : :
1022 [ + + ]: 471 : if (lvolerrno < 0) {
1023 : 3 : SPDK_ERRLOG("Could not remove blob on lvol gracefully - forced removal\n");
1024 : 0 : } else {
1025 [ - + - + : 468 : SPDK_INFOLOG(lvol, "Lvol %s deleted\n", lvol->unique_id);
# # # # ]
1026 : : }
1027 : :
1028 [ + + # # : 471 : if (lvol->degraded_set != NULL) {
# # ]
1029 [ + + ]: 39 : 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 [ # # # # ]: 4 : struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
1036 : :
1037 : 4 : lvs_degraded_lvol_set_remove(degraded_set, lvol);
1038 : 4 : lvs_degraded_lvol_set_add(degraded_set, clone_lvol);
1039 : 0 : } else {
1040 : 35 : spdk_lvs_esnap_missing_remove(lvol);
1041 : : }
1042 : 0 : }
1043 : :
1044 [ + + # # : 471 : TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1045 : 471 : lvol_free(lvol);
1046 [ # # # # : 471 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1047 : 471 : free(req);
1048 : 471 : }
1049 : :
1050 : : static void
1051 : 772 : lvol_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
1052 : : {
1053 : 772 : struct spdk_lvol_with_handle_req *req = cb_arg;
1054 [ # # # # ]: 772 : struct spdk_lvol *lvol = req->lvol;
1055 : :
1056 [ - + # # : 772 : TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1057 : :
1058 [ - + ]: 772 : 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 [ # # # # ]: 772 : lvol->blob = blob;
1066 [ # # # # ]: 772 : lvol->blob_id = spdk_blob_get_id(blob);
1067 : :
1068 [ # # # # : 772 : TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1069 : :
1070 [ # # # # ]: 772 : lvol->ref_count++;
1071 : :
1072 [ - + # # : 772 : assert(req->cb_fn != NULL);
# # # # ]
1073 [ # # # # : 772 : req->cb_fn(req->cb_arg, req->lvol, lvolerrno);
# # # # #
# # # # #
# # ]
1074 : 772 : free(req);
1075 : 0 : }
1076 : :
1077 : : static void
1078 : 780 : lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
1079 : : {
1080 : 780 : struct spdk_lvol_with_handle_req *req = cb_arg;
1081 : : struct spdk_blob_store *bs;
1082 : 441 : struct spdk_blob_open_opts opts;
1083 : :
1084 [ + + ]: 780 : if (lvolerrno < 0) {
1085 [ - + # # : 8 : TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
1086 [ # # # # ]: 8 : lvol_free(req->lvol);
1087 [ - + # # : 8 : assert(req->cb_fn != NULL);
# # # # ]
1088 [ # # # # : 8 : req->cb_fn(req->cb_arg, NULL, lvolerrno);
# # # # #
# # # ]
1089 : 8 : free(req);
1090 : 8 : return;
1091 : : }
1092 : :
1093 : 772 : spdk_blob_open_opts_init(&opts, sizeof(opts));
1094 [ # # # # : 772 : 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 [ # # # # : 772 : opts.esnap_ctx = req->lvol;
# # ]
1105 [ # # # # : 772 : bs = req->lvol->lvol_store->blobstore;
# # # # #
# # # ]
1106 : :
1107 [ + + + + : 772 : 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 [ # # # # : 3 : struct spdk_lvs_degraded_lvol_set *degraded_set = req->origlvol->degraded_set;
# # # # ]
1114 : :
1115 [ # # # # ]: 3 : lvs_degraded_lvol_set_remove(degraded_set, req->origlvol);
1116 [ # # # # ]: 3 : lvs_degraded_lvol_set_add(degraded_set, req->lvol);
1117 : 0 : }
1118 : :
1119 : 772 : spdk_bs_open_blob_ext(bs, blobid, &opts, lvol_create_open_cb, req);
1120 : 0 : }
1121 : :
1122 : : static void
1123 : 1104 : lvol_get_xattr_value(void *xattr_ctx, const char *name,
1124 : : const void **value, size_t *value_len)
1125 : : {
1126 : 1104 : struct spdk_lvol *lvol = xattr_ctx;
1127 : :
1128 [ + + + + : 1104 : if (!strcmp(LVOL_NAME, name)) {
# # ]
1129 [ # # # # ]: 552 : *value = lvol->name;
1130 [ # # ]: 552 : *value_len = SPDK_LVOL_NAME_MAX;
1131 : 552 : return;
1132 : : }
1133 [ + + + + : 552 : if (!strcmp("uuid", name)) {
# # ]
1134 [ # # # # ]: 549 : *value = lvol->uuid_str;
1135 [ # # ]: 549 : *value_len = sizeof(lvol->uuid_str);
1136 : 549 : return;
1137 : : }
1138 [ # # ]: 3 : *value = NULL;
1139 [ # # ]: 3 : *value_len = 0;
1140 : 0 : }
1141 : :
1142 : : static int
1143 : 838 : lvs_verify_lvol_name(struct spdk_lvol_store *lvs, const char *name)
1144 : : {
1145 : : struct spdk_lvol *tmp;
1146 : :
1147 [ + + + + : 838 : if (name == NULL || strnlen(name, SPDK_LVOL_NAME_MAX) == 0) {
+ + ]
1148 [ - + - + : 21 : SPDK_INFOLOG(lvol, "lvol name not provided.\n");
# # ]
1149 : 21 : return -EINVAL;
1150 : : }
1151 : :
1152 [ + + + + ]: 817 : if (strnlen(name, SPDK_LVOL_NAME_MAX) == SPDK_LVOL_NAME_MAX) {
1153 : 6 : SPDK_ERRLOG("Name has no null terminator.\n");
1154 : 6 : return -EINVAL;
1155 : : }
1156 : :
1157 [ + + # # : 2980 : TAILQ_FOREACH(tmp, &lvs->lvols, link) {
# # # # #
# # # #
# ]
1158 [ + + - + : 2194 : if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
+ + # # ]
1159 : 25 : SPDK_ERRLOG("lvol with name %s already exists\n", name);
1160 : 25 : return -EEXIST;
1161 : : }
1162 : 0 : }
1163 : :
1164 [ + + # # : 786 : TAILQ_FOREACH(tmp, &lvs->pending_lvols, link) {
# # # # #
# # # #
# ]
1165 [ + + - + : 3 : if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
+ - # # ]
1166 : 3 : SPDK_ERRLOG("lvol with name %s is being already created\n", name);
1167 : 3 : return -EEXIST;
1168 : : }
1169 : 0 : }
1170 : :
1171 : 783 : return 0;
1172 : 0 : }
1173 : :
1174 : : int
1175 : 605 : 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 : 280 : struct spdk_blob_opts opts;
1183 : 605 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1184 : : int rc;
1185 : :
1186 [ + + ]: 605 : if (lvs == NULL) {
1187 : 3 : SPDK_ERRLOG("lvol store does not exist\n");
1188 : 3 : return -EINVAL;
1189 : : }
1190 : :
1191 : 602 : rc = lvs_verify_lvol_name(lvs, name);
1192 [ + + ]: 602 : if (rc < 0) {
1193 : 22 : return rc;
1194 : : }
1195 : :
1196 [ # # # # ]: 580 : bs = lvs->blobstore;
1197 : :
1198 : 580 : req = calloc(1, sizeof(*req));
1199 [ - + ]: 580 : if (!req) {
1200 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1201 : 0 : return -ENOMEM;
1202 : : }
1203 [ # # # # ]: 580 : req->cb_fn = cb_fn;
1204 [ # # # # ]: 580 : req->cb_arg = cb_arg;
1205 : :
1206 [ # # ]: 580 : lvol = lvol_alloc(lvs, name, thin_provision, clear_method);
1207 [ - + ]: 580 : 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 [ # # # # ]: 580 : req->lvol = lvol;
1214 : 580 : spdk_blob_opts_init(&opts, sizeof(opts));
1215 [ # # # # ]: 580 : opts.thin_provision = thin_provision;
1216 : 580 : opts.num_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(bs));
1217 [ # # # # : 580 : opts.clear_method = lvol->clear_method;
# # ]
1218 [ # # # # ]: 580 : opts.xattrs.count = SPDK_COUNTOF(xattr_names);
1219 [ # # # # ]: 580 : opts.xattrs.names = xattr_names;
1220 [ # # # # ]: 580 : opts.xattrs.ctx = lvol;
1221 [ # # # # ]: 580 : opts.xattrs.get_value = lvol_get_xattr_value;
1222 : :
1223 [ # # # # ]: 580 : spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
1224 : :
1225 : 580 : return 0;
1226 : 0 : }
1227 : :
1228 : : int
1229 : 124 : 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 : 124 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1239 : : int rc;
1240 : :
1241 [ + + ]: 124 : if (lvs == NULL) {
1242 : 3 : SPDK_ERRLOG("lvol store does not exist\n");
1243 : 3 : return -EINVAL;
1244 : : }
1245 : :
1246 : 121 : rc = lvs_verify_lvol_name(lvs, clone_name);
1247 [ + + ]: 121 : if (rc < 0) {
1248 : 15 : return rc;
1249 : : }
1250 : :
1251 [ # # # # ]: 106 : bs = lvs->blobstore;
1252 : :
1253 : 106 : cluster_sz = spdk_bs_get_cluster_size(bs);
1254 [ + + + + ]: 106 : if ((size_bytes % cluster_sz) != 0) {
1255 [ # # ]: 3 : 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 : 3 : return -EINVAL;
1259 : : }
1260 : :
1261 : 103 : req = calloc(1, sizeof(*req));
1262 [ - + ]: 103 : if (!req) {
1263 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
1264 : 0 : return -ENOMEM;
1265 : : }
1266 [ # # # # ]: 103 : req->cb_fn = cb_fn;
1267 [ # # # # ]: 103 : req->cb_arg = cb_arg;
1268 : :
1269 : 103 : lvol = lvol_alloc(lvs, clone_name, true, LVOL_CLEAR_WITH_DEFAULT);
1270 [ - + ]: 103 : if (!lvol) {
1271 : 0 : free(req);
1272 : 0 : SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
1273 : 0 : return -ENOMEM;
1274 : : }
1275 [ # # # # ]: 103 : req->lvol = lvol;
1276 : :
1277 : 103 : spdk_blob_opts_init(&opts, sizeof(opts));
1278 [ # # ]: 103 : opts.esnap_id = esnap_id;
1279 [ # # ]: 103 : opts.esnap_id_len = id_len;
1280 [ # # ]: 103 : opts.thin_provision = true;
1281 : 103 : opts.num_clusters = spdk_divide_round_up(size_bytes, cluster_sz);
1282 [ # # # # : 103 : opts.clear_method = lvol->clear_method;
# # ]
1283 [ # # # # ]: 103 : opts.xattrs.count = SPDK_COUNTOF(xattr_names);
1284 [ # # # # ]: 103 : opts.xattrs.names = xattr_names;
1285 [ # # # # ]: 103 : opts.xattrs.ctx = lvol;
1286 [ # # # # ]: 103 : opts.xattrs.get_value = lvol_get_xattr_value;
1287 : :
1288 [ # # # # ]: 103 : spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
1289 : :
1290 : 103 : return 0;
1291 : 0 : }
1292 : :
1293 : : void
1294 : 72 : 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 : 72 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1303 : : int rc;
1304 : :
1305 [ + + ]: 72 : if (origlvol == NULL) {
1306 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Lvol not provided.\n");
# # ]
1307 [ # # # # ]: 3 : cb_fn(cb_arg, NULL, -EINVAL);
1308 : 3 : return;
1309 : : }
1310 : :
1311 [ # # # # ]: 69 : origblob = origlvol->blob;
1312 [ # # # # ]: 69 : lvs = origlvol->lvol_store;
1313 [ - + ]: 69 : 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 : 69 : rc = lvs_verify_lvol_name(lvs, snapshot_name);
1320 [ + + ]: 69 : if (rc < 0) {
1321 [ # # # # ]: 9 : cb_fn(cb_arg, NULL, rc);
1322 : 9 : return;
1323 : : }
1324 : :
1325 : 60 : req = calloc(1, sizeof(*req));
1326 [ - + ]: 60 : 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 [ # # # # ]: 60 : newlvol = lvol_alloc(origlvol->lvol_store, snapshot_name, true,
1333 [ # # # # ]: 60 : (enum lvol_clear_method)origlvol->clear_method);
1334 [ - + ]: 60 : 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 : 60 : snapshot_xattrs.count = SPDK_COUNTOF(xattr_names);
1342 [ # # ]: 60 : snapshot_xattrs.ctx = newlvol;
1343 [ # # ]: 60 : snapshot_xattrs.names = xattr_names;
1344 [ # # ]: 60 : snapshot_xattrs.get_value = lvol_get_xattr_value;
1345 [ # # # # ]: 60 : req->lvol = newlvol;
1346 [ # # # # ]: 60 : req->origlvol = origlvol;
1347 [ # # # # ]: 60 : req->cb_fn = cb_fn;
1348 [ # # # # ]: 60 : req->cb_arg = cb_arg;
1349 : :
1350 [ # # # # ]: 60 : spdk_bs_create_snapshot(lvs->blobstore, spdk_blob_get_id(origblob), &snapshot_xattrs,
1351 : 0 : lvol_create_cb, req);
1352 : 0 : }
1353 : :
1354 : : void
1355 : 49 : 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 : 49 : char *xattr_names[] = {LVOL_NAME, "uuid"};
1364 : : int rc;
1365 : :
1366 [ + + ]: 49 : if (origlvol == NULL) {
1367 [ - + - + : 3 : SPDK_INFOLOG(lvol, "Lvol not provided.\n");
# # ]
1368 [ # # # # ]: 3 : cb_fn(cb_arg, NULL, -EINVAL);
1369 : 3 : return;
1370 : : }
1371 : :
1372 [ # # # # ]: 46 : origblob = origlvol->blob;
1373 [ # # # # ]: 46 : lvs = origlvol->lvol_store;
1374 [ - + ]: 46 : 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 : 46 : rc = lvs_verify_lvol_name(lvs, clone_name);
1381 [ + + ]: 46 : if (rc < 0) {
1382 [ # # # # ]: 9 : cb_fn(cb_arg, NULL, rc);
1383 : 9 : return;
1384 : : }
1385 : :
1386 : 37 : req = calloc(1, sizeof(*req));
1387 [ - + ]: 37 : 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 [ # # # # ]: 37 : newlvol = lvol_alloc(lvs, clone_name, true, (enum lvol_clear_method)origlvol->clear_method);
1394 [ - + ]: 37 : 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 : 37 : clone_xattrs.count = SPDK_COUNTOF(xattr_names);
1402 [ # # ]: 37 : clone_xattrs.ctx = newlvol;
1403 [ # # ]: 37 : clone_xattrs.names = xattr_names;
1404 [ # # ]: 37 : clone_xattrs.get_value = lvol_get_xattr_value;
1405 [ # # # # ]: 37 : req->lvol = newlvol;
1406 [ # # # # ]: 37 : req->cb_fn = cb_fn;
1407 [ # # # # ]: 37 : req->cb_arg = cb_arg;
1408 : :
1409 [ # # # # ]: 37 : spdk_bs_create_clone(lvs->blobstore, spdk_blob_get_id(origblob), &clone_xattrs,
1410 : : lvol_create_cb,
1411 : 0 : req);
1412 : 0 : }
1413 : :
1414 : : static void
1415 : 35 : lvol_resize_done(void *cb_arg, int lvolerrno)
1416 : : {
1417 : 35 : struct spdk_lvol_req *req = cb_arg;
1418 : :
1419 [ # # # # : 35 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1420 : 35 : free(req);
1421 : 35 : }
1422 : :
1423 : : static void
1424 : 42 : lvol_blob_resize_cb(void *cb_arg, int bserrno)
1425 : : {
1426 : 42 : struct spdk_lvol_req *req = cb_arg;
1427 [ # # # # ]: 42 : struct spdk_lvol *lvol = req->lvol;
1428 : :
1429 [ + + ]: 42 : if (bserrno != 0) {
1430 [ # # # # : 7 : req->cb_fn(req->cb_arg, bserrno);
# # # # #
# # # ]
1431 : 7 : free(req);
1432 : 7 : return;
1433 : : }
1434 : :
1435 [ # # # # ]: 35 : spdk_blob_sync_md(lvol->blob, lvol_resize_done, req);
1436 : 0 : }
1437 : :
1438 : : void
1439 : 42 : spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz,
1440 : : spdk_lvol_op_complete cb_fn, void *cb_arg)
1441 : : {
1442 [ # # # # ]: 42 : struct spdk_blob *blob = lvol->blob;
1443 [ # # # # ]: 42 : struct spdk_lvol_store *lvs = lvol->lvol_store;
1444 : : struct spdk_lvol_req *req;
1445 [ # # # # ]: 42 : uint64_t new_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(lvs->blobstore));
1446 : :
1447 : 42 : req = calloc(1, sizeof(*req));
1448 [ - + ]: 42 : 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 [ # # # # ]: 42 : req->cb_fn = cb_fn;
1454 [ # # # # ]: 42 : req->cb_arg = cb_arg;
1455 [ # # # # ]: 42 : req->lvol = lvol;
1456 : :
1457 : 42 : spdk_blob_resize(blob, new_clusters, lvol_blob_resize_cb, req);
1458 : 0 : }
1459 : :
1460 : : static void
1461 : 7 : lvol_set_read_only_cb(void *cb_arg, int lvolerrno)
1462 : : {
1463 : 7 : struct spdk_lvol_req *req = cb_arg;
1464 : :
1465 [ # # # # : 7 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1466 : 7 : free(req);
1467 : 7 : }
1468 : :
1469 : : void
1470 : 7 : 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 : 7 : req = calloc(1, sizeof(*req));
1475 [ - + ]: 7 : 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 [ # # # # ]: 7 : req->cb_fn = cb_fn;
1481 [ # # # # ]: 7 : req->cb_arg = cb_arg;
1482 : :
1483 [ # # # # ]: 7 : spdk_blob_set_read_only(lvol->blob);
1484 [ # # # # ]: 7 : spdk_blob_sync_md(lvol->blob, lvol_set_read_only_cb, req);
1485 : 0 : }
1486 : :
1487 : : static void
1488 : 7 : lvol_rename_cb(void *cb_arg, int lvolerrno)
1489 : : {
1490 : 7 : struct spdk_lvol_req *req = cb_arg;
1491 : :
1492 [ - + ]: 7 : if (lvolerrno != 0) {
1493 : 0 : SPDK_ERRLOG("Lvol rename operation failed\n");
1494 : 0 : } else {
1495 [ - + # # : 7 : snprintf(req->lvol->name, sizeof(req->lvol->name), "%s", req->name);
# # # # ]
1496 : : }
1497 : :
1498 [ # # # # : 7 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1499 : 7 : free(req);
1500 : 7 : }
1501 : :
1502 : : void
1503 : 10 : 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 [ # # # # ]: 10 : 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 [ - + - + : 10 : 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 [ + + # # : 32 : TAILQ_FOREACH(tmp, &lvol->lvol_store->lvols, link) {
# # # # #
# # # # #
# # # # ]
1520 [ + + - + : 25 : if (strncmp(tmp->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
+ + # # ]
1521 [ # # # # : 3 : SPDK_ERRLOG("Lvol %s already exists in lvol store %s\n", new_name, lvol->lvol_store->name);
# # ]
1522 [ # # # # ]: 3 : cb_fn(cb_arg, -EEXIST);
1523 : 3 : return;
1524 : : }
1525 : 0 : }
1526 : :
1527 : 7 : req = calloc(1, sizeof(*req));
1528 [ - + ]: 7 : 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 [ # # # # ]: 7 : req->cb_fn = cb_fn;
1534 [ # # # # ]: 7 : req->cb_arg = cb_arg;
1535 [ # # # # ]: 7 : req->lvol = lvol;
1536 [ # # ]: 7 : snprintf(req->name, sizeof(req->name), "%s", new_name);
1537 : :
1538 [ - + ]: 7 : rc = spdk_blob_set_xattr(blob, "name", new_name, strlen(new_name) + 1);
1539 [ - + ]: 7 : if (rc < 0) {
1540 : 0 : free(req);
1541 [ # # # # ]: 0 : cb_fn(cb_arg, rc);
1542 : 0 : return;
1543 : : }
1544 : :
1545 : 7 : spdk_blob_sync_md(blob, lvol_rename_cb, req);
1546 : 0 : }
1547 : :
1548 : : void
1549 : 474 : 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 : 344 : spdk_blob_id clone_id;
1555 : 474 : size_t count = 1;
1556 : : int rc;
1557 : :
1558 [ - + # # ]: 474 : assert(cb_fn != NULL);
1559 : :
1560 [ - + ]: 474 : 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 [ # # # # ]: 474 : lvs = lvol->lvol_store;
1567 : :
1568 [ + + # # : 474 : if (lvol->ref_count != 0) {
# # ]
1569 [ # # ]: 3 : SPDK_ERRLOG("Cannot destroy lvol %s because it is still open\n", lvol->unique_id);
1570 [ # # # # ]: 3 : cb_fn(cb_arg, -EBUSY);
1571 : 3 : return;
1572 : : }
1573 : :
1574 : 471 : req = calloc(1, sizeof(*req));
1575 [ - + ]: 471 : 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 [ # # # # ]: 471 : req->cb_fn = cb_fn;
1582 [ # # # # ]: 471 : req->cb_arg = cb_arg;
1583 [ # # # # ]: 471 : req->lvol = lvol;
1584 [ # # # # : 471 : bs = lvol->lvol_store->blobstore;
# # # # ]
1585 : :
1586 [ # # # # : 471 : rc = spdk_blob_get_clones(lvs->blobstore, lvol->blob_id, &clone_id, &count);
# # # # ]
1587 [ + - + + ]: 471 : if (rc == 0 && count == 1) {
1588 [ # # # # ]: 11 : req->clone_lvol = lvs_get_lvol_by_blob_id(lvs, clone_id);
1589 [ - + ]: 460 : } 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 [ # # # # ]: 471 : lvol->action_in_progress = true;
1599 : :
1600 [ # # # # ]: 471 : spdk_bs_delete_blob(bs, lvol->blob_id, lvol_delete_blob_cb, req);
1601 : 0 : }
1602 : :
1603 : : void
1604 : 899 : 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 [ - + # # ]: 899 : assert(cb_fn != NULL);
1609 : :
1610 [ + + ]: 899 : if (lvol == NULL) {
1611 : 3 : SPDK_ERRLOG("lvol does not exist\n");
1612 [ # # # # ]: 3 : cb_fn(cb_arg, -ENODEV);
1613 : 3 : return;
1614 : : }
1615 : :
1616 [ + + # # : 896 : if (lvol->ref_count > 1) {
# # ]
1617 [ # # # # ]: 3 : lvol->ref_count--;
1618 [ # # # # ]: 3 : cb_fn(cb_arg, 0);
1619 : 3 : return;
1620 [ + + # # : 893 : } else if (lvol->ref_count == 0) {
# # ]
1621 [ # # # # ]: 6 : cb_fn(cb_arg, -EINVAL);
1622 : 6 : return;
1623 : : }
1624 : :
1625 : 887 : req = calloc(1, sizeof(*req));
1626 [ - + ]: 887 : 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 [ # # # # ]: 887 : req->cb_fn = cb_fn;
1633 [ # # # # ]: 887 : req->cb_arg = cb_arg;
1634 [ # # # # ]: 887 : req->lvol = lvol;
1635 : :
1636 [ # # # # ]: 887 : lvol->action_in_progress = true;
1637 : :
1638 [ # # # # ]: 887 : spdk_blob_close(lvol->blob, lvol_close_blob_cb, req);
1639 : 0 : }
1640 : :
1641 : : struct spdk_io_channel *
1642 : 1237 : spdk_lvol_get_io_channel(struct spdk_lvol *lvol)
1643 : : {
1644 [ # # # # : 1237 : return spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
# # # # ]
1645 : : }
1646 : :
1647 : : static void
1648 : 22 : lvol_inflate_cb(void *cb_arg, int lvolerrno)
1649 : : {
1650 : 22 : struct spdk_lvol_req *req = cb_arg;
1651 : :
1652 [ # # # # ]: 22 : spdk_bs_free_io_channel(req->channel);
1653 : :
1654 [ + + ]: 22 : if (lvolerrno < 0) {
1655 : 7 : SPDK_ERRLOG("Could not inflate lvol\n");
1656 : 0 : }
1657 : :
1658 [ # # # # : 22 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
1659 : 22 : free(req);
1660 : 22 : }
1661 : :
1662 : : void
1663 : 13 : 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 [ - + # # ]: 13 : assert(cb_fn != NULL);
1669 : :
1670 [ - + ]: 13 : 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 : 13 : req = calloc(1, sizeof(*req));
1677 [ - + ]: 13 : 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 [ # # # # ]: 13 : req->cb_fn = cb_fn;
1684 [ # # # # ]: 13 : req->cb_arg = cb_arg;
1685 [ # # # # : 13 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
# # # # #
# # # ]
1686 [ - + # # : 13 : 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 [ # # # # ]: 13 : blob_id = spdk_blob_get_id(lvol->blob);
1694 [ # # # # : 13 : spdk_bs_inflate_blob(lvol->lvol_store->blobstore, req->channel, blob_id, lvol_inflate_cb,
# # # # #
# # # ]
1695 : 0 : req);
1696 : 0 : }
1697 : :
1698 : : void
1699 : 9 : 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 [ - + # # ]: 9 : assert(cb_fn != NULL);
1705 : :
1706 [ - + ]: 9 : 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 : 9 : req = calloc(1, sizeof(*req));
1713 [ - + ]: 9 : 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 [ # # # # ]: 9 : req->cb_fn = cb_fn;
1720 [ # # # # ]: 9 : req->cb_arg = cb_arg;
1721 [ # # # # : 9 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
# # # # #
# # # ]
1722 [ - + # # : 9 : 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 [ # # # # ]: 9 : blob_id = spdk_blob_get_id(lvol->blob);
1730 [ # # # # : 9 : spdk_bs_blob_decouple_parent(lvol->lvol_store->blobstore, req->channel, blob_id,
# # # # #
# # # ]
1731 : 0 : lvol_inflate_cb, req);
1732 : 0 : }
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 : 45 : lvs_get_lvol_by_blob_id(struct spdk_lvol_store *lvs, spdk_blob_id blob_id)
1807 : : {
1808 : : struct spdk_lvol *lvol;
1809 : :
1810 [ + - # # : 62 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
# # # # #
# # # #
# ]
1811 [ + + # # : 62 : if (lvol->blob_id == blob_id) {
# # ]
1812 : 45 : return lvol;
1813 : : }
1814 : 0 : }
1815 : 0 : return NULL;
1816 : 0 : }
1817 : :
1818 : : static int
1819 : 88 : 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 : 88 : struct spdk_lvol_store *lvs = bs_ctx;
1824 : 88 : struct spdk_lvol *lvol = blob_ctx;
1825 : 88 : spdk_blob_id blob_id = spdk_blob_get_id(blob);
1826 : :
1827 [ + + ]: 88 : if (lvs == NULL) {
1828 [ + + - + : 6 : if (lvol == NULL || lvol->lvol_store == NULL) {
# # # # ]
1829 : 3 : SPDK_ERRLOG("Blob 0x%" PRIx64 ": no lvs context nor lvol context\n",
1830 : : blob_id);
1831 : 3 : return -EINVAL;
1832 : : }
1833 [ # # # # ]: 3 : lvs = lvol->lvol_store;
1834 : 0 : }
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 [ + + + + : 85 : if (!lvs->load_esnaps) {
# # # # ]
1844 [ # # ]: 56 : *bs_dev = NULL;
1845 : 56 : return 0;
1846 : : }
1847 : :
1848 [ + + ]: 29 : if (lvol == NULL) {
1849 : 20 : 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 : 20 : lvol = lvs_get_lvol_by_blob_id(lvs, blob_id);
1857 [ - + ]: 20 : 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 : 0 : }
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 : 282 : lvs_esnap_name_cmp(struct spdk_lvs_degraded_lvol_set *m1, struct spdk_lvs_degraded_lvol_set *m2)
1890 : : {
1891 [ + - # # : 282 : if (m1->id_len == m2->id_len) {
# # # # #
# ]
1892 [ - + - + : 282 : return memcmp(m1->esnap_id, m2->esnap_id, m1->id_len);
# # # # #
# # # # #
# # ]
1893 : : }
1894 [ # # # # : 0 : return (m1->id_len > m2->id_len) ? 1 : -1;
# # # # ]
1895 : 0 : }
1896 : :
1897 [ + + + + : 2617 : RB_GENERATE_STATIC(degraded_lvol_sets_tree, spdk_lvs_degraded_lvol_set, node, lvs_esnap_name_cmp)
+ + + + +
+ + + + +
+ + + + -
- - - - -
- + + - -
- - - - -
- - - - -
- - - - -
- - + + -
- - - - -
- - - - -
- - - # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
1898 : :
1899 : : static void
1900 : 122 : lvs_degraded_lvol_set_add(struct spdk_lvs_degraded_lvol_set *degraded_set, struct spdk_lvol *lvol)
1901 : : {
1902 [ - + # # : 122 : assert(lvol->lvol_store->thread == spdk_get_thread());
# # # # #
# # # ]
1903 : :
1904 [ # # # # ]: 122 : lvol->degraded_set = degraded_set;
1905 [ # # # # : 122 : TAILQ_INSERT_TAIL(°raded_set->lvols, lvol, degraded_link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
1906 : 122 : }
1907 : :
1908 : : static void
1909 : 44 : lvs_degraded_lvol_set_remove(struct spdk_lvs_degraded_lvol_set *degraded_set,
1910 : : struct spdk_lvol *lvol)
1911 : : {
1912 [ - + # # : 44 : assert(lvol->lvol_store->thread == spdk_get_thread());
# # # # #
# # # ]
1913 : :
1914 [ # # # # ]: 44 : lvol->degraded_set = NULL;
1915 [ + + # # : 44 : 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 : 44 : }
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 : 115 : 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 [ - + # # : 115 : assert(lvs->thread == spdk_get_thread());
# # # # ]
1931 : :
1932 [ # # ]: 115 : find.esnap_id = esnap_id;
1933 [ # # ]: 115 : find.id_len = id_len;
1934 [ # # ]: 115 : degraded_set = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
1935 [ + + ]: 115 : if (degraded_set == NULL) {
1936 : 55 : degraded_set = calloc(1, sizeof(*degraded_set));
1937 [ - + ]: 55 : 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 [ # # # # ]: 55 : degraded_set->esnap_id = calloc(1, id_len);
1943 [ - + # # : 55 : 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 [ - + - + : 55 : memcpy((void *)degraded_set->esnap_id, esnap_id, id_len);
# # # # ]
1950 [ # # # # ]: 55 : degraded_set->id_len = id_len;
1951 [ # # # # ]: 55 : degraded_set->lvol_store = lvs;
1952 [ # # # # : 55 : TAILQ_INIT(°raded_set->lvols);
# # # # #
# # # # #
# # ]
1953 [ # # ]: 55 : RB_INSERT(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
1954 : 0 : }
1955 : :
1956 : 115 : lvs_degraded_lvol_set_add(degraded_set, lvol);
1957 : :
1958 : 115 : return 0;
1959 : 0 : }
1960 : :
1961 : : /*
1962 : : * Remove the record of the specified lvol needing a degraded_set bdev.
1963 : : */
1964 : : void
1965 : 451 : spdk_lvs_esnap_missing_remove(struct spdk_lvol *lvol)
1966 : : {
1967 [ # # # # ]: 451 : struct spdk_lvol_store *lvs = lvol->lvol_store;
1968 [ # # # # ]: 451 : struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
1969 : :
1970 [ - + # # : 451 : assert(lvs->thread == spdk_get_thread());
# # # # ]
1971 : :
1972 [ + + ]: 451 : if (degraded_set == NULL) {
1973 : 414 : return;
1974 : : }
1975 : :
1976 : 37 : lvs_degraded_lvol_set_remove(degraded_set, lvol);
1977 : :
1978 [ + + # # : 37 : if (!TAILQ_EMPTY(°raded_set->lvols)) {
# # # # ]
1979 : 3 : return;
1980 : : }
1981 : :
1982 [ # # ]: 34 : RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
1983 : :
1984 [ # # # # ]: 34 : free((char *)degraded_set->esnap_id);
1985 : 34 : free(degraded_set);
1986 : 0 : }
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 : 78 : lvs_esnap_hotplug_done(void *cb_arg, int bserrno)
1996 : : {
1997 : 78 : struct lvs_esnap_hotplug_req *req = cb_arg;
1998 [ # # # # ]: 78 : struct spdk_lvol *lvol = req->lvol;
1999 [ # # # # ]: 78 : struct spdk_lvol_store *lvs = lvol->lvol_store;
2000 : :
2001 [ - + ]: 78 : 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 [ # # # # : 78 : req->cb_fn(req->cb_arg, lvol, bserrno);
# # # # #
# # # ]
2006 : 78 : free(req);
2007 : 78 : }
2008 : :
2009 : : static void
2010 : 48 : 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 [ # # # # ]: 48 : 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 [ # # # # ]: 48 : const void *esnap_id = degraded_set->esnap_id;
2017 [ # # # # ]: 48 : uint32_t id_len = degraded_set->id_len;
2018 : : struct lvs_esnap_hotplug_req *req;
2019 : : int rc;
2020 : :
2021 [ - + # # : 48 : 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 [ # # # # : 48 : last_missing = TAILQ_LAST(°raded_set->lvols, degraded_lvols);
# # # # #
# # # ]
2036 : :
2037 [ + - # # : 87 : TAILQ_FOREACH_SAFE(lvol, °raded_set->lvols, degraded_link, tmp) {
# # # # #
# # # # #
# # ]
2038 : 87 : req = calloc(1, sizeof(*req));
2039 [ - + ]: 87 : 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 [ + + # # : 87 : TAILQ_REMOVE(°raded_set->lvols, lvol, degraded_link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
2054 [ # # # # ]: 87 : lvol->degraded_set = NULL;
2055 : :
2056 : 87 : bs_dev = NULL;
2057 [ # # # # : 87 : rc = lvs->esnap_bs_dev_create(lvs, lvol, lvol->blob, esnap_id, id_len, &bs_dev);
# # # # #
# # # ]
2058 [ + + ]: 87 : if (rc != 0) {
2059 [ # # ]: 9 : SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: error %d\n",
2060 : : lvol->unique_id, rc);
2061 [ # # # # ]: 9 : lvol->degraded_set = degraded_set;
2062 [ # # # # : 9 : TAILQ_INSERT_TAIL(°raded_set->lvols, lvol, degraded_link);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
2063 [ # # # # ]: 9 : cb_fn(cb_arg, lvol, rc);
2064 : 9 : free(req);
2065 : 9 : goto next;
2066 : : }
2067 : :
2068 [ # # # # ]: 78 : req->lvol = lvol;
2069 [ # # # # ]: 78 : req->cb_fn = cb_fn;
2070 [ # # # # ]: 78 : req->cb_arg = cb_arg;
2071 [ # # # # ]: 78 : spdk_blob_set_esnap_bs_dev(lvol->blob, bs_dev, lvs_esnap_hotplug_done, req);
2072 : :
2073 : 87 : next:
2074 [ + + ]: 87 : 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 : 48 : break;
2080 : : }
2081 : 0 : }
2082 : :
2083 [ + + # # : 48 : if (TAILQ_EMPTY(°raded_set->lvols)) {
# # # # ]
2084 [ # # ]: 21 : RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
2085 [ # # # # ]: 21 : free((void *)degraded_set->esnap_id);
2086 : 21 : free(degraded_set);
2087 : 0 : }
2088 : 48 : }
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 : 5890 : 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 : 5890 : struct spdk_lvs_degraded_lvol_set find = { 0 };
2100 : : struct spdk_lvol_store *lvs;
2101 : 5890 : struct spdk_thread *thread = spdk_get_thread();
2102 : 5890 : bool ret = false;
2103 : :
2104 [ + - ]: 5890 : find.esnap_id = esnap_id;
2105 [ + - ]: 5890 : find.id_len = id_len;
2106 : :
2107 [ + + ]: 5890 : pthread_mutex_lock(&g_lvol_stores_mutex);
2108 [ + + # # : 7798 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
# # # # ]
2109 [ - + # # : 1908 : 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 [ # # ]: 1908 : found = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
2124 [ + + ]: 1908 : if (found == NULL) {
2125 : 1860 : continue;
2126 : : }
2127 : :
2128 : 48 : ret = true;
2129 : 48 : lvs_esnap_degraded_hotplug(found, cb_fn, cb_arg);
2130 : 0 : }
2131 [ + + ]: 5890 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2132 : :
2133 [ + - ]: 5890 : return ret;
2134 : : }
2135 : :
2136 : : int
2137 : 17 : spdk_lvol_iter_immediate_clones(struct spdk_lvol *lvol, spdk_lvol_iter_cb cb_fn, void *cb_arg)
2138 : : {
2139 [ # # # # ]: 17 : struct spdk_lvol_store *lvs = lvol->lvol_store;
2140 [ # # # # ]: 17 : struct spdk_blob_store *bs = lvs->blobstore;
2141 : : struct spdk_lvol *clone;
2142 : : spdk_blob_id *ids;
2143 : 17 : size_t id_cnt = 0;
2144 : : size_t i;
2145 : : int rc;
2146 : :
2147 [ # # # # ]: 17 : rc = spdk_blob_get_clones(bs, lvol->blob_id, NULL, &id_cnt);
2148 [ + + ]: 17 : if (rc != -ENOMEM) {
2149 : : /* -ENOMEM says id_cnt is valid, no other errors should be returned. */
2150 [ - + # # ]: 6 : assert(rc == 0);
2151 : 6 : return rc;
2152 : : }
2153 : :
2154 : 11 : ids = calloc(id_cnt, sizeof(*ids));
2155 [ - + ]: 11 : 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 [ # # # # ]: 11 : rc = spdk_blob_get_clones(bs, lvol->blob_id, ids, &id_cnt);
2161 [ - + ]: 11 : 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 [ + + ]: 22 : for (i = 0; i < id_cnt; i++) {
2168 [ # # # # ]: 14 : clone = lvs_get_lvol_by_blob_id(lvs, ids[i]);
2169 [ - + ]: 14 : 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 [ # # # # ]: 14 : rc = cb_fn(cb_arg, clone);
2175 [ + + ]: 14 : if (rc != 0) {
2176 [ - + - + : 3 : 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 : 3 : break;
2180 : : }
2181 : 0 : }
2182 : :
2183 : 11 : free(ids);
2184 : 11 : return rc;
2185 : 0 : }
2186 : :
2187 : : struct spdk_lvol *
2188 : 8 : spdk_lvol_get_by_uuid(const struct spdk_uuid *uuid)
2189 : : {
2190 : : struct spdk_lvol_store *lvs;
2191 : : struct spdk_lvol *lvol;
2192 : :
2193 [ - + ]: 8 : pthread_mutex_lock(&g_lvol_stores_mutex);
2194 : :
2195 [ + - # # : 8 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
# # # # ]
2196 [ + - # # : 9 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
# # # # #
# # # #
# ]
2197 [ + + # # ]: 9 : if (spdk_uuid_compare(uuid, &lvol->uuid) == 0) {
2198 [ - + ]: 8 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2199 : 8 : return lvol;
2200 : : }
2201 : 0 : }
2202 : 0 : }
2203 : :
2204 [ # # ]: 0 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2205 : 0 : return NULL;
2206 : 0 : }
2207 : :
2208 : : struct spdk_lvol *
2209 : 983 : 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 [ # # ]: 983 : pthread_mutex_lock(&g_lvol_stores_mutex);
2215 : :
2216 [ + + # # : 1863 : TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
# # # # ]
2217 [ + + - + : 943 : if (strcmp(lvs_name, lvs->name) != 0) {
+ + # # ]
2218 : 9 : continue;
2219 : : }
2220 [ + + # # : 956 : TAILQ_FOREACH(lvol, &lvs->lvols, link) {
# # # # #
# # # #
# ]
2221 [ + + - + : 85 : if (strcmp(lvol_name, lvol->name) == 0) {
+ + # # ]
2222 [ # # ]: 63 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2223 : 63 : return lvol;
2224 : : }
2225 : 0 : }
2226 : 0 : }
2227 : :
2228 [ # # ]: 920 : pthread_mutex_unlock(&g_lvol_stores_mutex);
2229 : 920 : return NULL;
2230 : 0 : }
2231 : :
2232 : : bool
2233 : 955 : spdk_lvol_is_degraded(const struct spdk_lvol *lvol)
2234 : : {
2235 [ # # # # ]: 955 : struct spdk_blob *blob = lvol->blob;
2236 : :
2237 [ - + ]: 955 : if (blob == NULL) {
2238 : 0 : return true;
2239 : : }
2240 : 955 : return spdk_blob_is_degraded(blob);
2241 : 0 : }
2242 : :
2243 : : static void
2244 : 4 : lvol_shallow_copy_cb(void *cb_arg, int lvolerrno)
2245 : : {
2246 : 4 : struct spdk_lvol_copy_req *req = cb_arg;
2247 [ # # # # ]: 4 : struct spdk_lvol *lvol = req->lvol;
2248 : :
2249 [ # # # # ]: 4 : spdk_bs_free_io_channel(req->channel);
2250 : :
2251 [ - + ]: 4 : 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 [ # # # # : 4 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
2256 : 4 : free(req);
2257 : 4 : }
2258 : :
2259 : : int
2260 : 10 : 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 [ - + # # ]: 10 : assert(cb_fn != NULL);
2269 : :
2270 [ + + ]: 10 : if (lvol == NULL) {
2271 : 3 : SPDK_ERRLOG("lvol must not be NULL\n");
2272 : 3 : return -EINVAL;
2273 : : }
2274 : :
2275 [ - + # # : 7 : assert(lvol->lvol_store->thread == spdk_get_thread());
# # # # #
# # # ]
2276 : :
2277 [ + + ]: 7 : if (ext_dev == NULL) {
2278 [ # # ]: 3 : SPDK_ERRLOG("lvol %s shallow copy, ext_dev must not be NULL\n", lvol->unique_id);
2279 : 3 : return -EINVAL;
2280 : : }
2281 : :
2282 : 4 : req = calloc(1, sizeof(*req));
2283 [ - + ]: 4 : 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 [ # # # # ]: 4 : req->lvol = lvol;
2289 [ # # # # ]: 4 : req->cb_fn = cb_fn;
2290 [ # # # # ]: 4 : req->cb_arg = cb_arg;
2291 [ # # # # : 4 : req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
# # # # #
# # # ]
2292 [ - + # # : 4 : 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 [ # # # # ]: 4 : blob_id = spdk_blob_get_id(lvol->blob);
2299 : :
2300 [ # # # # : 4 : rc = spdk_bs_blob_shallow_copy(lvol->lvol_store->blobstore, req->channel, blob_id, ext_dev,
# # # # #
# # # ]
2301 : 0 : status_cb_fn, status_cb_arg, lvol_shallow_copy_cb, req);
2302 : :
2303 [ - + ]: 4 : 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 : 4 : return rc;
2310 : 0 : }
2311 : :
2312 : : static void
2313 : 10 : lvol_set_parent_cb(void *cb_arg, int lvolerrno)
2314 : : {
2315 : 10 : struct spdk_lvol_req *req = cb_arg;
2316 : :
2317 [ + + ]: 10 : 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 [ # # # # : 10 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
2322 : 10 : free(req);
2323 : 10 : }
2324 : :
2325 : : void
2326 : 16 : 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 [ - + # # ]: 16 : assert(cb_fn != NULL);
2333 : :
2334 [ + + ]: 16 : if (lvol == NULL) {
2335 : 3 : SPDK_ERRLOG("lvol must not be NULL\n");
2336 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2337 : 3 : return;
2338 : : }
2339 : :
2340 [ + + ]: 13 : if (snapshot == NULL) {
2341 : 3 : SPDK_ERRLOG("snapshot must not be NULL\n");
2342 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2343 : 3 : return;
2344 : : }
2345 : :
2346 : 10 : req = calloc(1, sizeof(*req));
2347 [ - + ]: 10 : 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 [ # # # # ]: 10 : req->lvol = lvol;
2354 [ # # # # ]: 10 : req->cb_fn = cb_fn;
2355 [ # # # # ]: 10 : req->cb_arg = cb_arg;
2356 : :
2357 [ # # # # ]: 10 : blob_id = spdk_blob_get_id(lvol->blob);
2358 [ # # # # ]: 10 : snapshot_id = spdk_blob_get_id(snapshot->blob);
2359 : :
2360 [ # # # # : 10 : spdk_bs_blob_set_parent(lvol->lvol_store->blobstore, blob_id, snapshot_id,
# # # # ]
2361 : 0 : lvol_set_parent_cb, req);
2362 : 0 : }
2363 : :
2364 : : static void
2365 : 9 : lvol_set_external_parent_cb(void *cb_arg, int lvolerrno)
2366 : : {
2367 : 9 : struct spdk_lvol_bs_dev_req *req = cb_arg;
2368 : :
2369 [ + + ]: 9 : 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 [ # # # # : 9 : req->cb_fn(req->cb_arg, lvolerrno);
# # # # #
# # # ]
2375 : 9 : free(req);
2376 : 9 : }
2377 : :
2378 : : void
2379 : 18 : 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 [ - + # # ]: 18 : assert(cb_fn != NULL);
2388 : :
2389 [ + + ]: 18 : if (lvol == NULL) {
2390 : 3 : SPDK_ERRLOG("lvol must not be NULL\n");
2391 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2392 : 3 : return;
2393 : : }
2394 : :
2395 [ + + ]: 15 : if (esnap_id == NULL) {
2396 : 3 : SPDK_ERRLOG("snapshot must not be NULL\n");
2397 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2398 : 3 : return;
2399 : : }
2400 : :
2401 [ + - # # ]: 12 : if (esnap_id_len == sizeof(lvol->uuid_str) &&
2402 [ + + - + : 12 : memcmp(esnap_id, lvol->uuid_str, esnap_id_len) == 0) {
+ + ]
2403 [ # # ]: 3 : SPDK_ERRLOG("lvol %s and esnap have the same UUID\n", lvol->name);
2404 [ # # # # ]: 3 : cb_fn(cb_arg, -EINVAL);
2405 : 3 : return;
2406 : : }
2407 : :
2408 [ # # # # : 9 : rc = lvs_esnap_bs_dev_create(lvol->lvol_store, lvol, lvol->blob, esnap_id, esnap_id_len, &bs_dev);
# # # # ]
2409 [ - + ]: 9 : if (rc < 0) {
2410 [ # # # # ]: 0 : cb_fn(cb_arg, rc);
2411 : 0 : return;
2412 : : }
2413 : :
2414 : 9 : req = calloc(1, sizeof(*req));
2415 [ - + ]: 9 : 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 [ # # # # ]: 9 : req->lvol = lvol;
2422 [ # # # # ]: 9 : req->bs_dev = bs_dev;
2423 [ # # # # ]: 9 : req->cb_fn = cb_fn;
2424 [ # # # # ]: 9 : req->cb_arg = cb_arg;
2425 : :
2426 [ # # # # ]: 9 : blob_id = spdk_blob_get_id(lvol->blob);
2427 : :
2428 [ # # # # : 9 : spdk_bs_blob_set_external_parent(lvol->lvol_store->blobstore, blob_id, bs_dev, esnap_id,
# # # # ]
2429 : 0 : esnap_id_len, lvol_set_external_parent_cb, req);
2430 : 0 : }
|