~ubuntu-branches/ubuntu/edgy/mtd/edgy

« back to all changes in this revision

Viewing changes to drivers/mtd/mtd_blkdevs-24.c

  • Committer: Bazaar Package Importer
  • Author(s): Riku Voipio
  • Date: 2005-01-23 12:56:16 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050123125616-jlum1hlbtsj2sx5f
Tags: 20050122-2
* Fix the version, darn
* Get rid of historic conflict, closes: #160614

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: mtd_blkdevs-24.c,v 1.17 2005/01/05 17:35:22 dwmw2 Exp $
 
3
 *
 
4
 * (C) 2003 David Woodhouse <dwmw2@infradead.org>
 
5
 *
 
6
 * Interface to Linux 2.4 block layer for MTD 'translation layers'.
 
7
 *
 
8
 */
 
9
 
 
10
#include <linux/kernel.h>
 
11
#include <linux/slab.h>
 
12
#include <linux/module.h>
 
13
#include <linux/list.h>
 
14
#include <linux/fs.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>
 
25
 
 
26
static LIST_HEAD(blktrans_majors);
 
27
 
 
28
extern struct semaphore mtd_table_mutex;
 
29
extern struct mtd_info *mtd_table[];
 
30
 
 
31
struct mtd_blkcore_priv {
 
32
        devfs_handle_t devfs_dir_handle;
 
33
        int blksizes[256];
 
34
        int sizes[256];
 
35
        struct hd_struct part_table[256];
 
36
        struct gendisk gd;
 
37
        spinlock_t devs_lock; /* See comment in _request function */
 
38
        struct completion thread_dead;
 
39
        int exiting;
 
40
        wait_queue_head_t thread_wq;
 
41
};
 
42
 
 
43
static inline struct mtd_blktrans_dev *tr_get_dev(struct mtd_blktrans_ops *tr,
 
44
                                           int devnum)
 
45
{
 
46
        struct list_head *this;
 
47
        struct mtd_blktrans_dev *d;
 
48
 
 
49
        list_for_each(this, &tr->devs) {
 
50
                d = list_entry(this, struct mtd_blktrans_dev, list);
 
51
 
 
52
                if (d->devnum == devnum)
 
53
                        return d;
 
54
        }
 
55
        return NULL;
 
56
}
 
57
 
 
58
static inline struct mtd_blktrans_ops *get_tr(int major)
 
59
{
 
60
        struct list_head *this;
 
61
        struct mtd_blktrans_ops *t;
 
62
 
 
63
        list_for_each(this, &blktrans_majors) {
 
64
                t = list_entry(this, struct mtd_blktrans_ops, list);
 
65
 
 
66
                if (t->major == major)
 
67
                        return t;
 
68
        }
 
69
        return NULL;
 
70
}
 
71
 
 
72
static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 
73
                               struct mtd_blktrans_dev *dev,
 
74
                               struct request *req)
 
75
{
 
76
        unsigned long block, nsect;
 
77
        char *buf;
 
78
        int minor;
 
79
 
 
80
        minor = MINOR(req->rq_dev);
 
81
        block = req->sector;
 
82
        nsect = req->current_nr_sectors;
 
83
        buf = req->buffer;
 
84
 
 
85
        if (block + nsect > tr->blkcore_priv->part_table[minor].nr_sects) {
 
86
                printk(KERN_WARNING "Access beyond end of device.\n");
 
87
                return 0;
 
88
        }
 
89
        block += tr->blkcore_priv->part_table[minor].start_sect;
 
90
 
 
91
        switch(req->cmd) {
 
92
        case READ:
 
93
                for (; nsect > 0; nsect--, block++, buf += 512)
 
94
                        if (tr->readsect(dev, block, buf))
 
95
                                return 0;
 
96
                return 1;
 
97
 
 
98
        case WRITE:
 
99
                if (!tr->writesect)
 
100
                        return 0;
 
101
 
 
102
                for (; nsect > 0; nsect--, block++, buf += 512)
 
103
                        if (tr->writesect(dev, block, buf))
 
104
                                return 0;
 
105
                return 1;
 
106
 
 
107
        default:
 
108
                printk(KERN_NOTICE "Unknown request cmd %d\n", req->cmd);
 
109
                return 0;
 
110
        }
 
111
}
 
112
 
 
113
static int mtd_blktrans_thread(void *arg)
 
