xref: /spdk/examples/interrupt_tgt/interrupt_tgt.c (revision c6c1234de9e0015e670dd0b51bf6ce39ee0e07bd)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2020 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 #include "spdk/conf.h"
8 #include "spdk/event.h"
9 #include "spdk/vhost.h"
10 #include "spdk/json.h"
11 #include "spdk/jsonrpc.h"
12 #include "spdk/rpc.h"
13 #include "spdk/env.h"
14 #include "spdk/scheduler.h"
15 
16 #include "spdk_internal/event.h"
17 
18 struct rpc_reactor_set_interrupt_mode {
19 	int32_t lcore;
20 	bool disable_interrupt;
21 	int rc;
22 	struct spdk_thread *rpc_thread;
23 	struct spdk_jsonrpc_request *request;
24 };
25 
26 static const struct spdk_json_object_decoder rpc_reactor_set_interrupt_mode_decoders[] = {
27 	{"lcore", offsetof(struct rpc_reactor_set_interrupt_mode, lcore), spdk_json_decode_int32},
28 	{"disable_interrupt", offsetof(struct rpc_reactor_set_interrupt_mode, disable_interrupt), spdk_json_decode_bool},
29 };
30 
31 static void
32 rpc_reactor_set_interrupt_mode_cb(void *cb_arg)
33 {
34 	struct rpc_reactor_set_interrupt_mode *req = cb_arg;
35 
36 	SPDK_NOTICELOG("complete reactor switch\n");
37 
38 	spdk_jsonrpc_send_bool_response(req->request, true);
39 	free(req);
40 }
41 
42 static void
43 set_interrupt_mode_cb(void *arg1, void *arg2)
44 {
45 	struct rpc_reactor_set_interrupt_mode *req = arg1;
46 
47 	spdk_thread_send_msg(req->rpc_thread, rpc_reactor_set_interrupt_mode_cb, req);
48 }
49 
50 static void
51 set_interrupt_mode(void *arg1, void *arg2)
52 {
53 	struct rpc_reactor_set_interrupt_mode *req = arg1;
54 	int rc;
55 
56 	rc = spdk_reactor_set_interrupt_mode(req->lcore, !req->disable_interrupt,
57 					     set_interrupt_mode_cb, req);
58 	if (rc)	{
59 		req->rc = rc;
60 		set_interrupt_mode_cb(req, NULL);
61 	}
62 }
63 
64 static void
65 rpc_reactor_set_interrupt_mode(struct spdk_jsonrpc_request *request,
66 			       const struct spdk_json_val *params)
67 {
68 	struct rpc_reactor_set_interrupt_mode *req;
69 
70 	req = calloc(1, sizeof(*req));
71 	if (req == NULL) {
72 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
73 						 "Out of memory");
74 		return;
75 	}
76 
77 	req->request = request;
78 	req->rpc_thread = spdk_get_thread();
79 
80 	if (spdk_json_decode_object(params, rpc_reactor_set_interrupt_mode_decoders,
81 				    SPDK_COUNTOF(rpc_reactor_set_interrupt_mode_decoders),
82 				    req)) {
83 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
84 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
85 						 "spdk_json_decode_object failed");
86 		free(req);
87 		return;
88 	}
89 
90 	if (!spdk_interrupt_mode_is_enabled()) {
91 		SPDK_ERRLOG("Interrupt mode is not set when staring the application\n");
92 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
93 						 "spdk_json_decode_object failed");
94 		free(req);
95 		return;
96 	}
97 
98 
99 	SPDK_NOTICELOG("RPC Start to %s interrupt mode on reactor %d.\n",
100 		       req->disable_interrupt ? "disable" : "enable", req->lcore);
101 	if (req->lcore >= (int64_t)spdk_env_get_first_core() &&
102 	    req->lcore <= (int64_t)spdk_env_get_last_core()) {
103 		struct spdk_event *e;
104 
105 		e = spdk_event_allocate(spdk_scheduler_get_scheduling_lcore(),
106 					set_interrupt_mode, req, NULL);
107 		spdk_event_call(e);
108 	} else {
109 		free(req);
110 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
111 						 "Invalid parameters");
112 	}
113 }
114 /* private */ SPDK_RPC_REGISTER("reactor_set_interrupt_mode", rpc_reactor_set_interrupt_mode,
115 				SPDK_RPC_RUNTIME)
116 
117 static void
118 interrupt_tgt_usage(void)
119 {
120 	printf(" -E                        Set interrupt mode\n");
121 	printf(" -S <path>                 directory where to create vhost sockets (default: pwd)\n");
122 }
123 
124 static int
125 interrupt_tgt_parse_arg(int ch, char *arg)
126 {
127 	switch (ch) {
128 	case 'S':
129 		spdk_vhost_set_socket_path(arg);
130 		break;
131 	case 'E':
132 		spdk_interrupt_mode_enable();
133 		break;
134 	default:
135 		return -EINVAL;
136 	}
137 	return 0;
138 }
139 
140 static void
141 interrupt_tgt_started(void *arg1)
142 {
143 }
144 
145 int
146 main(int argc, char *argv[])
147 {
148 	struct spdk_app_opts opts = {};
149 	int rc;
150 
151 	spdk_app_opts_init(&opts, sizeof(opts));
152 	opts.name = "interrupt_tgt";
153 
154 	if ((rc = spdk_app_parse_args(argc, argv, &opts, "S:E", NULL,
155 				      interrupt_tgt_parse_arg, interrupt_tgt_usage)) !=
156 	    SPDK_APP_PARSE_ARGS_SUCCESS) {
157 		exit(rc);
158 	}
159 
160 	/* Blocks until the application is exiting */
161 	rc = spdk_app_start(&opts, interrupt_tgt_started, NULL);
162 
163 	spdk_app_fini();
164 
165 	return rc;
166 }
167