xref: /spdk/lib/bdev/bdev_rpc.c (revision ebc227d9b23abcf5f81099611254eef84221d186)
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/bdev.h"
35 
36 #include "spdk/env.h"
37 #include "spdk/rpc.h"
38 #include "spdk/util.h"
39 #include "spdk/string.h"
40 #include "spdk/base64.h"
41 #include "spdk/bdev_module.h"
42 
43 #include "spdk_internal/log.h"
44 
45 struct spdk_rpc_set_bdev_opts {
46 	uint32_t bdev_io_pool_size;
47 	uint32_t bdev_io_cache_size;
48 	bool bdev_auto_examine;
49 };
50 
51 static const struct spdk_json_object_decoder rpc_set_bdev_opts_decoders[] = {
52 	{"bdev_io_pool_size", offsetof(struct spdk_rpc_set_bdev_opts, bdev_io_pool_size), spdk_json_decode_uint32, true},
53 	{"bdev_io_cache_size", offsetof(struct spdk_rpc_set_bdev_opts, bdev_io_cache_size), spdk_json_decode_uint32, true},
54 	{"bdev_auto_examine", offsetof(struct spdk_rpc_set_bdev_opts, bdev_auto_examine), spdk_json_decode_bool, true},
55 };
56 
57 static void
58 rpc_bdev_set_options(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
59 {
60 	struct spdk_rpc_set_bdev_opts rpc_opts;
61 	struct spdk_bdev_opts bdev_opts;
62 	struct spdk_json_write_ctx *w;
63 	int rc;
64 
65 	rpc_opts.bdev_io_pool_size = UINT32_MAX;
66 	rpc_opts.bdev_io_cache_size = UINT32_MAX;
67 	rpc_opts.bdev_auto_examine = true;
68 
69 	if (params != NULL) {
70 		if (spdk_json_decode_object(params, rpc_set_bdev_opts_decoders,
71 					    SPDK_COUNTOF(rpc_set_bdev_opts_decoders), &rpc_opts)) {
72 			SPDK_ERRLOG("spdk_json_decode_object() failed\n");
73 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
74 							 "Invalid parameters");
75 			return;
76 		}
77 	}
78 
79 	spdk_bdev_get_opts(&bdev_opts);
80 	if (rpc_opts.bdev_io_pool_size != UINT32_MAX) {
81 		bdev_opts.bdev_io_pool_size = rpc_opts.bdev_io_pool_size;
82 	}
83 	if (rpc_opts.bdev_io_cache_size != UINT32_MAX) {
84 		bdev_opts.bdev_io_cache_size = rpc_opts.bdev_io_cache_size;
85 	}
86 	bdev_opts.bdev_auto_examine = rpc_opts.bdev_auto_examine;
87 	rc = spdk_bdev_set_opts(&bdev_opts);
88 
89 	if (rc != 0) {
90 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
91 						     "Pool size %" PRIu32 " too small for cache size %" PRIu32,
92 						     bdev_opts.bdev_io_pool_size, bdev_opts.bdev_io_cache_size);
93 		return;
94 	}
95 
96 	w = spdk_jsonrpc_begin_result(request);
97 	spdk_json_write_bool(w, true);
98 	spdk_jsonrpc_end_result(request, w);
99 }
100 SPDK_RPC_REGISTER("bdev_set_options", rpc_bdev_set_options, SPDK_RPC_STARTUP)
101 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_set_options, set_bdev_options)
102 
103 struct rpc_bdev_examine {
104 	char *name;
105 };
106 
107 static void
108 free_rpc_bdev_examine(struct rpc_bdev_examine *r)
109 {
110 	free(r->name);
111 }
112 
113 static const struct spdk_json_object_decoder rpc_examine_bdev_decoders[] = {
114 	{"name", offsetof(struct rpc_bdev_examine, name), spdk_json_decode_string},
115 };
116 
117 static void
118 rpc_bdev_examine_bdev(struct spdk_jsonrpc_request *request,
119 		      const struct spdk_json_val *params)
120 {
121 	struct rpc_bdev_examine req = {NULL};
122 	struct spdk_json_write_ctx *w;
123 	int rc;
124 
125 	if (spdk_json_decode_object(params, rpc_examine_bdev_decoders,
126 				    SPDK_COUNTOF(rpc_examine_bdev_decoders),
127 				    &req)) {
128 		SPDK_ERRLOG("spdk_json_decode_object() failed\n");
129 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
130 						 "spdk_json_decode_object failed");
131 		goto cleanup;
132 	}
133 
134 	rc = spdk_bdev_examine(req.name);
135 	if (rc != 0) {
136 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
137 		goto cleanup;
138 	}
139 	w = spdk_jsonrpc_begin_result(request);
140 	spdk_json_write_bool(w, true);
141 	spdk_jsonrpc_end_result(request, w);
142 
143 cleanup:
144 	free_rpc_bdev_examine(&req);
145 }
146 SPDK_RPC_REGISTER("bdev_examine", rpc_bdev_examine_bdev, SPDK_RPC_RUNTIME)
147 
148 struct rpc_bdev_get_iostat_ctx {
149 	int bdev_count;
150 	struct spdk_jsonrpc_request *request;
151 	struct spdk_json_write_ctx *w;
152 };
153 
154 static void
155 rpc_bdev_get_iostat_cb(struct spdk_bdev *bdev,
156 		       struct spdk_bdev_io_stat *stat, void *cb_arg, int rc)
157 {
158 	struct rpc_bdev_get_iostat_ctx *ctx = cb_arg;
159 	struct spdk_json_write_ctx *w = ctx->w;
160 	const char *bdev_name;
161 
162 	if (rc != 0) {
163 		goto done;
164 	}
165 
166 	bdev_name = spdk_bdev_get_name(bdev);
167 	if (bdev_name != NULL) {
168 		spdk_json_write_object_begin(w);
169 
170 		spdk_json_write_named_string(w, "name", bdev_name);
171 
172 		spdk_json_write_named_uint64(w, "bytes_read", stat->bytes_read);
173 
174 		spdk_json_write_named_uint64(w, "num_read_ops", stat->num_read_ops);
175 
176 		spdk_json_write_named_uint64(w, "bytes_written", stat->bytes_written);
177 
178 		spdk_json_write_named_uint64(w, "num_write_ops", stat->num_write_ops);
179 
180 		spdk_json_write_named_uint64(w, "bytes_unmapped", stat->bytes_unmapped);
181 
182 		spdk_json_write_named_uint64(w, "num_unmap_ops", stat->num_unmap_ops);
183 
184 		spdk_json_write_named_uint64(w, "read_latency_ticks", stat->read_latency_ticks);
185 
186 		spdk_json_write_named_uint64(w, "write_latency_ticks", stat->write_latency_ticks);
187 
188 		spdk_json_write_named_uint64(w, "unmap_latency_ticks", stat->unmap_latency_ticks);
189 
190 		if (spdk_bdev_get_qd_sampling_period(bdev)) {
191 			spdk_json_write_named_uint64(w, "queue_depth_polling_period",
192 						     spdk_bdev_get_qd_sampling_period(bdev));
193 
194 			spdk_json_write_named_uint64(w, "queue_depth", spdk_bdev_get_qd(bdev));
195 
196 			spdk_json_write_named_uint64(w, "io_time", spdk_bdev_get_io_time(bdev));
197 
198 			spdk_json_write_named_uint64(w, "weighted_io_time",
199 						     spdk_bdev_get_weighted_io_time(bdev));
200 		}
201 
202 		spdk_json_write_object_end(w);
203 	}
204 
205 done:
206 	free(stat);
207 	if (--ctx->bdev_count == 0) {
208 		spdk_json_write_array_end(ctx->w);
209 		spdk_json_write_object_end(w);
210 		spdk_jsonrpc_end_result(ctx->request, ctx->w);
211 		free(ctx);
212 	}
213 }
214 
215 struct rpc_bdev_get_iostat {
216 	char *name;
217 };
218 
219 static void
220 free_rpc_bdev_get_iostat(struct rpc_bdev_get_iostat *r)
221 {
222 	free(r->name);
223 }
224 
225 static const struct spdk_json_object_decoder rpc_bdev_get_iostat_decoders[] = {
226 	{"name", offsetof(struct rpc_bdev_get_iostat, name), spdk_json_decode_string, true},
227 };
228 
229 static void
230 rpc_bdev_get_iostat(struct spdk_jsonrpc_request *request,
231 		    const struct spdk_json_val *params)
232 {
233 	struct rpc_bdev_get_iostat req = {};
234 	struct spdk_bdev *bdev = NULL;
235 	struct spdk_json_write_ctx *w;
236 	struct spdk_bdev_io_stat *stat;
237 	struct rpc_bdev_get_iostat_ctx *ctx;
238 
239 	if (params != NULL) {
240 		if (spdk_json_decode_object(params, rpc_bdev_get_iostat_decoders,
241 					    SPDK_COUNTOF(rpc_bdev_get_iostat_decoders),
242 					    &req)) {
243 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
244 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
245 							 "spdk_json_decode_object failed");
246 			free_rpc_bdev_get_iostat(&req);
247 			return;
248 		}
249 
250 		if (req.name) {
251 			bdev = spdk_bdev_get_by_name(req.name);
252 			if (bdev == NULL) {
253 				SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
254 				spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
255 				free_rpc_bdev_get_iostat(&req);
256 				return;
257 			}
258 		}
259 	}
260 
261 	free_rpc_bdev_get_iostat(&req);
262 
263 	ctx = calloc(1, sizeof(struct rpc_bdev_get_iostat_ctx));
264 	if (ctx == NULL) {
265 		SPDK_ERRLOG("Failed to allocate rpc_bdev_get_iostat_ctx struct\n");
266 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
267 		return;
268 	}
269 
270 	w = spdk_jsonrpc_begin_result(request);
271 	/*
272 	 * Increment initial bdev_count so that it will never reach 0 in the middle
273 	 * of iterating.
274 	 */
275 	ctx->bdev_count++;
276 	ctx->request = request;
277 	ctx->w = w;
278 
279 
280 	spdk_json_write_object_begin(w);
281 	spdk_json_write_named_uint64(w, "tick_rate", spdk_get_ticks_hz());
282 	spdk_json_write_named_uint64(w, "ticks", spdk_get_ticks());
283 
284 	spdk_json_write_named_array_begin(w, "bdevs");
285 
286 	if (bdev != NULL) {
287 		stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
288 		if (stat == NULL) {
289 			SPDK_ERRLOG("Failed to allocate rpc_bdev_get_iostat_ctx struct\n");
290 		} else {
291 			ctx->bdev_count++;
292 			spdk_bdev_get_device_stat(bdev, stat, rpc_bdev_get_iostat_cb, ctx);
293 		}
294 	} else {
295 		for (bdev = spdk_bdev_first(); bdev != NULL; bdev = spdk_bdev_next(bdev)) {
296 			stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
297 			if (stat == NULL) {
298 				SPDK_ERRLOG("Failed to allocate spdk_bdev_io_stat struct\n");
299 				break;
300 			}
301 			ctx->bdev_count++;
302 			spdk_bdev_get_device_stat(bdev, stat, rpc_bdev_get_iostat_cb, ctx);
303 		}
304 	}
305 
306 	if (--ctx->bdev_count == 0) {
307 		spdk_json_write_array_end(w);
308 		spdk_json_write_object_end(w);
309 		spdk_jsonrpc_end_result(request, w);
310 		free(ctx);
311 	}
312 }
313 SPDK_RPC_REGISTER("bdev_get_iostat", rpc_bdev_get_iostat, SPDK_RPC_RUNTIME)
314 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_get_iostat, get_bdevs_iostat)
315 
316 static void
317 rpc_dump_bdev_info(struct spdk_json_write_ctx *w,
318 		   struct spdk_bdev *bdev)
319 {
320 	struct spdk_bdev_alias *tmp;
321 	uint64_t qos_limits[SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES];
322 	int i;
323 
324 	spdk_json_write_object_begin(w);
325 
326 	spdk_json_write_named_string(w, "name", spdk_bdev_get_name(bdev));
327 
328 	spdk_json_write_named_array_begin(w, "aliases");
329 
330 	TAILQ_FOREACH(tmp, spdk_bdev_get_aliases(bdev), tailq) {
331 		spdk_json_write_string(w, tmp->alias);
332 	}
333 
334 	spdk_json_write_array_end(w);
335 
336 	spdk_json_write_named_string(w, "product_name", spdk_bdev_get_product_name(bdev));
337 
338 	spdk_json_write_named_uint32(w, "block_size", spdk_bdev_get_block_size(bdev));
339 
340 	spdk_json_write_named_uint64(w, "num_blocks", spdk_bdev_get_num_blocks(bdev));
341 
342 	if (!spdk_mem_all_zero(&bdev->uuid, sizeof(bdev->uuid))) {
343 		char uuid_str[SPDK_UUID_STRING_LEN];
344 
345 		spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &bdev->uuid);
346 		spdk_json_write_named_string(w, "uuid", uuid_str);
347 	}
348 
349 	if (spdk_bdev_get_md_size(bdev) != 0) {
350 		spdk_json_write_named_uint32(w, "md_size", spdk_bdev_get_md_size(bdev));
351 		spdk_json_write_named_bool(w, "md_interleave", spdk_bdev_is_md_interleaved(bdev));
352 		spdk_json_write_named_uint32(w, "dif_type", spdk_bdev_get_dif_type(bdev));
353 		if (spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) {
354 			spdk_json_write_named_bool(w, "dif_is_head_of_md", spdk_bdev_is_dif_head_of_md(bdev));
355 			spdk_json_write_named_object_begin(w, "enabled_dif_check_types");
356 			spdk_json_write_named_bool(w, "reftag",
357 						   spdk_bdev_is_dif_check_enabled(bdev, SPDK_DIF_CHECK_TYPE_REFTAG));
358 			spdk_json_write_named_bool(w, "apptag",
359 						   spdk_bdev_is_dif_check_enabled(bdev, SPDK_DIF_CHECK_TYPE_APPTAG));
360 			spdk_json_write_named_bool(w, "guard",
361 						   spdk_bdev_is_dif_check_enabled(bdev, SPDK_DIF_CHECK_TYPE_GUARD));
362 			spdk_json_write_object_end(w);
363 		}
364 	}
365 
366 	spdk_json_write_named_object_begin(w, "assigned_rate_limits");
367 	spdk_bdev_get_qos_rate_limits(bdev, qos_limits);
368 	for (i = 0; i < SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES; i++) {
369 		spdk_json_write_named_uint64(w, spdk_bdev_get_qos_rpc_type(i), qos_limits[i]);
370 	}
371 	spdk_json_write_object_end(w);
372 
373 	spdk_json_write_named_bool(w, "claimed", (bdev->internal.claim_module != NULL));
374 
375 	spdk_json_write_named_bool(w, "zoned", bdev->zoned);
376 	if (bdev->zoned) {
377 		spdk_json_write_named_uint64(w, "zone_size", bdev->zone_size);
378 		spdk_json_write_named_uint64(w, "max_open_zones", bdev->max_open_zones);
379 		spdk_json_write_named_uint64(w, "optimal_open_zones", bdev->optimal_open_zones);
380 	}
381 
382 	spdk_json_write_named_object_begin(w, "supported_io_types");
383 	spdk_json_write_named_bool(w, "read",
384 				   spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_READ));
385 	spdk_json_write_named_bool(w, "write",
386 				   spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE));
387 	spdk_json_write_named_bool(w, "unmap",
388 				   spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP));
389 	spdk_json_write_named_bool(w, "write_zeroes",
390 				   spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES));
391 	spdk_json_write_named_bool(w, "flush",
392 				   spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_FLUSH));
393 	spdk_json_write_named_bool(w, "reset",
394 				   spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_RESET));
395 	spdk_json_write_named_bool(w, "nvme_admin",
396 				   spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_NVME_ADMIN));
397 	spdk_json_write_named_bool(w, "nvme_io",
398 				   spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_NVME_IO));
399 	spdk_json_write_object_end(w);
400 
401 	spdk_json_write_named_object_begin(w, "driver_specific");
402 	spdk_bdev_dump_info_json(bdev, w);
403 	spdk_json_write_object_end(w);
404 
405 	spdk_json_write_object_end(w);
406 }
407 
408 struct rpc_bdev_get_bdevs {
409 	char *name;
410 };
411 
412 static void
413 free_rpc_bdev_get_bdevs(struct rpc_bdev_get_bdevs *r)
414 {
415 	free(r->name);
416 }
417 
418 static const struct spdk_json_object_decoder rpc_bdev_get_bdevs_decoders[] = {
419 	{"name", offsetof(struct rpc_bdev_get_bdevs, name), spdk_json_decode_string, true},
420 };
421 
422 static void
423 rpc_bdev_get_bdevs(struct spdk_jsonrpc_request *request,
424 		   const struct spdk_json_val *params)
425 {
426 	struct rpc_bdev_get_bdevs req = {};
427 	struct spdk_json_write_ctx *w;
428 	struct spdk_bdev *bdev = NULL;
429 
430 	if (params && spdk_json_decode_object(params, rpc_bdev_get_bdevs_decoders,
431 					      SPDK_COUNTOF(rpc_bdev_get_bdevs_decoders),
432 					      &req)) {
433 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
434 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
435 						 "spdk_json_decode_object failed");
436 		free_rpc_bdev_get_bdevs(&req);
437 		return;
438 	}
439 
440 	if (req.name) {
441 		bdev = spdk_bdev_get_by_name(req.name);
442 		if (bdev == NULL) {
443 			SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
444 			spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
445 			free_rpc_bdev_get_bdevs(&req);
446 			return;
447 		}
448 	}
449 
450 	free_rpc_bdev_get_bdevs(&req);
451 	w = spdk_jsonrpc_begin_result(request);
452 	spdk_json_write_array_begin(w);
453 
454 	if (bdev != NULL) {
455 		rpc_dump_bdev_info(w, bdev);
456 	} else {
457 		for (bdev = spdk_bdev_first(); bdev != NULL; bdev = spdk_bdev_next(bdev)) {
458 			rpc_dump_bdev_info(w, bdev);
459 		}
460 	}
461 
462 	spdk_json_write_array_end(w);
463 
464 	spdk_jsonrpc_end_result(request, w);
465 }
466 SPDK_RPC_REGISTER("bdev_get_bdevs", rpc_bdev_get_bdevs, SPDK_RPC_RUNTIME)
467 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_get_bdevs, get_bdevs)
468 
469 struct rpc_bdev_set_qd_sampling_period {
470 	char *name;
471 	uint64_t period;
472 };
473 
474 static void
475 free_rpc_bdev_set_qd_sampling_period(struct rpc_bdev_set_qd_sampling_period *r)
476 {
477 	free(r->name);
478 }
479 
480 static const struct spdk_json_object_decoder
481 	rpc_bdev_set_qd_sampling_period_decoders[] = {
482 	{"name", offsetof(struct rpc_bdev_set_qd_sampling_period, name), spdk_json_decode_string},
483 	{"period", offsetof(struct rpc_bdev_set_qd_sampling_period, period), spdk_json_decode_uint64},
484 };
485 
486 static void
487 rpc_bdev_set_qd_sampling_period(struct spdk_jsonrpc_request *request,
488 				const struct spdk_json_val *params)
489 {
490 	struct rpc_bdev_set_qd_sampling_period req = {0};
491 	struct spdk_bdev *bdev;
492 	struct spdk_json_write_ctx *w;
493 
494 	if (spdk_json_decode_object(params, rpc_bdev_set_qd_sampling_period_decoders,
495 				    SPDK_COUNTOF(rpc_bdev_set_qd_sampling_period_decoders),
496 				    &req)) {
497 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
498 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
499 						 "spdk_json_decode_object failed");
500 		goto cleanup;
501 	}
502 
503 	bdev = spdk_bdev_get_by_name(req.name);
504 	if (bdev == NULL) {
505 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
506 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
507 		goto cleanup;
508 	}
509 
510 	w = spdk_jsonrpc_begin_result(request);
511 	spdk_bdev_set_qd_sampling_period(bdev, req.period);
512 
513 	spdk_json_write_bool(w, true);
514 	spdk_jsonrpc_end_result(request, w);
515 
516 cleanup:
517 	free_rpc_bdev_set_qd_sampling_period(&req);
518 }
519 SPDK_RPC_REGISTER("bdev_set_qd_sampling_period",
520 		  rpc_bdev_set_qd_sampling_period,
521 		  SPDK_RPC_RUNTIME)
522 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_set_qd_sampling_period,
523 				   set_bdev_qd_sampling_period)
524 
525 struct rpc_bdev_set_qos_limit {
526 	char		*name;
527 	uint64_t	limits[SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES];
528 };
529 
530 static void
531 free_rpc_bdev_set_qos_limit(struct rpc_bdev_set_qos_limit *r)
532 {
533 	free(r->name);
534 }
535 
536 static const struct spdk_json_object_decoder rpc_bdev_set_qos_limit_decoders[] = {
537 	{"name", offsetof(struct rpc_bdev_set_qos_limit, name), spdk_json_decode_string},
538 	{
539 		"rw_ios_per_sec", offsetof(struct rpc_bdev_set_qos_limit,
540 					   limits[SPDK_BDEV_QOS_RW_IOPS_RATE_LIMIT]),
541 		spdk_json_decode_uint64, true
542 	},
543 	{
544 		"rw_mbytes_per_sec", offsetof(struct rpc_bdev_set_qos_limit,
545 					      limits[SPDK_BDEV_QOS_RW_BPS_RATE_LIMIT]),
546 		spdk_json_decode_uint64, true
547 	},
548 	{
549 		"r_mbytes_per_sec", offsetof(struct rpc_bdev_set_qos_limit,
550 					     limits[SPDK_BDEV_QOS_R_BPS_RATE_LIMIT]),
551 		spdk_json_decode_uint64, true
552 	},
553 	{
554 		"w_mbytes_per_sec", offsetof(struct rpc_bdev_set_qos_limit,
555 					     limits[SPDK_BDEV_QOS_W_BPS_RATE_LIMIT]),
556 		spdk_json_decode_uint64, true
557 	},
558 };
559 
560 static void
561 rpc_bdev_set_qos_limit_complete(void *cb_arg, int status)
562 {
563 	struct spdk_jsonrpc_request *request = cb_arg;
564 	struct spdk_json_write_ctx *w;
565 
566 	if (status != 0) {
567 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
568 						     "Failed to configure rate limit: %s",
569 						     spdk_strerror(-status));
570 		return;
571 	}
572 
573 	w = spdk_jsonrpc_begin_result(request);
574 	spdk_json_write_bool(w, true);
575 	spdk_jsonrpc_end_result(request, w);
576 }
577 
578 static void
579 rpc_bdev_set_qos_limit(struct spdk_jsonrpc_request *request,
580 		       const struct spdk_json_val *params)
581 {
582 	struct rpc_bdev_set_qos_limit req = {NULL, {UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX}};
583 	struct spdk_bdev *bdev;
584 	int i;
585 
586 	if (spdk_json_decode_object(params, rpc_bdev_set_qos_limit_decoders,
587 				    SPDK_COUNTOF(rpc_bdev_set_qos_limit_decoders),
588 				    &req)) {
589 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
590 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
591 						 "spdk_json_decode_object failed");
592 		goto cleanup;
593 	}
594 
595 	bdev = spdk_bdev_get_by_name(req.name);
596 	if (bdev == NULL) {
597 		SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
598 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
599 		goto cleanup;
600 	}
601 
602 	for (i = 0; i < SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES; i++) {
603 		if (req.limits[i] != UINT64_MAX) {
604 			break;
605 		}
606 	}
607 	if (i == SPDK_BDEV_QOS_NUM_RATE_LIMIT_TYPES) {
608 		SPDK_ERRLOG("no rate limits specified\n");
609 		spdk_jsonrpc_send_error_response(request, -EINVAL, "No rate limits specified");
610 		goto cleanup;
611 	}
612 
613 	spdk_bdev_set_qos_rate_limits(bdev, req.limits, rpc_bdev_set_qos_limit_complete, request);
614 
615 cleanup:
616 	free_rpc_bdev_set_qos_limit(&req);
617 }
618 
619 SPDK_RPC_REGISTER("bdev_set_qos_limit", rpc_bdev_set_qos_limit, SPDK_RPC_RUNTIME)
620 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_set_qos_limit, set_bdev_qos_limit)
621 
622 /* SPDK_RPC_ENABLE_BDEV_HISTOGRAM */
623 
624 struct rpc_bdev_enable_histogram_request {
625 	char *name;
626 	bool enable;
627 };
628 
629 static void
630 free_rpc_bdev_enable_histogram_request(struct rpc_bdev_enable_histogram_request *r)
631 {
632 	free(r->name);
633 }
634 
635 static const struct spdk_json_object_decoder rpc_bdev_enable_histogram_request_decoders[] = {
636 	{"name", offsetof(struct rpc_bdev_enable_histogram_request, name), spdk_json_decode_string},
637 	{"enable", offsetof(struct rpc_bdev_enable_histogram_request, enable), spdk_json_decode_bool},
638 };
639 
640 static void
641 bdev_histogram_status_cb(void *cb_arg, int status)
642 {
643 	struct spdk_jsonrpc_request *request = cb_arg;
644 	struct spdk_json_write_ctx *w = spdk_jsonrpc_begin_result(request);
645 
646 	spdk_json_write_bool(w, status == 0);
647 	spdk_jsonrpc_end_result(request, w);
648 }
649 
650 static void
651 rpc_bdev_enable_histogram(struct spdk_jsonrpc_request *request,
652 			  const struct spdk_json_val *params)
653 {
654 	struct rpc_bdev_enable_histogram_request req = {NULL};
655 	struct spdk_bdev *bdev;
656 
657 	if (spdk_json_decode_object(params, rpc_bdev_enable_histogram_request_decoders,
658 				    SPDK_COUNTOF(rpc_bdev_enable_histogram_request_decoders),
659 				    &req)) {
660 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
661 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
662 						 "spdk_json_decode_object failed");
663 		goto cleanup;
664 	}
665 
666 	bdev = spdk_bdev_get_by_name(req.name);
667 	if (bdev == NULL) {
668 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
669 		goto cleanup;
670 	}
671 
672 	spdk_bdev_histogram_enable(bdev, bdev_histogram_status_cb, request, req.enable);
673 
674 cleanup:
675 	free_rpc_bdev_enable_histogram_request(&req);
676 }
677 
678 SPDK_RPC_REGISTER("bdev_enable_histogram", rpc_bdev_enable_histogram, SPDK_RPC_RUNTIME)
679 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_enable_histogram, enable_bdev_histogram)
680 
681 /* SPDK_RPC_GET_BDEV_HISTOGRAM */
682 
683 struct rpc_bdev_get_histogram_request {
684 	char *name;
685 };
686 
687 static const struct spdk_json_object_decoder rpc_bdev_get_histogram_request_decoders[] = {
688 	{"name", offsetof(struct rpc_bdev_get_histogram_request, name), spdk_json_decode_string}
689 };
690 
691 static void
692 free_rpc_bdev_get_histogram_request(struct rpc_bdev_get_histogram_request *r)
693 {
694 	free(r->name);
695 }
696 
697 static void
698 _rpc_bdev_histogram_data_cb(void *cb_arg, int status, struct spdk_histogram_data *histogram)
699 {
700 	struct spdk_jsonrpc_request *request = cb_arg;
701 	struct spdk_json_write_ctx *w;
702 	int rc;
703 	char *encoded_histogram;
704 	size_t src_len, dst_len;
705 
706 
707 	if (status != 0) {
708 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
709 						 spdk_strerror(-status));
710 		goto invalid;
711 	}
712 
713 	src_len = SPDK_HISTOGRAM_NUM_BUCKETS(histogram) * sizeof(uint64_t);
714 	dst_len = spdk_base64_get_encoded_strlen(src_len) + 1;
715 
716 	encoded_histogram = malloc(dst_len);
717 	if (encoded_histogram == NULL) {
718 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
719 						 spdk_strerror(ENOMEM));
720 		goto invalid;
721 	}
722 
723 	rc = spdk_base64_encode(encoded_histogram, histogram->bucket, src_len);
724 	if (rc != 0) {
725 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
726 						 spdk_strerror(-rc));
727 		goto free_encoded_histogram;
728 	}
729 
730 	w = spdk_jsonrpc_begin_result(request);
731 	spdk_json_write_object_begin(w);
732 	spdk_json_write_named_string(w, "histogram", encoded_histogram);
733 	spdk_json_write_named_int64(w, "bucket_shift", histogram->bucket_shift);
734 	spdk_json_write_named_int64(w, "tsc_rate", spdk_get_ticks_hz());
735 	spdk_json_write_object_end(w);
736 	spdk_jsonrpc_end_result(request, w);
737 
738 free_encoded_histogram:
739 	free(encoded_histogram);
740 invalid:
741 	spdk_histogram_data_free(histogram);
742 }
743 
744 static void
745 rpc_bdev_get_histogram(struct spdk_jsonrpc_request *request,
746 		       const struct spdk_json_val *params)
747 {
748 	struct rpc_bdev_get_histogram_request req = {NULL};
749 	struct spdk_histogram_data *histogram;
750 	struct spdk_bdev *bdev;
751 
752 	if (spdk_json_decode_object(params, rpc_bdev_get_histogram_request_decoders,
753 				    SPDK_COUNTOF(rpc_bdev_get_histogram_request_decoders),
754 				    &req)) {
755 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
756 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
757 						 "spdk_json_decode_object failed");
758 		goto cleanup;
759 	}
760 
761 	bdev = spdk_bdev_get_by_name(req.name);
762 	if (bdev == NULL) {
763 		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
764 		goto cleanup;
765 	}
766 
767 	histogram = spdk_histogram_data_alloc();
768 	if (histogram == NULL) {
769 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
770 		goto cleanup;
771 	}
772 
773 	spdk_bdev_histogram_get(bdev, histogram, _rpc_bdev_histogram_data_cb, request);
774 
775 cleanup:
776 	free_rpc_bdev_get_histogram_request(&req);
777 }
778 
779 SPDK_RPC_REGISTER("bdev_get_histogram", rpc_bdev_get_histogram, SPDK_RPC_RUNTIME)
780 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_get_histogram, get_bdev_histogram)
781