114
{
 
115
        struct mtd_blktrans_ops *tr = arg;
 
116
        struct request_queue *rq = BLK_DEFAULT_QUEUE(tr->major);
 
117
 
 
118
        /* we might get involved when memory gets low, so use PF_MEMALLOC */
 
119
        current->flags |= PF_MEMALLOC;
 
120
 
 
121
        snprintf(current->comm, sizeof(current->comm), "%sd", tr->name);
 
122
 
 
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
 
126
           do exit. */
 
127
        spin_lock_irq(&current->sigmask_lock);
 
128
        sigfillset(&current->blocked);
 
129
        recalc_sigpending();
 
130
        spin_unlock_irq(&current->sigmask_lock);
 
131
 
 
132
        daemonize("%sd", tr->name);
 
133
 
 
134
        while (!tr->blkcore_priv->exiting) {
 
135
                struct request *req;
 
136
                struct mtd_blktrans_dev *dev;
 
137
                int devnum;
 
138
                int res = 0;
 
139
                DECLARE_WAITQUEUE(wait, current);
 
140
 
 
141
                spin_lock_irq(&io_request_lock);
 
142
 
 
143
                if (list_empty(&rq->queue_head)) {
 
144
 
 
145
                        add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
 
146
                        set_current_state(TASK_INTERRUPTIBLE);
 
147
 
 
148
                        spin_unlock_irq(&io_request_lock);
 
149
 
 
150
                        schedule();
 
151
                        remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
 
152
 
 
153
                        continue;
 
154
                }
 
155
 
 
156
                req = blkdev_entry_next_request(&rq->queue_head);
 
157
 
 
158
                devnum = MINOR(req->rq_dev) >> tr->part_bits;
 
159
 
 
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);
 
163
 
 
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
 
169
                   callbacks. */
 
170
                spin_lock(&tr->blkcore_priv->devs_lock);
 
171
                dev = tr_get_dev(tr, devnum);
 
172
                spin_unlock(&tr->blkcore_priv->devs_lock);
 
173
 
 
174
                BUG_ON(!dev);
 
175
 
 
176
                /* Ensure serialisation of requests */
 
177
                down(&dev->sem);
 
178
 
 
179
                res = do_blktrans_request(tr, dev, req);
 
180
                up(&dev->sem);
 
181
 
 
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);
 
187
                }
 
188
        }
 
189
        complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
 
190
}
 
191
 
 
192
static void mtd_blktrans_request(struct request_queue *rq)
 
193
{
 
194
        struct mtd_blktrans_ops *tr = rq->queuedata;
 
195
        wake_up(&tr->blkcore_priv->thread_wq);
 
196
}
 
197
 
 
198
int blktrans_open(struct inode *i, struct file *f)
 
199
{
 
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);
 
204
        int devnum;
 
205
        int ret = -ENODEV;
 
206
 
 
207
        if (is_read_only(i->i_rdev) && (f->f_mode & FMODE_WRITE))
 
208
                return -EROFS;
 
209
 
 
210
        down(&mtd_table_mutex);
 
211
 
 
212
        tr = get_tr(major_nr);
 
213
 
 
214
        if (!tr)
 
215
                goto out;
 
216
 
 
217
        devnum = minor_nr >> tr->part_bits;
 
218
 
 
219
        dev = tr_get_dev(tr, devnum);
 
220
 
 
221
        if (!dev)
 
222
                goto out;
 
223
 
 
224
        if (!tr->blkcore_priv->part_table[minor_nr].nr_sects) {
 
225
                ret = -ENODEV;
 
226
                goto out;
 
227
        }
 
228
 
 
229
        if (!try_inc_mod_count(dev->mtd->owner))
 
230
                goto out;
 
231
 
 
232
        if (!try_inc_mod_count(tr->owner))
 
233
                goto out_tr;
 
234
 
 
235
        dev->mtd->usecount++;
 
236
 
 
237
        ret = 0;
 
238
        if (tr->open && (ret = tr->open(dev))) {
 
239
                dev->mtd->usecount--;
 
240
                if (dev->mtd->owner)
 
241
                        __MOD_DEC_USE_COUNT(dev->mtd->owner);
 
242
        out_tr:
 
243
                if (tr->owner)
 
244
                        __MOD_DEC_USE_COUNT(tr->owner);
 
245
        }
 
246
 out:
 
247
        up(&mtd_table_mutex);
 
248
 
 
249
        return ret;
 
250
}
 
251
 
 
252
int blktrans_release(struct inode *i, struct file *f)
 
