xref: /spdk/lib/event/app_rpc.c (revision 4e8e97c886e47e337dc470ac8c1ffa044d729af0)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation. All rights reserved.
5  *   Copyright (c) 2019 Mellanox Technologies LTD. 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/stdinc.h"
35 
36 #include "spdk/event.h"
37 #include "spdk/rpc.h"
38 #include "spdk/string.h"
39 #include "spdk/util.h"
40 #include "spdk/env.h"
41 #include "spdk/thread.h"
42 
43 #include "spdk/log.h"
44 #include "spdk_internal/event.h"
45 #include "spdk_internal/thread.h"
46 
47 struct rpc_spdk_kill_instance {
48 	char *sig_name;
49 };
50 
51 static void
52 free_rpc_spdk_kill_instance(struct rpc_spdk_kill_instance *req)
53 {
54 	free(req->sig_name);
55 }
56 
57 static const struct spdk_json_object_decoder rpc_spdk_kill_instance_decoders[] = {
58 	{"sig_name", offsetof(struct rpc_spdk_kill_instance, sig_name), spdk_json_decode_string},
59 };
60 
61 static void
62 rpc_spdk_kill_instance(struct spdk_jsonrpc_request *request,
63 		       const struct spdk_json_val *params)
64 {
65 	static const struct {
66 		const char	*signal_string;
67 		int32_t		signal;
68 	} signals[] = {
69 		{"SIGINT",	SIGINT},
70 		{"SIGTERM",	SIGTERM},
71 		{"SIGQUIT",	SIGQUIT},
72 		{"SIGHUP",	SIGHUP},
73 		{"SIGKILL",	SIGKILL},
74 		{"SIGUSR1",	SIGUSR1},
75 	};
76 	size_t i, sig_count;
77 	int signal;
78 	struct rpc_spdk_kill_instance req = {};
79 	struct spdk_json_write_ctx *w;
80 
81 	if (spdk_json_decode_object(params, rpc_spdk_kill_instance_decoders,
82 				    SPDK_COUNTOF(rpc_spdk_kill_instance_decoders),
83 				    &req)) {
84 		SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n");
85 		goto invalid;
86 	}
87 
88 	sig_count = SPDK_COUNTOF(signals);
89 	signal = spdk_strtol(req.sig_name, 10);
90 	for (i = 0 ; i < sig_count; i++) {
91 		if (strcmp(req.sig_name, signals[i].signal_string) == 0 ||
92 		    signal == signals[i].signal) {
93 			break;
94 		}
95 	}
96 
97 	if (i == sig_count) {
98 		goto invalid;
99 	}
100 
101 	SPDK_DEBUGLOG(app_rpc, "sending signal %d\n", signals[i].signal);
102 	free_rpc_spdk_kill_instance(&req);
103 	kill(getpid(), signals[i].signal);
104 
105 	w = spdk_jsonrpc_begin_result(request);
106 	spdk_json_write_bool(w, true);
107 	spdk_jsonrpc_end_result(request, w);
108 	return;
109 
110 invalid:
111 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
112 	free_rpc_spdk_kill_instance(&req);
113 }
114 SPDK_RPC_REGISTER("spdk_kill_instance", rpc_spdk_kill_instance, SPDK_RPC_RUNTIME)
115 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(spdk_kill_instance, kill_instance)
116 
117 
118 struct rpc_framework_monitor_context_switch {
119 	bool enabled;
120 };
121 
122 static const struct spdk_json_object_decoder rpc_framework_monitor_context_switch_decoders[] = {
123 	{"enabled", offsetof(struct rpc_framework_monitor_context_switch, enabled), spdk_json_decode_bool},
124 };
125 
126 static void
127 rpc_framework_monitor_context_switch(struct spdk_jsonrpc_request *request,
128 				     const struct spdk_json_val *params)
129 {
130 	struct rpc_framework_monitor_context_switch req = {};
131 	struct spdk_json_write_ctx *w;
132 
133 	if (params != NULL) {
134 		if (spdk_json_decode_object(params, rpc_framework_monitor_context_switch_decoders,
135 					    SPDK_COUNTOF(rpc_framework_monitor_context_switch_decoders),
136 					    &req)) {
137 			SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n");
138 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
139 			return;
140 		}
141 
142 		spdk_framework_enable_context_switch_monitor(req.enabled);
143 	}
144 
145 	w = spdk_jsonrpc_begin_result(request);
146 	spdk_json_write_object_begin(w);
147 
148 	spdk_json_write_named_bool(w, "enabled", spdk_framework_context_switch_monitor_enabled());
149 
150 	spdk_json_write_object_end(w);
151 	spdk_jsonrpc_end_result(request, w);
152 }
153 
154 SPDK_RPC_REGISTER("framework_monitor_context_switch", rpc_framework_monitor_context_switch,
155 		  SPDK_RPC_RUNTIME)
156 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(framework_monitor_context_switch, context_switch_monitor)
157 
158 struct rpc_get_stats_ctx {
159 	struct spdk_jsonrpc_request *request;
160 	struct spdk_json_write_ctx *w;
161 	uint64_t now;
162 };
163 
164 static void
165 rpc_thread_get_stats_done(void *arg)
166 {
167 	struct rpc_get_stats_ctx *ctx = arg;
168 
169 	spdk_json_write_array_end(ctx->w);
170 	spdk_json_write_object_end(ctx->w);
171 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
172 
173 	free(ctx);
174 }
175 
176 static void
177 rpc_thread_get_stats_for_each(struct spdk_jsonrpc_request *request, spdk_msg_fn fn)
178 {
179 	struct rpc_get_stats_ctx *ctx;
180 
181 	ctx = calloc(1, sizeof(*ctx));
182 	if (!ctx) {
183 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
184 						 "Memory allocation error");
185 		return;
186 	}
187 	ctx->request = request;
188 
189 	ctx->w = spdk_jsonrpc_begin_result(ctx->request);
190 	spdk_json_write_object_begin(ctx->w);
191 	spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz());
192 	spdk_json_write_named_array_begin(ctx->w, "threads");
193 
194 	spdk_for_each_thread(fn, ctx, rpc_thread_get_stats_done);
195 }
196 
197 static void
198 _rpc_thread_get_stats(void *arg)
199 {
200 	struct rpc_get_stats_ctx *ctx = arg;
201 	struct spdk_thread *thread = spdk_get_thread();
202 	struct spdk_poller *poller;
203 	struct spdk_thread_stats stats;
204 	uint64_t active_pollers_count = 0;
205 	uint64_t timed_pollers_count = 0;
206 	uint64_t paused_pollers_count = 0;
207 
208 	TAILQ_FOREACH(poller, &thread->active_pollers, tailq) {
209 		active_pollers_count++;
210 	}
211 	TAILQ_FOREACH(poller, &thread->timed_pollers, tailq) {
212 		timed_pollers_count++;
213 	}
214 	TAILQ_FOREACH(poller, &thread->paused_pollers, tailq) {
215 		paused_pollers_count++;
216 	}
217 
218 	if (0 == spdk_thread_get_stats(&stats)) {
219 		spdk_json_write_object_begin(ctx->w);
220 		spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
221 		spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
222 		spdk_json_write_named_string(ctx->w, "cpumask",
223 					     spdk_cpuset_fmt(spdk_thread_get_cpumask(thread)));
224 		spdk_json_write_named_uint64(ctx->w, "busy", stats.busy_tsc);
225 		spdk_json_write_named_uint64(ctx->w, "idle", stats.idle_tsc);
226 		spdk_json_write_named_uint64(ctx->w, "active_pollers_count", active_pollers_count);
227 		spdk_json_write_named_uint64(ctx->w, "timed_pollers_count", timed_pollers_count);
228 		spdk_json_write_named_uint64(ctx->w, "paused_pollers_count", paused_pollers_count);
229 		spdk_json_write_object_end(ctx->w);
230 	}
231 }
232 
233 static void
234 rpc_thread_get_stats(struct spdk_jsonrpc_request *request,
235 		     const struct spdk_json_val *params)
236 {
237 	if (params) {
238 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
239 						 "'thread_get_stats' requires no arguments");
240 		return;
241 	}
242 
243 	rpc_thread_get_stats_for_each(request, _rpc_thread_get_stats);
244 }
245 
246 SPDK_RPC_REGISTER("thread_get_stats", rpc_thread_get_stats, SPDK_RPC_RUNTIME)
247 
248 static void
249 rpc_get_poller(struct spdk_poller *poller, struct spdk_json_write_ctx *w)
250 {
251 	spdk_json_write_object_begin(w);
252 	spdk_json_write_named_string(w, "name", poller->name);
253 	spdk_json_write_named_string(w, "state", spdk_poller_state_str(poller->state));
254 	spdk_json_write_named_uint64(w, "run_count", poller->run_count);
255 	spdk_json_write_named_uint64(w, "busy_count", poller->busy_count);
256 	if (poller->period_ticks) {
257 		spdk_json_write_named_uint64(w, "period_ticks", poller->period_ticks);
258 	}
259 	spdk_json_write_object_end(w);
260 }
261 
262 static void
263 _rpc_thread_get_pollers(void *arg)
264 {
265 	struct rpc_get_stats_ctx *ctx = arg;
266 	struct spdk_thread *thread = spdk_get_thread();
267 	struct spdk_poller *poller;
268 
269 	spdk_json_write_object_begin(ctx->w);
270 	spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
271 	spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
272 
273 	spdk_json_write_named_array_begin(ctx->w, "active_pollers");
274 	TAILQ_FOREACH(poller, &thread->active_pollers, tailq) {
275 		rpc_get_poller(poller, ctx->w);
276 	}
277 	spdk_json_write_array_end(ctx->w);
278 
279 	spdk_json_write_named_array_begin(ctx->w, "timed_pollers");
280 	TAILQ_FOREACH(poller, &thread->timed_pollers, tailq) {
281 		rpc_get_poller(poller, ctx->w);
282 	}
283 	spdk_json_write_array_end(ctx->w);
284 
285 	spdk_json_write_named_array_begin(ctx->w, "paused_pollers");
286 	TAILQ_FOREACH(poller, &thread->paused_pollers, tailq) {
287 		rpc_get_poller(poller, ctx->w);
288 	}
289 	spdk_json_write_array_end(ctx->w);
290 
291 	spdk_json_write_object_end(ctx->w);
292 }
293 
294 static void
295 rpc_thread_get_pollers(struct spdk_jsonrpc_request *request,
296 		       const struct spdk_json_val *params)
297 {
298 	if (params) {
299 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
300 						 "'thread_get_pollers' requires no arguments");
301 		return;
302 	}
303 
304 	rpc_thread_get_stats_for_each(request, _rpc_thread_get_pollers);
305 }
306 
307 SPDK_RPC_REGISTER("thread_get_pollers", rpc_thread_get_pollers, SPDK_RPC_RUNTIME)
308 
309 static void
310 rpc_get_io_channel(struct spdk_io_channel *ch, struct spdk_json_write_ctx *w)
311 {
312 	spdk_json_write_object_begin(w);
313 	spdk_json_write_named_string(w, "name", spdk_io_device_get_name(ch->dev));
314 	spdk_json_write_named_uint32(w, "ref", ch->ref);
315 	spdk_json_write_object_end(w);
316 }
317 
318 static void
319 _rpc_thread_get_io_channels(void *arg)
320 {
321 	struct rpc_get_stats_ctx *ctx = arg;
322 	struct spdk_thread *thread = spdk_get_thread();
323 	struct spdk_io_channel *ch;
324 
325 	spdk_json_write_object_begin(ctx->w);
326 	spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
327 
328 	spdk_json_write_named_array_begin(ctx->w, "io_channels");
329 	TAILQ_FOREACH(ch, &thread->io_channels, tailq) {
330 		rpc_get_io_channel(ch, ctx->w);
331 	}
332 	spdk_json_write_array_end(ctx->w);
333 
334 	spdk_json_write_object_end(ctx->w);
335 }
336 
337 static void
338 rpc_thread_get_io_channels(struct spdk_jsonrpc_request *request,
339 			   const struct spdk_json_val *params)
340 {
341 	if (params) {
342 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
343 						 "'thread_get_io_channels' requires no arguments");
344 		return;
345 	}
346 
347 	rpc_thread_get_stats_for_each(request, _rpc_thread_get_io_channels);
348 }
349 
350 SPDK_RPC_REGISTER("thread_get_io_channels", rpc_thread_get_io_channels, SPDK_RPC_RUNTIME);
351 
352 static void
353 rpc_framework_get_reactors_done(void *arg1, void *arg2)
354 {
355 	struct rpc_get_stats_ctx *ctx = arg1;
356 
357 	spdk_json_write_array_end(ctx->w);
358 	spdk_json_write_object_end(ctx->w);
359 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
360 
361 	free(ctx);
362 }
363 
364 #define GET_DELTA(end, start)	(end >= start ? end - start : 0)
365 
366 static void
367 _rpc_framework_get_reactors(void *arg1, void *arg2)
368 {
369 	struct rpc_get_stats_ctx *ctx = arg1;
370 	uint32_t current_core;
371 	struct spdk_reactor *reactor;
372 	struct spdk_lw_thread *lw_thread;
373 	struct spdk_thread *thread;
374 
375 	current_core = spdk_env_get_current_core();
376 	reactor = spdk_reactor_get(current_core);
377 
378 	assert(reactor != NULL);
379 
380 	spdk_json_write_object_begin(ctx->w);
381 	spdk_json_write_named_uint32(ctx->w, "lcore", current_core);
382 	spdk_json_write_named_uint64(ctx->w, "busy", reactor->busy_tsc);
383 	spdk_json_write_named_uint64(ctx->w, "idle", reactor->idle_tsc);
384 
385 	spdk_json_write_named_array_begin(ctx->w, "lw_threads");
386 	TAILQ_FOREACH(lw_thread, &reactor->threads, link) {
387 		thread = spdk_thread_get_from_ctx(lw_thread);
388 
389 		spdk_json_write_object_begin(ctx->w);
390 		spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
391 		spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
392 		spdk_json_write_named_string(ctx->w, "cpumask",
393 					     spdk_cpuset_fmt(spdk_thread_get_cpumask(thread)));
394 		spdk_json_write_named_uint64(ctx->w, "elapsed",
395 					     GET_DELTA(ctx->now, lw_thread->tsc_start));
396 		spdk_json_write_object_end(ctx->w);
397 	}
398 	spdk_json_write_array_end(ctx->w);
399 
400 	spdk_json_write_object_end(ctx->w);
401 }
402 
403 static void
404 rpc_framework_get_reactors(struct spdk_jsonrpc_request *request,
405 			   const struct spdk_json_val *params)
406 {
407 	struct rpc_get_stats_ctx *ctx;
408 
409 	if (params) {
410 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
411 						 "`framework_get_reactors` requires no arguments");
412 		return;
413 	}
414 
415 	ctx = calloc(1, sizeof(*ctx));
416 	if (!ctx) {
417 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
418 						 "Memory allocation error");
419 		return;
420 	}
421 
422 	ctx->now = spdk_get_ticks();
423 	ctx->request = request;
424 	ctx->w = spdk_jsonrpc_begin_result(ctx->request);
425 
426 	spdk_json_write_object_begin(ctx->w);
427 	spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz());
428 	spdk_json_write_named_array_begin(ctx->w, "reactors");
429 
430 	spdk_for_each_reactor(_rpc_framework_get_reactors, ctx, NULL,
431 			      rpc_framework_get_reactors_done);
432 }
433 
434 SPDK_RPC_REGISTER("framework_get_reactors", rpc_framework_get_reactors, SPDK_RPC_RUNTIME)
435 
436 struct rpc_thread_set_cpumask_ctx {
437 	struct spdk_jsonrpc_request *request;
438 	struct spdk_cpuset cpumask;
439 	int status;
440 	struct spdk_thread *orig_thread;
441 };
442 
443 static void
444 rpc_thread_set_cpumask_done(void *_ctx)
445 {
446 	struct rpc_thread_set_cpumask_ctx *ctx = _ctx;
447 	struct spdk_json_write_ctx *w;
448 
449 	if (ctx->status == 0) {
450 		w = spdk_jsonrpc_begin_result(ctx->request);
451 		spdk_json_write_bool(w, true);
452 		spdk_jsonrpc_end_result(ctx->request, w);
453 	} else {
454 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
455 						 spdk_strerror(-ctx->status));
456 	}
457 
458 	free(ctx);
459 }
460 
461 static void
462 _rpc_thread_set_cpumask(void *_ctx)
463 {
464 	struct rpc_thread_set_cpumask_ctx *ctx = _ctx;
465 
466 	ctx->status = spdk_thread_set_cpumask(&ctx->cpumask);
467 
468 	spdk_thread_send_msg(ctx->orig_thread, rpc_thread_set_cpumask_done, ctx);
469 }
470 
471 struct rpc_thread_set_cpumask {
472 	uint64_t id;
473 	char *cpumask;
474 };
475 
476 static const struct spdk_json_object_decoder rpc_thread_set_cpumask_decoders[] = {
477 	{"id", offsetof(struct rpc_thread_set_cpumask, id), spdk_json_decode_uint64},
478 	{"cpumask", offsetof(struct rpc_thread_set_cpumask, cpumask), spdk_json_decode_string},
479 };
480 
481 static void
482 rpc_thread_set_cpumask(struct spdk_jsonrpc_request *request,
483 		       const struct spdk_json_val *params)
484 {
485 	struct rpc_thread_set_cpumask req = {};
486 	struct rpc_thread_set_cpumask_ctx *ctx;
487 	const struct spdk_cpuset *coremask;
488 	struct spdk_cpuset tmp_mask;
489 	struct spdk_thread *thread;
490 	int rc;
491 
492 	ctx = calloc(1, sizeof(*ctx));
493 	if (ctx == NULL) {
494 		SPDK_ERRLOG("Memory allocation failed\n");
495 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
496 						 "Memory allocation failed");
497 		return;
498 	}
499 
500 	if (spdk_json_decode_object(params, rpc_thread_set_cpumask_decoders,
501 				    SPDK_COUNTOF(rpc_thread_set_cpumask_decoders),
502 				    &req)) {
503 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
504 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
505 						 "spdk_json_decode_object failed");
506 		goto err;
507 	}
508 
509 	thread = spdk_thread_get_by_id(req.id);
510 	if (thread == NULL) {
511 		SPDK_ERRLOG("Thread %" PRIu64 " does not exist\n", req.id);
512 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
513 						     "Thread %" PRIu64 " does not exist", req.id);
514 		goto err;
515 	}
516 
517 	rc = spdk_app_parse_core_mask(req.cpumask, &ctx->cpumask);
518 	if (rc != 0) {
519 		SPDK_ERRLOG("Invalid cpumask %s\n", req.cpumask);
520 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
521 						     "Invalid cpumask %s", req.cpumask);
522 		goto err;
523 	}
524 
525 	if (spdk_cpuset_count(&ctx->cpumask) == 0) {
526 		coremask = spdk_app_get_core_mask();
527 		spdk_cpuset_copy(&tmp_mask, coremask);
528 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
529 						     "No CPU is selected from reactor mask %s\n",
530 						     spdk_cpuset_fmt(&tmp_mask));
531 		goto err;
532 	}
533 
534 	ctx->request = request;
535 	ctx->orig_thread = spdk_get_thread();
536 
537 	spdk_thread_send_msg(thread, _rpc_thread_set_cpumask, ctx);
538 
539 	free(req.cpumask);
540 	return;
541 
542 err:
543 	free(req.cpumask);
544 	free(ctx);
545 }
546 SPDK_RPC_REGISTER("thread_set_cpumask", rpc_thread_set_cpumask, SPDK_RPC_RUNTIME)
547 SPDK_LOG_REGISTER_COMPONENT(app_rpc)
548