Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b2fe8ba6 authored by Oleg Nesterov's avatar Oleg Nesterov
Browse files

uprobes/perf: Avoid uprobe_apply() whenever possible



uprobe_perf_open/close call the costly uprobe_apply() every time,
we can avoid it if:

	- "nr_systemwide != 0" is not changed.

	- There is another process/thread with the same ->mm.

	- copy_proccess() does inherit_event(). dup_mmap() preserves the
	  inserted breakpoints.

	- event->attr.enable_on_exec == T, we can rely on uprobe_mmap()
	  called by exec/mmap paths.

	- tp_target is exiting. Only _close() checks PF_EXITING, I don't
	  think TRACE_REG_PERF_OPEN can hit the dying task too often.

Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
parent f42d24a1
Loading
Loading
Loading
Loading
+36 −6
Original line number Diff line number Diff line
@@ -680,15 +680,37 @@ __uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm)
	return false;
}

static inline bool
uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event)
{
	return __uprobe_perf_filter(&tu->filter, event->hw.tp_target->mm);
}

static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event)
{
	bool done;

	write_lock(&tu->filter.rwlock);
	if (event->hw.tp_target)
	if (event->hw.tp_target) {
		/*
		 * event->parent != NULL means copy_process(), we can avoid
		 * uprobe_apply(). current->mm must be probed and we can rely
		 * on dup_mmap() which preserves the already installed bp's.
		 *
		 * attr.enable_on_exec means that exec/mmap will install the
		 * breakpoints we need.
		 */
		done = tu->filter.nr_systemwide ||
			event->parent || event->attr.enable_on_exec ||
			uprobe_filter_event(tu, event);
		list_add(&event->hw.tp_list, &tu->filter.perf_events);
	else
	} else {
		done = tu->filter.nr_systemwide;
		tu->filter.nr_systemwide++;
	}
	write_unlock(&tu->filter.rwlock);

	if (!done)
		uprobe_apply(tu->inode, tu->offset, &tu->consumer, true);

	return 0;
@@ -696,13 +718,21 @@ static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event)

static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event)
{
	bool done;

	write_lock(&tu->filter.rwlock);
	if (event->hw.tp_target)
	if (event->hw.tp_target) {
		list_del(&event->hw.tp_list);
	else
		done = tu->filter.nr_systemwide ||
			(event->hw.tp_target->flags & PF_EXITING) ||
			uprobe_filter_event(tu, event);
	} else {
		tu->filter.nr_systemwide--;
		done = tu->filter.nr_systemwide;
	}
	write_unlock(&tu->filter.rwlock);

	if (!done)
		uprobe_apply(tu->inode, tu->offset, &tu->consumer, false);

	return 0;