253
{
 
254
        struct mtd_blktrans_dev *dev;
 
255
        struct mtd_blktrans_ops *tr;
 
256
        int ret = 0;
 
257
        int devnum;
 
258
 
 
259
        down(&mtd_table_mutex);
 
260
 
 
261
        tr = get_tr(MAJOR(i->i_rdev));
 
262
        if (!tr) {
 
263
                up(&mtd_table_mutex);
 
264
                return -ENODEV;
 
265
        }
 
266
 
 
267
        devnum = MINOR(i->i_rdev) >> tr->part_bits;
 
268
        dev = tr_get_dev(tr, devnum);
 
269
 
 
270
        if (!dev) {
 
271
                up(&mtd_table_mutex);
 
272
                return -ENODEV;
 
273
        }
 
274
 
 
275
        if (tr->release)
 
276
                ret = tr->release(dev);
 
277
 
 
278
        if (!ret) {
 
279
                dev->mtd->usecount--;
 
280
                if (dev->mtd->owner)
 
281
                        __MOD_DEC_USE_COUNT(dev->mtd->owner);
 
282
                if (tr->owner)
 
283
                        __MOD_DEC_USE_COUNT(tr->owner);
 
284
        }
 
285
        
 
286
        up(&mtd_table_mutex);
 
287
 
 
288
        return ret;
 
289
}
 
290
 
 
291
static int mtd_blktrans_rrpart(kdev_t rdev, struct mtd_blktrans_ops *tr,
 
292
                               struct mtd_blktrans_dev *dev)
 
293
{
 
294
        struct gendisk *gd = &(tr->blkcore_priv->gd);
 
295
        int i;
 
296
        int minor = MINOR(rdev);
 
297
 
 
298
        if (minor & ((1<<tr->part_bits)-1) || !tr->part_bits) {
 
299
                /* BLKRRPART on a partition. Go away. */
 
300
                return -ENOTTY;
 
301
        }
 
302
 
 
303
        if (!capable(CAP_SYS_ADMIN))
 
304
            return -EACCES;
 
305
 
 
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);
 
310
 
 
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;
 
315
        }
 
316
 
 
317
        grok_partitions(gd, minor, 1 << tr->part_bits, 
 
318
                        dev->size);
 
319
        up(&mtd_table_mutex);
 
320
 
 
321
        return 0;
 
322
}
 
323
 
 
324
static int blktrans_ioctl(struct inode *inode, struct file *file, 
 
325
                              unsigned int cmd, unsigned long arg)
 
326
{
 
327
        struct mtd_blktrans_dev *dev;
 
328
        struct mtd_blktrans_ops *tr;
 
329
        int devnum;
 
330
 
 
331
        switch(cmd) {
 
332
        case BLKGETSIZE:
 
333
        case BLKGETSIZE64:
 
334
        case BLKBSZSET:
 
335
        case BLKBSZGET:
 
336
        case BLKROSET:
 
337
        case BLKROGET:
 
338
        case BLKRASET:
 
339
        case BLKRAGET:
 
340
        case BLKPG:
 
341
        case BLKELVGET:
 
342
        case BLKELVSET:
 
343
                return blk_ioctl(inode->i_rdev, cmd, arg);
 
344
        }
 
345
 
 
346
        down(&mtd_table_mutex);
 
347
 
 
348
        tr = get_tr(MAJOR(inode->i_rdev));
 
349
        if (!tr) {
 
350
                up(&mtd_table_mutex);
 
351
                return -ENODEV;
 
352
        }
 
353
 
 
354
        devnum = MINOR(inode->i_rdev) >> tr->part_bits;
 
355
        dev = tr_get_dev(tr, devnum);
 
356
 
 
357
        up(&mtd_table_mutex);
 
358
 
 
359
        if (!dev)
 
360
                return -ENODEV;
 
361
 
 
362
        switch(cmd) {
 
363
        case BLKRRPART:
 
364
                return mtd_blktrans_rrpart(inode->i_rdev, tr, dev);
 
365
                
 
366
        case BLKFLSBUF:
 
367
                blk_ioctl(inode->i_rdev, cmd, arg);
 
368
                if (tr->flush)
 
369
                        return tr->flush(dev);
 
370
                /* The core code did the work, we had nothing to do. */
 
371
                return 0;
 
372
 
 
373
        case HDIO_GETGEO:
 
374
                if (tr->getgeo) {
 
375
                        struct hd_geometry g;
 
376
                        struct gendisk *gd = &(tr->blkcore_priv->gd);
 
377
                        int ret;
 
378
 
 
379
                        memset(&g, 0, sizeof(g));
 
380
                        ret = tr->getgeo(dev, &g);
 
381
                        if (ret)
 
382
                                return ret;
 
383
 
 
384
                        g.start = gd->part[MINOR(inode->i_rdev)].start_sect;
 
385
                        if (copy_to_user((void *)arg, &g, sizeof(g)))
 
386
                                return -EFAULT;
 
387
                        return 0;
 
388
                } /* else */
 
389
        default:
 
390
                return -ENOTTY;
 
391
        }
 
392
}
 
