aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/mtdcore.c49
-rw-r--r--include/linux/mtd/mtd.h2
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 */
664void *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
641EXPORT_SYMBOL_GPL(add_mtd_device); 689EXPORT_SYMBOL_GPL(add_mtd_device);
642EXPORT_SYMBOL_GPL(del_mtd_device); 690EXPORT_SYMBOL_GPL(del_mtd_device);
643EXPORT_SYMBOL_GPL(get_mtd_device); 691EXPORT_SYMBOL_GPL(get_mtd_device);
@@ -648,6 +696,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device);
648EXPORT_SYMBOL_GPL(register_mtd_user); 696EXPORT_SYMBOL_GPL(register_mtd_user);
649EXPORT_SYMBOL_GPL(unregister_mtd_user); 697EXPORT_SYMBOL_GPL(unregister_mtd_user);
650EXPORT_SYMBOL_GPL(default_mtd_writev); 698EXPORT_SYMBOL_GPL(default_mtd_writev);
699EXPORT_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,
348int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, 348int 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
351void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);
352
351#ifdef CONFIG_MTD_PARTITIONS 353#ifdef CONFIG_MTD_PARTITIONS
352void mtd_erase_callback(struct erase_info *instr); 354void mtd_erase_callback(struct erase_info *instr);
353#else 355#else