diff options
author | Timur Tabi <timur@freescale.com> | 2008-07-24 00:28:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 13:47:20 -0400 |
commit | 2be0ffe2b29bd31d3debd0877797892ff2d91f4c (patch) | |
tree | 7f6e56b3fc5a721296851448e3facf821ef543dd /mm | |
parent | 3560e249abda6bee41a07a7bf0383a6e193e2839 (diff) |
mm: add alloc_pages_exact() and free_pages_exact()
alloc_pages_exact() is similar to alloc_pages(), except that it allocates
the minimum number of pages to fulfill the request. This is useful if you
want to allocate a very large buffer that is slightly larger than an even
power-of-two number of pages. In that case, alloc_pages() will waste a
lot of memory.
I have a video driver that wants to allocate a 5MB buffer. alloc_pages()
wiill waste 3MB of physically-contiguous memory.
Signed-off-by: Timur Tabi <timur@freescale.com>
Cc: Andi Kleen <andi@firstfloor.org>
Acked-by: Mel Gorman <mel@csn.ul.ie>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/page_alloc.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index eaa86671ebbd..8d528d57b403 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1697,6 +1697,59 @@ void free_pages(unsigned long addr, unsigned int order) | |||
1697 | 1697 | ||
1698 | EXPORT_SYMBOL(free_pages); | 1698 | EXPORT_SYMBOL(free_pages); |
1699 | 1699 | ||
1700 | /** | ||
1701 | * alloc_pages_exact - allocate an exact number physically-contiguous pages. | ||
1702 | * @size: the number of bytes to allocate | ||
1703 | * @gfp_mask: GFP flags for the allocation | ||
1704 | * | ||
1705 | * This function is similar to alloc_pages(), except that it allocates the | ||
1706 | * minimum number of pages to satisfy the request. alloc_pages() can only | ||
1707 | * allocate memory in power-of-two pages. | ||
1708 | * | ||
1709 | * This function is also limited by MAX_ORDER. | ||
1710 | * | ||
1711 | * Memory allocated by this function must be released by free_pages_exact(). | ||
1712 | */ | ||
1713 | void *alloc_pages_exact(size_t size, gfp_t gfp_mask) | ||
1714 | { | ||
1715 | unsigned int order = get_order(size); | ||
1716 | unsigned long addr; | ||
1717 | |||
1718 | addr = __get_free_pages(gfp_mask, order); | ||
1719 | if (addr) { | ||
1720 | unsigned long alloc_end = addr + (PAGE_SIZE << order); | ||
1721 | unsigned long used = addr + PAGE_ALIGN(size); | ||
1722 | |||
1723 | split_page(virt_to_page(addr), order); | ||
1724 | while (used < alloc_end) { | ||
1725 | free_page(used); | ||
1726 | used += PAGE_SIZE; | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | return (void *)addr; | ||
1731 | } | ||
1732 | EXPORT_SYMBOL(alloc_pages_exact); | ||
1733 | |||
1734 | /** | ||
1735 | * free_pages_exact - release memory allocated via alloc_pages_exact() | ||
1736 | * @virt: the value returned by alloc_pages_exact. | ||
1737 | * @size: size of allocation, same value as passed to alloc_pages_exact(). | ||
1738 | * | ||
1739 | * Release the memory allocated by a previous call to alloc_pages_exact. | ||
1740 | */ | ||
1741 | void free_pages_exact(void *virt, size_t size) | ||
1742 | { | ||
1743 | unsigned long addr = (unsigned long)virt; | ||
1744 | unsigned long end = addr + PAGE_ALIGN(size); | ||
1745 | |||
1746 | while (addr < end) { | ||
1747 | free_page(addr); | ||
1748 | addr += PAGE_SIZE; | ||
1749 | } | ||
1750 | } | ||
1751 | EXPORT_SYMBOL(free_pages_exact); | ||
1752 | |||
1700 | static unsigned int nr_free_zone_pages(int offset) | 1753 | static unsigned int nr_free_zone_pages(int offset) |
1701 | { | 1754 | { |
1702 | struct zoneref *z; | 1755 | struct zoneref *z; |