Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.0 495 lines 13 kB view raw
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 <target/iscsi/iscsi_target_core.h> 24#include "iscsi_target_tq.h" 25#include "iscsi_target.h" 26 27static LIST_HEAD(inactive_ts_list); 28static DEFINE_SPINLOCK(inactive_ts_lock); 29static DEFINE_SPINLOCK(ts_bitmap_lock); 30 31static 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 43static 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 62int 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 125static 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 154void 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 170static 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 191void 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 205struct iscsi_thread_set *iscsi_get_thread_set(void) 206{ 207 struct iscsi_thread_set *ts; 208 209get_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 226void 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 248void 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 263int 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 318int 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 345static 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 356static 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 369struct 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); 398sleep: 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 423struct 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); 451sleep: 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 476int 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 492void iscsi_thread_set_free(void) 493{ 494 kfree(iscsit_global->ts_bitmap); 495}