Skip to content

Commit aa5de30

Browse files
liu-song-6torvalds
authored andcommitted
kernel/events/uprobes.c: only do FOLL_SPLIT_PMD for uprobe register
Attaching uprobe to text section in THP splits the PMD mapped page table into PTE mapped entries. On uprobe detach, we would like to regroup PMD mapped page table entry to regain performance benefit of THP. However, the regroup is broken For perf_event based trace_uprobe. This is because perf_event based trace_uprobe calls uprobe_unregister twice on close: first in TRACE_REG_PERF_CLOSE, then in TRACE_REG_PERF_UNREGISTER. The second call will split the PMD mapped page table entry, which is not the desired behavior. Fix this by only use FOLL_SPLIT_PMD for uprobe register case. Add a WARN() to confirm uprobe unregister never work on huge pages, and abort the operation when this WARN() triggers. Link: http://lkml.kernel.org/r/[email protected] Fixes: 5a52c9d ("uprobe: use FOLL_SPLIT_PMD instead of FOLL_SPLIT") Signed-off-by: Song Liu <[email protected]> Reviewed-by: Srikar Dronamraju <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Cc: Oleg Nesterov <[email protected]> Cc: Matthew Wilcox (Oracle) <[email protected]> Cc: William Kucharski <[email protected]> Cc: Yang Shi <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent ef18a1c commit aa5de30

File tree

1 file changed

+11
-2
lines changed

1 file changed

+11
-2
lines changed

kernel/events/uprobes.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,21 +474,30 @@ int uprobe_write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
474474
struct vm_area_struct *vma;
475475
int ret, is_register, ref_ctr_updated = 0;
476476
bool orig_page_huge = false;
477+
unsigned int gup_flags = FOLL_FORCE;
477478

478479
is_register = is_swbp_insn(&opcode);
479480
uprobe = container_of(auprobe, struct uprobe, arch);
480481

481482
retry:
483+
if (is_register)
484+
gup_flags |= FOLL_SPLIT_PMD;
482485
/* Read the page with vaddr into memory */
483-
ret = get_user_pages_remote(NULL, mm, vaddr, 1,
484-
FOLL_FORCE | FOLL_SPLIT_PMD, &old_page, &vma, NULL);
486+
ret = get_user_pages_remote(NULL, mm, vaddr, 1, gup_flags,
487+
&old_page, &vma, NULL);
485488
if (ret <= 0)
486489
return ret;
487490

488491
ret = verify_opcode(old_page, vaddr, &opcode);
489492
if (ret <= 0)
490493
goto put_old;
491494

495+
if (WARN(!is_register && PageCompound(old_page),
496+
"uprobe unregister should never work on compound page\n")) {
497+
ret = -EINVAL;
498+
goto put_old;
499+
}
500+
492501
/* We are going to replace instruction, update ref_ctr. */
493502
if (!ref_ctr_updated && uprobe->ref_ctr_offset) {
494503
ret = update_ref_ctr(uprobe, mm, is_register ? 1 : -1);

0 commit comments

Comments
 (0)