]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/target/iscsi/iscsi_target_tq.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/josef/btrfs...
[karo-tx-linux.git] / drivers / target / iscsi / iscsi_target_tq.c
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
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
43 static 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
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
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         ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list);
70
71         list_del(&ts->ts_list);
72         iscsit_global->inactive_ts--;
73         spin_unlock(&inactive_ts_lock);
74
75         return ts;
76 }
77
78 int iscsi_allocate_thread_sets(u32 thread_pair_count)
79 {
80         int allocated_thread_pair_count = 0, i, thread_id;
81         struct iscsi_thread_set *ts = NULL;
82
83         for (i = 0; i < thread_pair_count; i++) {
84                 ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL);
85                 if (!ts) {
86                         pr_err("Unable to allocate memory for"
87                                         " thread set.\n");
88                         return allocated_thread_pair_count;
89                 }
90                 /*
91                  * Locate the next available regision in the thread_set_bitmap
92                  */
93                 spin_lock(&ts_bitmap_lock);
94                 thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap,
95                                 iscsit_global->ts_bitmap_count, get_order(1));
96                 spin_unlock(&ts_bitmap_lock);
97                 if (thread_id < 0) {
98                         pr_err("bitmap_find_free_region() failed for"
99                                 " thread_set_bitmap\n");
100                         kfree(ts);
101                         return allocated_thread_pair_count;
102                 }
103
104                 ts->thread_id = thread_id;
105                 ts->status = ISCSI_THREAD_SET_FREE;
106                 INIT_LIST_HEAD(&ts->ts_list);
107                 spin_lock_init(&ts->ts_state_lock);
108                 init_completion(&ts->rx_post_start_comp);
109                 init_completion(&ts->tx_post_start_comp);
110                 init_completion(&ts->rx_restart_comp);
111                 init_completion(&ts->tx_restart_comp);
112                 init_completion(&ts->rx_start_comp);
113                 init_completion(&ts->tx_start_comp);
114
115                 ts->create_threads = 1;
116                 ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s",
117                                         ISCSI_TX_THREAD_NAME);
118                 if (IS_ERR(ts->tx_thread)) {
119                         dump_stack();
120                         pr_err("Unable to start iscsi_target_tx_thread\n");
121                         break;
122                 }
123
124                 ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s",
125                                         ISCSI_RX_THREAD_NAME);
126                 if (IS_ERR(ts->rx_thread)) {
127                         kthread_stop(ts->tx_thread);
128                         pr_err("Unable to start iscsi_target_rx_thread\n");
129                         break;
130                 }
131                 ts->create_threads = 0;
132
133                 iscsi_add_ts_to_inactive_list(ts);
134                 allocated_thread_pair_count++;
135         }
136
137         pr_debug("Spawned %d thread set(s) (%d total threads).\n",
138                 allocated_thread_pair_count, allocated_thread_pair_count * 2);
139         return allocated_thread_pair_count;
140 }
141
142 void iscsi_deallocate_thread_sets(void)
143 {
144         u32 released_count = 0;
145         struct iscsi_thread_set *ts = NULL;
146
147         while ((ts = iscsi_get_ts_from_inactive_list())) {
148
149                 spin_lock_bh(&ts->ts_state_lock);
150                 ts->status = ISCSI_THREAD_SET_DIE;
151                 spin_unlock_bh(&ts->ts_state_lock);
152
153                 if (ts->rx_thread) {
154                         send_sig(SIGINT, ts->rx_thread, 1);
155                         kthread_stop(ts->rx_thread);
156                 }
157                 if (ts->tx_thread) {
158                         send_sig(SIGINT, ts->tx_thread, 1);
159                         kthread_stop(ts->tx_thread);
160                 }
161                 /*
162                  * Release this thread_id in the thread_set_bitmap
163                  */
164                 spin_lock(&ts_bitmap_lock);
165                 bitmap_release_region(iscsit_global->ts_bitmap,
166                                 ts->thread_id, get_order(1));
167                 spin_unlock(&ts_bitmap_lock);
168
169                 released_count++;
170                 kfree(ts);
171         }
172
173         if (released_count)
174                 pr_debug("Stopped %d thread set(s) (%d total threads)."
175                         "\n", released_count, released_count * 2);
176 }
177
178 static void iscsi_deallocate_extra_thread_sets(void)
179 {
180         u32 orig_count, released_count = 0;
181         struct iscsi_thread_set *ts = NULL;
182
183         orig_count = TARGET_THREAD_SET_COUNT;
184
185         while ((iscsit_global->inactive_ts + 1) > orig_count) {
186                 ts = iscsi_get_ts_from_inactive_list();
187                 if (!ts)
188                         break;
189
190                 spin_lock_bh(&ts->ts_state_lock);
191                 ts->status = ISCSI_THREAD_SET_DIE;
192                 spin_unlock_bh(&ts->ts_state_lock);
193
194                 if (ts->rx_thread) {
195                         send_sig(SIGINT, ts->rx_thread, 1);
196                         kthread_stop(ts->rx_thread);
197                 }
198                 if (ts->tx_thread) {
199                         send_sig(SIGINT, ts->tx_thread, 1);
200                         kthread_stop(ts->tx_thread);
201                 }
202                 /*
203                  * Release this thread_id in the thread_set_bitmap
204                  */
205                 spin_lock(&ts_bitmap_lock);
206                 bitmap_release_region(iscsit_global->ts_bitmap,
207                                 ts->thread_id, get_order(1));
208                 spin_unlock(&ts_bitmap_lock);
209
210                 released_count++;
211                 kfree(ts);
212         }
213
214         if (released_count) {
215                 pr_debug("Stopped %d thread set(s) (%d total threads)."
216                         "\n", released_count, released_count * 2);
217         }
218 }
219
220 void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts)
221 {
222         iscsi_add_ts_to_active_list(ts);
223
224         spin_lock_bh(&ts->ts_state_lock);
225         conn->thread_set = ts;
226         ts->conn = conn;
227         spin_unlock_bh(&ts->ts_state_lock);
228         /*
229          * Start up the RX thread and wait on rx_post_start_comp.  The RX
230          * Thread will then do the same for the TX Thread in
231          * iscsi_rx_thread_pre_handler().
232          */
233         complete(&ts->rx_start_comp);
234         wait_for_completion(&ts->rx_post_start_comp);
235 }
236
237 struct iscsi_thread_set *iscsi_get_thread_set(void)
238 {
239         int allocate_ts = 0;
240         struct completion comp;
241         struct iscsi_thread_set *ts = NULL;
242         /*
243          * If no inactive thread set is available on the first call to
244          * iscsi_get_ts_from_inactive_list(), sleep for a second and
245          * try again.  If still none are available after two attempts,
246          * allocate a set ourselves.
247          */
248 get_set:
249         ts = iscsi_get_ts_from_inactive_list();
250         if (!ts) {
251                 if (allocate_ts == 2)
252                         iscsi_allocate_thread_sets(1);
253
254                 init_completion(&comp);
255                 wait_for_completion_timeout(&comp, 1 * HZ);
256
257                 allocate_ts++;
258                 goto get_set;
259         }
260
261         ts->delay_inactive = 1;
262         ts->signal_sent = 0;
263         ts->thread_count = 2;
264         init_completion(&ts->rx_restart_comp);
265         init_completion(&ts->tx_restart_comp);
266
267         return ts;
268 }
269
270 void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear)
271 {
272         struct iscsi_thread_set *ts = NULL;
273
274         if (!conn->thread_set) {
275                 pr_err("struct iscsi_conn->thread_set is NULL\n");
276                 return;
277         }
278         ts = conn->thread_set;
279
280         spin_lock_bh(&ts->ts_state_lock);
281         ts->thread_clear &= ~thread_clear;
282
283         if ((thread_clear & ISCSI_CLEAR_RX_THREAD) &&
284             (ts->blocked_threads & ISCSI_BLOCK_RX_THREAD))
285                 complete(&ts->rx_restart_comp);
286         else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) &&
287                  (ts->blocked_threads & ISCSI_BLOCK_TX_THREAD))
288                 complete(&ts->tx_restart_comp);
289         spin_unlock_bh(&ts->ts_state_lock);
290 }
291
292 void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent)
293 {
294         struct iscsi_thread_set *ts = NULL;
295
296         if (!conn->thread_set) {
297                 pr_err("struct iscsi_conn->thread_set is NULL\n");
298                 return;
299         }
300         ts = conn->thread_set;
301
302         spin_lock_bh(&ts->ts_state_lock);
303         ts->signal_sent |= signal_sent;
304         spin_unlock_bh(&ts->ts_state_lock);
305 }
306
307 int iscsi_release_thread_set(struct iscsi_conn *conn)
308 {
309         int thread_called = 0;
310         struct iscsi_thread_set *ts = NULL;
311
312         if (!conn || !conn->thread_set) {
313                 pr_err("connection or thread set pointer is NULL\n");
314                 BUG();
315         }
316         ts = conn->thread_set;
317
318         spin_lock_bh(&ts->ts_state_lock);
319         ts->status = ISCSI_THREAD_SET_RESET;
320
321         if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME,
322                         strlen(ISCSI_RX_THREAD_NAME)))
323                 thread_called = ISCSI_RX_THREAD;
324         else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME,
325                         strlen(ISCSI_TX_THREAD_NAME)))
326                 thread_called = ISCSI_TX_THREAD;
327
328         if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) &&
329            (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) {
330
331                 if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) {
332                         send_sig(SIGINT, ts->rx_thread, 1);
333                         ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD;
334                 }
335                 ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD;
336                 spin_unlock_bh(&ts->ts_state_lock);
337                 wait_for_completion(&ts->rx_restart_comp);
338                 spin_lock_bh(&ts->ts_state_lock);
339                 ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD;
340         }
341         if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) &&
342            (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) {
343
344                 if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) {
345                         send_sig(SIGINT, ts->tx_thread, 1);
346                         ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD;
347                 }
348                 ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD;
349                 spin_unlock_bh(&ts->ts_state_lock);
350                 wait_for_completion(&ts->tx_restart_comp);
351                 spin_lock_bh(&ts->ts_state_lock);
352                 ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD;
353         }
354
355         ts->conn = NULL;
356         ts->status = ISCSI_THREAD_SET_FREE;
357         spin_unlock_bh(&ts->ts_state_lock);
358
359         return 0;
360 }
361
362 int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn)
363 {
364         struct iscsi_thread_set *ts;
365
366         if (!conn->thread_set)
367                 return -1;
368         ts = conn->thread_set;
369
370         spin_lock_bh(&ts->ts_state_lock);
371         if (ts->status != ISCSI_THREAD_SET_ACTIVE) {
372                 spin_unlock_bh(&ts->ts_state_lock);
373                 return -1;
374         }
375
376         if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) {
377                 send_sig(SIGINT, ts->tx_thread, 1);
378                 ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD;
379         }
380         if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) {
381                 send_sig(SIGINT, ts->rx_thread, 1);
382                 ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD;
383         }
384         spin_unlock_bh(&ts->ts_state_lock);
385
386         return 0;
387 }
388
389 static void iscsi_check_to_add_additional_sets(void)
390 {
391         int thread_sets_add;
392
393         spin_lock(&inactive_ts_lock);
394         thread_sets_add = iscsit_global->inactive_ts;
395         spin_unlock(&inactive_ts_lock);
396         if (thread_sets_add == 1)
397                 iscsi_allocate_thread_sets(1);
398 }
399
400 static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts)
401 {
402         spin_lock_bh(&ts->ts_state_lock);
403         if ((ts->status == ISCSI_THREAD_SET_DIE) || signal_pending(current)) {
404                 spin_unlock_bh(&ts->ts_state_lock);
405                 return -1;
406         }
407         spin_unlock_bh(&ts->ts_state_lock);
408
409         return 0;
410 }
411
412 struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts)
413 {
414         int ret;
415
416         spin_lock_bh(&ts->ts_state_lock);
417         if (ts->create_threads) {
418                 spin_unlock_bh(&ts->ts_state_lock);
419                 goto sleep;
420         }
421
422         flush_signals(current);
423
424         if (ts->delay_inactive && (--ts->thread_count == 0)) {
425                 spin_unlock_bh(&ts->ts_state_lock);
426                 iscsi_del_ts_from_active_list(ts);
427
428                 if (!iscsit_global->in_shutdown)
429                         iscsi_deallocate_extra_thread_sets();
430
431                 iscsi_add_ts_to_inactive_list(ts);
432                 spin_lock_bh(&ts->ts_state_lock);
433         }
434
435         if ((ts->status == ISCSI_THREAD_SET_RESET) &&
436             (ts->thread_clear & ISCSI_CLEAR_RX_THREAD))
437                 complete(&ts->rx_restart_comp);
438
439         ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD;
440         spin_unlock_bh(&ts->ts_state_lock);
441 sleep:
442         ret = wait_for_completion_interruptible(&ts->rx_start_comp);
443         if (ret != 0)
444                 return NULL;
445
446         if (iscsi_signal_thread_pre_handler(ts) < 0)
447                 return NULL;
448
449         if (!ts->conn) {
450                 pr_err("struct iscsi_thread_set->conn is NULL for"
451                         " thread_id: %d, going back to sleep\n", ts->thread_id);
452                 goto sleep;
453         }
454         iscsi_check_to_add_additional_sets();
455         /*
456          * The RX Thread starts up the TX Thread and sleeps.
457          */
458         ts->thread_clear |= ISCSI_CLEAR_RX_THREAD;
459         complete(&ts->tx_start_comp);
460         wait_for_completion(&ts->tx_post_start_comp);
461
462         return ts->conn;
463 }
464
465 struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts)
466 {
467         int ret;
468
469         spin_lock_bh(&ts->ts_state_lock);
470         if (ts->create_threads) {
471                 spin_unlock_bh(&ts->ts_state_lock);
472                 goto sleep;
473         }
474
475         flush_signals(current);
476
477         if (ts->delay_inactive && (--ts->thread_count == 0)) {
478                 spin_unlock_bh(&ts->ts_state_lock);
479                 iscsi_del_ts_from_active_list(ts);
480
481                 if (!iscsit_global->in_shutdown)
482                         iscsi_deallocate_extra_thread_sets();
483
484                 iscsi_add_ts_to_inactive_list(ts);
485                 spin_lock_bh(&ts->ts_state_lock);
486         }
487         if ((ts->status == ISCSI_THREAD_SET_RESET) &&
488             (ts->thread_clear & ISCSI_CLEAR_TX_THREAD))
489                 complete(&ts->tx_restart_comp);
490
491         ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD;
492         spin_unlock_bh(&ts->ts_state_lock);
493 sleep:
494         ret = wait_for_completion_interruptible(&ts->tx_start_comp);
495         if (ret != 0)
496                 return NULL;
497
498         if (iscsi_signal_thread_pre_handler(ts) < 0)
499                 return NULL;
500
501         if (!ts->conn) {
502                 pr_err("struct iscsi_thread_set->conn is NULL for "
503                         " thread_id: %d, going back to sleep\n",
504                         ts->thread_id);
505                 goto sleep;
506         }
507
508         iscsi_check_to_add_additional_sets();
509         /*
510          * From the TX thread, up the tx_post_start_comp that the RX Thread is
511          * sleeping on in iscsi_rx_thread_pre_handler(), then up the
512          * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on.
513          */
514         ts->thread_clear |= ISCSI_CLEAR_TX_THREAD;
515         complete(&ts->tx_post_start_comp);
516         complete(&ts->rx_post_start_comp);
517
518         spin_lock_bh(&ts->ts_state_lock);
519         ts->status = ISCSI_THREAD_SET_ACTIVE;
520         spin_unlock_bh(&ts->ts_state_lock);
521
522         return ts->conn;
523 }
524
525 int iscsi_thread_set_init(void)
526 {
527         int size;
528
529         iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS;
530
531         size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long);
532         iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL);
533         if (!iscsit_global->ts_bitmap) {
534                 pr_err("Unable to allocate iscsit_global->ts_bitmap\n");
535                 return -ENOMEM;
536         }
537
538         return 0;
539 }
540
541 void iscsi_thread_set_free(void)
542 {
543         kfree(iscsit_global->ts_bitmap);
544 }