linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: tip-bot for Oleg Nesterov <oleg@redhat.com>
To: linux-tip-commits@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, anton@redhat.com, hpa@zytor.com,
	mingo@kernel.org, srikar@linux.vnet.ibm.com, oleg@redhat.com,
	tglx@linutronix.de
Subject: [tip:perf/core] uprobes: Teach build_probe_list() to consider the range
Date: Mon, 30 Jul 2012 07:17:37 -0700	[thread overview]
Message-ID: <tip-891c39708144bbe401b4aa151bffd0fe41b1dafd@git.kernel.org> (raw)
In-Reply-To: <20120729182240.GA20352@redhat.com>

Commit-ID:  891c39708144bbe401b4aa151bffd0fe41b1dafd
Gitweb:     http://git.kernel.org/tip/891c39708144bbe401b4aa151bffd0fe41b1dafd
Author:     Oleg Nesterov <oleg@redhat.com>
AuthorDate: Sun, 29 Jul 2012 20:22:40 +0200
Committer:  Ingo Molnar <mingo@kernel.org>
CommitDate: Mon, 30 Jul 2012 11:27:23 +0200

uprobes: Teach build_probe_list() to consider the range

Currently build_probe_list() builds the list of all uprobes
attached to the given inode, and the caller should filter out
those who don't fall into the [start,end) range, this is
sub-optimal.

This patch turns find_least_offset_node() into
find_node_in_range() which returns the first node inside the
[min,max] range, and changes build_probe_list() to use this node
as a starting point for rb_prev() and rb_next() to find all
other nodes the caller needs. The resulting list is no longer
sorted but we do not care.

This can speed up both build_probe_list() and the callers, but
there is another reason to introduce find_node_in_range(). It
can be used to figure out whether the given vma has uprobes or
not, this will be needed soon.

While at it, shift INIT_LIST_HEAD(tmp_list) into
build_probe_list().

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Srikar Dronamraju <srikar.vnet.ibm.com>
Cc: Anton Arapov <anton@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/20120729182240.GA20352@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 kernel/events/uprobes.c |  103 +++++++++++++++++++++++------------------------
 1 files changed, 50 insertions(+), 53 deletions(-)

diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index fb961d5..2ef1233 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -939,59 +939,66 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
 		put_uprobe(uprobe);
 }
 
-/*
- * Of all the nodes that correspond to the given inode, return the node
- * with the least offset.
- */
-static struct rb_node *find_least_offset_node(struct inode *inode)
+static struct rb_node *
+find_node_in_range(struct inode *inode, loff_t min, loff_t max)
 {
-	struct uprobe u = { .inode = inode, .offset = 0};
 	struct rb_node *n = uprobes_tree.rb_node;
-	struct rb_node *close_node = NULL;
-	struct uprobe *uprobe;
-	int match;
 
 	while (n) {
-		uprobe = rb_entry(n, struct uprobe, rb_node);
-		match = match_uprobe(&u, uprobe);
-
-		if (uprobe->inode == inode)
-			close_node = n;
+		struct uprobe *u = rb_entry(n, struct uprobe, rb_node);
 
-		if (!match)
-			return close_node;
-
-		if (match < 0)
+		if (inode < u->inode) {
 			n = n->rb_left;
-		else
+		} else if (inode > u->inode) {
 			n = n->rb_right;
+		} else {
+			if (max < u->offset)
+				n = n->rb_left;
+			else if (min > u->offset)
+				n = n->rb_right;
+			else
+				break;
+		}
 	}
 
-	return close_node;
+	return n;
 }
 
 /*
- * For a given inode, build a list of probes that need to be inserted.
+ * For a given range in vma, build a list of probes that need to be inserted.
  */
-static void build_probe_list(struct inode *inode, struct list_head *head)
+static void build_probe_list(struct inode *inode,
+				struct vm_area_struct *vma,
+				unsigned long start, unsigned long end,
+				struct list_head *head)
 {
-	struct uprobe *uprobe;
+	loff_t min, max;
 	unsigned long flags;
-	struct rb_node *n;
-
-	spin_lock_irqsave(&uprobes_treelock, flags);
-
-	n = find_least_offset_node(inode);
+	struct rb_node *n, *t;
+	struct uprobe *u;
 
-	for (; n; n = rb_next(n)) {
-		uprobe = rb_entry(n, struct uprobe, rb_node);
-		if (uprobe->inode != inode)
-			break;
+	INIT_LIST_HEAD(head);
+	min = ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + start - vma->vm_start;
+	max = min + (end - start) - 1;
 
-		list_add(&uprobe->pending_list, head);
-		atomic_inc(&uprobe->ref);
+	spin_lock_irqsave(&uprobes_treelock, flags);
+	n = find_node_in_range(inode, min, max);
+	if (n) {
+		for (t = n; t; t = rb_prev(t)) {
+			u = rb_entry(t, struct uprobe, rb_node);
+			if (u->inode != inode || u->offset < min)
+				break;
+			list_add(&u->pending_list, head);
+			atomic_inc(&u->ref);
+		}
+		for (t = n; (t = rb_next(t)); ) {
+			u = rb_entry(t, struct uprobe, rb_node);
+			if (u->inode != inode || u->offset > max)
+				break;
+			list_add(&u->pending_list, head);
+			atomic_inc(&u->ref);
+		}
 	}
-
 	spin_unlock_irqrestore(&uprobes_treelock, flags);
 }
 
@@ -1021,9 +1028,8 @@ int uprobe_mmap(struct vm_area_struct *vma)
 	if (!inode)
 		return 0;
 
-	INIT_LIST_HEAD(&tmp_list);
 	mutex_lock(uprobes_mmap_hash(inode));
-	build_probe_list(inode, &tmp_list);
+	build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list);
 
 	ret = 0;
 	count = 0;