393
 
 
394
struct block_device_operations mtd_blktrans_ops = {
 
395
        .owner          = THIS_MODULE,
 
396
        .open           = blktrans_open,
 
397
        .release        = blktrans_release,
 
398
        .ioctl          = blktrans_ioctl,
 
399
};
 
400
 
 
401
int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 
402
{
 
403
        struct mtd_blktrans_ops *tr = new->tr;
 
404
        struct list_head *this;
 
405
        int last_devnum = -1;
 
406
        int i;
 
407
 
 
408
        if (!down_trylock(&mtd_table_mutex)) {
 
409
                up(&mtd_table_mutex);
 
410
                BUG();
 
411
        }
 
412
 
 
413
        spin_lock(&tr->blkcore_priv->devs_lock);
 
414
 
 
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);
 
423
                                goto added;
 
424
                        }
 
425
                } else if (d->devnum == new->devnum) {
 
426
                        /* Required number taken */
 
427
                        spin_unlock(&tr->blkcore_priv->devs_lock);
 
428
                        return -EBUSY;
 
429
                } else if (d->devnum > new->devnum) {
 
430
                        /* Required number was free */
 
431
                        list_add_tail(&new->list, &d->list);
 
432
                        goto added;
 
433
                } 
 
434
                last_devnum = d->devnum;
 
435
        }
 
436
        if (new->devnum == -1)
 
437
                new->devnum = last_devnum+1;
 
438
 
 
439
        if ((new->devnum << tr->part_bits) > 256) {
 
440
                spin_unlock(&tr->blkcore_priv->devs_lock);
 
441
                return -EBUSY;
 
442
        }
 
443
 
 
444
        init_MUTEX(&new->sem);
 
445
        list_add_tail(&new->list, &tr->devs);
 
446
 added:
 
447
        spin_unlock(&tr->blkcore_priv->devs_lock);
 
448
 
 
449
        if (!tr->writesect)
 
450
                new->readonly = 1;
 
451
 
 
452
        for (i = new->devnum << tr->part_bits;
 
453
             i < (new->devnum+1) << tr->part_bits; 
 
454
             i++) {
 
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;
 
460
        }
 
461
 
 
462
        /*
 
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 */
 
466
 
 
467
        tr->blkcore_priv->sizes[new->devnum << tr->part_bits] = 
 
468
                (new->size * new->blksize) >> 10; /* 2.4 and its dumb units */
 
469
 
 
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;
 
472
 
 
473
        if (tr->part_bits) {
 
474
                grok_partitions(&tr->blkcore_priv->gd, new->devnum,
 
475
                                1 << tr->part_bits, new->size);
 
476
        }
 
477
#ifdef CONFIG_DEVFS_FS
 
478
        if (!tr->part_bits) {
 
479
                char name[2];
 
480
 
 
481
                name[0] = '0' + new->devnum;
 
482
                name[1] = 0;
 
483
 
 
484
                new->blkcore_priv = 
 
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);
 
489
        }
 
490
#endif
 
491
        return 0;
 
492
}
 
493
 
 
494
int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
 
495
{
 
496
        struct mtd_blktrans_ops *tr = old->tr;
 
497
        int i;
 
498
 
 
499
        if (!down_trylock(&mtd_table_mutex)) {
 
500
                up(&mtd_table_mutex);
 
501
                BUG();
 
502
        }
 
503
 
 
504
#ifdef CONFIG_DEVFS_FS
 
505
        if (!tr->part_bits) {
 
506
                devfs_unregister(old->blkcore_priv);
 
507
                old->blkcore_priv = NULL;
 
508
        } else {
 
509
                devfs_register_partitions(&tr->blkcore_priv->gd,
 
510
                                          old->devnum << tr->part_bits, 1);
 
511
        }
 
512
#endif
 
513
        spin_lock(&tr->blkcore_priv->devs_lock);
 
514
        list_del(&old->list);
 
515
        spin_unlock(&tr->blkcore_priv->devs_lock);
 
516
 
 
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;
 
522
        }
 
523
 
 
524
        return 0;
 
525
}
 
526
 
 
527
void blktrans_notify_remove(struct mtd_info *mtd)
 
