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