/* Could be our memmap page is filled with PAGE_UNUSED already ... */
vmemmap_mark_sub_pmd_used(start, end);
/* Mark the unused parts of the new memmap page PAGE_UNUSED. */ if (!IS_ALIGNED(start, PMD_SIZE))
memset((void *)page, PAGE_UNUSED, start - page); /* *Wewanttoavoidmemset(PAGE_UNUSED)whenpopulatingthevmemmapof *consecutivesections.RememberforthelastaddedPMDthelast *unusedrangeinthepopulatedPMD.
*/ if (!IS_ALIGNED(end, PMD_SIZE))
unused_sub_pmd_start = end;
}
/* Returns true if the PMD is completely unused and can be freed. */ staticbool vmemmap_unuse_sub_pmd(unsignedlong start, unsignedlong end)
{ unsignedlong page = ALIGN_DOWN(start, PMD_SIZE);
staticvoid try_free_pte_table(pmd_t *pmd, unsignedlong start)
{
pte_t *pte; int i;
/* We can safely assume this is fully in 1:1 mapping & vmemmap area */
pte = pte_offset_kernel(pmd, start); for (i = 0; i < PTRS_PER_PTE; i++, pte++) { if (!pte_none(*pte)) return;
}
vmem_pte_free((unsignedlong *) pmd_deref(*pmd));
pmd_clear(pmd);
}
/* __ref: we'll only call vmemmap_alloc_block() via vmemmap_populate() */ staticint __ref modify_pmd_table(pud_t *pud, unsignedlong addr, unsignedlong end, bool add, bool direct, struct vmem_altmap *altmap)
{ unsignedlong next, prot, pages = 0; int ret = -ENOMEM;
pmd_t *pmd;
pte_t *pte;
prot = pgprot_val(SEGMENT_KERNEL);
pmd = pmd_offset(pud, addr); for (; addr < end; addr = next, pmd++) {
next = pmd_addr_end(addr, end); if (!add) { if (pmd_none(*pmd)) continue; if (pmd_leaf(*pmd)) { if (IS_ALIGNED(addr, PMD_SIZE) &&
IS_ALIGNED(next, PMD_SIZE)) { if (!direct)
vmem_free_pages(pmd_deref(*pmd), get_order(PMD_SIZE), altmap);
pmd_clear(pmd);
pages++;
} elseif (!direct && vmemmap_unuse_sub_pmd(addr, next)) {
vmem_free_pages(pmd_deref(*pmd), get_order(PMD_SIZE), altmap);
pmd_clear(pmd);
} continue;
}
} elseif (pmd_none(*pmd)) { if (IS_ALIGNED(addr, PMD_SIZE) &&
IS_ALIGNED(next, PMD_SIZE) &&
cpu_has_edat1() && direct &&
!debug_pagealloc_enabled()) {
set_pmd(pmd, __pmd(__pa(addr) | prot));
pages++; continue;
} elseif (!direct && cpu_has_edat1()) { void *new_page;
/* *Use1MBframesforvmemmapifavailable.We *alwaysuselargeframeseveniftheyareonly *partiallyused.Otherwisewewouldhavealso *pagetablessincevmemmap_populategets *calledforeachsectionseparately.
*/
new_page = vmemmap_alloc_block_buf(PMD_SIZE, NUMA_NO_NODE, altmap); if (new_page) {
set_pmd(pmd, __pmd(__pa(new_page) | prot)); if (!IS_ALIGNED(addr, PMD_SIZE) ||
!IS_ALIGNED(next, PMD_SIZE)) {
vmemmap_use_new_sub_pmd(addr, next);
} continue;
}
}
pte = vmem_pte_alloc(); if (!pte) goto out;
pmd_populate(&init_mm, pmd, pte);
} elseif (pmd_leaf(*pmd)) { if (!direct)
vmemmap_use_sub_pmd(addr, next); continue;
}
ret = modify_pte_table(pmd, addr, next, add, direct, altmap); if (ret) goto out; if (!add)
try_free_pte_table(pmd, addr & PMD_MASK);
}
ret = 0;
out: if (direct)
update_page_count(PG_DIRECT_MAP_1M, add ? pages : -pages); return ret;
}
staticvoid try_free_pmd_table(pud_t *pud, unsignedlong start)
{
pmd_t *pmd; int i;
pmd = pmd_offset(pud, start); for (i = 0; i < PTRS_PER_PMD; i++, pmd++) if (!pmd_none(*pmd)) return;
vmem_free_pages(pud_deref(*pud), CRST_ALLOC_ORDER, NULL);
pud_clear(pud);
}
if (WARN_ON_ONCE(!PAGE_ALIGNED(start | end))) return -EINVAL; /* Don't mess with any tables not fully in 1:1 mapping & vmemmap area */ if (WARN_ON_ONCE(end > __abs_lowcore)) return -EINVAL; for (addr = start; addr < end; addr = next) {
next = pgd_addr_end(addr, end);
pgd = pgd_offset_k(addr);
if (!add) { if (pgd_none(*pgd)) continue;
} elseif (pgd_none(*pgd)) {
p4d = vmem_crst_alloc(_REGION2_ENTRY_EMPTY); if (!p4d) goto out;
pgd_populate(&init_mm, pgd, p4d);
}
ret = modify_p4d_table(pgd, addr, next, add, direct, altmap); if (ret) goto out; if (!add)
try_free_p4d_table(pgd, addr & PGDIR_MASK);
}
ret = 0;
out: if (!add)
flush_tlb_kernel_range(start, end); return ret;
}
/* *Addabackedmem_maparraytothevirtualmem_maparray.
*/ int __meminit vmemmap_populate(unsignedlong start, unsignedlong end, int node, struct vmem_altmap *altmap)
{ int ret;
mutex_lock(&vmem_mutex); /* We don't care about the node, just use NUMA_NO_NODE on allocations */
ret = add_pagetable(start, end, false, altmap); if (ret)
remove_pagetable(start, end, false, altmap);
mutex_unlock(&vmem_mutex); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.