Blame view
drivers/mtd/mtd_blkdevs.c
13.3 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
a1452a377 mtd: Update copyr... |
2 |
* Interface to Linux block layer for MTD 'translation layers'. |
1da177e4c Linux-2.6.12-rc2 |
3 |
* |
a1452a377 mtd: Update copyr... |
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
* Copyright © 2003-2010 David Woodhouse <dwmw2@infradead.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
1da177e4c Linux-2.6.12-rc2 |
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
* */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/list.h> #include <linux/fs.h> #include <linux/mtd/blktrans.h> #include <linux/mtd/mtd.h> #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/spinlock.h> #include <linux/hdreg.h> #include <linux/init.h> |
48b192686 [PATCH] sem2mutex... |
34 |
#include <linux/mutex.h> |
99f9b2431 [MTD] mtd_blkdevs... |
35 |
#include <linux/kthread.h> |
1da177e4c Linux-2.6.12-rc2 |
36 |
#include <asm/uaccess.h> |
1da177e4c Linux-2.6.12-rc2 |
37 |
|
356d70f19 [MTD] mtdcore.c: ... |
38 |
#include "mtdcore.h" |
1da177e4c Linux-2.6.12-rc2 |
39 |
|
356d70f19 [MTD] mtdcore.c: ... |
40 |
static LIST_HEAD(blktrans_majors); |
048d87199 mtd: blktrans: Ho... |
41 |
static DEFINE_MUTEX(blktrans_ref_mutex); |
7f53f12f0 mtd: mtd_blkdevs:... |
42 |
static void blktrans_dev_release(struct kref *kref) |
048d87199 mtd: blktrans: Ho... |
43 44 45 46 47 |
{ struct mtd_blktrans_dev *dev = container_of(kref, struct mtd_blktrans_dev, ref); dev->disk->private_data = NULL; |
e4d64cab9 mtd: blktrans: do... |
48 |
blk_cleanup_queue(dev->rq); |
048d87199 mtd: blktrans: Ho... |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
put_disk(dev->disk); list_del(&dev->list); kfree(dev); } static struct mtd_blktrans_dev *blktrans_dev_get(struct gendisk *disk) { struct mtd_blktrans_dev *dev; mutex_lock(&blktrans_ref_mutex); dev = disk->private_data; if (!dev) goto unlock; kref_get(&dev->ref); unlock: mutex_unlock(&blktrans_ref_mutex); return dev; } |
7f53f12f0 mtd: mtd_blkdevs:... |
68 |
static void blktrans_dev_put(struct mtd_blktrans_dev *dev) |
048d87199 mtd: blktrans: Ho... |
69 70 71 72 73 |
{ mutex_lock(&blktrans_ref_mutex); kref_put(&dev->ref, blktrans_dev_release); mutex_unlock(&blktrans_ref_mutex); } |
1da177e4c Linux-2.6.12-rc2 |
74 |
|
1da177e4c Linux-2.6.12-rc2 |
75 76 77 78 79 80 81 |
static int do_blktrans_request(struct mtd_blktrans_ops *tr, struct mtd_blktrans_dev *dev, struct request *req) { unsigned long block, nsect; char *buf; |
83096ebf1 block: convert to... |
82 |
block = blk_rq_pos(req) << 9 >> tr->blkshift; |
1011c1b9f block: blk_rq_[cu... |
83 |
nsect = blk_rq_cur_bytes(req) >> tr->blkshift; |
191876729 [MTD] Allow varia... |
84 |
|
1da177e4c Linux-2.6.12-rc2 |
85 |
buf = req->buffer; |
33659ebba block: remove wra... |
86 |
if (req->cmd_type != REQ_TYPE_FS) |
f06d9a2b5 block: replace en... |
87 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
88 |
|
83096ebf1 block: convert to... |
89 90 |
if (blk_rq_pos(req) + blk_rq_cur_sectors(req) > get_capacity(req->rq_disk)) |
f06d9a2b5 block: replace en... |
91 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
92 |
|
33659ebba block: remove wra... |
93 |
if (req->cmd_flags & REQ_DISCARD) |
1122a26f2 block: use normal... |
94 |
return tr->discard(dev, block, nsect); |
1da177e4c Linux-2.6.12-rc2 |
95 96 |
switch(rq_data_dir(req)) { case READ: |
191876729 [MTD] Allow varia... |
97 |
for (; nsect > 0; nsect--, block++, buf += tr->blksize) |
1da177e4c Linux-2.6.12-rc2 |
98 |
if (tr->readsect(dev, block, buf)) |
f06d9a2b5 block: replace en... |
99 |
return -EIO; |
2d4dc890b block: add helper... |
100 |
rq_flush_dcache_pages(req); |
f06d9a2b5 block: replace en... |
101 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
102 103 |
case WRITE: if (!tr->writesect) |
f06d9a2b5 block: replace en... |
104 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
105 |
|
2d4dc890b block: add helper... |
106 |
rq_flush_dcache_pages(req); |
191876729 [MTD] Allow varia... |
107 |
for (; nsect > 0; nsect--, block++, buf += tr->blksize) |
1da177e4c Linux-2.6.12-rc2 |
108 |
if (tr->writesect(dev, block, buf)) |
f06d9a2b5 block: replace en... |
109 110 |
return -EIO; return 0; |
1da177e4c Linux-2.6.12-rc2 |
111 |
default: |
9a2923082 [MTD] fix printk ... |
112 113 |
printk(KERN_NOTICE "Unknown request %u ", rq_data_dir(req)); |
f06d9a2b5 block: replace en... |
114 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
115 116 |
} } |
c7519dbf6 mtd_blkdevs: Add ... |
117 118 119 120 |
int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev) { if (kthread_should_stop()) return 1; |
7bf7e370d Merge branch 'mas... |
121 |
return dev->bg_stop; |
c7519dbf6 mtd_blkdevs: Add ... |
122 123 |
} EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background); |
1da177e4c Linux-2.6.12-rc2 |
124 125 |
static int mtd_blktrans_thread(void *arg) { |
a86386225 mtd: blktrans: re... |
126 |
struct mtd_blktrans_dev *dev = arg; |
c7519dbf6 mtd_blkdevs: Add ... |
127 |
struct mtd_blktrans_ops *tr = dev->tr; |
a86386225 mtd: blktrans: re... |
128 |
struct request_queue *rq = dev->rq; |
1498ada7a mtd_blkdevs: dequ... |
129 |
struct request *req = NULL; |
c7519dbf6 mtd_blkdevs: Add ... |
130 |
int background_done = 0; |
1da177e4c Linux-2.6.12-rc2 |
131 |
|
1da177e4c Linux-2.6.12-rc2 |
132 |
spin_lock_irq(rq->queue_lock); |
1498ada7a mtd_blkdevs: dequ... |
133 |
|
3e67fe454 [MTD] Finish conv... |
134 |
while (!kthread_should_stop()) { |
f06d9a2b5 block: replace en... |
135 |
int res; |
1da177e4c Linux-2.6.12-rc2 |
136 |
|
7bf7e370d Merge branch 'mas... |
137 |
dev->bg_stop = false; |
9934c8c04 block: implement ... |
138 |
if (!req && !(req = blk_fetch_request(rq))) { |
c7519dbf6 mtd_blkdevs: Add ... |
139 140 141 142 143 144 145 146 147 148 |
if (tr->background && !background_done) { spin_unlock_irq(rq->queue_lock); mutex_lock(&dev->lock); tr->background(dev); mutex_unlock(&dev->lock); spin_lock_irq(rq->queue_lock); /* * Do background processing just once per idle * period. */ |
7bf7e370d Merge branch 'mas... |
149 |
background_done = !dev->bg_stop; |
c7519dbf6 mtd_blkdevs: Add ... |
150 151 |
continue; } |
1da177e4c Linux-2.6.12-rc2 |
152 |
set_current_state(TASK_INTERRUPTIBLE); |
12aebf3e1 mtd: blktrans: fi... |
153 154 155 |
if (kthread_should_stop()) set_current_state(TASK_RUNNING); |
1da177e4c Linux-2.6.12-rc2 |
156 |
spin_unlock_irq(rq->queue_lock); |
1da177e4c Linux-2.6.12-rc2 |
157 |
schedule(); |
1da177e4c Linux-2.6.12-rc2 |
158 |
spin_lock_irq(rq->queue_lock); |
1da177e4c Linux-2.6.12-rc2 |
159 160 |
continue; } |
1da177e4c Linux-2.6.12-rc2 |
161 |
spin_unlock_irq(rq->queue_lock); |
48b192686 [PATCH] sem2mutex... |
162 |
mutex_lock(&dev->lock); |
a86386225 mtd: blktrans: re... |
163 |
res = do_blktrans_request(dev->tr, dev, req); |
48b192686 [PATCH] sem2mutex... |
164 |
mutex_unlock(&dev->lock); |
1da177e4c Linux-2.6.12-rc2 |
165 166 |
spin_lock_irq(rq->queue_lock); |
1498ada7a mtd_blkdevs: dequ... |
167 168 |
if (!__blk_end_request_cur(req, res)) req = NULL; |
c7519dbf6 mtd_blkdevs: Add ... |
169 170 |
background_done = 0; |
1da177e4c Linux-2.6.12-rc2 |
171 |
} |
1498ada7a mtd_blkdevs: dequ... |
172 173 174 |
if (req) __blk_end_request_all(req, -EIO); |
1da177e4c Linux-2.6.12-rc2 |
175 |
spin_unlock_irq(rq->queue_lock); |
3e67fe454 [MTD] Finish conv... |
176 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
177 178 179 180 |
} static void mtd_blktrans_request(struct request_queue *rq) { |
048d87199 mtd: blktrans: Ho... |
181 182 183 184 |
struct mtd_blktrans_dev *dev; struct request *req = NULL; dev = rq->queuedata; |
1da177e4c Linux-2.6.12-rc2 |
185 |
|
048d87199 mtd: blktrans: Ho... |
186 187 188 |
if (!dev) while ((req = blk_fetch_request(rq)) != NULL) __blk_end_request_all(req, -ENODEV); |
7bf7e370d Merge branch 'mas... |
189 190 |
else { dev->bg_stop = true; |
048d87199 mtd: blktrans: Ho... |
191 |
wake_up_process(dev->thread); |
7bf7e370d Merge branch 'mas... |
192 |
} |
048d87199 mtd: blktrans: Ho... |
193 |
} |
1da177e4c Linux-2.6.12-rc2 |
194 |
|
af0e2a0a8 [PATCH] switch mt... |
195 |
static int blktrans_open(struct block_device *bdev, fmode_t mode) |
1da177e4c Linux-2.6.12-rc2 |
196 |
{ |
048d87199 mtd: blktrans: Ho... |
197 |
struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); |
008c751ec mtd: allow to unl... |
198 |
int ret = 0; |
048d87199 mtd: blktrans: Ho... |
199 200 |
if (!dev) |
6e9624b8c block: push down ... |
201 |
return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ |
048d87199 mtd: blktrans: Ho... |
202 203 |
mutex_lock(&dev->lock); |
008c751ec mtd: allow to unl... |
204 |
if (dev->open++) |
048d87199 mtd: blktrans: Ho... |
205 |
goto unlock; |
048d87199 mtd: blktrans: Ho... |
206 |
|
008c751ec mtd: allow to unl... |
207 208 |
kref_get(&dev->ref); __module_get(dev->tr->owner); |
94735ec40 mtd: mtd_blkdevs:... |
209 210 211 212 213 214 215 |
if (!dev->mtd) goto unlock; if (dev->tr->open) { ret = dev->tr->open(dev); if (ret) goto error_put; |
008c751ec mtd: allow to unl... |
216 |
} |
048d87199 mtd: blktrans: Ho... |
217 |
|
94735ec40 mtd: mtd_blkdevs:... |
218 219 220 |
ret = __get_mtd_device(dev->mtd); if (ret) goto error_release; |
048d87199 mtd: blktrans: Ho... |
221 222 223 |
unlock: mutex_unlock(&dev->lock); blktrans_dev_put(dev); |
1da177e4c Linux-2.6.12-rc2 |
224 |
return ret; |
94735ec40 mtd: mtd_blkdevs:... |
225 226 227 228 229 230 231 232 233 234 |
error_release: if (dev->tr->release) dev->tr->release(dev); error_put: module_put(dev->tr->owner); kref_put(&dev->ref, blktrans_dev_release); mutex_unlock(&dev->lock); blktrans_dev_put(dev); return ret; |
1da177e4c Linux-2.6.12-rc2 |
235 |
} |
af0e2a0a8 [PATCH] switch mt... |
236 |
static int blktrans_release(struct gendisk *disk, fmode_t mode) |
1da177e4c Linux-2.6.12-rc2 |
237 |
{ |
048d87199 mtd: blktrans: Ho... |
238 |
struct mtd_blktrans_dev *dev = blktrans_dev_get(disk); |
008c751ec mtd: allow to unl... |
239 |
int ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
240 |
|
048d87199 mtd: blktrans: Ho... |
241 242 |
if (!dev) return ret; |
1da177e4c Linux-2.6.12-rc2 |
243 |
|
048d87199 mtd: blktrans: Ho... |
244 |
mutex_lock(&dev->lock); |
008c751ec mtd: allow to unl... |
245 |
if (--dev->open) |
048d87199 mtd: blktrans: Ho... |
246 |
goto unlock; |
008c751ec mtd: allow to unl... |
247 248 249 250 251 252 253 |
kref_put(&dev->ref, blktrans_dev_release); module_put(dev->tr->owner); if (dev->mtd) { ret = dev->tr->release ? dev->tr->release(dev) : 0; __put_mtd_device(dev->mtd); } |
048d87199 mtd: blktrans: Ho... |
254 255 256 |
unlock: mutex_unlock(&dev->lock); blktrans_dev_put(dev); |
1da177e4c Linux-2.6.12-rc2 |
257 258 |
return ret; } |
a885c8c43 [PATCH] Add block... |
259 260 |
static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) { |
048d87199 mtd: blktrans: Ho... |
261 262 263 264 265 266 267 |
struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); int ret = -ENXIO; if (!dev) return ret; mutex_lock(&dev->lock); |
a885c8c43 [PATCH] Add block... |
268 |
|
048d87199 mtd: blktrans: Ho... |
269 270 271 272 273 274 275 276 |
if (!dev->mtd) goto unlock; ret = dev->tr->getgeo ? dev->tr->getgeo(dev, geo) : 0; unlock: mutex_unlock(&dev->lock); blktrans_dev_put(dev); return ret; |
a885c8c43 [PATCH] Add block... |
277 |
} |
1da177e4c Linux-2.6.12-rc2 |
278 |
|
af0e2a0a8 [PATCH] switch mt... |
279 |
static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, |
1da177e4c Linux-2.6.12-rc2 |
280 281 |
unsigned int cmd, unsigned long arg) { |
048d87199 mtd: blktrans: Ho... |
282 283 284 285 286 287 288 289 290 291 |
struct mtd_blktrans_dev *dev = blktrans_dev_get(bdev->bd_disk); int ret = -ENXIO; if (!dev) return ret; mutex_lock(&dev->lock); if (!dev->mtd) goto unlock; |
1da177e4c Linux-2.6.12-rc2 |
292 293 294 |
switch (cmd) { case BLKFLSBUF: |
048d87199 mtd: blktrans: Ho... |
295 |
ret = dev->tr->flush ? dev->tr->flush(dev) : 0; |
007c2d876 mtd: return succe... |
296 |
break; |
1da177e4c Linux-2.6.12-rc2 |
297 |
default: |
048d87199 mtd: blktrans: Ho... |
298 |
ret = -ENOTTY; |
1da177e4c Linux-2.6.12-rc2 |
299 |
} |
048d87199 mtd: blktrans: Ho... |
300 301 302 303 |
unlock: mutex_unlock(&dev->lock); blktrans_dev_put(dev); return ret; |
1da177e4c Linux-2.6.12-rc2 |
304 |
} |
83d5cde47 const: make block... |
305 |
static const struct block_device_operations mtd_blktrans_ops = { |
1da177e4c Linux-2.6.12-rc2 |
306 |
.owner = THIS_MODULE, |
af0e2a0a8 [PATCH] switch mt... |
307 308 |
.open = blktrans_open, .release = blktrans_release, |
8a6cfeb6d block: push down ... |
309 |
.ioctl = blktrans_ioctl, |
a885c8c43 [PATCH] Add block... |
310 |
.getgeo = blktrans_getgeo, |
1da177e4c Linux-2.6.12-rc2 |
311 312 313 314 315 |
}; int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) { struct mtd_blktrans_ops *tr = new->tr; |
71a928c0e [MTD] Use list_fo... |
316 |
struct mtd_blktrans_dev *d; |
1da177e4c Linux-2.6.12-rc2 |
317 318 |
int last_devnum = -1; struct gendisk *gd; |
a86386225 mtd: blktrans: re... |
319 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
320 |
|
b3561ea94 Clean up mutex_tr... |
321 |
if (mutex_trylock(&mtd_table_mutex)) { |
48b192686 [PATCH] sem2mutex... |
322 |
mutex_unlock(&mtd_table_mutex); |
1da177e4c Linux-2.6.12-rc2 |
323 324 |
BUG(); } |
048d87199 mtd: blktrans: Ho... |
325 |
mutex_lock(&blktrans_ref_mutex); |
71a928c0e [MTD] Use list_fo... |
326 |
list_for_each_entry(d, &tr->devs, list) { |
1da177e4c Linux-2.6.12-rc2 |
327 328 329 330 331 332 333 334 335 336 |
if (new->devnum == -1) { /* Use first free number */ if (d->devnum != last_devnum+1) { /* Found a free devnum. Plug it in here */ new->devnum = last_devnum+1; list_add_tail(&new->list, &d->list); goto added; } } else if (d->devnum == new->devnum) { /* Required number taken */ |
048d87199 mtd: blktrans: Ho... |
337 |
mutex_unlock(&blktrans_ref_mutex); |
1da177e4c Linux-2.6.12-rc2 |
338 339 340 341 342 |
return -EBUSY; } else if (d->devnum > new->devnum) { /* Required number was free */ list_add_tail(&new->list, &d->list); goto added; |
97894cda5 [MTD] core: Clean... |
343 |
} |
1da177e4c Linux-2.6.12-rc2 |
344 345 |
last_devnum = d->devnum; } |
a86386225 mtd: blktrans: re... |
346 347 |
ret = -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
348 349 |
if (new->devnum == -1) new->devnum = last_devnum+1; |
4d3a8534b mtd: Raise limit ... |
350 351 352 353 |
/* Check that the device and any partitions will get valid * minor numbers and that the disk naming code below can cope * with this number. */ if (new->devnum > (MINORMASK >> tr->part_bits) || |
048d87199 mtd: blktrans: Ho... |
354 355 |
(tr->part_bits && new->devnum >= 27 * 26)) { mutex_unlock(&blktrans_ref_mutex); |
a86386225 mtd: blktrans: re... |
356 |
goto error1; |
048d87199 mtd: blktrans: Ho... |
357 |
} |
1da177e4c Linux-2.6.12-rc2 |
358 |
|
1da177e4c Linux-2.6.12-rc2 |
359 360 |
list_add_tail(&new->list, &tr->devs); added: |
048d87199 mtd: blktrans: Ho... |
361 |
mutex_unlock(&blktrans_ref_mutex); |
ce37ab42a [MTD] Always init... |
362 |
mutex_init(&new->lock); |
048d87199 mtd: blktrans: Ho... |
363 |
kref_init(&new->ref); |
1da177e4c Linux-2.6.12-rc2 |
364 365 |
if (!tr->writesect) new->readonly = 1; |
a86386225 mtd: blktrans: re... |
366 367 |
/* Create gendisk */ ret = -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
368 |
gd = alloc_disk(1 << tr->part_bits); |
a86386225 mtd: blktrans: re... |
369 370 371 372 373 374 |
if (!gd) goto error2; new->disk = gd; gd->private_data = new; |
1da177e4c Linux-2.6.12-rc2 |
375 376 377 |
gd->major = tr->major; gd->first_minor = (new->devnum) << tr->part_bits; gd->fops = &mtd_blktrans_ops; |
97894cda5 [MTD] core: Clean... |
378 |
|
65a8de36b [MTD] mtd_blkdevs... |
379 380 381 382 383 384 385 386 387 388 389 390 |
if (tr->part_bits) if (new->devnum < 26) snprintf(gd->disk_name, sizeof(gd->disk_name), "%s%c", tr->name, 'a' + new->devnum); else snprintf(gd->disk_name, sizeof(gd->disk_name), "%s%c%c", tr->name, 'a' - 1 + new->devnum / 26, 'a' + new->devnum % 26); else snprintf(gd->disk_name, sizeof(gd->disk_name), "%s%d", tr->name, new->devnum); |
1da177e4c Linux-2.6.12-rc2 |
391 |
|
191876729 [MTD] Allow varia... |
392 |
set_capacity(gd, (new->size * tr->blksize) >> 9); |
1da177e4c Linux-2.6.12-rc2 |
393 |
|
a86386225 mtd: blktrans: re... |
394 395 396 397 398 399 400 401 402 |
/* Create the request queue */ spin_lock_init(&new->queue_lock); new->rq = blk_init_queue(mtd_blktrans_request, &new->queue_lock); if (!new->rq) goto error3; new->rq->queuedata = new; blk_queue_logical_block_size(new->rq, tr->blksize); |
115ee88c1 mtd_blkdevs: Set ... |
403 404 405 406 |
if (tr->discard) { queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq); new->rq->limits.max_discard_sectors = UINT_MAX; } |
a86386225 mtd: blktrans: re... |
407 408 409 410 411 412 413 414 415 416 417 |
gd->queue = new->rq; /* Create processing thread */ /* TODO: workqueue ? */ new->thread = kthread_run(mtd_blktrans_thread, new, "%s%d", tr->name, new->mtd->index); if (IS_ERR(new->thread)) { ret = PTR_ERR(new->thread); goto error4; } |
d694846b6 [MTD] set blkdev ... |
418 |
gd->driverfs_dev = &new->mtd->dev; |
1da177e4c Linux-2.6.12-rc2 |
419 420 421 422 423 |
if (new->readonly) set_disk_ro(gd, 1); add_disk(gd); |
026ec5788 mtd: blktrans: al... |
424 |
|
133fa8c7d mtd: Few follow u... |
425 426 |
if (new->disk_attributes) { ret = sysfs_create_group(&disk_to_dev(gd)->kobj, |
026ec5788 mtd: blktrans: al... |
427 |
new->disk_attributes); |
133fa8c7d mtd: Few follow u... |
428 429 |
WARN_ON(ret); } |
1da177e4c Linux-2.6.12-rc2 |
430 |
return 0; |
a86386225 mtd: blktrans: re... |
431 432 433 434 435 436 437 |
error4: blk_cleanup_queue(new->rq); error3: put_disk(new->disk); error2: list_del(&new->list); error1: |
a86386225 mtd: blktrans: re... |
438 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
439 440 441 442 |
} int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) { |
048d87199 mtd: blktrans: Ho... |
443 |
unsigned long flags; |
b3561ea94 Clean up mutex_tr... |
444 |
if (mutex_trylock(&mtd_table_mutex)) { |
48b192686 [PATCH] sem2mutex... |
445 |
mutex_unlock(&mtd_table_mutex); |
1da177e4c Linux-2.6.12-rc2 |
446 447 |
BUG(); } |
026ec5788 mtd: blktrans: al... |
448 449 450 |
if (old->disk_attributes) sysfs_remove_group(&disk_to_dev(old->disk)->kobj, old->disk_attributes); |
dba76c033 mtd: blkdevs: fix... |
451 452 |
/* Stop new requests to arrive */ del_gendisk(old->disk); |
a86386225 mtd: blktrans: re... |
453 454 |
/* Stop the thread */ kthread_stop(old->thread); |
048d87199 mtd: blktrans: Ho... |
455 456 457 458 459 |
/* Kill current requests */ spin_lock_irqsave(&old->queue_lock, flags); old->rq->queuedata = NULL; blk_start_queue(old->rq); spin_unlock_irqrestore(&old->queue_lock, flags); |
048d87199 mtd: blktrans: Ho... |
460 |
|
008c751ec mtd: allow to unl... |
461 462 |
/* If the device is currently open, tell trans driver to close it, then put mtd device, and don't touch it again */ |
048d87199 mtd: blktrans: Ho... |
463 |
mutex_lock(&old->lock); |
008c751ec mtd: allow to unl... |
464 465 466 467 |
if (old->open) { if (old->tr->release) old->tr->release(old); __put_mtd_device(old->mtd); |
048d87199 mtd: blktrans: Ho... |
468 |
} |
048d87199 mtd: blktrans: Ho... |
469 470 471 472 |
old->mtd = NULL; mutex_unlock(&old->lock); blktrans_dev_put(old); |
1da177e4c Linux-2.6.12-rc2 |
473 474 475 476 477 |
return 0; } static void blktrans_notify_remove(struct mtd_info *mtd) { |
71a928c0e [MTD] Use list_fo... |
478 479 |
struct mtd_blktrans_ops *tr; struct mtd_blktrans_dev *dev, *next; |
1da177e4c Linux-2.6.12-rc2 |
480 |
|
71a928c0e [MTD] Use list_fo... |
481 482 |
list_for_each_entry(tr, &blktrans_majors, list) list_for_each_entry_safe(dev, next, &tr->devs, list) |
1da177e4c Linux-2.6.12-rc2 |
483 484 |
if (dev->mtd == mtd) tr->remove_dev(dev); |
1da177e4c Linux-2.6.12-rc2 |
485 486 487 488 |
} static void blktrans_notify_add(struct mtd_info *mtd) { |
71a928c0e [MTD] Use list_fo... |
489 |
struct mtd_blktrans_ops *tr; |
1da177e4c Linux-2.6.12-rc2 |
490 491 492 |
if (mtd->type == MTD_ABSENT) return; |
71a928c0e [MTD] Use list_fo... |
493 |
list_for_each_entry(tr, &blktrans_majors, list) |
1da177e4c Linux-2.6.12-rc2 |
494 |
tr->add_mtd(tr, mtd); |
1da177e4c Linux-2.6.12-rc2 |
495 496 497 498 499 500 |
} static struct mtd_notifier blktrans_notifier = { .add = blktrans_notify_add, .remove = blktrans_notify_remove, }; |
97894cda5 [MTD] core: Clean... |
501 |
|
1da177e4c Linux-2.6.12-rc2 |
502 503 |
int register_mtd_blktrans(struct mtd_blktrans_ops *tr) { |
f1332ba2f mtd: Introduce an... |
504 505 |
struct mtd_info *mtd; int ret; |
1da177e4c Linux-2.6.12-rc2 |
506 |
|
97894cda5 [MTD] core: Clean... |
507 |
/* Register the notifier if/when the first device type is |
1da177e4c Linux-2.6.12-rc2 |
508 509 510 511 |
registered, to prevent the link/init ordering from fucking us over. */ if (!blktrans_notifier.list.next) register_mtd_user(&blktrans_notifier); |
1da177e4c Linux-2.6.12-rc2 |
512 |
|
48b192686 [PATCH] sem2mutex... |
513 |
mutex_lock(&mtd_table_mutex); |
1da177e4c Linux-2.6.12-rc2 |
514 515 |
ret = register_blkdev(tr->major, tr->name); |
6fe4c5903 MTD: Fix wrong ch... |
516 |
if (ret < 0) { |
1da177e4c Linux-2.6.12-rc2 |
517 518 519 |
printk(KERN_WARNING "Unable to register %s block device on major %d: %d ", tr->name, tr->major, ret); |
48b192686 [PATCH] sem2mutex... |
520 |
mutex_unlock(&mtd_table_mutex); |
1da177e4c Linux-2.6.12-rc2 |
521 522 |
return ret; } |
eae9acd13 Support 'discard ... |
523 |
|
6fe4c5903 MTD: Fix wrong ch... |
524 525 |
if (ret) tr->major = ret; |
191876729 [MTD] Allow varia... |
526 |
tr->blkshift = ffs(tr->blksize) - 1; |
1da177e4c Linux-2.6.12-rc2 |
527 |
|
1da177e4c Linux-2.6.12-rc2 |
528 529 |
INIT_LIST_HEAD(&tr->devs); list_add(&tr->list, &blktrans_majors); |
f1332ba2f mtd: Introduce an... |
530 531 532 |
mtd_for_each_device(mtd) if (mtd->type != MTD_ABSENT) tr->add_mtd(tr, mtd); |
1da177e4c Linux-2.6.12-rc2 |
533 |
|
48b192686 [PATCH] sem2mutex... |
534 |
mutex_unlock(&mtd_table_mutex); |
1da177e4c Linux-2.6.12-rc2 |
535 536 537 538 539 |
return 0; } int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) { |
71a928c0e [MTD] Use list_fo... |
540 |
struct mtd_blktrans_dev *dev, *next; |
1da177e4c Linux-2.6.12-rc2 |
541 |
|
48b192686 [PATCH] sem2mutex... |
542 |
mutex_lock(&mtd_table_mutex); |
1da177e4c Linux-2.6.12-rc2 |
543 |
|
1da177e4c Linux-2.6.12-rc2 |
544 545 |
/* Remove it from the list of active majors */ list_del(&tr->list); |
71a928c0e [MTD] Use list_fo... |
546 |
list_for_each_entry_safe(dev, next, &tr->devs, list) |
1da177e4c Linux-2.6.12-rc2 |
547 |
tr->remove_dev(dev); |
1da177e4c Linux-2.6.12-rc2 |
548 |
|
1da177e4c Linux-2.6.12-rc2 |
549 |
unregister_blkdev(tr->major, tr->name); |
48b192686 [PATCH] sem2mutex... |
550 |
mutex_unlock(&mtd_table_mutex); |
1da177e4c Linux-2.6.12-rc2 |
551 |
|
373ebfbf1 BUG_ON() Conversi... |
552 |
BUG_ON(!list_empty(&tr->devs)); |
1da177e4c Linux-2.6.12-rc2 |
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
return 0; } static void __exit mtd_blktrans_exit(void) { /* No race here -- if someone's currently in register_mtd_blktrans we're screwed anyway. */ if (blktrans_notifier.list.next) unregister_mtd_user(&blktrans_notifier); } module_exit(mtd_blktrans_exit); EXPORT_SYMBOL_GPL(register_mtd_blktrans); EXPORT_SYMBOL_GPL(deregister_mtd_blktrans); EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev); EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev); MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'"); |