@@ -1032,11 +1038,6 @@ int uprobe_mmap(struct vm_area_struct *vma)
 		if (!ret) {
 			loff_t vaddr = vma_address(vma, uprobe->offset);
 
-			if (vaddr < vma->vm_start || vaddr >= vma->vm_end) {
-				put_uprobe(uprobe);
-				continue;
-			}
-
 			ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
 			/*
 			 * We can race against uprobe_register(), see the
@@ -1092,21 +1093,17 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon
 	if (!inode)
 		return;
 
-	INIT_LIST_HEAD(&tmp_list);
 	mutex_lock(uprobes_mmap_hash(inode));
-	build_probe_list(inode, &tmp_list);
+	build_probe_list(inode, vma, start, end, &tmp_list);
 
 	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
 		loff_t vaddr = vma_address(vma, uprobe->offset);
-
-		if (vaddr >= start && vaddr < end) {
-			/*
-			 * An unregister could have removed the probe before
-			 * unmap. So check before we decrement the count.
-			 */
-			if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
-				atomic_dec(&vma->vm_mm->uprobes_state.count);
-		}
+		/*
+		 * An unregister could have removed the probe before
+		 * unmap. So check before we decrement the count.
+		 */
+		if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
+			atomic_dec(&vma->vm_mm->uprobes_state.count);
 		put_uprobe(uprobe);
 	}
 	mutex_unlock(uprobes_mmap_hash(inode));

  reply	other threads:[~2012-07-30 14:17 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-29 18:21 [PATCH 0/14] uprobes: acked patches Oleg Nesterov
2012-07-29 18:22 ` [PATCH 01/14] uprobes: don't recheck vma/f_mapping in write_opcode() Oleg Nesterov
2012-07-30 14:09   ` [tip:perf/core] uprobes: Don't recheck vma/ f_mapping " tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 02/14] uprobes: __replace_page() should not use page_address_in_vma() Oleg Nesterov
2012-07-30 14:10   ` [tip:perf/core] " tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 03/14] uprobes: kill write_opcode()->lock_page(new_page) Oleg Nesterov
2012-07-30 14:11   ` [tip:perf/core] uprobes: Kill write_opcode()->lock_page(new_page) tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 04/14] uprobes: cleanup and document write_opcode()->lock_page(old_page) Oleg Nesterov
2012-07-30 14:12   ` [tip:perf/core] uprobes: Clean up and document write_opcode()-> lock_page(old_page) tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 05/14] uprobes: uprobe_mmap/munmap needs list_for_each_entry_safe() Oleg Nesterov
2012-07-30 14:13   ` [tip:perf/core] uprobes: Uprobe_mmap/ munmap " tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 06/14] uprobes: suppress uprobe_munmap() from mmput() Oleg Nesterov
2012-07-30 14:14   ` [tip:perf/core] uprobes: Suppress " tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 07/14] uprobes: fix overflow in vma_address/find_active_uprobe Oleg Nesterov
2012-07-30 14:14   ` [tip:perf/core] uprobes: Fix overflow in vma_address()/ find_active_uprobe() tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 08/14] uprobes: kill copy_vma()->uprobe_mmap() Oleg Nesterov
2012-07-30 14:15   ` [tip:perf/core] uprobes: Remove copy_vma()->uprobe_mmap() tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 09/14] uprobes: kill insert_vm_struct()->uprobe_mmap() Oleg Nesterov
2012-07-30 14:16   ` [tip:perf/core] uprobes: Remove insert_vm_struct()->uprobe_mmap() tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 10/14] uprobes: teach build_probe_list() to consider the range Oleg Nesterov
2012-07-30 14:17   ` tip-bot for Oleg Nesterov [this message]
2012-07-29 18:22 ` [PATCH 11/14] uprobes: introduce vaddr_to_offset(vma, vaddr) Oleg Nesterov
2012-07-30 14:18   ` [tip:perf/core] uprobes: Introduce " tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 12/14] uprobes: fix register_for_each_vma()->vma_address() check Oleg Nesterov
2012-07-30 14:19   ` [tip:perf/core] uprobes: Fix register_for_each_vma()->vma_address( ) check tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 13/14] uprobes: rename vma_address() and make it return "unsigned long" Oleg Nesterov
2012-07-30 14:20   ` [tip:perf/core] uprobes: Rename vma_address() and make it return " unsigned long" tip-bot for Oleg Nesterov
2012-07-29 18:22 ` [PATCH 14/14] uprobes: __replace_page() needs munlock_vma_page() Oleg Nesterov
2012-07-30 14:21   ` [tip:perf/core] " tip-bot for Oleg Nesterov

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=tip-891c39708144bbe401b4aa151bffd0fe41b1dafd@git.kernel.org \
    --to=oleg@redhat.com \
    --cc=anton@redhat.com \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tip-commits@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=srikar@linux.vnet.ibm.com \
    --cc=tglx@linutronix.de \
    /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;
as well as URLs for NNTP newsgroup(s).