Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 054319b5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'timers-fixes-for-linus' of...

Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  time: Fix accumulation bug triggered by long delay.
  posix-cpu-timers: Reset expire cache when no timer is running
  timer stats: Fix del_timer_sync() and try_to_del_timer_sync()
  clockevents: Sanitize min_delta_ns adjustment and prevent overflows
parents 833961d8 830ec045
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ enum clock_event_nofitiers {
 * @list:		list head for the management code
 * @mode:		operating mode assigned by the management code
 * @next_event:		local storage for the next event in oneshot mode
 * @retries:		number of forced programming retries
 */
struct clock_event_device {
	const char		*name;
@@ -93,6 +94,7 @@ struct clock_event_device {
	struct list_head	list;
	enum clock_event_mode	mode;
	ktime_t			next_event;
	unsigned long		retries;
};

/*
+7 −3
Original line number Diff line number Diff line
@@ -1061,9 +1061,9 @@ static void check_thread_timers(struct task_struct *tsk,
	}
}

static void stop_process_timers(struct task_struct *tsk)
static void stop_process_timers(struct signal_struct *sig)
{
	struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
	struct thread_group_cputimer *cputimer = &sig->cputimer;
	unsigned long flags;

	if (!cputimer->running)
@@ -1072,6 +1072,10 @@ static void stop_process_timers(struct task_struct *tsk)
	spin_lock_irqsave(&cputimer->lock, flags);
	cputimer->running = 0;
	spin_unlock_irqrestore(&cputimer->lock, flags);

	sig->cputime_expires.prof_exp = cputime_zero;
	sig->cputime_expires.virt_exp = cputime_zero;
	sig->cputime_expires.sched_exp = 0;
}

static u32 onecputick;
@@ -1133,7 +1137,7 @@ static void check_process_timers(struct task_struct *tsk,
	    list_empty(&timers[CPUCLOCK_VIRT]) &&
	    cputime_eq(sig->it[CPUCLOCK_VIRT].expires, cputime_zero) &&
	    list_empty(&timers[CPUCLOCK_SCHED])) {
		stop_process_timers(tsk);
		stop_process_timers(sig);
		return;
	}

+40 −12
Original line number Diff line number Diff line
@@ -22,6 +22,29 @@

#include "tick-internal.h"

/* Limit min_delta to a jiffie */
#define MIN_DELTA_LIMIT		(NSEC_PER_SEC / HZ)

static int tick_increase_min_delta(struct clock_event_device *dev)
{
	/* Nothing to do if we already reached the limit */
	if (dev->min_delta_ns >= MIN_DELTA_LIMIT)
		return -ETIME;

	if (dev->min_delta_ns < 5000)
		dev->min_delta_ns = 5000;
	else
		dev->min_delta_ns += dev->min_delta_ns >> 1;

	if (dev->min_delta_ns > MIN_DELTA_LIMIT)
		dev->min_delta_ns = MIN_DELTA_LIMIT;

	printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n",
	       dev->name ? dev->name : "?",
	       (unsigned long long) dev->min_delta_ns);
	return 0;
}

/**
 * tick_program_event internal worker function
 */
@@ -37,23 +60,28 @@ int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires,
		if (!ret || !force)
			return ret;

		dev->retries++;
		/*
		 * We tried 2 times to program the device with the given
		 * min_delta_ns. If that's not working then we double it
		 * We tried 3 times to program the device with the given
		 * min_delta_ns. If that's not working then we increase it
		 * and emit a warning.
		 */
		if (++i > 2) {
			/* Increase the min. delta and try again */
			if (!dev->min_delta_ns)
				dev->min_delta_ns = 5000;
			else
				dev->min_delta_ns += dev->min_delta_ns >> 1;

			if (tick_increase_min_delta(dev)) {
				/*
				 * Get out of the loop if min_delta_ns
				 * hit the limit already. That's
				 * better than staying here forever.
				 *
				 * We clear next_event so we have a
				 * chance that the box survives.
				 */
				printk(KERN_WARNING
			       "CE: %s increasing min_delta_ns to %llu nsec\n",
			       dev->name ? dev->name : "?",
			       (unsigned long long) dev->min_delta_ns << 1);

				       "CE: Reprogramming failure. Giving up\n");
				dev->next_event.tv64 = KTIME_MAX;
				return -ETIME;
			}
			i = 0;
		}

+2 −1
Original line number Diff line number Diff line
@@ -818,6 +818,7 @@ void update_wall_time(void)
	shift = min(shift, maxshift);
	while (offset >= timekeeper.cycle_interval) {
		offset = logarithmic_accumulation(offset, shift);
		if(offset < timekeeper.cycle_interval<<shift)
			shift--;
	}

+2 −1
Original line number Diff line number Diff line
@@ -228,6 +228,7 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
	SEQ_printf(m, " event_handler:  ");
	print_name_offset(m, dev->event_handler);
	SEQ_printf(m, "\n");
	SEQ_printf(m, " retries:        %lu\n", dev->retries);
}

static void timer_list_show_tickdevices(struct seq_file *m)
@@ -257,7 +258,7 @@ static int timer_list_show(struct seq_file *m, void *v)
	u64 now = ktime_to_ns(ktime_get());
	int cpu;

	SEQ_printf(m, "Timer List Version: v0.5\n");
	SEQ_printf(m, "Timer List Version: v0.6\n");
	SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
	SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);

Loading