[dm-devel] [PATCH] dm-statistics: fix a possible counter corruption on 32-bit systems
Mikulas Patocka
mpatocka at redhat.com
Fri Sep 13 21:42:24 UTC 2013
Hi
I found this bug when reading through the statistics patch. That trick to
avoid irq disabling can be done on 64-bit architectures, but not on
32-bit.
Push this patch upstream.
Mikulas
---
dm-statistics: fix a possible counter corruption on 32-bit systems
There was a deliberate race condition in dm_stat_for_entry to avoid the
overhead disabling and enabling interrupts. The race could result in some
events not being counted.
However, on 32-bit architectures, operations on long long variables are
not atomic, so the race condition could cause the counter to jump by 2^32.
Such jumps could be disruptive, so we need to do proper locking on 32-bit
architectures.
Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
---
drivers/md/dm-stats.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
Index: linux-3.11-fast/drivers/md/dm-stats.c
===================================================================
--- linux-3.11-fast.orig/drivers/md/dm-stats.c 2013-09-13 22:26:00.000000000 +0200
+++ linux-3.11-fast/drivers/md/dm-stats.c 2013-09-13 23:30:08.000000000 +0200
@@ -451,19 +451,26 @@ static void dm_stat_for_entry(struct dm_
struct dm_stat_percpu *p;
/*
- * For strict correctness we should use local_irq_disable/enable
+ * For strict correctness we should use local_irq_save/restore
* instead of preempt_disable/enable.
*
- * This is racy if the driver finishes bios from non-interrupt
- * context as well as from interrupt context or from more different
- * interrupts.
+ * preempt_disable/enable is racy if the driver finishes bios
+ * from non-interrupt context as well as from interrupt context
+ * or from more different interrupts.
*
- * However, the race only results in not counting some events,
- * so it is acceptable.
+ * On 64-bit architectures the race only results in not counting some
+ * events, so it is acceptable. On 32-bit architectures the race could
+ * cause the counter going off by 2^32, so we need to do proper locking
+ * there.
*
* part_stat_lock()/part_stat_unlock() have this race too.
*/
+#if BITS_PER_LONG == 32
+ unsigned long flags;
+ local_irq_save(flags);
+#else
preempt_disable();
+#endif
p = &s->stat_percpu[smp_processor_id()][entry];
if (!end) {
@@ -478,7 +485,11 @@ static void dm_stat_for_entry(struct dm_
p->ticks[idx] += duration;
}
+#if BITS_PER_LONG == 32
+ local_irq_restore(flags);
+#else
preempt_enable();
+#endif
}
static void __dm_stat_bio(struct dm_stat *s, unsigned long bi_rw,
More information about the dm-devel
mailing list