|
@@ -43,6 +43,7 @@
|
|
|
#include <linux/tick.h>
|
|
|
#include <linux/seq_file.h>
|
|
|
#include <linux/err.h>
|
|
|
+#include <linux/debugobjects.h>
|
|
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
@@ -342,6 +343,115 @@ ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs)
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_DEBUG_OBJECTS_TIMERS
|
|
|
+
|
|
|
+static struct debug_obj_descr hrtimer_debug_descr;
|
|
|
+
|
|
|
+/*
|
|
|
+ * fixup_init is called when:
|
|
|
+ * - an active object is initialized
|
|
|
+ */
|
|
|
+static int hrtimer_fixup_init(void *addr, enum debug_obj_state state)
|
|
|
+{
|
|
|
+ struct hrtimer *timer = addr;
|
|
|
+
|
|
|
+ switch (state) {
|
|
|
+ case ODEBUG_STATE_ACTIVE:
|
|
|
+ hrtimer_cancel(timer);
|
|
|
+ debug_object_init(timer, &hrtimer_debug_descr);
|
|
|
+ return 1;
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * fixup_activate is called when:
|
|
|
+ * - an active object is activated
|
|
|
+ * - an unknown object is activated (might be a statically initialized object)
|
|
|
+ */
|
|
|
+static int hrtimer_fixup_activate(void *addr, enum debug_obj_state state)
|
|
|
+{
|
|
|
+ switch (state) {
|
|
|
+
|
|
|
+ case ODEBUG_STATE_NOTAVAILABLE:
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ case ODEBUG_STATE_ACTIVE:
|
|
|
+ WARN_ON(1);
|
|
|
+
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * fixup_free is called when:
|
|
|
+ * - an active object is freed
|
|
|
+ */
|
|
|
+static int hrtimer_fixup_free(void *addr, enum debug_obj_state state)
|
|
|
+{
|
|
|
+ struct hrtimer *timer = addr;
|
|
|
+
|
|
|
+ switch (state) {
|
|
|
+ case ODEBUG_STATE_ACTIVE:
|
|
|
+ hrtimer_cancel(timer);
|
|
|
+ debug_object_free(timer, &hrtimer_debug_descr);
|
|
|
+ return 1;
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static struct debug_obj_descr hrtimer_debug_descr = {
|
|
|
+ .name = "hrtimer",
|
|
|
+ .fixup_init = hrtimer_fixup_init,
|
|
|
+ .fixup_activate = hrtimer_fixup_activate,
|
|
|
+ .fixup_free = hrtimer_fixup_free,
|
|
|
+};
|
|
|
+
|
|
|
+static inline void debug_hrtimer_init(struct hrtimer *timer)
|
|
|
+{
|
|
|
+ debug_object_init(timer, &hrtimer_debug_descr);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void debug_hrtimer_activate(struct hrtimer *timer)
|
|
|
+{
|
|
|
+ debug_object_activate(timer, &hrtimer_debug_descr);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void debug_hrtimer_deactivate(struct hrtimer *timer)
|
|
|
+{
|
|
|
+ debug_object_deactivate(timer, &hrtimer_debug_descr);
|
|
|
+}
|
|
|
+
|
|
|
+static inline void debug_hrtimer_free(struct hrtimer *timer)
|
|
|
+{
|
|
|
+ debug_object_free(timer, &hrtimer_debug_descr);
|
|
|
+}
|
|
|
+
|
|
|
+static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
|
|
|
+ enum hrtimer_mode mode);
|
|
|
+
|
|
|
+void hrtimer_init_on_stack(struct hrtimer *timer, clockid_t clock_id,
|
|
|
+ enum hrtimer_mode mode)
|
|
|
+{
|
|
|
+ debug_object_init_on_stack(timer, &hrtimer_debug_descr);
|
|
|
+ __hrtimer_init(timer, clock_id, mode);
|
|
|
+}
|
|
|
+
|
|
|
+void destroy_hrtimer_on_stack(struct hrtimer *timer)
|
|
|
+{
|
|
|
+ debug_object_free(timer, &hrtimer_debug_descr);
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+static inline void debug_hrtimer_init(struct hrtimer *timer) { }
|
|
|
+static inline void debug_hrtimer_activate(struct hrtimer *timer) { }
|
|
|
+static inline void debug_hrtimer_deactivate(struct hrtimer *timer) { }
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
* Check, whether the timer is on the callback pending list
|
|
|
*/
|
|
@@ -567,6 +677,7 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
|
|
|
/* Timer is expired, act upon the callback mode */
|
|
|
switch(timer->cb_mode) {
|
|
|
case HRTIMER_CB_IRQSAFE_NO_RESTART:
|
|
|
+ debug_hrtimer_deactivate(timer);
|
|
|
/*
|
|
|
* We can call the callback from here. No restart
|
|
|
* happens, so no danger of recursion
|
|
@@ -581,6 +692,7 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
|
|
|
* the tick timer in the softirq ! The calling site
|
|
|
* takes care of this.
|
|
|
*/
|
|
|
+ debug_hrtimer_deactivate(timer);
|
|
|
return 1;
|
|
|
case HRTIMER_CB_IRQSAFE:
|
|
|
case HRTIMER_CB_SOFTIRQ:
|
|
@@ -735,6 +847,8 @@ static void enqueue_hrtimer(struct hrtimer *timer,
|
|
|
struct hrtimer *entry;
|
|
|
int leftmost = 1;
|
|
|
|
|
|
+ debug_hrtimer_activate(timer);
|
|
|
+
|
|
|
/*
|
|
|
* Find the right place in the rbtree:
|
|
|
*/
|
|
@@ -831,6 +945,7 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
|
|
|
* reprogramming happens in the interrupt handler. This is a
|
|
|
* rare case and less expensive than a smp call.
|
|
|
*/
|
|
|
+ debug_hrtimer_deactivate(timer);
|
|
|
timer_stats_hrtimer_clear_start_info(timer);
|
|
|
reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases);
|
|
|
__remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE,
|
|
@@ -878,6 +993,7 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
|
|
|
tim = ktime_add_safe(tim, base->resolution);
|
|
|
#endif
|
|
|
}
|
|
|
+
|
|
|
timer->expires = tim;
|
|
|
|
|
|
timer_stats_hrtimer_set_start_info(timer);
|
|
@@ -1011,14 +1127,8 @@ ktime_t hrtimer_get_next_event(void)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-/**
|
|
|
- * hrtimer_init - initialize a timer to the given clock
|
|
|
- * @timer: the timer to be initialized
|
|
|
- * @clock_id: the clock to be used
|
|
|
- * @mode: timer mode abs/rel
|
|
|
- */
|
|
|
-void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
|
|
|
- enum hrtimer_mode mode)
|
|
|
+static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
|
|
|
+ enum hrtimer_mode mode)
|
|
|
{
|
|
|
struct hrtimer_cpu_base *cpu_base;
|
|
|
|
|
@@ -1039,6 +1149,19 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
|
|
|
memset(timer->start_comm, 0, TASK_COMM_LEN);
|
|
|
#endif
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hrtimer_init - initialize a timer to the given clock
|
|
|
+ * @timer: the timer to be initialized
|
|
|
+ * @clock_id: the clock to be used
|
|
|
+ * @mode: timer mode abs/rel
|
|
|
+ */
|
|
|
+void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
|
|
|
+ enum hrtimer_mode mode)
|
|
|
+{
|
|
|
+ debug_hrtimer_init(timer);
|
|
|
+ __hrtimer_init(timer, clock_id, mode);
|
|
|
+}
|
|
|
EXPORT_SYMBOL_GPL(hrtimer_init);
|
|
|
|
|
|
/**
|
|
@@ -1072,6 +1195,7 @@ static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base)
|
|
|
timer = list_entry(cpu_base->cb_pending.next,
|
|
|
struct hrtimer, cb_entry);
|
|
|
|
|
|
+ debug_hrtimer_deactivate(timer);
|
|
|
timer_stats_account_hrtimer(timer);
|
|
|
|
|
|
fn = timer->function;
|
|
@@ -1120,6 +1244,7 @@ static void __run_hrtimer(struct hrtimer *timer)
|
|
|
enum hrtimer_restart (*fn)(struct hrtimer *);
|
|
|
int restart;
|
|
|
|
|
|
+ debug_hrtimer_deactivate(timer);
|
|
|
__remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0);
|
|
|
timer_stats_account_hrtimer(timer);
|
|
|
|
|
@@ -1378,22 +1503,27 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
|
|
|
{
|
|
|
struct hrtimer_sleeper t;
|
|
|
struct timespec __user *rmtp;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
- hrtimer_init(&t.timer, restart->nanosleep.index, HRTIMER_MODE_ABS);
|
|
|
+ hrtimer_init_on_stack(&t.timer, restart->nanosleep.index,
|
|
|
+ HRTIMER_MODE_ABS);
|
|
|
t.timer.expires.tv64 = restart->nanosleep.expires;
|
|
|
|
|
|
if (do_nanosleep(&t, HRTIMER_MODE_ABS))
|
|
|
- return 0;
|
|
|
+ goto out;
|
|
|
|
|
|
rmtp = restart->nanosleep.rmtp;
|
|
|
if (rmtp) {
|
|
|
- int ret = update_rmtp(&t.timer, rmtp);
|
|
|
+ ret = update_rmtp(&t.timer, rmtp);
|
|
|
if (ret <= 0)
|
|
|
- return ret;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
/* The other values in restart are already filled in */
|
|
|
- return -ERESTART_RESTARTBLOCK;
|
|
|
+ ret = -ERESTART_RESTARTBLOCK;
|
|
|
+out:
|
|
|
+ destroy_hrtimer_on_stack(&t.timer);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
|
@@ -1401,20 +1531,23 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
|
|
{
|
|
|
struct restart_block *restart;
|
|
|
struct hrtimer_sleeper t;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
- hrtimer_init(&t.timer, clockid, mode);
|
|
|
+ hrtimer_init_on_stack(&t.timer, clockid, mode);
|
|
|
t.timer.expires = timespec_to_ktime(*rqtp);
|
|
|
if (do_nanosleep(&t, mode))
|
|
|
- return 0;
|
|
|
+ goto out;
|
|
|
|
|
|
/* Absolute timers do not update the rmtp value and restart: */
|
|
|
- if (mode == HRTIMER_MODE_ABS)
|
|
|
- return -ERESTARTNOHAND;
|
|
|
+ if (mode == HRTIMER_MODE_ABS) {
|
|
|
+ ret = -ERESTARTNOHAND;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
if (rmtp) {
|
|
|
- int ret = update_rmtp(&t.timer, rmtp);
|
|
|
+ ret = update_rmtp(&t.timer, rmtp);
|
|
|
if (ret <= 0)
|
|
|
- return ret;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
restart = ¤t_thread_info()->restart_block;
|
|
@@ -1423,7 +1556,10 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
|
|
|
restart->nanosleep.rmtp = rmtp;
|
|
|
restart->nanosleep.expires = t.timer.expires.tv64;
|
|
|
|
|
|
- return -ERESTART_RESTARTBLOCK;
|
|
|
+ ret = -ERESTART_RESTARTBLOCK;
|
|
|
+out:
|
|
|
+ destroy_hrtimer_on_stack(&t.timer);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
asmlinkage long
|
|
@@ -1468,6 +1604,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
|
|
|
while ((node = rb_first(&old_base->active))) {
|
|
|
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);
|
|
|
timer->base = new_base;
|
|
|
/*
|