diff options
author | Maxim Levitsky <maximlevitsky@gmail.com> | 2010-02-22 13:39:29 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-02-26 12:04:03 -0500 |
commit | a863862257b7dd08d855bafcb0aedd9ad848ed91 (patch) | |
tree | e5f3996d006e769b7f5517cab8fbdb334462ab85 /drivers/mtd/mtd_blkdevs.c | |
parent | 3bd456576f22acd55fb6c3d3d4261131821f5a3b (diff) |
mtd: blktrans: remove mtd_blkcore_priv, switch to per device queue and thread
This is the biggest change. To make hotplug possible, and this layer
clean, the mtd_blktrans_dev now contains everything for a single mtd
block translation device. Also removed some very old leftovers.
Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/mtd_blkdevs.c')
-rw-r--r-- | drivers/mtd/mtd_blkdevs.c | 124 |
1 files changed, 58 insertions, 66 deletions
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 2f8c202dbd86..6a572625bfc0 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/mtd/mtd.h> | 14 | #include <linux/mtd/mtd.h> |
15 | #include <linux/blkdev.h> | 15 | #include <linux/blkdev.h> |
16 | #include <linux/blkpg.h> | 16 | #include <linux/blkpg.h> |
17 | #include <linux/freezer.h> | ||
18 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
19 | #include <linux/hdreg.h> | 18 | #include <linux/hdreg.h> |
20 | #include <linux/init.h> | 19 | #include <linux/init.h> |
@@ -26,11 +25,6 @@ | |||
26 | 25 | ||
27 | static LIST_HEAD(blktrans_majors); | 26 | static LIST_HEAD(blktrans_majors); |
28 | 27 | ||
29 | struct mtd_blkcore_priv { | ||
30 | struct task_struct *thread; | ||
31 | struct request_queue *rq; | ||
32 | spinlock_t queue_lock; | ||
33 | }; | ||
34 | 28 | ||
35 | static int do_blktrans_request(struct mtd_blktrans_ops *tr, | 29 | static int do_blktrans_request(struct mtd_blktrans_ops *tr, |
36 | struct mtd_blktrans_dev *dev, | 30 | struct mtd_blktrans_dev *dev, |
@@ -61,7 +55,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, | |||
61 | return -EIO; | 55 | return -EIO; |
62 | rq_flush_dcache_pages(req); | 56 | rq_flush_dcache_pages(req); |
63 | return 0; | 57 | return 0; |
64 | |||
65 | case WRITE: | 58 | case WRITE: |
66 | if (!tr->writesect) | 59 | if (!tr->writesect) |
67 | return -EIO; | 60 | return -EIO; |
@@ -71,7 +64,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, | |||
71 | if (tr->writesect(dev, block, buf)) | 64 | if (tr->writesect(dev, block, buf)) |
72 | return -EIO; | 65 | return -EIO; |
73 | return 0; | 66 | return 0; |
74 | |||
75 | default: | 67 | default: |
76 | printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); | 68 | printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); |
77 | return -EIO; | 69 | return -EIO; |
@@ -80,14 +72,13 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, | |||
80 | 72 | ||
81 | static int mtd_blktrans_thread(void *arg) | 73 | static int mtd_blktrans_thread(void *arg) |
82 | { | 74 | { |
83 | struct mtd_blktrans_ops *tr = arg; | 75 | struct mtd_blktrans_dev *dev = arg; |
84 | struct request_queue *rq = tr->blkcore_priv->rq; | 76 | struct request_queue *rq = dev->rq; |
85 | struct request *req = NULL; | 77 | struct request *req = NULL; |
86 | 78 | ||
87 | spin_lock_irq(rq->queue_lock); | 79 | spin_lock_irq(rq->queue_lock); |
88 | 80 | ||
89 | while (!kthread_should_stop()) { | 81 | while (!kthread_should_stop()) { |
90 | struct mtd_blktrans_dev *dev; | ||
91 | int res; | 82 | int res; |
92 | 83 | ||
93 | if (!req && !(req = blk_fetch_request(rq))) { | 84 | if (!req && !(req = blk_fetch_request(rq))) { |
@@ -98,13 +89,10 @@ static int mtd_blktrans_thread(void *arg) | |||
98 | continue; | 89 | continue; |
99 | } | 90 | } |
100 | 91 | ||
101 | dev = req->rq_disk->private_data; | ||
102 | tr = dev->tr; | ||
103 | |||
104 | spin_unlock_irq(rq->queue_lock); | 92 | spin_unlock_irq(rq->queue_lock); |
105 | 93 | ||
106 | mutex_lock(&dev->lock); | 94 | mutex_lock(&dev->lock); |
107 | res = do_blktrans_request(tr, dev, req); | 95 | res = do_blktrans_request(dev->tr, dev, req); |
108 | mutex_unlock(&dev->lock); | 96 | mutex_unlock(&dev->lock); |
109 | 97 | ||
110 | spin_lock_irq(rq->queue_lock); | 98 | spin_lock_irq(rq->queue_lock); |
@@ -123,8 +111,8 @@ static int mtd_blktrans_thread(void *arg) | |||
123 | 111 | ||
124 | static void mtd_blktrans_request(struct request_queue *rq) | 112 | static void mtd_blktrans_request(struct request_queue *rq) |
125 | { | 113 | { |
126 | struct mtd_blktrans_ops *tr = rq->queuedata; | 114 | struct mtd_blktrans_dev *dev = rq->queuedata; |
127 | wake_up_process(tr->blkcore_priv->thread); | 115 | wake_up_process(dev->thread); |
128 | } | 116 | } |
129 | 117 | ||
130 | 118 | ||
@@ -214,6 +202,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
214 | struct mtd_blktrans_dev *d; | 202 | struct mtd_blktrans_dev *d; |
215 | int last_devnum = -1; | 203 | int last_devnum = -1; |
216 | struct gendisk *gd; | 204 | struct gendisk *gd; |
205 | int ret; | ||
217 | 206 | ||
218 | if (mutex_trylock(&mtd_table_mutex)) { | 207 | if (mutex_trylock(&mtd_table_mutex)) { |
219 | mutex_unlock(&mtd_table_mutex); | 208 | mutex_unlock(&mtd_table_mutex); |
@@ -239,6 +228,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
239 | } | 228 | } |
240 | last_devnum = d->devnum; | 229 | last_devnum = d->devnum; |
241 | } | 230 | } |
231 | |||
232 | ret = -EBUSY; | ||
242 | if (new->devnum == -1) | 233 | if (new->devnum == -1) |
243 | new->devnum = last_devnum+1; | 234 | new->devnum = last_devnum+1; |
244 | 235 | ||
@@ -247,7 +238,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
247 | * with this number. */ | 238 | * with this number. */ |
248 | if (new->devnum > (MINORMASK >> tr->part_bits) || | 239 | if (new->devnum > (MINORMASK >> tr->part_bits) || |
249 | (tr->part_bits && new->devnum >= 27 * 26)) | 240 | (tr->part_bits && new->devnum >= 27 * 26)) |
250 | return -EBUSY; | 241 | goto error1; |
251 | 242 | ||
252 | list_add_tail(&new->list, &tr->devs); | 243 | list_add_tail(&new->list, &tr->devs); |
253 | added: | 244 | added: |
@@ -255,11 +246,16 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
255 | if (!tr->writesect) | 246 | if (!tr->writesect) |
256 | new->readonly = 1; | 247 | new->readonly = 1; |
257 | 248 | ||
249 | |||
250 | /* Create gendisk */ | ||
251 | ret = -ENOMEM; | ||
258 | gd = alloc_disk(1 << tr->part_bits); | 252 | gd = alloc_disk(1 << tr->part_bits); |
259 | if (!gd) { | 253 | |
260 | list_del(&new->list); | 254 | if (!gd) |
261 | return -ENOMEM; | 255 | goto error2; |
262 | } | 256 | |
257 | new->disk = gd; | ||
258 | gd->private_data = new; | ||
263 | gd->major = tr->major; | 259 | gd->major = tr->major; |
264 | gd->first_minor = (new->devnum) << tr->part_bits; | 260 | gd->first_minor = (new->devnum) << tr->part_bits; |
265 | gd->fops = &mtd_blktrans_ops; | 261 | gd->fops = &mtd_blktrans_ops; |
@@ -277,21 +273,49 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
277 | snprintf(gd->disk_name, sizeof(gd->disk_name), | 273 | snprintf(gd->disk_name, sizeof(gd->disk_name), |
278 | "%s%d", tr->name, new->devnum); | 274 | "%s%d", tr->name, new->devnum); |
279 | 275 | ||
280 | /* 2.5 has capacity in units of 512 bytes while still | ||
281 | having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ | ||
282 | set_capacity(gd, (new->size * tr->blksize) >> 9); | 276 | set_capacity(gd, (new->size * tr->blksize) >> 9); |
283 | 277 | ||
284 | gd->private_data = new; | 278 | |
285 | new->blkcore_priv = gd; | 279 | /* Create the request queue */ |
286 | gd->queue = tr->blkcore_priv->rq; | 280 | spin_lock_init(&new->queue_lock); |
281 | new->rq = blk_init_queue(mtd_blktrans_request, &new->queue_lock); | ||
282 | |||
283 | if (!new->rq) | ||
284 | goto error3; | ||
285 | |||
286 | new->rq->queuedata = new; | ||
287 | blk_queue_logical_block_size(new->rq, tr->blksize); | ||
288 | |||
289 | if (tr->discard) | ||
290 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, | ||
291 | new->rq); | ||
292 | |||
293 | gd->queue = new->rq; | ||
294 | |||
295 | /* Create processing thread */ | ||
296 | /* TODO: workqueue ? */ | ||
297 | new->thread = kthread_run(mtd_blktrans_thread, new, | ||
298 | "%s%d", tr->name, new->mtd->index); | ||
299 | if (IS_ERR(new->thread)) { | ||
300 | ret = PTR_ERR(new->thread); | ||
301 | goto error4; | ||
302 | } | ||
287 | gd->driverfs_dev = &new->mtd->dev; | 303 | gd->driverfs_dev = &new->mtd->dev; |
288 | 304 | ||
289 | if (new->readonly) | 305 | if (new->readonly) |
290 | set_disk_ro(gd, 1); | 306 | set_disk_ro(gd, 1); |
291 | 307 | ||
292 | add_disk(gd); | 308 | add_disk(gd); |
293 | |||
294 | return 0; | 309 | return 0; |
310 | error4: | ||
311 | blk_cleanup_queue(new->rq); | ||
312 | error3: | ||
313 | put_disk(new->disk); | ||
314 | error2: | ||
315 | list_del(&new->list); | ||
316 | error1: | ||
317 | kfree(new); | ||
318 | return ret; | ||
295 | } | 319 | } |
296 | 320 | ||
297 | int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) | 321 | int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) |
@@ -303,9 +327,13 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) | |||
303 | 327 | ||
304 | list_del(&old->list); | 328 | list_del(&old->list); |
305 | 329 | ||
306 | del_gendisk(old->blkcore_priv); | 330 | /* stop new requests to arrive */ |
307 | put_disk(old->blkcore_priv); | 331 | del_gendisk(old->disk); |
308 | 332 | ||
333 | /* Stop the thread */ | ||
334 | kthread_stop(old->thread); | ||
335 | |||
336 | blk_cleanup_queue(old->rq); | ||
309 | return 0; | 337 | return 0; |
310 | } | 338 | } |
311 | 339 | ||
@@ -347,9 +375,6 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
347 | if (!blktrans_notifier.list.next) | 375 | if (!blktrans_notifier.list.next) |
348 | register_mtd_user(&blktrans_notifier); | 376 | register_mtd_user(&blktrans_notifier); |
349 | 377 | ||
350 | tr->blkcore_priv = kzalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); | ||
351 | if (!tr->blkcore_priv) | ||
352 | return -ENOMEM; | ||
353 | 378 | ||
354 | mutex_lock(&mtd_table_mutex); | 379 | mutex_lock(&mtd_table_mutex); |
355 | 380 | ||
@@ -357,39 +382,12 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
357 | if (ret) { | 382 | if (ret) { |
358 | printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", | 383 | printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", |
359 | tr->name, tr->major, ret); | 384 | tr->name, tr->major, ret); |
360 | kfree(tr->blkcore_priv); | ||
361 | mutex_unlock(&mtd_table_mutex); | 385 | mutex_unlock(&mtd_table_mutex); |
362 | return ret; | 386 | return ret; |
363 | } | 387 | } |
364 | spin_lock_init(&tr->blkcore_priv->queue_lock); | ||
365 | |||
366 | tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock); | ||
367 | if (!tr->blkcore_priv->rq) { | ||
368 | unregister_blkdev(tr->major, tr->name); | ||
369 | kfree(tr->blkcore_priv); | ||
370 | mutex_unlock(&mtd_table_mutex); | ||
371 | return -ENOMEM; | ||
372 | } | ||
373 | |||
374 | tr->blkcore_priv->rq->queuedata = tr; | ||
375 | blk_queue_logical_block_size(tr->blkcore_priv->rq, tr->blksize); | ||
376 | if (tr->discard) | ||
377 | queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, | ||
378 | tr->blkcore_priv->rq); | ||
379 | 388 | ||
380 | tr->blkshift = ffs(tr->blksize) - 1; | 389 | tr->blkshift = ffs(tr->blksize) - 1; |
381 | 390 | ||
382 | tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr, | ||
383 | "%sd", tr->name); | ||
384 | if (IS_ERR(tr->blkcore_priv->thread)) { | ||
385 | ret = PTR_ERR(tr->blkcore_priv->thread); | ||
386 | blk_cleanup_queue(tr->blkcore_priv->rq); | ||
387 | unregister_blkdev(tr->major, tr->name); | ||
388 | kfree(tr->blkcore_priv); | ||
389 | mutex_unlock(&mtd_table_mutex); | ||
390 | return ret; | ||
391 | } | ||
392 | |||
393 | INIT_LIST_HEAD(&tr->devs); | 391 | INIT_LIST_HEAD(&tr->devs); |
394 | list_add(&tr->list, &blktrans_majors); | 392 | list_add(&tr->list, &blktrans_majors); |
395 | 393 | ||
@@ -408,8 +406,6 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
408 | 406 | ||
409 | mutex_lock(&mtd_table_mutex); | 407 | mutex_lock(&mtd_table_mutex); |
410 | 408 | ||
411 | /* Clean up the kernel thread */ | ||
412 | kthread_stop(tr->blkcore_priv->thread); | ||
413 | 409 | ||
414 | /* Remove it from the list of active majors */ | 410 | /* Remove it from the list of active majors */ |
415 | list_del(&tr->list); | 411 | list_del(&tr->list); |
@@ -417,13 +413,9 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
417 | list_for_each_entry_safe(dev, next, &tr->devs, list) | 413 | list_for_each_entry_safe(dev, next, &tr->devs, list) |
418 | tr->remove_dev(dev); | 414 | tr->remove_dev(dev); |
419 | 415 | ||
420 | blk_cleanup_queue(tr->blkcore_priv->rq); | ||
421 | unregister_blkdev(tr->major, tr->name); | 416 | unregister_blkdev(tr->major, tr->name); |
422 | |||
423 | mutex_unlock(&mtd_table_mutex); | 417 | mutex_unlock(&mtd_table_mutex); |
424 | 418 | ||
425 | kfree(tr->blkcore_priv); | ||
426 | |||
427 | BUG_ON(!list_empty(&tr->devs)); | 419 | BUG_ON(!list_empty(&tr->devs)); |
428 | return 0; | 420 | return 0; |
429 | } | 421 | } |