netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jarek Poplawski <jarkao2@o2.pl>
To: Patrick McHardy <kaber@trash.net>
Cc: David Miller <davem@davemloft.net>,
	Andrew Morton <akpm@linux-foundation.org>,
	netdev@vger.kernel.org,
	"bugme-daemon\@kernel-bugs\.osdl\.org"
	<bugme-daemon@kernel-bugs.osdl.org>,
	ranko@spidernet.net
Subject: Re: [NET]: gen_estimator: fix locking and timer related bugs [Re: [Bugme-new] [Bug 8668] New: HTB Deadlock]
Date: Thu, 28 Jun 2007 08:54:48 +0200	[thread overview]
Message-ID: <20070628065448.GA1618@ff.dom.local> (raw)
In-Reply-To: <46828179.5030404@trash.net>

On Wed, Jun 27, 2007 at 05:25:45PM +0200, Patrick McHardy wrote:
> Patrick McHardy wrote:
> > [NET]: gen_estimator: fix locking and timer related bugs
> > 
> 
> 
> That one still left a race, we could be reinitalizing the timer
> while it is still running. This patch additionally makes sure
> each timer is only initialized once.
> 

> [NET]: gen_estimator: fix locking and timer related bugs
> 
> As noticed by Jarek Poplawski <jarkao2@o2.pl>, the timer removal in
> gen_kill_estimator races with the timer function rearming the timer.
> 
> Additionally there are a few more related problems that seem to be
> relicts from the timer when the estimator was qdisc specific and

- relicts from the timer when the estimator was qdisc specific and
+ relicts from the time when the estimator was qdisc specific and

> could rely on the rtnl or dev->qdisc_lock:

I've lost some time thinking about this rtnl and checking where
these gen_ functions are used, and how much foolish could be
asking about this here, so, it seems there should be some policy
about commenting required locking in networking - I mean after
reading e.g. sch_generic.c you could wrongly think no comments
means: no locking required. (And probably it would be better/
easier for "the more experienced" to do some supplements, if you
know what I mean...)

