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 v3.13-rc8 513 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 "iscsi_target_core.h" 24#include "iscsi_target_tq.h" 25#include "iscsi_target.h" 26 27static LIST_HEAD(active_ts_list); 28static LIST_HEAD(inactive_ts_list); 29static DEFINE_SPINLOCK(active_ts_lock); 30static DEFINE_SPINLOCK(inactive_ts_lock); 31static DEFINE_SPINLOCK(ts_bitmap_lock); 32 33static 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 41static 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 49static 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 57static 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 76int 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 139static 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 168void 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 184static 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 205void 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 221struct iscsi_thread_set *iscsi_get_thread_set(void) 222{ 223 struct iscsi_thread_set *ts; 224 225get_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 242void 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 264void 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 279int 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 334int 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 361static 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 372static 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 385struct 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); 415sleep: 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 440struct 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); 469sleep: 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 494int 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 510void iscsi_thread_set_free(void) 511{ 512 kfree(iscsit_global->ts_bitmap); 513}