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; }