> 
> - the check whether the list is empty and a timer needs to be started
>   when adding a new estimator doesn't take the lock, so it races
>   against concurrent additions, which can result in the timer beeing
>   added twice or getting reinitialized after being added.
> 
> - the new estimator's next pointer is also set without holding the
>   lock, again racing against concurrent additions with possible
>   list corruption as a result.
> 
> - the timer deletion when killing an estimator is also not under
>   the lock and races against timer arming when adding a new estimator.
> 
> Fix by holding the lock around the entire list addition and initial
> timer arming. Removal is not done explicitly anymore, instead the
> timer function only rearms the timer when there are still estimators
> present.
> 
> Signed-off-by: Patrick McHardy <kaber@trash.net>
> 
> ---
> commit b6a0c468c258d96c6f132fc71ca74225235bc223
> tree 6f61004cf4810a4826aa5c7477e4d455ae3a5698
> parent 48d8d7ee5dd17c64833e0343ab4ae8ef01cc2648
> author Patrick McHardy <kaber@trash.net> Wed, 27 Jun 2007 17:06:02 +0200
> committer Patrick McHardy <kaber@trash.net> Wed, 27 Jun 2007 17:24:13 +0200
> 
>  net/core/gen_estimator.c |   27 +++++++++++----------------
>  1 files changed, 11 insertions(+), 16 deletions(-)
> 
> diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
> index 17daf4c..88a7805 100644
> --- a/net/core/gen_estimator.c
> +++ b/net/core/gen_estimator.c
> @@ -127,8 +127,8 @@ static void est_timer(unsigned long arg)
>  		e->rate_est->pps = (e->avpps+0x1FF)>>10;
>  		spin_unlock(e->stats_lock);
>  	}
> -
> -	mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
> +	if (elist[idx].list != NULL)
> +		mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
>  	read_unlock(&est_lock);
>  }
>  
> @@ -152,6 +152,7 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
>  {
>  	struct gen_estimator *est;
>  	struct gnet_estimator *parm = RTA_DATA(opt);
> +	int idx;
>  
>  	if (RTA_PAYLOAD(opt) < sizeof(*parm))
>  		return -EINVAL;
> @@ -163,7 +164,7 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
>  	if (est == NULL)
>  		return -ENOBUFS;
>  
> -	est->interval = parm->interval + 2;
> +	est->interval = idx = parm->interval + 2;
>  	est->bstats = bstats;
>  	est->rate_est = rate_est;
>  	est->stats_lock = stats_lock;
> @@ -173,16 +174,14 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
>  	est->last_packets = bstats->packets;
>  	est->avpps = rate_est->pps<<10;
>  
> -	est->next = elist[est->interval].list;
> -	if (est->next == NULL) {
> -		init_timer(&elist[est->interval].timer);
> -		elist[est->interval].timer.data = est->interval;
> -		elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
> -		elist[est->interval].timer.function = est_timer;
> -		add_timer(&elist[est->interval].timer);
> -	}
>  	write_lock_bh(&est_lock);
> -	elist[est->interval].list = est;
> +	if (!elist[idx].timer.function)

I think, here could be more consistency about "!" or "== NULL".

> +		setup_timer(&elist[idx].timer, est_timer, est->interval);

...and about idx instead of est->interval.

> +	if (elist[est->interval].list == NULL)

idx?

> +		mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
> +
> +	est->next = elist[idx].list;
> +	elist[idx].list = est;
>  	write_unlock_bh(&est_lock);
>  	return 0;
>  }
> @@ -202,7 +201,6 @@ void gen_kill_estimator(struct gnet_stats_basic *bstats,
>  	struct gen_estimator *est, **pest;
>  
>  	for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
> -		int killed = 0;
>  		pest = &elist[idx].list;
>  		while ((est=*pest) != NULL) {
>  			if (est->rate_est != rate_est || est->bstats != bstats) {
> @@ -215,10 +213,7 @@ void gen_kill_estimator(struct gnet_stats_basic *bstats,
>  			write_unlock_bh(&est_lock);
>  
>  			kfree(est);
> -			killed++;
>  		}
> -		if (killed && elist[idx].list == NULL)
> -			del_timer(&elist[idx].timer);

I think this is needed. The old timer could be pending, while
the gen_new_estimator() is run just after this e.g. in
gen_replace_estimator().

>  	}
>  }
>  

Regards,
Jarek P.

  reply	other threads:[~2007-06-28  6:46 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <bug-8668-10286@http.bugzilla.kernel.org/>
2007-06-25  5:24 ` [Bugme-new] [Bug 8668] New: HTB Deadlock Andrew Morton
2007-06-25  9:28   ` Patrick McHardy
2007-06-25  9:30     ` Patrick McHardy
2007-06-25 11:37       ` Ranko Zivojnovic
2007-06-27 11:45     ` Jarek Poplawski
2007-06-27 11:44       ` Patrick McHardy
2007-06-27 12:10         ` Jarek Poplawski
2007-06-27 12:30           ` Jarek Poplawski
2007-06-27 14:53           ` Patrick McHardy
2007-06-27 15:09             ` [NET]: gen_estimator: fix locking and timer related bugs [Re: [Bugme-new] [Bug 8668] New: HTB Deadlock] Patrick McHardy
2007-06-27 15:25               ` Patrick McHardy
2007-06-28  6:54                 ` Jarek Poplawski [this message]
2007-06-28  9:56                   ` Jarek Poplawski
2007-06-28  9:13                 ` Jarek Poplawski
2007-06-28 12:23                   ` Patrick McHardy
2007-06-28 13:03                     ` Jarek Poplawski
2007-06-28 12:55                       ` Patrick McHardy
2007-06-28 13:27                         ` Jarek Poplawski
2007-06-29  7:02                         ` Jarek Poplawski
2007-06-29  7:56                           ` Jarek Poplawski
2007-06-28  7:52             ` [Bugme-new] [Bug 8668] New: HTB Deadlock Jarek Poplawski
2007-06-28 12:24               ` Patrick McHardy
2007-06-28 13:18                 ` Jarek Poplawski
2007-06-28 13:16                   ` Patrick McHardy

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=20070628065448.GA1618@ff.dom.local \
    --to=jarkao2@o2.pl \
    --cc=akpm@linux-foundation.org \
    --cc=bugme-daemon@kernel-bugs.osdl.org \
    --cc=davem@davemloft.net \
    --cc=kaber@trash.net \
    --cc=netdev@vger.kernel.org \
    --cc=ranko@spidernet.net \
    /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).