lkml.org 
[lkml]   [2020]   [Jun]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 060/135] libata: Use per port sync for detach
    Date
    From: Kai-Heng Feng <kai.heng.feng@canonical.com>

    [ Upstream commit b5292111de9bb70cba3489075970889765302136 ]

    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>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/ata/libata-core.c | 11 +++++------
    include/linux/libata.h | 3 +++
    2 files changed, 8 insertions(+), 6 deletions(-)

    diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
    index fc4bf8ff40ead..17cebfe5acc82 100644
    --- a/drivers/ata/libata-core.c
    +++ b/drivers/ata/libata-core.c
    @@ -56,7 +56,6 @@
    #include <linux/workqueue.h>
    #include <linux/scatterlist.h>
    #include <linux/io.h>
    -#include <linux/async.h>
    #include <linux/log2.h>
    #include <linux/slab.h>
    #include <linux/glob.h>
    @@ -6222,7 +6221,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
    /* perform each probe asynchronously */
    for (i = 0; i < host->n_ports; i++) {
    struct ata_port *ap = host->ports[i];
    - async_schedule(async_port_probe, ap);
    + ap->cookie = async_schedule(async_port_probe, ap);
    }

    return 0;
    @@ -6355,11 +6354,11 @@ void ata_host_detach(struct ata_host *host)
    {
    int i;

    - /* Ensure ata_port probe has completed */
    - async_synchronize_full();
    -
    - for (i = 0; i < host->n_ports; i++)
    + for (i = 0; i < host->n_ports; i++) {
    + /* Ensure ata_port probe has completed */
    + async_synchronize_cookie(host->ports[i]->cookie + 1);
    ata_port_detach(host->ports[i]);
    + }

    /* the host is dead now, dissociate ACPI */
    ata_acpi_dissociate(host);
    diff --git a/include/linux/libata.h b/include/linux/libata.h
    index 6428ac4746dee..af561d33221d6 100644
    --- a/include/linux/libata.h
    +++ b/include/linux/libata.h
    @@ -38,6 +38,7 @@
    #include <linux/acpi.h>
    #include <linux/cdrom.h>
    #include <linux/sched.h>
    +#include <linux/async.h>

    /*
    * Define if arch has non-standard setup. This is a _PCI_ standard
    @@ -872,6 +873,8 @@ struct ata_port {
    struct timer_list fastdrain_timer;
    unsigned long fastdrain_cnt;

    + async_cookie_t cookie;
    +
    int em_message_type;
    void *private_data;

    --
    2.25.1
    \
     
     \ /
      Last update: 2020-06-29 23:40    [W:4.226 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site