2
* $Id: mtd_blkdevs-24.c,v 1.17 2005/01/05 17:35:22 dwmw2 Exp $
4
* (C) 2003 David Woodhouse <dwmw2@infradead.org>
6
* Interface to Linux 2.4 block layer for MTD 'translation layers'.
10
#include <linux/kernel.h>
11
#include <linux/slab.h>
12
#include <linux/module.h>
13
#include <linux/list.h>
15
#include <linux/mtd/blktrans.h>
16
#include <linux/mtd/mtd.h>
17
#include <linux/blkdev.h>
18
#include <linux/blk.h>
19
#include <linux/blkpg.h>
20
#include <linux/spinlock.h>
21
#include <linux/hdreg.h>
22
#include <linux/init.h>
23
#include <asm/semaphore.h>
24
#include <asm/uaccess.h>
26
static LIST_HEAD(blktrans_majors);
28
extern struct semaphore mtd_table_mutex;
29
extern struct mtd_info *mtd_table[];
31
struct mtd_blkcore_priv {
32
devfs_handle_t devfs_dir_handle;
35
struct hd_struct part_table[256];
37
spinlock_t devs_lock; /* See comment in _request function */
38
struct completion thread_dead;
40
wait_queue_head_t thread_wq;
43
static inline struct mtd_blktrans_dev *tr_get_dev(struct mtd_blktrans_ops *tr,
46
struct list_head *this;
47
struct mtd_blktrans_dev *d;
49
list_for_each(this, &tr->devs) {
50
d = list_entry(this, struct mtd_blktrans_dev, list);
52
if (d->devnum == devnum)
58
static inline struct mtd_blktrans_ops *get_tr(int major)
60
struct list_head *this;
61
struct mtd_blktrans_ops *t;
63
list_for_each(this, &blktrans_majors) {
64
t = list_entry(this, struct mtd_blktrans_ops, list);
66
if (t->major == major)
72
static int do_blktrans_request(struct mtd_blktrans_ops *tr,
73
struct mtd_blktrans_dev *dev,
76
unsigned long block, nsect;
80
minor = MINOR(req->rq_dev);
82
nsect = req->current_nr_sectors;
85
if (block + nsect > tr->blkcore_priv->part_table[minor].nr_sects) {
86
printk(KERN_WARNING "Access beyond end of device.\n");
89
block += tr->blkcore_priv->part_table[minor].start_sect;
93
for (; nsect > 0; nsect--, block++, buf += 512)
94
if (tr->readsect(dev, block, buf))
102
for (; nsect > 0; nsect--, block++, buf += 512)
103
if (tr->writesect(dev, block, buf))
108
printk(KERN_NOTICE "Unknown request cmd %d\n", req->cmd);
113
static int mtd_blktrans_thread(void *arg)
115
struct mtd_blktrans_ops *tr = arg;
116
struct request_queue *rq = BLK_DEFAULT_QUEUE(tr->major);
118
/* we might get involved when memory gets low, so use PF_MEMALLOC */
119
current->flags |= PF_MEMALLOC;
121
snprintf(current->comm, sizeof(current->comm), "%sd", tr->name);
123
/* daemonize() doesn't do this for us since some kernel threads
124
actually want to deal with signals. We can't just call
125
exit_sighand() since that'll cause an oops when we finally
127
spin_lock_irq(¤t->sigmask_lock);
128
sigfillset(¤t->blocked);
130
spin_unlock_irq(¤t->sigmask_lock);
132
daemonize("%sd", tr->name);
134
while (!tr->blkcore_priv->exiting) {
136
struct mtd_blktrans_dev *dev;
139
DECLARE_WAITQUEUE(wait, current);
141
spin_lock_irq(&io_request_lock);
143
if (list_empty(&rq->queue_head)) {
145
add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
146
set_current_state(TASK_INTERRUPTIBLE);
148
spin_unlock_irq(&io_request_lock);
151
remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
156
req = blkdev_entry_next_request(&rq->queue_head);
158
devnum = MINOR(req->rq_dev) >> tr->part_bits;
160
/* The ll_rw_blk code knows not to touch the request
161
at the head of the queue */
162
spin_unlock_irq(&io_request_lock);
164
/* FIXME: Where can we store the dev, on which
165
we already have a refcount anyway? We need to
166
lock against concurrent addition/removal of devices,
167
but if we use the mtd_table_mutex we deadlock when
168
grok_partitions is called from the registration
170
spin_lock(&tr->blkcore_priv->devs_lock);
171
dev = tr_get_dev(tr, devnum);
172
spin_unlock(&tr->blkcore_priv->devs_lock);
176
/* Ensure serialisation of requests */
179
res = do_blktrans_request(tr, dev, req);
182
if (!end_that_request_first(req, res, tr->name)) {
183
spin_lock_irq(&io_request_lock);
184
blkdev_dequeue_request(req);
185
end_that_request_last(req);
186
spin_unlock_irq(&io_request_lock);
189
complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
192
static void mtd_blktrans_request(struct request_queue *rq)
194
struct mtd_blktrans_ops *tr = rq->queuedata;
195
wake_up(&tr->blkcore_priv->thread_wq);
198
int blktrans_open(struct inode *i, struct file *f)
200
struct mtd_blktrans_ops *tr = NULL;
201
struct mtd_blktrans_dev *dev = NULL;
202
int major_nr = MAJOR(i->i_rdev);
203
int minor_nr = MINOR(i->i_rdev);
207
if (is_read_only(i->i_rdev) && (f->f_mode & FMODE_WRITE))
210
down(&mtd_table_mutex);
212
tr = get_tr(major_nr);
217
devnum = minor_nr >> tr->part_bits;
219
dev = tr_get_dev(tr, devnum);
224
if (!tr->blkcore_priv->part_table[minor_nr].nr_sects) {
229
if (!try_inc_mod_count(dev->mtd->owner))
232
if (!try_inc_mod_count(tr->owner))
235
dev->mtd->usecount++;
238
if (tr->open && (ret = tr->open(dev))) {
239
dev->mtd->usecount--;
241
__MOD_DEC_USE_COUNT(dev->mtd->owner);
244
__MOD_DEC_USE_COUNT(tr->owner);
247
up(&mtd_table_mutex);
252
int blktrans_release(struct inode *i, struct file *f)
254
struct mtd_blktrans_dev *dev;
255
struct mtd_blktrans_ops *tr;
259
down(&mtd_table_mutex);
261
tr = get_tr(MAJOR(i->i_rdev));
263
up(&mtd_table_mutex);
267
devnum = MINOR(i->i_rdev) >> tr->part_bits;
268
dev = tr_get_dev(tr, devnum);
271
up(&mtd_table_mutex);
276
ret = tr->release(dev);
279
dev->mtd->usecount--;
281
__MOD_DEC_USE_COUNT(dev->mtd->owner);
283
__MOD_DEC_USE_COUNT(tr->owner);
286
up(&mtd_table_mutex);
291
static int mtd_blktrans_rrpart(kdev_t rdev, struct mtd_blktrans_ops *tr,
292
struct mtd_blktrans_dev *dev)
294
struct gendisk *gd = &(tr->blkcore_priv->gd);
296
int minor = MINOR(rdev);
298
if (minor & ((1<<tr->part_bits)-1) || !tr->part_bits) {
299
/* BLKRRPART on a partition. Go away. */
303
if (!capable(CAP_SYS_ADMIN))
306
/* We are required to prevent simultaneous open() ourselves.
307
The core doesn't do that for us. Did I ever mention how
308
much the Linux block layer sucks? Sledgehammer approach... */
309
down(&mtd_table_mutex);
311
for (i=0; i < (1<<tr->part_bits); i++) {
312
invalidate_device(MKDEV(tr->major, minor+i), 1);
313
gd->part[minor + i].start_sect = 0;
314
gd->part[minor + i].nr_sects = 0;
317
grok_partitions(gd, minor, 1 << tr->part_bits,
319
up(&mtd_table_mutex);
324
static int blktrans_ioctl(struct inode *inode, struct file *file,
325
unsigned int cmd, unsigned long arg)
327
struct mtd_blktrans_dev *dev;
328
struct mtd_blktrans_ops *tr;
343
return blk_ioctl(inode->i_rdev, cmd, arg);
346
down(&mtd_table_mutex);
348
tr = get_tr(MAJOR(inode->i_rdev));
350
up(&mtd_table_mutex);
354
devnum = MINOR(inode->i_rdev) >> tr->part_bits;
355
dev = tr_get_dev(tr, devnum);
357
up(&mtd_table_mutex);
364
return mtd_blktrans_rrpart(inode->i_rdev, tr, dev);
367
blk_ioctl(inode->i_rdev, cmd, arg);
369
return tr->flush(dev);
370
/* The core code did the work, we had nothing to do. */
375
struct hd_geometry g;
376
struct gendisk *gd = &(tr->blkcore_priv->gd);
379
memset(&g, 0, sizeof(g));
380
ret = tr->getgeo(dev, &g);
384
g.start = gd->part[MINOR(inode->i_rdev)].start_sect;
385
if (copy_to_user((void *)arg, &g, sizeof(g)))
394
struct block_device_operations mtd_blktrans_ops = {
395
.owner = THIS_MODULE,
396
.open = blktrans_open,
397
.release = blktrans_release,
398
.ioctl = blktrans_ioctl,
401
int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
403
struct mtd_blktrans_ops *tr = new->tr;
404
struct list_head *this;
405
int last_devnum = -1;
408
if (!down_trylock(&mtd_table_mutex)) {
409
up(&mtd_table_mutex);
413
spin_lock(&tr->blkcore_priv->devs_lock);
415
list_for_each(this, &tr->devs) {
416
struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list);
417
if (new->devnum == -1) {
418
/* Use first free number */
419
if (d->devnum != last_devnum+1) {
420
/* Found a free devnum. Plug it in here */
421
new->devnum = last_devnum+1;
422
list_add_tail(&new->list, &d->list);
425
} else if (d->devnum == new->devnum) {
426
/* Required number taken */
427
spin_unlock(&tr->blkcore_priv->devs_lock);
429
} else if (d->devnum > new->devnum) {
430
/* Required number was free */
431
list_add_tail(&new->list, &d->list);
434
last_devnum = d->devnum;
436
if (new->devnum == -1)
437
new->devnum = last_devnum+1;
439
if ((new->devnum << tr->part_bits) > 256) {
440
spin_unlock(&tr->blkcore_priv->devs_lock);
444
init_MUTEX(&new->sem);
445
list_add_tail(&new->list, &tr->devs);
447
spin_unlock(&tr->blkcore_priv->devs_lock);
452
for (i = new->devnum << tr->part_bits;
453
i < (new->devnum+1) << tr->part_bits;
455
set_device_ro(MKDEV(tr->major, i), new->readonly);
456
tr->blkcore_priv->blksizes[i] = new->blksize;
457
tr->blkcore_priv->sizes[i] = 0;
458
tr->blkcore_priv->part_table[i].nr_sects = 0;
459
tr->blkcore_priv->part_table[i].start_sect = 0;
463
<viro_zzz> dwmw2: BLOCK_SIZE_BITS has nothing to do with block devices
464
<viro> dwmw2: any code which sets blk_size[][] should be
465
size >> 10 /+ 2.4 and its dumb units */
467
tr->blkcore_priv->sizes[new->devnum << tr->part_bits] =
468
(new->size * new->blksize) >> 10; /* 2.4 and its dumb units */
470
/* But this is still in device's sectors? $DEITY knows */
471
tr->blkcore_priv->part_table[new->devnum << tr->part_bits].nr_sects = new->size;
474
grok_partitions(&tr->blkcore_priv->gd, new->devnum,
475
1 << tr->part_bits, new->size);
477
#ifdef CONFIG_DEVFS_FS
478
if (!tr->part_bits) {
481
name[0] = '0' + new->devnum;
485
devfs_register(tr->blkcore_priv->devfs_dir_handle,
486
name, DEVFS_FL_DEFAULT, tr->major,
487
new->devnum, S_IFBLK|S_IRUGO|S_IWUGO,
488
&mtd_blktrans_ops, NULL);
494
int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
496
struct mtd_blktrans_ops *tr = old->tr;
499
if (!down_trylock(&mtd_table_mutex)) {
500
up(&mtd_table_mutex);
504
#ifdef CONFIG_DEVFS_FS
505
if (!tr->part_bits) {
506
devfs_unregister(old->blkcore_priv);
507
old->blkcore_priv = NULL;
509
devfs_register_partitions(&tr->blkcore_priv->gd,
510
old->devnum << tr->part_bits, 1);
513
spin_lock(&tr->blkcore_priv->devs_lock);
514
list_del(&old->list);
515
spin_unlock(&tr->blkcore_priv->devs_lock);
517
for (i = (old->devnum << tr->part_bits);
518
i < ((old->devnum+1) << tr->part_bits); i++) {
519
tr->blkcore_priv->sizes[i] = 0;
520
tr->blkcore_priv->part_table[i].nr_sects = 0;
521
tr->blkcore_priv->part_table[i].start_sect = 0;
527
void blktrans_notify_remove(struct mtd_info *mtd)
529
struct list_head *this, *this2, *next;
531
list_for_each(this, &blktrans_majors) {
532
struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
534
list_for_each_safe(this2, next, &tr->devs) {
535
struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list);
543
void blktrans_notify_add(struct mtd_info *mtd)
545
struct list_head *this;
547
if (mtd->type == MTD_ABSENT)
550
list_for_each(this, &blktrans_majors) {
551
struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
553
tr->add_mtd(tr, mtd);
558
static struct mtd_notifier blktrans_notifier = {
559
.add = blktrans_notify_add,
560
.remove = blktrans_notify_remove,
563
int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
567
/* Register the notifier if/when the first device type is
568
registered, to prevent the link/init ordering from fucking
570
if (!blktrans_notifier.list.next)
571
register_mtd_user(&blktrans_notifier);
573
tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
574
if (!tr->blkcore_priv)
577
memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
579
down(&mtd_table_mutex);
581
ret = devfs_register_blkdev(tr->major, tr->name, &mtd_blktrans_ops);
583
printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
584
tr->name, tr->major, ret);
585
kfree(tr->blkcore_priv);
586
up(&mtd_table_mutex);
590
blk_init_queue(BLK_DEFAULT_QUEUE(tr->major), &mtd_blktrans_request);
591
(BLK_DEFAULT_QUEUE(tr->major))->queuedata = tr;
593
init_completion(&tr->blkcore_priv->thread_dead);
594
init_waitqueue_head(&tr->blkcore_priv->thread_wq);
596
ret = kernel_thread(mtd_blktrans_thread, tr,
597
CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
599
blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
600
devfs_unregister_blkdev(tr->major, tr->name);
601
kfree(tr->blkcore_priv);
602
up(&mtd_table_mutex);
606
tr->blkcore_priv->devfs_dir_handle =
607
devfs_mk_dir(NULL, tr->name, NULL);
609
blksize_size[tr->major] = tr->blkcore_priv->blksizes;
610
blk_size[tr->major] = tr->blkcore_priv->sizes;
612
tr->blkcore_priv->gd.major = tr->major;
613
tr->blkcore_priv->gd.major_name = tr->name;
614
tr->blkcore_priv->gd.minor_shift = tr->part_bits;
615
tr->blkcore_priv->gd.max_p = (1<<tr->part_bits) - 1;
616
tr->blkcore_priv->gd.part = tr->blkcore_priv->part_table;
617
tr->blkcore_priv->gd.sizes = tr->blkcore_priv->sizes;
618
tr->blkcore_priv->gd.nr_real = 256 >> tr->part_bits;
620
spin_lock_init(&tr->blkcore_priv->devs_lock);
622
add_gendisk(&tr->blkcore_priv->gd);
624
INIT_LIST_HEAD(&tr->devs);
625
list_add(&tr->list, &blktrans_majors);
627
for (i=0; i<MAX_MTD_DEVICES; i++) {
628
if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)
629
tr->add_mtd(tr, mtd_table[i]);
631
up(&mtd_table_mutex);
636
int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
638
struct list_head *this, *next;
640
down(&mtd_table_mutex);
642
/* Clean up the kernel thread */
643
tr->blkcore_priv->exiting = 1;
644
wake_up(&tr->blkcore_priv->thread_wq);
645
wait_for_completion(&tr->blkcore_priv->thread_dead);
647
/* Remove it from the list of active majors */
650
/* Remove each of its devices */
651
list_for_each_safe(this, next, &tr->devs) {
652
struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list);
656
blksize_size[tr->major] = NULL;
657
blk_size[tr->major] = NULL;
659
del_gendisk(&tr->blkcore_priv->gd);
661
blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
662
devfs_unregister_blkdev(tr->major, tr->name);
664
devfs_unregister(tr->blkcore_priv->devfs_dir_handle);
666
up(&mtd_table_mutex);
668
kfree(tr->blkcore_priv);
670
if (!list_empty(&tr->devs))
675
static void __exit mtd_blktrans_exit(void)
677
/* No race here -- if someone's currently in register_mtd_blktrans
678
we're screwed anyway. */
679
if (blktrans_notifier.list.next)
680
unregister_mtd_user(&blktrans_notifier);
683
module_exit(mtd_blktrans_exit);
685
EXPORT_SYMBOL_GPL(register_mtd_blktrans);
686
EXPORT_SYMBOL_GPL(deregister_mtd_blktrans);
687
EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev);
688
EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev);
690
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
691
MODULE_LICENSE("GPL");
692
MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'");