diff options
-rw-r--r-- | drivers/mtd/mtdcore.c | 49 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 2 |
2 files changed, 51 insertions, 0 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index da69bc8a5a7d..a50348b60d79 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
@@ -638,6 +638,54 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, | |||
638 | return ret; | 638 | return ret; |
639 | } | 639 | } |
640 | 640 | ||
641 | /** | ||
642 | * mtd_kmalloc_up_to - allocate a contiguous buffer up to the specified size | ||
643 | * @size: A pointer to the ideal or maximum size of the allocation. Points | ||
644 | * to the actual allocation size on success. | ||
645 | * | ||
646 | * This routine attempts to allocate a contiguous kernel buffer up to | ||
647 | * the specified size, backing off the size of the request exponentially | ||
648 | * until the request succeeds or until the allocation size falls below | ||
649 | * the system page size. This attempts to make sure it does not adversely | ||
650 | * impact system performance, so when allocating more than one page, we | ||
651 | * ask the memory allocator to avoid re-trying, swapping, writing back | ||
652 | * or performing I/O. | ||
653 | * | ||
654 | * Note, this function also makes sure that the allocated buffer is aligned to | ||
655 | * the MTD device's min. I/O unit, i.e. the "mtd->writesize" value. | ||
656 | * | ||
657 | * This is called, for example by mtd_{read,write} and jffs2_scan_medium, | ||
658 | * to handle smaller (i.e. degraded) buffer allocations under low- or | ||
659 | * fragmented-memory situations where such reduced allocations, from a | ||
660 | * requested ideal, are allowed. | ||
661 | * | ||
662 | * Returns a pointer to the allocated buffer on success; otherwise, NULL. | ||
663 | */ | ||
664 | void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size) | ||
665 | { | ||
666 | gfp_t flags = __GFP_NOWARN | __GFP_WAIT | | ||
667 | __GFP_NORETRY | __GFP_NO_KSWAPD; | ||
668 | size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE); | ||
669 | void *kbuf; | ||
670 | |||
671 | *size = min_t(size_t, *size, KMALLOC_MAX_SIZE); | ||
672 | |||
673 | while (*size > min_alloc) { | ||
674 | kbuf = kmalloc(*size, flags); | ||
675 | if (kbuf) | ||
676 | return kbuf; | ||
677 | |||
678 | *size >>= 1; | ||
679 | *size = ALIGN(*size, mtd->writesize); | ||
680 | } | ||
681 | |||
682 | /* | ||
683 | * For the last resort allocation allow 'kmalloc()' to do all sorts of | ||
684 | * things (write-back, dropping caches, etc) by using GFP_KERNEL. | ||
685 | */ | ||
686 | return kmalloc(*size, GFP_KERNEL); | ||
687 | } | ||
688 | |||
641 | EXPORT_SYMBOL_GPL(add_mtd_device); | 689 | EXPORT_SYMBOL_GPL(add_mtd_device); |
642 | EXPORT_SYMBOL_GPL(del_mtd_device); | 690 | EXPORT_SYMBOL_GPL(del_mtd_device); |
643 | EXPORT_SYMBOL_GPL(get_mtd_device); | 691 | EXPORT_SYMBOL_GPL(get_mtd_device); |
@@ -648,6 +696,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device); | |||
648 | EXPORT_SYMBOL_GPL(register_mtd_user); | 696 | EXPORT_SYMBOL_GPL(register_mtd_user); |
649 | EXPORT_SYMBOL_GPL(unregister_mtd_user); | 697 | EXPORT_SYMBOL_GPL(unregister_mtd_user); |
650 | EXPORT_SYMBOL_GPL(default_mtd_writev); | 698 | EXPORT_SYMBOL_GPL(default_mtd_writev); |
699 | EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to); | ||
651 | 700 | ||
652 | #ifdef CONFIG_PROC_FS | 701 | #ifdef CONFIG_PROC_FS |
653 | 702 | ||
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 9d5306bad117..06b489a7605b 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -348,6 +348,8 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, | |||
348 | int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, | 348 | int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, |
349 | unsigned long count, loff_t from, size_t *retlen); | 349 | unsigned long count, loff_t from, size_t *retlen); |
350 | 350 | ||
351 | void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size); | ||
352 | |||
351 | #ifdef CONFIG_MTD_PARTITIONS | 353 | #ifdef CONFIG_MTD_PARTITIONS |
352 | void mtd_erase_callback(struct erase_info *instr); | 354 | void mtd_erase_callback(struct erase_info *instr); |
353 | #else | 355 | #else |