Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerepc/book3s64/hash: Align start/end address correctly with bolt mapping

This ensures we don't do a partial mapping of memory. With nvdimm, when
creating namespaces with size not aligned to 16MB, the kernel ends up partially
mapping the pages. This can result in kernel adding multiple hash page table
entries for the same range. A new namespace will result in
create_section_mapping() with start and end overlapping an already existing
bolted hash page table entry.

commit: 6acd7d5ef264 ("libnvdimm/namespace: Enforce memremap_compat_align()")
made sure that we always create namespaces aligned to 16MB. But we can do
better by avoiding mapping pages that are not aligned. This helps to catch
access to these partially mapped pages early.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200907072539.67310-1-aneesh.kumar@linux.ibm.com

authored by

Aneesh Kumar K.V and committed by
Michael Ellerman
79b123cd bbc4f40b

+10 -3
+9 -3
arch/powerpc/mm/book3s64/hash_utils.c
··· 260 260 DBG("htab_bolt_mapping(%lx..%lx -> %lx (%lx,%d,%d)\n", 261 261 vstart, vend, pstart, prot, psize, ssize); 262 262 263 - for (vaddr = vstart, paddr = pstart; vaddr < vend; 264 - vaddr += step, paddr += step) { 263 + /* Carefully map only the possible range */ 264 + vaddr = ALIGN(vstart, step); 265 + paddr = ALIGN(pstart, step); 266 + vend = ALIGN_DOWN(vend, step); 267 + 268 + for (; vaddr < vend; vaddr += step, paddr += step) { 265 269 unsigned long hash, hpteg; 266 270 unsigned long vsid = get_kernel_vsid(vaddr, ssize); 267 271 unsigned long vpn = hpt_vpn(vaddr, vsid, ssize); ··· 347 343 if (!mmu_hash_ops.hpte_removebolted) 348 344 return -ENODEV; 349 345 350 - for (vaddr = vstart; vaddr < vend; vaddr += step) { 346 + /* Unmap the full range specificied */ 347 + vaddr = ALIGN_DOWN(vstart, step); 348 + for (;vaddr < vend; vaddr += step) { 351 349 rc = mmu_hash_ops.hpte_removebolted(vaddr, psize, ssize); 352 350 if (rc == -ENOENT) { 353 351 ret = -ENOENT;
+1
arch/powerpc/mm/book3s64/radix_pgtable.c
··· 276 276 int psize; 277 277 278 278 start = ALIGN(start, PAGE_SIZE); 279 + end = ALIGN_DOWN(end, PAGE_SIZE); 279 280 for (addr = start; addr < end; addr += mapping_size) { 280 281 unsigned long gap, previous_size; 281 282 int rc;