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

Configure Feed

Select the types of activity you want to include in your feed.

kernel/events/uprobes: pass VMA instead of MM to remove_breakpoint()

Patch series "kernel/events/uprobes: uprobe_write_opcode() rewrite", v3.

Currently, uprobe_write_opcode() implements COW-breaking manually, which
is really far from ideal. Further, there is interest in supporting
uprobes on hugetlb pages [1], and leaving at least the COW-breaking to the
core will make this much easier.

Also, I think the current code doesn't really handle some things properly
(see patch #3) when replacing/zapping pages.

Let's rewrite it, to leave COW-breaking to the fault handler, and handle
registration/unregistration by temporarily unmapping the anonymous page,
modifying it, and mapping it again. We still have to implement zapping of
anonymous pages ourselves, unfortunately.

We could look into not performing the temporary unmapping if we can
perform the write atomically, which would likely also make adding hugetlb
support a lot easier. But, limited (e.g., only PMD/PUD) hugetlb support
could be added on top of this with some tweaking.

Note that we now won't have to allocate another anonymous folio when
unregistering (which will be beneficial for hugetlb as well), we can
simply modify the already-mapped one from the registration (if any). When
registering a uprobe, we'll first trigger a ptrace-like write fault to
break COW, to then modify the already-mapped page.

Briefly sanity tested with perf probes and with the bpf uprobes selftest.


This patch (of 3):

Pass VMA instead of MM to remove_breakpoint() and remove the "MM" argument
from install_breakpoint(), because it can easily be derived from the VMA.

Link: https://lkml.kernel.org/r/20250321113713.204682-1-david@redhat.com
Link: https://lkml.kernel.org/r/20250321113713.204682-2-david@redhat.com
Signed-off-by: David Hildenbrand <david@redhat.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Jiri Olsa <olsajiri@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Namhyung kim <namhyung@kernel.org>
Cc: Russel King <linux@armlinux.org.uk>
Cc: tongtiangen <tongtiangen@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

David Hildenbrand and committed by
Andrew Morton
b56e6446 79049bb4

+11 -9
+11 -9
kernel/events/uprobes.c
··· 1134 1134 return ret; 1135 1135 } 1136 1136 1137 - static int 1138 - install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, 1139 - struct vm_area_struct *vma, unsigned long vaddr) 1137 + static int install_breakpoint(struct uprobe *uprobe, struct vm_area_struct *vma, 1138 + unsigned long vaddr) 1140 1139 { 1140 + struct mm_struct *mm = vma->vm_mm; 1141 1141 bool first_uprobe; 1142 1142 int ret; 1143 1143 ··· 1162 1162 return ret; 1163 1163 } 1164 1164 1165 - static int 1166 - remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) 1165 + static int remove_breakpoint(struct uprobe *uprobe, struct vm_area_struct *vma, 1166 + unsigned long vaddr) 1167 1167 { 1168 + struct mm_struct *mm = vma->vm_mm; 1169 + 1168 1170 set_bit(MMF_RECALC_UPROBES, &mm->flags); 1169 1171 return set_orig_insn(&uprobe->arch, mm, vaddr); 1170 1172 } ··· 1298 1296 if (is_register) { 1299 1297 /* consult only the "caller", new consumer. */ 1300 1298 if (consumer_filter(new, mm)) 1301 - err = install_breakpoint(uprobe, mm, vma, info->vaddr); 1299 + err = install_breakpoint(uprobe, vma, info->vaddr); 1302 1300 } else if (test_bit(MMF_HAS_UPROBES, &mm->flags)) { 1303 1301 if (!filter_chain(uprobe, mm)) 1304 - err |= remove_breakpoint(uprobe, mm, info->vaddr); 1302 + err |= remove_breakpoint(uprobe, vma, info->vaddr); 1305 1303 } 1306 1304 1307 1305 unlock: ··· 1474 1472 continue; 1475 1473 1476 1474 vaddr = offset_to_vaddr(vma, uprobe->offset); 1477 - err |= remove_breakpoint(uprobe, mm, vaddr); 1475 + err |= remove_breakpoint(uprobe, vma, vaddr); 1478 1476 } 1479 1477 mmap_read_unlock(mm); 1480 1478 ··· 1612 1610 if (!fatal_signal_pending(current) && 1613 1611 filter_chain(uprobe, vma->vm_mm)) { 1614 1612 unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset); 1615 - install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); 1613 + install_breakpoint(uprobe, vma, vaddr); 1616 1614 } 1617 1615 put_uprobe(uprobe); 1618 1616 }