Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Andreas Herrmann and committed by
James Bottomley
1db2c9c0 64b29a13

+46 -81
+4 -4
drivers/s390/scsi/zfcp_aux.c
··· 520 520 521 521 out: 522 522 if (fsf_req != NULL) 523 - zfcp_fsf_req_cleanup(fsf_req); 523 + zfcp_fsf_req_free(fsf_req); 524 524 525 525 if ((adapter != NULL) && (retval != -ENXIO)) 526 526 zfcp_adapter_put(adapter); ··· 1149 1149 INIT_LIST_HEAD(&adapter->port_remove_lh); 1150 1150 1151 1151 /* initialize list of fsf requests */ 1152 - rwlock_init(&adapter->fsf_req_list_lock); 1152 + spin_lock_init(&adapter->fsf_req_list_lock); 1153 1153 INIT_LIST_HEAD(&adapter->fsf_req_list_head); 1154 1154 1155 1155 /* initialize abort lock */ ··· 1234 1234 zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); 1235 1235 dev_set_drvdata(&adapter->ccw_device->dev, NULL); 1236 1236 /* sanity check: no pending FSF requests */ 1237 - read_lock_irqsave(&adapter->fsf_req_list_lock, flags); 1237 + spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); 1238 1238 retval = !list_empty(&adapter->fsf_req_list_head); 1239 - read_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); 1239 + spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); 1240 1240 if (retval) { 1241 1241 ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, " 1242 1242 "%i requests outstanding\n",
+1 -1
drivers/s390/scsi/zfcp_def.h
··· 861 861 u32 ports; /* number of remote ports */ 862 862 struct timer_list scsi_er_timer; /* SCSI err recovery watch */ 863 863 struct list_head fsf_req_list_head; /* head of FSF req list */ 864 - rwlock_t fsf_req_list_lock; /* lock for ops on list of 864 + spinlock_t fsf_req_list_lock; /* lock for ops on list of 865 865 FSF requests */ 866 866 atomic_t fsf_reqs_active; /* # active FSF reqs */ 867 867 struct zfcp_qdio_queue request_queue; /* request queue */
+2 -2
drivers/s390/scsi/zfcp_erp.c
··· 891 891 892 892 if (erp_action->fsf_req) { 893 893 /* take lock to ensure that request is not being deleted meanwhile */ 894 - write_lock(&adapter->fsf_req_list_lock); 894 + spin_lock(&adapter->fsf_req_list_lock); 895 895 /* check whether fsf req does still exist */ 896 896 list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list) 897 897 if (fsf_req == erp_action->fsf_req) ··· 934 934 */ 935 935 erp_action->fsf_req = NULL; 936 936 } 937 - write_unlock(&adapter->fsf_req_list_lock); 937 + spin_unlock(&adapter->fsf_req_list_lock); 938 938 } else 939 939 debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq"); 940 940
+1 -1
drivers/s390/scsi/zfcp_ext.h
··· 116 116 struct timer_list*, int); 117 117 extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *); 118 118 extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *); 119 - extern void zfcp_fsf_req_cleanup(struct zfcp_fsf_req *); 119 + extern void zfcp_fsf_req_free(struct zfcp_fsf_req *); 120 120 extern struct zfcp_fsf_req *zfcp_fsf_send_fcp_command_task_management( 121 121 struct zfcp_adapter *, struct zfcp_unit *, u8, int); 122 122 extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(
+23 -58
drivers/s390/scsi/zfcp_fsf.c
··· 61 61 static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); 62 62 static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); 63 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 65 /* association between FSF command and FSF QTCB type */ 67 66 static u32 fsf_qtcb_type[] = { ··· 148 149 * 149 150 * locks: none 150 151 */ 151 - static void 152 + void 152 153 zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req) 153 154 { 154 155 if (likely(fsf_req->pool != NULL)) 155 156 mempool_free(fsf_req, fsf_req->pool); 156 - else 157 - kfree(fsf_req); 157 + else 158 + kfree(fsf_req); 158 159 } 159 160 160 161 /* ··· 169 170 int 170 171 zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) 171 172 { 172 - int retval = 0; 173 173 struct zfcp_fsf_req *fsf_req, *tmp; 174 + unsigned long flags; 175 + LIST_HEAD(remove_queue); 174 176 175 - list_for_each_entry_safe(fsf_req, tmp, &adapter->fsf_req_list_head, 176 - list) 177 - zfcp_fsf_req_dismiss(fsf_req); 178 - /* wait_event_timeout? */ 179 - while (!list_empty(&adapter->fsf_req_list_head)) { 180 - ZFCP_LOG_DEBUG("fsf req list of adapter %s not yet empty\n", 181 - zfcp_get_busid_by_adapter(adapter)); 182 - /* wait for woken intiators to clean up their requests */ 183 - msleep(jiffies_to_msecs(ZFCP_FSFREQ_CLEANUP_TIMEOUT)); 177 + spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); 178 + list_splice_init(&adapter->fsf_req_list_head, &remove_queue); 179 + atomic_set(&adapter->fsf_reqs_active, 0); 180 + spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); 181 + 182 + list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) { 183 + list_del(&fsf_req->list); 184 + zfcp_fsf_req_dismiss(fsf_req); 184 185 } 185 186 186 - /* consistency check */ 187 - if (atomic_read(&adapter->fsf_reqs_active)) { 188 - ZFCP_LOG_NORMAL("bug: There are still %d FSF requests pending " 189 - "on adapter %s after cleanup.\n", 190 - atomic_read(&adapter->fsf_reqs_active), 191 - zfcp_get_busid_by_adapter(adapter)); 192 - atomic_set(&adapter->fsf_reqs_active, 0); 193 - } 194 - 195 - return retval; 187 + return 0; 196 188 } 197 189 198 190 /* ··· 216 226 { 217 227 int retval = 0; 218 228 int cleanup; 219 - struct zfcp_adapter *adapter = fsf_req->adapter; 220 - 221 - /* do some statistics */ 222 - atomic_dec(&adapter->fsf_reqs_active); 223 229 224 230 if (unlikely(fsf_req->fsf_command == FSF_QTCB_UNSOLICITED_STATUS)) { 225 231 ZFCP_LOG_DEBUG("Status read response received\n"); ··· 246 260 * lock must not be held here since it will be 247 261 * grabed by the called routine, too 248 262 */ 249 - zfcp_fsf_req_cleanup(fsf_req); 263 + zfcp_fsf_req_free(fsf_req); 250 264 } else { 251 265 /* notify initiator waiting for the requests completion */ 252 266 ZFCP_LOG_TRACE("waking initiator of FSF request %p\n",fsf_req); ··· 922 936 923 937 if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { 924 938 mempool_free(status_buffer, adapter->pool.data_status_read); 925 - zfcp_fsf_req_cleanup(fsf_req); 939 + zfcp_fsf_req_free(fsf_req); 926 940 goto out; 927 941 } 928 942 ··· 1019 1033 break; 1020 1034 } 1021 1035 mempool_free(status_buffer, adapter->pool.data_status_read); 1022 - zfcp_fsf_req_cleanup(fsf_req); 1036 + zfcp_fsf_req_free(fsf_req); 1023 1037 /* 1024 1038 * recycle buffer and start new request repeat until outbound 1025 1039 * queue is empty or adapter shutdown is requested ··· 2244 2258 wait_event(fsf_req->completion_wq, 2245 2259 fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); 2246 2260 del_timer_sync(timer); 2247 - zfcp_fsf_req_cleanup(fsf_req); 2261 + zfcp_fsf_req_free(fsf_req); 2248 2262 out: 2249 2263 kfree(timer); 2250 2264 return retval; ··· 4593 4607 *status = fsf_req->status; 4594 4608 4595 4609 /* cleanup request */ 4596 - zfcp_fsf_req_cleanup(fsf_req); 4610 + zfcp_fsf_req_free(fsf_req); 4597 4611 out: 4598 4612 return retval; 4599 4613 } ··· 4792 4806 inc_seq_no = 0; 4793 4807 4794 4808 /* put allocated FSF request at list tail */ 4795 - write_lock_irqsave(&adapter->fsf_req_list_lock, flags); 4809 + spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); 4796 4810 list_add_tail(&fsf_req->list, &adapter->fsf_req_list_head); 4797 - write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); 4811 + spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); 4798 4812 4799 4813 /* figure out expiration time of timeout and start timeout */ 4800 4814 if (unlikely(timer)) { ··· 4838 4852 */ 4839 4853 if (timer) 4840 4854 del_timer(timer); 4841 - write_lock_irqsave(&adapter->fsf_req_list_lock, flags); 4855 + spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); 4842 4856 list_del(&fsf_req->list); 4843 - write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); 4857 + spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); 4844 4858 /* 4845 4859 * adjust the number of free SBALs in request queue as well as 4846 4860 * position of first one ··· 4876 4890 atomic_inc(&adapter->fsf_reqs_active); 4877 4891 } 4878 4892 return retval; 4879 - } 4880 - 4881 - /* 4882 - * function: zfcp_fsf_req_cleanup 4883 - * 4884 - * purpose: cleans up an FSF request and removes it from the specified list 4885 - * 4886 - * returns: 4887 - * 4888 - * assumption: no pending SB in SBALEs other than QTCB 4889 - */ 4890 - void 4891 - zfcp_fsf_req_cleanup(struct zfcp_fsf_req *fsf_req) 4892 - { 4893 - struct zfcp_adapter *adapter = fsf_req->adapter; 4894 - unsigned long flags; 4895 - 4896 - write_lock_irqsave(&adapter->fsf_req_list_lock, flags); 4897 - list_del(&fsf_req->list); 4898 - write_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); 4899 - zfcp_fsf_req_free(fsf_req); 4900 4893 } 4901 4894 4902 4895 #undef ZFCP_LOG_AREA
+14 -14
drivers/s390/scsi/zfcp_qdio.c
··· 446 446 zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) 447 447 { 448 448 struct zfcp_fsf_req *fsf_req; 449 - int retval = 0; 450 449 451 450 /* invalid (per convention used in this driver) */ 452 451 if (unlikely(!sbale_addr)) { 453 452 ZFCP_LOG_NORMAL("bug: invalid reqid\n"); 454 - retval = -EINVAL; 455 - goto out; 453 + return -EINVAL; 456 454 } 457 455 458 456 /* valid request id and thus (hopefully :) valid fsf_req address */ 459 457 fsf_req = (struct zfcp_fsf_req *) sbale_addr; 460 458 459 + /* serialize with zfcp_fsf_req_dismiss_all */ 460 + spin_lock(&adapter->fsf_req_list_lock); 461 + if (list_empty(&adapter->fsf_req_list_head)) { 462 + spin_unlock(&adapter->fsf_req_list_lock); 463 + return 0; 464 + } 465 + list_del(&fsf_req->list); 466 + atomic_dec(&adapter->fsf_reqs_active); 467 + spin_unlock(&adapter->fsf_req_list_lock); 468 + 461 469 if (unlikely(adapter != fsf_req->adapter)) { 462 470 ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, " 463 471 "fsf_req->adapter=%p, adapter=%p)\n", 464 472 fsf_req, fsf_req->adapter, adapter); 465 - retval = -EINVAL; 466 - goto out; 467 - } 468 - 469 - ZFCP_LOG_TRACE("fsf_req at %p, QTCB at %p\n", fsf_req, fsf_req->qtcb); 470 - if (likely(fsf_req->qtcb)) { 471 - ZFCP_LOG_TRACE("hex dump of QTCB:\n"); 472 - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb, 473 - sizeof(struct fsf_qtcb)); 473 + return -EINVAL; 474 474 } 475 475 476 476 /* finish the FSF request */ 477 477 zfcp_fsf_req_complete(fsf_req); 478 - out: 479 - return retval; 478 + 479 + return 0; 480 480 } 481 481 482 482 /**
+1 -1
drivers/s390/scsi/zfcp_scsi.c
··· 575 575 *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[0]; 576 576 dbf_fsf_qual[1] = 577 577 *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[2]; 578 - zfcp_fsf_req_cleanup(new_fsf_req); 578 + zfcp_fsf_req_free(new_fsf_req); 579 579 #else 580 580 retval = zfcp_fsf_req_wait_and_cleanup(new_fsf_req, 581 581 ZFCP_UNINTERRUPTIBLE, &status);