diff options
-rw-r--r-- | include/linux/gfp.h | 3 | ||||
-rw-r--r-- | mm/page_alloc.c | 53 |
2 files changed, 56 insertions, 0 deletions
diff --git a/include/linux/gfp.h b/include/linux/gfp.h index f640ed241422..e8003afeffba 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h | |||
@@ -228,6 +228,9 @@ extern struct page *alloc_page_vma(gfp_t gfp_mask, | |||
228 | extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); | 228 | extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); |
229 | extern unsigned long get_zeroed_page(gfp_t gfp_mask); | 229 | extern unsigned long get_zeroed_page(gfp_t gfp_mask); |
230 | 230 | ||
231 | void *alloc_pages_exact(size_t size, gfp_t gfp_mask); | ||
232 | void free_pages_exact(void *virt, size_t size); | ||
233 | |||
231 | #define __get_free_page(gfp_mask) \ | 234 | #define __get_free_page(gfp_mask) \ |
232 | __get_free_pages((gfp_mask),0) | 235 | __get_free_pages((gfp_mask),0) |
233 | 236 | ||
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; |