diff options
author | Andreas Herrmann <aherrman@de.ibm.com> | 2005-06-13 07:20:35 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-06-13 22:32:48 -0400 |
commit | 1db2c9c0931a53fe013db55fd2ff58859db31e8d (patch) | |
tree | 1134627ac98d91896dcdb161d5df7ecef60a4de3 /drivers/s390/scsi/zfcp_fsf.c | |
parent | 64b29a130901d5b8578e9f602cf2dae56aaff224 (diff) |
[SCSI] zfcp: fix bug during adapter shutdown
Fixes a race between zfcp_fsf_req_dismiss_all and
zfcp_qdio_reqid_check. During adapter shutdown it occurred that a
request was cleaned up twice. First during its normal
completion. Second when dismiss_all was called. The fix is to
serialize access to fsf request list between zfcp_fsf_req_dismiss_all
and zfcp_qdio_reqid_check and delete a fsf request from the list if
its completion is triggered. (Additionally a rwlock was replaced by a
spinlock and fsf_req_cleanup was eliminated.)
Signed-off-by: Andreas Herrmann <aherrman@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/s390/scsi/zfcp_fsf.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 79 |
1 files changed, 22 insertions, 57 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 21a6d7633475..56b2ea97da1f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -61,7 +61,6 @@ static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *); | |||
61 | static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); | 61 | static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); |
62 | static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); | 62 | static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); |
63 | static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *); | 63 | static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *); |
64 | static void zfcp_fsf_req_free(struct zfcp_fsf_req *); | ||
65 | 64 | ||
66 | /* association between FSF command and FSF QTCB type */ | 65 | /* association between FSF command and FSF QTCB type */ |
67 | static u32 fsf_qtcb_type[] = { | 66 | static u32 fsf_qtcb_type[] = { |
@@ -149,13 +148,13 @@ zfcp_fsf_req_alloc(mempool_t *pool, int req_flags) | |||
149 | * | 148 | * |
150 | * locks: none | 149 | * locks: none |
151 | */ | 150 | */ |
152 | static void | 151 | void |
153 | zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) | 152 | zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) |
154 | { | 153 | { |
155 | if (likely(fsf_req->pool != NULL)) | 154 | if (likely(fsf_req->pool != NULL)) |
156 | mempool_free(fsf_req, fsf_req->pool); | 155 | mempool_free(fsf_req, fsf_req->pool); |
157 | else | 156 | else |
158 | kfree(fsf_req); | 157 | kfree(fsf_req); |
159 | } | 158 | } |
160 | 159 | ||
161 | /* | 160 | /* |
@@ -170,30 +169,21 @@ zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) | |||
170 | int | 169 | int |
171 | zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) | 170 | zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) |
172 | { | 171 | { |
173 | int retval = 0; | ||
174 | struct zfcp_fsf_req *fsf_req, *tmp; | 172 | struct zfcp_fsf_req *fsf_req, *tmp; |
173 | unsigned long flags; | ||
174 | LIST_HEAD(remove_queue); | ||
175 | 175 | ||
176 | list_for_each_entry_safe(fsf_req, tmp, &adapter->fsf_req_list_head, | 176 | spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); |
177 | list) | 177 | list_splice_init(&adapter->fsf_req_list_head, &remove_queue); |
178 | zfcp_fsf_req_dismiss(fsf_req); | 178 | atomic_set(&adapter->fsf_reqs_active, 0); |
179 | /* wait_event_timeout? */ | 179 | spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); |
180 | while (!list_empty(&adapter->fsf_req_list_head)) { | ||
181 | ZFCP_LOG_DEBUG("fsf req list of adapter %s not yet empty\n", | ||
182 | zfcp_get_busid_by_adapter(adapter)); | ||
183 | /* wait for woken intiators to clean up their requests */ | ||
184 | msleep(jiffies_to_msecs(ZFCP_FSFREQ_CLEANUP_TIMEOUT)); | ||
185 | } | ||
186 | 180 | ||
187 | /* consistency check */ | 181 | list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) { |
188 | if (atomic_read(&adapter->fsf_reqs_active)) { | 182 | list_del(&fsf_req->list); |
189 | ZFCP_LOG_NORMAL("bug: There are still %d FSF requests pending " | 183 | zfcp_fsf_req_dismiss(fsf_req); |
190 | "on adapter %s after cleanup.\n", | ||
191 | atomic_read(&adapter->fsf_reqs_active), | ||
192 | zfcp_get_busid_by_adapter(adapter)); | ||
193 | atomic_set(&adapter->fsf_reqs_active, 0); | ||
194 | } | 184 | } |
195 | 185 | ||
196 | return retval; | 186 | return 0; |
197 | } | 187 | } |
198 | 188 | ||
199 | /* | 189 | /* |
@@ -226,10 +216,6 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) | |||
226 | { | 216 | { |
227 | int retval = 0; | 217 | int retval = 0; |
228 | int cleanup; | 218 | int cleanup; |
229 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
230 | |||
231 | /* do some statistics */ | ||
232 | atomic_dec(&adapter->fsf_reqs_active); | ||
233 | 219 | ||
234 | if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { | 220 | if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { |
235 | ZFCP_LOG_DEBUG("Status read response received\n"); | 221 | ZFCP_LOG_DEBUG("Status read response received\n"); |
@@ -260,7 +246,7 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req) | |||
260 | * lock must not be held here since it will be | 246 | * lock must not be held here since it will be |
261 | * grabed by the called routine, too | 247 | * grabed by the called routine, too |
262 | */ | 248 | */ |
263 | zfcp_fsf_req_cleanup(fsf_req); | 249 | zfcp_fsf_req_free(fsf_req); |
264 | } else { | 250 | } else { |
265 | /* notify initiator waiting for the requests completion */ | 251 | /* notify initiator waiting for the requests completion */ |
266 | ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req); | 252 | ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req); |
@@ -936,7 +922,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) | |||
936 | 922 | ||
937 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { | 923 | if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { |
938 | mempool_free(status_buffer, adapter->pool.data_status_read); | 924 | mempool_free(status_buffer, adapter->pool.data_status_read); |
939 | zfcp_fsf_req_cleanup(fsf_req); | 925 | zfcp_fsf_req_free(fsf_req); |
940 | goto out; | 926 | goto out; |
941 | } | 927 | } |
942 | 928 | ||
@@ -1033,7 +1019,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) | |||
1033 | break; | 1019 | break; |
1034 | } | 1020 | } |
1035 | mempool_free(status_buffer, adapter->pool.data_status_read); | 1021 | mempool_free(status_buffer, adapter->pool.data_status_read); |
1036 | zfcp_fsf_req_cleanup(fsf_req); | 1022 | zfcp_fsf_req_free(fsf_req); |
1037 | /* | 1023 | /* |
1038 | * recycle buffer and start new request repeat until outbound | 1024 | * recycle buffer and start new request repeat until outbound |
1039 | * queue is empty or adapter shutdown is requested | 1025 | * queue is empty or adapter shutdown is requested |
@@ -2258,7 +2244,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter, | |||
2258 | wait_event(fsf_req->completion_wq, | 2244 | wait_event(fsf_req->completion_wq, |
2259 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); | 2245 | fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); |
2260 | del_timer_sync(timer); | 2246 | del_timer_sync(timer); |
2261 | zfcp_fsf_req_cleanup(fsf_req); | 2247 | zfcp_fsf_req_free(fsf_req); |
2262 | out: | 2248 | out: |
2263 | kfree(timer); | 2249 | kfree(timer); |
2264 | return retval; | 2250 | return retval; |
@@ -4607,7 +4593,7 @@ zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *fsf_req, | |||
4607 | *status = fsf_req->status; | 4593 | *status = fsf_req->status; |
4608 | 4594 | ||
4609 | /* cleanup request */ | 4595 | /* cleanup request */ |
4610 | zfcp_fsf_req_cleanup(fsf_req); | 4596 | zfcp_fsf_req_free(fsf_req); |
4611 | out: | 4597 | out: |
4612 | return retval; | 4598 | return retval; |
4613 | } | 4599 | } |
@@ -4806,9 +4792,9 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) | |||
4806 | inc_seq_no = 0; | 4792 | inc_seq_no = 0; |
4807 | 4793 | ||
4808 | /* put allocated FSF request at list tail */ | 4794 | /* put allocated FSF request at list tail */ |
4809 | write_lock_irqsave(&adapter->fsf_req_list_lock, flags); | 4795 | spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); |
4810 | list_add_tail(&fsf_req->list, &adapter->fsf_req_list_head); | 4796 | list_add_tail(&fsf_req->list, &adapter->fsf_req_list_head); |
4811 | write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); | 4797 | spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); |
4812 | 4798 | ||
4813 | /* figure out expiration time of timeout and start timeout */ | 4799 | /* figure out expiration time of timeout and start timeout */ |
4814 | if (unlikely(timer)) { | 4800 | if (unlikely(timer)) { |
@@ -4852,9 +4838,9 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) | |||
4852 | */ | 4838 | */ |
4853 | if (timer) | 4839 | if (timer) |
4854 | del_timer(timer); | 4840 | del_timer(timer); |
4855 | write_lock_irqsave(&adapter->fsf_req_list_lock, flags); | 4841 | spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); |
4856 | list_del(&fsf_req->list); | 4842 | list_del(&fsf_req->list); |
4857 | write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); | 4843 | spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); |
4858 | /* | 4844 | /* |
4859 | * adjust the number of free SBALs in request queue as well as | 4845 | * adjust the number of free SBALs in request queue as well as |
4860 | * position of first one | 4846 | * position of first one |
@@ -4892,25 +4878,4 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) | |||
4892 | return retval; | 4878 | return retval; |
4893 | } | 4879 | } |
4894 | 4880 | ||
4895 | /* | ||
4896 | * function: zfcp_fsf_req_cleanup | ||
4897 | * | ||
4898 | * purpose: cleans up an FSF request and removes it from the specified list | ||
4899 | * | ||
4900 | * returns: | ||
4901 | * | ||
4902 | * assumption: no pending SB in SBALEs other than QTCB | ||
4903 | */ | ||
4904 | void | ||
4905 | zfcp_fsf_req_cleanup(struct zfcp_fsf_req *fsf_req) | ||
4906 | { | ||
4907 | struct zfcp_adapter *adapter = fsf_req->adapter; | ||
4908 | unsigned long flags; | ||
4909 | |||
4910 | write_lock_irqsave(&adapter->fsf_req_list_lock, flags); | ||
4911 | list_del(&fsf_req->list); | ||
4912 | write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); | ||
4913 | zfcp_fsf_req_free(fsf_req); | ||
4914 | } | ||
4915 | |||
4916 | #undef ZFCP_LOG_AREA | 4881 | #undef ZFCP_LOG_AREA |