Add a check in populate_pgd to make sure that populate_pud is called on a range that actually fits inside a PUD. Signed-off-by: Arvind Sankar <nivedita@xxxxxxxxxxxx> --- arch/x86/mm/pat/set_memory.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index d0b7b06253a5..a1003bc9fdf6 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -1420,6 +1420,7 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr) p4d_t *p4d; pgd_t *pgd_entry; long ret; + unsigned long end, end_p4d; pgd_entry = cpa->pgd + pgd_index(addr); @@ -1443,6 +1444,15 @@ static int populate_pgd(struct cpa_data *cpa, unsigned long addr) set_p4d(p4d, __p4d(__pa(pud) | _KERNPG_TABLE)); } + /* + * Ensure that the range fits inside one p4d entry. If a larger range + * was requested, __change_page_attr_set_clr will loop to finish it. + */ + end = addr + (cpa->numpages << PAGE_SHIFT); + end_p4d = (addr + P4D_SIZE) & P4D_MASK; + if (end_p4d < end) + cpa->numpages = (end_p4d - addr) >> PAGE_SHIFT; + pgprot_val(pgprot) &= ~pgprot_val(cpa->mask_clr); pgprot_val(pgprot) |= pgprot_val(cpa->mask_set); -- 2.24.1