Skip to content

Commit 4dbc3e4

Browse files
KAGA-KOKOgregkh
authored andcommitted
scsi: core: Avoid that ATA error handling can trigger a kernel hang or 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]>
1 parent 2e50333 commit 4dbc3e4

File tree

5 files changed

+8
-7
lines changed

5 files changed

+8
-7
lines changed

drivers/scsi/hosts.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,6 @@ static void scsi_host_dev_release(struct device *dev)
328328
if (shost->work_q)
329329
destroy_workqueue(shost->work_q);
330330

331-
destroy_rcu_head(&shost->rcu);
332-
333331
if (shost->shost_state == SHOST_CREATED) {
334332
/*
335333
* Free the shost_dev device name here if scsi_host_alloc()
@@ -404,7 +402,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
404402
INIT_LIST_HEAD(&shost->starved_list);
405403
init_waitqueue_head(&shost->host_wait);
406404
mutex_init(&shost->scan_mutex);
407-
init_rcu_head(&shost->rcu);
408405

409406
index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
410407
if (index < 0)

drivers/scsi/scsi_error.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd)
222222

223223
static void scsi_eh_inc_host_failed(struct rcu_head *head)
224224
{
225-
struct Scsi_Host *shost = container_of(head, typeof(*shost), rcu);
225+
struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu);
226+
struct Scsi_Host *shost = scmd->device->host;
226227
unsigned long flags;
227228

228229
spin_lock_irqsave(shost->host_lock, flags);
@@ -258,7 +259,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
258259
* Ensure that all tasks observe the host state change before the
259260
* host_failed change.
260261
*/
261-
call_rcu(&shost->rcu, scsi_eh_inc_host_failed);
262+
call_rcu(&scmd->rcu, scsi_eh_inc_host_failed);
262263
}
263264

264265
/**

drivers/scsi/scsi_lib.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,7 @@ static bool scsi_end_request(struct request *req, blk_status_t error,
670670
if (!blk_rq_is_scsi(req)) {
671671
WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED));
672672
cmd->flags &= ~SCMD_INITIALIZED;
673+
destroy_rcu_head(&cmd->rcu);
673674
}
674675

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

11521153
scsi_req_init(&cmd->req);
1154+
init_rcu_head(&cmd->rcu);
11531155
cmd->jiffies_at_alloc = jiffies;
11541156
cmd->retries = 0;
11551157
}

include/scsi/scsi_cmnd.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ struct scsi_cmnd {
6969
struct list_head list; /* scsi_cmnd participates in queue lists */
7070
struct list_head eh_entry; /* entry for the host eh_cmd_q */
7171
struct delayed_work abort_work;
72+
73+
struct rcu_head rcu;
74+
7275
int eh_eflags; /* Used by error handlr */
7376

7477
/*

include/scsi/scsi_host.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,8 +571,6 @@ struct Scsi_Host {
571571
struct blk_mq_tag_set tag_set;
572572
};
573573

574-
struct rcu_head rcu;
575-
576574
atomic_t host_busy; /* commands actually active on low-level */
577575
atomic_t host_blocked;
578576

0 commit comments

Comments
 (0)