[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>
Цей коміт міститься в:

зафіксовано
James Bottomley

джерело
64b29a1309
коміт
1db2c9c093
@@ -446,37 +446,37 @@ int
|
||||
zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
|
||||
{
|
||||
struct zfcp_fsf_req *fsf_req;
|
||||
int retval = 0;
|
||||
|
||||
/* invalid (per convention used in this driver) */
|
||||
if (unlikely(!sbale_addr)) {
|
||||
ZFCP_LOG_NORMAL("bug: invalid reqid\n");
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* valid request id and thus (hopefully :) valid fsf_req address */
|
||||
fsf_req = (struct zfcp_fsf_req *) sbale_addr;
|
||||
|
||||
/* serialize with zfcp_fsf_req_dismiss_all */
|
||||
spin_lock(&adapter->fsf_req_list_lock);
|
||||
if (list_empty(&adapter->fsf_req_list_head)) {
|
||||
spin_unlock(&adapter->fsf_req_list_lock);
|
||||
return 0;
|
||||
}
|
||||
list_del(&fsf_req->list);
|
||||
atomic_dec(&adapter->fsf_reqs_active);
|
||||
spin_unlock(&adapter->fsf_req_list_lock);
|
||||
|
||||
if (unlikely(adapter != fsf_req->adapter)) {
|
||||
ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, "
|
||||
"fsf_req->adapter=%p, adapter=%p)\n",
|
||||
fsf_req, fsf_req->adapter, adapter);
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ZFCP_LOG_TRACE("fsf_req at %p, QTCB at %p\n", fsf_req, fsf_req->qtcb);
|
||||
if (likely(fsf_req->qtcb)) {
|
||||
ZFCP_LOG_TRACE("hex dump of QTCB:\n");
|
||||
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb,
|
||||
sizeof(struct fsf_qtcb));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* finish the FSF request */
|
||||
zfcp_fsf_req_complete(fsf_req);
|
||||
out:
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Посилання в новій задачі
Заблокувати користувача