mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
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
This commit is contained in:
commit
054319b5e2
@ -73,6 +73,7 @@ enum clock_event_nofitiers {
|
|||||||
* @list: list head for the management code
|
* @list: list head for the management code
|
||||||
* @mode: operating mode assigned by the management code
|
* @mode: operating mode assigned by the management code
|
||||||
* @next_event: local storage for the next event in oneshot mode
|
* @next_event: local storage for the next event in oneshot mode
|
||||||
|
* @retries: number of forced programming retries
|
||||||
*/
|
*/
|
||||||
struct clock_event_device {
|
struct clock_event_device {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -93,6 +94,7 @@ struct clock_event_device {
|
|||||||
struct list_head list;
|
struct list_head list;
|
||||||
enum clock_event_mode mode;
|
enum clock_event_mode mode;
|
||||||
ktime_t next_event;
|
ktime_t next_event;
|
||||||
|
unsigned long retries;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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;
|
unsigned long flags;
|
||||||
|
|
||||||
if (!cputimer->running)
|
if (!cputimer->running)
|
||||||
@ -1072,6 +1072,10 @@ static void stop_process_timers(struct task_struct *tsk)
|
|||||||
spin_lock_irqsave(&cputimer->lock, flags);
|
spin_lock_irqsave(&cputimer->lock, flags);
|
||||||
cputimer->running = 0;
|
cputimer->running = 0;
|
||||||
spin_unlock_irqrestore(&cputimer->lock, flags);
|
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;
|
static u32 onecputick;
|
||||||
@ -1133,7 +1137,7 @@ static void check_process_timers(struct task_struct *tsk,
|
|||||||
list_empty(&timers[CPUCLOCK_VIRT]) &&
|
list_empty(&timers[CPUCLOCK_VIRT]) &&
|
||||||
cputime_eq(sig->it[CPUCLOCK_VIRT].expires, cputime_zero) &&
|
cputime_eq(sig->it[CPUCLOCK_VIRT].expires, cputime_zero) &&
|
||||||
list_empty(&timers[CPUCLOCK_SCHED])) {
|
list_empty(&timers[CPUCLOCK_SCHED])) {
|
||||||
stop_process_timers(tsk);
|
stop_process_timers(sig);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,29 @@
|
|||||||
|
|
||||||
#include "tick-internal.h"
|
#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
|
* 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)
|
if (!ret || !force)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
dev->retries++;
|
||||||
/*
|
/*
|
||||||
* We tried 2 times to program the device with the given
|
* We tried 3 times to program the device with the given
|
||||||
* min_delta_ns. If that's not working then we double it
|
* min_delta_ns. If that's not working then we increase it
|
||||||
* and emit a warning.
|
* and emit a warning.
|
||||||
*/
|
*/
|
||||||
if (++i > 2) {
|
if (++i > 2) {
|
||||||
/* Increase the min. delta and try again */
|
/* Increase the min. delta and try again */
|
||||||
if (!dev->min_delta_ns)
|
if (tick_increase_min_delta(dev)) {
|
||||||
dev->min_delta_ns = 5000;
|
/*
|
||||||
else
|
* Get out of the loop if min_delta_ns
|
||||||
dev->min_delta_ns += dev->min_delta_ns >> 1;
|
* hit the limit already. That's
|
||||||
|
* better than staying here forever.
|
||||||
printk(KERN_WARNING
|
*
|
||||||
"CE: %s increasing min_delta_ns to %llu nsec\n",
|
* We clear next_event so we have a
|
||||||
dev->name ? dev->name : "?",
|
* chance that the box survives.
|
||||||
(unsigned long long) dev->min_delta_ns << 1);
|
*/
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"CE: Reprogramming failure. Giving up\n");
|
||||||
|
dev->next_event.tv64 = KTIME_MAX;
|
||||||
|
return -ETIME;
|
||||||
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,7 +818,8 @@ void update_wall_time(void)
|
|||||||
shift = min(shift, maxshift);
|
shift = min(shift, maxshift);
|
||||||
while (offset >= timekeeper.cycle_interval) {
|
while (offset >= timekeeper.cycle_interval) {
|
||||||
offset = logarithmic_accumulation(offset, shift);
|
offset = logarithmic_accumulation(offset, shift);
|
||||||
shift--;
|
if(offset < timekeeper.cycle_interval<<shift)
|
||||||
|
shift--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* correct the clock when NTP error is too big */
|
/* correct the clock when NTP error is too big */
|
||||||
|
@ -228,6 +228,7 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
|
|||||||
SEQ_printf(m, " event_handler: ");
|
SEQ_printf(m, " event_handler: ");
|
||||||
print_name_offset(m, dev->event_handler);
|
print_name_offset(m, dev->event_handler);
|
||||||
SEQ_printf(m, "\n");
|
SEQ_printf(m, "\n");
|
||||||
|
SEQ_printf(m, " retries: %lu\n", dev->retries);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void timer_list_show_tickdevices(struct seq_file *m)
|
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());
|
u64 now = ktime_to_ns(ktime_get());
|
||||||
int cpu;
|
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, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
|
||||||
SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
|
SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
|
||||||
|
|
||||||
|
@ -880,6 +880,7 @@ int try_to_del_timer_sync(struct timer_list *timer)
|
|||||||
if (base->running_timer == timer)
|
if (base->running_timer == timer)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
timer_stats_timer_clear_start_info(timer);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (timer_pending(timer)) {
|
if (timer_pending(timer)) {
|
||||||
detach_timer(timer, 1);
|
detach_timer(timer, 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user