Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux...
[pandora-kernel.git] / drivers / mtd / mtd_blkdevs.c
index 50ab431..f932979 100644 (file)
@@ -133,6 +133,10 @@ static int mtd_blktrans_thread(void *arg)
 
                if (!req && !(req = blk_fetch_request(rq))) {
                        set_current_state(TASK_INTERRUPTIBLE);
+
+                       if (kthread_should_stop())
+                               set_current_state(TASK_RUNNING);
+
                        spin_unlock_irq(rq->queue_lock);
                        schedule();
                        spin_lock_irq(rq->queue_lock);
@@ -176,7 +180,7 @@ static void mtd_blktrans_request(struct request_queue *rq)
 static int blktrans_open(struct block_device *bdev, fmode_t mode)
 {
        struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk);
-       int ret;
+       int ret = 0;
 
        if (!dev)
                return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/
@@ -184,17 +188,17 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
        mutex_lock(&mtd_blkdevs_mutex);
        mutex_lock(&dev->lock);
 
-       if (!dev->mtd) {
-               ret = -ENXIO;
+       if (dev->open++)
                goto unlock;
-       }
 
-       ret = !dev->open++ && dev->tr->open ? dev->tr->open(dev) : 0;
+       kref_get(&dev->ref);
+       __module_get(dev->tr->owner);
+
+       if (dev->mtd) {
+               ret = dev->tr->open ? dev->tr->open(dev) : 0;
+               __get_mtd_device(dev->mtd);
+       }
 
-       /* Take another reference on the device so it won't go away till
-               last release */
-       if (!ret)
-               kref_get(&dev->ref);
 unlock:
        mutex_unlock(&dev->lock);
        blktrans_dev_put(dev);
@@ -205,7 +209,7 @@ unlock:
 static int blktrans_release(struct gendisk *disk, fmode_t mode)
 {
        struct mtd_blktrans_dev *dev = blktrans_dev_get(disk);
-       int ret = -ENXIO;
+       int ret = 0;
 
        if (!dev)
                return ret;
@@ -213,13 +217,16 @@ static int blktrans_release(struct gendisk *disk, fmode_t mode)
        mutex_lock(&mtd_blkdevs_mutex);
        mutex_lock(&dev->lock);
 
-       /* Release one reference, we sure its not the last one here*/
-       kref_put(&dev->ref, blktrans_dev_release);
-
-       if (!dev->mtd)
+       if (--dev->open)
                goto unlock;
 
-       ret = !--dev->open && dev->tr->release ? dev->tr->release(dev) : 0;
+       kref_put(&dev->ref, blktrans_dev_release);
+       module_put(dev->tr->owner);
+
+       if (dev->mtd) {
+               ret = dev->tr->release ? dev->tr->release(dev) : 0;
+               __put_mtd_device(dev->mtd);
+       }
 unlock:
        mutex_unlock(&dev->lock);
        blktrans_dev_put(dev);
@@ -385,9 +392,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 
        gd->queue = new->rq;
 
-       __get_mtd_device(new->mtd);
-       __module_get(tr->owner);
-
        /* Create processing thread */
        /* TODO: workqueue ? */
        new->thread = kthread_run(mtd_blktrans_thread, new,
@@ -410,8 +414,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        }
        return 0;
 error4:
-       module_put(tr->owner);
-       __put_mtd_device(new->mtd);
        blk_cleanup_queue(new->rq);
 error3:
        put_disk(new->disk);
@@ -448,17 +450,15 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
        blk_start_queue(old->rq);
        spin_unlock_irqrestore(&old->queue_lock, flags);
 
-       /* Ask trans driver for release to the mtd device */
+       /* If the device is currently open, tell trans driver to close it,
+               then put mtd device, and don't touch it again */
        mutex_lock(&old->lock);
-       if (old->open && old->tr->release) {
-               old->tr->release(old);
-               old->open = 0;
+       if (old->open) {
+               if (old->tr->release)
+                       old->tr->release(old);
+               __put_mtd_device(old->mtd);
        }
 
-       __put_mtd_device(old->mtd);
-       module_put(old->tr->owner);
-
-       /* At that point, we don't touch the mtd anymore */
        old->mtd = NULL;
 
        mutex_unlock(&old->lock);
@@ -508,13 +508,16 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
        mutex_lock(&mtd_table_mutex);
 
        ret = register_blkdev(tr->major, tr->name);
-       if (ret) {
+       if (ret < 0) {
                printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
                       tr->name, tr->major, ret);
                mutex_unlock(&mtd_table_mutex);
                return ret;
        }
 
+       if (ret)
+               tr->major = ret;
+
        tr->blkshift = ffs(tr->blksize) - 1;
 
        INIT_LIST_HEAD(&tr->devs);