summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2007-05-08 11:17:54 +0200
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-05-08 18:56:50 +0200
commitca2d02c2f9ea476062ae181eec60b8bcd97857d6 (patch)
treedffe33856db601a173a117263b9ee4799d555ac6
parent[SCSI] zfcp: Fix deadlock between zfcp ERP and SCSI (diff)
downloadlinux-ca2d02c2f9ea476062ae181eec60b8bcd97857d6.tar.xz
linux-ca2d02c2f9ea476062ae181eec60b8bcd97857d6.zip
[SCSI] zfcp: rework request ID management.
Simplify request ID management and make sure that frequently used functions are inlined. Also fix a memory leak in zfcp_adapter_enqueue() which only gets hit in error handling. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/s390/scsi/zfcp_aux.c82
-rw-r--r--drivers/s390/scsi/zfcp_def.h36
-rw-r--r--drivers/s390/scsi/zfcp_erp.c3
-rw-r--r--drivers/s390/scsi/zfcp_ext.h4
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c17
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c4
7 files changed, 59 insertions, 89 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 49d5fc729bef..324899c96efe 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -118,97 +118,32 @@ _zfcp_hex_dump(char *addr, int count)
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF
-static int zfcp_reqlist_init(struct zfcp_adapter *adapter)
+static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)
{
- int i;
+ int idx;
adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
GFP_KERNEL);
-
if (!adapter->req_list)
return -ENOMEM;
- for (i=0; i<REQUEST_LIST_SIZE; i++)
- INIT_LIST_HEAD(&adapter->req_list[i]);
-
+ for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+ INIT_LIST_HEAD(&adapter->req_list[idx]);
return 0;
}
static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
{
- struct zfcp_fsf_req *request, *tmp;
- unsigned int i;
-
- for (i=0; i<REQUEST_LIST_SIZE; i++) {
- if (list_empty(&adapter->req_list[i]))
- continue;
-
- list_for_each_entry_safe(request, tmp,
- &adapter->req_list[i], list)
- list_del(&request->list);
- }
-
kfree(adapter->req_list);
}
-void zfcp_reqlist_add(struct zfcp_adapter *adapter,
- struct zfcp_fsf_req *fsf_req)
-{
- unsigned int i;
-
- i = fsf_req->req_id % REQUEST_LIST_SIZE;
- list_add_tail(&fsf_req->list, &adapter->req_list[i]);
-}
-
-void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id)
-{
- struct zfcp_fsf_req *request, *tmp;
- unsigned int i, counter;
- u64 dbg_tmp[2];
-
- i = req_id % REQUEST_LIST_SIZE;
- BUG_ON(list_empty(&adapter->req_list[i]));
-
- counter = 0;
- list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) {
- if (request->req_id == req_id) {
- dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active);
- dbg_tmp[1] = (u64) counter;
- debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
- list_del(&request->list);
- break;
- }
- counter++;
- }
-}
-
-struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter,
- unsigned long req_id)
-{
- struct zfcp_fsf_req *request, *tmp;
- unsigned int i;
-
- /* 0 is reserved as an invalid req_id */
- if (req_id == 0)
- return NULL;
-
- i = req_id % REQUEST_LIST_SIZE;
-
- list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list)
- if (request->req_id == req_id)
- return request;
-
- return NULL;
-}
-
int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
{
- unsigned int i;
+ unsigned int idx;
- for (i=0; i<REQUEST_LIST_SIZE; i++)
- if (!list_empty(&adapter->req_list[i]))
+ for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+ if (!list_empty(&adapter->req_list[idx]))
return 0;
-
return 1;
}
@@ -1106,7 +1041,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* initialize list of fsf requests */
spin_lock_init(&adapter->req_list_lock);
- retval = zfcp_reqlist_init(adapter);
+ retval = zfcp_reqlist_alloc(adapter);
if (retval) {
ZFCP_LOG_INFO("request list initialization failed\n");
goto failed_low_mem_buffers;
@@ -1167,6 +1102,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
sysfs_failed:
dev_set_drvdata(&ccw_device->dev, NULL);
+ zfcp_reqlist_free(adapter);
failed_low_mem_buffers:
zfcp_free_low_mem_buffers(adapter);
if (qdio_free(ccw_device) != 0)
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 07b0957b82f3..22649639230b 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -1090,6 +1090,42 @@ extern void _zfcp_hex_dump(char *, int);
#define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port))
/*
+ * Helper functions for request ID management.
+ */
+static inline int zfcp_reqlist_hash(unsigned long req_id)
+{
+ return req_id % REQUEST_LIST_SIZE;
+}
+
+static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter,
+ struct zfcp_fsf_req *fsf_req)
+{
+ unsigned int idx;
+
+ idx = zfcp_reqlist_hash(fsf_req->req_id);
+ list_add_tail(&fsf_req->list, &adapter->req_list[idx]);
+}
+
+static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter,
+ struct zfcp_fsf_req *fsf_req)
+{
+ list_del(&fsf_req->list);
+}
+
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
+{
+ struct zfcp_fsf_req *request;
+ unsigned int idx;
+
+ idx = zfcp_reqlist_hash(req_id);
+ list_for_each_entry(request, &adapter->req_list[idx], list)
+ if (request->req_id == req_id)
+ return request;
+ return NULL;
+}
+
+/*
* functions needed for reference/usage counting
*/
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 885572300589..e2a3d6fe1651 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -847,8 +847,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
if (erp_action->fsf_req) {
/* take lock to ensure that request is not deleted meanwhile */
spin_lock(&adapter->req_list_lock);
- if (zfcp_reqlist_ismember(adapter,
- erp_action->fsf_req->req_id)) {
+ if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
/* fsf_req still exists */
debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 01386ac688a2..991d45667a44 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -184,10 +184,6 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
unsigned long);
extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
struct scsi_cmnd *);
-extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *);
-extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long);
-extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *,
- unsigned long);
extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
#endif /* ZFCP_EXT_H */
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 07094c3dc341..083308b1d3e2 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -4787,7 +4787,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
retval = -EIO;
del_timer(&fsf_req->timer);
spin_lock(&adapter->req_list_lock);
- zfcp_reqlist_remove(adapter, fsf_req->req_id);
+ zfcp_reqlist_remove(adapter, fsf_req);
spin_unlock(&adapter->req_list_lock);
/* undo changes in request queue made for this request */
zfcp_qdio_zero_sbals(req_queue->buffer,
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index e50e6ad4e6cb..cb08ca3cc0f9 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -283,7 +283,7 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
}
/**
- * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status
+ * zfcp_qdio_reqid_check - checks for valid reqids.
*/
static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
unsigned long req_id)
@@ -294,14 +294,17 @@ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
debug_long_event(adapter->erp_dbf, 4, req_id);
spin_lock_irqsave(&adapter->req_list_lock, flags);
- fsf_req = zfcp_reqlist_ismember(adapter, req_id);
+ fsf_req = zfcp_reqlist_find(adapter, req_id);
- if (!fsf_req) {
- spin_unlock_irqrestore(&adapter->req_list_lock, flags);
- panic("error: unknown request id (%ld).\n", req_id);
- }
+ if (!fsf_req)
+ /*
+ * Unknown request means that we have potentially memory
+ * corruption and must stop the machine immediatly.
+ */
+ panic("error: unknown request id (%ld) on adapter %s.\n",
+ req_id, zfcp_get_busid_by_adapter(adapter));
- zfcp_reqlist_remove(adapter, req_id);
+ zfcp_reqlist_remove(adapter, fsf_req);
atomic_dec(&adapter->reqs_active);
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index e742b3de16ac..16e2d64658af 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -407,8 +407,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
/* Check whether corresponding fsf_req is still pending */
spin_lock(&adapter->req_list_lock);
- fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long)
- scpnt->host_scribble);
+ fsf_req = zfcp_reqlist_find(adapter,
+ (unsigned long) scpnt->host_scribble);
spin_unlock(&adapter->req_list_lock);
if (!fsf_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);