From: sashiko-bot@kernel.org
To: "Darko Tominac" <dtominac@cisco.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH] mm/madvise: preserve uprobe breakpoints across MADV_DONTNEED
Date: Wed, 29 Apr 2026 17:33:04 +0000 [thread overview]
Message-ID: <20260429173305.9421EC19425@smtp.kernel.org> (raw)
In-Reply-To: <20260429131522.4049054-1-dtominac@cisco.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Incorrect VMA classification using vma->vm_file instead of vma_is_anonymous()
- [High] VMA addresses used as boolean flags (0 used as 'not found' sentinel)
- [High] Ignored return value in the slow path of madvise_dontneed_free() silently swallows errors
--
commit 0e33540d810d6a2eadc17b982d88ac4970eca760
Author: Darko Tominac <dtominac@cisco.com>
mm/madvise: preserve uprobe breakpoints across MADV_DONTNEED
This patch modifies MADV_DONTNEED and MADV_FREE behavior to prevent discarding
file-backed pages that contain active uprobe software breakpoints. It adds
checks to identify if a VMA contains uprobes and handles them via a slow path
that skips zapping the specific pages containing breakpoints.
Cc: xe-linux-external@cisco.com
Cc: danielwa@cisco.com
Signed-off-by: Darko Tominac <dtominac@cisco.com>
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index 4084e926e284..0f8aea99b96f 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
[ ... ]
> @@ -1654,6 +1675,60 @@ vma_has_uprobes(struct vm_area_struct *vma, unsigned long start, unsigned long e
> return !!n;
> }
>
> +/**
> + * vma_first_uprobe_addr - find first uprobe in a vma range.
> + * @vma: the vma to search.
> + * @start: start address of the range (inclusive).
> + * @end: end address of the range (exclusive).
> + *
> + * Used by madvise to skip directly to uprobe pages.
> + *
> + * Return: the page-aligned virtual address of the first uprobe in
> + * [@start, @end), or 0 if none exists.
> + */
> +unsigned long vma_first_uprobe_addr(struct vm_area_struct *vma,
> + unsigned long start, unsigned long end)
> +{
> + loff_t min, max, first_offset;
> + struct inode *inode;
> + struct rb_node *n, *t;
> + struct uprobe *u;
> +
> + /* No uprobes possible on anonymous mappings */
> + if (!vma->vm_file)
> + return 0;
Should this use !vma_is_anonymous(vma) instead of checking vma->vm_file?
Since private anonymous mappings of /dev/zero have vm_file != NULL but are
otherwise treated as anonymous, won't this incorrectly classify them as
file-backed and unnecessarily proceed with uprobe checks?
Also, since valid virtual addresses (like vm_start) can legitimately be zero,
is it safe to use 0 as a sentinel value for not found? If a uprobe is
installed at virtual address 0, it seems this would incorrectly signal that
no uprobe was found.
[ ... ]
> diff --git a/mm/madvise.c b/mm/madvise.c
> index ce238dd96f15..c9d3c26efd74 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
[ ... ]
> @@ -947,12 +972,46 @@ static long madvise_dontneed_free(struct madvise_behavior *madv_behavior)
> VM_WARN_ON(range->start > range->end);
> }
>
> - if (behavior == MADV_DONTNEED || behavior == MADV_DONTNEED_LOCKED)
> - return madvise_dontneed_single_vma(madv_behavior);
> - else if (behavior == MADV_FREE)
> - return madvise_free_single_vma(madv_behavior);
> - else
> - return -EINVAL;
> + /*
> + * Preserve uprobes: if any uprobes are active in this VMA range,
> + * avoid discarding pages that contain active breakpoints.
> + *
> + * Fast path: if no uprobes are registered system-wide, or the VMA
> + * is not file-backed (uprobes only instrument file-backed mappings,
> + * so anonymous VMAs can never contain breakpoints), or no uprobes
> + * are present in this VMA range, proceed with the full operation.
> + */
> + if (likely(!any_uprobes_registered()) ||
> + !madv_behavior->vma->vm_file ||
Similar to the question above, should this use vma_is_anonymous() instead
of checking vm_file, to avoid erroneously taking the slow path for private
/dev/zero mappings?
> + !vma_has_uprobes(madv_behavior->vma, range->start, range->end))
> + return madvise_dontneed_free_range(madv_behavior,
> + range->start, range->end);
> +
> + /*
> + * Slow path: jump from uprobe to uprobe via rbtree lookup, zapping
> + * the clean range before each uprobe page. This is O(M * log N)
> + * where M is the number of uprobes in the range and N is the total
> + * uprobe count, versus O(pages) for a page-by-page scan. 'cur'
> + * tracks the beginning of the current clean range.
> + */
> + cur = range->start;
> + end = range->end;
> + while (cur < end) {
> + uprobe_addr = vma_first_uprobe_addr(madv_behavior->vma,
> + cur, end);
> + if (!uprobe_addr) {
If uprobe_addr is 0 (a potentially valid virtual address), does this loop
terminate early and incorrectly zap the uprobe at address 0?
> + /* No more uprobes - zap the rest */
> + madvise_dontneed_free_range(madv_behavior, cur, end);
Does this code need to check the return value of madvise_dontneed_free_range()?
If madvise(MADV_FREE) is called on a file-backed VMA with uprobes, the fast
path would return -EINVAL. However, because the return value here is ignored,
won't the slow path unconditionally return 0 and silently swallow the error?
> + break;
> + }
> + /* Zap the clean range before the uprobe page */
> + if (cur < uprobe_addr)
> + madvise_dontneed_free_range(madv_behavior, cur,
> + uprobe_addr);
Does this call also need its return value checked to prevent swallowing errors?
> + /* Skip past the uprobe page */
> + cur = uprobe_addr + PAGE_SIZE;
> + }
> + return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260429131522.4049054-1-dtominac@cisco.com?part=1
prev parent reply other threads:[~2026-04-29 17:33 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-29 13:15 [PATCH] mm/madvise: preserve uprobe breakpoints across MADV_DONTNEED Darko Tominac
2026-04-29 13:31 ` David Hildenbrand (Arm)
2026-04-29 15:24 ` Oleg Nesterov
2026-04-29 21:11 ` Daniel Walker (danielwa)
2026-04-30 9:16 ` Oleg Nesterov
2026-04-30 9:54 ` David Hildenbrand (Arm)
2026-04-30 18:46 ` Oleg Nesterov
2026-04-30 19:11 ` Jann Horn
2026-04-30 15:22 ` Jann Horn
2026-04-30 19:25 ` Daniel Walker (danielwa)
2026-05-01 19:25 ` David Hildenbrand (Arm)
2026-04-29 17:33 ` sashiko-bot [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260429173305.9421EC19425@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dtominac@cisco.com \
--cc=linux-perf-users@vger.kernel.org \
--cc=sashiko@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox