aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2013-09-05 19:13:41 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2013-09-10 23:23:05 -0400
commit5ab41ca467546d18dc793195a7c9f8e307311dbf (patch)
treeef07b8dac736e04c7cfe0b4dd5b51add5aec9e6a
parentd5705c4ab5035be618a34c95505727acac2e70ec (diff)
iscsi-target: Add thread_set->ts_activate_sem + use common deallocate
This patch removes the iscsi_thread_set->[rx,tx]_post_start_comp that was originally used synchronize startup between rx and tx threads within a single thread_set. Instead, use a single ->ts_activate_sem in iscsi_activate_thread_set() to wait for both processes to awake in the RX/TX pre handlers. Also, go ahead and refactor thread_set deallocate code into a common iscsi_deallocate_thread_one(), and update iscsi_deallocate_thread_sets() and iscsi_deallocate_extra_thread_sets() use this code v3 changes: - Make iscsi_deallocate_thread_one defined as static (Fengguang) v2 changes: - Set ISCSI_THREAD_SET_ACTIVE before calling complete in iscsi_activate_thread_set - Protect ts->conn sanity checks with ->ts_state_lock in RX/TX pre handlers - Add ->ts_activate_sem to save extra context switches per iscsi_activate_thread_set() call. - Refactor thread_set shutdown into iscsi_deallocate_thread_one() Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/iscsi/iscsi_target_tq.c139
-rw-r--r--drivers/target/iscsi/iscsi_target_tq.h5
2 files changed, 59 insertions, 85 deletions
diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c
index 1a5bbec03f3e..ba0ac41889af 100644
--- a/drivers/target/iscsi/iscsi_target_tq.c
+++ b/drivers/target/iscsi/iscsi_target_tq.c
@@ -105,12 +105,11 @@ int iscsi_allocate_thread_sets(u32 thread_pair_count)
105 ts->status = ISCSI_THREAD_SET_FREE; 105 ts->status = ISCSI_THREAD_SET_FREE;
106 INIT_LIST_HEAD(&ts->ts_list); 106 INIT_LIST_HEAD(&ts->ts_list);
107 spin_lock_init(&ts->ts_state_lock); 107 spin_lock_init(&ts->ts_state_lock);
108 init_completion(&ts->rx_post_start_comp);
109 init_completion(&ts->tx_post_start_comp);
110 init_completion(&ts->rx_restart_comp); 108 init_completion(&ts->rx_restart_comp);
111 init_completion(&ts->tx_restart_comp); 109 init_completion(&ts->tx_restart_comp);
112 init_completion(&ts->rx_start_comp); 110 init_completion(&ts->rx_start_comp);
113 init_completion(&ts->tx_start_comp); 111 init_completion(&ts->tx_start_comp);
112 sema_init(&ts->ts_activate_sem, 0);
114 113
115 ts->create_threads = 1; 114 ts->create_threads = 1;
116 ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s", 115 ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s",
@@ -139,35 +138,44 @@ int iscsi_allocate_thread_sets(u32 thread_pair_count)
139 return allocated_thread_pair_count; 138 return allocated_thread_pair_count;
140} 139}
141 140
142void iscsi_deallocate_thread_sets(void) 141static void iscsi_deallocate_thread_one(struct iscsi_thread_set *ts)
143{ 142{
144 u32 released_count = 0; 143 spin_lock_bh(&ts->ts_state_lock);
145 struct iscsi_thread_set *ts = NULL; 144 ts->status = ISCSI_THREAD_SET_DIE;
146
147 while ((ts = iscsi_get_ts_from_inactive_list())) {
148 145
146 if (ts->rx_thread) {
147 complete(&ts->rx_start_comp);
148 spin_unlock_bh(&ts->ts_state_lock);
149 kthread_stop(ts->rx_thread);
149 spin_lock_bh(&ts->ts_state_lock); 150 spin_lock_bh(&ts->ts_state_lock);
150 ts->status = ISCSI_THREAD_SET_DIE; 151 }
152 if (ts->tx_thread) {
153 complete(&ts->tx_start_comp);
151 spin_unlock_bh(&ts->ts_state_lock); 154 spin_unlock_bh(&ts->ts_state_lock);
155 kthread_stop(ts->tx_thread);
156 spin_lock_bh(&ts->ts_state_lock);
157 }
158 spin_unlock_bh(&ts->ts_state_lock);
159 /*
160 * Release this thread_id in the thread_set_bitmap
161 */
162 spin_lock(&ts_bitmap_lock);
163 bitmap_release_region(iscsit_global->ts_bitmap,
164 ts->thread_id, get_order(1));
165 spin_unlock(&ts_bitmap_lock);
152 166
153 if (ts->rx_thread) { 167 kfree(ts);
154 send_sig(SIGINT, ts->rx_thread, 1); 168}
155 kthread_stop(ts->rx_thread); 169
156 } 170void iscsi_deallocate_thread_sets(void)
157 if (ts->tx_thread) { 171{
158 send_sig(SIGINT, ts->tx_thread, 1); 172 struct iscsi_thread_set *ts = NULL;
159 kthread_stop(ts->tx_thread); 173 u32 released_count = 0;
160 }
161 /*
162 * Release this thread_id in the thread_set_bitmap
163 */
164 spin_lock(&ts_bitmap_lock);
165 bitmap_release_region(iscsit_global->ts_bitmap,
166 ts->thread_id, get_order(1));
167 spin_unlock(&ts_bitmap_lock);
168 174
175 while ((ts = iscsi_get_ts_from_inactive_list())) {
176
177 iscsi_deallocate_thread_one(ts);
169 released_count++; 178 released_count++;
170 kfree(ts);
171 } 179 }
172 180
173 if (released_count) 181 if (released_count)
@@ -187,38 +195,13 @@ static void iscsi_deallocate_extra_thread_sets(void)
187 if (!ts) 195 if (!ts)
188 break; 196 break;
189 197
190 spin_lock_bh(&ts->ts_state_lock); 198 iscsi_deallocate_thread_one(ts);
191 ts->status = ISCSI_THREAD_SET_DIE;
192
193 if (ts->rx_thread) {
194 complete(&ts->rx_start_comp);
195 spin_unlock_bh(&ts->ts_state_lock);
196 kthread_stop(ts->rx_thread);
197 spin_lock_bh(&ts->ts_state_lock);
198 }
199 if (ts->tx_thread) {
200 complete(&ts->tx_start_comp);
201 spin_unlock_bh(&ts->ts_state_lock);
202 kthread_stop(ts->tx_thread);
203 spin_lock_bh(&ts->ts_state_lock);
204 }
205 spin_unlock_bh(&ts->ts_state_lock);
206 /*
207 * Release this thread_id in the thread_set_bitmap
208 */
209 spin_lock(&ts_bitmap_lock);
210 bitmap_release_region(iscsit_global->ts_bitmap,
211 ts->thread_id, get_order(1));
212 spin_unlock(&ts_bitmap_lock);
213
214 released_count++; 199 released_count++;
215 kfree(ts);
216 } 200 }
217 201
218 if (released_count) { 202 if (released_count)
219 pr_debug("Stopped %d thread set(s) (%d total threads)." 203 pr_debug("Stopped %d thread set(s) (%d total threads)."
220 "\n", released_count, released_count * 2); 204 "\n", released_count, released_count * 2);
221 }
222} 205}
223 206
224void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) 207void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts)
@@ -228,14 +211,13 @@ void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set
228 spin_lock_bh(&ts->ts_state_lock); 211 spin_lock_bh(&ts->ts_state_lock);
229 conn->thread_set = ts; 212 conn->thread_set = ts;
230 ts->conn = conn; 213 ts->conn = conn;
214 ts->status = ISCSI_THREAD_SET_ACTIVE;
231 spin_unlock_bh(&ts->ts_state_lock); 215 spin_unlock_bh(&ts->ts_state_lock);
232 /* 216
233 * Start up the RX thread and wait on rx_post_start_comp. The RX
234 * Thread will then do the same for the TX Thread in
235 * iscsi_rx_thread_pre_handler().
236 */
237 complete(&ts->rx_start_comp); 217 complete(&ts->rx_start_comp);
238 wait_for_completion(&ts->rx_post_start_comp); 218 complete(&ts->tx_start_comp);
219
220 down(&ts->ts_activate_sem);
239} 221}
240 222
241struct iscsi_thread_set *iscsi_get_thread_set(void) 223struct iscsi_thread_set *iscsi_get_thread_set(void)
@@ -267,6 +249,7 @@ get_set:
267 ts->thread_count = 2; 249 ts->thread_count = 2;
268 init_completion(&ts->rx_restart_comp); 250 init_completion(&ts->rx_restart_comp);
269 init_completion(&ts->tx_restart_comp); 251 init_completion(&ts->tx_restart_comp);
252 sema_init(&ts->ts_activate_sem, 0);
270 253
271 return ts; 254 return ts;
272} 255}
@@ -452,18 +435,19 @@ sleep:
452 if (iscsi_signal_thread_pre_handler(ts) < 0) 435 if (iscsi_signal_thread_pre_handler(ts) < 0)
453 return NULL; 436 return NULL;
454 437
438 iscsi_check_to_add_additional_sets();
439
440 spin_lock_bh(&ts->ts_state_lock);
455 if (!ts->conn) { 441 if (!ts->conn) {
456 pr_err("struct iscsi_thread_set->conn is NULL for" 442 pr_err("struct iscsi_thread_set->conn is NULL for"
457 " thread_id: %d, going back to sleep\n", ts->thread_id); 443 " RX thread_id: %s/%d\n", current->comm, current->pid);
458 goto sleep; 444 spin_unlock_bh(&ts->ts_state_lock);
445 return NULL;
459 } 446 }
460 iscsi_check_to_add_additional_sets();
461 /*
462 * The RX Thread starts up the TX Thread and sleeps.
463 */
464 ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; 447 ts->thread_clear |= ISCSI_CLEAR_RX_THREAD;
465 complete(&ts->tx_start_comp); 448 spin_unlock_bh(&ts->ts_state_lock);
466 wait_for_completion(&ts->tx_post_start_comp); 449
450 up(&ts->ts_activate_sem);
467 451
468 return ts->conn; 452 return ts->conn;
469} 453}
@@ -505,27 +489,20 @@ sleep:
505 if (iscsi_signal_thread_pre_handler(ts) < 0) 489 if (iscsi_signal_thread_pre_handler(ts) < 0)
506 return NULL; 490 return NULL;
507 491
508 if (!ts->conn) {
509 pr_err("struct iscsi_thread_set->conn is NULL for "
510 " thread_id: %d, going back to sleep\n",
511 ts->thread_id);
512 goto sleep;
513 }
514
515 iscsi_check_to_add_additional_sets(); 492 iscsi_check_to_add_additional_sets();
516 /*
517 * From the TX thread, up the tx_post_start_comp that the RX Thread is
518 * sleeping on in iscsi_rx_thread_pre_handler(), then up the
519 * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on.
520 */
521 ts->thread_clear |= ISCSI_CLEAR_TX_THREAD;
522 complete(&ts->tx_post_start_comp);
523 complete(&ts->rx_post_start_comp);
524 493
525 spin_lock_bh(&ts->ts_state_lock); 494 spin_lock_bh(&ts->ts_state_lock);
526 ts->status = ISCSI_THREAD_SET_ACTIVE; 495 if (!ts->conn) {
496 pr_err("struct iscsi_thread_set->conn is NULL for"
497 " TX thread_id: %s/%d\n", current->comm, current->pid);
498 spin_unlock_bh(&ts->ts_state_lock);
499 return NULL;
500 }
501 ts->thread_clear |= ISCSI_CLEAR_TX_THREAD;
527 spin_unlock_bh(&ts->ts_state_lock); 502 spin_unlock_bh(&ts->ts_state_lock);
528 503
504 up(&ts->ts_activate_sem);
505
529 return ts->conn; 506 return ts->conn;
530} 507}
531 508
diff --git a/drivers/target/iscsi/iscsi_target_tq.h b/drivers/target/iscsi/iscsi_target_tq.h
index 547d11831282..cc1eede5ab3a 100644
--- a/drivers/target/iscsi/iscsi_target_tq.h
+++ b/drivers/target/iscsi/iscsi_target_tq.h
@@ -64,10 +64,6 @@ struct iscsi_thread_set {
64 struct iscsi_conn *conn; 64 struct iscsi_conn *conn;
65 /* used for controlling ts state accesses */ 65 /* used for controlling ts state accesses */
66 spinlock_t ts_state_lock; 66 spinlock_t ts_state_lock;
67 /* Used for rx side post startup */
68 struct completion rx_post_start_comp;
69 /* Used for tx side post startup */
70 struct completion tx_post_start_comp;
71 /* used for restarting thread queue */ 67 /* used for restarting thread queue */
72 struct completion rx_restart_comp; 68 struct completion rx_restart_comp;
73 /* used for restarting thread queue */ 69 /* used for restarting thread queue */
@@ -82,6 +78,7 @@ struct iscsi_thread_set {
82 struct task_struct *tx_thread; 78 struct task_struct *tx_thread;
83 /* struct iscsi_thread_set in list list head*/ 79 /* struct iscsi_thread_set in list list head*/
84 struct list_head ts_list; 80 struct list_head ts_list;
81 struct semaphore ts_activate_sem;
85}; 82};
86 83
87#endif /*** ISCSI_THREAD_QUEUE_H ***/ 84#endif /*** ISCSI_THREAD_QUEUE_H ***/