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