ChangeSet 1.2181.4.79, 2005/03/28 12:33:26-08:00, [EMAIL PROTECTED]
[PATCH] USB: fix for ub for sleeping function called from invalid
context at kernel/workqueue.c:264
From: Pete Zaitcev <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
ub.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++---------------------
1 files changed, 47 insertions(+), 21 deletions(-)
diff -Nru a/drivers/block/ub.c b/drivers/block/ub.c
--- a/drivers/block/ub.c 2005-03-30 15:20:54 -08:00
+++ b/drivers/block/ub.c 2005-03-30 15:20:54 -08:00
@@ -300,6 +300,7 @@
/*
*/
+static void ub_cleanup(struct ub_dev *sc);
static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq);
static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
struct request *rq);
@@ -478,21 +479,47 @@
static void ub_id_put(int id)
{
+ unsigned long flags;
if (id < 0 || id >= UB_MAX_HOSTS) {
printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id);
return;
}
+
+ spin_lock_irqsave(&ub_lock, flags);
if (ub_hostv[id] == 0) {
+ spin_unlock_irqrestore(&ub_lock, flags);
printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id);
return;
}
ub_hostv[id] = 0;
+ spin_unlock_irqrestore(&ub_lock, flags);
+}
+
+/*
+ * Downcount for deallocation. This rides on two assumptions:
+ * - once something is poisoned, its refcount cannot grow
+ * - opens cannot happen at this time (del_gendisk was done)
+ * If the above is true, we can drop the lock, which we need for
+ * blk_cleanup_queue(): the silly thing may attempt to sleep.
+ * [Actually, it never needs to sleep for us, but it calls might_sleep()]
+ */
+static void ub_put(struct ub_dev *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ub_lock, flags);
+ --sc->openc;
+ if (sc->openc == 0 && atomic_read(&sc->poison)) {
+ spin_unlock_irqrestore(&ub_lock, flags);
+ ub_cleanup(sc);
+ } else {
+ spin_unlock_irqrestore(&ub_lock, flags);
+ }
}
/*
* Final cleanup and deallocation.
- * This must be called with ub_lock taken.
*/
static void ub_cleanup(struct ub_dev *sc)
{
@@ -1531,11 +1558,7 @@
return 0;
err_open:
- spin_lock_irqsave(&ub_lock, flags);
- --sc->openc;
- if (sc->openc == 0 && atomic_read(&sc->poison))
- ub_cleanup(sc);
- spin_unlock_irqrestore(&ub_lock, flags);
+ ub_put(sc);
return rc;
}
@@ -1545,15 +1568,8 @@
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ub_dev *sc = disk->private_data;
- unsigned long flags;
- spin_lock_irqsave(&ub_lock, flags);
- --sc->openc;
- if (sc->openc == 0)
- sc->first_open = 0;
- if (sc->openc == 0 && atomic_read(&sc->poison))
- ub_cleanup(sc);
- spin_unlock_irqrestore(&ub_lock, flags);
+ ub_put(sc);
return 0;
}
@@ -2048,9 +2064,7 @@
usb_set_intfdata(intf, NULL);
// usb_put_intf(sc->intf);
usb_put_dev(sc->dev);
- spin_lock_irq(&ub_lock);
ub_id_put(sc->id);
- spin_unlock_irq(&ub_lock);
err_id:
kfree(sc);
err_core:
@@ -2064,6 +2078,15 @@
unsigned long flags;
/*
+ * Prevent ub_bd_release from pulling the rug from under us.
+ * XXX This is starting to look like a kref.
+ * XXX Why not to take this ref at probe time?
+ */
+ spin_lock_irqsave(&ub_lock, flags);
+ sc->openc++;
+ spin_unlock_irqrestore(&ub_lock, flags);
+
+ /*
* Fence stall clearnings, operations triggered by unlinkings and so on.
* We do not attempt to unlink any URBs, because we do not trust the
* unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
@@ -2099,10 +2122,16 @@
spin_unlock_irqrestore(&sc->lock, flags);
/*
- * Unregister the upper layer, this waits for all commands to end.
+ * Unregister the upper layer.
*/
if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
+ /*
+ * I wish I could do:
+ * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
+ * As it is, we rely on our internal poisoning and let
+ * the upper levels to spin furiously failing all the I/O.
+ */
/*
* Taking a lock on a structure which is about to be freed
@@ -2138,10 +2167,7 @@
usb_put_dev(sc->dev);
sc->dev = NULL;
- spin_lock_irqsave(&ub_lock, flags);
- if (sc->openc == 0)
- ub_cleanup(sc);
- spin_unlock_irqrestore(&ub_lock, flags);
+ ub_put(sc);
}
static struct usb_driver ub_driver = {
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html