• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * This file contains the iSCSI Login Thread and Thread Queue functions.
3  *
4  * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
5  *
6  * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
7  *
8  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  ******************************************************************************/
20 
21 #include <linux/kthread.h>
22 #include <linux/list.h>
23 #include <linux/bitmap.h>
24 
25 #include "iscsi_target_core.h"
26 #include "iscsi_target_tq.h"
27 #include "iscsi_target.h"
28 
29 static LIST_HEAD(active_ts_list);
30 static LIST_HEAD(inactive_ts_list);
31 static DEFINE_SPINLOCK(active_ts_lock);
32 static DEFINE_SPINLOCK(inactive_ts_lock);
33 static DEFINE_SPINLOCK(ts_bitmap_lock);
34 
iscsi_add_ts_to_active_list(struct iscsi_thread_set * ts)35 static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts)
36 {
37 	spin_lock(&active_ts_lock);
38 	list_add_tail(&ts->ts_list, &active_ts_list);
39 	iscsit_global->active_ts++;
40 	spin_unlock(&active_ts_lock);
41 }
42 
iscsi_add_ts_to_inactive_list(struct iscsi_thread_set * ts)43 extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
44 {
45 	spin_lock(&inactive_ts_lock);
46 	list_add_tail(&ts->ts_list, &inactive_ts_list);
47 	iscsit_global->inactive_ts++;
48 	spin_unlock(&inactive_ts_lock);
49 }
50 
iscsi_del_ts_from_active_list(struct iscsi_thread_set * ts)51 static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts)
52 {
53 	spin_lock(&active_ts_lock);
54 	list_del(&ts->ts_list);
55 	iscsit_global->active_ts--;
56 	spin_unlock(&active_ts_lock);
57 }
58 
iscsi_get_ts_from_inactive_list(void)59 static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)
60 {
61 	struct iscsi_thread_set *ts;
62 
63 	spin_lock(&inactive_ts_lock);
64 	if (list_empty(&inactive_ts_list)) {
65 		spin_unlock(&inactive_ts_lock);
66 		return NULL;
67 	}
68 
69 	list_for_each_entry(ts, &inactive_ts_list, ts_list)
70 		break;
71 
72 	list_del(&ts->ts_list);
73 	iscsit_global->inactive_ts--;
74 	spin_unlock(&inactive_ts_lock);
75 
76 	return ts;
77 }
78 
iscsi_allocate_thread_sets(u32 thread_pair_count)79 extern int iscsi_allocate_thread_sets(u32 thread_pair_count)
80 {
81 	int allocated_thread_pair_count = 0, i, thread_id;
82 	struct iscsi_thread_set *ts = NULL;
83 
84 	for (i = 0; i < thread_pair_count; i++) {
85 		ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL);
86 		if (!ts) {
87 			pr_err("Unable to allocate memory for"
88 					" thread set.\n");
89 			return allocated_thread_pair_count;
90 		}
91 		/*
92 		 * Locate the next available regision in the thread_set_bitmap
93 		 */
94 		spin_lock(&ts_bitmap_lock);
95 		thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap,
96 				iscsit_global->ts_bitmap_count, get_order(1));
97 		spin_unlock(&ts_bitmap_lock);
98 		if (thread_id < 0) {
99 			pr_err("bitmap_find_free_region() failed for"
100 				" thread_set_bitmap\n");
101 			kfree(ts);
102 			return allocated_thread_pair_count;
103 		}
104 
105 		ts->thread_id = thread_id;
106 		ts->status = ISCSI_THREAD_SET_FREE;
107 		INIT_LIST_HEAD(&ts->ts_list);
108 		spin_lock_init(&ts->ts_state_lock);
109 		init_completion(&ts->rx_post_start_comp);
110 		init_completion(&ts->tx_post_start_comp);
111 		init_completion(&ts->rx_restart_comp);
112 		init_completion(&ts->tx_restart_comp);
113 		init_completion(&ts->rx_start_comp);
114 		init_completion(&ts->tx_start_comp);
115 
116 		ts->create_threads = 1;
117 		ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s",
118 					ISCSI_TX_THREAD_NAME);
119 		if (IS_ERR(ts->tx_thread)) {
120 			dump_stack();
121 			pr_err("Unable to start iscsi_target_tx_thread\n");
122 			break;
123 		}
124 
125 		ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s",
126 					ISCSI_RX_THREAD_NAME);
127 		if (IS_ERR(ts->rx_thread)) {
128 			kthread_stop(ts->tx_thread);
129 			pr_err("Unable to start iscsi_target_rx_thread\n");
130 			break;
131 		}
132 		ts->create_threads = 0;
133 
134 		iscsi_add_ts_to_inactive_list(ts);
135 		allocated_thread_pair_count++;
136 	}
137 
138 	pr_debug("Spawned %d thread set(s) (%d total threads).\n",
139 		allocated_thread_pair_count, allocated_thread_pair_count * 2);
140 	return allocated_thread_pair_count;
141 }
142 
iscsi_deallocate_thread_sets(void)143 extern void iscsi_deallocate_thread_sets(void)
144 {
145 	u32 released_count = 0;
146 	struct iscsi_thread_set *ts = NULL;
147 
148 	while ((ts = iscsi_get_ts_from_inactive_list())) {
149 
150 		spin_lock_bh(&ts->ts_state_lock);
151 		ts->status = ISCSI_THREAD_SET_DIE;
152 		spin_unlock_bh(&ts->ts_state_lock);
153 
154 		if (ts->rx_thread) {
155 			send_sig(SIGINT, ts->rx_thread, 1);
156 			kthread_stop(ts->rx_thread);
157 		}
158 		if (ts->tx_thread) {
159 			send_sig(SIGINT, ts->tx_thread, 1);
160 			kthread_stop(ts->tx_thread);
161 		}
162 		/*
163 		 * Release this thread_id in the thread_set_bitmap
164 		 */
165 		spin_lock(&ts_bitmap_lock);
166 		bitmap_release_region(iscsit_global->ts_bitmap,
167 				ts->thread_id, get_order(1));
168 		spin_unlock(&ts_bitmap_lock);
169 
170 		released_count++;
171 		kfree(ts);
172 	}
173 
174 	if (released_count)
175 		pr_debug("Stopped %d thread set(s) (%d total threads)."
176 			"\n", released_count, released_count * 2);
177 }
178 
iscsi_deallocate_extra_thread_sets(void)179 static void iscsi_deallocate_extra_thread_sets(void)
180 {
181 	u32 orig_count, released_count = 0;
182 	struct iscsi_thread_set *ts = NULL;
183 
184 	orig_count = TARGET_THREAD_SET_COUNT;
185 
186 	while ((iscsit_global->inactive_ts + 1) > orig_count) {
187 		ts = iscsi_get_ts_from_inactive_list();
188 		if (!ts)
189 			break;
190 
191 		spin_lock_bh(&ts->ts_state_lock);
192 		ts->status = ISCSI_THREAD_SET_DIE;
193 		spin_unlock_bh(&ts->ts_state_lock);
194 
195 		if (ts->rx_thread) {
196 			send_sig(SIGINT, ts->rx_thread, 1);
197 			kthread_stop(ts->rx_thread);
198 		}
199 		if (ts->tx_thread) {
200 			send_sig(SIGINT, ts->tx_thread, 1);
201 			kthread_stop(ts->tx_thread);
202 		}
203 		/*
204 		 * Release this thread_id in the thread_set_bitmap
205 		 */
206 		spin_lock(&ts_bitmap_lock);
207 		bitmap_release_region(iscsit_global->ts_bitmap,
208 				ts->thread_id, get_order(1));
209 		spin_unlock(&ts_bitmap_lock);
210 
211 		released_count++;
212 		kfree(ts);
213 	}
214 
215 	if (released_count) {
216 		pr_debug("Stopped %d thread set(s) (%d total threads)."
217 			"\n", released_count, released_count * 2);
218 	}
219 }
220 
iscsi_activate_thread_set(struct iscsi_conn * conn,struct iscsi_thread_set * ts)221 void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts)
222 {
223 	iscsi_add_ts_to_active_list(ts);
224 
225 	spin_lock_bh(&ts->ts_state_lock);
226 	conn->thread_set = ts;
227 	ts->conn = conn;
228 	spin_unlock_bh(&ts->ts_state_lock);
229 	/*
230 	 * Start up the RX thread and wait on rx_post_start_comp.  The RX
231 	 * Thread will then do the same for the TX Thread in
232 	 * iscsi_rx_thread_pre_handler().
233 	 */
234 	complete(&ts->rx_start_comp);
235 	wait_for_completion(&ts->rx_post_start_comp);
236 }
237 
iscsi_get_thread_set(void)238 struct iscsi_thread_set *iscsi_get_thread_set(void)
239 {
240 	int allocate_ts = 0;
241 	struct completion comp;
242 	struct iscsi_thread_set *ts = NULL;
243 	/*
244 	 * If no inactive thread set is available on the first call to
245 	 * iscsi_get_ts_from_inactive_list(), sleep for a second and
246 	 * try again.  If still none are available after two attempts,
247 	 * allocate a set ourselves.
248 	 */
249 get_set:
250 	ts = iscsi_get_ts_from_inactive_list();
251 	if (!ts) {
252 		if (allocate_ts == 2)
253 			iscsi_allocate_thread_sets(1);
254 
255 		init_completion(&comp);
256 		wait_for_completion_timeout(&comp, 1 * HZ);
257 
258 		allocate_ts++;
259 		goto get_set;
260 	}
261 
262 	ts->delay_inactive = 1;
263 	ts->signal_sent = 0;
264 	ts->thread_count = 2;
265 	init_completion(&ts->rx_restart_comp);
266 	init_completion(&ts->tx_restart_comp);
267 
268 	return ts;
269 }
270 
iscsi_set_thread_clear(struct iscsi_conn * conn,u8 thread_clear)271 void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear)
272 {
273 	struct iscsi_thread_set *ts = NULL;
274 
275 	if (!conn->thread_set) {
276 		pr_err("struct iscsi_conn->thread_set is NULL\n");
277 		return;
278 	}
279 	ts = conn->thread_set;
280 
281 	spin_lock_bh(&ts->ts_state_lock);
282 	ts->thread_clear &= ~thread_clear;
283 
284 	if ((thread_clear & ISCSI_CLEAR_RX_THREAD) &&
285 	    (ts->blocked_threads & ISCSI_BLOCK_RX_THREAD))
286 		complete(&ts->rx_restart_comp);
287 	else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) &&
288 		 (ts->blocked_threads & ISCSI_BLOCK_TX_THREAD))
289 		complete(&ts->tx_restart_comp);
290 	spin_unlock_bh(&ts->ts_state_lock);
291 }
292 
iscsi_set_thread_set_signal(struct iscsi_conn * conn,u8 signal_sent)293 void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent)
294 {
295 	struct iscsi_thread_set *ts = NULL;
296 
297 	if (!conn->thread_set) {
298 		pr_err("struct iscsi_conn->thread_set is NULL\n");
299 		return;
300 	}
301 	ts = conn->thread_set;
302 
303 	spin_lock_bh(&ts->ts_state_lock);
304 	ts->signal_sent |= signal_sent;
305 	spin_unlock_bh(&ts->ts_state_lock);
306 }
307 
iscsi_release_thread_set(struct iscsi_conn * conn)308 int iscsi_release_thread_set(struct iscsi_conn *conn)
309 {
310 	int thread_called = 0;
311 	struct iscsi_thread_set *ts = NULL;
312 
313 	if (!conn || !conn->thread_set) {
314 		pr_err("connection or thread set pointer is NULL\n");
315 		BUG();
316 	}
317 	ts = conn->thread_set;
318 
319 	spin_lock_bh(&ts->ts_state_lock);
320 	ts->status = ISCSI_THREAD_SET_RESET;
321 
322 	if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME,
323 			strlen(ISCSI_RX_THREAD_NAME)))
324 		thread_called = ISCSI_RX_THREAD;
325 	else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME,
326 			strlen(ISCSI_TX_THREAD_NAME)))
327 		thread_called = ISCSI_TX_THREAD;
328 
329 	if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) &&
330 	   (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) {
331 
332 		if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) {
333 			send_sig(SIGINT, ts->rx_thread, 1);
334 			ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD;
335 		}
336 		ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD;
337 		spin_unlock_bh(&ts->ts_state_lock);
338 		wait_for_completion(&ts->rx_restart_comp);
339 		spin_lock_bh(&ts->ts_state_lock);
340 		ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD;
341 	}
342 	if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) &&
343 	   (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) {
344 
345 		if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) {
346 			send_sig(SIGINT, ts->tx_thread, 1);
347 			ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD;
348 		}
349 		ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD;
350 		spin_unlock_bh(&ts->ts_state_lock);
351 		wait_for_completion(&ts->tx_restart_comp);
352 		spin_lock_bh(&ts->ts_state_lock);
353 		ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD;
354 	}
355 
356 	ts->conn = NULL;
357 	ts->status = ISCSI_THREAD_SET_FREE;
358 	spin_unlock_bh(&ts->ts_state_lock);
359 
360 	return 0;
361 }
362 
iscsi_thread_set_force_reinstatement(struct iscsi_conn * conn)363 int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn)
364 {
365 	struct iscsi_thread_set *ts;
366 
367 	if (!conn->thread_set)
368 		return -1;
369 	ts = conn->thread_set;
370 
371 	spin_lock_bh(&ts->ts_state_lock);
372 	if (ts->status != ISCSI_THREAD_SET_ACTIVE) {
373 		spin_unlock_bh(&ts->ts_state_lock);
374 		return -1;
375 	}
376 
377 	if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) {
378 		send_sig(SIGINT, ts->tx_thread, 1);
379 		ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD;
380 	}
381 	if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) {
382 		send_sig(SIGINT, ts->rx_thread, 1);
383 		ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD;
384 	}
385 	spin_unlock_bh(&ts->ts_state_lock);
386 
387 	return 0;
388 }
389 
iscsi_check_to_add_additional_sets(void)390 static void iscsi_check_to_add_additional_sets(void)
391 {
392 	int thread_sets_add;
393 
394 	spin_lock(&inactive_ts_lock);
395 	thread_sets_add = iscsit_global->inactive_ts;
396 	spin_unlock(&inactive_ts_lock);
397 	if (thread_sets_add == 1)
398 		iscsi_allocate_thread_sets(1);
399 }
400 
iscsi_signal_thread_pre_handler(struct iscsi_thread_set * ts)401 static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts)
402 {
403 	spin_lock_bh(&ts->ts_state_lock);
404 	if ((ts->status == ISCSI_THREAD_SET_DIE) || signal_pending(current)) {
405 		spin_unlock_bh(&ts->ts_state_lock);
406 		return -1;
407 	}
408 	spin_unlock_bh(&ts->ts_state_lock);
409 
410 	return 0;
411 }
412 
iscsi_rx_thread_pre_handler(struct iscsi_thread_set * ts)413 struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts)
414 {
415 	int ret;
416 
417 	spin_lock_bh(&ts->ts_state_lock);
418 	if (ts->create_threads) {
419 		spin_unlock_bh(&ts->ts_state_lock);
420 		goto sleep;
421 	}
422 
423 	flush_signals(current);
424 
425 	if (ts->delay_inactive && (--ts->thread_count == 0)) {
426 		spin_unlock_bh(&ts->ts_state_lock);
427 		iscsi_del_ts_from_active_list(ts);
428 
429 		if (!iscsit_global->in_shutdown)
430 			iscsi_deallocate_extra_thread_sets();
431 
432 		iscsi_add_ts_to_inactive_list(ts);
433 		spin_lock_bh(&ts->ts_state_lock);
434 	}
435 
436 	if ((ts->status == ISCSI_THREAD_SET_RESET) &&
437 	    (ts->thread_clear & ISCSI_CLEAR_RX_THREAD))
438 		complete(&ts->rx_restart_comp);
439 
440 	ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD;
441 	spin_unlock_bh(&ts->ts_state_lock);
442 sleep:
443 	ret = wait_for_completion_interruptible(&ts->rx_start_comp);
444 	if (ret != 0)
445 		return NULL;
446 
447 	if (iscsi_signal_thread_pre_handler(ts) < 0)
448 		return NULL;
449 
450 	if (!ts->conn) {
451 		pr_err("struct iscsi_thread_set->conn is NULL for"
452 			" thread_id: %d, going back to sleep\n", ts->thread_id);
453 		goto sleep;
454 	}
455 	iscsi_check_to_add_additional_sets();
456 	/*
457 	 * The RX Thread starts up the TX Thread and sleeps.
458 	 */
459 	ts->thread_clear |= ISCSI_CLEAR_RX_THREAD;
460 	complete(&ts->tx_start_comp);
461 	wait_for_completion(&ts->tx_post_start_comp);
462 
463 	return ts->conn;
464 }
465 
iscsi_tx_thread_pre_handler(struct iscsi_thread_set * ts)466 struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts)
467 {
468 	int ret;
469 
470 	spin_lock_bh(&ts->ts_state_lock);
471 	if (ts->create_threads) {
472 		spin_unlock_bh(&ts->ts_state_lock);
473 		goto sleep;
474 	}
475 
476 	flush_signals(current);
477 
478 	if (ts->delay_inactive && (--ts->thread_count == 0)) {
479 		spin_unlock_bh(&ts->ts_state_lock);
480 		iscsi_del_ts_from_active_list(ts);
481 
482 		if (!iscsit_global->in_shutdown)
483 			iscsi_deallocate_extra_thread_sets();
484 
485 		iscsi_add_ts_to_inactive_list(ts);
486 		spin_lock_bh(&ts->ts_state_lock);
487 	}
488 	if ((ts->status == ISCSI_THREAD_SET_RESET) &&
489 	    (ts->thread_clear & ISCSI_CLEAR_TX_THREAD))
490 		complete(&ts->tx_restart_comp);
491 
492 	ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD;
493 	spin_unlock_bh(&ts->ts_state_lock);
494 sleep:
495 	ret = wait_for_completion_interruptible(&ts->tx_start_comp);
496 	if (ret != 0)
497 		return NULL;
498 
499 	if (iscsi_signal_thread_pre_handler(ts) < 0)
500 		return NULL;
501 
502 	if (!ts->conn) {
503 		pr_err("struct iscsi_thread_set->conn is NULL for "
504 			" thread_id: %d, going back to sleep\n",
505 			ts->thread_id);
506 		goto sleep;
507 	}
508 
509 	iscsi_check_to_add_additional_sets();
510 	/*
511 	 * From the TX thread, up the tx_post_start_comp that the RX Thread is
512 	 * sleeping on in iscsi_rx_thread_pre_handler(), then up the
513 	 * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on.
514 	 */
515 	ts->thread_clear |= ISCSI_CLEAR_TX_THREAD;
516 	complete(&ts->tx_post_start_comp);
517 	complete(&ts->rx_post_start_comp);
518 
519 	spin_lock_bh(&ts->ts_state_lock);
520 	ts->status = ISCSI_THREAD_SET_ACTIVE;
521 	spin_unlock_bh(&ts->ts_state_lock);
522 
523 	return ts->conn;
524 }
525 
iscsi_thread_set_init(void)526 int iscsi_thread_set_init(void)
527 {
528 	int size;
529 
530 	iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS;
531 
532 	size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long);
533 	iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL);
534 	if (!iscsit_global->ts_bitmap) {
535 		pr_err("Unable to allocate iscsit_global->ts_bitmap\n");
536 		return -ENOMEM;
537 	}
538 
539 	return 0;
540 }
541 
iscsi_thread_set_free(void)542 void iscsi_thread_set_free(void)
543 {
544 	kfree(iscsit_global->ts_bitmap);
545 }
546