diff mbox

[04/12] mm: alloc_contig_freed_pages() added

Message ID 1301577368-16095-5-git-send-email-m.szyprowski@samsung.com (mailing list archive)
State RFC
Headers show

Commit Message

Marek Szyprowski March 31, 2011, 1:16 p.m. UTC
None

Comments

Marek Szyprowski April 5, 2011, 7:23 a.m. UTC | #1
Hello,

On Monday, April 04, 2011 3:15 PM Micha? Nazarewicz wrote:

> > What kind of success have you had running this in practice?  I'd be
> > worried that some silly task or a sticky dentry would end up in the
> > range that you want to allocate in.
> 
> I'm not sure what you are asking.
> 
> The function requires the range to be marked as MIGRATE_ISOLATE and all
> pages being free, so nothing can be allocated there while the function
> is running.
> 
> If you are asking about CMA in general, the range that CMA uses is marked
> as MIGRATE_CMA (a new migrate type) which means that only MIGRATE_MOVABLE
> pages can be allocated there.  This means, that in theory, if there is
> enough memory the pages can always be moved out of the region.  At leasts
> that's my understanding of the type.  If this is correct, the allocation
> should always succeed provided enough memory for the pages within the
> region to be moved to is available.
> 
> As of practice, I have run some simple test to see if the code works and
> they succeeded.  Also, Marek has run some test with actual hardware and
> those worked well as well (but I'll let Marek talk about any details).

We did the tests with real multimedia drivers - video codec and video
converter (s5p-mfc and s5p-fimc). These drivers allocate large contiguous 
buffers for video data. The allocation is performed when driver is opened
by user space application. 

First we consumed system memory by running a set of simple applications
that just did some malloc() and filled memory with random pattern to consume
free pages. Then some of that memory has been freed and we ran the video
decoding application. Multimedia drivers successfully managed to allocate
required contiguous buffers from MIGRATE_CMA ranges.

The tests have been performed with different system usage patterns (malloc(),
heavy filesystem load, anonymous memory mapping). In all these cases CMA
worked surprisingly good allowing the drivers to allocate the required 
contiguous buffers.

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/page-isolation.h b/include/linux/page-isolation.h
index 58cdbac..f1417ed 100644
--- a/include/linux/page-isolation.h
+++ b/include/linux/page-isolation.h
@@ -32,6 +32,9 @@  test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn);
  */
 extern int set_migratetype_isolate(struct page *page);
 extern void unset_migratetype_isolate(struct page *page);
+extern unsigned long alloc_contig_freed_pages(unsigned long start,
+					      unsigned long end, gfp_t flag);
+extern void free_contig_pages(struct page *page, int nr_pages);
 
 /*
  * For migration.
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d6e7ba7..11f8bcb 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5545,6 +5545,50 @@  out:
 	spin_unlock_irqrestore(&zone->lock, flags);
 }
 
+unsigned long alloc_contig_freed_pages(unsigned long start, unsigned long end,
+				       gfp_t flag)
+{
+	unsigned long pfn = start, count;
+	struct page *page;
+	struct zone *zone;
+	int order;
+
+	VM_BUG_ON(!pfn_valid(start));
+	zone = page_zone(pfn_to_page(start));
+
+	spin_lock_irq(&zone->lock);
+
+	page = pfn_to_page(pfn);
+	for (;;) {
+		VM_BUG_ON(page_count(page) || !PageBuddy(page));
+		list_del(&page->lru);
+		order = page_order(page);
+		zone->free_area[order].nr_free--;
+		rmv_page_order(page);
+		__mod_zone_page_state(zone, NR_FREE_PAGES, -(1UL << order));
+		pfn  += 1 << order;
+		if (pfn >= end)
+			break;
+		VM_BUG_ON(!pfn_valid(pfn));
+		page += 1 << order;
+	}
+
+	spin_unlock_irq(&zone->lock);
+
+	/* After this, pages in the range can be freed one be one */
+	page = pfn_to_page(start);
+	for (count = pfn - start; count; --count, ++page)
+		prep_new_page(page, 0, flag);
+
+	return pfn;
+}
+
+void free_contig_pages(struct page *page, int nr_pages)
+{
+	for (; nr_pages; --nr_pages, ++page)
+		__free_page(page);
+}
+
 #ifdef CONFIG_MEMORY_HOTREMOVE
 /*
  * All pages in the range must be isolated before calling this.