tick/broadcast: Serialize access to tick_next_period
[sfrench/cifs-2.6.git] / kernel / time / tick-broadcast.c
index 36d7464c8962543d6b29fa43f3c70d28c3c41362..2a47c8f80e53bfbb024643c8cd01e1cf4ab96fe2 100644 (file)
@@ -877,6 +877,22 @@ static void tick_broadcast_init_next_event(struct cpumask *mask,
        }
 }
 
+static inline ktime_t tick_get_next_period(void)
+{
+       ktime_t next;
+
+       /*
+        * Protect against concurrent updates (store /load tearing on
+        * 32bit). It does not matter if the time is already in the
+        * past. The broadcast device which is about to be programmed will
+        * fire in any case.
+        */
+       raw_spin_lock(&jiffies_lock);
+       next = tick_next_period;
+       raw_spin_unlock(&jiffies_lock);
+       return next;
+}
+
 /**
  * tick_broadcast_setup_oneshot - setup the broadcast device
  */
@@ -905,10 +921,11 @@ static void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
                           tick_broadcast_oneshot_mask, tmpmask);
 
                if (was_periodic && !cpumask_empty(tmpmask)) {
+                       ktime_t nextevt = tick_get_next_period();
+
                        clockevents_switch_state(bc, CLOCK_EVT_STATE_ONESHOT);
-                       tick_broadcast_init_next_event(tmpmask,
-                                                      tick_next_period);
-                       tick_broadcast_set_event(bc, cpu, tick_next_period);
+                       tick_broadcast_init_next_event(tmpmask, nextevt);
+                       tick_broadcast_set_event(bc, cpu, nextevt);
                } else
                        bc->next_event = KTIME_MAX;
        } else {