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 | |
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')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 23 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 19 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 18 |
6 files changed, 32 insertions, 35 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); |
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index c8bad675dbd1..1710c12a32c4 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -268,7 +268,7 @@ void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, | |||
268 | strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); | 268 | strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); |
269 | strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); | 269 | strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); |
270 | 270 | ||
271 | rec->u.status.failed = adapter->status_read_failed; | 271 | rec->u.status.failed = atomic_read(&adapter->stat_miss); |
272 | if (status_buffer != NULL) { | 272 | if (status_buffer != NULL) { |
273 | rec->u.status.status_type = status_buffer->status_type; | 273 | rec->u.status.status_type = status_buffer->status_type; |
274 | rec->u.status.status_subtype = status_buffer->status_subtype; | 274 | rec->u.status.status_subtype = status_buffer->status_subtype; |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 306fcd0cae31..adfbbb07448a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -136,7 +136,6 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) | |||
136 | #define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION | 136 | #define ZFCP_QTCB_VERSION FSF_QTCB_CURRENT_VERSION |
137 | /* ATTENTION: value must not be used by hardware */ | 137 | /* ATTENTION: value must not be used by hardware */ |
138 | #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 | 138 | #define FSF_QTCB_UNSOLICITED_STATUS 0x6305 |
139 | #define ZFCP_STATUS_READ_FAILED_THRESHOLD 3 | ||
140 | #define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM | 139 | #define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM |
141 | 140 | ||
142 | /* Do 1st retry in 1 second, then double the timeout for each following retry */ | 141 | /* Do 1st retry in 1 second, then double the timeout for each following retry */ |
@@ -759,7 +758,8 @@ struct zfcp_adapter { | |||
759 | rwlock_t abort_lock; /* Protects against SCSI | 758 | rwlock_t abort_lock; /* Protects against SCSI |
760 | stack abort/command | 759 | stack abort/command |
761 | completion races */ | 760 | completion races */ |
762 | u16 status_read_failed; /* # failed status reads */ | 761 | atomic_t stat_miss; /* # missing status reads*/ |
762 | struct work_struct stat_work; | ||
763 | atomic_t status; /* status of this adapter */ | 763 | atomic_t status; /* status of this adapter */ |
764 | struct list_head erp_ready_head; /* error recovery for this | 764 | struct list_head erp_ready_head; /* error recovery for this |
765 | adapter/devices */ | 765 | adapter/devices */ |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 805484658dd9..55a4fdc42626 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -2139,25 +2139,10 @@ static int | |||
2139 | zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action | 2139 | zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action |
2140 | *erp_action) | 2140 | *erp_action) |
2141 | { | 2141 | { |
2142 | int retval = ZFCP_ERP_SUCCEEDED; | ||
2143 | int temp_ret; | ||
2144 | struct zfcp_adapter *adapter = erp_action->adapter; | 2142 | struct zfcp_adapter *adapter = erp_action->adapter; |
2145 | int i; | ||
2146 | 2143 | ||
2147 | adapter->status_read_failed = 0; | 2144 | atomic_set(&adapter->stat_miss, 16); |
2148 | for (i = 0; i < ZFCP_STATUS_READS_RECOM; i++) { | 2145 | return zfcp_status_read_refill(adapter); |
2149 | temp_ret = zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL); | ||
2150 | if (temp_ret < 0) { | ||
2151 | ZFCP_LOG_INFO("error: set-up of unsolicited status " | ||
2152 | "notification failed on adapter %s\n", | ||
2153 | zfcp_get_busid_by_adapter(adapter)); | ||
2154 | retval = ZFCP_ERP_FAILED; | ||
2155 | i--; | ||
2156 | break; | ||
2157 | } | ||
2158 | } | ||
2159 | |||
2160 | return retval; | ||
2161 | } | 2146 | } |
2162 | 2147 | ||
2163 | /* | 2148 | /* |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 6abf178fda5d..250565794fa5 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -92,6 +92,7 @@ extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long); | |||
92 | extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); | 92 | extern void zfcp_erp_start_timer(struct zfcp_fsf_req *); |
93 | extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); | 93 | extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *); |
94 | extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); | 94 | extern int zfcp_fsf_status_read(struct zfcp_adapter *, int); |
95 | extern int zfcp_status_read_refill(struct zfcp_adapter *adapter); | ||
95 | extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, | 96 | extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, |
96 | unsigned long *, struct zfcp_fsf_req **); | 97 | unsigned long *, struct zfcp_fsf_req **); |
97 | extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, | 98 | extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 1e7136483c1b..b344e8a72f1f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -1029,21 +1029,9 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) | |||
1029 | * FIXME: | 1029 | * FIXME: |
1030 | * allocation failure possible? (Is this code needed?) | 1030 | * allocation failure possible? (Is this code needed?) |
1031 | */ | 1031 | */ |
1032 | retval = zfcp_fsf_status_read(adapter, 0); | 1032 | |
1033 | if (retval < 0) { | 1033 | atomic_inc(&adapter->stat_miss); |
1034 | ZFCP_LOG_INFO("Failed to create unsolicited status read " | 1034 | schedule_work(&adapter->stat_work); |
1035 | "request for the adapter %s.\n", | ||
1036 | zfcp_get_busid_by_adapter(adapter)); | ||
1037 | /* temporary fix to avoid status read buffer shortage */ | ||
1038 | adapter->status_read_failed++; | ||
1039 | if ((ZFCP_STATUS_READS_RECOM - adapter->status_read_failed) | ||
1040 | < ZFCP_STATUS_READ_FAILED_THRESHOLD) { | ||
1041 | ZFCP_LOG_INFO("restart adapter %s due to status read " | ||
1042 | "buffer shortage\n", | ||
1043 | zfcp_get_busid_by_adapter(adapter)); | ||
1044 | zfcp_erp_adapter_reopen(adapter, 0, 103, fsf_req); | ||
1045 | } | ||
1046 | } | ||
1047 | out: | 1035 | out: |
1048 | return retval; | 1036 | return retval; |
1049 | } | 1037 | } |