Skip to content

Commit

Permalink
scsi: core: Avoid that ATA error handling can trigger a kernel hang o…
Browse files Browse the repository at this point in the history
…r oops

commit 3be8828 upstream.

Avoid that the recently introduced call_rcu() call in the SCSI core
triggers a double call_rcu() call.

Reported-by: Natanael Copa <[email protected]>
Reported-by: Damien Le Moal <[email protected]>
References: https://bugzilla.kernel.org/show_bug.cgi?id=198861
Fixes: 3bd6f43 ("scsi: core: Ensure that the SCSI error handler gets woken up")
Signed-off-by: Bart Van Assche <[email protected]>
Reviewed-by: Damien Le Moal <[email protected]>
Tested-by: Damien Le Moal <[email protected]>
Cc: Natanael Copa <[email protected]>
Cc: Damien Le Moal <[email protected]>
Cc: Alexandre Oliva <[email protected]>
Cc: Pavel Tikhomirov <[email protected]>
Cc: Hannes Reinecke <[email protected]>
Cc: Johannes Thumshirn <[email protected]>
Cc: <[email protected]>
Signed-off-by: Martin K. Petersen <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
KAGA-KOKO authored and gregkh committed Mar 15, 2018
1 parent 2e50333 commit 4dbc3e4
Show file tree
Hide file tree
Showing 5 changed files with 8 additions and 7 deletions.
3 changes: 0 additions & 3 deletions drivers/scsi/hosts.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,6 @@ static void scsi_host_dev_release(struct device *dev)
if (shost->work_q)
destroy_workqueue(shost->work_q);

destroy_rcu_head(&shost->rcu);

if (shost->shost_state == SHOST_CREATED) {
/*
* Free the shost_dev device name here if scsi_host_alloc()
Expand Down Expand Up @@ -404,7 +402,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
INIT_LIST_HEAD(&shost->starved_list);
init_waitqueue_head(&shost->host_wait);
mutex_init(&shost->scan_mutex);
init_rcu_head(&shost->rcu);

index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
if (index < 0)
Expand Down
5 changes: 3 additions & 2 deletions drivers/scsi/scsi_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd)

static void scsi_eh_inc_host_failed(struct rcu_head *head)
{
struct Scsi_Host *shost = container_of(head, typeof(*shost), rcu);
struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu);
struct Scsi_Host *shost = scmd->device->host;
unsigned long flags;

spin_lock_irqsave(shost->host_lock, flags);
Expand Down Expand Up @@ -258,7 +259,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
* Ensure that all tasks observe the host state change before the
* host_failed change.
*/
call_rcu(&shost->rcu, scsi_eh_inc_host_failed);
call_rcu(&scmd->rcu, scsi_eh_inc_host_failed);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/scsi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ static bool scsi_end_request(struct request *req, blk_status_t error,
if (!blk_rq_is_scsi(req)) {
WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED));
cmd->flags &= ~SCMD_INITIALIZED;
destroy_rcu_head(&cmd->rcu);
}

if (req->mq_ctx) {
Expand Down Expand Up @@ -1150,6 +1151,7 @@ void scsi_initialize_rq(struct request *rq)
struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);

scsi_req_init(&cmd->req);
init_rcu_head(&cmd->rcu);
cmd->jiffies_at_alloc = jiffies;
cmd->retries = 0;
}
Expand Down
3 changes: 3 additions & 0 deletions include/scsi/scsi_cmnd.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ struct scsi_cmnd {
struct list_head list; /* scsi_cmnd participates in queue lists */
struct list_head eh_entry; /* entry for the host eh_cmd_q */
struct delayed_work abort_work;

struct rcu_head rcu;

int eh_eflags; /* Used by error handlr */

/*
Expand Down
2 changes: 0 additions & 2 deletions include/scsi/scsi_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -571,8 +571,6 @@ struct Scsi_Host {
struct blk_mq_tag_set tag_set;
};

struct rcu_head rcu;

atomic_t host_busy; /* commands actually active on low-level */
atomic_t host_blocked;

Expand Down

0 comments on commit 4dbc3e4

Please sign in to comment.