diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-09-05 19:13:41 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-09-10 23:23:05 -0400 |
commit | 5ab41ca467546d18dc793195a7c9f8e307311dbf (patch) | |
tree | ef07b8dac736e04c7cfe0b4dd5b51add5aec9e6a | |
parent | d5705c4ab5035be618a34c95505727acac2e70ec (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.c | 139 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_tq.h | 5 |
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 | ||
142 | void iscsi_deallocate_thread_sets(void) | 141 | static 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 | } | 170 | void 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 | ||
224 | void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) | 207 | void 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 | ||
241 | struct iscsi_thread_set *iscsi_get_thread_set(void) | 223 | struct 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 ***/ |