aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2010-09-06 11:57:14 -0400
committerJeff Garzik <jgarzik@redhat.com>2010-10-21 20:21:05 -0400
commitc0c362b60e259e3480a36ef70280d545818844f0 (patch)
treed9871b719cd76f9f683278f938662e080a6ad9d7 /include
parent97750cebb3000a9cc08f8ce8dc8c7143be7d7201 (diff)
libata: implement cross-port EH exclusion
In libata, the non-EH code paths should always take and release ap->lock explicitly when accessing hardware or shared data structures. However, once EH is active, it's assumed that the port is owned by EH and EH methods don't explicitly take ap->lock unless race from irq handler or other code paths are expected. However, libata EH didn't guarantee exclusion among EHs for ports of the same host. IOW, multiple EHs may execute in parallel on multiple ports of the same controller. In many cases, especially in SATA, the ports are completely independent of each other and this doesn't cause problems; however, there are cases where different ports share the same resource, which lead to obscure timing related bugs such as the one fixed by commit 213373cf (ata_piix: fix locking around SIDPR access). This patch implements exclusion among EHs of the same host. When EH begins, it acquires per-host EH ownership by calling ata_eh_acquire(). When EH finishes, the ownership is released by calling ata_eh_release(). EH ownership is also released whenever the EH thread goes to sleep from ata_msleep() or explicitly and reacquired after waking up. This ensures that while EH is actively accessing the hardware, it has exclusive access to it while allowing EHs to interleave and progress in parallel as they hit waiting stages, which dominate the time spent in EH. This achieves cross-port EH exclusion without pervasive and fragile changes while still allowing parallel EH for the most part. This was first reported by yuanding02@gmail.com more than three years ago in the following bugzilla. :-) https://bugzilla.kernel.org/show_bug.cgi?id=8223 Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Reported-by: yuanding02@gmail.com Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'include')
-rw-r--r--include/linux/libata.h5
1 files changed, 5 insertions, 0 deletions
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 2fbd22bd68ce..52112d39d71e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -37,6 +37,7 @@
37#include <scsi/scsi_host.h> 37#include <scsi/scsi_host.h>
38#include <linux/acpi.h> 38#include <linux/acpi.h>
39#include <linux/cdrom.h> 39#include <linux/cdrom.h>
40#include <linux/sched.h>
40 41
41/* 42/*
42 * Define if arch has non-standard setup. This is a _PCI_ standard 43 * Define if arch has non-standard setup. This is a _PCI_ standard
@@ -535,6 +536,10 @@ struct ata_host {
535 void *private_data; 536 void *private_data;
536 struct ata_port_operations *ops; 537 struct ata_port_operations *ops;
537 unsigned long flags; 538 unsigned long flags;
539
540 struct mutex eh_mutex;
541 struct task_struct *eh_owner;
542
538#ifdef CONFIG_ATA_ACPI 543#ifdef CONFIG_ATA_ACPI
539 acpi_handle acpi_handle; 544 acpi_handle acpi_handle;
540#endif 545#endif