Re: [PATCH 2/2] block: Convert BDI proportion calculations toflexible proportions

From: Jan Kara
Date: Thu May 31 2012 - 18:42:06 EST


On Fri 01-06-12 00:26:05, Peter Zijlstra wrote:
> On Fri, 2012-06-01 at 00:11 +0200, Jan Kara wrote:
> > bool fprop_new_period(struct fprop_global *p, int periods)
> > {
> > - u64 events = percpu_counter_sum(&p->events);
> > + u64 events;
> > + unsigned long flags;
> >
> > + local_irq_save(flags);
> > + events = percpu_counter_sum(&p->events);
> > + local_irq_restore(flags);
> > /*
> > * Don't do anything if there are no events.
> > */
> > @@ -73,7 +77,9 @@ bool fprop_new_period(struct fprop_global *p, int periods)
> > if (periods < 64)
> > events -= events >> periods;
> > /* Use addition to avoid losing events happening between sum and set */
> > + local_irq_save(flags);
> > percpu_counter_add(&p->events, -events);
> > + local_irq_restore(flags);
> > p->period += periods;
> > write_seqcount_end(&p->sequence);
>
> Uhm, why bother enabling it in between? Just wrap the whole function in
> a single IRQ disable.
I wanted to have interrupts disabled for as short as possible but if you
think it doesn't matter, I'll take your advice. The result is attached.

Honza
--
Jan Kara <jack@xxxxxxx>
SUSE Labs, CR
From: Jan Kara <jack@xxxxxxx>
Subject: lib: Fix possible deadlock in flexible proportion code

When percpu counter function in fprop_new_period() is interrupted by an
interrupt while holding counter lock, it can cause deadlock when the
interrupt wants to take the lock as well. Fix the problem by disabling
interrupts when calling percpu counter functions.

Signed-off-by: Jan Kara <jack@xxxxxxx>

diff -u b/lib/flex_proportions.c b/lib/flex_proportions.c
--- b/lib/flex_proportions.c
+++ b/lib/flex_proportions.c
@@ -62,13 +62,18 @@
*/
bool fprop_new_period(struct fprop_global *p, int periods)
{
- u64 events = percpu_counter_sum(&p->events);
+ u64 events;
+ unsigned long flags;

+ local_irq_save(flags);
+ events = percpu_counter_sum(&p->events);
/*
* Don't do anything if there are no events.
*/
- if (events <= 1)
+ if (events <= 1) {
+ local_irq_restore(flags);
return false;
+ }
write_seqcount_begin(&p->sequence);
if (periods < 64)
events -= events >> periods;
@@ -76,6 +81,7 @@
percpu_counter_add(&p->events, -events);
p->period += periods;
write_seqcount_end(&p->sequence);
+ local_irq_restore(flags);

return true;
}