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