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); |