aboutsummaryrefslogtreecommitdiffstats
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.c68
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
40static DEFINE_MUTEX(mtd_blkdevs_mutex);
41static LIST_HEAD(blktrans_majors); 40static LIST_HEAD(blktrans_majors);
42static DEFINE_MUTEX(blktrans_ref_mutex); 41static 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)
176static int blktrans_open(struct block_device *bdev, fmode_t mode) 179static 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);
198unlock: 200unlock:
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
205static int blktrans_release(struct gendisk *disk, fmode_t mode) 206static 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 }
223unlock: 226unlock:
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 }
272unlock: 273unlock:
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;
412error4: 409error4:
413 module_put(tr->owner);
414 __put_mtd_device(new->mtd);
415 blk_cleanup_queue(new->rq); 410 blk_cleanup_queue(new->rq);
416error3: 411error3:
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);