Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libata: Use per port sync for detach

Commit 130f4caf145c ("libata: Ensure ata_port probe has completed before
detach") may cause system freeze during suspend.

Using async_synchronize_full() in PM callbacks is wrong, since async
callbacks that are already scheduled may wait for not-yet-scheduled
callbacks, causes a circular dependency.

Instead of using big hammer like async_synchronize_full(), use async
cookie to make sure port probe are synced, without affecting other
scheduled PM callbacks.

Fixes: 130f4caf145c ("libata: Ensure ata_port probe has completed before detach")
Suggested-by: John Garry <john.garry@huawei.com>
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Tested-by: John Garry <john.garry@huawei.com>
BugLink: https://bugs.launchpad.net/bugs/1867983
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Kai-Heng Feng and committed by
Jens Axboe
b5292111 f650ef61

+8 -6
+5 -6
drivers/ata/libata-core.c
··· 42 42 #include <linux/workqueue.h> 43 43 #include <linux/scatterlist.h> 44 44 #include <linux/io.h> 45 - #include <linux/async.h> 46 45 #include <linux/log2.h> 47 46 #include <linux/slab.h> 48 47 #include <linux/glob.h> ··· 5777 5778 /* perform each probe asynchronously */ 5778 5779 for (i = 0; i < host->n_ports; i++) { 5779 5780 struct ata_port *ap = host->ports[i]; 5780 - async_schedule(async_port_probe, ap); 5781 + ap->cookie = async_schedule(async_port_probe, ap); 5781 5782 } 5782 5783 5783 5784 return 0; ··· 5919 5920 { 5920 5921 int i; 5921 5922 5922 - /* Ensure ata_port probe has completed */ 5923 - async_synchronize_full(); 5924 - 5925 - for (i = 0; i < host->n_ports; i++) 5923 + for (i = 0; i < host->n_ports; i++) { 5924 + /* Ensure ata_port probe has completed */ 5925 + async_synchronize_cookie(host->ports[i]->cookie + 1); 5926 5926 ata_port_detach(host->ports[i]); 5927 + } 5927 5928 5928 5929 /* the host is dead now, dissociate ACPI */ 5929 5930 ata_acpi_dissociate(host);
+3
include/linux/libata.h
··· 22 22 #include <linux/acpi.h> 23 23 #include <linux/cdrom.h> 24 24 #include <linux/sched.h> 25 + #include <linux/async.h> 25 26 26 27 /* 27 28 * Define if arch has non-standard setup. This is a _PCI_ standard ··· 872 871 873 872 struct timer_list fastdrain_timer; 874 873 unsigned long fastdrain_cnt; 874 + 875 + async_cookie_t cookie; 875 876 876 877 int em_message_type; 877 878 void *private_data;