aboutsummaryrefslogtreecommitdiffstats
path: root/lib/flex_proportions.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-05-31 18:42:06 -0400
committerFengguang Wu <fengguang.wu@intel.com>2012-06-08 19:37:55 -0400
commite78d4833c03e28205b3d983f0c4e586ee34785fd (patch)
treea0c91fbb027dd2cafce11c3fa699efca0d4fb52a /lib/flex_proportions.c
parentf3109a51f8dc88e8a94f620240b7474b91bed37a (diff)
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@suse.cz> Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
Diffstat (limited to 'lib/flex_proportions.c')
-rw-r--r--lib/flex_proportions.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/lib/flex_proportions.c b/lib/flex_proportions.c
index e02a3883ae0..c785554f952 100644
--- a/lib/flex_proportions.c
+++ b/lib/flex_proportions.c
@@ -62,13 +62,18 @@ void fprop_global_destroy(struct fprop_global *p)
62 */ 62 */
63bool fprop_new_period(struct fprop_global *p, int periods) 63bool fprop_new_period(struct fprop_global *p, int periods)
64{ 64{
65 u64 events = percpu_counter_sum(&p->events); 65 u64 events;
66 unsigned long flags;
66 67
68 local_irq_save(flags);
69 events = percpu_counter_sum(&p->events);
67 /* 70 /*
68 * Don't do anything if there are no events. 71 * Don't do anything if there are no events.
69 */ 72 */
70 if (events <= 1) 73 if (events <= 1) {
74 local_irq_restore(flags);
71 return false; 75 return false;
76 }
72 write_seqcount_begin(&p->sequence); 77 write_seqcount_begin(&p->sequence);
73 if (periods < 64) 78 if (periods < 64)
74 events -= events >> periods; 79 events -= events >> periods;
@@ -76,6 +81,7 @@ bool fprop_new_period(struct fprop_global *p, int periods)
76 percpu_counter_add(&p->events, -events); 81 percpu_counter_add(&p->events, -events);
77 p->period += periods; 82 p->period += periods;
78 write_seqcount_end(&p->sequence); 83 write_seqcount_end(&p->sequence);
84 local_irq_restore(flags);
79 85
80 return true; 86 return true;
81} 87}