diff options
Diffstat (limited to 'drivers/mtd/mtd_blkdevs.c')
| -rw-r--r-- | drivers/mtd/mtd_blkdevs.c | 68 |
1 files changed, 32 insertions, 36 deletions
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 50ab431b24eb..cb20c67995d8 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
| @@ -37,7 +37,6 @@ | |||
| 37 | 37 | ||
| 38 | #include "mtdcore.h" | 38 | #include "mtdcore.h" |
| 39 | 39 | ||
| 40 | static DEFINE_MUTEX(mtd_blkdevs_mutex); | ||
| 41 | static LIST_HEAD(blktrans_majors); | 40 | static LIST_HEAD(blktrans_majors); |
| 42 | static DEFINE_MUTEX(blktrans_ref_mutex); | 41 | static DEFINE_MUTEX(blktrans_ref_mutex); |
| 43 | 42 | ||
| @@ -133,6 +132,10 @@ static int mtd_blktrans_thread(void *arg) | |||
| 133 | 132 | ||
| 134 | if (!req && !(req = blk_fetch_request(rq))) { | 133 | if (!req && !(req = blk_fetch_request(rq))) { |
| 135 | set_current_state(TASK_INTERRUPTIBLE); | 134 | set_current_state(TASK_INTERRUPTIBLE); |
| 135 | |||
| 136 | if (kthread_should_stop()) | ||
| 137 | set_current_state(TASK_RUNNING); | ||
| 138 | |||
| 136 | spin_unlock_irq(rq->queue_lock); | 139 | spin_unlock_irq(rq->queue_lock); |
| 137 | schedule(); | 140 | schedule(); |
| 138 | spin_lock_irq(rq->queue_lock); | 141 | spin_lock_irq(rq->queue_lock); |
| @@ -176,54 +179,53 @@ static void mtd_blktrans_request(struct request_queue *rq) | |||
| 176 | static int blktrans_open(struct block_device *bdev, fmode_t mode) | 179 | static int blktrans_open(struct block_device *bdev, fmode_t mode) |
| 177 | { | 180 | { |
| 178 | struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); | 181 | struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); |
| 179 | int ret; | 182 | int ret = 0; |
| 180 | 183 | ||
| 181 | if (!dev) | 184 | if (!dev) |
| 182 | return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ | 185 | return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ |
| 183 | 186 | ||
| 184 | mutex_lock(&mtd_blkdevs_mutex); | ||
| 185 | mutex_lock(&dev->lock); | 187 | mutex_lock(&dev->lock); |
| 186 | 188 | ||
| 187 | if (!dev->mtd) { | 189 | if (dev->open++) |
| 188 | ret = -ENXIO; | ||
| 189 | goto unlock; | 190 | goto unlock; |
| 190 | } | ||
| 191 | 191 | ||
| 192 | ret = !dev->open++ && dev->tr->open ? dev->tr->open(dev) : 0; | 192 | kref_get(&dev->ref); |
| 193 | __module_get(dev->tr->owner); | ||
| 194 | |||
| 195 | if (dev->mtd) { | ||
| 196 | ret = dev->tr->open ? dev->tr->open(dev) : 0; | ||
| 197 | __get_mtd_device(dev->mtd); | ||
| 198 | } | ||
| 193 | 199 | ||
| 194 | /* Take another reference on the device so it won't go away till | ||
| 195 | last release */ | ||
| 196 | if (!ret) | ||
| 197 | kref_get(&dev->ref); | ||
| 198 | unlock: | 200 | unlock: |
| 199 | mutex_unlock(&dev->lock); | 201 | mutex_unlock(&dev->lock); |
| 200 | blktrans_dev_put(dev); | 202 | blktrans_dev_put(dev); |
| 201 | mutex_unlock(&mtd_blkdevs_mutex); | ||
| 202 | return ret; | 203 | return ret; |
| 203 | } | 204 | } |
| 204 | 205 | ||
| 205 | static int blktrans_release(struct gendisk *disk, fmode_t mode) | 206 | static int blktrans_release(struct gendisk *disk, fmode_t mode) |
| 206 | { | 207 | { |
| 207 | struct mtd_blktrans_dev *dev = blktrans_dev_get(disk); | 208 | struct mtd_blktrans_dev *dev = blktrans_dev_get(disk); |
| 208 | int ret = -ENXIO; | 209 | int ret = 0; |
| 209 | 210 | ||
| 210 | if (!dev) | 211 | if (!dev) |
| 211 | return ret; | 212 | return ret; |
| 212 | 213 | ||
| 213 | mutex_lock(&mtd_blkdevs_mutex); | ||
| 214 | mutex_lock(&dev->lock); | 214 | mutex_lock(&dev->lock); |
| 215 | 215 | ||
| 216 | /* Release one reference, we sure its not the last one here*/ | 216 | if (--dev->open) |
| 217 | kref_put(&dev->ref, blktrans_dev_release); | ||
| 218 | |||
| 219 | if (!dev->mtd) | ||
| 220 | goto unlock; | 217 | goto unlock; |
| 221 | 218 | ||
| 222 | ret = !--dev->open && dev->tr->release ? dev->tr->release(dev) : 0; | 219 | kref_put(&dev->ref, blktrans_dev_release); |
| 220 | module_put(dev->tr->owner); | ||
| 221 | |||
| 222 | if (dev->mtd) { | ||
| 223 | ret = dev->tr->release ? dev->tr->release(dev) : 0; | ||
| 224 | __put_mtd_device(dev->mtd); | ||
| 225 | } | ||
| 223 | unlock: | 226 | unlock: |
| 224 | mutex_unlock(&dev->lock); | 227 | mutex_unlock(&dev->lock); |
| 225 | blktrans_dev_put(dev); | 228 | blktrans_dev_put(dev); |
| 226 | mutex_unlock(&mtd_blkdevs_mutex); | ||
| 227 | return ret; | 229 | return ret; |
| 228 | } | 230 | } |
| 229 | 231 | ||
| @@ -256,7 +258,6 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 256 | if (!dev) | 258 | if (!dev) |
| 257 | return ret; | 259 | return ret; |
| 258 | 260 | ||
| 259 | mutex_lock(&mtd_blkdevs_mutex); | ||
| 260 | mutex_lock(&dev->lock); | 261 | mutex_lock(&dev->lock); |
| 261 | 262 | ||
| 262 | if (!dev->mtd) | 263 | if (!dev->mtd) |
| @@ -271,7 +272,6 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, | |||
| 271 | } | 272 | } |
| 272 | unlock: | 273 | unlock: |
| 273 | mutex_unlock(&dev->lock); | 274 | mutex_unlock(&dev->lock); |
| 274 | mutex_unlock(&mtd_blkdevs_mutex); | ||
| 275 | blktrans_dev_put(dev); | 275 | blktrans_dev_put(dev); |
| 276 | return ret; | 276 | return ret; |
| 277 | } | 277 | } |
| @@ -385,9 +385,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
| 385 | 385 | ||
| 386 | gd->queue = new->rq; | 386 | gd->queue = new->rq; |
| 387 | 387 | ||
| 388 | __get_mtd_device(new->mtd); | ||
| 389 | __module_get(tr->owner); | ||
| 390 | |||
| 391 | /* Create processing thread */ | 388 | /* Create processing thread */ |
| 392 | /* TODO: workqueue ? */ | 389 | /* TODO: workqueue ? */ |
| 393 | new->thread = kthread_run(mtd_blktrans_thread, new, | 390 | new->thread = kthread_run(mtd_blktrans_thread, new, |
| @@ -410,8 +407,6 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
| 410 | } | 407 | } |
| 411 | return 0; | 408 | return 0; |
| 412 | error4: | 409 | error4: |
| 413 | module_put(tr->owner); | ||
| 414 | __put_mtd_device(new->mtd); | ||
| 415 | blk_cleanup_queue(new->rq); | 410 | blk_cleanup_queue(new->rq); |
| 416 | error3: | 411 | error3: |
| 417 | put_disk(new->disk); | 412 | put_disk(new->disk); |
| @@ -448,17 +443,15 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) | |||
| 448 | blk_start_queue(old->rq); | 443 | blk_start_queue(old->rq); |
| 449 | spin_unlock_irqrestore(&old->queue_lock, flags); | 444 | spin_unlock_irqrestore(&old->queue_lock, flags); |
| 450 | 445 | ||
| 451 | /* Ask trans driver for release to the mtd device */ | 446 | /* If the device is currently open, tell trans driver to close it, |
| 447 | then put mtd device, and don't touch it again */ | ||
| 452 | mutex_lock(&old->lock); | 448 | mutex_lock(&old->lock); |
| 453 | if (old->open && old->tr->release) { | 449 | if (old->open) { |
| 454 | old->tr->release(old); | 450 | if (old->tr->release) |
| 455 | old->open = 0; | 451 | old->tr->release(old); |
| 452 | __put_mtd_device(old->mtd); | ||
| 456 | } | 453 | } |
| 457 | 454 | ||
| 458 | __put_mtd_device(old->mtd); | ||
| 459 | module_put(old->tr->owner); | ||
| 460 | |||
| 461 | /* At that point, we don't touch the mtd anymore */ | ||
| 462 | old->mtd = NULL; | 455 | old->mtd = NULL; |
| 463 | 456 | ||
| 464 | mutex_unlock(&old->lock); | 457 | mutex_unlock(&old->lock); |
| @@ -508,13 +501,16 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
| 508 | mutex_lock(&mtd_table_mutex); | 501 | mutex_lock(&mtd_table_mutex); |
| 509 | 502 | ||
| 510 | ret = register_blkdev(tr->major, tr->name); | 503 | ret = register_blkdev(tr->major, tr->name); |
| 511 | if (ret) { | 504 | if (ret < 0) { |
| 512 | printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", | 505 | printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", |
| 513 | tr->name, tr->major, ret); | 506 | tr->name, tr->major, ret); |
| 514 | mutex_unlock(&mtd_table_mutex); | 507 | mutex_unlock(&mtd_table_mutex); |
| 515 | return ret; | 508 | return ret; |
| 516 | } | 509 | } |
| 517 | 510 | ||
| 511 | if (ret) | ||
| 512 | tr->major = ret; | ||
| 513 | |||
| 518 | tr->blkshift = ffs(tr->blksize) - 1; | 514 | tr->blkshift = ffs(tr->blksize) - 1; |
| 519 | 515 | ||
| 520 | INIT_LIST_HEAD(&tr->devs); | 516 | INIT_LIST_HEAD(&tr->devs); |
