aboutsummaryrefslogtreecommitdiff
path: root/drivers/block/ub.c
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2006-01-05 00:14:02 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-31 17:23:36 -0800
commitb31f821c6dee6f3ecfca6b2583a6552538fb91bf (patch)
tree3305511c230623ccd4fb1c766c57585479644cc6 /drivers/block/ub.c
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/ub.c')
-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 db4943c53d3..c3600cb3636 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -1106,7 +1106,8 @@ static void ub_urb_timeout(unsigned long arg)
unsigned long flags;
spin_lock_irqsave(sc->lock, flags);
- usb_unlink_urb(&sc->work_urb);
+ if (!ub_is_completed(&sc->work_done))
+ usb_unlink_urb(&sc->work_urb);
spin_unlock_irqrestore(sc->lock, flags);
}
@@ -1131,7 +1132,6 @@ static void ub_scsi_action(unsigned long _dev)
unsigned long flags;
spin_lock_irqsave(sc->lock, flags);
- del_timer(&sc->work_timer);
ub_scsi_dispatch(sc);
spin_unlock_irqrestore(sc->lock, flags);
}
@@ -1155,6 +1155,7 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
} else {
if (!ub_is_completed(&sc->work_done))
break;
+ del_timer(&sc->work_timer);
ub_scsi_urb_compl(sc, cmd);
}
}