aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-12-18 07:07:32 -0500
committerTejun Heo <tj@kernel.org>2013-12-19 13:50:32 -0500
commit85fbd722ad0f5d64d1ad15888cd1eb2188bfb557 (patch)
treed77c0fe2f3c2776bb69869b0e200702419652e98 /drivers/ata
parentf78dea064c5f7de07de4912a6e5136dbc443d614 (diff)
libata, freezer: avoid block device removal while system is frozen
Freezable kthreads and workqueues are fundamentally problematic in that they effectively introduce a big kernel lock widely used in the kernel and have already been the culprit of several deadlock scenarios. This is the latest occurrence. During resume, libata rescans all the ports and revalidates all pre-existing devices. If it determines that a device has gone missing, the device is removed from the system which involves invalidating block device and flushing bdi while holding driver core layer locks. Unfortunately, this can race with the rest of device resume. Because freezable kthreads and workqueues are thawed after device resume is complete and block device removal depends on freezable workqueues and kthreads (e.g. bdi_wq, jbd2) to make progress, this can lead to deadlock - block device removal can't proceed because kthreads are frozen and kthreads can't be thawed because device resume is blocked behind block device removal. 839a8e8660b6 ("writeback: replace custom worker pool implementation with unbound workqueue") made this particular deadlock scenario more visible but the underlying problem has always been there - the original forker task and jbd2 are freezable too. In fact, this is highly likely just one of many possible deadlock scenarios given that freezer behaves as a big kernel lock and we don't have any debug mechanism around it. I believe the right thing to do is getting rid of freezable kthreads and workqueues. This is something fundamentally broken. For now, implement a funny workaround in libata - just avoid doing block device hot[un]plug while the system is frozen. Kernel engineering at its finest. :( v2: Add EXPORT_SYMBOL_GPL(pm_freezing) for cases where libata is built as a module. v3: Comment updated and polling interval changed to 10ms as suggested by Rafael. v4: Add #ifdef CONFIG_FREEZER around the hack as pm_freezing is not defined when FREEZER is not configured thus breaking build. Reported by kbuild test robot. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Tomaž Šolc <tomaz.solc@tablix.org> Reviewed-by: "Rafael J. Wysocki" <rjw@rjwysocki.net> Link: https://bugzilla.kernel.org/show_bug.cgi?id=62801 Link: http://lkml.kernel.org/r/20131213174932.GA27070@htj.dyndns.org Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Len Brown <len.brown@intel.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: stable@vger.kernel.org Cc: kbuild test robot <fengguang.wu@intel.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-scsi.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index db6dfcfa3e2e..176f62950e3d 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3871,6 +3871,27 @@ void ata_scsi_hotplug(struct work_struct *work)
3871 return; 3871 return;
3872 } 3872 }
3873 3873
3874 /*
3875 * XXX - UGLY HACK
3876 *
3877 * The block layer suspend/resume path is fundamentally broken due
3878 * to freezable kthreads and workqueue and may deadlock if a block
3879 * device gets removed while resume is in progress. I don't know
3880 * what the solution is short of removing freezable kthreads and
3881 * workqueues altogether.
3882 *
3883 * The following is an ugly hack to avoid kicking off device
3884 * removal while freezer is active. This is a joke but does avoid
3885 * this particular deadlock scenario.
3886 *
3887 * https://bugzilla.kernel.org/show_bug.cgi?id=62801
3888 * http://marc.info/?l=linux-kernel&m=138695698516487
3889 */
3890#ifdef CONFIG_FREEZER
3891 while (pm_freezing)
3892 msleep(10);
3893#endif
3894
3874 DPRINTK("ENTER\n"); 3895 DPRINTK("ENTER\n");
3875 mutex_lock(&ap->scsi_scan_mutex); 3896 mutex_lock(&ap->scsi_scan_mutex);
3876 3897