[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>
Цей коміт міститься в:
Andreas Herrmann
2005-06-13 13:20:35 +02:00
зафіксовано James Bottomley
джерело 64b29a1309
коміт 1db2c9c093
7 змінених файлів з 46 додано та 81 видалено

Переглянути файл

@@ -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;
}
/**