aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2006-01-05 03:14:02 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-31 20:23:36 -0500
commitb31f821c6dee6f3ecfca6b2583a6552538fb91bf (patch)
tree3305511c230623ccd4fb1c766c57585479644cc6 /drivers/block
parent65b4fe553bf43018c06740f3d1f6caf42cf95924 (diff)
[PATCH] USB: ub 04 Loss of timer and a hang
If SCSI commands are submitted while other commands are still processed, the dispatch loop turns, and we stop the work_timer. Then, if URB fails to complete, ub hangs until the device is unplugged. This does not happen often, becase we only allow one SCSI command per block device, but does happen (on multi-LUN devices, for example). The fix is to stop timer only when we actually going to change the state. The nicest code would be to have the timer stopped in URB callback, but this is impossible, because it can be called from inside a timer, through the urb_unlink. Then we get BUG in timer.c:cascade(). So, we do it a little dirtier. Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/ub.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index db4943c53d36..c3600cb36365 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -1106,7 +1106,8 @@ static void ub_urb_timeout(unsigned long arg)
1106 unsigned long flags; 1106 unsigned long flags;
1107 1107
1108 spin_lock_irqsave(sc->lock, flags); 1108 spin_lock_irqsave(sc->lock, flags);
1109 usb_unlink_urb(&sc->work_urb); 1109 if (!ub_is_completed(&sc->work_done))
1110 usb_unlink_urb(&sc->work_urb);
1110 spin_unlock_irqrestore(sc->lock, flags); 1111 spin_unlock_irqrestore(sc->lock, flags);
1111} 1112}
1112 1113
@@ -1131,7 +1132,6 @@ static void ub_scsi_action(unsigned long _dev)
1131 unsigned long flags; 1132 unsigned long flags;
1132 1133
1133 spin_lock_irqsave(sc->lock, flags); 1134 spin_lock_irqsave(sc->lock, flags);
1134 del_timer(&sc->work_timer);
1135 ub_scsi_dispatch(sc); 1135 ub_scsi_dispatch(sc);
1136 spin_unlock_irqrestore(sc->lock, flags); 1136 spin_unlock_irqrestore(sc->lock, flags);
1137} 1137}
@@ -1155,6 +1155,7 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
1155 } else { 1155 } else {
1156 if (!ub_is_completed(&sc->work_done)) 1156 if (!ub_is_completed(&sc->work_done))
1157 break; 1157 break;
1158 del_timer(&sc->work_timer);
1158 ub_scsi_urb_compl(sc, cmd); 1159 ub_scsi_urb_compl(sc, cmd);
1159 } 1160 }
1160 } 1161 }