All of lore.kernel.org
 help / color / mirror / Atom feed
From: Namhyung Kim <namhyung@kernel.org>
To: Jiri Olsa <jolsa@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	lkml <linux-kernel@vger.kernel.org>,
	Ingo Molnar <mingo@kernel.org>, David Ahern <dsahern@gmail.com>,
	Alexander Shishkin <alexander.shishkin@linux.intel.com>,
	Peter Zijlstra <a.p.zijlstra@chello.nl>,
	Kan Liang <kan.liang@intel.com>, Andi Kleen <ak@linux.intel.com>,
	Lukasz Odzioba <lukasz.odzioba@intel.com>,
	Wang Nan <wangnan0@huawei.com>,
	kernel-team@lge.com
Subject: Re: [PATCH 1/4] perf tools: Fix struct comm_str removal crash
Date: Tue, 17 Jul 2018 10:49:40 +0900	[thread overview]
Message-ID: <20180717014940.GA9295@sejong> (raw)
In-Reply-To: <20180716102934.GA14153@krava>

Hi Jiri,

On Mon, Jul 16, 2018 at 12:29:34PM +0200, Jiri Olsa wrote:
> On Sun, Jul 15, 2018 at 10:08:27PM +0900, Namhyung Kim wrote:
> 
> SNIP
> 
> > > Because thread 2 first decrements the refcnt and only after then it
> > > removes the struct comm_str from the list, the thread 1 can find this
> > > object on the list with refcnt equls to 0 and hit the assert.
> > > 
> > > This patch fixes the thread 2 path, by removing the struct comm_str
> > > FIRST from the list and only AFTER calling comm_str__put on it. This
> > > way the thread 1 finds only valid objects on the list.
> > 
> > I'm not sure we can unconditionally remove the comm_str from the tree.
> > It should be removed only if refcount is going to zero IMHO.
> > Otherwise it could end up having multiple comm_str entry for a same
> > name.
> 
> right, but it wouldn't crash ;-)
> 
> how about attached change, that actualy deals with the refcnt
> race I'm running the tests now, seems ok so far

I think we can keep if the refcount is back to non-zero.  What about this?
(not tested..)


static struct comm_str *comm_str__get(cs)
{
    if (cs)
        refcount_inc_no_warn(&cs->refcnt);  // should be added
    return cs;
}

static void comm_str__put(cs)
{
    if (cs && refcount_dec_and_test(&cs->refcnt)) {
        down_write(&comm_str_lock);
        /* might race with comm_str__findnew() */
        if (!refcount_read(&cs->refcnt)) {
            rb_erase(&cs->rb_node, &comm_str_root);
            zfree(&cs->str);
            free(cs);
        }
        up_write(&comm_str_lock);
    }
}


Thanks,
Namhyung


> 
> 
> ---
> diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
> index 7798a2cc8a86..592b03548021 100644
> --- a/tools/perf/util/comm.c
> +++ b/tools/perf/util/comm.c
> @@ -18,22 +18,27 @@ struct comm_str {
>  static struct rb_root comm_str_root;
>  static struct rw_semaphore comm_str_lock = {.lock = PTHREAD_RWLOCK_INITIALIZER,};
>  
> -static struct comm_str *comm_str__get(struct comm_str *cs)
> +static bool comm_str__get(struct comm_str *cs)
>  {
> -	if (cs)
> -		refcount_inc(&cs->refcnt);
> -	return cs;
> +	return cs ? refcount_inc_not_zero(&cs->refcnt) : false;
>  }
>  
> -static void comm_str__put(struct comm_str *cs)
> +static int comm_str__put(struct comm_str *cs, bool lock)
>  {
> -	if (cs && refcount_dec_and_test(&cs->refcnt)) {
> +	if (!cs || !refcount_dec_and_test(&cs->refcnt))
> +		return 0;
> +
> +	if (lock)
>  		down_write(&comm_str_lock);
> -		rb_erase(&cs->rb_node, &comm_str_root);
> +
> +	rb_erase(&cs->rb_node, &comm_str_root);
> +
> +	if (lock)
>  		up_write(&comm_str_lock);
> -		zfree(&cs->str);
> -		free(cs);
> -	}
> +
> +	zfree(&cs->str);
> +	free(cs);
> +	return 1;
>  }
>  
>  static struct comm_str *comm_str__alloc(const char *str)
> @@ -67,9 +72,22 @@ struct comm_str *__comm_str__findnew(const char *str, struct rb_root *root)
>  		parent = *p;
>  		iter = rb_entry(parent, struct comm_str, rb_node);
>  
> -		cmp = strcmp(str, iter->str);
> -		if (!cmp)
> -			return comm_str__get(iter);
> +		/*
> +		 * If we race with comm_str__put, iter->refcnt == 0
> +		 * and it will be removed within comm_str__put
> +		 * thread shortly, ignore it in this search.
> +		 */
> +		if (comm_str__get(iter)) {
> +			cmp = strcmp(str, iter->str);
> +			if (!cmp)
> +				return iter;
> +			/*
> +			 * If we actualy had to remove the item, restart
> +			 * the search to have the clean tree search.
> +			 */
> +			if (comm_str__put(iter, false))
> +				return __comm_str__findnew(str, root);
> +		}
>  
>  		if (cmp < 0)
>  			p = &(*p)->rb_left;
> @@ -125,7 +143,7 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
>  	if (!new)
>  		return -ENOMEM;
>  
> -	comm_str__put(old);
> +	comm_str__put(old, true);
>  	comm->comm_str = new;
>  	comm->start = timestamp;
>  	if (exec)
> @@ -136,7 +154,7 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
>  
>  void comm__free(struct comm *comm)
>  {
> -	comm_str__put(comm->comm_str);
> +	comm_str__put(comm->comm_str, true);
>  	free(comm);
>  }
>  

  reply	other threads:[~2018-07-17  1:49 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-12 14:20 [PATCH 0/4] perf tools: Fix top crashes Jiri Olsa
2018-07-12 14:20 ` [PATCH 1/4] perf tools: Fix struct comm_str removal crash Jiri Olsa
2018-07-15 13:08   ` Namhyung Kim
2018-07-16 10:29     ` Jiri Olsa
2018-07-17  1:49       ` Namhyung Kim [this message]
2018-07-17  9:02         ` Jiri Olsa
2018-07-18 10:44           ` Jiri Olsa
2018-07-12 14:20 ` [PATCH 2/4] perf tools: Add threads__get_last_match function Jiri Olsa
2018-07-22  7:53   ` [lkp-robot] [perf tools] 600b7378cf: perf-sanity-tests.Share_thread_mg.fail kernel test robot
2018-07-22  7:53     ` kernel test robot
2018-07-23  6:59     ` Jiri Olsa
2018-07-23  6:59       ` Jiri Olsa
2018-07-12 14:20 ` [PATCH 3/4] perf tools: Add threads__set_last_match function Jiri Olsa
2018-07-12 14:20 ` [PATCH 4/4] perf tools: Use last_match threads cache only in single thread mode Jiri Olsa

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=20180717014940.GA9295@sejong \
    --to=namhyung@kernel.org \
    --cc=a.p.zijlstra@chello.nl \
    --cc=acme@kernel.org \
    --cc=ak@linux.intel.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=dsahern@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=jolsa@redhat.com \
    --cc=kan.liang@intel.com \
    --cc=kernel-team@lge.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lukasz.odzioba@intel.com \
    --cc=mingo@kernel.org \
    --cc=wangnan0@huawei.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.