summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtd_blkdevs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/mtd_blkdevs.c')
-rw-r--r--drivers/mtd/mtd_blkdevs.c95
1 files changed, 57 insertions, 38 deletions
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 03e19c1965cc..cb20c67995d8 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -1,7 +1,21 @@
/*
- * (C) 2003 David Woodhouse <dwmw2@infradead.org>
+ * Interface to Linux block layer for MTD 'translation layers'.
*
- * Interface to Linux 2.5 block layer for MTD 'translation layers'.
+ * Copyright © 2003-2010 David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
@@ -73,14 +87,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
buf = req->buffer;
- if (!blk_fs_request(req))
+ if (req->cmd_type != REQ_TYPE_FS)
return -EIO;
if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
get_capacity(req->rq_disk))
return -EIO;
- if (blk_discard_rq(req))
+ if (req->cmd_flags & REQ_DISCARD)
return tr->discard(dev, block, nsect);
switch(rq_data_dir(req)) {
@@ -118,6 +132,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);
@@ -161,24 +179,24 @@ 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;
+ return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/
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);
@@ -188,20 +206,23 @@ 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;
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);
@@ -245,6 +266,7 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode,
switch (cmd) {
case BLKFLSBUF:
ret = dev->tr->flush ? dev->tr->flush(dev) : 0;
+ break;
default:
ret = -ENOTTY;
}
@@ -258,7 +280,7 @@ static const struct block_device_operations mtd_blktrans_ops = {
.owner = THIS_MODULE,
.open = blktrans_open,
.release = blktrans_release,
- .locked_ioctl = blktrans_ioctl,
+ .ioctl = blktrans_ioctl,
.getgeo = blktrans_getgeo,
};
@@ -363,9 +385,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,
@@ -388,8 +407,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);
@@ -409,13 +426,14 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
BUG();
}
- /* Stop new requests to arrive */
- del_gendisk(old->disk);
-
if (old->disk_attributes)
sysfs_remove_group(&disk_to_dev(old->disk)->kobj,
old->disk_attributes);
+ /* Stop new requests to arrive */
+ del_gendisk(old->disk);
+
+
/* Stop the thread */
kthread_stop(old->thread);
@@ -425,17 +443,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);
@@ -485,13 +501,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);