net: icmp: fix data-race in cmp_global_allow()
[linux-2.6-block.git] / net / ipv4 / icmp.c
index a72fbdf1fb85ccb7359229a7b9bbed0c6a67edf4..18068ed42f258349a07248a85acdf93b8c2f1749 100644 (file)
@@ -249,10 +249,11 @@ bool icmp_global_allow(void)
        bool rc = false;
 
        /* Check if token bucket is empty and cannot be refilled
-        * without taking the spinlock.
+        * without taking the spinlock. The READ_ONCE() are paired
+        * with the following WRITE_ONCE() in this same function.
         */
-       if (!icmp_global.credit) {
-               delta = min_t(u32, now - icmp_global.stamp, HZ);
+       if (!READ_ONCE(icmp_global.credit)) {
+               delta = min_t(u32, now - READ_ONCE(icmp_global.stamp), HZ);
                if (delta < HZ / 50)
                        return false;
        }
@@ -262,14 +263,14 @@ bool icmp_global_allow(void)
        if (delta >= HZ / 50) {
                incr = sysctl_icmp_msgs_per_sec * delta / HZ ;
                if (incr)
-                       icmp_global.stamp = now;
+                       WRITE_ONCE(icmp_global.stamp, now);
        }
        credit = min_t(u32, icmp_global.credit + incr, sysctl_icmp_msgs_burst);
        if (credit) {
                credit--;
                rc = true;
        }
-       icmp_global.credit = credit;
+       WRITE_ONCE(icmp_global.credit, credit);
        spin_unlock(&icmp_global.lock);
        return rc;
 }