void __ref vmemmap_free(unsigned long start, unsigned long end, struct vmem_altmap *altmap) { unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift; unsigned long page_order = get_order(page_size); unsigned long alt_start = ~0, alt_end = ~0; unsigned long base_pfn; start = _ALIGN_DOWN(start, page_size); if (altmap) { alt_start = altmap->base_pfn; alt_end = altmap->base_pfn + altmap->reserve + altmap->free + altmap->alloc + altmap->align; } pr_debug("vmemmap_free %lx...%lx\n", start, end); for (; start < end; start += page_size) { unsigned long nr_pages, addr; struct page *section_base; struct page *page; /* * the section has already be marked as invalid, so * vmemmap_populated() true means some other sections still * in this page, so skip it. */ if (vmemmap_populated(start, page_size)) continue; addr = vmemmap_list_free(start); if (!addr) continue; page = pfn_to_page(addr >> PAGE_SHIFT); section_base = pfn_to_page(vmemmap_section_start(start)); nr_pages = 1 << page_order; base_pfn = PHYS_PFN(addr); if (base_pfn >= alt_start && base_pfn < alt_end) { vmem_altmap_free(altmap, nr_pages); } else if (PageReserved(page)) { /* allocated from bootmem */ if (page_size < PAGE_SIZE) { /* * this shouldn't happen, but if it is * the case, leave the memory there */ WARN_ON_ONCE(1); } else { while (nr_pages--) free_reserved_page(page++); } } else { free_pages((unsigned long)(__va(addr)), page_order); } vmemmap_remove_mapping(start, page_size); } }
/* * Check if this vmemmap page is already initialised. If any section * which overlaps this vmemmap page is initialised then this page is * initialised already. */ static int __meminit vmemmap_populated(unsigned long start, int page_size) { unsigned long end = start + page_size; start = (unsigned long)(pfn_to_page(vmemmap_section_start(start))); for (; start < end; start += (PAGES_PER_SECTION * sizeof(struct page))) if (pfn_valid(page_to_pfn((struct page *)start))) return 1; return 0; }