hrtimer: mark migration state
authorThomas Gleixner <tglx@linutronix.de>
Mon, 29 Sep 2008 13:44:46 +0000 (15:44 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 29 Sep 2008 15:09:14 +0000 (17:09 +0200)
Impact: during migration active hrtimers can be seen as inactive

The migration code removes the hrtimers from the queues of the dead
CPU and sets the state temporary to INACTIVE. The enqueue code sets it
to ACTIVE/PENDING again.

Prevent that the wrong state can be seen by using a separate migration
state bit.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
include/linux/hrtimer.h
kernel/hrtimer.c

index 6d93dce61cbbc25c8b17d2f8f8c5c9d0e864ee9f..bdd88df1b4e5c2cb235bcf4335022a6cf9fd616b 100644 (file)
@@ -67,9 +67,10 @@ enum hrtimer_cb_mode {
  * 0x02                callback function running
  * 0x04                callback pending (high resolution mode)
  *
- * Special case:
+ * Special cases:
  * 0x03                callback function running and enqueued
  *             (was requeued on another CPU)
+ * 0x09                timer was migrated on CPU hotunplug
  * The "callback function running and enqueued" status is only possible on
  * SMP. It happens for example when a posix timer expired and the callback
  * queued a signal. Between dropping the lock which protects the posix timer
@@ -87,6 +88,7 @@ enum hrtimer_cb_mode {
 #define HRTIMER_STATE_ENQUEUED 0x01
 #define HRTIMER_STATE_CALLBACK 0x02
 #define HRTIMER_STATE_PENDING  0x04
+#define HRTIMER_STATE_MIGRATE  0x08
 
 /**
  * struct hrtimer - the basic hrtimer structure
index ac2f6d6d4868a7b91a15675e243042f4cf78c2ae..ace723dd1e52f400c63be443ce6f78325ccc8219 100644 (file)
@@ -1602,7 +1602,13 @@ static int migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
                timer = rb_entry(node, struct hrtimer, node);
                BUG_ON(hrtimer_callback_running(timer));
                debug_hrtimer_deactivate(timer);
-               __remove_hrtimer(timer, old_base, HRTIMER_STATE_INACTIVE, 0);
+
+               /*
+                * Mark it as STATE_MIGRATE not INACTIVE otherwise the
+                * timer could be seen as !active and just vanish away
+                * under us on another CPU
+                */
+               __remove_hrtimer(timer, old_base, HRTIMER_STATE_MIGRATE, 0);
                timer->base = new_base;
                /*
                 * Enqueue the timer. Allow reprogramming of the event device
@@ -1620,13 +1626,15 @@ static int migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
                 * state, we need to do that otherwise we end up with
                 * a stale timer.
                 */
-               if (timer->state == HRTIMER_STATE_INACTIVE) {
+               if (timer->state == HRTIMER_STATE_MIGRATE) {
                        timer->state = HRTIMER_STATE_PENDING;
                        list_add_tail(&timer->cb_entry,
                                      &new_base->cpu_base->cb_pending);
                        raise = 1;
                }
 #endif
+               /* Clear the migration state bit */
+               timer->state &= ~HRTIMER_STATE_MIGRATE;
        }
        return raise;
 }