Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
3 : : * Copyright (C) 2016 Intel Corporation.
4 : : * All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/string.h"
8 : : #include "spdk/likely.h"
9 : :
10 : : #include "iscsi/iscsi.h"
11 : : #include "iscsi/init_grp.h"
12 : : #include "iscsi/portal_grp.h"
13 : : #include "iscsi/conn.h"
14 : : #include "iscsi/task.h"
15 : : #include "iscsi/tgt_node.h"
16 : :
17 : : #include "spdk/log.h"
18 : :
19 : : struct spdk_iscsi_opts *g_spdk_iscsi_opts = NULL;
20 : :
21 : : static struct spdk_thread *g_init_thread = NULL;
22 : : static spdk_iscsi_init_cb g_init_cb_fn = NULL;
23 : : static void *g_init_cb_arg = NULL;
24 : :
25 : : static spdk_iscsi_fini_cb g_fini_cb_fn;
26 : : static void *g_fini_cb_arg;
27 : :
28 : : #define ISCSI_DATA_BUFFER_ALIGNMENT (0x1000)
29 : : #define ISCSI_DATA_BUFFER_MASK (ISCSI_DATA_BUFFER_ALIGNMENT - 1)
30 : :
31 : : static void
32 : 12017664 : mobj_ctor(struct spdk_mempool *mp, __attribute__((unused)) void *arg,
33 : : void *_m, __attribute__((unused)) unsigned i)
34 : : {
35 : 12017664 : struct spdk_mobj *m = _m;
36 : :
37 : 12017664 : m->mp = mp;
38 : 12017664 : m->buf = (uint8_t *)m + sizeof(struct spdk_mobj);
39 : 12017664 : m->buf = (void *)((uintptr_t)((uint8_t *)m->buf + ISCSI_DATA_BUFFER_ALIGNMENT) &
40 : : ~ISCSI_DATA_BUFFER_MASK);
41 : 12017664 : }
42 : :
43 : : static int
44 : 652 : iscsi_initialize_pdu_pool(void)
45 : : {
46 : 652 : struct spdk_iscsi_globals *iscsi = &g_iscsi;
47 : 652 : int imm_mobj_size = SPDK_BDEV_BUF_SIZE_WITH_MD(iscsi_get_max_immediate_data_size()) +
48 : 652 : sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT;
49 : 652 : int dout_mobj_size = SPDK_BDEV_BUF_SIZE_WITH_MD(SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH) +
50 : : sizeof(struct spdk_mobj) + ISCSI_DATA_BUFFER_ALIGNMENT;
51 : :
52 : : /* create PDU pool */
53 : 761 : iscsi->pdu_pool = spdk_mempool_create("PDU_Pool",
54 : 652 : iscsi->pdu_pool_size,
55 : : sizeof(struct spdk_iscsi_pdu),
56 : : 256, SPDK_ENV_SOCKET_ID_ANY);
57 [ - + ]: 652 : if (!iscsi->pdu_pool) {
58 [ # # ]: 0 : if (spdk_mempool_lookup("PDU_Pool") != NULL) {
59 : 0 : SPDK_ERRLOG("Cannot create PDU pool: already exists\n");
60 : 0 : SPDK_ERRLOG("Probably running in multiprocess environment, which is "
61 : : "unsupported by the iSCSI library\n");
62 : : } else {
63 : 0 : SPDK_ERRLOG("create PDU pool failed\n");
64 : : }
65 : 0 : return -1;
66 : : }
67 : :
68 : 761 : iscsi->pdu_immediate_data_pool = spdk_mempool_create_ctor("PDU_immediate_data_Pool",
69 : 652 : iscsi->immediate_data_pool_size,
70 : : imm_mobj_size, 256,
71 : : SPDK_ENV_SOCKET_ID_ANY,
72 : : mobj_ctor, NULL);
73 [ - + ]: 652 : if (!iscsi->pdu_immediate_data_pool) {
74 : 0 : SPDK_ERRLOG("create PDU immediate data pool failed\n");
75 : 0 : return -1;
76 : : }
77 : :
78 : 761 : iscsi->pdu_data_out_pool = spdk_mempool_create_ctor("PDU_data_out_Pool",
79 : 652 : iscsi->data_out_pool_size,
80 : : dout_mobj_size, 256,
81 : : SPDK_ENV_SOCKET_ID_ANY,
82 : : mobj_ctor, NULL);
83 [ - + ]: 652 : if (!iscsi->pdu_data_out_pool) {
84 : 0 : SPDK_ERRLOG("create PDU data out pool failed\n");
85 : 0 : return -1;
86 : : }
87 : :
88 : 652 : return 0;
89 : : }
90 : :
91 : : static void
92 : 80336 : iscsi_sess_ctor(struct spdk_mempool *pool, void *arg, void *session_buf,
93 : : unsigned index)
94 : : {
95 : 80336 : struct spdk_iscsi_globals *iscsi = arg;
96 : 80336 : struct spdk_iscsi_sess *sess = session_buf;
97 : :
98 : 80336 : iscsi->session[index] = sess;
99 : :
100 : : /* tsih 0 is reserved, so start tsih values at 1. */
101 : 80336 : sess->tsih = index + 1;
102 : 80336 : }
103 : :
104 : : #define DEFAULT_TASK_POOL_SIZE 32768
105 : :
106 : : static int
107 : 652 : iscsi_initialize_task_pool(void)
108 : : {
109 : 652 : struct spdk_iscsi_globals *iscsi = &g_iscsi;
110 : :
111 : : /* create scsi_task pool */
112 : 652 : iscsi->task_pool = spdk_mempool_create("SCSI_TASK_Pool",
113 : : DEFAULT_TASK_POOL_SIZE,
114 : : sizeof(struct spdk_iscsi_task),
115 : : 128, SPDK_ENV_SOCKET_ID_ANY);
116 [ - + ]: 652 : if (!iscsi->task_pool) {
117 : 0 : SPDK_ERRLOG("create task pool failed\n");
118 : 0 : return -1;
119 : : }
120 : :
121 : 652 : return 0;
122 : : }
123 : :
124 : : #define SESSION_POOL_SIZE(iscsi) (iscsi->MaxSessions)
125 : : static int
126 : 652 : iscsi_initialize_session_pool(void)
127 : : {
128 : 652 : struct spdk_iscsi_globals *iscsi = &g_iscsi;
129 : :
130 : 761 : iscsi->session_pool = spdk_mempool_create_ctor("Session_Pool",
131 : 652 : SESSION_POOL_SIZE(iscsi),
132 : : sizeof(struct spdk_iscsi_sess), 0,
133 : : SPDK_ENV_SOCKET_ID_ANY,
134 : : iscsi_sess_ctor, iscsi);
135 [ - + ]: 652 : if (!iscsi->session_pool) {
136 : 0 : SPDK_ERRLOG("create session pool failed\n");
137 : 0 : return -1;
138 : : }
139 : :
140 : 652 : return 0;
141 : : }
142 : :
143 : : static int
144 : 652 : iscsi_initialize_all_pools(void)
145 : : {
146 [ - + ]: 652 : if (iscsi_initialize_pdu_pool() != 0) {
147 : 0 : return -1;
148 : : }
149 : :
150 [ - + ]: 652 : if (iscsi_initialize_session_pool() != 0) {
151 : 0 : return -1;
152 : : }
153 : :
154 [ - + ]: 652 : if (iscsi_initialize_task_pool() != 0) {
155 : 0 : return -1;
156 : : }
157 : :
158 : 652 : return 0;
159 : : }
160 : :
161 : : static void
162 : 3260 : iscsi_check_pool(struct spdk_mempool *pool, size_t count)
163 : : {
164 [ + - - + ]: 3260 : if (pool && spdk_mempool_count(pool) != count) {
165 : 0 : SPDK_ERRLOG("spdk_mempool_count(%s) == %zu, should be %zu\n",
166 : : spdk_mempool_get_name(pool), spdk_mempool_count(pool), count);
167 : : }
168 : 3260 : }
169 : :
170 : : static void
171 : 652 : iscsi_check_pools(void)
172 : : {
173 : 652 : struct spdk_iscsi_globals *iscsi = &g_iscsi;
174 : :
175 : 652 : iscsi_check_pool(iscsi->pdu_pool, iscsi->pdu_pool_size);
176 : 652 : iscsi_check_pool(iscsi->session_pool, SESSION_POOL_SIZE(iscsi));
177 : 652 : iscsi_check_pool(iscsi->pdu_immediate_data_pool, iscsi->immediate_data_pool_size);
178 : 652 : iscsi_check_pool(iscsi->pdu_data_out_pool, iscsi->data_out_pool_size);
179 : 652 : iscsi_check_pool(iscsi->task_pool, DEFAULT_TASK_POOL_SIZE);
180 : 652 : }
181 : :
182 : : static void
183 : 652 : iscsi_free_pools(void)
184 : : {
185 : 652 : struct spdk_iscsi_globals *iscsi = &g_iscsi;
186 : :
187 : 652 : spdk_mempool_free(iscsi->pdu_pool);
188 : 652 : spdk_mempool_free(iscsi->session_pool);
189 : 652 : spdk_mempool_free(iscsi->pdu_immediate_data_pool);
190 : 652 : spdk_mempool_free(iscsi->pdu_data_out_pool);
191 : 652 : spdk_mempool_free(iscsi->task_pool);
192 : 652 : }
193 : :
194 : : void
195 : 70799259 : iscsi_put_pdu(struct spdk_iscsi_pdu *pdu)
196 : : {
197 [ - + ]: 70799259 : if (!pdu) {
198 : 0 : return;
199 : : }
200 : :
201 [ - + ]: 70799259 : assert(pdu->ref > 0);
202 : 70799259 : pdu->ref--;
203 : :
204 [ + + ]: 70799259 : if (pdu->ref == 0) {
205 [ + + ]: 47312373 : if (pdu->mobj[0]) {
206 : 9935204 : iscsi_datapool_put(pdu->mobj[0]);
207 : : }
208 [ + + ]: 47312373 : if (pdu->mobj[1]) {
209 : 645 : iscsi_datapool_put(pdu->mobj[1]);
210 : : }
211 : :
212 [ + + - + : 47312373 : if (pdu->data && !pdu->data_from_mempool) {
+ + ]
213 : 243492 : free(pdu->data);
214 : : }
215 : :
216 : 47312373 : spdk_mempool_put(g_iscsi.pdu_pool, (void *)pdu);
217 : : }
218 : : }
219 : :
220 : 47312373 : struct spdk_iscsi_pdu *iscsi_get_pdu(struct spdk_iscsi_conn *conn)
221 : : {
222 : : struct spdk_iscsi_pdu *pdu;
223 : :
224 [ - + ]: 47312373 : assert(conn != NULL);
225 : 47312373 : pdu = spdk_mempool_get(g_iscsi.pdu_pool);
226 [ - + ]: 47312373 : if (!pdu) {
227 : 0 : SPDK_ERRLOG("Unable to get PDU\n");
228 : 0 : abort();
229 : : }
230 : :
231 : : /* we do not want to zero out the last part of the structure reserved for AHS and sense data */
232 [ - + ]: 47312373 : memset(pdu, 0, offsetof(struct spdk_iscsi_pdu, ahs));
233 : 47312373 : pdu->ref = 1;
234 : 47312373 : pdu->conn = conn;
235 : : /* Initialize CRC. */
236 : 47312373 : pdu->crc32c = SPDK_CRC32C_INITIAL;
237 : :
238 : 47312373 : return pdu;
239 : : }
240 : :
241 : : static void
242 : 652 : iscsi_log_globals(void)
243 : : {
244 [ - + - + : 652 : SPDK_DEBUGLOG(iscsi, "AuthFile %s\n",
- - ]
245 : : g_iscsi.authfile ? g_iscsi.authfile : "(none)");
246 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "NodeBase %s\n", g_iscsi.nodebase);
247 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "MaxSessions %d\n", g_iscsi.MaxSessions);
248 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "MaxConnectionsPerSession %d\n",
249 : : g_iscsi.MaxConnectionsPerSession);
250 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "MaxQueueDepth %d\n", g_iscsi.MaxQueueDepth);
251 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "DefaultTime2Wait %d\n",
252 : : g_iscsi.DefaultTime2Wait);
253 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "DefaultTime2Retain %d\n",
254 : : g_iscsi.DefaultTime2Retain);
255 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "FirstBurstLength %d\n",
256 : : g_iscsi.FirstBurstLength);
257 [ - + - + : 652 : SPDK_DEBUGLOG(iscsi, "ImmediateData %s\n",
- - - - ]
258 : : g_iscsi.ImmediateData ? "Yes" : "No");
259 [ - + - + : 652 : SPDK_DEBUGLOG(iscsi, "AllowDuplicateIsid %s\n",
- - - - ]
260 : : g_iscsi.AllowDuplicateIsid ? "Yes" : "No");
261 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "ErrorRecoveryLevel %d\n",
262 : : g_iscsi.ErrorRecoveryLevel);
263 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "Timeout %d\n", g_iscsi.timeout);
264 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "NopInInterval %d\n",
265 : : g_iscsi.nopininterval);
266 [ - + - + ]: 652 : if (g_iscsi.disable_chap) {
267 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi,
268 : : "DiscoveryAuthMethod None\n");
269 [ + + + - ]: 652 : } else if (!g_iscsi.require_chap) {
270 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi,
271 : : "DiscoveryAuthMethod Auto\n");
272 : : } else {
273 [ # # # # : 0 : SPDK_DEBUGLOG(iscsi,
# # # # #
# # # ]
274 : : "DiscoveryAuthMethod %s %s\n",
275 : : g_iscsi.require_chap ? "CHAP" : "",
276 : : g_iscsi.mutual_chap ? "Mutual" : "");
277 : : }
278 : :
279 [ + - ]: 652 : if (g_iscsi.chap_group == 0) {
280 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi,
281 : : "DiscoveryAuthGroup None\n");
282 : : } else {
283 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi,
284 : : "DiscoveryAuthGroup AuthGroup%d\n",
285 : : g_iscsi.chap_group);
286 : : }
287 : :
288 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "MaxLargeDataInPerConnection %d\n",
289 : : g_iscsi.MaxLargeDataInPerConnection);
290 : :
291 [ - + - + ]: 652 : SPDK_DEBUGLOG(iscsi, "MaxR2TPerConnection %d\n",
292 : : g_iscsi.MaxR2TPerConnection);
293 : 652 : }
294 : :
295 : : #define NUM_PDU_PER_CONNECTION(opts) (2 * (opts->MaxQueueDepth + \
296 : : opts->MaxLargeDataInPerConnection + \
297 : : 2 * opts->MaxR2TPerConnection + 8))
298 : : #define PDU_POOL_SIZE(opts) (opts->MaxSessions * NUM_PDU_PER_CONNECTION(opts))
299 : : #define IMMEDIATE_DATA_POOL_SIZE(opts) (opts->MaxSessions * 128)
300 : : #define DATA_OUT_POOL_SIZE(opts) (opts->MaxSessions * MAX_DATA_OUT_PER_CONNECTION)
301 : :
302 : : static void
303 : 652 : iscsi_opts_init(struct spdk_iscsi_opts *opts)
304 : : {
305 : 652 : opts->MaxSessions = DEFAULT_MAX_SESSIONS;
306 : 652 : opts->MaxConnectionsPerSession = DEFAULT_MAX_CONNECTIONS_PER_SESSION;
307 : 652 : opts->MaxQueueDepth = DEFAULT_MAX_QUEUE_DEPTH;
308 : 652 : opts->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
309 : 652 : opts->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
310 : 652 : opts->FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
311 : 652 : opts->ImmediateData = DEFAULT_IMMEDIATEDATA;
312 : 652 : opts->AllowDuplicateIsid = false;
313 : 652 : opts->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
314 : 652 : opts->timeout = DEFAULT_TIMEOUT;
315 : 652 : opts->nopininterval = DEFAULT_NOPININTERVAL;
316 : 652 : opts->disable_chap = false;
317 : 652 : opts->require_chap = false;
318 : 652 : opts->mutual_chap = false;
319 : 652 : opts->chap_group = 0;
320 : 652 : opts->authfile = NULL;
321 : 652 : opts->nodebase = NULL;
322 : 652 : opts->MaxLargeDataInPerConnection = DEFAULT_MAX_LARGE_DATAIN_PER_CONNECTION;
323 : 652 : opts->MaxR2TPerConnection = DEFAULT_MAXR2T;
324 : 652 : opts->pdu_pool_size = PDU_POOL_SIZE(opts);
325 : 652 : opts->immediate_data_pool_size = IMMEDIATE_DATA_POOL_SIZE(opts);
326 : 652 : opts->data_out_pool_size = DATA_OUT_POOL_SIZE(opts);
327 : 652 : }
328 : :
329 : : struct spdk_iscsi_opts *
330 : 652 : iscsi_opts_alloc(void)
331 : : {
332 : : struct spdk_iscsi_opts *opts;
333 : :
334 : 652 : opts = calloc(1, sizeof(*opts));
335 [ - + ]: 652 : if (!opts) {
336 : 0 : SPDK_ERRLOG("calloc() failed for iscsi options\n");
337 : 0 : return NULL;
338 : : }
339 : :
340 : 652 : iscsi_opts_init(opts);
341 : :
342 : 652 : return opts;
343 : : }
344 : :
345 : : void
346 : 724 : iscsi_opts_free(struct spdk_iscsi_opts *opts)
347 : : {
348 : 724 : free(opts->authfile);
349 : 724 : free(opts->nodebase);
350 : 724 : free(opts);
351 : 724 : }
352 : :
353 : : /* Deep copy of spdk_iscsi_opts */
354 : : struct spdk_iscsi_opts *
355 : 72 : iscsi_opts_copy(struct spdk_iscsi_opts *src)
356 : : {
357 : : struct spdk_iscsi_opts *dst;
358 : :
359 : 72 : dst = calloc(1, sizeof(*dst));
360 [ - + ]: 72 : if (!dst) {
361 : 0 : SPDK_ERRLOG("calloc() failed for iscsi options\n");
362 : 0 : return NULL;
363 : : }
364 : :
365 [ - + ]: 72 : if (src->authfile) {
366 [ # # ]: 0 : dst->authfile = strdup(src->authfile);
367 [ # # ]: 0 : if (!dst->authfile) {
368 : 0 : free(dst);
369 : 0 : SPDK_ERRLOG("failed to strdup for auth file %s\n", src->authfile);
370 : 0 : return NULL;
371 : : }
372 : : }
373 : :
374 [ + + ]: 72 : if (src->nodebase) {
375 [ - + ]: 41 : dst->nodebase = strdup(src->nodebase);
376 [ - + ]: 41 : if (!dst->nodebase) {
377 : 0 : free(dst->authfile);
378 : 0 : free(dst);
379 : 0 : SPDK_ERRLOG("failed to strdup for nodebase %s\n", src->nodebase);
380 : 0 : return NULL;
381 : : }
382 : : }
383 : :
384 : 72 : dst->MaxSessions = src->MaxSessions;
385 : 72 : dst->MaxConnectionsPerSession = src->MaxConnectionsPerSession;
386 : 72 : dst->MaxQueueDepth = src->MaxQueueDepth;
387 : 72 : dst->DefaultTime2Wait = src->DefaultTime2Wait;
388 : 72 : dst->DefaultTime2Retain = src->DefaultTime2Retain;
389 : 72 : dst->FirstBurstLength = src->FirstBurstLength;
390 [ - + ]: 72 : dst->ImmediateData = src->ImmediateData;
391 [ - + ]: 72 : dst->AllowDuplicateIsid = src->AllowDuplicateIsid;
392 : 72 : dst->ErrorRecoveryLevel = src->ErrorRecoveryLevel;
393 : 72 : dst->timeout = src->timeout;
394 : 72 : dst->nopininterval = src->nopininterval;
395 [ - + ]: 72 : dst->disable_chap = src->disable_chap;
396 [ - + ]: 72 : dst->require_chap = src->require_chap;
397 [ - + ]: 72 : dst->mutual_chap = src->mutual_chap;
398 : 72 : dst->chap_group = src->chap_group;
399 : 72 : dst->MaxLargeDataInPerConnection = src->MaxLargeDataInPerConnection;
400 : 72 : dst->MaxR2TPerConnection = src->MaxR2TPerConnection;
401 : 72 : dst->pdu_pool_size = src->pdu_pool_size;
402 : 72 : dst->immediate_data_pool_size = src->immediate_data_pool_size;
403 : 72 : dst->data_out_pool_size = src->data_out_pool_size;
404 : :
405 : 72 : return dst;
406 : : }
407 : :
408 : : static int
409 : 652 : iscsi_opts_verify(struct spdk_iscsi_opts *opts)
410 : : {
411 [ + + ]: 652 : if (!opts->nodebase) {
412 [ - + ]: 611 : opts->nodebase = strdup(SPDK_ISCSI_DEFAULT_NODEBASE);
413 [ - + ]: 611 : if (opts->nodebase == NULL) {
414 : 0 : SPDK_ERRLOG("strdup() failed for default nodebase\n");
415 : 0 : return -ENOMEM;
416 : : }
417 : : }
418 : :
419 [ + - - + ]: 652 : if (opts->MaxSessions == 0 || opts->MaxSessions > 65535) {
420 : 0 : SPDK_ERRLOG("%d is invalid. MaxSessions must be more than 0 and no more than 65535\n",
421 : : opts->MaxSessions);
422 : 0 : return -EINVAL;
423 : : }
424 : :
425 [ + - - + ]: 652 : if (opts->MaxConnectionsPerSession == 0 || opts->MaxConnectionsPerSession > 65535) {
426 : 0 : SPDK_ERRLOG("%d is invalid. MaxConnectionsPerSession must be more than 0 and no more than 65535\n",
427 : : opts->MaxConnectionsPerSession);
428 : 0 : return -EINVAL;
429 : : }
430 : :
431 [ + - - + ]: 652 : if (opts->MaxQueueDepth == 0 || opts->MaxQueueDepth > 256) {
432 : 0 : SPDK_ERRLOG("%d is invalid. MaxQueueDepth must be more than 0 and no more than 256\n",
433 : : opts->MaxQueueDepth);
434 : 0 : return -EINVAL;
435 : : }
436 : :
437 [ - + ]: 652 : if (opts->DefaultTime2Wait > 3600) {
438 : 0 : SPDK_ERRLOG("%d is invalid. DefaultTime2Wait must be no more than 3600\n",
439 : : opts->DefaultTime2Wait);
440 : 0 : return -EINVAL;
441 : : }
442 : :
443 [ - + ]: 652 : if (opts->DefaultTime2Retain > 3600) {
444 : 0 : SPDK_ERRLOG("%d is invalid. DefaultTime2Retain must be no more than 3600\n",
445 : : opts->DefaultTime2Retain);
446 : 0 : return -EINVAL;
447 : : }
448 : :
449 [ + - ]: 652 : if (opts->FirstBurstLength >= SPDK_ISCSI_MIN_FIRST_BURST_LENGTH) {
450 [ - + ]: 652 : if (opts->FirstBurstLength > SPDK_ISCSI_MAX_BURST_LENGTH) {
451 : 0 : SPDK_ERRLOG("FirstBurstLength %d shall not exceed MaxBurstLength %d\n",
452 : : opts->FirstBurstLength, SPDK_ISCSI_MAX_BURST_LENGTH);
453 : 0 : return -EINVAL;
454 : : }
455 : : } else {
456 : 0 : SPDK_ERRLOG("FirstBurstLength %d shall be no less than %d\n",
457 : : opts->FirstBurstLength, SPDK_ISCSI_MIN_FIRST_BURST_LENGTH);
458 : 0 : return -EINVAL;
459 : : }
460 : :
461 [ - + ]: 652 : if (opts->ErrorRecoveryLevel > 2) {
462 : 0 : SPDK_ERRLOG("ErrorRecoveryLevel %d is not supported.\n", opts->ErrorRecoveryLevel);
463 : 0 : return -EINVAL;
464 : : }
465 : :
466 [ - + ]: 652 : if (opts->timeout < 0) {
467 : 0 : SPDK_ERRLOG("%d is invalid. timeout must not be less than 0\n", opts->timeout);
468 : 0 : return -EINVAL;
469 : : }
470 : :
471 [ + - - + ]: 652 : if (opts->nopininterval < 0 || opts->nopininterval > MAX_NOPININTERVAL) {
472 : 0 : SPDK_ERRLOG("%d is invalid. nopinterval must be between 0 and %d\n",
473 : : opts->nopininterval, MAX_NOPININTERVAL);
474 : 0 : return -EINVAL;
475 : : }
476 : :
477 [ - + - + : 1195 : if (!iscsi_check_chap_params(opts->disable_chap, opts->require_chap,
- + ]
478 [ - + ]: 652 : opts->mutual_chap, opts->chap_group)) {
479 : 0 : SPDK_ERRLOG("CHAP params in opts are illegal combination\n");
480 : 0 : return -EINVAL;
481 : : }
482 : :
483 [ - + ]: 652 : if (opts->MaxLargeDataInPerConnection == 0) {
484 : 0 : SPDK_ERRLOG("0 is invalid. MaxLargeDataInPerConnection must be more than 0\n");
485 : 0 : return -EINVAL;
486 : : }
487 : :
488 [ - + ]: 652 : if (opts->MaxR2TPerConnection == 0) {
489 : 0 : SPDK_ERRLOG("0 is invalid. MaxR2TPerConnection must be more than 0\n");
490 : 0 : return -EINVAL;
491 : : }
492 : :
493 [ - + ]: 652 : if (opts->pdu_pool_size == 0) {
494 : 0 : SPDK_ERRLOG("0 is invalid. pdu_pool_size must be more than 0\n");
495 : 0 : return -EINVAL;
496 : : }
497 : :
498 [ - + ]: 652 : if (opts->immediate_data_pool_size == 0) {
499 : 0 : SPDK_ERRLOG("0 is invalid. immediate_data_pool_size must be more than 0\n");
500 : 0 : return -EINVAL;
501 : : }
502 : :
503 [ - + ]: 652 : if (opts->data_out_pool_size == 0) {
504 : 0 : SPDK_ERRLOG("0 is invalid. data_out_pool_size must be more than 0\n");
505 : 0 : return -EINVAL;
506 : : }
507 : :
508 : 652 : return 0;
509 : : }
510 : :
511 : : static int
512 : 652 : iscsi_set_global_params(struct spdk_iscsi_opts *opts)
513 : : {
514 : : int rc;
515 : :
516 : 652 : rc = iscsi_opts_verify(opts);
517 [ - + ]: 652 : if (rc != 0) {
518 : 0 : SPDK_ERRLOG("spdk_iscsi_opts_verify() failed\n");
519 : 0 : return rc;
520 : : }
521 : :
522 [ - + ]: 652 : if (opts->authfile != NULL) {
523 [ # # ]: 0 : g_iscsi.authfile = strdup(opts->authfile);
524 [ # # ]: 0 : if (!g_iscsi.authfile) {
525 : 0 : SPDK_ERRLOG("failed to strdup for auth file %s\n", opts->authfile);
526 : 0 : return -ENOMEM;
527 : : }
528 : : }
529 : :
530 [ - + ]: 652 : g_iscsi.nodebase = strdup(opts->nodebase);
531 [ - + ]: 652 : if (!g_iscsi.nodebase) {
532 : 0 : SPDK_ERRLOG("failed to strdup for nodebase %s\n", opts->nodebase);
533 : 0 : return -ENOMEM;
534 : : }
535 : :
536 : 652 : g_iscsi.MaxSessions = opts->MaxSessions;
537 : 652 : g_iscsi.MaxConnectionsPerSession = opts->MaxConnectionsPerSession;
538 : 652 : g_iscsi.MaxQueueDepth = opts->MaxQueueDepth;
539 : 652 : g_iscsi.DefaultTime2Wait = opts->DefaultTime2Wait;
540 : 652 : g_iscsi.DefaultTime2Retain = opts->DefaultTime2Retain;
541 : 652 : g_iscsi.FirstBurstLength = opts->FirstBurstLength;
542 [ - + ]: 652 : g_iscsi.ImmediateData = opts->ImmediateData;
543 [ - + ]: 652 : g_iscsi.AllowDuplicateIsid = opts->AllowDuplicateIsid;
544 : 652 : g_iscsi.ErrorRecoveryLevel = opts->ErrorRecoveryLevel;
545 : 652 : g_iscsi.timeout = opts->timeout;
546 : 652 : g_iscsi.nopininterval = opts->nopininterval;
547 [ - + ]: 652 : g_iscsi.disable_chap = opts->disable_chap;
548 [ - + ]: 652 : g_iscsi.require_chap = opts->require_chap;
549 [ - + ]: 652 : g_iscsi.mutual_chap = opts->mutual_chap;
550 : 652 : g_iscsi.chap_group = opts->chap_group;
551 : 652 : g_iscsi.MaxLargeDataInPerConnection = opts->MaxLargeDataInPerConnection;
552 : 652 : g_iscsi.MaxR2TPerConnection = opts->MaxR2TPerConnection;
553 : 652 : g_iscsi.pdu_pool_size = opts->pdu_pool_size;
554 : 652 : g_iscsi.immediate_data_pool_size = opts->immediate_data_pool_size;
555 : 652 : g_iscsi.data_out_pool_size = opts->data_out_pool_size;
556 : :
557 : 652 : iscsi_log_globals();
558 : :
559 : 652 : return 0;
560 : : }
561 : :
562 : : int
563 : 10 : iscsi_set_discovery_auth(bool disable_chap, bool require_chap, bool mutual_chap,
564 : : int32_t chap_group)
565 : : {
566 [ - + ]: 10 : if (!iscsi_check_chap_params(disable_chap, require_chap, mutual_chap,
567 : : chap_group)) {
568 : 0 : SPDK_ERRLOG("CHAP params are illegal combination\n");
569 : 0 : return -EINVAL;
570 : : }
571 : :
572 [ - + ]: 10 : pthread_mutex_lock(&g_iscsi.mutex);
573 : 10 : g_iscsi.disable_chap = disable_chap;
574 : 10 : g_iscsi.require_chap = require_chap;
575 : 10 : g_iscsi.mutual_chap = mutual_chap;
576 : 10 : g_iscsi.chap_group = chap_group;
577 [ - + ]: 10 : pthread_mutex_unlock(&g_iscsi.mutex);
578 : :
579 : 10 : return 0;
580 : : }
581 : :
582 : : int
583 : 16 : iscsi_auth_group_add_secret(struct spdk_iscsi_auth_group *group,
584 : : const char *user, const char *secret,
585 : : const char *muser, const char *msecret)
586 : : {
587 : : struct spdk_iscsi_auth_secret *_secret;
588 : : size_t len;
589 : :
590 [ + - - + ]: 16 : if (user == NULL || secret == NULL) {
591 : 0 : SPDK_ERRLOG("user and secret must be specified\n");
592 : 0 : return -EINVAL;
593 : : }
594 : :
595 [ + + - + ]: 16 : if (muser != NULL && msecret == NULL) {
596 : 0 : SPDK_ERRLOG("msecret must be specified with muser\n");
597 : 0 : return -EINVAL;
598 : : }
599 : :
600 [ + + ]: 22 : TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
601 [ - + - + : 6 : if (strcmp(_secret->user, user) == 0) {
- + ]
602 : 0 : SPDK_ERRLOG("user for secret is duplicated\n");
603 : 0 : return -EEXIST;
604 : : }
605 : : }
606 : :
607 : 16 : _secret = calloc(1, sizeof(*_secret));
608 [ - + ]: 16 : if (_secret == NULL) {
609 : 0 : SPDK_ERRLOG("calloc() failed for CHAP secret\n");
610 : 0 : return -ENOMEM;
611 : : }
612 : :
613 [ - + ]: 16 : len = strnlen(user, sizeof(_secret->user));
614 [ - + ]: 16 : if (len > sizeof(_secret->user) - 1) {
615 : 0 : SPDK_ERRLOG("CHAP user longer than %zu characters: %s\n",
616 : : sizeof(_secret->user) - 1, user);
617 : 0 : free(_secret);
618 : 0 : return -EINVAL;
619 : : }
620 [ - + - + ]: 16 : memcpy(_secret->user, user, len);
621 : :
622 [ - + ]: 16 : len = strnlen(secret, sizeof(_secret->secret));
623 [ - + ]: 16 : if (len > sizeof(_secret->secret) - 1) {
624 : 0 : SPDK_ERRLOG("CHAP secret longer than %zu characters: %s\n",
625 : : sizeof(_secret->secret) - 1, secret);
626 : 0 : free(_secret);
627 : 0 : return -EINVAL;
628 : : }
629 [ - + - + ]: 16 : memcpy(_secret->secret, secret, len);
630 : :
631 [ + + ]: 16 : if (muser != NULL) {
632 [ - + ]: 14 : len = strnlen(muser, sizeof(_secret->muser));
633 [ - + ]: 14 : if (len > sizeof(_secret->muser) - 1) {
634 : 0 : SPDK_ERRLOG("Mutual CHAP user longer than %zu characters: %s\n",
635 : : sizeof(_secret->muser) - 1, muser);
636 : 0 : free(_secret);
637 : 0 : return -EINVAL;
638 : : }
639 [ - + - + ]: 14 : memcpy(_secret->muser, muser, len);
640 : :
641 [ - + ]: 14 : len = strnlen(msecret, sizeof(_secret->msecret));
642 [ - + ]: 14 : if (len > sizeof(_secret->msecret) - 1) {
643 : 0 : SPDK_ERRLOG("Mutual CHAP secret longer than %zu characters: %s\n",
644 : : sizeof(_secret->msecret) - 1, msecret);
645 : 0 : free(_secret);
646 : 0 : return -EINVAL;
647 : : }
648 [ - + - + ]: 14 : memcpy(_secret->msecret, msecret, len);
649 : : }
650 : :
651 : 16 : TAILQ_INSERT_TAIL(&group->secret_head, _secret, tailq);
652 : 16 : return 0;
653 : : }
654 : :
655 : : int
656 : 6 : iscsi_auth_group_delete_secret(struct spdk_iscsi_auth_group *group,
657 : : const char *user)
658 : : {
659 : : struct spdk_iscsi_auth_secret *_secret;
660 : :
661 [ - + ]: 6 : if (user == NULL) {
662 : 0 : SPDK_ERRLOG("user must be specified\n");
663 : 0 : return -EINVAL;
664 : : }
665 : :
666 [ + - ]: 10 : TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
667 [ - + - + : 10 : if (strcmp(_secret->user, user) == 0) {
+ + ]
668 : 6 : break;
669 : : }
670 : : }
671 : :
672 [ - + ]: 6 : if (_secret == NULL) {
673 : 0 : SPDK_ERRLOG("secret is not found\n");
674 : 0 : return -ENODEV;
675 : : }
676 : :
677 [ + + ]: 6 : TAILQ_REMOVE(&group->secret_head, _secret, tailq);
678 : 6 : free(_secret);
679 : :
680 : 6 : return 0;
681 : : }
682 : :
683 : : int
684 : 12 : iscsi_add_auth_group(int32_t tag, struct spdk_iscsi_auth_group **_group)
685 : : {
686 : : struct spdk_iscsi_auth_group *group;
687 : :
688 [ + + ]: 16 : TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
689 [ - + ]: 4 : if (group->tag == tag) {
690 : 0 : SPDK_ERRLOG("Auth group (%d) already exists\n", tag);
691 : 0 : return -EEXIST;
692 : : }
693 : : }
694 : :
695 : 12 : group = calloc(1, sizeof(*group));
696 [ - + ]: 12 : if (group == NULL) {
697 : 0 : SPDK_ERRLOG("calloc() failed for auth group\n");
698 : 0 : return -ENOMEM;
699 : : }
700 : :
701 : 12 : TAILQ_INIT(&group->secret_head);
702 : 12 : group->tag = tag;
703 : :
704 : 12 : TAILQ_INSERT_TAIL(&g_iscsi.auth_group_head, group, tailq);
705 : :
706 : 12 : *_group = group;
707 : 12 : return 0;
708 : : }
709 : :
710 : : void
711 : 12 : iscsi_delete_auth_group(struct spdk_iscsi_auth_group *group)
712 : : {
713 : : struct spdk_iscsi_auth_secret *_secret, *tmp;
714 : :
715 [ + + ]: 12 : TAILQ_REMOVE(&g_iscsi.auth_group_head, group, tailq);
716 : :
717 [ + + ]: 22 : TAILQ_FOREACH_SAFE(_secret, &group->secret_head, tailq, tmp) {
718 [ - + ]: 10 : TAILQ_REMOVE(&group->secret_head, _secret, tailq);
719 : 10 : free(_secret);
720 : : }
721 : 12 : free(group);
722 : 12 : }
723 : :
724 : : struct spdk_iscsi_auth_group *
725 : 18 : iscsi_find_auth_group_by_tag(int32_t tag)
726 : : {
727 : : struct spdk_iscsi_auth_group *group;
728 : :
729 [ + - ]: 20 : TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
730 [ + + ]: 20 : if (group->tag == tag) {
731 : 18 : return group;
732 : : }
733 : : }
734 : :
735 : 0 : return NULL;
736 : : }
737 : :
738 : : static void
739 : 652 : iscsi_auth_groups_destroy(void)
740 : : {
741 : : struct spdk_iscsi_auth_group *group, *tmp;
742 : :
743 [ + + ]: 660 : TAILQ_FOREACH_SAFE(group, &g_iscsi.auth_group_head, tailq, tmp) {
744 : 8 : iscsi_delete_auth_group(group);
745 : : }
746 : 652 : }
747 : :
748 : : static int
749 : 0 : iscsi_parse_auth_group(struct spdk_conf_section *sp)
750 : : {
751 : : int rc;
752 : : int i;
753 : : int tag;
754 : : const char *val, *user, *secret, *muser, *msecret;
755 : 0 : struct spdk_iscsi_auth_group *group = NULL;
756 : :
757 : 0 : val = spdk_conf_section_get_val(sp, "Comment");
758 [ # # ]: 0 : if (val != NULL) {
759 [ # # # # ]: 0 : SPDK_DEBUGLOG(iscsi, "Comment %s\n", val);
760 : : }
761 : :
762 : 0 : tag = spdk_conf_section_get_num(sp);
763 : :
764 : 0 : rc = iscsi_add_auth_group(tag, &group);
765 [ # # ]: 0 : if (rc != 0) {
766 : 0 : SPDK_ERRLOG("Failed to add auth group\n");
767 : 0 : return rc;
768 : : }
769 : :
770 : 0 : for (i = 0; ; i++) {
771 : 0 : val = spdk_conf_section_get_nval(sp, "Auth", i);
772 [ # # ]: 0 : if (val == NULL) {
773 : 0 : break;
774 : : }
775 : :
776 : 0 : user = spdk_conf_section_get_nmval(sp, "Auth", i, 0);
777 : 0 : secret = spdk_conf_section_get_nmval(sp, "Auth", i, 1);
778 : 0 : muser = spdk_conf_section_get_nmval(sp, "Auth", i, 2);
779 : 0 : msecret = spdk_conf_section_get_nmval(sp, "Auth", i, 3);
780 : :
781 : 0 : rc = iscsi_auth_group_add_secret(group, user, secret, muser, msecret);
782 [ # # ]: 0 : if (rc != 0) {
783 : 0 : SPDK_ERRLOG("Failed to add secret to auth group\n");
784 : 0 : iscsi_delete_auth_group(group);
785 : 0 : return rc;
786 : : }
787 : : }
788 : :
789 : 0 : return 0;
790 : : }
791 : :
792 : : static int
793 : 0 : iscsi_parse_auth_info(void)
794 : : {
795 : : struct spdk_conf *config;
796 : : struct spdk_conf_section *sp;
797 : : int rc;
798 : :
799 : 0 : config = spdk_conf_allocate();
800 [ # # ]: 0 : if (!config) {
801 : 0 : SPDK_ERRLOG("Failed to allocate config file\n");
802 : 0 : return -ENOMEM;
803 : : }
804 : :
805 : 0 : rc = spdk_conf_read(config, g_iscsi.authfile);
806 [ # # ]: 0 : if (rc != 0) {
807 [ # # # # ]: 0 : SPDK_INFOLOG(iscsi, "Failed to load auth file\n");
808 : 0 : spdk_conf_free(config);
809 : 0 : return rc;
810 : : }
811 : :
812 : 0 : sp = spdk_conf_first_section(config);
813 [ # # ]: 0 : while (sp != NULL) {
814 [ # # ]: 0 : if (spdk_conf_section_match_prefix(sp, "AuthGroup")) {
815 [ # # ]: 0 : if (spdk_conf_section_get_num(sp) == 0) {
816 : 0 : SPDK_ERRLOG("Group 0 is invalid\n");
817 : 0 : iscsi_auth_groups_destroy();
818 : 0 : spdk_conf_free(config);
819 : 0 : return -EINVAL;
820 : : }
821 : :
822 : 0 : rc = iscsi_parse_auth_group(sp);
823 [ # # ]: 0 : if (rc != 0) {
824 : 0 : SPDK_ERRLOG("parse_auth_group() failed\n");
825 : 0 : iscsi_auth_groups_destroy();
826 : 0 : spdk_conf_free(config);
827 : 0 : return rc;
828 : : }
829 : : }
830 : 0 : sp = spdk_conf_next_section(sp);
831 : : }
832 : :
833 : 0 : spdk_conf_free(config);
834 : 0 : return 0;
835 : : }
836 : :
837 : : static struct spdk_iscsi_auth_secret *
838 : 352 : iscsi_find_auth_secret(const char *authuser, int ag_tag)
839 : : {
840 : : struct spdk_iscsi_auth_group *group;
841 : : struct spdk_iscsi_auth_secret *_secret;
842 : :
843 [ + - ]: 356 : TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
844 [ + + ]: 356 : if (group->tag == ag_tag) {
845 [ + - ]: 352 : TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
846 [ - + - + : 352 : if (strcmp(_secret->user, authuser) == 0) {
+ - ]
847 : 352 : return _secret;
848 : : }
849 : : }
850 : : }
851 : : }
852 : :
853 : 0 : return NULL;
854 : : }
855 : :
856 : : int
857 : 352 : iscsi_chap_get_authinfo(struct iscsi_chap_auth *auth, const char *authuser,
858 : : int ag_tag)
859 : : {
860 : : struct spdk_iscsi_auth_secret *_secret;
861 : :
862 [ - + ]: 352 : if (authuser == NULL) {
863 : 0 : return -EINVAL;
864 : : }
865 : :
866 [ - + ]: 352 : if (auth->user[0] != '\0') {
867 [ # # ]: 0 : memset(auth->user, 0, sizeof(auth->user));
868 [ # # ]: 0 : memset(auth->secret, 0, sizeof(auth->secret));
869 [ # # ]: 0 : memset(auth->muser, 0, sizeof(auth->muser));
870 [ # # ]: 0 : memset(auth->msecret, 0, sizeof(auth->msecret));
871 : : }
872 : :
873 [ - + ]: 352 : pthread_mutex_lock(&g_iscsi.mutex);
874 : :
875 : 352 : _secret = iscsi_find_auth_secret(authuser, ag_tag);
876 [ - + ]: 352 : if (_secret == NULL) {
877 [ # # ]: 0 : pthread_mutex_unlock(&g_iscsi.mutex);
878 : :
879 : 0 : SPDK_ERRLOG("CHAP secret is not found: user:%s, tag:%d\n",
880 : : authuser, ag_tag);
881 : 0 : return -ENOENT;
882 : : }
883 : :
884 [ - + - + ]: 352 : memcpy(auth->user, _secret->user, sizeof(auth->user));
885 [ - + - + ]: 352 : memcpy(auth->secret, _secret->secret, sizeof(auth->secret));
886 : :
887 [ + + ]: 352 : if (_secret->muser[0] != '\0') {
888 [ - + - + ]: 8 : memcpy(auth->muser, _secret->muser, sizeof(auth->muser));
889 [ - + - + ]: 8 : memcpy(auth->msecret, _secret->msecret, sizeof(auth->msecret));
890 : : }
891 : :
892 [ - + ]: 352 : pthread_mutex_unlock(&g_iscsi.mutex);
893 : 352 : return 0;
894 : : }
895 : :
896 : : static int
897 : 652 : iscsi_initialize_global_params(void)
898 : : {
899 : : int rc;
900 : :
901 [ + + ]: 652 : if (!g_spdk_iscsi_opts) {
902 : 580 : g_spdk_iscsi_opts = iscsi_opts_alloc();
903 [ - + ]: 580 : if (!g_spdk_iscsi_opts) {
904 : 0 : SPDK_ERRLOG("iscsi_opts_alloc_failed() failed\n");
905 : 0 : return -ENOMEM;
906 : : }
907 : : }
908 : :
909 : 652 : rc = iscsi_set_global_params(g_spdk_iscsi_opts);
910 [ - + ]: 652 : if (rc != 0) {
911 : 0 : SPDK_ERRLOG("iscsi_set_global_params() failed\n");
912 : : }
913 : :
914 : 652 : iscsi_opts_free(g_spdk_iscsi_opts);
915 : 652 : g_spdk_iscsi_opts = NULL;
916 : :
917 : 652 : return rc;
918 : : }
919 : :
920 : : static void
921 : 652 : iscsi_init_complete(int rc)
922 : : {
923 : 652 : spdk_iscsi_init_cb cb_fn = g_init_cb_fn;
924 : 652 : void *cb_arg = g_init_cb_arg;
925 : :
926 : 652 : g_init_cb_fn = NULL;
927 : 652 : g_init_cb_arg = NULL;
928 : :
929 : 652 : cb_fn(cb_arg, rc);
930 : 652 : }
931 : :
932 : : static void
933 : 652 : iscsi_parse_configuration(void)
934 : : {
935 : 652 : int rc = 0;
936 : :
937 [ - + ]: 652 : if (g_iscsi.authfile != NULL) {
938 [ # # # # ]: 0 : if (access(g_iscsi.authfile, R_OK) == 0) {
939 : 0 : rc = iscsi_parse_auth_info();
940 [ # # ]: 0 : if (rc < 0) {
941 : 0 : SPDK_ERRLOG("iscsi_parse_auth_info() failed\n");
942 : : }
943 : : } else {
944 [ # # # # ]: 0 : SPDK_INFOLOG(iscsi, "CHAP secret file is not found in the path %s\n",
945 : : g_iscsi.authfile);
946 : : }
947 : : }
948 : :
949 : 652 : iscsi_init_complete(rc);
950 : 652 : }
951 : :
952 : : static int
953 : 1618455708 : iscsi_poll_group_poll(void *ctx)
954 : : {
955 : 1618455708 : struct spdk_iscsi_poll_group *group = ctx;
956 : : struct spdk_iscsi_conn *conn, *tmp;
957 : : int rc;
958 : :
959 [ + + ]: 1618455708 : if (spdk_unlikely(STAILQ_EMPTY(&group->connections))) {
960 : 1461194236 : return SPDK_POLLER_IDLE;
961 : : }
962 : :
963 : 157261472 : rc = spdk_sock_group_poll(group->sock_group);
964 [ - + ]: 157261472 : if (rc < 0) {
965 : 0 : SPDK_ERRLOG("Failed to poll sock_group=%p\n", group->sock_group);
966 : : }
967 : :
968 [ + + ]: 366877034 : STAILQ_FOREACH_SAFE(conn, &group->connections, pg_link, tmp) {
969 [ + + ]: 209615562 : if (conn->state == ISCSI_CONN_STATE_EXITING) {
970 : 575 : iscsi_conn_destruct(conn);
971 : : }
972 : : }
973 : :
974 : 157261472 : return rc != 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
975 : : }
976 : :
977 : : static int
978 : 7744 : iscsi_poll_group_handle_nop(void *ctx)
979 : : {
980 : 7744 : struct spdk_iscsi_poll_group *group = ctx;
981 : : struct spdk_iscsi_conn *conn, *tmp;
982 : :
983 [ + + ]: 11640 : STAILQ_FOREACH_SAFE(conn, &group->connections, pg_link, tmp) {
984 : 3896 : iscsi_conn_handle_nop(conn);
985 : : }
986 : :
987 : 7744 : return SPDK_POLLER_BUSY;
988 : : }
989 : :
990 : : static int
991 : 894 : iscsi_poll_group_create(void *io_device, void *ctx_buf)
992 : : {
993 : 894 : struct spdk_iscsi_poll_group *pg = ctx_buf;
994 : :
995 : 894 : STAILQ_INIT(&pg->connections);
996 : 894 : pg->sock_group = spdk_sock_group_create(NULL);
997 [ - + ]: 894 : assert(pg->sock_group != NULL);
998 : :
999 : 894 : pg->poller = SPDK_POLLER_REGISTER(iscsi_poll_group_poll, pg, 0);
1000 : : /* set the period to 1 sec */
1001 : 894 : pg->nop_poller = SPDK_POLLER_REGISTER(iscsi_poll_group_handle_nop, pg, 1000000);
1002 : :
1003 : 894 : return 0;
1004 : : }
1005 : :
1006 : : static void
1007 : 894 : iscsi_poll_group_destroy(void *io_device, void *ctx_buf)
1008 : : {
1009 : 894 : struct spdk_iscsi_poll_group *pg = ctx_buf;
1010 : : struct spdk_io_channel *ch;
1011 : : struct spdk_thread *thread;
1012 : :
1013 [ - + ]: 894 : assert(pg->poller != NULL);
1014 [ - + ]: 894 : assert(pg->sock_group != NULL);
1015 : :
1016 : 894 : spdk_sock_group_close(&pg->sock_group);
1017 : 894 : spdk_poller_unregister(&pg->poller);
1018 : 894 : spdk_poller_unregister(&pg->nop_poller);
1019 : :
1020 : 894 : ch = spdk_io_channel_from_ctx(pg);
1021 : 894 : thread = spdk_io_channel_get_thread(ch);
1022 : :
1023 [ - + ]: 894 : assert(thread == spdk_get_thread());
1024 : :
1025 : 894 : spdk_thread_exit(thread);
1026 : 894 : }
1027 : :
1028 : : static void
1029 : 894 : _iscsi_init_thread_done(void *ctx)
1030 : : {
1031 : 894 : struct spdk_iscsi_poll_group *pg = ctx;
1032 : :
1033 : 894 : TAILQ_INSERT_TAIL(&g_iscsi.poll_group_head, pg, link);
1034 [ + + ]: 894 : if (--g_iscsi.refcnt == 0) {
1035 : 652 : iscsi_parse_configuration();
1036 : : }
1037 : 894 : }
1038 : :
1039 : : static void
1040 : 894 : _iscsi_init_thread(void *ctx)
1041 : : {
1042 : : struct spdk_io_channel *ch;
1043 : : struct spdk_iscsi_poll_group *pg;
1044 : :
1045 : 894 : ch = spdk_get_io_channel(&g_iscsi);
1046 : 894 : pg = spdk_io_channel_get_ctx(ch);
1047 : :
1048 : 894 : spdk_thread_send_msg(g_init_thread, _iscsi_init_thread_done, pg);
1049 : 894 : }
1050 : :
1051 : : static void
1052 : 652 : initialize_iscsi_poll_group(void)
1053 : : {
1054 : 652 : struct spdk_cpuset tmp_cpumask = {};
1055 : : uint32_t i;
1056 : 297 : char thread_name[32];
1057 : : struct spdk_thread *thread;
1058 : :
1059 : 652 : spdk_io_device_register(&g_iscsi, iscsi_poll_group_create, iscsi_poll_group_destroy,
1060 : : sizeof(struct spdk_iscsi_poll_group), "iscsi_tgt");
1061 : :
1062 : : /* Create threads for CPU cores active for this application, and send a
1063 : : * message to each thread to create a poll group on it.
1064 : : */
1065 : 652 : g_init_thread = spdk_get_thread();
1066 [ - + ]: 652 : assert(g_init_thread != NULL);
1067 [ - + ]: 652 : assert(g_iscsi.refcnt == 0);
1068 : :
1069 [ + + ]: 1546 : SPDK_ENV_FOREACH_CORE(i) {
1070 : 894 : spdk_cpuset_zero(&tmp_cpumask);
1071 : 894 : spdk_cpuset_set_cpu(&tmp_cpumask, i, true);
1072 [ - + ]: 894 : snprintf(thread_name, sizeof(thread_name), "iscsi_poll_group_%u", i);
1073 : :
1074 : 894 : thread = spdk_thread_create(thread_name, &tmp_cpumask);
1075 [ - + ]: 894 : assert(thread != NULL);
1076 : :
1077 : 894 : g_iscsi.refcnt++;
1078 : 894 : spdk_thread_send_msg(thread, _iscsi_init_thread, NULL);
1079 : : }
1080 : 652 : }
1081 : :
1082 : : static int
1083 : 652 : iscsi_parse_globals(void)
1084 : : {
1085 : : int rc;
1086 : :
1087 : 652 : rc = iscsi_initialize_global_params();
1088 [ - + ]: 652 : if (rc != 0) {
1089 : 0 : SPDK_ERRLOG("iscsi_initialize_iscsi_global_params() failed\n");
1090 : 0 : return rc;
1091 : : }
1092 : :
1093 : 652 : g_iscsi.session = calloc(1, sizeof(struct spdk_iscsi_sess *) * g_iscsi.MaxSessions);
1094 [ - + ]: 652 : if (!g_iscsi.session) {
1095 : 0 : SPDK_ERRLOG("calloc() failed for session array\n");
1096 : 0 : return -1;
1097 : : }
1098 : :
1099 : : /*
1100 : : * For now, just support same number of total connections, rather
1101 : : * than MaxSessions * MaxConnectionsPerSession. After we add better
1102 : : * handling for low resource conditions from our various buffer
1103 : : * pools, we can bump this up to support more connections.
1104 : : */
1105 : 652 : g_iscsi.MaxConnections = g_iscsi.MaxSessions;
1106 : :
1107 : 652 : rc = iscsi_initialize_all_pools();
1108 [ - + ]: 652 : if (rc != 0) {
1109 : 0 : SPDK_ERRLOG("initialize_all_pools() failed\n");
1110 : 0 : free(g_iscsi.session);
1111 : 0 : g_iscsi.session = NULL;
1112 : 0 : return -1;
1113 : : }
1114 : :
1115 : 652 : rc = initialize_iscsi_conns();
1116 [ - + ]: 652 : if (rc < 0) {
1117 : 0 : SPDK_ERRLOG("initialize_iscsi_conns() failed\n");
1118 : 0 : free(g_iscsi.session);
1119 : 0 : g_iscsi.session = NULL;
1120 : 0 : return rc;
1121 : : }
1122 : :
1123 : 652 : initialize_iscsi_poll_group();
1124 : 652 : return 0;
1125 : : }
1126 : :
1127 : : void
1128 : 652 : spdk_iscsi_init(spdk_iscsi_init_cb cb_fn, void *cb_arg)
1129 : : {
1130 : : int rc;
1131 : :
1132 [ - + ]: 652 : assert(cb_fn != NULL);
1133 : 652 : g_init_cb_fn = cb_fn;
1134 : 652 : g_init_cb_arg = cb_arg;
1135 : :
1136 : 652 : rc = iscsi_parse_globals();
1137 [ - + ]: 652 : if (rc < 0) {
1138 : 0 : SPDK_ERRLOG("iscsi_parse_globals() failed\n");
1139 : 0 : iscsi_init_complete(-1);
1140 : : }
1141 : :
1142 : : /*
1143 : : * iscsi_parse_configuration() will be called as the callback to
1144 : : * spdk_initialize_iscsi_poll_group() and will complete iSCSI
1145 : : * subsystem initialization.
1146 : : */
1147 : 652 : }
1148 : :
1149 : : void
1150 : 652 : spdk_iscsi_fini(spdk_iscsi_fini_cb cb_fn, void *cb_arg)
1151 : : {
1152 : 652 : g_fini_cb_fn = cb_fn;
1153 : 652 : g_fini_cb_arg = cb_arg;
1154 : :
1155 : 652 : iscsi_portal_grp_close_all();
1156 : 652 : shutdown_iscsi_conns();
1157 : 652 : }
1158 : :
1159 : : static void
1160 : 652 : iscsi_fini_done(void *io_device)
1161 : : {
1162 : 652 : g_fini_cb_fn(g_fini_cb_arg);
1163 : 652 : }
1164 : :
1165 : : static void
1166 : 652 : _iscsi_fini_dev_unreg(struct spdk_io_channel_iter *i, int status)
1167 : : {
1168 : 652 : iscsi_check_pools();
1169 : 652 : iscsi_free_pools();
1170 : 652 : free(g_iscsi.session);
1171 : :
1172 [ - + ]: 652 : assert(TAILQ_EMPTY(&g_iscsi.poll_group_head));
1173 : :
1174 : 652 : iscsi_shutdown_tgt_nodes();
1175 : 652 : iscsi_init_grps_destroy();
1176 : 652 : iscsi_portal_grps_destroy();
1177 : 652 : iscsi_auth_groups_destroy();
1178 : :
1179 : 652 : free(g_iscsi.authfile);
1180 : 652 : free(g_iscsi.nodebase);
1181 : :
1182 [ - + ]: 652 : pthread_mutex_destroy(&g_iscsi.mutex);
1183 [ + - ]: 652 : if (g_init_thread != NULL) {
1184 : : /* g_init_thread is set just after the io_device is
1185 : : * registered, so we can use it to determine if it
1186 : : * needs to be unregistered (in cases where iscsi init
1187 : : * fails).
1188 : : */
1189 : 652 : spdk_io_device_unregister(&g_iscsi, iscsi_fini_done);
1190 : : } else {
1191 : 0 : iscsi_fini_done(NULL);
1192 : : }
1193 : 652 : }
1194 : :
1195 : : static void
1196 : 894 : _iscsi_fini_thread(struct spdk_io_channel_iter *i)
1197 : : {
1198 : : struct spdk_io_channel *ch;
1199 : : struct spdk_iscsi_poll_group *pg;
1200 : :
1201 : 894 : ch = spdk_io_channel_iter_get_channel(i);
1202 : 894 : pg = spdk_io_channel_get_ctx(ch);
1203 : :
1204 [ - + ]: 894 : pthread_mutex_lock(&g_iscsi.mutex);
1205 [ + + ]: 894 : TAILQ_REMOVE(&g_iscsi.poll_group_head, pg, link);
1206 [ - + ]: 894 : pthread_mutex_unlock(&g_iscsi.mutex);
1207 : :
1208 : 894 : spdk_put_io_channel(ch);
1209 : :
1210 : 894 : spdk_for_each_channel_continue(i, 0);
1211 : 894 : }
1212 : :
1213 : : void
1214 : 652 : shutdown_iscsi_conns_done(void)
1215 : : {
1216 : 652 : spdk_for_each_channel(&g_iscsi, _iscsi_fini_thread, NULL, _iscsi_fini_dev_unreg);
1217 : 652 : }
1218 : :
1219 : : void
1220 : 230 : iscsi_opts_info_json(struct spdk_json_write_ctx *w)
1221 : : {
1222 : 230 : spdk_json_write_object_begin(w);
1223 : :
1224 [ - + ]: 230 : if (g_iscsi.authfile != NULL) {
1225 : 0 : spdk_json_write_named_string(w, "auth_file", g_iscsi.authfile);
1226 : : }
1227 : 230 : spdk_json_write_named_string(w, "node_base", g_iscsi.nodebase);
1228 : :
1229 : 230 : spdk_json_write_named_uint32(w, "max_sessions", g_iscsi.MaxSessions);
1230 : 230 : spdk_json_write_named_uint32(w, "max_connections_per_session",
1231 : : g_iscsi.MaxConnectionsPerSession);
1232 : :
1233 : 230 : spdk_json_write_named_uint32(w, "max_queue_depth", g_iscsi.MaxQueueDepth);
1234 : :
1235 : 230 : spdk_json_write_named_uint32(w, "default_time2wait", g_iscsi.DefaultTime2Wait);
1236 : 230 : spdk_json_write_named_uint32(w, "default_time2retain", g_iscsi.DefaultTime2Retain);
1237 : :
1238 : 230 : spdk_json_write_named_uint32(w, "first_burst_length", g_iscsi.FirstBurstLength);
1239 : :
1240 [ - + ]: 230 : spdk_json_write_named_bool(w, "immediate_data", g_iscsi.ImmediateData);
1241 : :
1242 [ - + ]: 230 : spdk_json_write_named_bool(w, "allow_duplicated_isid", g_iscsi.AllowDuplicateIsid);
1243 : :
1244 : 230 : spdk_json_write_named_uint32(w, "error_recovery_level", g_iscsi.ErrorRecoveryLevel);
1245 : :
1246 : 230 : spdk_json_write_named_int32(w, "nop_timeout", g_iscsi.timeout);
1247 : 230 : spdk_json_write_named_int32(w, "nop_in_interval", g_iscsi.nopininterval);
1248 : :
1249 [ - + ]: 230 : spdk_json_write_named_bool(w, "disable_chap", g_iscsi.disable_chap);
1250 [ - + ]: 230 : spdk_json_write_named_bool(w, "require_chap", g_iscsi.require_chap);
1251 [ - + ]: 230 : spdk_json_write_named_bool(w, "mutual_chap", g_iscsi.mutual_chap);
1252 : 230 : spdk_json_write_named_int32(w, "chap_group", g_iscsi.chap_group);
1253 : :
1254 : 230 : spdk_json_write_named_uint32(w, "max_large_datain_per_connection",
1255 : : g_iscsi.MaxLargeDataInPerConnection);
1256 : 230 : spdk_json_write_named_uint32(w, "max_r2t_per_connection",
1257 : : g_iscsi.MaxR2TPerConnection);
1258 : :
1259 : 230 : spdk_json_write_named_uint32(w, "pdu_pool_size", g_iscsi.pdu_pool_size);
1260 : 230 : spdk_json_write_named_uint32(w, "immediate_data_pool_size",
1261 : : g_iscsi.immediate_data_pool_size);
1262 : 230 : spdk_json_write_named_uint32(w, "data_out_pool_size", g_iscsi.data_out_pool_size);
1263 : :
1264 : 230 : spdk_json_write_object_end(w);
1265 : 230 : }
1266 : :
1267 : : static void
1268 : 52 : iscsi_auth_group_info_json(struct spdk_iscsi_auth_group *group,
1269 : : struct spdk_json_write_ctx *w)
1270 : : {
1271 : : struct spdk_iscsi_auth_secret *_secret;
1272 : :
1273 : 52 : spdk_json_write_object_begin(w);
1274 : :
1275 : 52 : spdk_json_write_named_int32(w, "tag", group->tag);
1276 : :
1277 : 52 : spdk_json_write_named_array_begin(w, "secrets");
1278 [ + + ]: 140 : TAILQ_FOREACH(_secret, &group->secret_head, tailq) {
1279 : 88 : spdk_json_write_object_begin(w);
1280 : :
1281 : 88 : spdk_json_write_named_string(w, "user", _secret->user);
1282 : 88 : spdk_json_write_named_string(w, "secret", _secret->secret);
1283 : :
1284 [ + - ]: 88 : if (_secret->muser[0] != '\0') {
1285 : 88 : spdk_json_write_named_string(w, "muser", _secret->muser);
1286 : 88 : spdk_json_write_named_string(w, "msecret", _secret->msecret);
1287 : : }
1288 : :
1289 : 88 : spdk_json_write_object_end(w);
1290 : : }
1291 : 52 : spdk_json_write_array_end(w);
1292 : :
1293 : 52 : spdk_json_write_object_end(w);
1294 : 52 : }
1295 : :
1296 : : static void
1297 : 0 : iscsi_auth_group_config_json(struct spdk_iscsi_auth_group *group,
1298 : : struct spdk_json_write_ctx *w)
1299 : : {
1300 : 0 : spdk_json_write_object_begin(w);
1301 : :
1302 : 0 : spdk_json_write_named_string(w, "method", "iscsi_create_auth_group");
1303 : :
1304 : 0 : spdk_json_write_name(w, "params");
1305 : 0 : iscsi_auth_group_info_json(group, w);
1306 : :
1307 : 0 : spdk_json_write_object_end(w);
1308 : 0 : }
1309 : :
1310 : : void
1311 : 132 : iscsi_auth_groups_info_json(struct spdk_json_write_ctx *w)
1312 : : {
1313 : : struct spdk_iscsi_auth_group *group;
1314 : :
1315 [ + + ]: 184 : TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
1316 : 52 : iscsi_auth_group_info_json(group, w);
1317 : : }
1318 : 132 : }
1319 : :
1320 : : static void
1321 : 106 : iscsi_auth_groups_config_json(struct spdk_json_write_ctx *w)
1322 : : {
1323 : : struct spdk_iscsi_auth_group *group;
1324 : :
1325 [ - + ]: 106 : TAILQ_FOREACH(group, &g_iscsi.auth_group_head, tailq) {
1326 : 0 : iscsi_auth_group_config_json(group, w);
1327 : : }
1328 : 106 : }
1329 : :
1330 : : static void
1331 : 106 : iscsi_opts_config_json(struct spdk_json_write_ctx *w)
1332 : : {
1333 : 106 : spdk_json_write_object_begin(w);
1334 : :
1335 : 106 : spdk_json_write_named_string(w, "method", "iscsi_set_options");
1336 : :
1337 : 106 : spdk_json_write_name(w, "params");
1338 : 106 : iscsi_opts_info_json(w);
1339 : :
1340 : 106 : spdk_json_write_object_end(w);
1341 : 106 : }
1342 : :
1343 : : void
1344 : 106 : spdk_iscsi_config_json(struct spdk_json_write_ctx *w)
1345 : : {
1346 : 106 : spdk_json_write_array_begin(w);
1347 : 106 : iscsi_opts_config_json(w);
1348 : 106 : iscsi_portal_grps_config_json(w);
1349 : 106 : iscsi_init_grps_config_json(w);
1350 : 106 : iscsi_tgt_nodes_config_json(w);
1351 : 106 : iscsi_auth_groups_config_json(w);
1352 : 106 : spdk_json_write_array_end(w);
1353 : 106 : }
1354 : :
1355 : 734 : SPDK_LOG_REGISTER_COMPONENT(iscsi)
|