===================================================================
@@ -0,0 +1,233 @@
+struct page_range {
+ unsigned long base, end, pages;
+};
+
+int __get_contig_block(unsigned long pfn, unsigned long nr_pages, void *arg)
+{
+ struct page_range *blockinfo = arg;
+
+ if (nr_pages > blockinfo->pages) {
+ blockinfo->base = pfn;
+ blockinfo->end = pfn + nr_pages;
+ return 1;
+ }
+ return 0;
+}
+
+
+unsigned long __find_contig_block(unsigned long base,
+ unsigned long end, unsigned long pages)
+{
+ unsigned long pfn, tmp, index;
+ struct page_range blockinfo;
+ int ret;
+
+ /* Skip memory holes */
+retry:
+ blockinfo.base = base;
+ blockinfo.end = end;
+ blockinfo.pages = pages;
+ ret = walk_system_ram_range(base, end - base, &blockinfo,
+ __get_contig_block);
+ if (!ret)
+ return 0;
+ /* Ok, we gound contiguous memory chunk of size. Isolate it.*/
+ for (pfn = blockinfo->base; pfn + pages < blockinfo->end;) {
+
+ for (index = 0; index < nr_pages; index += pageblock_nr_pages)
+ struct page *page;
+
+ page = pfn_to_page(pfn+index);
+ if (set_migratetype_isoalte(page))
+ break;
+ }
+ if (index == nr_pages)
+ return pfn; /* [pfn...pfn+nr_pages) are isolated */
+ /* rollback */
+ for (tmp = 0; tmp < index; tmp += pageblock_nr_pages) {
+ page = pfn_to_page(pfn+tmp);
+ unset_migratetype_isolate(page);
+ }
+ pfn += index;
+ }
+ /* failed ? */
+ if (blockinfo.end + pages < end) {
+ /* Move base address and find the next block */
+ base = blockinfo.end;
+ goto retry;
+ }
+ return 0;
+}
+
+unsigned long
+find_isolate_conting_block(unsigned long hint, unsigned long size)
+{
+ unsigned long base, found, end, blocks, pages;
+ unsigned long *map;
+ int nid, retry;
+ physaddr_t addr = 0;
+
+ pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ pages = ALIGN(pages, pageblock_nr_pages);
+ blocks = pages/pageblock_nr_pages;
+ base = hint;
+
+retry:
+ for_each_node_state(nid, N_HIGH_MEMORY) {
+ unsigned long start;
+ pg_data_t *node = NODE_DATA(nid);
+
+ if (node->node_start_pfn + node->node_end_pfn - base < pages)
+ continue;
+ if (base < node->node_start_pfn)
+ base = node->node_start_pfn;
+ end = node->node_end_pfn;
+ /* Maybe we can use this Node */
+ found = __find_contig_block(base, end, blocks);
+ if (found) /* Found ? */
+ break;
+ base = end; /* try next node*/
+ }
+ if (!found)
+ goto out;
+ /*
+ * Ok, here, we have contiguous pageblock marked as "isolated"
+ * try migration.
+ */
+ retry = 5;
+ while (retry--) {
+ if (!do_migrate_range(found, found + pages))
+ break;
+ lru_add_drain_all();
+ flush_scheduled_work();
+ cond_resched();
+ drain_all_pages();
+ }
+ lru_add_drain_all();
+ flush_scheduled_work();
+ drain_all_pages();
+ offlined_pages = check_pages_isolated(found, found+pages);
+ /* Ok, here, [found...found+pages) memory are isolated */
+out:
+ return found;
+}
--
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