scsi: scsi_dh_alua: Check scsi_device_get() return value

Do not queue ALUA work nor call scsi_device_put() if the
scsi_device_get() call fails. This patch fixes the following crash:

general protection fault: 0000 [#1] SMP
RIP: 0010:scsi_device_put+0xb/0x30
Call Trace:
 scsi_disk_put+0x2d/0x40
 sd_release+0x3d/0xb0
 __blkdev_put+0x29e/0x360
 blkdev_put+0x49/0x170
 dm_put_table_device+0x58/0xc0 [dm_mod]
 dm_put_device+0x70/0xc0 [dm_mod]
 free_priority_group+0x92/0xc0 [dm_multipath]
 free_multipath+0x70/0xc0 [dm_multipath]
 multipath_dtr+0x19/0x20 [dm_multipath]
 dm_table_destroy+0x67/0x120 [dm_mod]
 dev_suspend+0xde/0x240 [dm_mod]
 ctl_ioctl+0x1f5/0x520 [dm_mod]
 dm_ctl_ioctl+0xe/0x20 [dm_mod]
 do_vfs_ioctl+0x8f/0x700
 SyS_ioctl+0x3c/0x70
 entry_SYSCALL_64_fastpath+0x18/0xad

Fixes: commit 03197b61c5 ("scsi_dh_alua: Use workqueue for RTPG")
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Tang Junhui <tang.junhui@zte.com.cn>
Cc: <stable@vger.kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Bart Van Assche 2017-03-17 17:02:01 -07:00 committed by Martin K. Petersen
parent bf33f87dd0
commit 625fe857e4

View File

@ -870,7 +870,7 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
unsigned long flags; unsigned long flags;
struct workqueue_struct *alua_wq = kaluad_wq; struct workqueue_struct *alua_wq = kaluad_wq;
if (!pg) if (!pg || scsi_device_get(sdev))
return; return;
spin_lock_irqsave(&pg->lock, flags); spin_lock_irqsave(&pg->lock, flags);
@ -884,14 +884,12 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
pg->flags |= ALUA_PG_RUN_RTPG; pg->flags |= ALUA_PG_RUN_RTPG;
kref_get(&pg->kref); kref_get(&pg->kref);
pg->rtpg_sdev = sdev; pg->rtpg_sdev = sdev;
scsi_device_get(sdev);
start_queue = 1; start_queue = 1;
} else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) { } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) {
pg->flags |= ALUA_PG_RUN_RTPG; pg->flags |= ALUA_PG_RUN_RTPG;
/* Do not queue if the worker is already running */ /* Do not queue if the worker is already running */
if (!(pg->flags & ALUA_PG_RUNNING)) { if (!(pg->flags & ALUA_PG_RUNNING)) {
kref_get(&pg->kref); kref_get(&pg->kref);
sdev = NULL;
start_queue = 1; start_queue = 1;
} }
} }
@ -900,13 +898,15 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
alua_wq = kaluad_sync_wq; alua_wq = kaluad_sync_wq;
spin_unlock_irqrestore(&pg->lock, flags); spin_unlock_irqrestore(&pg->lock, flags);
if (start_queue && if (start_queue) {
!queue_delayed_work(alua_wq, &pg->rtpg_work, if (queue_delayed_work(alua_wq, &pg->rtpg_work,
msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS))) { msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS)))
if (sdev) sdev = NULL;
scsi_device_put(sdev); else
kref_put(&pg->kref, release_port_group); kref_put(&pg->kref, release_port_group);
} }
if (sdev)
scsi_device_put(sdev);
} }
/* /*