struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) { int ret; spin_lock_bh(&ts->ts_state_lock); if (ts->create_threads) { spin_unlock_bh(&ts->ts_state_lock); goto sleep; } flush_signals(current); if (ts->delay_inactive && (--ts->thread_count == 0)) { spin_unlock_bh(&ts->ts_state_lock); iscsi_del_ts_from_active_list(ts); if (!iscsit_global->in_shutdown) iscsi_deallocate_extra_thread_sets(); iscsi_add_ts_to_inactive_list(ts); spin_lock_bh(&ts->ts_state_lock); } if ((ts->status == ISCSI_THREAD_SET_RESET) && (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) complete(&ts->rx_restart_comp); ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD; spin_unlock_bh(&ts->ts_state_lock); sleep: ret = wait_for_completion_interruptible(&ts->rx_start_comp); pr_info("%s: %s/%d (thread set %d) got %d waiting for rx_start_comp\n", __func__, current->comm, task_pid_nr(current), ts->thread_id, ret); if (ret != 0) return NULL; if (iscsi_signal_thread_pre_handler(ts) < 0) return NULL; if (!ts->conn) { pr_err("struct iscsi_thread_set->conn is NULL for" " thread_id: %d, going back to sleep\n", ts->thread_id); goto sleep; } iscsi_check_to_add_additional_sets(); /* * The RX Thread starts up the TX Thread and sleeps. */ spin_lock_bh(&ts->ts_state_lock); ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; spin_unlock_bh(&ts->ts_state_lock); complete(&ts->tx_start_comp); wait_for_completion(&ts->tx_post_start_comp); pr_info("%s/%d: returning connection %p for rx thread\n", current->comm, task_pid_nr(current), ts->conn); return ts->conn; }
struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) { int ret; spin_lock_bh(&ts->ts_state_lock); if (ts->create_threads) { spin_unlock_bh(&ts->ts_state_lock); goto sleep; } flush_signals(current); if (ts->delay_inactive && (--ts->thread_count == 0)) { spin_unlock_bh(&ts->ts_state_lock); iscsi_del_ts_from_active_list(ts); if (!iscsit_global->in_shutdown) iscsi_deallocate_extra_thread_sets(); iscsi_add_ts_to_inactive_list(ts); spin_lock_bh(&ts->ts_state_lock); } if ((ts->status == ISCSI_THREAD_SET_RESET) && (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) complete(&ts->tx_restart_comp); ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD; spin_unlock_bh(&ts->ts_state_lock); sleep: ret = wait_for_completion_interruptible(&ts->tx_start_comp); if (ret != 0) return NULL; if (iscsi_signal_thread_pre_handler(ts) < 0) return NULL; if (!ts->conn) { pr_err("struct iscsi_thread_set->conn is NULL for " " thread_id: %d, going back to sleep\n", ts->thread_id); goto sleep; } iscsi_check_to_add_additional_sets(); /* * From the TX thread, up the tx_post_start_comp that the RX Thread is * sleeping on in iscsi_rx_thread_pre_handler(), then up the * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on. */ ts->thread_clear |= ISCSI_CLEAR_TX_THREAD; complete(&ts->tx_post_start_comp); complete(&ts->rx_post_start_comp); spin_lock_bh(&ts->ts_state_lock); ts->status = ISCSI_THREAD_SET_ACTIVE; spin_unlock_bh(&ts->ts_state_lock); return ts->conn; }
extern int iscsi_allocate_thread_sets(u32 thread_pair_count) { int allocated_thread_pair_count = 0, i, thread_id; struct iscsi_thread_set *ts = NULL; for (i = 0; i < thread_pair_count; i++) { ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL); if (!ts) { pr_err("Unable to allocate memory for" " thread set.\n"); return allocated_thread_pair_count; } /* * Locate the next available regision in the thread_set_bitmap */ spin_lock(&ts_bitmap_lock); thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap, iscsit_global->ts_bitmap_count, get_order(1)); spin_unlock(&ts_bitmap_lock); if (thread_id < 0) { pr_err("bitmap_find_free_region() failed for" " thread_set_bitmap\n"); kfree(ts); return allocated_thread_pair_count; } ts->thread_id = thread_id; ts->status = ISCSI_THREAD_SET_FREE; INIT_LIST_HEAD(&ts->ts_list); spin_lock_init(&ts->ts_state_lock); init_completion(&ts->rx_post_start_comp); init_completion(&ts->tx_post_start_comp); init_completion(&ts->rx_restart_comp); init_completion(&ts->tx_restart_comp); init_completion(&ts->deferred_restart_comp); init_completion(&ts->rx_start_comp); init_completion(&ts->tx_start_comp); init_completion(&ts->deferred_start_comp); ts->create_threads = 1; ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s-%d", ISCSI_TX_THREAD_NAME, thread_id); if (IS_ERR(ts->tx_thread)) { dump_stack(); pr_err("Unable to start iscsi_target_tx_thread\n"); break; } ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s-%d", ISCSI_RX_THREAD_NAME, thread_id); if (IS_ERR(ts->rx_thread)) { kthread_stop(ts->tx_thread); pr_err("Unable to start iscsi_target_rx_thread\n"); break; } ts->deferred_thread = kthread_run(iscsi_target_deferred_thread, ts, "%s-%d", ISCSI_DEFERRED_THREAD_NAME, thread_id); if (IS_ERR(ts->deferred_thread)) { kthread_stop(ts->rx_thread); kthread_stop(ts->tx_thread); pr_err("Unable to start iscsi_target_deferred_thread\n"); break; } ts->create_threads = 0; iscsi_add_ts_to_inactive_list(ts); allocated_thread_pair_count++; } pr_debug("Spawned %d thread set(s) (%d total threads).\n", allocated_thread_pair_count, allocated_thread_pair_count * 3); return allocated_thread_pair_count; }