528
{
 
529
        struct list_head *this, *this2, *next;
 
530
 
 
531
        list_for_each(this, &blktrans_majors) {
 
532
                struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
 
533
 
 
534
                list_for_each_safe(this2, next, &tr->devs) {
 
535
                        struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list);
 
536
 
 
537
                        if (dev->mtd == mtd)
 
538
                                tr->remove_dev(dev);
 
539
                }
 
540
        }
 
541
}
 
542
 
 
543
void blktrans_notify_add(struct mtd_info *mtd)
 
544
{
 
545
        struct list_head *this;
 
546
 
 
547
        if (mtd->type == MTD_ABSENT)
 
548
                return;
 
549
 
 
550
        list_for_each(this, &blktrans_majors) {
 
551
                struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
 
552
 
 
553
                tr->add_mtd(tr, mtd);
 
554
        }
 
555
 
 
556
}
 
557
 
 
558
static struct mtd_notifier blktrans_notifier = {
 
559
        .add = blktrans_notify_add,
 
560
        .remove = blktrans_notify_remove,
 
561
};
 
562
      
 
563
int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
 
564
{
 
565
        int ret, i;
 
566
 
 
567
        /* Register the notifier if/when the first device type is 
 
568
           registered, to prevent the link/init ordering from fucking
 
569
           us over. */
 
570
        if (!blktrans_notifier.list.next)
 
571
                register_mtd_user(&blktrans_notifier);
 
572
 
 
573
        tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
 
574
        if (!tr->blkcore_priv)
 
575
                return -ENOMEM;
 
576
 
 
577
        memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
 
578
 
 
579
        down(&mtd_table_mutex);
 
580
 
 
581
        ret = devfs_register_blkdev(tr->major, tr->name, &mtd_blktrans_ops);
 
582
        if (ret) {
 
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);
 
587
                return ret;
 
588
        }
 
589
 
 
590
        blk_init_queue(BLK_DEFAULT_QUEUE(tr->major), &mtd_blktrans_request);
 
591
        (BLK_DEFAULT_QUEUE(tr->major))->queuedata = tr;
 
592
        
 
593
        init_completion(&tr->blkcore_priv->thread_dead);
 
594
        init_waitqueue_head(&tr->blkcore_priv->thread_wq);
 
595
 
 
596
        ret = kernel_thread(mtd_blktrans_thread, tr, 
 
597
                          CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
 
598
        if (ret < 0) {
 
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);
 
603
                return ret;
 
604
        } 
 
605
 
 
606
        tr->blkcore_priv->devfs_dir_handle = 
 
607
                        devfs_mk_dir(NULL, tr->name, NULL);
 
608
 
 
609
        blksize_size[tr->major] = tr->blkcore_priv->blksizes;
 
610
        blk_size[tr->major] = tr->blkcore_priv->sizes;
 
611
 
 
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;
 
619
 
 
620
        spin_lock_init(&tr->blkcore_priv->devs_lock);
 
621
 
 
622
        add_gendisk(&tr->blkcore_priv->gd);
 
623
 
 
624
        INIT_LIST_HEAD(&tr->devs);
 
625
        list_add(&tr->list, &blktrans_majors);
 
626
 
 
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]);
 
630
        }
 
631
        up(&mtd_table_mutex);
 
632
 
 
633
        return 0;
 
634
}
 
635
 
 
636
int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
 
637
{
 
638
        struct list_head *this, *next;
 
639
 
 
640
        down(&mtd_table_mutex);
 
641
 
 
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);
 
646
        
 
647
        /* Remove it from the list of active majors */
 
648
        list_del(&tr->list);
 
649
 
 
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);
 
653
                tr->remove_dev(dev);
 
654
        }
 
655
 
 
656
        blksize_size[tr->major] = NULL;
 
657
        blk_size[tr->major] = NULL;
 
658
 
 
659
        del_gendisk(&tr->blkcore_priv->gd);
 
660
 
 
661
        blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
 
662
        devfs_unregister_blkdev(tr->major, tr->name);
 
663
 
 
664
        devfs_unregister(tr->blkcore_priv->devfs_dir_handle);
 
665
 
 
666
        up(&mtd_table_mutex);
 
667
 
 
668
        kfree(tr->blkcore_priv);
 
669
 
 
670
        if (!list_empty(&tr->devs))
 
671
                BUG();
 
672
        return 0;
 
673
}
 
674
 
 
675
static void __exit mtd_blktrans_exit(void)
 
676
{
 
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);
 
681
}
 
682
 
 
683
module_exit(mtd_blktrans_exit);
 
684
 
 
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);
 
689
 
 
690
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
 
691
MODULE_LICENSE("GPL");
 
692
MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'");