Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/env.h"
9 : : #include "spdk/init.h"
10 : : #include "spdk/thread.h"
11 : : #include "spdk/log.h"
12 : : #include "spdk/rpc.h"
13 : :
14 : : #define RPC_SELECT_INTERVAL 4000 /* 4ms */
15 : :
16 : : static struct spdk_poller *g_rpc_poller = NULL;
17 : :
18 : : struct init_rpc_server {
19 : : struct spdk_rpc_server *server;
20 : : char listen_addr[sizeof(((struct sockaddr_un *)0)->sun_path)];
21 : : bool active;
22 : : STAILQ_ENTRY(init_rpc_server) link;
23 : : };
24 : :
25 : : static STAILQ_HEAD(, init_rpc_server) g_init_rpc_servers = STAILQ_HEAD_INITIALIZER(
26 : : g_init_rpc_servers);
27 : :
28 : : static int
29 : 4704981 : rpc_subsystem_poll_servers(void *arg)
30 : : {
31 : : struct init_rpc_server *init_server;
32 : :
33 [ + + ]: 9419952 : STAILQ_FOREACH(init_server, &g_init_rpc_servers, link) {
34 [ + + + + ]: 4714971 : if (init_server->active) {
35 : 4703591 : spdk_rpc_server_accept(init_server->server);
36 : : }
37 : : }
38 : :
39 : 4704981 : return SPDK_POLLER_BUSY;
40 : : }
41 : :
42 : : static void
43 : 1527 : rpc_opts_copy(struct spdk_rpc_opts *opts, const struct spdk_rpc_opts *opts_src,
44 : : size_t size)
45 : : {
46 [ - + ]: 1527 : assert(opts);
47 [ - + ]: 1527 : assert(opts_src);
48 : :
49 : 1527 : opts->size = size;
50 : :
51 : : #define SET_FIELD(field) \
52 : : if (offsetof(struct spdk_rpc_opts, field) + sizeof(opts->field) <= size) { \
53 : : opts->field = opts_src->field; \
54 : : } \
55 : :
56 [ + - ]: 1527 : SET_FIELD(log_file);
57 [ + - ]: 1527 : SET_FIELD(log_level);
58 : :
59 : : /* Do not remove this statement, you should always update this statement when you adding a new field,
60 : : * and do not forget to add the SET_FIELD statement for your added field. */
61 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_rpc_opts) == 24, "Incorrect size");
62 : :
63 : : #undef SET_FIELD
64 : 1527 : }
65 : :
66 : : static void
67 : 3730 : rpc_opts_get_default(struct spdk_rpc_opts *opts, size_t size)
68 : : {
69 [ - + ]: 3730 : assert(opts);
70 : :
71 : 3730 : opts->size = size;
72 : :
73 : : #define SET_FIELD(field, value) \
74 : : if (offsetof(struct spdk_rpc_opts, field) + sizeof(opts->field) <= size) { \
75 : : opts->field = value; \
76 : : } \
77 : :
78 [ + - ]: 3730 : SET_FIELD(log_file, NULL);
79 [ + - ]: 3730 : SET_FIELD(log_level, SPDK_LOG_DISABLED);
80 : :
81 : : #undef SET_FIELD
82 : 3730 : }
83 : :
84 : : static int
85 : 3751 : rpc_verify_opts_and_methods(const struct spdk_rpc_opts *opts)
86 : : {
87 [ - + ]: 3751 : if (!spdk_rpc_verify_methods()) {
88 : 0 : return -EINVAL;
89 : : }
90 : :
91 [ + + - + ]: 3751 : if (opts != NULL && opts->size == 0) {
92 : 0 : SPDK_ERRLOG("size in the options structure should not be zero\n");
93 : 0 : return -EINVAL;
94 : : }
95 : :
96 : 3751 : return 0;
97 : : }
98 : :
99 : : static void
100 : 3730 : rpc_set_spdk_log_opts(const struct spdk_rpc_opts *_opts)
101 : : {
102 : 1781 : struct spdk_rpc_opts opts;
103 : :
104 : 3730 : rpc_opts_get_default(&opts, sizeof(opts));
105 [ + + ]: 3730 : if (_opts != NULL) {
106 : 1527 : rpc_opts_copy(&opts, _opts, _opts->size);
107 [ + + ]: 2203 : } else if (!STAILQ_EMPTY(&g_init_rpc_servers)) {
108 : 156 : return;
109 : : }
110 : :
111 : 3574 : spdk_jsonrpc_set_log_file(opts.log_file);
112 : 3574 : spdk_jsonrpc_set_log_level(opts.log_level);
113 : : }
114 : :
115 : : static struct init_rpc_server *
116 : 10589 : get_server_by_addr(const char *listen_addr)
117 : : {
118 : : struct init_rpc_server *init_server;
119 : :
120 [ + + ]: 10901 : STAILQ_FOREACH(init_server, &g_init_rpc_servers, link) {
121 [ + + - + : 7096 : if (strcmp(listen_addr, init_server->listen_addr) == 0) {
+ + ]
122 : 6784 : return init_server;
123 : : }
124 : : }
125 : :
126 : 3805 : return NULL;
127 : : }
128 : :
129 : : int
130 : 3751 : spdk_rpc_initialize(const char *listen_addr, const struct spdk_rpc_opts *opts)
131 : : {
132 : : struct init_rpc_server *init_server;
133 : : int rc;
134 : :
135 [ - + ]: 3751 : if (listen_addr == NULL) {
136 : 0 : return -EINVAL;
137 : : }
138 : :
139 : 3751 : rc = rpc_verify_opts_and_methods(opts);
140 [ - + ]: 3751 : if (rc) {
141 : 0 : return rc;
142 : : }
143 : :
144 [ - + ]: 3751 : if (get_server_by_addr(listen_addr) != NULL) {
145 : 0 : SPDK_ERRLOG("Socket listen_addr already in use\n");
146 : 0 : return -EADDRINUSE;
147 : : }
148 : :
149 : 3751 : init_server = calloc(1, sizeof(struct init_rpc_server));
150 [ - + ]: 3751 : if (init_server == NULL) {
151 : 0 : SPDK_ERRLOG("Unable to allocate init RPC server\n");
152 : 0 : return -ENOMEM;
153 : : }
154 : :
155 [ - + ]: 3751 : rc = snprintf(init_server->listen_addr, sizeof(init_server->listen_addr), "%s",
156 : : listen_addr);
157 [ - + ]: 3751 : if (rc < 0) {
158 : 0 : SPDK_ERRLOG("Unable to copy listen address %s\n", listen_addr);
159 : 0 : free(init_server);
160 : 0 : return -EINVAL;
161 : : }
162 : :
163 : : /* Listen on the requested address */
164 : 3751 : init_server->server = spdk_rpc_server_listen(listen_addr);
165 [ + + ]: 3751 : if (init_server->server == NULL) {
166 : 21 : SPDK_ERRLOG("Unable to start RPC service at %s\n", listen_addr);
167 : 21 : free(init_server);
168 : 21 : return -EINVAL;
169 : : }
170 : :
171 : 3730 : rpc_set_spdk_log_opts(opts);
172 : 3730 : init_server->active = true;
173 : :
174 : 3730 : STAILQ_INSERT_TAIL(&g_init_rpc_servers, init_server, link);
175 [ + + ]: 3730 : if (g_rpc_poller == NULL) {
176 : : /* Register a poller to periodically check for RPCs */
177 : 3574 : g_rpc_poller = SPDK_POLLER_REGISTER(rpc_subsystem_poll_servers, NULL, RPC_SELECT_INTERVAL);
178 : : }
179 : :
180 : 3730 : return 0;
181 : : }
182 : :
183 : : void
184 : 3784 : spdk_rpc_server_finish(const char *listen_addr)
185 : : {
186 : : struct init_rpc_server *init_server;
187 : :
188 : 3784 : init_server = get_server_by_addr(listen_addr);
189 [ + + ]: 3784 : if (!init_server) {
190 : 54 : SPDK_ERRLOG("No server listening on provided address: %s\n", listen_addr);
191 : 54 : return;
192 : : }
193 : :
194 : 3730 : spdk_rpc_server_close(init_server->server);
195 [ + + + - : 3730 : STAILQ_REMOVE(&g_init_rpc_servers, init_server, init_rpc_server, link);
- + + - ]
196 : 3730 : free(init_server);
197 : :
198 [ + + ]: 3730 : if (STAILQ_EMPTY(&g_init_rpc_servers)) {
199 : 3574 : spdk_poller_unregister(&g_rpc_poller);
200 : : }
201 : : }
202 : :
203 : : void
204 : 2961 : spdk_rpc_finish(void)
205 : : {
206 : : struct init_rpc_server *init_server, *tmp;
207 : :
208 [ + + ]: 4491 : STAILQ_FOREACH_SAFE(init_server, &g_init_rpc_servers, link, tmp) {
209 : 1530 : spdk_rpc_server_finish(init_server->listen_addr);
210 : : }
211 : 2961 : }
212 : :
213 : : static void
214 : 3054 : set_server_active_flag(const char *listen_addr, bool is_active)
215 : : {
216 : : struct init_rpc_server *init_server;
217 : :
218 : 3054 : init_server = get_server_by_addr(listen_addr);
219 [ - + ]: 3054 : if (!init_server) {
220 : 0 : SPDK_ERRLOG("No server listening on provided address: %s\n", listen_addr);
221 : 0 : return;
222 : : }
223 : :
224 : 3054 : init_server->active = is_active;
225 : : }
226 : :
227 : : void
228 : 1527 : spdk_rpc_server_pause(const char *listen_addr)
229 : : {
230 : 1527 : set_server_active_flag(listen_addr, false);
231 : 1527 : }
232 : :
233 : : void
234 : 1527 : spdk_rpc_server_resume(const char *listen_addr)
235 : : {
236 : 1527 : set_server_active_flag(listen_addr, true);
237 : 1527 : }
|