diff options
author | Andreas Herrmann <aherrman@de.ibm.com> | 2005-06-13 07:20:35 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-06-13 22:32:48 -0400 |
commit | 1db2c9c0931a53fe013db55fd2ff58859db31e8d (patch) | |
tree | 1134627ac98d91896dcdb161d5df7ecef60a4de3 /drivers/s390/scsi/zfcp_qdio.c | |
parent | 64b29a130901d5b8578e9f602cf2dae56aaff224 (diff) |
[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>
Diffstat (limited to 'drivers/s390/scsi/zfcp_qdio.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 28 |
1 files changed, 14 insertions, 14 deletions
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index fb218dd9d934..24e16ec331d9 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
@@ -446,37 +446,37 @@ int | |||
446 | zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) | 446 | zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr) |
447 | { | 447 | { |
448 | struct zfcp_fsf_req *fsf_req; | 448 | struct zfcp_fsf_req *fsf_req; |
449 | int retval = 0; | ||
450 | 449 | ||
451 | /* invalid (per convention used in this driver) */ | 450 | /* invalid (per convention used in this driver) */ |
452 | if (unlikely(!sbale_addr)) { | 451 | if (unlikely(!sbale_addr)) { |
453 | ZFCP_LOG_NORMAL("bug: invalid reqid\n"); | 452 | ZFCP_LOG_NORMAL("bug: invalid reqid\n"); |
454 | retval = -EINVAL; | 453 | return -EINVAL; |
455 | goto out; | ||
456 | } | 454 | } |
457 | 455 | ||
458 | /* valid request id and thus (hopefully :) valid fsf_req address */ | 456 | /* valid request id and thus (hopefully :) valid fsf_req address */ |
459 | fsf_req = (struct zfcp_fsf_req *) sbale_addr; | 457 | fsf_req = (struct zfcp_fsf_req *) sbale_addr; |
460 | 458 | ||
459 | /* serialize with zfcp_fsf_req_dismiss_all */ | ||
460 | spin_lock(&adapter->fsf_req_list_lock); | ||
461 | if (list_empty(&adapter->fsf_req_list_head)) { | ||
462 | spin_unlock(&adapter->fsf_req_list_lock); | ||
463 | return 0; | ||
464 | } | ||
465 | list_del(&fsf_req->list); | ||
466 | atomic_dec(&adapter->fsf_reqs_active); | ||
467 | spin_unlock(&adapter->fsf_req_list_lock); | ||
468 | |||
461 | if (unlikely(adapter != fsf_req->adapter)) { | 469 | if (unlikely(adapter != fsf_req->adapter)) { |
462 | ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, " | 470 | ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, " |
463 | "fsf_req->adapter=%p, adapter=%p)\n", | 471 | "fsf_req->adapter=%p, adapter=%p)\n", |
464 | fsf_req, fsf_req->adapter, adapter); | 472 | fsf_req, fsf_req->adapter, adapter); |
465 | retval = -EINVAL; | 473 | return -EINVAL; |
466 | goto out; | ||
467 | } | ||
468 | |||
469 | ZFCP_LOG_TRACE("fsf_req at %p, QTCB at %p\n", fsf_req, fsf_req->qtcb); | ||
470 | if (likely(fsf_req->qtcb)) { | ||
471 | ZFCP_LOG_TRACE("hex dump of QTCB:\n"); | ||
472 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) fsf_req->qtcb, | ||
473 | sizeof(struct fsf_qtcb)); | ||
474 | } | 474 | } |
475 | 475 | ||
476 | /* finish the FSF request */ | 476 | /* finish the FSF request */ |
477 | zfcp_fsf_req_complete(fsf_req); | 477 | zfcp_fsf_req_complete(fsf_req); |
478 | out: | 478 | |
479 | return retval; | 479 | return 0; |
480 | } | 480 | } |
481 | 481 | ||
482 | /** | 482 | /** |