aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorDavid Jeffery <djeffery@redhat.com>2012-11-21 02:39:54 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-17 08:43:54 -0800
commit78c9672f78f8bdf6321f6bead28c7dbd251ddd24 (patch)
tree7f93047ff9eee3148c351a232e22111810000d58 /drivers/scsi
parentb9ebaf5aad54cb173db311f007057976d867cdd3 (diff)
downloadkernel_samsung_smdk4412-78c9672f78f8bdf6321f6bead28c7dbd251ddd24.tar.gz
kernel_samsung_smdk4412-78c9672f78f8bdf6321f6bead28c7dbd251ddd24.tar.bz2
kernel_samsung_smdk4412-78c9672f78f8bdf6321f6bead28c7dbd251ddd24.zip
SCSI: qla2xxx: Test and clear FCPORT_UPDATE_NEEDED atomically.
commit a394aac88506159e047630fc90dc2242568382d8 upstream. 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> Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index a2a1a831b5f..7e78020b355 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3406,9 +3406,9 @@ qla2x00_do_dpc(void *data)
base_vha->host_no));
}
- if (test_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) {
+ if (test_and_clear_bit(FCPORT_UPDATE_NEEDED,
+ &base_vha->dpc_flags)) {
qla2x00_update_fcports(base_vha);
- clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
}
if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {