diff options
author | David Jeffery <djeffery@redhat.com> | 2012-11-21 02:39:54 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-11-30 04:35:45 -0500 |
commit | a394aac88506159e047630fc90dc2242568382d8 (patch) | |
tree | d2ea22fb36af0b09a8f67d2f9d7a404ce68f0681 /drivers/scsi | |
parent | 63ea923a97cb0d78efcbbd229950e101588f0ddb (diff) |
[SCSI] qla2xxx: Test and clear FCPORT_UPDATE_NEEDED atomically.
When the qla2xxx driver loses access to multiple, remote ports, there is a race
condition which can occur which will keep the request stuck on a scsi request
queue indefinitely.
This bad state occurred do to a race condition with how the FCPORT_UPDATE_NEEDED
bit is set in qla2x00_schedule_rport_del(), and how it is cleared in
qla2x00_do_dpc(). The problem port has its drport pointer set, but it has never
been processed by the driver to inform the fc transport that the port has been
lost. qla2x00_schedule_rport_del() sets drport, and then sets the
FCPORT_UPDATE_NEEDED bit. In qla2x00_do_dpc(), the port lists are walked and
any drport pointer is handled and the fc transport informed of the port loss,
then the FCPORT_UPDATE_NEEDED bit is cleared. This leaves a race where the
dpc thread is processing one port removal, another port removal is marked
with a call to qla2x00_schedule_rport_del(), and the dpc thread clears the
bit for both removals, even though only the first removal was actually
handled. Until another event occurs to set FCPORT_UPDATE_NEEDED, the later
port removal is never finished and qla2xxx stays in a bad state which causes
requests to become stuck on request queues.
This patch updates the driver to test and clear FCPORT_UPDATE_NEEDED
atomically. This ensures the port state changes are processed and not lost.
Signed-off-by: David Jeffery <djeffery@redhat.com>
Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Cc: stable@vger.kernel.org
Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d501bf5f806b..a60396725e8a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -4505,9 +4505,9 @@ qla2x00_do_dpc(void *data) | |||
4505 | "ISP abort end.\n"); | 4505 | "ISP abort end.\n"); |
4506 | } | 4506 | } |
4507 | 4507 | ||
4508 | if (test_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) { | 4508 | if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, |
4509 | &base_vha->dpc_flags)) { | ||
4509 | qla2x00_update_fcports(base_vha); | 4510 | qla2x00_update_fcports(base_vha); |
4510 | clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); | ||
4511 | } | 4511 | } |
4512 | 4512 | ||
4513 | if (test_bit(SCR_PENDING, &base_vha->dpc_flags)) { | 4513 | if (test_bit(SCR_PENDING, &base_vha->dpc_flags)) { |