xref: /spdk/module/bdev/lvol/vbdev_lvol_rpc.c (revision 407e88fd2ab020d753e33014cf759353a9901b51)
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_internal/log.h"
40 
41 SPDK_LOG_REGISTER_COMPONENT("lvolrpc", SPDK_LOG_LVOL_RPC)
42 
43 struct rpc_construct_lvol_store {
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(SPDK_LOG_LVOL_RPC, "lvs UUID nor lvs name specified\n");
56 		return -EINVAL;
57 	} else if ((uuid && lvs_name)) {
58 		SPDK_INFOLOG(SPDK_LOG_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(SPDK_LOG_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(SPDK_LOG_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_construct_lvol_store(struct rpc_construct_lvol_store *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_construct_lvol_store_decoders[] = {
89 	{"bdev_name", offsetof(struct rpc_construct_lvol_store, bdev_name), spdk_json_decode_string},
90 	{"cluster_sz", offsetof(struct rpc_construct_lvol_store, cluster_sz), spdk_json_decode_uint32, true},
91 	{"lvs_name", offsetof(struct rpc_construct_lvol_store, lvs_name), spdk_json_decode_string},
92 	{"clear_method", offsetof(struct rpc_construct_lvol_store, clear_method), spdk_json_decode_string, true},
93 };
94 
95 static void
96 _spdk_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 spdk_rpc_construct_lvol_store(struct spdk_jsonrpc_request *request,
120 			      const struct spdk_json_val *params)
121 {
122 	struct rpc_construct_lvol_store req = {};
123 	struct spdk_bdev *bdev;
124 	int rc = 0;
125 	enum lvs_clear_method clear_method;
126 
127 	if (spdk_json_decode_object(params, rpc_construct_lvol_store_decoders,
128 				    SPDK_COUNTOF(rpc_construct_lvol_store_decoders),
129 				    &req)) {
130 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
131 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
132 						 "spdk_json_decode_object failed");
133 		goto cleanup;
134 	}
135 
136 	bdev = spdk_bdev_get_by_name(req.bdev_name);
137 	if (bdev == NULL) {
138 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.bdev_name);
139 		spdk_jsonrpc_send_error_response_fmt(request, -ENODEV, "Bdev %s not found", req.bdev_name);
140 		goto cleanup;
141 	}
142 
143 	if (req.clear_method != NULL) {
144 		if (!strcasecmp(req.clear_method, "none")) {
145 			clear_method = LVS_CLEAR_WITH_NONE;
146 		} else if (!strcasecmp(req.clear_method, "unmap")) {
147 			clear_method = LVS_CLEAR_WITH_UNMAP;
148 		} else if (!strcasecmp(req.clear_method, "write_zeroes")) {
149 			clear_method = LVS_CLEAR_WITH_WRITE_ZEROES;
150 		} else {
151 			spdk_jsonrpc_send_error_response(request, -EINVAL, "Invalid clear_method parameter");
152 			goto cleanup;
153 		}
154 	} else {
155 		clear_method = LVS_CLEAR_WITH_UNMAP;
156 	}
157 
158 	rc = vbdev_lvs_create(bdev, req.lvs_name, req.cluster_sz, clear_method,
159 			      _spdk_rpc_lvol_store_construct_cb, request);
160 	if (rc < 0) {
161 		spdk_jsonrpc_send_error_response(request, -rc, spdk_strerror(rc));
162 		goto cleanup;
163 	}
164 	free_rpc_construct_lvol_store(&req);
165 
166 	return;
167 
168 cleanup:
169 	free_rpc_construct_lvol_store(&req);
170 }
171 SPDK_RPC_REGISTER("construct_lvol_store", spdk_rpc_construct_lvol_store, SPDK_RPC_RUNTIME)
172 
173 struct rpc_rename_lvol_store {
174 	char *old_name;
175 	char *new_name;
176 };
177 
178 static void
179 free_rpc_rename_lvol_store(struct rpc_rename_lvol_store *req)
180 {
181 	free(req->old_name);
182 	free(req->new_name);
183 }
184 
185 static const struct spdk_json_object_decoder rpc_rename_lvol_store_decoders[] = {
186 	{"old_name", offsetof(struct rpc_rename_lvol_store, old_name), spdk_json_decode_string},
187 	{"new_name", offsetof(struct rpc_rename_lvol_store, new_name), spdk_json_decode_string},
188 };
189 
190 static void
191 _spdk_rpc_rename_lvol_store_cb(void *cb_arg, int lvserrno)
192 {
193 	struct spdk_json_write_ctx *w;
194 	struct spdk_jsonrpc_request *request = cb_arg;
195 
196 	if (lvserrno != 0) {
197 		goto invalid;
198 	}
199 
200 	w = spdk_jsonrpc_begin_result(request);
201 	spdk_json_write_bool(w, true);
202 	spdk_jsonrpc_end_result(request, w);
203 	return;
204 
205 invalid:
206 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
207 					 spdk_strerror(-lvserrno));
208 }
209 
210 static void
211 spdk_rpc_rename_lvol_store(struct spdk_jsonrpc_request *request,
212 			   const struct spdk_json_val *params)
213 {
214 	struct rpc_rename_lvol_store req = {};
215 	struct spdk_lvol_store *lvs;
216 
217 	if (spdk_json_decode_object(params, rpc_rename_lvol_store_decoders,
218 				    SPDK_COUNTOF(rpc_rename_lvol_store_decoders),
219 				    &req)) {
220 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
221 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
222 						 "spdk_json_decode_object failed");
223 		goto cleanup;
224 	}
225 
226 	lvs = vbdev_get_lvol_store_by_name(req.old_name);
227 	if (lvs == NULL) {
228 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "no lvs existing for given name\n");
229 		spdk_jsonrpc_send_error_response_fmt(request, -ENOENT, "Lvol store %s not found", req.old_name);
230 		goto cleanup;
231 	}
232 
233 	vbdev_lvs_rename(lvs, req.new_name, _spdk_rpc_rename_lvol_store_cb, request);
234 
235 cleanup:
236 	free_rpc_rename_lvol_store(&req);
237 }
238 SPDK_RPC_REGISTER("rename_lvol_store", spdk_rpc_rename_lvol_store, SPDK_RPC_RUNTIME)
239 
240 struct rpc_destroy_lvol_store {
241 	char *uuid;
242 	char *lvs_name;
243 };
244 
245 static void
246 free_rpc_destroy_lvol_store(struct rpc_destroy_lvol_store *req)
247 {
248 	free(req->uuid);
249 	free(req->lvs_name);
250 }
251 
252 static const struct spdk_json_object_decoder rpc_destroy_lvol_store_decoders[] = {
253 	{"uuid", offsetof(struct rpc_destroy_lvol_store, uuid), spdk_json_decode_string, true},
254 	{"lvs_name", offsetof(struct rpc_destroy_lvol_store, lvs_name), spdk_json_decode_string, true},
255 };
256 
257 static void
258 _spdk_rpc_lvol_store_destroy_cb(void *cb_arg, int lvserrno)
259 {
260 	struct spdk_json_write_ctx *w;
261 	struct spdk_jsonrpc_request *request = cb_arg;
262 
263 	if (lvserrno != 0) {
264 		goto invalid;
265 	}
266 
267 	w = spdk_jsonrpc_begin_result(request);
268 	spdk_json_write_bool(w, true);
269 	spdk_jsonrpc_end_result(request, w);
270 	return;
271 
272 invalid:
273 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
274 					 spdk_strerror(-lvserrno));
275 }
276 
277 static void
278 spdk_rpc_destroy_lvol_store(struct spdk_jsonrpc_request *request,
279 			    const struct spdk_json_val *params)
280 {
281 	struct rpc_destroy_lvol_store req = {};
282 	struct spdk_lvol_store *lvs = NULL;
283 	int rc;
284 
285 	if (spdk_json_decode_object(params, rpc_destroy_lvol_store_decoders,
286 				    SPDK_COUNTOF(rpc_destroy_lvol_store_decoders),
287 				    &req)) {
288 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
289 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
290 						 "spdk_json_decode_object failed");
291 		goto cleanup;
292 	}
293 
294 	rc = vbdev_get_lvol_store_by_uuid_xor_name(req.uuid, req.lvs_name, &lvs);
295 	if (rc != 0) {
296 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
297 		goto cleanup;
298 	}
299 
300 	vbdev_lvs_destruct(lvs, _spdk_rpc_lvol_store_destroy_cb, request);
301 
302 cleanup:
303 	free_rpc_destroy_lvol_store(&req);
304 }
305 SPDK_RPC_REGISTER("destroy_lvol_store", spdk_rpc_destroy_lvol_store, SPDK_RPC_RUNTIME)
306 
307 struct rpc_construct_lvol_bdev {
308 	char *uuid;
309 	char *lvs_name;
310 	char *lvol_name;
311 	uint64_t size;
312 	bool thin_provision;
313 	char *clear_method;
314 };
315 
316 static void
317 free_rpc_construct_lvol_bdev(struct rpc_construct_lvol_bdev *req)
318 {
319 	free(req->uuid);
320 	free(req->lvs_name);
321 	free(req->lvol_name);
322 	free(req->clear_method);
323 }
324 
325 static const struct spdk_json_object_decoder rpc_construct_lvol_bdev_decoders[] = {
326 	{"uuid", offsetof(struct rpc_construct_lvol_bdev, uuid), spdk_json_decode_string, true},
327 	{"lvs_name", offsetof(struct rpc_construct_lvol_bdev, lvs_name), spdk_json_decode_string, true},
328 	{"lvol_name", offsetof(struct rpc_construct_lvol_bdev, lvol_name), spdk_json_decode_string},
329 	{"size", offsetof(struct rpc_construct_lvol_bdev, size), spdk_json_decode_uint64},
330 	{"thin_provision", offsetof(struct rpc_construct_lvol_bdev, thin_provision), spdk_json_decode_bool, true},
331 	{"clear_method", offsetof(struct rpc_construct_lvol_bdev, clear_method), spdk_json_decode_string, true},
332 };
333 
334 static void
335 _spdk_rpc_construct_lvol_bdev_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno)
336 {
337 	struct spdk_json_write_ctx *w;
338 	struct spdk_jsonrpc_request *request = cb_arg;
339 
340 	if (lvolerrno != 0) {
341 		goto invalid;
342 	}
343 
344 	w = spdk_jsonrpc_begin_result(request);
345 	spdk_json_write_string(w, lvol->unique_id);
346 	spdk_jsonrpc_end_result(request, w);
347 	return;
348 
349 invalid:
350 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
351 					 spdk_strerror(-lvolerrno));
352 }
353 
354 static void
355 spdk_rpc_construct_lvol_bdev(struct spdk_jsonrpc_request *request,
356 			     const struct spdk_json_val *params)
357 {
358 	struct rpc_construct_lvol_bdev req = {};
359 	enum lvol_clear_method clear_method;
360 	int rc = 0;
361 	struct spdk_lvol_store *lvs = NULL;
362 
363 	SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Creating blob\n");
364 
365 	if (spdk_json_decode_object(params, rpc_construct_lvol_bdev_decoders,
366 				    SPDK_COUNTOF(rpc_construct_lvol_bdev_decoders),
367 				    &req)) {
368 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
369 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
370 						 "spdk_json_decode_object failed");
371 		goto cleanup;
372 	}
373 
374 	rc = vbdev_get_lvol_store_by_uuid_xor_name(req.uuid, req.lvs_name, &lvs);
375 	if (rc != 0) {
376 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
377 		goto cleanup;
378 	}
379 
380 	if (req.clear_method != NULL) {
381 		if (!strcasecmp(req.clear_method, "none")) {
382 			clear_method = LVOL_CLEAR_WITH_NONE;
383 		} else if (!strcasecmp(req.clear_method, "unmap")) {
384 			clear_method = LVOL_CLEAR_WITH_UNMAP;
385 		} else if (!strcasecmp(req.clear_method, "write_zeroes")) {
386 			clear_method = LVOL_CLEAR_WITH_WRITE_ZEROES;
387 		} else {
388 			spdk_jsonrpc_send_error_response(request, -EINVAL, "Invalid clean_method option");
389 			goto cleanup;
390 		}
391 	} else {
392 		clear_method = LVOL_CLEAR_WITH_DEFAULT;
393 	}
394 
395 	rc = vbdev_lvol_create(lvs, req.lvol_name, req.size, req.thin_provision,
396 			       clear_method, _spdk_rpc_construct_lvol_bdev_cb, request);
397 	if (rc < 0) {
398 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
399 		goto cleanup;
400 	}
401 
402 cleanup:
403 	free_rpc_construct_lvol_bdev(&req);
404 }
405 
406 SPDK_RPC_REGISTER("construct_lvol_bdev", spdk_rpc_construct_lvol_bdev, SPDK_RPC_RUNTIME)
407 
408 struct rpc_snapshot_lvol_bdev {
409 	char *lvol_name;
410 	char *snapshot_name;
411 };
412 
413 static void
414 free_rpc_snapshot_lvol_bdev(struct rpc_snapshot_lvol_bdev *req)
415 {
416 	free(req->lvol_name);
417 	free(req->snapshot_name);
418 }
419 
420 static const struct spdk_json_object_decoder rpc_snapshot_lvol_bdev_decoders[] = {
421 	{"lvol_name", offsetof(struct rpc_snapshot_lvol_bdev, lvol_name), spdk_json_decode_string},
422 	{"snapshot_name", offsetof(struct rpc_snapshot_lvol_bdev, snapshot_name), spdk_json_decode_string},
423 };
424 
425 static void
426 _spdk_rpc_snapshot_lvol_bdev_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno)
427 {
428 	struct spdk_json_write_ctx *w;
429 	struct spdk_jsonrpc_request *request = cb_arg;
430 
431 	if (lvolerrno != 0) {
432 		goto invalid;
433 	}
434 
435 	w = spdk_jsonrpc_begin_result(request);
436 	spdk_json_write_string(w, lvol->unique_id);
437 	spdk_jsonrpc_end_result(request, w);
438 	return;
439 
440 invalid:
441 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
442 					 spdk_strerror(-lvolerrno));
443 }
444 
445 static void
446 spdk_rpc_snapshot_lvol_bdev(struct spdk_jsonrpc_request *request,
447 			    const struct spdk_json_val *params)
448 {
449 	struct rpc_snapshot_lvol_bdev req = {};
450 	struct spdk_bdev *bdev;
451 	struct spdk_lvol *lvol;
452 
453 	SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Snapshotting blob\n");
454 
455 	if (spdk_json_decode_object(params, rpc_snapshot_lvol_bdev_decoders,
456 				    SPDK_COUNTOF(rpc_snapshot_lvol_bdev_decoders),
457 				    &req)) {
458 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
459 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
460 						 "spdk_json_decode_object failed");
461 		goto cleanup;
462 	}
463 
464 	bdev = spdk_bdev_get_by_name(req.lvol_name);
465 	if (bdev == NULL) {
466 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "bdev '%s' does not exist\n", req.lvol_name);
467 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
468 		goto cleanup;
469 	}
470 
471 	lvol = vbdev_lvol_get_from_bdev(bdev);
472 	if (lvol == NULL) {
473 		SPDK_ERRLOG("lvol does not exist\n");
474 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
475 		goto cleanup;
476 	}
477 
478 	vbdev_lvol_create_snapshot(lvol, req.snapshot_name, _spdk_rpc_snapshot_lvol_bdev_cb, request);
479 
480 cleanup:
481 	free_rpc_snapshot_lvol_bdev(&req);
482 }
483 
484 SPDK_RPC_REGISTER("snapshot_lvol_bdev", spdk_rpc_snapshot_lvol_bdev, SPDK_RPC_RUNTIME)
485 
486 struct rpc_bdev_lvol_clone {
487 	char *snapshot_name;
488 	char *clone_name;
489 };
490 
491 static void
492 free_rpc_bdev_lvol_clone(struct rpc_bdev_lvol_clone *req)
493 {
494 	free(req->snapshot_name);
495 	free(req->clone_name);
496 }
497 
498 static const struct spdk_json_object_decoder rpc_bdev_lvol_clone_decoders[] = {
499 	{"snapshot_name", offsetof(struct rpc_bdev_lvol_clone, snapshot_name), spdk_json_decode_string},
500 	{"clone_name", offsetof(struct rpc_bdev_lvol_clone, clone_name), spdk_json_decode_string, true},
501 };
502 
503 static void
504 _spdk_rpc_bdev_lvol_clone_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno)
505 {
506 	struct spdk_json_write_ctx *w;
507 	struct spdk_jsonrpc_request *request = cb_arg;
508 
509 	if (lvolerrno != 0) {
510 		goto invalid;
511 	}
512 
513 	w = spdk_jsonrpc_begin_result(request);
514 	spdk_json_write_string(w, lvol->unique_id);
515 	spdk_jsonrpc_end_result(request, w);
516 	return;
517 
518 invalid:
519 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
520 					 spdk_strerror(-lvolerrno));
521 }
522 
523 static void
524 spdk_rpc_bdev_lvol_clone(struct spdk_jsonrpc_request *request,
525 			 const struct spdk_json_val *params)
526 {
527 	struct rpc_bdev_lvol_clone req = {};
528 	struct spdk_bdev *bdev;
529 	struct spdk_lvol *lvol;
530 
531 	SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Cloning blob\n");
532 
533 	if (spdk_json_decode_object(params, rpc_bdev_lvol_clone_decoders,
534 				    SPDK_COUNTOF(rpc_bdev_lvol_clone_decoders),
535 				    &req)) {
536 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
537 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
538 						 "spdk_json_decode_object failed");
539 		goto cleanup;
540 	}
541 
542 	bdev = spdk_bdev_get_by_name(req.snapshot_name);
543 	if (bdev == NULL) {
544 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "bdev '%s' does not exist\n", req.snapshot_name);
545 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
546 		goto cleanup;
547 	}
548 
549 	lvol = vbdev_lvol_get_from_bdev(bdev);
550 	if (lvol == NULL) {
551 		SPDK_ERRLOG("lvol does not exist\n");
552 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
553 		goto cleanup;
554 	}
555 
556 	vbdev_lvol_create_clone(lvol, req.clone_name, _spdk_rpc_bdev_lvol_clone_cb, request);
557 
558 cleanup:
559 	free_rpc_bdev_lvol_clone(&req);
560 }
561 
562 SPDK_RPC_REGISTER("bdev_lvol_clone", spdk_rpc_bdev_lvol_clone, SPDK_RPC_RUNTIME)
563 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_clone, clone_lvol_bdev)
564 
565 struct rpc_bdev_lvol_rename {
566 	char *old_name;
567 	char *new_name;
568 };
569 
570 static void
571 free_rpc_bdev_lvol_rename(struct rpc_bdev_lvol_rename *req)
572 {
573 	free(req->old_name);
574 	free(req->new_name);
575 }
576 
577 static const struct spdk_json_object_decoder rpc_bdev_lvol_rename_decoders[] = {
578 	{"old_name", offsetof(struct rpc_bdev_lvol_rename, old_name), spdk_json_decode_string},
579 	{"new_name", offsetof(struct rpc_bdev_lvol_rename, new_name), spdk_json_decode_string},
580 };
581 
582 static void
583 _spdk_rpc_bdev_lvol_rename_cb(void *cb_arg, int lvolerrno)
584 {
585 	struct spdk_json_write_ctx *w;
586 	struct spdk_jsonrpc_request *request = cb_arg;
587 
588 	if (lvolerrno != 0) {
589 		goto invalid;
590 	}
591 
592 	w = spdk_jsonrpc_begin_result(request);
593 	spdk_json_write_bool(w, true);
594 	spdk_jsonrpc_end_result(request, w);
595 	return;
596 
597 invalid:
598 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
599 					 spdk_strerror(-lvolerrno));
600 }
601 
602 static void
603 spdk_rpc_bdev_lvol_rename(struct spdk_jsonrpc_request *request,
604 			  const struct spdk_json_val *params)
605 {
606 	struct rpc_bdev_lvol_rename req = {};
607 	struct spdk_bdev *bdev;
608 	struct spdk_lvol *lvol;
609 
610 	SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Renaming lvol\n");
611 
612 	if (spdk_json_decode_object(params, rpc_bdev_lvol_rename_decoders,
613 				    SPDK_COUNTOF(rpc_bdev_lvol_rename_decoders),
614 				    &req)) {
615 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
616 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
617 						 "spdk_json_decode_object failed");
618 		goto cleanup;
619 	}
620 
621 	bdev = spdk_bdev_get_by_name(req.old_name);
622 	if (bdev == NULL) {
623 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.old_name);
624 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
625 		goto cleanup;
626 	}
627 
628 	lvol = vbdev_lvol_get_from_bdev(bdev);
629 	if (lvol == NULL) {
630 		SPDK_ERRLOG("lvol does not exist\n");
631 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
632 		goto cleanup;
633 	}
634 
635 	vbdev_lvol_rename(lvol, req.new_name, _spdk_rpc_bdev_lvol_rename_cb, request);
636 
637 cleanup:
638 	free_rpc_bdev_lvol_rename(&req);
639 }
640 
641 SPDK_RPC_REGISTER("bdev_lvol_rename", spdk_rpc_bdev_lvol_rename, SPDK_RPC_RUNTIME)
642 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_rename, rename_lvol_bdev)
643 
644 struct rpc_inflate_lvol_bdev {
645 	char *name;
646 };
647 
648 static void
649 free_rpc_inflate_lvol_bdev(struct rpc_inflate_lvol_bdev *req)
650 {
651 	free(req->name);
652 }
653 
654 static const struct spdk_json_object_decoder rpc_inflate_lvol_bdev_decoders[] = {
655 	{"name", offsetof(struct rpc_inflate_lvol_bdev, name), spdk_json_decode_string},
656 };
657 
658 static void
659 _spdk_rpc_inflate_lvol_bdev_cb(void *cb_arg, int lvolerrno)
660 {
661 	struct spdk_json_write_ctx *w;
662 	struct spdk_jsonrpc_request *request = cb_arg;
663 
664 	if (lvolerrno != 0) {
665 		goto invalid;
666 	}
667 
668 	w = spdk_jsonrpc_begin_result(request);
669 	spdk_json_write_bool(w, true);
670 	spdk_jsonrpc_end_result(request, w);
671 	return;
672 
673 invalid:
674 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
675 					 spdk_strerror(-lvolerrno));
676 }
677 
678 static void
679 spdk_rpc_inflate_lvol_bdev(struct spdk_jsonrpc_request *request,
680 			   const struct spdk_json_val *params)
681 {
682 	struct rpc_inflate_lvol_bdev req = {};
683 	struct spdk_bdev *bdev;
684 	struct spdk_lvol *lvol;
685 
686 	SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Inflating lvol\n");
687 
688 	if (spdk_json_decode_object(params, rpc_inflate_lvol_bdev_decoders,
689 				    SPDK_COUNTOF(rpc_inflate_lvol_bdev_decoders),
690 				    &req)) {
691 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
692 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
693 						 "spdk_json_decode_object failed");
694 		goto cleanup;
695 	}
696 
697 	bdev = spdk_bdev_get_by_name(req.name);
698 	if (bdev == NULL) {
699 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
700 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
701 		goto cleanup;
702 	}
703 
704 	lvol = vbdev_lvol_get_from_bdev(bdev);
705 	if (lvol == NULL) {
706 		SPDK_ERRLOG("lvol does not exist\n");
707 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
708 		goto cleanup;
709 	}
710 
711 	spdk_lvol_inflate(lvol, _spdk_rpc_inflate_lvol_bdev_cb, request);
712 
713 cleanup:
714 	free_rpc_inflate_lvol_bdev(&req);
715 }
716 
717 SPDK_RPC_REGISTER("inflate_lvol_bdev", spdk_rpc_inflate_lvol_bdev, SPDK_RPC_RUNTIME)
718 
719 static void
720 spdk_rpc_decouple_parent_lvol_bdev(struct spdk_jsonrpc_request *request,
721 				   const struct spdk_json_val *params)
722 {
723 	struct rpc_inflate_lvol_bdev req = {};
724 	struct spdk_bdev *bdev;
725 	struct spdk_lvol *lvol;
726 
727 	SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Decoupling parent of lvol\n");
728 
729 	if (spdk_json_decode_object(params, rpc_inflate_lvol_bdev_decoders,
730 				    SPDK_COUNTOF(rpc_inflate_lvol_bdev_decoders),
731 				    &req)) {
732 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
733 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
734 						 "spdk_json_decode_object failed");
735 		goto cleanup;
736 	}
737 
738 	bdev = spdk_bdev_get_by_name(req.name);
739 	if (bdev == NULL) {
740 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
741 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
742 		goto cleanup;
743 	}
744 
745 	lvol = vbdev_lvol_get_from_bdev(bdev);
746 	if (lvol == NULL) {
747 		SPDK_ERRLOG("lvol does not exist\n");
748 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
749 		goto cleanup;
750 	}
751 
752 	spdk_lvol_decouple_parent(lvol, _spdk_rpc_inflate_lvol_bdev_cb, request);
753 
754 cleanup:
755 	free_rpc_inflate_lvol_bdev(&req);
756 }
757 
758 SPDK_RPC_REGISTER("decouple_parent_lvol_bdev", spdk_rpc_decouple_parent_lvol_bdev, SPDK_RPC_RUNTIME)
759 
760 struct rpc_resize_lvol_bdev {
761 	char *name;
762 	uint64_t size;
763 };
764 
765 static void
766 free_rpc_resize_lvol_bdev(struct rpc_resize_lvol_bdev *req)
767 {
768 	free(req->name);
769 }
770 
771 static const struct spdk_json_object_decoder rpc_resize_lvol_bdev_decoders[] = {
772 	{"name", offsetof(struct rpc_resize_lvol_bdev, name), spdk_json_decode_string},
773 	{"size", offsetof(struct rpc_resize_lvol_bdev, size), spdk_json_decode_uint64},
774 };
775 
776 static void
777 _spdk_rpc_resize_lvol_bdev_cb(void *cb_arg, int lvolerrno)
778 {
779 	struct spdk_json_write_ctx *w;
780 	struct spdk_jsonrpc_request *request = cb_arg;
781 
782 	if (lvolerrno != 0) {
783 		goto invalid;
784 	}
785 
786 	w = spdk_jsonrpc_begin_result(request);
787 	spdk_json_write_bool(w, true);
788 	spdk_jsonrpc_end_result(request, w);
789 	return;
790 
791 invalid:
792 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
793 					 spdk_strerror(-lvolerrno));
794 }
795 
796 static void
797 spdk_rpc_resize_lvol_bdev(struct spdk_jsonrpc_request *request,
798 			  const struct spdk_json_val *params)
799 {
800 	struct rpc_resize_lvol_bdev req = {};
801 	struct spdk_bdev *bdev;
802 	struct spdk_lvol *lvol;
803 
804 	SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Resizing lvol\n");
805 
806 	if (spdk_json_decode_object(params, rpc_resize_lvol_bdev_decoders,
807 				    SPDK_COUNTOF(rpc_resize_lvol_bdev_decoders),
808 				    &req)) {
809 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
810 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
811 						 "spdk_json_decode_object failed");
812 		goto cleanup;
813 	}
814 
815 	bdev = spdk_bdev_get_by_name(req.name);
816 	if (bdev == NULL) {
817 		SPDK_ERRLOG("no bdev for provided name %s\n", req.name);
818 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
819 		goto cleanup;
820 	}
821 
822 	lvol = vbdev_lvol_get_from_bdev(bdev);
823 	if (lvol == NULL) {
824 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
825 		goto cleanup;
826 	}
827 
828 	vbdev_lvol_resize(lvol, req.size, _spdk_rpc_resize_lvol_bdev_cb, request);
829 
830 cleanup:
831 	free_rpc_resize_lvol_bdev(&req);
832 }
833 
834 SPDK_RPC_REGISTER("resize_lvol_bdev", spdk_rpc_resize_lvol_bdev, SPDK_RPC_RUNTIME)
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 _spdk_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 spdk_rpc_set_read_only_lvol_bdev(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(SPDK_LOG_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(SPDK_LOG_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, _spdk_rpc_set_ro_lvol_bdev_cb, request);
909 
910 cleanup:
911 	free_rpc_set_ro_lvol_bdev(&req);
912 }
913 
914 SPDK_RPC_REGISTER("set_read_only_lvol_bdev", spdk_rpc_set_read_only_lvol_bdev, SPDK_RPC_RUNTIME)
915 
916 struct rpc_destroy_lvol_bdev {
917 	char *name;
918 };
919 
920 static void
921 free_rpc_destroy_lvol_bdev(struct rpc_destroy_lvol_bdev *req)
922 {
923 	free(req->name);
924 }
925 
926 static const struct spdk_json_object_decoder rpc_destroy_lvol_bdev_decoders[] = {
927 	{"name", offsetof(struct rpc_destroy_lvol_bdev, name), spdk_json_decode_string},
928 };
929 
930 static void
931 _spdk_rpc_destroy_lvol_bdev_cb(void *cb_arg, int lvolerrno)
932 {
933 	struct spdk_json_write_ctx *w;
934 	struct spdk_jsonrpc_request *request = cb_arg;
935 
936 	if (lvolerrno != 0) {
937 		goto invalid;
938 	}
939 
940 	w = spdk_jsonrpc_begin_result(request);
941 	spdk_json_write_bool(w, true);
942 	spdk_jsonrpc_end_result(request, w);
943 	return;
944 
945 invalid:
946 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
947 					 spdk_strerror(-lvolerrno));
948 }
949 
950 static void
951 spdk_rpc_destroy_lvol_bdev(struct spdk_jsonrpc_request *request,
952 			   const struct spdk_json_val *params)
953 {
954 	struct rpc_destroy_lvol_bdev req = {};
955 	struct spdk_bdev *bdev;
956 	struct spdk_lvol *lvol;
957 
958 	if (spdk_json_decode_object(params, rpc_destroy_lvol_bdev_decoders,
959 				    SPDK_COUNTOF(rpc_destroy_lvol_bdev_decoders),
960 				    &req)) {
961 		SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
962 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
963 						 "spdk_json_decode_object failed");
964 		goto cleanup;
965 	}
966 
967 	bdev = spdk_bdev_get_by_name(req.name);
968 	if (bdev == NULL) {
969 		SPDK_ERRLOG("no bdev for provided name %s\n", req.name);
970 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
971 		goto cleanup;
972 	}
973 
974 	lvol = vbdev_lvol_get_from_bdev(bdev);
975 	if (lvol == NULL) {
976 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
977 		goto cleanup;
978 	}
979 
980 	vbdev_lvol_destroy(lvol, _spdk_rpc_destroy_lvol_bdev_cb, request);
981 
982 cleanup:
983 	free_rpc_destroy_lvol_bdev(&req);
984 }
985 
986 SPDK_RPC_REGISTER("destroy_lvol_bdev", spdk_rpc_destroy_lvol_bdev, SPDK_RPC_RUNTIME)
987 
988 struct rpc_bdev_lvol_get_lvstores {
989 	char *uuid;
990 	char *lvs_name;
991 };
992 
993 static void
994 free_rpc_bdev_lvol_get_lvstores(struct rpc_bdev_lvol_get_lvstores *req)
995 {
996 	free(req->uuid);
997 	free(req->lvs_name);
998 }
999 
1000 static const struct spdk_json_object_decoder rpc_bdev_lvol_get_lvstores_decoders[] = {
1001 	{"uuid", offsetof(struct rpc_bdev_lvol_get_lvstores, uuid), spdk_json_decode_string, true},
1002 	{"lvs_name", offsetof(struct rpc_bdev_lvol_get_lvstores, lvs_name), spdk_json_decode_string, true},
1003 };
1004 
1005 static void
1006 spdk_rpc_dump_lvol_store_info(struct spdk_json_write_ctx *w, struct lvol_store_bdev *lvs_bdev)
1007 {
1008 	struct spdk_blob_store *bs;
1009 	uint64_t cluster_size, block_size;
1010 	char uuid[SPDK_UUID_STRING_LEN];
1011 
1012 	bs = lvs_bdev->lvs->blobstore;
1013 	cluster_size = spdk_bs_get_cluster_size(bs);
1014 	/* Block size of lvols is always size of blob store page */
1015 	block_size = spdk_bs_get_page_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", block_size);
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 spdk_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(SPDK_LOG_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 		spdk_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 			spdk_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", spdk_rpc_bdev_lvol_get_lvstores, SPDK_RPC_RUNTIME)
1090 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_get_lvstores, get_lvol_stores)
1091