[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>
This commit is contained in:
Родитель
5f852be9e1
Коммит
ca2d02c2f9
|
@ -118,97 +118,32 @@ _zfcp_hex_dump(char *addr, int count)
|
||||||
|
|
||||||
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF
|
#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),
|
adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
||||||
if (!adapter->req_list)
|
if (!adapter->req_list)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i=0; i<REQUEST_LIST_SIZE; i++)
|
for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
|
||||||
INIT_LIST_HEAD(&adapter->req_list[i]);
|
INIT_LIST_HEAD(&adapter->req_list[idx]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
|
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);
|
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)
|
int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int idx;
|
||||||
|
|
||||||
for (i=0; i<REQUEST_LIST_SIZE; i++)
|
for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
|
||||||
if (!list_empty(&adapter->req_list[i]))
|
if (!list_empty(&adapter->req_list[idx]))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1106,7 +1041,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
|
||||||
|
|
||||||
/* initialize list of fsf requests */
|
/* initialize list of fsf requests */
|
||||||
spin_lock_init(&adapter->req_list_lock);
|
spin_lock_init(&adapter->req_list_lock);
|
||||||
retval = zfcp_reqlist_init(adapter);
|
retval = zfcp_reqlist_alloc(adapter);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
ZFCP_LOG_INFO("request list initialization failed\n");
|
ZFCP_LOG_INFO("request list initialization failed\n");
|
||||||
goto failed_low_mem_buffers;
|
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);
|
zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
|
||||||
sysfs_failed:
|
sysfs_failed:
|
||||||
dev_set_drvdata(&ccw_device->dev, NULL);
|
dev_set_drvdata(&ccw_device->dev, NULL);
|
||||||
|
zfcp_reqlist_free(adapter);
|
||||||
failed_low_mem_buffers:
|
failed_low_mem_buffers:
|
||||||
zfcp_free_low_mem_buffers(adapter);
|
zfcp_free_low_mem_buffers(adapter);
|
||||||
if (qdio_free(ccw_device) != 0)
|
if (qdio_free(ccw_device) != 0)
|
||||||
|
|
|
@ -1089,6 +1089,42 @@ extern void _zfcp_hex_dump(char *, int);
|
||||||
#define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter))
|
#define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter))
|
||||||
#define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port))
|
#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
|
* functions needed for reference/usage counting
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -847,8 +847,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
|
||||||
if (erp_action->fsf_req) {
|
if (erp_action->fsf_req) {
|
||||||
/* take lock to ensure that request is not deleted meanwhile */
|
/* take lock to ensure that request is not deleted meanwhile */
|
||||||
spin_lock(&adapter->req_list_lock);
|
spin_lock(&adapter->req_list_lock);
|
||||||
if (zfcp_reqlist_ismember(adapter,
|
if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
|
||||||
erp_action->fsf_req->req_id)) {
|
|
||||||
/* fsf_req still exists */
|
/* fsf_req still exists */
|
||||||
debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
|
debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
|
||||||
debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
|
debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
|
||||||
|
|
|
@ -184,10 +184,6 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
|
||||||
unsigned long);
|
unsigned long);
|
||||||
extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
|
extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
|
||||||
struct scsi_cmnd *);
|
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 *);
|
extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
|
||||||
|
|
||||||
#endif /* ZFCP_EXT_H */
|
#endif /* ZFCP_EXT_H */
|
||||||
|
|
|
@ -4787,7 +4787,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
|
||||||
retval = -EIO;
|
retval = -EIO;
|
||||||
del_timer(&fsf_req->timer);
|
del_timer(&fsf_req->timer);
|
||||||
spin_lock(&adapter->req_list_lock);
|
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);
|
spin_unlock(&adapter->req_list_lock);
|
||||||
/* undo changes in request queue made for this request */
|
/* undo changes in request queue made for this request */
|
||||||
zfcp_qdio_zero_sbals(req_queue->buffer,
|
zfcp_qdio_zero_sbals(req_queue->buffer,
|
||||||
|
|
|
@ -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,
|
static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
|
||||||
unsigned long req_id)
|
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);
|
debug_long_event(adapter->erp_dbf, 4, req_id);
|
||||||
|
|
||||||
spin_lock_irqsave(&adapter->req_list_lock, flags);
|
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) {
|
if (!fsf_req)
|
||||||
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
|
/*
|
||||||
panic("error: unknown request id (%ld).\n", req_id);
|
* 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);
|
atomic_dec(&adapter->reqs_active);
|
||||||
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
|
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
|
||||||
|
|
||||||
|
|
|
@ -407,8 +407,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
||||||
|
|
||||||
/* Check whether corresponding fsf_req is still pending */
|
/* Check whether corresponding fsf_req is still pending */
|
||||||
spin_lock(&adapter->req_list_lock);
|
spin_lock(&adapter->req_list_lock);
|
||||||
fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long)
|
fsf_req = zfcp_reqlist_find(adapter,
|
||||||
scpnt->host_scribble);
|
(unsigned long) scpnt->host_scribble);
|
||||||
spin_unlock(&adapter->req_list_lock);
|
spin_unlock(&adapter->req_list_lock);
|
||||||
if (!fsf_req) {
|
if (!fsf_req) {
|
||||||
write_unlock_irqrestore(&adapter->abort_lock, flags);
|
write_unlock_irqrestore(&adapter->abort_lock, flags);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче