xref: /spdk/module/bdev/lvol/vbdev_lvol_rpc.c (revision 4237d2d8cb14e5e52ede3ed9718019488b445afe)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/rpc.h"
35 #include "spdk/bdev.h"
36 #include "spdk/util.h"
37 #include "vbdev_lvol.h"
38 #include "spdk/string.h"
39 #include "spdk/log.h"
40 
41 SPDK_LOG_REGISTER_COMPONENT(lvol_rpc)
42 
43 struct rpc_bdev_lvol_create_lvstore {
44 	char *lvs_name;
45 	char *bdev_name;
46 	uint32_t cluster_sz;
47 	char *clear_method;
48 };
49 
50 static int
51 vbdev_get_lvol_store_by_uuid_xor_name(const char *uuid, const char *lvs_name,
52 				      struct spdk_lvol_store **lvs)
53 {
54 	if ((uuid == NULL && lvs_name == NULL)) {
55 		SPDK_INFOLOG(lvol_rpc, "lvs UUID nor lvs name specified\n");
56 		return -EINVAL;
57 	} else if ((uuid && lvs_name)) {
58 		SPDK_INFOLOG(lvol_rpc, "both lvs UUID '%s' and lvs name '%s' specified\n", uuid,
59 			     lvs_name);
60 		return -EINVAL;
61 	} else if (uuid) {
62 		*lvs = vbdev_get_lvol_store_by_uuid(uuid);
63 
64 		if (*lvs == NULL) {
65 			SPDK_INFOLOG(lvol_rpc, "blobstore with UUID '%s' not found\n", uuid);
66 			return -ENODEV;
67 		}
68 	} else if (lvs_name) {
69 
70 		*lvs = vbdev_get_lvol_store_by_name(lvs_name);
71 
72 		if (*lvs == NULL) {
73 			SPDK_INFOLOG(lvol_rpc, "blobstore with name '%s' not found\n", lvs_name);
74 			return -ENODEV;
75 		}
76 	}
77 	return 0;
78 }
79 
80 static void
81 free_rpc_bdev_lvol_create_lvstore(struct rpc_bdev_lvol_create_lvstore *req)
82 {
83 	free(req->bdev_name);
84 	free(req->lvs_name);
85 	free(req->clear_method);
86 }
87 
88 static const struct spdk_json_object_decoder rpc_bdev_lvol_create_lvstore_decoders[] = {
89 	{"bdev_name", offsetof(struct rpc_bdev_lvol_create_lvstore, bdev_name), spdk_json_decode_string},
90 	{"cluster_sz", offsetof(struct rpc_bdev_lvol_create_lvstore, cluster_sz), spdk_json_decode_uint32, true},
91 	{"lvs_name", offsetof(struct rpc_bdev_lvol_create_lvstore, lvs_name), spdk_json_decode_string},
92 	{"clear_method", offsetof(struct rpc_bdev_lvol_create_lvstore, clear_method), spdk_json_decode_string, true},
93 };
94 
95 static void
96 rpc_lvol_store_construct_cb(void *cb_arg, struct spdk_lvol_store *lvol_store, int lvserrno)
97 {
98 	struct spdk_json_write_ctx *w;
99 	char lvol_store_uuid[SPDK_UUID_STRING_LEN];
100 	struct spdk_jsonrpc_request *request = cb_arg;
101 
102 	if (lvserrno != 0) {
103 		goto invalid;
104 	}
105 
106 	spdk_uuid_fmt_lower(lvol_store_uuid, sizeof(lvol_store_uuid), &lvol_store->uuid);
107 
108 	w = spdk_jsonrpc_begin_result(request);
109 	spdk_json_write_string(w, lvol_store_uuid);
110 	spdk_jsonrpc_end_result(request, w);
111 	return;
112 
113 invalid:
114 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
115 					 spdk_strerror(-lvserrno));
116 }
117 
118 static void
119 rpc_bdev_lvol_create_lvstore(struct spdk_jsonrpc_request *request,
120 			     const struct spdk_json_val *params)
121 {
122 	struct rpc_bdev_lvol_create_lvstore req = {};
123 	int rc = 0;
124 	enum lvs_clear_method clear_method;
125 
126 	if (spdk_json_decode_object(params, rpc_bdev_lvol_create_lvstore_decoders,
127 				    SPDK_COUNTOF(rpc_bdev_lvol_create_lvstore_decoders),
128 				    &req)) {
129 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
130 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
131 						 "spdk_json_decode_object failed");
132 		goto cleanup;
133 	}
134 
135 	if (req.clear_method != NULL) {
136 		if (!strcasecmp(req.clear_method, "none")) {
137 			clear_method = LVS_CLEAR_WITH_NONE;
138 		} else if (!strcasecmp(req.clear_method, "unmap")) {
139 			clear_method = LVS_CLEAR_WITH_UNMAP;
140 		} else if (!strcasecmp(req.clear_method, "write_zeroes")) {
141 			clear_method = LVS_CLEAR_WITH_WRITE_ZEROES;
142 		} else {
143 			spdk_jsonrpc_send_error_response(request, -EINVAL, "Invalid clear_method parameter");
144 			goto cleanup;
145 		}
146 	} else {
147 		clear_method = LVS_CLEAR_WITH_UNMAP;
148 	}
149 
150 	rc = vbdev_lvs_create(req.bdev_name, req.lvs_name, req.cluster_sz, clear_method,
151 			      rpc_lvol_store_construct_cb, request);
152 	if (rc < 0) {
153 		spdk_jsonrpc_send_error_response(request, -rc, spdk_strerror(rc));
154 		goto cleanup;
155 	}
156 	free_rpc_bdev_lvol_create_lvstore(&req);
157 
158 	return;
159 
160 cleanup:
161 	free_rpc_bdev_lvol_create_lvstore(&req);
162 }
163 SPDK_RPC_REGISTER("bdev_lvol_create_lvstore", rpc_bdev_lvol_create_lvstore, SPDK_RPC_RUNTIME)
164 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_create_lvstore, construct_lvol_store)
165 
166 struct rpc_bdev_lvol_rename_lvstore {
167 	char *old_name;
168 	char *new_name;
169 };
170 
171 static void
172 free_rpc_bdev_lvol_rename_lvstore(struct rpc_bdev_lvol_rename_lvstore *req)
173 {
174 	free(req->old_name);
175 	free(req->new_name);
176 }
177 
178 static const struct spdk_json_object_decoder rpc_bdev_lvol_rename_lvstore_decoders[] = {
179 	{"old_name", offsetof(struct rpc_bdev_lvol_rename_lvstore, old_name), spdk_json_decode_string},
180 	{"new_name", offsetof(struct rpc_bdev_lvol_rename_lvstore, new_name), spdk_json_decode_string},
181 };
182 
183 static void
184 rpc_bdev_lvol_rename_lvstore_cb(void *cb_arg, int lvserrno)
185 {
186 	struct spdk_json_write_ctx *w;
187 	struct spdk_jsonrpc_request *request = cb_arg;
188 
189 	if (lvserrno != 0) {
190 		goto invalid;
191 	}
192 
193 	w = spdk_jsonrpc_begin_result(request);
194 	spdk_json_write_bool(w, true);
195 	spdk_jsonrpc_end_result(request, w);
196 	return;
197 
198 invalid:
199 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
200 					 spdk_strerror(-lvserrno));
201 }
202 
203 static void
204 rpc_bdev_lvol_rename_lvstore(struct spdk_jsonrpc_request *request,
205 			     const struct spdk_json_val *params)
206 {
207 	struct rpc_bdev_lvol_rename_lvstore req = {};
208 	struct spdk_lvol_store *lvs;
209 
210 	if (spdk_json_decode_object(params, rpc_bdev_lvol_rename_lvstore_decoders,
211 				    SPDK_COUNTOF(rpc_bdev_lvol_rename_lvstore_decoders),
212 				    &req)) {
213 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
214 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
215 						 "spdk_json_decode_object failed");
216 		goto cleanup;
217 	}
218 
219 	lvs = vbdev_get_lvol_store_by_name(req.old_name);
220 	if (lvs == NULL) {
221 		SPDK_INFOLOG(lvol_rpc, "no lvs existing for given name\n");
222 		spdk_jsonrpc_send_error_response_fmt(request, -ENOENT, "Lvol store %s not found", req.old_name);
223 		goto cleanup;
224 	}
225 
226 	vbdev_lvs_rename(lvs, req.new_name, rpc_bdev_lvol_rename_lvstore_cb, request);
227 
228 cleanup:
229 	free_rpc_bdev_lvol_rename_lvstore(&req);
230 }
231 SPDK_RPC_REGISTER("bdev_lvol_rename_lvstore", rpc_bdev_lvol_rename_lvstore, SPDK_RPC_RUNTIME)
232 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_rename_lvstore, rename_lvol_store)
233 
234 struct rpc_bdev_lvol_delete_lvstore {
235 	char *uuid;
236 	char *lvs_name;
237 };
238 
239 static void
240 free_rpc_bdev_lvol_delete_lvstore(struct rpc_bdev_lvol_delete_lvstore *req)
241 {
242 	free(req->uuid);
243 	free(req->lvs_name);
244 }
245 
246 static const struct spdk_json_object_decoder rpc_bdev_lvol_delete_lvstore_decoders[] = {
247 	{"uuid", offsetof(struct rpc_bdev_lvol_delete_lvstore, uuid), spdk_json_decode_string, true},
248 	{"lvs_name", offsetof(struct rpc_bdev_lvol_delete_lvstore, lvs_name), spdk_json_decode_string, true},
249 };
250 
251 static void
252 rpc_lvol_store_destroy_cb(void *cb_arg, int lvserrno)
253 {
254 	struct spdk_json_write_ctx *w;
255 	struct spdk_jsonrpc_request *request = cb_arg;
256 
257 	if (lvserrno != 0) {
258 		goto invalid;
259 	}
260 
261 	w = spdk_jsonrpc_begin_result(request);
262 	spdk_json_write_bool(w, true);
263 	spdk_jsonrpc_end_result(request, w);
264 	return;
265 
266 invalid:
267 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
268 					 spdk_strerror(-lvserrno));
269 }
270 
271 static void
272 rpc_bdev_lvol_delete_lvstore(struct spdk_jsonrpc_request *request,
273 			     const struct spdk_json_val *params)
274 {
275 	struct rpc_bdev_lvol_delete_lvstore req = {};
276 	struct spdk_lvol_store *lvs = NULL;
277 	int rc;
278 
279 	if (spdk_json_decode_object(params, rpc_bdev_lvol_delete_lvstore_decoders,
280 				    SPDK_COUNTOF(rpc_bdev_lvol_delete_lvstore_decoders),
281 				    &req)) {
282 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
283 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
284 						 "spdk_json_decode_object failed");
285 		goto cleanup;
286 	}
287 
288 	rc = vbdev_get_lvol_store_by_uuid_xor_name(req.uuid, req.lvs_name, &lvs);
289 	if (rc != 0) {
290 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
291 		goto cleanup;
292 	}
293 
294 	vbdev_lvs_destruct(lvs, rpc_lvol_store_destroy_cb, request);
295 
296 cleanup:
297 	free_rpc_bdev_lvol_delete_lvstore(&req);
298 }
299 SPDK_RPC_REGISTER("bdev_lvol_delete_lvstore", rpc_bdev_lvol_delete_lvstore, SPDK_RPC_RUNTIME)
300 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_delete_lvstore, destroy_lvol_store)
301 
302 struct rpc_bdev_lvol_create {
303 	char *uuid;
304 	char *lvs_name;
305 	char *lvol_name;
306 	uint64_t size;
307 	bool thin_provision;
308 	char *clear_method;
309 };
310 
311 static void
312 free_rpc_bdev_lvol_create(struct rpc_bdev_lvol_create *req)
313 {
314 	free(req->uuid);
315 	free(req->lvs_name);
316 	free(req->lvol_name);
317 	free(req->clear_method);
318 }
319 
320 static const struct spdk_json_object_decoder rpc_bdev_lvol_create_decoders[] = {
321 	{"uuid", offsetof(struct rpc_bdev_lvol_create, uuid), spdk_json_decode_string, true},
322 	{"lvs_name", offsetof(struct rpc_bdev_lvol_create, lvs_name), spdk_json_decode_string, true},
323 	{"lvol_name", offsetof(struct rpc_bdev_lvol_create, lvol_name), spdk_json_decode_string},
324 	{"size", offsetof(struct rpc_bdev_lvol_create, size), spdk_json_decode_uint64},
325 	{"thin_provision", offsetof(struct rpc_bdev_lvol_create, thin_provision), spdk_json_decode_bool, true},
326 	{"clear_method", offsetof(struct rpc_bdev_lvol_create, clear_method), spdk_json_decode_string, true},
327 };
328 
329 static void
330 rpc_bdev_lvol_create_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno)
331 {
332 	struct spdk_json_write_ctx *w;
333 	struct spdk_jsonrpc_request *request = cb_arg;
334 
335 	if (lvolerrno != 0) {
336 		goto invalid;
337 	}
338 
339 	w = spdk_jsonrpc_begin_result(request);
340 	spdk_json_write_string(w, lvol->unique_id);
341 	spdk_jsonrpc_end_result(request, w);
342 	return;
343 
344 invalid:
345 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
346 					 spdk_strerror(-lvolerrno));
347 }
348 
349 static void
350 rpc_bdev_lvol_create(struct spdk_jsonrpc_request *request,
351 		     const struct spdk_json_val *params)
352 {
353 	struct rpc_bdev_lvol_create req = {};
354 	enum lvol_clear_method clear_method;
355 	int rc = 0;
356 	struct spdk_lvol_store *lvs = NULL;
357 
358 	SPDK_INFOLOG(lvol_rpc, "Creating blob\n");
359 
360 	if (spdk_json_decode_object(params, rpc_bdev_lvol_create_decoders,
361 				    SPDK_COUNTOF(rpc_bdev_lvol_create_decoders),
362 				    &req)) {
363 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
364 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
365 						 "spdk_json_decode_object failed");
366 		goto cleanup;
367 	}
368 
369 	rc = vbdev_get_lvol_store_by_uuid_xor_name(req.uuid, req.lvs_name, &lvs);
370 	if (rc != 0) {
371 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
372 		goto cleanup;
373 	}
374 
375 	if (req.clear_method != NULL) {
376 		if (!strcasecmp(req.clear_method, "none")) {
377 			clear_method = LVOL_CLEAR_WITH_NONE;
378 		} else if (!strcasecmp(req.clear_method, "unmap")) {
379 			clear_method = LVOL_CLEAR_WITH_UNMAP;
380 		} else if (!strcasecmp(req.clear_method, "write_zeroes")) {
381 			clear_method = LVOL_CLEAR_WITH_WRITE_ZEROES;
382 		} else {
383 			spdk_jsonrpc_send_error_response(request, -EINVAL, "Invalid clean_method option");
384 			goto cleanup;
385 		}
386 	} else {
387 		clear_method = LVOL_CLEAR_WITH_DEFAULT;
388 	}
389 
390 	rc = vbdev_lvol_create(lvs, req.lvol_name, req.size, req.thin_provision,
391 			       clear_method, rpc_bdev_lvol_create_cb, request);
392 	if (rc < 0) {
393 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
394 		goto cleanup;
395 	}
396 
397 cleanup:
398 	free_rpc_bdev_lvol_create(&req);
399 }
400 
401 SPDK_RPC_REGISTER("bdev_lvol_create", rpc_bdev_lvol_create, SPDK_RPC_RUNTIME)
402 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_create, construct_lvol_bdev)
403 
404 struct rpc_bdev_lvol_snapshot {
405 	char *lvol_name;
406 	char *snapshot_name;
407 };
408 
409 static void
410 free_rpc_bdev_lvol_snapshot(struct rpc_bdev_lvol_snapshot *req)
411 {
412 	free(req->lvol_name);
413 	free(req->snapshot_name);
414 }
415 
416 static const struct spdk_json_object_decoder rpc_bdev_lvol_snapshot_decoders[] = {
417 	{"lvol_name", offsetof(struct rpc_bdev_lvol_snapshot, lvol_name), spdk_json_decode_string},
418 	{"snapshot_name", offsetof(struct rpc_bdev_lvol_snapshot, snapshot_name), spdk_json_decode_string},
419 };
420 
421 static void
422 rpc_bdev_lvol_snapshot_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno)
423 {
424 	struct spdk_json_write_ctx *w;
425 	struct spdk_jsonrpc_request *request = cb_arg;
426 
427 	if (lvolerrno != 0) {
428 		goto invalid;
429 	}
430 
431 	w = spdk_jsonrpc_begin_result(request);
432 	spdk_json_write_string(w, lvol->unique_id);
433 	spdk_jsonrpc_end_result(request, w);
434 	return;
435 
436 invalid:
437 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
438 					 spdk_strerror(-lvolerrno));
439 }
440 
441 static void
442 rpc_bdev_lvol_snapshot(struct spdk_jsonrpc_request *request,
443 		       const struct spdk_json_val *params)
444 {
445 	struct rpc_bdev_lvol_snapshot req = {};
446 	struct spdk_bdev *bdev;
447 	struct spdk_lvol *lvol;
448 
449 	SPDK_INFOLOG(lvol_rpc, "Snapshotting blob\n");
450 
451 	if (spdk_json_decode_object(params, rpc_bdev_lvol_snapshot_decoders,
452 				    SPDK_COUNTOF(rpc_bdev_lvol_snapshot_decoders),
453 				    &req)) {
454 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
455 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
456 						 "spdk_json_decode_object failed");
457 		goto cleanup;
458 	}
459 
460 	bdev = spdk_bdev_get_by_name(req.lvol_name);
461 	if (bdev == NULL) {
462 		SPDK_INFOLOG(lvol_rpc, "bdev '%s' does not exist\n", req.lvol_name);
463 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
464 		goto cleanup;
465 	}
466 
467 	lvol = vbdev_lvol_get_from_bdev(bdev);
468 	if (lvol == NULL) {
469 		SPDK_ERRLOG("lvol does not exist\n");
470 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
471 		goto cleanup;
472 	}
473 
474 	vbdev_lvol_create_snapshot(lvol, req.snapshot_name, rpc_bdev_lvol_snapshot_cb, request);
475 
476 cleanup:
477 	free_rpc_bdev_lvol_snapshot(&req);
478 }
479 
480 SPDK_RPC_REGISTER("bdev_lvol_snapshot", rpc_bdev_lvol_snapshot, SPDK_RPC_RUNTIME)
481 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_snapshot, snapshot_lvol_bdev)
482 
483 struct rpc_bdev_lvol_clone {
484 	char *snapshot_name;
485 	char *clone_name;
486 };
487 
488 static void
489 free_rpc_bdev_lvol_clone(struct rpc_bdev_lvol_clone *req)
490 {
491 	free(req->snapshot_name);
492 	free(req->clone_name);
493 }
494 
495 static const struct spdk_json_object_decoder rpc_bdev_lvol_clone_decoders[] = {
496 	{"snapshot_name", offsetof(struct rpc_bdev_lvol_clone, snapshot_name), spdk_json_decode_string},
497 	{"clone_name", offsetof(struct rpc_bdev_lvol_clone, clone_name), spdk_json_decode_string, true},
498 };
499 
500 static void
501 rpc_bdev_lvol_clone_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno)
502 {
503 	struct spdk_json_write_ctx *w;
504 	struct spdk_jsonrpc_request *request = cb_arg;
505 
506 	if (lvolerrno != 0) {
507 		goto invalid;
508 	}
509 
510 	w = spdk_jsonrpc_begin_result(request);
511 	spdk_json_write_string(w, lvol->unique_id);
512 	spdk_jsonrpc_end_result(request, w);
513 	return;
514 
515 invalid:
516 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
517 					 spdk_strerror(-lvolerrno));
518 }
519 
520 static void
521 rpc_bdev_lvol_clone(struct spdk_jsonrpc_request *request,
522 		    const struct spdk_json_val *params)
523 {
524 	struct rpc_bdev_lvol_clone req = {};
525 	struct spdk_bdev *bdev;
526 	struct spdk_lvol *lvol;
527 
528 	SPDK_INFOLOG(lvol_rpc, "Cloning blob\n");
529 
530 	if (spdk_json_decode_object(params, rpc_bdev_lvol_clone_decoders,
531 				    SPDK_COUNTOF(rpc_bdev_lvol_clone_decoders),
532 				    &req)) {
533 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
534 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
535 						 "spdk_json_decode_object failed");
536 		goto cleanup;
537 	}
538 
539 	bdev = spdk_bdev_get_by_name(req.snapshot_name);
540 	if (bdev == NULL) {
541 		SPDK_INFOLOG(lvol_rpc, "bdev '%s' does not exist\n", req.snapshot_name);
542 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
543 		goto cleanup;
544 	}
545 
546 	lvol = vbdev_lvol_get_from_bdev(bdev);
547 	if (lvol == NULL) {
548 		SPDK_ERRLOG("lvol does not exist\n");
549 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
550 		goto cleanup;
551 	}
552 
553 	vbdev_lvol_create_clone(lvol, req.clone_name, rpc_bdev_lvol_clone_cb, request);
554 
555 cleanup:
556 	free_rpc_bdev_lvol_clone(&req);
557 }
558 
559 SPDK_RPC_REGISTER("bdev_lvol_clone", rpc_bdev_lvol_clone, SPDK_RPC_RUNTIME)
560 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_clone, clone_lvol_bdev)
561 
562 struct rpc_bdev_lvol_rename {
563 	char *old_name;
564 	char *new_name;
565 };
566 
567 static void
568 free_rpc_bdev_lvol_rename(struct rpc_bdev_lvol_rename *req)
569 {
570 	free(req->old_name);
571 	free(req->new_name);
572 }
573 
574 static const struct spdk_json_object_decoder rpc_bdev_lvol_rename_decoders[] = {
575 	{"old_name", offsetof(struct rpc_bdev_lvol_rename, old_name), spdk_json_decode_string},
576 	{"new_name", offsetof(struct rpc_bdev_lvol_rename, new_name), spdk_json_decode_string},
577 };
578 
579 static void
580 rpc_bdev_lvol_rename_cb(void *cb_arg, int lvolerrno)
581 {
582 	struct spdk_json_write_ctx *w;
583 	struct spdk_jsonrpc_request *request = cb_arg;
584 
585 	if (lvolerrno != 0) {
586 		goto invalid;
587 	}
588 
589 	w = spdk_jsonrpc_begin_result(request);
590 	spdk_json_write_bool(w, true);
591 	spdk_jsonrpc_end_result(request, w);
592 	return;
593 
594 invalid:
595 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
596 					 spdk_strerror(-lvolerrno));
597 }
598 
599 static void
600 rpc_bdev_lvol_rename(struct spdk_jsonrpc_request *request,
601 		     const struct spdk_json_val *params)
602 {
603 	struct rpc_bdev_lvol_rename req = {};
604 	struct spdk_bdev *bdev;
605 	struct spdk_lvol *lvol;
606 
607 	SPDK_INFOLOG(lvol_rpc, "Renaming lvol\n");
608 
609 	if (spdk_json_decode_object(params, rpc_bdev_lvol_rename_decoders,
610 				    SPDK_COUNTOF(rpc_bdev_lvol_rename_decoders),
611 				    &req)) {
612 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
613 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
614 						 "spdk_json_decode_object failed");
615 		goto cleanup;
616 	}
617 
618 	bdev = spdk_bdev_get_by_name(req.old_name);
619 	if (bdev == NULL) {
620 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.old_name);
621 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
622 		goto cleanup;
623 	}
624 
625 	lvol = vbdev_lvol_get_from_bdev(bdev);
626 	if (lvol == NULL) {
627 		SPDK_ERRLOG("lvol does not exist\n");
628 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
629 		goto cleanup;
630 	}
631 
632 	vbdev_lvol_rename(lvol, req.new_name, rpc_bdev_lvol_rename_cb, request);
633 
634 cleanup:
635 	free_rpc_bdev_lvol_rename(&req);
636 }
637 
638 SPDK_RPC_REGISTER("bdev_lvol_rename", rpc_bdev_lvol_rename, SPDK_RPC_RUNTIME)
639 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_rename, rename_lvol_bdev)
640 
641 struct rpc_bdev_lvol_inflate {
642 	char *name;
643 };
644 
645 static void
646 free_rpc_bdev_lvol_inflate(struct rpc_bdev_lvol_inflate *req)
647 {
648 	free(req->name);
649 }
650 
651 static const struct spdk_json_object_decoder rpc_bdev_lvol_inflate_decoders[] = {
652 	{"name", offsetof(struct rpc_bdev_lvol_inflate, name), spdk_json_decode_string},
653 };
654 
655 static void
656 rpc_bdev_lvol_inflate_cb(void *cb_arg, int lvolerrno)
657 {
658 	struct spdk_json_write_ctx *w;
659 	struct spdk_jsonrpc_request *request = cb_arg;
660 
661 	if (lvolerrno != 0) {
662 		goto invalid;
663 	}
664 
665 	w = spdk_jsonrpc_begin_result(request);
666 	spdk_json_write_bool(w, true);
667 	spdk_jsonrpc_end_result(request, w);
668 	return;
669 
670 invalid:
671 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
672 					 spdk_strerror(-lvolerrno));
673 }
674 
675 static void
676 rpc_bdev_lvol_inflate(struct spdk_jsonrpc_request *request,
677 		      const struct spdk_json_val *params)
678 {
679 	struct rpc_bdev_lvol_inflate req = {};
680 	struct spdk_bdev *bdev;
681 	struct spdk_lvol *lvol;
682 
683 	SPDK_INFOLOG(lvol_rpc, "Inflating lvol\n");
684 
685 	if (spdk_json_decode_object(params, rpc_bdev_lvol_inflate_decoders,
686 				    SPDK_COUNTOF(rpc_bdev_lvol_inflate_decoders),
687 				    &req)) {
688 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
689 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
690 						 "spdk_json_decode_object failed");
691 		goto cleanup;
692 	}
693 
694 	bdev = spdk_bdev_get_by_name(req.name);
695 	if (bdev == NULL) {
696 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
697 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
698 		goto cleanup;
699 	}
700 
701 	lvol = vbdev_lvol_get_from_bdev(bdev);
702 	if (lvol == NULL) {
703 		SPDK_ERRLOG("lvol does not exist\n");
704 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
705 		goto cleanup;
706 	}
707 
708 	spdk_lvol_inflate(lvol, rpc_bdev_lvol_inflate_cb, request);
709 
710 cleanup:
711 	free_rpc_bdev_lvol_inflate(&req);
712 }
713 
714 SPDK_RPC_REGISTER("bdev_lvol_inflate", rpc_bdev_lvol_inflate, SPDK_RPC_RUNTIME)
715 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_inflate, inflate_lvol_bdev)
716 
717 static void
718 rpc_bdev_lvol_decouple_parent(struct spdk_jsonrpc_request *request,
719 			      const struct spdk_json_val *params)
720 {
721 	struct rpc_bdev_lvol_inflate req = {};
722 	struct spdk_bdev *bdev;
723 	struct spdk_lvol *lvol;
724 
725 	SPDK_INFOLOG(lvol_rpc, "Decoupling parent of lvol\n");
726 
727 	if (spdk_json_decode_object(params, rpc_bdev_lvol_inflate_decoders,
728 				    SPDK_COUNTOF(rpc_bdev_lvol_inflate_decoders),
729 				    &req)) {
730 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
731 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
732 						 "spdk_json_decode_object failed");
733 		goto cleanup;
734 	}
735 
736 	bdev = spdk_bdev_get_by_name(req.name);
737 	if (bdev == NULL) {
738 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
739 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
740 		goto cleanup;
741 	}
742 
743 	lvol = vbdev_lvol_get_from_bdev(bdev);
744 	if (lvol == NULL) {
745 		SPDK_ERRLOG("lvol does not exist\n");
746 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
747 		goto cleanup;
748 	}
749 
750 	spdk_lvol_decouple_parent(lvol, rpc_bdev_lvol_inflate_cb, request);
751 
752 cleanup:
753 	free_rpc_bdev_lvol_inflate(&req);
754 }
755 
756 SPDK_RPC_REGISTER("bdev_lvol_decouple_parent", rpc_bdev_lvol_decouple_parent, SPDK_RPC_RUNTIME)
757 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_decouple_parent, decouple_parent_lvol_bdev)
758 
759 struct rpc_bdev_lvol_resize {
760 	char *name;
761 	uint64_t size;
762 };
763 
764 static void
765 free_rpc_bdev_lvol_resize(struct rpc_bdev_lvol_resize *req)
766 {
767 	free(req->name);
768 }
769 
770 static const struct spdk_json_object_decoder rpc_bdev_lvol_resize_decoders[] = {
771 	{"name", offsetof(struct rpc_bdev_lvol_resize, name), spdk_json_decode_string},
772 	{"size", offsetof(struct rpc_bdev_lvol_resize, size), spdk_json_decode_uint64},
773 };
774 
775 static void
776 rpc_bdev_lvol_resize_cb(void *cb_arg, int lvolerrno)
777 {
778 	struct spdk_json_write_ctx *w;
779 	struct spdk_jsonrpc_request *request = cb_arg;
780 
781 	if (lvolerrno != 0) {
782 		goto invalid;
783 	}
784 
785 	w = spdk_jsonrpc_begin_result(request);
786 	spdk_json_write_bool(w, true);
787 	spdk_jsonrpc_end_result(request, w);
788 	return;
789 
790 invalid:
791 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
792 					 spdk_strerror(-lvolerrno));
793 }
794 
795 static void
796 rpc_bdev_lvol_resize(struct spdk_jsonrpc_request *request,
797 		     const struct spdk_json_val *params)
798 {
799 	struct rpc_bdev_lvol_resize req = {};
800 	struct spdk_bdev *bdev;
801 	struct spdk_lvol *lvol;
802 
803 	SPDK_INFOLOG(lvol_rpc, "Resizing lvol\n");
804 
805 	if (spdk_json_decode_object(params, rpc_bdev_lvol_resize_decoders,
806 				    SPDK_COUNTOF(rpc_bdev_lvol_resize_decoders),
807 				    &req)) {
808 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
809 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
810 						 "spdk_json_decode_object failed");
811 		goto cleanup;
812 	}
813 
814 	bdev = spdk_bdev_get_by_name(req.name);
815 	if (bdev == NULL) {
816 		SPDK_ERRLOG("no bdev for provided name %s\n", req.name);
817 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
818 		goto cleanup;
819 	}
820 
821 	lvol = vbdev_lvol_get_from_bdev(bdev);
822 	if (lvol == NULL) {
823 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
824 		goto cleanup;
825 	}
826 
827 	vbdev_lvol_resize(lvol, req.size, rpc_bdev_lvol_resize_cb, request);
828 
829 cleanup:
830 	free_rpc_bdev_lvol_resize(&req);
831 }
832 
833 SPDK_RPC_REGISTER("bdev_lvol_resize", rpc_bdev_lvol_resize, SPDK_RPC_RUNTIME)
834 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_resize, resize_lvol_bdev)
835 
836 struct rpc_set_ro_lvol_bdev {
837 	char *name;
838 };
839 
840 static void
841 free_rpc_set_ro_lvol_bdev(struct rpc_set_ro_lvol_bdev *req)
842 {
843 	free(req->name);
844 }
845 
846 static const struct spdk_json_object_decoder rpc_set_ro_lvol_bdev_decoders[] = {
847 	{"name", offsetof(struct rpc_set_ro_lvol_bdev, name), spdk_json_decode_string},
848 };
849 
850 static void
851 rpc_set_ro_lvol_bdev_cb(void *cb_arg, int lvolerrno)
852 {
853 	struct spdk_json_write_ctx *w;
854 	struct spdk_jsonrpc_request *request = cb_arg;
855 
856 	if (lvolerrno != 0) {
857 		goto invalid;
858 	}
859 
860 	w = spdk_jsonrpc_begin_result(request);
861 	spdk_json_write_bool(w, true);
862 	spdk_jsonrpc_end_result(request, w);
863 	return;
864 
865 invalid:
866 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
867 					 spdk_strerror(-lvolerrno));
868 }
869 
870 static void
871 rpc_bdev_lvol_set_read_only(struct spdk_jsonrpc_request *request,
872 			    const struct spdk_json_val *params)
873 {
874 	struct rpc_set_ro_lvol_bdev req = {};
875 	struct spdk_bdev *bdev;
876 	struct spdk_lvol *lvol;
877 
878 	SPDK_INFOLOG(lvol_rpc, "Setting lvol as read only\n");
879 
880 	if (spdk_json_decode_object(params, rpc_set_ro_lvol_bdev_decoders,
881 				    SPDK_COUNTOF(rpc_set_ro_lvol_bdev_decoders),
882 				    &req)) {
883 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
884 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
885 						 "spdk_json_decode_object failed");
886 		goto cleanup;
887 	}
888 
889 	if (req.name == NULL) {
890 		SPDK_ERRLOG("missing name param\n");
891 		spdk_jsonrpc_send_error_response(request, -EINVAL, "Missing name parameter");
892 		goto cleanup;
893 	}
894 
895 	bdev = spdk_bdev_get_by_name(req.name);
896 	if (bdev == NULL) {
897 		SPDK_ERRLOG("no bdev for provided name %s\n", req.name);
898 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
899 		goto cleanup;
900 	}
901 
902 	lvol = vbdev_lvol_get_from_bdev(bdev);
903 	if (lvol == NULL) {
904 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
905 		goto cleanup;
906 	}
907 
908 	vbdev_lvol_set_read_only(lvol, rpc_set_ro_lvol_bdev_cb, request);
909 
910 cleanup:
911 	free_rpc_set_ro_lvol_bdev(&req);
912 }
913 
914 SPDK_RPC_REGISTER("bdev_lvol_set_read_only", rpc_bdev_lvol_set_read_only, SPDK_RPC_RUNTIME)
915 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_set_read_only, set_read_only_lvol_bdev)
916 
917 struct rpc_bdev_lvol_delete {
918 	char *name;
919 };
920 
921 static void
922 free_rpc_bdev_lvol_delete(struct rpc_bdev_lvol_delete *req)
923 {
924 	free(req->name);
925 }
926 
927 static const struct spdk_json_object_decoder rpc_bdev_lvol_delete_decoders[] = {
928 	{"name", offsetof(struct rpc_bdev_lvol_delete, name), spdk_json_decode_string},
929 };
930 
931 static void
932 rpc_bdev_lvol_delete_cb(void *cb_arg, int lvolerrno)
933 {
934 	struct spdk_json_write_ctx *w;
935 	struct spdk_jsonrpc_request *request = cb_arg;
936 
937 	if (lvolerrno != 0) {
938 		goto invalid;
939 	}
940 
941 	w = spdk_jsonrpc_begin_result(request);
942 	spdk_json_write_bool(w, true);
943 	spdk_jsonrpc_end_result(request, w);
944 	return;
945 
946 invalid:
947 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
948 					 spdk_strerror(-lvolerrno));
949 }
950 
951 static void
952 rpc_bdev_lvol_delete(struct spdk_jsonrpc_request *request,
953 		     const struct spdk_json_val *params)
954 {
955 	struct rpc_bdev_lvol_delete req = {};
956 	struct spdk_bdev *bdev;
957 	struct spdk_lvol *lvol;
958 
959 	if (spdk_json_decode_object(params, rpc_bdev_lvol_delete_decoders,
960 				    SPDK_COUNTOF(rpc_bdev_lvol_delete_decoders),
961 				    &req)) {
962 		SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
963 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
964 						 "spdk_json_decode_object failed");
965 		goto cleanup;
966 	}
967 
968 	bdev = spdk_bdev_get_by_name(req.name);
969 	if (bdev == NULL) {
970 		SPDK_ERRLOG("no bdev for provided name %s\n", req.name);
971 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
972 		goto cleanup;
973 	}
974 
975 	lvol = vbdev_lvol_get_from_bdev(bdev);
976 	if (lvol == NULL) {
977 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
978 		goto cleanup;
979 	}
980 
981 	vbdev_lvol_destroy(lvol, rpc_bdev_lvol_delete_cb, request);
982 
983 cleanup:
984 	free_rpc_bdev_lvol_delete(&req);
985 }
986 
987 SPDK_RPC_REGISTER("bdev_lvol_delete", rpc_bdev_lvol_delete, SPDK_RPC_RUNTIME)
988 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_delete, destroy_lvol_bdev)
989 
990 struct rpc_bdev_lvol_get_lvstores {
991 	char *uuid;
992 	char *lvs_name;
993 };
994 
995 static void
996 free_rpc_bdev_lvol_get_lvstores(struct rpc_bdev_lvol_get_lvstores *req)
997 {
998 	free(req->uuid);
999 	free(req->lvs_name);
1000 }
1001 
1002 static const struct spdk_json_object_decoder rpc_bdev_lvol_get_lvstores_decoders[] = {
1003 	{"uuid", offsetof(struct rpc_bdev_lvol_get_lvstores, uuid), spdk_json_decode_string, true},
1004 	{"lvs_name", offsetof(struct rpc_bdev_lvol_get_lvstores, lvs_name), spdk_json_decode_string, true},
1005 };
1006 
1007 static void
1008 rpc_dump_lvol_store_info(struct spdk_json_write_ctx *w, struct lvol_store_bdev *lvs_bdev)
1009 {
1010 	struct spdk_blob_store *bs;
1011 	uint64_t cluster_size;
1012 	char uuid[SPDK_UUID_STRING_LEN];
1013 
1014 	bs = lvs_bdev->lvs->blobstore;
1015 	cluster_size = spdk_bs_get_cluster_size(bs);
1016 
1017 	spdk_json_write_object_begin(w);
1018 
1019 	spdk_uuid_fmt_lower(uuid, sizeof(uuid), &lvs_bdev->lvs->uuid);
1020 	spdk_json_write_named_string(w, "uuid", uuid);
1021 
1022 	spdk_json_write_named_string(w, "name", lvs_bdev->lvs->name);
1023 
1024 	spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(lvs_bdev->bdev));
1025 
1026 	spdk_json_write_named_uint64(w, "total_data_clusters", spdk_bs_total_data_cluster_count(bs));
1027 
1028 	spdk_json_write_named_uint64(w, "free_clusters", spdk_bs_free_cluster_count(bs));
1029 
1030 	spdk_json_write_named_uint64(w, "block_size", spdk_bs_get_io_unit_size(bs));
1031 
1032 	spdk_json_write_named_uint64(w, "cluster_size", cluster_size);
1033 
1034 	spdk_json_write_object_end(w);
1035 }
1036 
1037 static void
1038 rpc_bdev_lvol_get_lvstores(struct spdk_jsonrpc_request *request,
1039 			   const struct spdk_json_val *params)
1040 {
1041 	struct rpc_bdev_lvol_get_lvstores req = {};
1042 	struct spdk_json_write_ctx *w;
1043 	struct lvol_store_bdev *lvs_bdev = NULL;
1044 	struct spdk_lvol_store *lvs = NULL;
1045 	int rc;
1046 
1047 	if (params != NULL) {
1048 		if (spdk_json_decode_object(params, rpc_bdev_lvol_get_lvstores_decoders,
1049 					    SPDK_COUNTOF(rpc_bdev_lvol_get_lvstores_decoders),
1050 					    &req)) {
1051 			SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
1052 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1053 							 "spdk_json_decode_object failed");
1054 			goto cleanup;
1055 		}
1056 
1057 		rc = vbdev_get_lvol_store_by_uuid_xor_name(req.uuid, req.lvs_name, &lvs);
1058 		if (rc != 0) {
1059 			spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
1060 			goto cleanup;
1061 		}
1062 
1063 		lvs_bdev = vbdev_get_lvs_bdev_by_lvs(lvs);
1064 		if (lvs_bdev == NULL) {
1065 			spdk_jsonrpc_send_error_response(request, ENODEV, spdk_strerror(-ENODEV));
1066 			goto cleanup;
1067 		}
1068 	}
1069 
1070 	w = spdk_jsonrpc_begin_result(request);
1071 	spdk_json_write_array_begin(w);
1072 
1073 	if (lvs_bdev != NULL) {
1074 		rpc_dump_lvol_store_info(w, lvs_bdev);
1075 	} else {
1076 		for (lvs_bdev = vbdev_lvol_store_first(); lvs_bdev != NULL;
1077 		     lvs_bdev = vbdev_lvol_store_next(lvs_bdev)) {
1078 			rpc_dump_lvol_store_info(w, lvs_bdev);
1079 		}
1080 	}
1081 	spdk_json_write_array_end(w);
1082 
1083 	spdk_jsonrpc_end_result(request, w);
1084 
1085 cleanup:
1086 	free_rpc_bdev_lvol_get_lvstores(&req);
1087 }
1088 
1089 SPDK_RPC_REGISTER("bdev_lvol_get_lvstores", rpc_bdev_lvol_get_lvstores, SPDK_RPC_RUNTIME)
1090 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_get_lvstores, get_lvol_stores)
1091