diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2014-08-31 19:09:59 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-09-30 03:34:37 -0400 |
commit | db525fce95f0ee39102f06f8599ced3f3f3af128 (patch) | |
tree | 104a30ca4d06b3d62234a06007e192ff4ecc3fdb /drivers/scsi/scsi_debug.c | |
parent | a41a9ad3bbf61fae0b6bfb232153da60d14fdbd9 (diff) |
scsi_debug: deadlock between completions and surprise module removal
A deadlock has been reported when the completion
of SCSI commands (simulated by a timer) was surprised
by a module removal. This patch removes one half of
the offending locks around timer deletions. This fix
is applied both to stop_all_queued() which is were
the deadlock was discovered and stop_queued_cmnd()
which has very similar logic.
This patch should be applied both to the lk 3.17 tree
and Christoph's drivers-for-3.18 tree.
Tested-and-reported-by: Milan Broz <gmazyland@gmail.com>
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1c475e9a46ab..2b6d447ad6d6 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -2743,6 +2743,13 @@ static int stop_queued_cmnd(struct scsi_cmnd *cmnd) | |||
2743 | if (test_bit(k, queued_in_use_bm)) { | 2743 | if (test_bit(k, queued_in_use_bm)) { |
2744 | sqcp = &queued_arr[k]; | 2744 | sqcp = &queued_arr[k]; |
2745 | if (cmnd == sqcp->a_cmnd) { | 2745 | if (cmnd == sqcp->a_cmnd) { |
2746 | devip = (struct sdebug_dev_info *) | ||
2747 | cmnd->device->hostdata; | ||
2748 | if (devip) | ||
2749 | atomic_dec(&devip->num_in_q); | ||
2750 | sqcp->a_cmnd = NULL; | ||
2751 | spin_unlock_irqrestore(&queued_arr_lock, | ||
2752 | iflags); | ||
2746 | if (scsi_debug_ndelay > 0) { | 2753 | if (scsi_debug_ndelay > 0) { |
2747 | if (sqcp->sd_hrtp) | 2754 | if (sqcp->sd_hrtp) |
2748 | hrtimer_cancel( | 2755 | hrtimer_cancel( |
@@ -2755,18 +2762,13 @@ static int stop_queued_cmnd(struct scsi_cmnd *cmnd) | |||
2755 | if (sqcp->tletp) | 2762 | if (sqcp->tletp) |
2756 | tasklet_kill(sqcp->tletp); | 2763 | tasklet_kill(sqcp->tletp); |
2757 | } | 2764 | } |
2758 | __clear_bit(k, queued_in_use_bm); | 2765 | clear_bit(k, queued_in_use_bm); |
2759 | devip = (struct sdebug_dev_info *) | 2766 | return 1; |
2760 | cmnd->device->hostdata; | ||
2761 | if (devip) | ||
2762 | atomic_dec(&devip->num_in_q); | ||
2763 | sqcp->a_cmnd = NULL; | ||
2764 | break; | ||
2765 | } | 2767 | } |
2766 | } | 2768 | } |
2767 | } | 2769 | } |
2768 | spin_unlock_irqrestore(&queued_arr_lock, iflags); | 2770 | spin_unlock_irqrestore(&queued_arr_lock, iflags); |
2769 | return (k < qmax) ? 1 : 0; | 2771 | return 0; |
2770 | } | 2772 | } |
2771 | 2773 | ||
2772 | /* Deletes (stops) timers or tasklets of all queued commands */ | 2774 | /* Deletes (stops) timers or tasklets of all queued commands */ |
@@ -2782,6 +2784,13 @@ static void stop_all_queued(void) | |||
2782 | if (test_bit(k, queued_in_use_bm)) { | 2784 | if (test_bit(k, queued_in_use_bm)) { |
2783 | sqcp = &queued_arr[k]; | 2785 | sqcp = &queued_arr[k]; |
2784 | if (sqcp->a_cmnd) { | 2786 | if (sqcp->a_cmnd) { |
2787 | devip = (struct sdebug_dev_info *) | ||
2788 | sqcp->a_cmnd->device->hostdata; | ||
2789 | if (devip) | ||
2790 | atomic_dec(&devip->num_in_q); | ||
2791 | sqcp->a_cmnd = NULL; | ||
2792 | spin_unlock_irqrestore(&queued_arr_lock, | ||
2793 | iflags); | ||
2785 | if (scsi_debug_ndelay > 0) { | 2794 | if (scsi_debug_ndelay > 0) { |
2786 | if (sqcp->sd_hrtp) | 2795 | if (sqcp->sd_hrtp) |
2787 | hrtimer_cancel( | 2796 | hrtimer_cancel( |
@@ -2794,12 +2803,8 @@ static void stop_all_queued(void) | |||
2794 | if (sqcp->tletp) | 2803 | if (sqcp->tletp) |
2795 | tasklet_kill(sqcp->tletp); | 2804 | tasklet_kill(sqcp->tletp); |
2796 | } | 2805 | } |
2797 | __clear_bit(k, queued_in_use_bm); | 2806 | clear_bit(k, queued_in_use_bm); |
2798 | devip = (struct sdebug_dev_info *) | 2807 | spin_lock_irqsave(&queued_arr_lock, iflags); |
2799 | sqcp->a_cmnd->device->hostdata; | ||
2800 | if (devip) | ||
2801 | atomic_dec(&devip->num_in_q); | ||
2802 | sqcp->a_cmnd = NULL; | ||
2803 | } | 2808 | } |
2804 | } | 2809 | } |
2805 | } | 2810 | } |