Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2016 Intel Corporation. All rights reserved.
3 : * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
4 : */
5 :
6 : #include "spdk/stdinc.h"
7 :
8 : #include "spdk/event.h"
9 : #include "spdk/rpc.h"
10 : #include "spdk/string.h"
11 : #include "spdk/util.h"
12 : #include "spdk/env.h"
13 : #include "spdk/scheduler.h"
14 : #include "spdk/thread.h"
15 : #include "spdk/json.h"
16 :
17 : #include "spdk/log.h"
18 : #include "spdk_internal/event.h"
19 : #include "spdk_internal/thread.h"
20 :
21 : struct rpc_spdk_kill_instance {
22 : char *sig_name;
23 : };
24 :
25 : static void
26 0 : free_rpc_spdk_kill_instance(struct rpc_spdk_kill_instance *req)
27 : {
28 0 : free(req->sig_name);
29 0 : }
30 :
31 : static const struct spdk_json_object_decoder rpc_spdk_kill_instance_decoders[] = {
32 : {"sig_name", offsetof(struct rpc_spdk_kill_instance, sig_name), spdk_json_decode_string},
33 : };
34 :
35 : static void
36 0 : rpc_spdk_kill_instance(struct spdk_jsonrpc_request *request,
37 : const struct spdk_json_val *params)
38 : {
39 : static const struct {
40 : const char *signal_string;
41 : int32_t signal;
42 : } signals[] = {
43 : {"SIGINT", SIGINT},
44 : {"SIGTERM", SIGTERM},
45 : {"SIGQUIT", SIGQUIT},
46 : {"SIGHUP", SIGHUP},
47 : {"SIGKILL", SIGKILL},
48 : {"SIGUSR1", SIGUSR1},
49 : };
50 : size_t i, sig_count;
51 : int signal;
52 0 : struct rpc_spdk_kill_instance req = {};
53 :
54 0 : if (spdk_json_decode_object(params, rpc_spdk_kill_instance_decoders,
55 : SPDK_COUNTOF(rpc_spdk_kill_instance_decoders),
56 : &req)) {
57 0 : SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n");
58 0 : goto invalid;
59 : }
60 :
61 0 : sig_count = SPDK_COUNTOF(signals);
62 0 : signal = spdk_strtol(req.sig_name, 10);
63 0 : for (i = 0 ; i < sig_count; i++) {
64 0 : if (strcmp(req.sig_name, signals[i].signal_string) == 0 ||
65 0 : signal == signals[i].signal) {
66 : break;
67 : }
68 : }
69 :
70 0 : if (i == sig_count) {
71 0 : goto invalid;
72 : }
73 :
74 0 : SPDK_DEBUGLOG(app_rpc, "sending signal %d\n", signals[i].signal);
75 0 : free_rpc_spdk_kill_instance(&req);
76 0 : kill(getpid(), signals[i].signal);
77 :
78 0 : spdk_jsonrpc_send_bool_response(request, true);
79 0 : return;
80 :
81 0 : invalid:
82 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
83 0 : free_rpc_spdk_kill_instance(&req);
84 : }
85 0 : SPDK_RPC_REGISTER("spdk_kill_instance", rpc_spdk_kill_instance, SPDK_RPC_RUNTIME)
86 :
87 :
88 : struct rpc_framework_monitor_context_switch {
89 : bool enabled;
90 : };
91 :
92 : static const struct spdk_json_object_decoder rpc_framework_monitor_context_switch_decoders[] = {
93 : {"enabled", offsetof(struct rpc_framework_monitor_context_switch, enabled), spdk_json_decode_bool},
94 : };
95 :
96 : static void
97 0 : rpc_framework_monitor_context_switch(struct spdk_jsonrpc_request *request,
98 : const struct spdk_json_val *params)
99 : {
100 0 : struct rpc_framework_monitor_context_switch req = {};
101 : struct spdk_json_write_ctx *w;
102 :
103 0 : if (params != NULL) {
104 0 : if (spdk_json_decode_object(params, rpc_framework_monitor_context_switch_decoders,
105 : SPDK_COUNTOF(rpc_framework_monitor_context_switch_decoders),
106 : &req)) {
107 0 : SPDK_DEBUGLOG(app_rpc, "spdk_json_decode_object failed\n");
108 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
109 0 : return;
110 : }
111 :
112 0 : spdk_framework_enable_context_switch_monitor(req.enabled);
113 : }
114 :
115 0 : w = spdk_jsonrpc_begin_result(request);
116 0 : spdk_json_write_object_begin(w);
117 :
118 0 : spdk_json_write_named_bool(w, "enabled", spdk_framework_context_switch_monitor_enabled());
119 :
120 0 : spdk_json_write_object_end(w);
121 0 : spdk_jsonrpc_end_result(request, w);
122 : }
123 :
124 0 : SPDK_RPC_REGISTER("framework_monitor_context_switch", rpc_framework_monitor_context_switch,
125 : SPDK_RPC_RUNTIME)
126 :
127 : struct rpc_get_stats_ctx {
128 : struct spdk_jsonrpc_request *request;
129 : struct spdk_json_write_ctx *w;
130 : uint64_t now;
131 : };
132 :
133 : static void
134 0 : rpc_thread_get_stats_done(void *arg)
135 : {
136 0 : struct rpc_get_stats_ctx *ctx = arg;
137 :
138 0 : spdk_json_write_array_end(ctx->w);
139 0 : spdk_json_write_object_end(ctx->w);
140 0 : spdk_jsonrpc_end_result(ctx->request, ctx->w);
141 :
142 0 : free(ctx);
143 0 : }
144 :
145 : static void
146 0 : rpc_thread_get_stats_for_each(struct spdk_jsonrpc_request *request, spdk_msg_fn fn)
147 : {
148 : struct rpc_get_stats_ctx *ctx;
149 :
150 0 : ctx = calloc(1, sizeof(*ctx));
151 0 : if (!ctx) {
152 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
153 : "Memory allocation error");
154 0 : return;
155 : }
156 0 : ctx->request = request;
157 :
158 0 : ctx->w = spdk_jsonrpc_begin_result(ctx->request);
159 0 : spdk_json_write_object_begin(ctx->w);
160 0 : spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz());
161 0 : spdk_json_write_named_array_begin(ctx->w, "threads");
162 :
163 0 : spdk_for_each_thread(fn, ctx, rpc_thread_get_stats_done);
164 : }
165 :
166 : static void
167 0 : _rpc_thread_get_stats(void *arg)
168 : {
169 0 : struct rpc_get_stats_ctx *ctx = arg;
170 0 : struct spdk_thread *thread = spdk_get_thread();
171 0 : struct spdk_cpuset tmp_mask = {};
172 : struct spdk_poller *poller;
173 0 : struct spdk_thread_stats stats;
174 0 : uint64_t active_pollers_count = 0;
175 0 : uint64_t timed_pollers_count = 0;
176 0 : uint64_t paused_pollers_count = 0;
177 :
178 0 : for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL;
179 0 : poller = spdk_thread_get_next_active_poller(poller)) {
180 0 : active_pollers_count++;
181 : }
182 :
183 0 : for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL;
184 0 : poller = spdk_thread_get_next_timed_poller(poller)) {
185 0 : timed_pollers_count++;
186 : }
187 :
188 0 : for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL;
189 0 : poller = spdk_thread_get_next_paused_poller(poller)) {
190 0 : paused_pollers_count++;
191 : }
192 :
193 0 : if (0 == spdk_thread_get_stats(&stats)) {
194 0 : spdk_json_write_object_begin(ctx->w);
195 0 : spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
196 0 : spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
197 0 : spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask());
198 0 : spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread));
199 0 : spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask));
200 0 : spdk_json_write_named_uint64(ctx->w, "busy", stats.busy_tsc);
201 0 : spdk_json_write_named_uint64(ctx->w, "idle", stats.idle_tsc);
202 0 : spdk_json_write_named_uint64(ctx->w, "active_pollers_count", active_pollers_count);
203 0 : spdk_json_write_named_uint64(ctx->w, "timed_pollers_count", timed_pollers_count);
204 0 : spdk_json_write_named_uint64(ctx->w, "paused_pollers_count", paused_pollers_count);
205 0 : spdk_json_write_object_end(ctx->w);
206 : }
207 0 : }
208 :
209 : static void
210 0 : rpc_thread_get_stats(struct spdk_jsonrpc_request *request,
211 : const struct spdk_json_val *params)
212 : {
213 0 : if (params) {
214 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
215 : "'thread_get_stats' requires no arguments");
216 0 : return;
217 : }
218 :
219 0 : rpc_thread_get_stats_for_each(request, _rpc_thread_get_stats);
220 : }
221 :
222 0 : SPDK_RPC_REGISTER("thread_get_stats", rpc_thread_get_stats, SPDK_RPC_RUNTIME)
223 :
224 : static void
225 0 : rpc_get_poller(struct spdk_poller *poller, struct spdk_json_write_ctx *w)
226 : {
227 0 : struct spdk_poller_stats stats;
228 : uint64_t period_ticks;
229 :
230 0 : period_ticks = spdk_poller_get_period_ticks(poller);
231 0 : spdk_poller_get_stats(poller, &stats);
232 :
233 0 : spdk_json_write_object_begin(w);
234 0 : spdk_json_write_named_string(w, "name", spdk_poller_get_name(poller));
235 0 : spdk_json_write_named_uint64(w, "id", spdk_poller_get_id(poller));
236 0 : spdk_json_write_named_string(w, "state", spdk_poller_get_state_str(poller));
237 0 : spdk_json_write_named_uint64(w, "run_count", stats.run_count);
238 0 : spdk_json_write_named_uint64(w, "busy_count", stats.busy_count);
239 0 : if (period_ticks) {
240 0 : spdk_json_write_named_uint64(w, "period_ticks", period_ticks);
241 : }
242 0 : spdk_json_write_object_end(w);
243 0 : }
244 :
245 : static void
246 0 : _rpc_thread_get_pollers(void *arg)
247 : {
248 0 : struct rpc_get_stats_ctx *ctx = arg;
249 0 : struct spdk_thread *thread = spdk_get_thread();
250 : struct spdk_poller *poller;
251 :
252 0 : spdk_json_write_object_begin(ctx->w);
253 0 : spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
254 0 : spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
255 :
256 0 : spdk_json_write_named_array_begin(ctx->w, "active_pollers");
257 0 : for (poller = spdk_thread_get_first_active_poller(thread); poller != NULL;
258 0 : poller = spdk_thread_get_next_active_poller(poller)) {
259 0 : rpc_get_poller(poller, ctx->w);
260 : }
261 0 : spdk_json_write_array_end(ctx->w);
262 :
263 0 : spdk_json_write_named_array_begin(ctx->w, "timed_pollers");
264 0 : for (poller = spdk_thread_get_first_timed_poller(thread); poller != NULL;
265 0 : poller = spdk_thread_get_next_timed_poller(poller)) {
266 0 : rpc_get_poller(poller, ctx->w);
267 : }
268 0 : spdk_json_write_array_end(ctx->w);
269 :
270 0 : spdk_json_write_named_array_begin(ctx->w, "paused_pollers");
271 0 : for (poller = spdk_thread_get_first_paused_poller(thread); poller != NULL;
272 0 : poller = spdk_thread_get_next_paused_poller(poller)) {
273 0 : rpc_get_poller(poller, ctx->w);
274 : }
275 0 : spdk_json_write_array_end(ctx->w);
276 :
277 0 : spdk_json_write_object_end(ctx->w);
278 0 : }
279 :
280 : static void
281 0 : rpc_thread_get_pollers(struct spdk_jsonrpc_request *request,
282 : const struct spdk_json_val *params)
283 : {
284 0 : if (params) {
285 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
286 : "'thread_get_pollers' requires no arguments");
287 0 : return;
288 : }
289 :
290 0 : rpc_thread_get_stats_for_each(request, _rpc_thread_get_pollers);
291 : }
292 :
293 0 : SPDK_RPC_REGISTER("thread_get_pollers", rpc_thread_get_pollers, SPDK_RPC_RUNTIME)
294 :
295 : static void
296 0 : rpc_get_io_channel(struct spdk_io_channel *ch, struct spdk_json_write_ctx *w)
297 : {
298 0 : spdk_json_write_object_begin(w);
299 0 : spdk_json_write_named_string(w, "name", spdk_io_channel_get_io_device_name(ch));
300 0 : spdk_json_write_named_uint32(w, "ref", spdk_io_channel_get_ref_count(ch));
301 0 : spdk_json_write_object_end(w);
302 0 : }
303 :
304 : static void
305 0 : _rpc_thread_get_io_channels(void *arg)
306 : {
307 0 : struct rpc_get_stats_ctx *ctx = arg;
308 0 : struct spdk_thread *thread = spdk_get_thread();
309 : struct spdk_io_channel *ch;
310 :
311 0 : spdk_json_write_object_begin(ctx->w);
312 0 : spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
313 :
314 0 : spdk_json_write_named_array_begin(ctx->w, "io_channels");
315 0 : for (ch = spdk_thread_get_first_io_channel(thread); ch != NULL;
316 0 : ch = spdk_thread_get_next_io_channel(ch)) {
317 0 : rpc_get_io_channel(ch, ctx->w);
318 : }
319 0 : spdk_json_write_array_end(ctx->w);
320 :
321 0 : spdk_json_write_object_end(ctx->w);
322 0 : }
323 :
324 : static void
325 0 : rpc_thread_get_io_channels(struct spdk_jsonrpc_request *request,
326 : const struct spdk_json_val *params)
327 : {
328 0 : if (params) {
329 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
330 : "'thread_get_io_channels' requires no arguments");
331 0 : return;
332 : }
333 :
334 0 : rpc_thread_get_stats_for_each(request, _rpc_thread_get_io_channels);
335 : }
336 :
337 0 : SPDK_RPC_REGISTER("thread_get_io_channels", rpc_thread_get_io_channels, SPDK_RPC_RUNTIME);
338 :
339 : static void
340 0 : rpc_framework_get_reactors_done(void *arg1, void *arg2)
341 : {
342 0 : struct rpc_get_stats_ctx *ctx = arg1;
343 :
344 0 : spdk_json_write_array_end(ctx->w);
345 0 : spdk_json_write_object_end(ctx->w);
346 0 : spdk_jsonrpc_end_result(ctx->request, ctx->w);
347 :
348 0 : free(ctx);
349 0 : }
350 :
351 : #define GET_DELTA(end, start) (end >= start ? end - start : 0)
352 :
353 : static void
354 0 : _rpc_framework_get_reactors(void *arg1, void *arg2)
355 : {
356 0 : struct rpc_get_stats_ctx *ctx = arg1;
357 : uint32_t current_core;
358 : uint32_t curr_core_freq;
359 : struct spdk_reactor *reactor;
360 : struct spdk_lw_thread *lw_thread;
361 : struct spdk_thread *thread;
362 0 : struct spdk_cpuset tmp_mask = {};
363 : struct spdk_governor *governor;
364 :
365 0 : current_core = spdk_env_get_current_core();
366 0 : reactor = spdk_reactor_get(current_core);
367 :
368 0 : assert(reactor != NULL);
369 :
370 0 : spdk_json_write_object_begin(ctx->w);
371 0 : spdk_json_write_named_uint32(ctx->w, "lcore", current_core);
372 0 : spdk_json_write_named_uint64(ctx->w, "busy", reactor->busy_tsc);
373 0 : spdk_json_write_named_uint64(ctx->w, "idle", reactor->idle_tsc);
374 0 : spdk_json_write_named_bool(ctx->w, "in_interrupt", reactor->in_interrupt);
375 :
376 0 : governor = spdk_governor_get();
377 0 : if (governor != NULL) {
378 : /* Governor returns core freqs in kHz, we want MHz. */
379 0 : curr_core_freq = governor->get_core_curr_freq(current_core) / 1000;
380 0 : spdk_json_write_named_uint32(ctx->w, "core_freq", curr_core_freq);
381 : }
382 :
383 0 : spdk_json_write_named_array_begin(ctx->w, "lw_threads");
384 0 : TAILQ_FOREACH(lw_thread, &reactor->threads, link) {
385 0 : thread = spdk_thread_get_from_ctx(lw_thread);
386 :
387 0 : spdk_json_write_object_begin(ctx->w);
388 0 : spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread));
389 0 : spdk_json_write_named_uint64(ctx->w, "id", spdk_thread_get_id(thread));
390 0 : spdk_cpuset_copy(&tmp_mask, spdk_app_get_core_mask());
391 0 : spdk_cpuset_and(&tmp_mask, spdk_thread_get_cpumask(thread));
392 0 : spdk_json_write_named_string(ctx->w, "cpumask", spdk_cpuset_fmt(&tmp_mask));
393 0 : spdk_json_write_named_uint64(ctx->w, "elapsed",
394 0 : GET_DELTA(ctx->now, lw_thread->tsc_start));
395 0 : spdk_json_write_object_end(ctx->w);
396 : }
397 0 : spdk_json_write_array_end(ctx->w);
398 :
399 0 : spdk_json_write_object_end(ctx->w);
400 0 : }
401 :
402 : static void
403 0 : rpc_framework_get_reactors(struct spdk_jsonrpc_request *request,
404 : const struct spdk_json_val *params)
405 : {
406 : struct rpc_get_stats_ctx *ctx;
407 :
408 0 : if (params) {
409 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
410 : "`framework_get_reactors` requires no arguments");
411 0 : return;
412 : }
413 :
414 0 : ctx = calloc(1, sizeof(*ctx));
415 0 : if (!ctx) {
416 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
417 : "Memory allocation error");
418 0 : return;
419 : }
420 :
421 0 : ctx->now = spdk_get_ticks();
422 0 : ctx->request = request;
423 0 : ctx->w = spdk_jsonrpc_begin_result(ctx->request);
424 :
425 0 : spdk_json_write_object_begin(ctx->w);
426 0 : spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz());
427 0 : spdk_json_write_named_array_begin(ctx->w, "reactors");
428 :
429 0 : spdk_for_each_reactor(_rpc_framework_get_reactors, ctx, NULL,
430 : rpc_framework_get_reactors_done);
431 : }
432 :
433 0 : SPDK_RPC_REGISTER("framework_get_reactors", rpc_framework_get_reactors, SPDK_RPC_RUNTIME)
434 :
435 : struct rpc_set_scheduler_ctx {
436 : char *name;
437 : uint64_t period;
438 : };
439 :
440 : static void
441 0 : free_rpc_framework_set_scheduler(struct rpc_set_scheduler_ctx *r)
442 : {
443 0 : free(r->name);
444 0 : }
445 :
446 : static const struct spdk_json_object_decoder rpc_set_scheduler_decoders[] = {
447 : {"name", offsetof(struct rpc_set_scheduler_ctx, name), spdk_json_decode_string},
448 : {"period", offsetof(struct rpc_set_scheduler_ctx, period), spdk_json_decode_uint64, true},
449 : };
450 :
451 : static void
452 0 : rpc_framework_set_scheduler(struct spdk_jsonrpc_request *request,
453 : const struct spdk_json_val *params)
454 : {
455 0 : struct rpc_set_scheduler_ctx req = {NULL};
456 0 : struct spdk_scheduler *scheduler = NULL;
457 : int ret;
458 :
459 0 : ret = spdk_json_decode_object_relaxed(params, rpc_set_scheduler_decoders,
460 : SPDK_COUNTOF(rpc_set_scheduler_decoders),
461 : &req);
462 0 : if (ret) {
463 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
464 : "Invalid parameters");
465 0 : goto end;
466 : }
467 :
468 0 : scheduler = spdk_scheduler_get();
469 : /* SPDK does not support changing scheduler back to static. */
470 0 : if (scheduler != NULL && (strcmp(req.name, "static") == 0) &&
471 0 : strcmp(scheduler->name, "static") != 0) {
472 0 : spdk_jsonrpc_send_error_response(request,
473 : SPDK_JSONRPC_ERROR_INVALID_PARAMS,
474 : "Static scheduler cannot be re-enabled "
475 : "after a different scheduler was selected");
476 0 : goto end;
477 : }
478 :
479 0 : if (req.period != 0) {
480 0 : spdk_scheduler_set_period(req.period);
481 : }
482 :
483 0 : ret = spdk_scheduler_set(req.name);
484 0 : if (ret) {
485 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
486 : spdk_strerror(ret));
487 0 : goto end;
488 : }
489 :
490 0 : scheduler = spdk_scheduler_get();
491 0 : if (scheduler != NULL && scheduler->set_opts != NULL) {
492 0 : ret = scheduler->set_opts(params);
493 : }
494 0 : if (ret) {
495 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(ret));
496 0 : goto end;
497 : }
498 :
499 0 : spdk_jsonrpc_send_bool_response(request, true);
500 :
501 0 : end:
502 0 : free_rpc_framework_set_scheduler(&req);
503 0 : }
504 0 : SPDK_RPC_REGISTER("framework_set_scheduler", rpc_framework_set_scheduler,
505 : SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
506 :
507 : static void
508 0 : rpc_framework_get_scheduler(struct spdk_jsonrpc_request *request,
509 : const struct spdk_json_val *params)
510 : {
511 : struct spdk_json_write_ctx *w;
512 0 : struct spdk_scheduler *scheduler = spdk_scheduler_get();
513 0 : uint64_t scheduler_period = spdk_scheduler_get_period();
514 0 : struct spdk_governor *governor = spdk_governor_get();
515 :
516 0 : if (params) {
517 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
518 : "'rpc_get_scheduler' requires no arguments");
519 0 : return;
520 : }
521 :
522 0 : w = spdk_jsonrpc_begin_result(request);
523 0 : spdk_json_write_object_begin(w);
524 0 : if (scheduler) {
525 0 : spdk_json_write_named_string(w, "scheduler_name", scheduler->name);
526 : }
527 0 : spdk_json_write_named_uint64(w, "scheduler_period", scheduler_period);
528 0 : if (governor != NULL) {
529 0 : spdk_json_write_named_string(w, "governor_name", governor->name);
530 : }
531 :
532 0 : if (scheduler != NULL && scheduler->get_opts != NULL) {
533 0 : scheduler->get_opts(w);
534 : }
535 :
536 0 : spdk_json_write_object_end(w);
537 0 : spdk_jsonrpc_end_result(request, w);
538 : }
539 0 : SPDK_RPC_REGISTER("framework_get_scheduler", rpc_framework_get_scheduler, SPDK_RPC_RUNTIME)
540 :
541 : struct rpc_thread_set_cpumask_ctx {
542 : struct spdk_jsonrpc_request *request;
543 : struct spdk_cpuset cpumask;
544 : int status;
545 : struct spdk_thread *orig_thread;
546 : };
547 :
548 : static void
549 0 : rpc_thread_set_cpumask_done(void *_ctx)
550 : {
551 0 : struct rpc_thread_set_cpumask_ctx *ctx = _ctx;
552 :
553 0 : if (ctx->status == 0) {
554 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
555 : } else {
556 0 : spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
557 0 : spdk_strerror(-ctx->status));
558 : }
559 :
560 0 : free(ctx);
561 0 : }
562 :
563 : static void
564 0 : _rpc_thread_set_cpumask(void *_ctx)
565 : {
566 0 : struct rpc_thread_set_cpumask_ctx *ctx = _ctx;
567 :
568 0 : ctx->status = spdk_thread_set_cpumask(&ctx->cpumask);
569 :
570 0 : spdk_thread_send_msg(ctx->orig_thread, rpc_thread_set_cpumask_done, ctx);
571 0 : }
572 :
573 : struct rpc_thread_set_cpumask {
574 : uint64_t id;
575 : char *cpumask;
576 : };
577 :
578 : static const struct spdk_json_object_decoder rpc_thread_set_cpumask_decoders[] = {
579 : {"id", offsetof(struct rpc_thread_set_cpumask, id), spdk_json_decode_uint64},
580 : {"cpumask", offsetof(struct rpc_thread_set_cpumask, cpumask), spdk_json_decode_string},
581 : };
582 :
583 : static void
584 0 : rpc_thread_set_cpumask(struct spdk_jsonrpc_request *request,
585 : const struct spdk_json_val *params)
586 : {
587 0 : struct rpc_thread_set_cpumask req = {};
588 : struct rpc_thread_set_cpumask_ctx *ctx;
589 : const struct spdk_cpuset *coremask;
590 0 : struct spdk_cpuset tmp_mask;
591 : struct spdk_thread *thread;
592 : int rc;
593 :
594 0 : ctx = calloc(1, sizeof(*ctx));
595 0 : if (ctx == NULL) {
596 0 : SPDK_ERRLOG("Memory allocation failed\n");
597 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
598 : "Memory allocation failed");
599 0 : return;
600 : }
601 :
602 0 : if (spdk_json_decode_object(params, rpc_thread_set_cpumask_decoders,
603 : SPDK_COUNTOF(rpc_thread_set_cpumask_decoders),
604 : &req)) {
605 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
606 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
607 : "spdk_json_decode_object failed");
608 0 : goto err;
609 : }
610 :
611 0 : thread = spdk_thread_get_by_id(req.id);
612 0 : if (thread == NULL) {
613 0 : SPDK_ERRLOG("Thread %" PRIu64 " does not exist\n", req.id);
614 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
615 : "Thread %" PRIu64 " does not exist", req.id);
616 0 : goto err;
617 : }
618 :
619 0 : rc = spdk_app_parse_core_mask(req.cpumask, &ctx->cpumask);
620 0 : if (rc != 0) {
621 0 : SPDK_ERRLOG("Invalid cpumask %s\n", req.cpumask);
622 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
623 : "Invalid cpumask %s", req.cpumask);
624 0 : goto err;
625 : }
626 :
627 0 : if (spdk_cpuset_count(&ctx->cpumask) == 0) {
628 0 : coremask = spdk_app_get_core_mask();
629 0 : spdk_cpuset_copy(&tmp_mask, coremask);
630 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
631 : "No CPU is selected from reactor mask %s\n",
632 : spdk_cpuset_fmt(&tmp_mask));
633 0 : goto err;
634 : }
635 :
636 : /* There may be any reactors running in interrupt mode. But currently,
637 : * when interrupt ability of the spdk_thread is not enabled,
638 : * spdk_thread can't get executed on reactor which runs in interrupt.
639 : * Exclude the situation that reactors specified by the cpumask are
640 : * all in interrupt mode.
641 : */
642 0 : if (!spdk_interrupt_mode_is_enabled()) {
643 0 : struct spdk_reactor *local_reactor = spdk_reactor_get(spdk_env_get_current_core());
644 0 : struct spdk_cpuset tmp_cpuset;
645 :
646 : /* Masking off reactors which are in interrupt mode */
647 0 : spdk_cpuset_copy(&tmp_cpuset, &local_reactor->notify_cpuset);
648 0 : spdk_cpuset_negate(&tmp_cpuset);
649 0 : spdk_cpuset_and(&tmp_cpuset, &ctx->cpumask);
650 0 : if (spdk_cpuset_count(&tmp_cpuset) == 0) {
651 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
652 : "cpumask %s are all in interrupt mode, and can't be scheduled yet\n",
653 : req.cpumask);
654 0 : goto err;
655 : }
656 : }
657 :
658 0 : ctx->request = request;
659 0 : ctx->orig_thread = spdk_get_thread();
660 :
661 0 : spdk_thread_send_msg(thread, _rpc_thread_set_cpumask, ctx);
662 :
663 0 : free(req.cpumask);
664 0 : return;
665 :
666 0 : err:
667 0 : free(req.cpumask);
668 0 : free(ctx);
669 : }
670 0 : SPDK_RPC_REGISTER("thread_set_cpumask", rpc_thread_set_cpumask, SPDK_RPC_RUNTIME)
671 0 : SPDK_LOG_REGISTER_COMPONENT(app_rpc)
|