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