diff options
author | Swen Schillig <swen@vnet.ibm.com> | 2008-05-19 06:17:37 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-06-05 10:27:13 -0400 |
commit | d26ab06ede83287f99067fee3034c5455a75faf9 (patch) | |
tree | 6070ae50cded8086ceab61092348790b39876146 /drivers/s390/scsi/zfcp_aux.c | |
parent | 15424921222f2bed0aa92ef1e8bc94f753d2c6ea (diff) |
[SCSI] zfcp: receiving an unsolicted status can lead to I/O stall
Processing of an unsolicted status request can lead to a locking race
of the request_queue's queue_lock during the recreation of the
used up status read request while still in interrupt context
of the response handler.
Detaching the 'refill' of the long running status read requests from
the handler to a scheduled work is solving this issue.
In addition, each refill-run is trying to re-establish the full amount
of status read requests, which might have failed in earlier runs.
Signed-off-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390/scsi/zfcp_aux.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index d23027a2f2f0..41635b13ccb1 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -970,6 +970,27 @@ static void zfcp_dummy_release(struct device *dev) | |||
970 | return; | 970 | return; |
971 | } | 971 | } |
972 | 972 | ||
973 | int zfcp_status_read_refill(struct zfcp_adapter *adapter) | ||
974 | { | ||
975 | while (atomic_read(&adapter->stat_miss) > 0) | ||
976 | if (zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL)) | ||
977 | break; | ||
978 | else | ||
979 | atomic_dec(&adapter->stat_miss); | ||
980 | |||
981 | if (ZFCP_STATUS_READS_RECOM <= atomic_read(&adapter->stat_miss)) { | ||
982 | zfcp_erp_adapter_reopen(adapter, 0, 103, NULL); | ||
983 | return 1; | ||
984 | } | ||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | static void _zfcp_status_read_scheduler(struct work_struct *work) | ||
989 | { | ||
990 | zfcp_status_read_refill(container_of(work, struct zfcp_adapter, | ||
991 | stat_work)); | ||
992 | } | ||
993 | |||
973 | /* | 994 | /* |
974 | * Enqueues an adapter at the end of the adapter list in the driver data. | 995 | * Enqueues an adapter at the end of the adapter list in the driver data. |
975 | * All adapter internal structures are set up. | 996 | * All adapter internal structures are set up. |
@@ -1063,6 +1084,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
1063 | 1084 | ||
1064 | /* initialize lock of associated request queue */ | 1085 | /* initialize lock of associated request queue */ |
1065 | rwlock_init(&adapter->request_queue.queue_lock); | 1086 | rwlock_init(&adapter->request_queue.queue_lock); |
1087 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | ||
1066 | 1088 | ||
1067 | /* mark adapter unusable as long as sysfs registration is not complete */ | 1089 | /* mark adapter unusable as long as sysfs registration is not complete */ |
1068 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 1090 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
@@ -1123,6 +1145,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
1123 | int retval = 0; | 1145 | int retval = 0; |
1124 | unsigned long flags; | 1146 | unsigned long flags; |
1125 | 1147 | ||
1148 | cancel_work_sync(&adapter->stat_work); | ||
1126 | zfcp_adapter_scsi_unregister(adapter); | 1149 | zfcp_adapter_scsi_unregister(adapter); |
1127 | device_unregister(&adapter->generic_services); | 1150 | device_unregister(&adapter->generic_services); |
1128 | zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); | 1151 | zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); |