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

Reply via email to