lkml.org 
[lkml]   [2015]   [Sep]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.16.y-ckt 077/133] scsi: fix scsi_error_handler vs. scsi_host_dev_release race
    Date
    3.16.7-ckt18 -stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Michal Hocko <mhocko@suse.com>

    commit 537b604c8b3aa8b96fe35f87dd085816552e294c upstream.

    b9d5c6b7ef57 ("[SCSI] cleanup setting task state in
    scsi_error_handler()") has introduced a race between scsi_error_handler
    and scsi_host_dev_release resulting in the hang when the device goes
    away because scsi_error_handler might miss a wake up:

    CPU0 CPU1
    scsi_error_handler scsi_host_dev_release
    kthread_stop()
    kthread_should_stop()
    test_bit(KTHREAD_SHOULD_STOP)
    set_bit(KTHREAD_SHOULD_STOP)
    wake_up_process()
    wait_for_completion()

    set_current_state(TASK_INTERRUPTIBLE)
    schedule()

    The most straightforward solution seems to be to invert the ordering of
    the set_current_state and kthread_should_stop.

    The issue has been noticed during reboot test on a 3.0 based kernel but
    the current code seems to be affected in the same way.

    [jejb: additional comment added]
    Reported-and-debugged-by: Mike Mayer <Mike.Meyer@teradata.com>
    Signed-off-by: Michal Hocko <mhocko@suse.com>
    Reviewed-by: Dan Williams <dan.j.williams@intel.com>
    Reviewed-by: Hannes Reinecke <hare@suse.de>
    Signed-off-by: James Bottomley <JBottomley@Odin.com>
    Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
    ---
    drivers/scsi/scsi_error.c | 11 ++++++++++-
    1 file changed, 10 insertions(+), 1 deletion(-)

    diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
    index f0c7a970547f..48790f1dbf79 100644
    --- a/drivers/scsi/scsi_error.c
    +++ b/drivers/scsi/scsi_error.c
    @@ -2154,8 +2154,17 @@ int scsi_error_handler(void *data)
    * We never actually get interrupted because kthread_run
    * disables signal delivery for the created thread.
    */
    - while (!kthread_should_stop()) {
    + while (true) {
    + /*
    + * The sequence in kthread_stop() sets the stop flag first
    + * then wakes the process. To avoid missed wakeups, the task
    + * should always be in a non running state before the stop
    + * flag is checked
    + */
    set_current_state(TASK_INTERRUPTIBLE);
    + if (kthread_should_stop())
    + break;
    +
    if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
    shost->host_failed != shost->host_busy) {
    SCSI_LOG_ERROR_RECOVERY(1,

    \
     
     \ /
      Last update: 2015-09-30 12:01    [W:4.045 / U:0.140 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site