All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>,
	"zhangwei(Jovi)" <jovi.zhangwei@huawei.com>,
	Frederic Weisbecker <fweisbec@gmail.com>,
	Ingo Molnar <mingo@redhat.com>, Oleg Nesterov <oleg@redhat.com>,
	Srikar Dronamraju <srikar@linux.vnet.ibm.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"yrl.pp-manager.tt@hitachi.com" <yrl.pp-manager.tt@hitachi.com>
Subject: Re: [PATCH] tracing/uprobes: Support ftrace_event_file base multibuffer
Date: Fri, 14 Jun 2013 09:21:12 -0700	[thread overview]
Message-ID: <20130614162112.GO5146@linux.vnet.ibm.com> (raw)
In-Reply-To: <1371223918.9844.324.camel@gandalf.local.home>

On Fri, Jun 14, 2013 at 11:31:58AM -0400, Steven Rostedt wrote:
> On Fri, 2013-06-14 at 22:21 +0900, Masami Hiramatsu wrote:
> > (2013/06/14 10:44), zhangwei(Jovi) wrote:
> > > Support multi-buffer on uprobe-based dynamic events by
> > > using ftrace_event_file.
> > > 
> > > The code change is based on kprobe-based dynamic events
> > > multibuffer support work commited by Masami(commit 41a7dd420c)
> > 
> > I'm not so sure that rcu_dereference_raw() can ensure the safety
> > of accessing pointer in uprobe handler. ( since kprobes disables
> > irq and preempt, it could use rcu.)
> 
> Correct.
> 
> > 
> > Srikar, Oleg, could you check that?
> > 
> > Thank you,
> > 
> > > 
> > > Signed-off-by: zhangwei(Jovi) <jovi.zhangwei@huawei.com>
> > > Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> > > Cc: Frederic Weisbecker <fweisbec@gmail.com>
> > > Cc: Oleg Nesterov <oleg@redhat.com>
> > > Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> > > ---
> > >  kernel/trace/trace_uprobe.c |  183 +++++++++++++++++++++++++++++++++++++------
> > >  1 file changed, 161 insertions(+), 22 deletions(-)
> > > 
> > > diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
> > > index d5d0cd3..31f08d6 100644
> > > --- a/kernel/trace/trace_uprobe.c
> > > +++ b/kernel/trace/trace_uprobe.c
> > > @@ -53,6 +53,7 @@ struct trace_uprobe {
> > >  	struct list_head		list;
> > >  	struct ftrace_event_class	class;
> > >  	struct ftrace_event_call	call;
> > > +	struct ftrace_event_file * __rcu *files;
> > >  	struct trace_uprobe_filter	filter;
> > >  	struct uprobe_consumer		consumer;
> > >  	struct inode			*inode;
> > > @@ -513,7 +514,8 @@ static const struct file_operations uprobe_profile_ops = {
> > >  };
> > > 
> > >  static void uprobe_trace_print(struct trace_uprobe *tu,
> > > -				unsigned long func, struct pt_regs *regs)
> > > +				unsigned long func, struct pt_regs *regs,
> > > +				struct ftrace_event_file *ftrace_file)
> > >  {
> > >  	struct uprobe_trace_entry_head *entry;
> > >  	struct ring_buffer_event *event;
> > > @@ -522,9 +524,15 @@ static void uprobe_trace_print(struct trace_uprobe *tu,
> > >  	int size, i;
> > >  	struct ftrace_event_call *call = &tu->call;
> > > 
> > > +	WARN_ON(call != ftrace_file->event_call);
> > > +
> > > +	if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags))
> > > +		return;
> > > +
> > >  	size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
> > > -	event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
> > > -						  size + tu->size, 0, 0);
> > > +	event = trace_event_buffer_lock_reserve(&buffer, ftrace_file,
> > > +						call->event.type,
> > > +						size + tu->size, 0, 0);
> > >  	if (!event)
> > >  		return;
> > > 
> > > @@ -548,15 +556,35 @@ static void uprobe_trace_print(struct trace_uprobe *tu,
> > >  /* uprobe handler */
> > >  static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
> > >  {
> > > -	if (!is_ret_probe(tu))
> > > -		uprobe_trace_print(tu, 0, regs);
> > > +	struct ftrace_event_file **file;
> > > +
> > > +	if (is_ret_probe(tu))
> > > +		return 0;
> > > +
> > > +	file = rcu_dereference_raw(tu->files);
> 
> Why are you using rcu_dereference_raw() and not rcu_dereference(). The
> _raw() is a bit special, and unless you know what you are doing with RCU
> here, don't use it.
> 
> As I see you using rcu_dereference_raw() all over this patch, along with
> mutexes, I believe that you are not using RCU correctly here.

If irqs and preempt are disabled, I suggest using rcu_dereference_sched().
That is what it is there for.  ;-)

							Thanx, Paul

> -- Steve
> 
> > > +	if (unlikely(!file))
> > > +		return 0;
> > > +
> > > +	while (*file) {
> > > +		uprobe_trace_print(tu, 0, regs, *file);
> > > +		file++;
> > > +	}
> > > +
> > >  	return 0;
> > >  }
> > > 
> > >  static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
> > >  				struct pt_regs *regs)
> > >  {
> > > -	uprobe_trace_print(tu, func, regs);
> > > +	struct ftrace_event_file **file = rcu_dereference_raw(tu->files);
> > > +
> > > +	if (unlikely(!file))
> > > +		return;
> > > +
> > > +	while (*file) {
> > > +		uprobe_trace_print(tu, func, regs, *file);
> > > +		file++;
> > > +	}
> > >  }
> > > 
> > >  /* Event entry printers */
> > > @@ -597,6 +625,26 @@ partial:
> > >  	return TRACE_TYPE_PARTIAL_LINE;
> > >  }
> > > 
> > > +
> > > +static int trace_uprobe_nr_files(struct trace_uprobe *tu)
> > > +{
> > > +	struct ftrace_event_file **file;
> > > +	int ret = 0;
> > > +
> > > +	/*
> > > +	 * Since all tu->files updater is protected by uprobe_enable_lock,
> > > +	 * we don't need to lock an rcu_read_lock.
> > > +	 */
> > > +	file = rcu_dereference_raw(tu->files);
> > > +	if (file)
> > > +		while (*(file++))
> > > +			ret++;
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static DEFINE_MUTEX(uprobe_enable_lock);
> > > +
> > >  static inline bool is_trace_uprobe_enabled(struct trace_uprobe *tu)
> > >  {
> > >  	return tu->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE);
> > > @@ -607,33 +655,123 @@ typedef bool (*filter_func_t)(struct uprobe_consumer *self,
> > >  				struct mm_struct *mm);
> > > 
> > >  static int
> > > -probe_event_enable(struct trace_uprobe *tu, int flag, filter_func_t filter)
> > > +probe_event_enable(struct trace_uprobe *tu, struct ftrace_event_file *file,
> > > +		   filter_func_t filter)
> > >  {
> > > +	int enabled = 0;
> > >  	int ret = 0;
> > > 
> > > +	mutex_lock(&uprobe_enable_lock);
> > > +
> > >  	if (is_trace_uprobe_enabled(tu))
> > > -		return -EINTR;
> > > +		enabled = 1;
> > > +
> > > +	if (file) {
> > > +		struct ftrace_event_file **new, **old;
> > > +		int n = trace_uprobe_nr_files(tu);
> > > +
> > > +		old = rcu_dereference_raw(tu->files);
> > > +		/* 1 is for new one and 1 is for stopper */
> > > +		new = kzalloc((n + 2) * sizeof(struct ftrace_event_file *),
> > > +			      GFP_KERNEL);
> > > +		if (!new) {
> > > +			ret = -ENOMEM;
> > > +			goto out_unlock;
> > > +		}
> > > +		memcpy(new, old, n * sizeof(struct ftrace_event_file *));
> > > +		new[n] = file;
> > > +		/* The last one keeps a NULL */
> > > +
> > > +		rcu_assign_pointer(tu->files, new);
> > > +		tu->flags |= TP_FLAG_TRACE;
> > > +
> > > +		if (old) {
> > > +			/* Make sure the probe is done with old files */
> > > +			synchronize_sched();
> > > +			kfree(old);
> > > +		}
> > > +	} else
> > > +		tu->flags |= TP_FLAG_PROFILE;
> > > 
> > >  	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
> > > 
> > > -	tu->flags |= flag;
> > > -	tu->consumer.filter = filter;
> > > -	ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
> > > -	if (ret)
> > > -		tu->flags &= ~flag;
> > > +	if (!enabled) {
> > > +		tu->consumer.filter = filter;
> > > +		ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
> > > +		if (ret)
> > > +			tu->flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE;
> > > +	}
> > > 
> > > + out_unlock:
> > > +	mutex_unlock(&uprobe_enable_lock);
> > >  	return ret;
> > >  }
> > > 
> > > -static void probe_event_disable(struct trace_uprobe *tu, int flag)
> > > +static int
> > > +trace_uprobe_file_index(struct trace_uprobe *tu, struct ftrace_event_file *file)
> > >  {
> > > -	if (!is_trace_uprobe_enabled(tu))
> > > -		return;
> > > +	struct ftrace_event_file **files;
> > > +	int i;
> > > +
> > > +	/*
> > > +	 * Since all tu->files updater is protected by uprobe_enable_lock,
> > > +	 * we don't need to lock an rcu_read_lock.
> > > +	 */
> > > +	files = rcu_dereference_raw(tu->files);
> > > +	if (files) {
> > > +		for (i = 0; files[i]; i++)
> > > +			if (files[i] == file)
> > > +				return i;
> > > +	}
> > > +
> > > +	return -1;
> > > +}
> > > +
> > > +static void
> > > +probe_event_disable(struct trace_uprobe *tu, struct ftrace_event_file *file)
> > > +{
> > > +	mutex_lock(&uprobe_enable_lock);
> > > +
> > > +	if (file) {
> > > +		struct ftrace_event_file **new, **old;
> > > +		int n = trace_uprobe_nr_files(tu);
> > > +		int i, j;
> > > +
> > > +		old = rcu_dereference_raw(tu->files);
> > > +		if (n == 0 || trace_uprobe_file_index(tu, file) < 0)
> > > +			goto out_unlock;
> > > +
> > > +		if (n == 1) {	/* Remove the last file */
> > > +			tu->flags &= ~TP_FLAG_TRACE;
> > > +			new = NULL;
> > > +		} else {
> > > +			new = kzalloc(n * sizeof(struct ftrace_event_file *),
> > > +				      GFP_KERNEL);
> > > +			if (!new)
> > > +				goto out_unlock;
> > > +
> > > +			/* This copy & check loop copies the NULL stopper too */
> > > +			for (i = 0, j = 0; j < n && i < n + 1; i++)
> > > +				if (old[i] != file)
> > > +					new[j++] = old[i];
> > > +		}
> > > +
> > > +		rcu_assign_pointer(tu->files, new);
> > > +
> > > +		/* Make sure the probe is done with old files */
> > > +		synchronize_sched();
> > > +		kfree(old);
> > > +	} else
> > > +		tu->flags &= ~TP_FLAG_PROFILE;
> > > +
> > > 
> > >  	WARN_ON(!uprobe_filter_is_empty(&tu->filter));
> > > 
> > > -	uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
> > > -	tu->flags &= ~flag;
> > > +	if (!is_trace_uprobe_enabled(tu))
> > > +		uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
> > > +
> > > + out_unlock:
> > > +	mutex_unlock(&uprobe_enable_lock);
> > >  }
> > > 
> > >  static int uprobe_event_define_fields(struct ftrace_event_call *event_call)
> > > @@ -869,21 +1007,22 @@ static
> > >  int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, void *data)
> > >  {
> > >  	struct trace_uprobe *tu = event->data;
> > > +	struct ftrace_event_file *file = data;
> > > 
> > >  	switch (type) {
> > >  	case TRACE_REG_REGISTER:
> > > -		return probe_event_enable(tu, TP_FLAG_TRACE, NULL);
> > > +		return probe_event_enable(tu, file, NULL);
> > > 
> > >  	case TRACE_REG_UNREGISTER:
> > > -		probe_event_disable(tu, TP_FLAG_TRACE);
> > > +		probe_event_disable(tu, file);
> > >  		return 0;
> > > 
> > >  #ifdef CONFIG_PERF_EVENTS
> > >  	case TRACE_REG_PERF_REGISTER:
> > > -		return probe_event_enable(tu, TP_FLAG_PROFILE, uprobe_perf_filter);
> > > +		return probe_event_enable(tu, NULL, uprobe_perf_filter);
> > > 
> > >  	case TRACE_REG_PERF_UNREGISTER:
> > > -		probe_event_disable(tu, TP_FLAG_PROFILE);
> > > +		probe_event_disable(tu, NULL);
> > >  		return 0;
> > > 
> > >  	case TRACE_REG_PERF_OPEN:
> > > 
> > 
> > 
> 
> 


  reply	other threads:[~2013-06-14 16:21 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-06-14  1:44 [PATCH] tracing/uprobes: Support ftrace_event_file base multibuffer zhangwei(Jovi)
2013-06-14 13:21 ` Masami Hiramatsu
2013-06-14 13:51   ` Oleg Nesterov
2013-06-14 14:09     ` Oleg Nesterov
2013-06-14 15:31   ` Steven Rostedt
2013-06-14 16:21     ` Paul E. McKenney [this message]
2013-06-14 16:33       ` Steven Rostedt
2013-06-14 17:25         ` Paul E. McKenney
2013-06-17  2:54           ` Masami Hiramatsu
2013-06-17 12:33             ` Steven Rostedt
2013-06-18  1:31               ` Masami Hiramatsu
2013-06-18  2:02                 ` Steven Rostedt
2013-06-14 14:44 ` Oleg Nesterov
2013-06-14 16:04   ` ftrace multibuffer && rcu (Was: tracing/uprobes: Support ftrace_event_file base multibuffer) Oleg Nesterov
2013-06-14 16:18     ` Oleg Nesterov
2013-06-14 16:26     ` Steven Rostedt
2013-06-14 17:02       ` Oleg Nesterov
2013-06-20 16:43   ` [PATCH] tracing/uprobes: Support ftrace_event_file base multibuffer Oleg Nesterov
2013-06-21  8:17     ` zhangwei(Jovi)

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=20130614162112.GO5146@linux.vnet.ibm.com \
    --to=paulmck@linux.vnet.ibm.com \
    --cc=fweisbec@gmail.com \
    --cc=jovi.zhangwei@huawei.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=masami.hiramatsu.pt@hitachi.com \
    --cc=mingo@redhat.com \
    --cc=oleg@redhat.com \
    --cc=rostedt@goodmis.org \
    --cc=srikar@linux.vnet.ibm.com \
    --cc=yrl.pp-manager.tt@hitachi.com \
    /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.