From b2b15e1d55288b5bd3fde89162f2ea70c77d920a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 14 May 2017 18:56:09 +0000 Subject: [PATCH] scst_local: Fix a race condition Avoid that the following crash can occur: general protection fault: 0000 [#1] PREEMPT SMP RIP: 0010:scsi_is_host_device+0x7/0x20 [scsi_mod] Call Trace: scst_process_aens+0x95/0x1d0 [scst_local] scst_aen_work_fn+0x6f/0x120 [scst_local] process_one_work+0x20b/0x6c0 worker_thread+0x4e/0x4a0 kthread+0x113/0x150 ret_from_fork+0x31/0x40 git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7185 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst_local/scst_local.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index d7c451f3d..e5d91d876 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -1265,6 +1265,7 @@ static void scst_process_aens(struct scst_local_sess *sess, __acquires(&sess->aen_lock) { struct scst_aen_work_item *work_item = NULL; + struct Scsi_Host *shost; TRACE_ENTRY(); @@ -1274,7 +1275,9 @@ static void scst_process_aens(struct scst_local_sess *sess, work_item = list_first_entry(&sess->aen_work_list, struct scst_aen_work_item, work_list_entry); list_del(&work_item->work_list_entry); - + shost = sess->shost; + if (shost && !scsi_host_get(shost)) + shost = NULL; spin_unlock(&sess->aen_lock); if (cleanup_only) @@ -1283,13 +1286,17 @@ static void scst_process_aens(struct scst_local_sess *sess, sBUG_ON(work_item->aen->event_fn != SCST_AEN_SCSI); /* Let's always rescan */ - scsi_scan_target(&sess->shost->shost_gendev, 0, 0, - SCAN_WILD_CARD, 1); + if (shost) + scsi_scan_target(&shost->shost_gendev, 0, 0, + SCAN_WILD_CARD, 1); done: scst_aen_done(work_item->aen); kfree(work_item); + if (shost) + scsi_host_put(shost); + spin_lock(&sess->aen_lock); } @@ -1707,12 +1714,18 @@ out: static int scst_local_driver_remove(struct device *dev) { struct scst_local_sess *sess; + struct Scsi_Host *shost = NULL; TRACE_ENTRY(); sess = to_scst_lcl_sess(dev); - scsi_remove_host(sess->shost); - scsi_host_put(sess->shost); + + spin_lock(&sess->aen_lock); + swap(sess->shost, shost); + spin_unlock(&sess->aen_lock); + + scsi_remove_host(shost); + scsi_host_put(shost); TRACE_EXIT(); return 0;