source: src/linux/universal/linux-3.2/drivers/mtd/mtdpart.c @ 28375

Last change on this file since 28375 was 28375, checked in by BrainSlayer, 16 months ago

update kernel

File size: 28.4 KB
Line 
1/*
2 * Simple MTD partitioning layer
3 *
4 * Copyright © 2000 Nicolas Pitre <nico@fluxnic.net>
5 * Copyright © 2002 Thomas Gleixner <gleixner@linutronix.de>
6 * Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#include <linux/module.h>
25#include <linux/types.h>
26#include <linux/kernel.h>
27#include <linux/slab.h>
28#include <linux/list.h>
29#include <linux/kmod.h>
30#include <linux/mtd/mtd.h>
31#include <linux/mtd/partitions.h>
32#include <linux/root_dev.h>
33#include <linux/magic.h>
34#include <linux/err.h>
35
36#define MTD_ERASE_PARTIAL       0x8000 /* partition only covers parts of an erase block */
37
38#include "mtdcore.h"
39
40/* Our partition linked list */
41static LIST_HEAD(mtd_partitions);
42static DEFINE_MUTEX(mtd_partitions_mutex);
43
44/* Our partition node structure */
45struct mtd_part {
46        struct mtd_info mtd;
47        struct mtd_info *master;
48        uint64_t offset;
49        struct list_head list;
50};
51
52/*
53 * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
54 * the pointer to that structure with this macro.
55 */
56#define PART(x)  ((struct mtd_part *)(x))
57#define IS_PART(mtd) (mtd->read == part_read)
58
59/*
60 * MTD methods which simply translate the effective address and pass through
61 * to the _real_ device.
62 */
63
64static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
65                size_t *retlen, u_char *buf)
66{
67        struct mtd_part *part = PART(mtd);
68        struct mtd_ecc_stats stats;
69        int res;
70
71        stats = part->master->ecc_stats;
72
73        if (from >= mtd->size)
74                len = 0;
75        else if (from + len > mtd->size)
76                len = mtd->size - from;
77        res = part->master->read(part->master, from + part->offset,
78                                   len, retlen, buf);
79        if (unlikely(res)) {
80                if (mtd_is_bitflip(res))
81                        mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
82                if (mtd_is_eccerr(res))
83                        mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
84        }
85        return res;
86}
87
88static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
89                size_t *retlen, void **virt, resource_size_t *phys)
90{
91        struct mtd_part *part = PART(mtd);
92        if (from >= mtd->size)
93                len = 0;
94        else if (from + len > mtd->size)
95                len = mtd->size - from;
96        return part->master->point (part->master, from + part->offset,
97                                    len, retlen, virt, phys);
98}
99
100static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
101{
102        struct mtd_part *part = PART(mtd);
103
104        part->master->unpoint(part->master, from + part->offset, len);
105}
106
107static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
108                                            unsigned long len,
109                                            unsigned long offset,
110                                            unsigned long flags)
111{
112        struct mtd_part *part = PART(mtd);
113
114        offset += part->offset;
115        return part->master->get_unmapped_area(part->master, len, offset,
116                                               flags);
117}
118
119static int part_read_oob(struct mtd_info *mtd, loff_t from,
120                struct mtd_oob_ops *ops)
121{
122        struct mtd_part *part = PART(mtd);
123        int res;
124
125        if (from >= mtd->size)
126                return -EINVAL;
127        if (ops->datbuf && from + ops->len > mtd->size)
128                return -EINVAL;
129
130        /*
131         * If OOB is also requested, make sure that we do not read past the end
132         * of this partition.
133         */
134        if (ops->oobbuf) {
135                size_t len, pages;
136
137                if (ops->mode == MTD_OPS_AUTO_OOB)
138                        len = mtd->oobavail;
139                else
140                        len = mtd->oobsize;
141                pages = mtd_div_by_ws(mtd->size, mtd);
142                pages -= mtd_div_by_ws(from, mtd);
143                if (ops->ooboffs + ops->ooblen > pages * len)
144                        return -EINVAL;
145        }
146
147        res = part->master->read_oob(part->master, from + part->offset, ops);
148        if (unlikely(res)) {
149                if (mtd_is_bitflip(res))
150                        mtd->ecc_stats.corrected++;
151                if (mtd_is_eccerr(res))
152                        mtd->ecc_stats.failed++;
153        }
154        return res;
155}
156
157static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
158                size_t len, size_t *retlen, u_char *buf)
159{
160        struct mtd_part *part = PART(mtd);
161        return part->master->read_user_prot_reg(part->master, from,
162                                        len, retlen, buf);
163}
164
165static int part_get_user_prot_info(struct mtd_info *mtd,
166                struct otp_info *buf, size_t len)
167{
168        struct mtd_part *part = PART(mtd);
169        return part->master->get_user_prot_info(part->master, buf, len);
170}
171
172static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
173                size_t len, size_t *retlen, u_char *buf)
174{
175        struct mtd_part *part = PART(mtd);
176        return part->master->read_fact_prot_reg(part->master, from,
177                                        len, retlen, buf);
178}
179
180static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
181                size_t len)
182{
183        struct mtd_part *part = PART(mtd);
184        return part->master->get_fact_prot_info(part->master, buf, len);
185}
186
187static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
188                size_t *retlen, const u_char *buf)
189{
190        struct mtd_part *part = PART(mtd);
191        if (!(mtd->flags & MTD_WRITEABLE))
192                return -EROFS;
193        if (to >= mtd->size)
194                len = 0;
195        else if (to + len > mtd->size)
196                len = mtd->size - to;
197        return part->master->write(part->master, to + part->offset,
198                                    len, retlen, buf);
199}
200
201static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
202                size_t *retlen, const u_char *buf)
203{
204        struct mtd_part *part = PART(mtd);
205        if (!(mtd->flags & MTD_WRITEABLE))
206                return -EROFS;
207        if (to >= mtd->size)
208                len = 0;
209        else if (to + len > mtd->size)
210                len = mtd->size - to;
211        return part->master->panic_write(part->master, to + part->offset,
212                                    len, retlen, buf);
213}
214
215static int part_write_oob(struct mtd_info *mtd, loff_t to,
216                struct mtd_oob_ops *ops)
217{
218        struct mtd_part *part = PART(mtd);
219
220        if (!(mtd->flags & MTD_WRITEABLE))
221                return -EROFS;
222
223        if (to >= mtd->size)
224                return -EINVAL;
225        if (ops->datbuf && to + ops->len > mtd->size)
226                return -EINVAL;
227        return part->master->write_oob(part->master, to + part->offset, ops);
228}
229
230static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
231                size_t len, size_t *retlen, u_char *buf)
232{
233        struct mtd_part *part = PART(mtd);
234        return part->master->write_user_prot_reg(part->master, from,
235                                        len, retlen, buf);
236}
237
238static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
239                size_t len)
240{
241        struct mtd_part *part = PART(mtd);
242        return part->master->lock_user_prot_reg(part->master, from, len);
243}
244
245static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
246                unsigned long count, loff_t to, size_t *retlen)
247{
248        struct mtd_part *part = PART(mtd);
249        if (!(mtd->flags & MTD_WRITEABLE))
250                return -EROFS;
251        return part->master->writev(part->master, vecs, count,
252                                        to + part->offset, retlen);
253}
254
255static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
256{
257        struct mtd_part *part = PART(mtd);
258        int ret;
259        if (!(mtd->flags & MTD_WRITEABLE))
260                return -EROFS;
261        if (instr->addr >= mtd->size)
262                return -EINVAL;
263
264        instr->partial_start = false;
265        if (mtd->flags & MTD_ERASE_PARTIAL) {
266                size_t readlen = 0;
267                u64 mtd_ofs;
268
269                instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
270                if (!instr->erase_buf)
271                        return -ENOMEM;
272
273                mtd_ofs = part->offset + instr->addr;
274                instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
275
276                if (instr->erase_buf_ofs > 0) {
277                        instr->addr -= instr->erase_buf_ofs;
278                        ret = part->master->read(part->master,
279                                instr->addr + part->offset,
280                                part->master->erasesize,
281                                &readlen, instr->erase_buf);
282
283                        instr->partial_start = true;
284                } else {
285                        mtd_ofs = part->offset + part->mtd.size;
286                        instr->erase_buf_ofs = part->master->erasesize -
287                                do_div(mtd_ofs, part->master->erasesize);
288
289                        if (instr->erase_buf_ofs > 0) {
290                                instr->len += instr->erase_buf_ofs;
291                                ret = part->master->read(part->master,
292                                        part->offset + instr->addr +
293                                        instr->len - part->master->erasesize,
294                                        part->master->erasesize, &readlen,
295                                        instr->erase_buf);
296                        } else {
297                                ret = 0;
298                        }
299                }
300                if (ret < 0) {
301                        kfree(instr->erase_buf);
302                        return ret;
303                }
304
305        }
306
307        instr->addr += part->offset;
308        ret = part->master->erase(part->master, instr);
309        if (ret) {
310                if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
311                        instr->fail_addr -= part->offset;
312                instr->addr -= part->offset;
313                if (mtd->flags & MTD_ERASE_PARTIAL)
314                        kfree(instr->erase_buf);
315        }
316
317        return ret;
318}
319
320void mtd_erase_callback(struct erase_info *instr)
321{
322        if (instr->mtd->erase == part_erase) {
323                struct mtd_part *part = PART(instr->mtd);
324                size_t wrlen = 0;
325
326                if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
327                        if (instr->partial_start) {
328                                part->master->write(part->master,
329                                        instr->addr, instr->erase_buf_ofs,
330                                        &wrlen, instr->erase_buf);
331                                instr->addr += instr->erase_buf_ofs;
332                        } else {
333                                instr->len -= instr->erase_buf_ofs;
334                                part->master->write(part->master,
335                                        instr->addr + instr->len,
336                                        instr->erase_buf_ofs, &wrlen,
337                                        instr->erase_buf +
338                                        part->master->erasesize -
339                                        instr->erase_buf_ofs);
340                        }
341                        kfree(instr->erase_buf);
342                }
343                if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
344                        instr->fail_addr -= part->offset;
345                instr->addr -= part->offset;
346        }
347        if (instr->callback)
348                instr->callback(instr);
349}
350EXPORT_SYMBOL_GPL(mtd_erase_callback);
351
352static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
353{
354        struct mtd_part *part = PART(mtd);
355        if ((len + ofs) > mtd->size)
356                return -EINVAL;
357        return part->master->lock(part->master, ofs + part->offset, len);
358}
359
360static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
361{
362        struct mtd_part *part = PART(mtd);
363        if ((len + ofs) > mtd->size)
364                return -EINVAL;
365        return part->master->unlock(part->master, ofs + part->offset, len);
366}
367
368static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
369{
370        struct mtd_part *part = PART(mtd);
371        if ((len + ofs) > mtd->size)
372                return -EINVAL;
373        return part->master->is_locked(part->master, ofs + part->offset, len);
374}
375
376static void part_sync(struct mtd_info *mtd)
377{
378        struct mtd_part *part = PART(mtd);
379        part->master->sync(part->master);
380}
381
382static int part_suspend(struct mtd_info *mtd)
383{
384        struct mtd_part *part = PART(mtd);
385        return part->master->suspend(part->master);
386}
387
388static void part_resume(struct mtd_info *mtd)
389{
390        struct mtd_part *part = PART(mtd);
391        part->master->resume(part->master);
392}
393
394static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
395{
396        struct mtd_part *part = PART(mtd);
397        if (ofs >= mtd->size)
398                return -EINVAL;
399        ofs += part->offset;
400        return part->master->block_isbad(part->master, ofs);
401}
402
403static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
404{
405        struct mtd_part *part = PART(mtd);
406        int res;
407
408        if (!(mtd->flags & MTD_WRITEABLE))
409                return -EROFS;
410        if (ofs >= mtd->size)
411                return -EINVAL;
412        ofs += part->offset;
413        res = part->master->block_markbad(part->master, ofs);
414        if (!res)
415                mtd->ecc_stats.badblocks++;
416        return res;
417}
418
419static inline void free_partition(struct mtd_part *p)
420{
421        kfree(p->mtd.name);
422        kfree(p);
423}
424
425/*
426 * This function unregisters and destroy all slave MTD objects which are
427 * attached to the given master MTD object.
428 */
429
430int del_mtd_partitions(struct mtd_info *master)
431{
432        struct mtd_part *slave, *next;
433        int ret, err = 0;
434
435        mutex_lock(&mtd_partitions_mutex);
436        list_for_each_entry_safe(slave, next, &mtd_partitions, list)
437                if (slave->master == master) {
438                        ret = del_mtd_device(&slave->mtd);
439                        if (ret < 0) {
440                                err = ret;
441                                continue;
442                        }
443                        list_del(&slave->list);
444                        free_partition(slave);
445                }
446        mutex_unlock(&mtd_partitions_mutex);
447
448        return err;
449}
450
451static struct mtd_part *allocate_partition(struct mtd_info *master,
452                        const struct mtd_partition *part, int partno,
453                        uint64_t cur_offset)
454{
455        struct mtd_part *slave;
456        char *name;
457
458        /* allocate the partition structure */
459        slave = kzalloc(sizeof(*slave), GFP_KERNEL);
460        name = kstrdup(part->name, GFP_KERNEL);
461        if (!name || !slave) {
462                printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
463                       master->name);
464                kfree(name);
465                kfree(slave);
466                return ERR_PTR(-ENOMEM);
467        }
468
469        /* set up the MTD object for this partition */
470        slave->mtd.type = master->type;
471        slave->mtd.flags = master->flags & ~part->mask_flags;
472        slave->mtd.size = part->size;
473        slave->mtd.writesize = master->writesize;
474        slave->mtd.writebufsize = master->writebufsize;
475        slave->mtd.oobsize = master->oobsize;
476        slave->mtd.oobavail = master->oobavail;
477        slave->mtd.subpage_sft = master->subpage_sft;
478
479        slave->mtd.name = name;
480        slave->mtd.owner = master->owner;
481        slave->mtd.backing_dev_info = master->backing_dev_info;
482
483        /* NOTE:  we don't arrange MTDs as a tree; it'd be error-prone
484         * to have the same data be in two different partitions.
485         */
486        slave->mtd.dev.parent = master->dev.parent;
487
488        slave->mtd.read = part_read;
489        slave->mtd.write = part_write;
490
491        if (master->panic_write)
492                slave->mtd.panic_write = part_panic_write;
493
494        if (master->point && master->unpoint) {
495                slave->mtd.point = part_point;
496                slave->mtd.unpoint = part_unpoint;
497        }
498
499        if (master->get_unmapped_area)
500                slave->mtd.get_unmapped_area = part_get_unmapped_area;
501        if (master->read_oob)
502                slave->mtd.read_oob = part_read_oob;
503        if (master->write_oob)
504                slave->mtd.write_oob = part_write_oob;
505        if (master->read_user_prot_reg)
506                slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
507        if (master->read_fact_prot_reg)
508                slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
509        if (master->write_user_prot_reg)
510                slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
511        if (master->lock_user_prot_reg)
512                slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
513        if (master->get_user_prot_info)
514                slave->mtd.get_user_prot_info = part_get_user_prot_info;
515        if (master->get_fact_prot_info)
516                slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
517        if (master->sync)
518                slave->mtd.sync = part_sync;
519        if (!partno && !master->dev.class && master->suspend && master->resume) {
520                        slave->mtd.suspend = part_suspend;
521                        slave->mtd.resume = part_resume;
522        }
523        if (master->writev)
524                slave->mtd.writev = part_writev;
525        if (master->lock)
526                slave->mtd.lock = part_lock;
527        if (master->unlock)
528                slave->mtd.unlock = part_unlock;
529        if (master->is_locked)
530                slave->mtd.is_locked = part_is_locked;
531        if (master->block_isbad)
532                slave->mtd.block_isbad = part_block_isbad;
533        if (master->block_markbad)
534                slave->mtd.block_markbad = part_block_markbad;
535        slave->mtd.erase = part_erase;
536        slave->master = master;
537        slave->offset = part->offset;
538
539        if (slave->offset == MTDPART_OFS_APPEND)
540                slave->offset = cur_offset;
541        if (slave->offset == MTDPART_OFS_NXTBLK) {
542                slave->offset = cur_offset;
543                if (mtd_mod_by_eb(cur_offset, master) != 0) {
544                        /* Round up to next erasesize */
545                        slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
546                        printk(KERN_NOTICE "Moving partition %d: "
547                               "0x%012llx -> 0x%012llx\n", partno,
548                               (unsigned long long)cur_offset, (unsigned long long)slave->offset);
549                }
550        }
551        if (slave->offset == MTDPART_OFS_RETAIN) {
552                slave->offset = cur_offset;
553                if (master->size - slave->offset >= slave->mtd.size) {
554                        slave->mtd.size = master->size - slave->offset
555                                                        - slave->mtd.size;
556                } else {
557                        printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n",
558                                part->name, master->size - slave->offset,
559                                slave->mtd.size);
560                        /* register to preserve ordering */
561                        goto out_register;
562                }
563        }
564        if (slave->mtd.size == MTDPART_SIZ_FULL)
565                slave->mtd.size = master->size - slave->offset;
566
567        printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
568                (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
569
570        /* let's do some sanity checks */
571        if (slave->offset >= master->size) {
572                /* let's register it anyway to preserve ordering */
573                slave->offset = 0;
574                slave->mtd.size = 0;
575                printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",
576                        part->name);
577                goto out_register;
578        }
579        if (slave->offset + slave->mtd.size > master->size) {
580                slave->mtd.size = master->size - slave->offset;
581                printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
582                        part->name, master->name, (unsigned long long)slave->mtd.size);
583        }
584        if (master->numeraseregions > 1) {
585                /* Deal with variable erase size stuff */
586                int i, max = master->numeraseregions;
587                u64 end = slave->offset + slave->mtd.size;
588                struct mtd_erase_region_info *regions = master->eraseregions;
589
590                /* Find the first erase regions which is part of this
591                 * partition. */
592                for (i = 0; i < max && regions[i].offset <= slave->offset; i++)
593                        ;
594                /* The loop searched for the region _behind_ the first one */
595                if (i > 0)
596                        i--;
597
598                /* Pick biggest erasesize */
599                for (; i < max && regions[i].offset < end; i++) {
600                        if (slave->mtd.erasesize < regions[i].erasesize) {
601                                slave->mtd.erasesize = regions[i].erasesize;
602                        }
603                }
604                BUG_ON(slave->mtd.erasesize == 0);
605        } else {
606                /* Single erase size */
607                slave->mtd.erasesize = master->erasesize;
608        }
609
610        if ((slave->mtd.flags & MTD_WRITEABLE) &&
611            mtd_mod_by_eb(slave->offset, &slave->mtd)) {
612                /* Doesn't start on a boundary of major erase size */
613                slave->mtd.flags |= MTD_ERASE_PARTIAL;
614                if (((u32) slave->mtd.size) > master->erasesize)
615                        slave->mtd.flags &= ~MTD_WRITEABLE;
616                else
617                        slave->mtd.erasesize = slave->mtd.size;
618        }
619        if ((slave->mtd.flags & MTD_WRITEABLE) &&
620            mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
621                slave->mtd.flags |= MTD_ERASE_PARTIAL;
622
623                if ((u32) slave->mtd.size > master->erasesize)
624                        slave->mtd.flags &= ~MTD_WRITEABLE;
625                else
626                        slave->mtd.erasesize = slave->mtd.size;
627        }
628        if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL)
629                printk(KERN_WARNING"mtd: partition \"%s\" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only\n",
630                                part->name);
631
632        slave->mtd.ecclayout = master->ecclayout;
633        if (master->block_isbad) {
634                uint64_t offs = 0;
635
636                while (offs < slave->mtd.size) {
637                        if (master->block_isbad(master,
638                                                offs + slave->offset))
639                                slave->mtd.ecc_stats.badblocks++;
640                        offs += slave->mtd.erasesize;
641                }
642        }
643
644out_register:
645        return slave;
646}
647
648int mtd_add_partition(struct mtd_info *master, char *name,
649                      long long offset, long long length)
650{
651        struct mtd_partition part;
652        struct mtd_part *p, *new;
653        uint64_t start, end;
654        int ret = 0;
655
656        /* the direct offset is expected */
657        if (offset == MTDPART_OFS_APPEND ||
658            offset == MTDPART_OFS_NXTBLK)
659                return -EINVAL;
660
661        if (length == MTDPART_SIZ_FULL)
662                length = master->size - offset;
663
664        if (length <= 0)
665                return -EINVAL;
666
667        part.name = name;
668        part.size = length;
669        part.offset = offset;
670        part.mask_flags = 0;
671        part.ecclayout = NULL;
672
673        new = allocate_partition(master, &part, -1, offset);
674        if (IS_ERR(new))
675                return PTR_ERR(new);
676
677        start = offset;
678        end = offset + length;
679
680        mutex_lock(&mtd_partitions_mutex);
681        list_for_each_entry(p, &mtd_partitions, list)
682                if (p->master == master) {
683                        if ((start >= p->offset) &&
684                            (start < (p->offset + p->mtd.size)))
685                                goto err_inv;
686
687                        if ((end >= p->offset) &&
688                            (end < (p->offset + p->mtd.size)))
689                                goto err_inv;
690                }
691
692        list_add(&new->list, &mtd_partitions);
693        mutex_unlock(&mtd_partitions_mutex);
694
695        add_mtd_device(&new->mtd);
696
697        return ret;
698err_inv:
699        mutex_unlock(&mtd_partitions_mutex);
700        free_partition(new);
701        return -EINVAL;
702}
703EXPORT_SYMBOL_GPL(mtd_add_partition);
704
705int mtd_del_partition(struct mtd_info *master, int partno)
706{
707        struct mtd_part *slave, *next;
708        int ret = -EINVAL;
709
710        mutex_lock(&mtd_partitions_mutex);
711        list_for_each_entry_safe(slave, next, &mtd_partitions, list)
712                if ((slave->master == master) &&
713                    (slave->mtd.index == partno)) {
714                        ret = del_mtd_device(&slave->mtd);
715                        if (ret < 0)
716                                break;
717
718                        list_del(&slave->list);
719                        free_partition(slave);
720                        break;
721                }
722        mutex_unlock(&mtd_partitions_mutex);
723
724        return ret;
725}
726EXPORT_SYMBOL_GPL(mtd_del_partition);
727
728#ifdef CONFIG_MTD_ROOTFS_SPLIT
729#define ROOTFS_SPLIT_NAME "rootfs_data"
730#define ROOTFS_REMOVED_NAME "<removed>"
731
732struct squashfs_super_block {
733        __le32 s_magic;
734        __le32 pad0[9];
735        __le64 bytes_used;
736};
737
738
739static int split_squashfs(struct mtd_info *master, int offset, int *split_offset)
740{
741        struct squashfs_super_block sb;
742        int len, ret;
743
744        ret = master->read(master, offset, sizeof(sb), &len, (void *) &sb);
745        if (ret || (len != sizeof(sb))) {
746                printk(KERN_ALERT "split_squashfs: error occured while reading "
747                        "from \"%s\"\n", master->name);
748                return -EINVAL;
749        }
750
751        if (SQUASHFS_MAGIC != le32_to_cpu(sb.s_magic) ) {
752                printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n",
753                        master->name);
754                *split_offset = 0;
755                return 0;
756        }
757
758        if (le64_to_cpu((sb.bytes_used)) <= 0) {
759                printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n",
760                        master->name);
761                *split_offset = 0;
762                return 0;
763        }
764
765        len = (u32) le64_to_cpu(sb.bytes_used);
766        len += (offset & 0x000fffff);
767        len +=  (master->erasesize - 1);
768        len &= ~(master->erasesize - 1);
769        len -= (offset & 0x000fffff);
770        *split_offset = offset + len;
771
772        return 0;
773}
774
775static int split_rootfs_data(struct mtd_info *master, struct mtd_info *rpart, const struct mtd_partition *part)
776{
777        struct mtd_partition *dpart;
778        struct mtd_part *slave = NULL;
779        struct mtd_part *spart;
780        int ret, split_offset = 0;
781
782        spart = PART(rpart);
783        ret = split_squashfs(master, spart->offset, &split_offset);
784        if (ret)
785                return ret;
786
787        if (split_offset <= 0)
788                return 0;
789
790        dpart = kmalloc(sizeof(*part)+sizeof(ROOTFS_SPLIT_NAME)+1, GFP_KERNEL);
791        if (dpart == NULL) {
792                printk(KERN_INFO "split_squashfs: no memory for partition \"%s\"\n",
793                        ROOTFS_SPLIT_NAME);
794                return -ENOMEM;
795        }
796
797        memcpy(dpart, part, sizeof(*part));
798        dpart->name = (unsigned char *)&dpart[1];
799        strcpy(dpart->name, ROOTFS_SPLIT_NAME);
800
801        dpart->size = rpart->size - (split_offset - spart->offset);
802        dpart->offset = split_offset;
803
804        if (dpart == NULL)
805                return 1;
806
807        printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%llX, len=%llX \n",
808                ROOTFS_SPLIT_NAME, dpart->offset, dpart->size);
809
810        slave = allocate_partition(master, dpart, 0, split_offset);
811        if (IS_ERR(slave))
812                return PTR_ERR(slave);
813        mutex_lock(&mtd_partitions_mutex);
814        list_add(&slave->list, &mtd_partitions);
815        mutex_unlock(&mtd_partitions_mutex);
816
817        add_mtd_device(&slave->mtd);
818
819        rpart->split = &slave->mtd;
820
821        return 0;
822}
823
824static int refresh_rootfs_split(struct mtd_info *mtd)
825{
826        struct mtd_partition tpart;
827        struct mtd_part *part;
828        char *name;
829        //int index = 0;
830        int offset, size;
831        int ret;
832
833        part = PART(mtd);
834
835        /* check for the new squashfs offset first */
836        ret = split_squashfs(part->master, part->offset, &offset);
837        if (ret)
838                return ret;
839
840        if ((offset > 0) && !mtd->split) {
841                printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name);
842                /* if we don't have a rootfs split partition, create a new one */
843                tpart.name = (char *) mtd->name;
844                tpart.size = mtd->size;
845                tpart.offset = part->offset;
846
847                return split_rootfs_data(part->master, &part->mtd, &tpart);
848        } else if ((offset > 0) && mtd->split) {
849                /* update the offsets of the existing partition */
850                size = mtd->size + part->offset - offset;
851
852                part = PART(mtd->split);
853                part->offset = offset;
854                part->mtd.size = size;
855                printk(KERN_INFO "%s: %s partition \"" ROOTFS_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n",
856                        __func__, (!strcmp(part->mtd.name, ROOTFS_SPLIT_NAME) ? "updating" : "creating"),
857                        (u32) part->offset, (u32) part->mtd.size);
858                name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
859                strcpy(name, ROOTFS_SPLIT_NAME);
860                part->mtd.name = name;
861        } else if ((offset <= 0) && mtd->split) {
862                printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name);
863
864                /* mark existing partition as removed */
865                part = PART(mtd->split);
866                name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
867                strcpy(name, ROOTFS_REMOVED_NAME);
868                part->mtd.name = name;
869                part->offset = 0;
870                part->mtd.size = 0;
871        }
872
873        return 0;
874}
875#endif /* CONFIG_MTD_ROOTFS_SPLIT */
876
877
878
879/*
880 * This function, given a master MTD object and a partition table, creates
881 * and registers slave MTD objects which are bound to the master according to
882 * the partition definitions.
883 *
884 * We don't register the master, or expect the caller to have done so,
885 * for reasons of data integrity.
886 */
887
888int add_mtd_partitions(struct mtd_info *master,
889                       const struct mtd_partition *parts,
890                       int nbparts)
891{
892        struct mtd_part *slave;
893        uint64_t cur_offset = 0;
894        int i;
895#ifdef CONFIG_MTD_ROOTFS_SPLIT
896        int ret;
897#endif
898
899        printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
900
901        for (i = 0; i < nbparts; i++) {
902                slave = allocate_partition(master, parts + i, i, cur_offset);
903                if (IS_ERR(slave)) {
904                        del_mtd_partitions(master);
905                        return PTR_ERR(slave);
906                }
907
908                mutex_lock(&mtd_partitions_mutex);
909                list_add(&slave->list, &mtd_partitions);
910                mutex_unlock(&mtd_partitions_mutex);
911
912                add_mtd_device(&slave->mtd);
913
914                if (!strcmp(parts[i].name, "rootfs")) {
915#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
916                        if (ROOT_DEV == 0) {
917                                printk(KERN_NOTICE "mtd: partition \"rootfs\" "
918                                        "set to be root filesystem\n");
919                                ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index);
920                        }
921#endif
922#ifdef CONFIG_MTD_ROOTFS_SPLIT
923                        ret = split_rootfs_data(master, &slave->mtd, &parts[i]);
924                        /* if (ret == 0)
925                         *      j++; */
926#endif
927                }
928
929                cur_offset = slave->offset + slave->mtd.size;
930        }
931
932        return 0;
933}
934
935int refresh_mtd_partitions(struct mtd_info *mtd)
936{
937        int ret = 0;
938
939        if (IS_PART(mtd)) {
940                struct mtd_part *part;
941                struct mtd_info *master;
942
943                part = PART(mtd);
944                master = part->master;
945                if (master->refresh_device)
946                        ret = master->refresh_device(master);
947        }
948
949        if (!ret && mtd->refresh_device)
950                ret = mtd->refresh_device(mtd);
951
952#ifdef CONFIG_MTD_ROOTFS_SPLIT
953        if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "rootfs"))
954                refresh_rootfs_split(mtd);
955#endif
956
957        return 0;
958}
959EXPORT_SYMBOL_GPL(refresh_mtd_partitions);
960
961static DEFINE_SPINLOCK(part_parser_lock);
962static LIST_HEAD(part_parsers);
963
964static struct mtd_part_parser *get_partition_parser(const char *name)
965{
966        struct mtd_part_parser *p, *ret = NULL;
967
968        spin_lock(&part_parser_lock);
969
970        list_for_each_entry(p, &part_parsers, list)
971                if (!strcmp(p->name, name) && try_module_get(p->owner)) {
972                        ret = p;
973                        break;
974                }
975
976        spin_unlock(&part_parser_lock);
977
978        return ret;
979}
980
981#define put_partition_parser(p) do { module_put((p)->owner); } while (0)
982
983int register_mtd_parser(struct mtd_part_parser *p)
984{
985        spin_lock(&part_parser_lock);
986        list_add(&p->list, &part_parsers);
987        spin_unlock(&part_parser_lock);
988
989        return 0;
990}
991EXPORT_SYMBOL_GPL(register_mtd_parser);
992
993int deregister_mtd_parser(struct mtd_part_parser *p)
994{
995        spin_lock(&part_parser_lock);
996        list_del(&p->list);
997        spin_unlock(&part_parser_lock);
998        return 0;
999}
1000EXPORT_SYMBOL_GPL(deregister_mtd_parser);
1001
1002/*
1003 * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
1004 * are changing this array!
1005 */
1006static const char *default_mtd_part_types[] = {
1007        "cmdlinepart",
1008        "ofpart",
1009        NULL
1010};
1011
1012/**
1013 * parse_mtd_partitions - parse MTD partitions
1014 * @master: the master partition (describes whole MTD device)
1015 * @types: names of partition parsers to try or %NULL
1016 * @pparts: array of partitions found is returned here
1017 * @data: MTD partition parser-specific data
1018 *
1019 * This function tries to find partition on MTD device @master. It uses MTD
1020 * partition parsers, specified in @types. However, if @types is %NULL, then
1021 * the default list of parsers is used. The default list contains only the
1022 * "cmdlinepart" and "ofpart" parsers ATM.
1023 * Note: If there are more then one parser in @types, the kernel only takes the
1024 * partitions parsed out by the first parser.
1025 *
1026 * This function may return:
1027 * o a negative error code in case of failure
1028 * o zero if no partitions were found
1029 * o a positive number of found partitions, in which case on exit @pparts will
1030 *   point to an array containing this number of &struct mtd_info objects.
1031 */
1032int parse_mtd_partitions(struct mtd_info *master, const char **types,
1033                         struct mtd_partition **pparts,
1034                         struct mtd_part_parser_data *data)
1035{
1036        struct mtd_part_parser *parser;
1037        int ret = 0;
1038
1039        if (!types)
1040                types = default_mtd_part_types;
1041
1042        for ( ; ret <= 0 && *types; types++) {
1043                parser = get_partition_parser(*types);
1044                if (!parser && !request_module("%s", *types))
1045                                parser = get_partition_parser(*types);
1046                if (!parser)
1047                        continue;
1048                ret = (*parser->parse_fn)(master, pparts, data);
1049                put_partition_parser(parser);
1050                if (ret > 0) {
1051                        printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
1052                               ret, parser->name, master->name);
1053                        break;
1054                }
1055        }
1056        return ret;
1057}
1058
1059int mtd_is_partition(struct mtd_info *mtd)
1060{
1061        struct mtd_part *part;
1062        int ispart = 0;
1063
1064        mutex_lock(&mtd_partitions_mutex);
1065        list_for_each_entry(part, &mtd_partitions, list)
1066                if (&part->mtd == mtd) {
1067                        ispart = 1;
1068                        break;
1069                }
1070        mutex_unlock(&mtd_partitions_mutex);
1071
1072        return ispart;
1073}
1074EXPORT_SYMBOL_GPL(mtd_is_partition);
Note: See TracBrowser for help on using the repository browser.