All of lore.kernel.org
 help / color / mirror / Atom feed
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

      parent reply	other threads:[~2026-04-29 17:33 UTC|newest]

Thread overview: 13+ 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 20:38   ` Darko Tominac -X (dtominac - GLOBALLOGIC INC at Cisco)
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.