From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.linutronix.de (146.0.238.70:993) by crypto-ml.lab.linutronix.de with IMAP4-SSL for ; 24 Feb 2019 15:11:59 -0000 Received: from mga02.intel.com ([134.134.136.20]) by Galois.linutronix.de with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256) (Exim 4.80) (envelope-from ) id 1gxvO0-0001Qu-Mm for speck@linutronix.de; Sun, 24 Feb 2019 16:08:13 +0100 From: Andi Kleen Subject: [MODERATED] [PATCH v6 20/43] MDSv6 Date: Sun, 24 Feb 2019 07:07:26 -0800 Message-Id: In-Reply-To: References: In-Reply-To: References: Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit MIME-Version: 1.0 To: speck@linutronix.de Cc: Andi Kleen List-ID: Timers run asynchronously to user processes. According to an audit most timer handlers do not touch user data, so don't need to clear. But some do. Add flags to normal and hrtimers to request clearing. Future patches will use these flags to mark timers that touch user data. Note this takes one bit from the timer wheel index field away, but it seems there are less wheels available anyways, so that should be ok. Signed-off-by: Andi Kleen --- include/linux/hrtimer.h | 4 ++++ include/linux/timer.h | 14 +++++++++++--- kernel/time/hrtimer.c | 5 +++++ kernel/time/timer.c | 8 ++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 2e8957eac4d4..c8e3db15e55b 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -32,6 +32,7 @@ struct hrtimer_cpu_base; * when starting the timer) * HRTIMER_MODE_SOFT - Timer callback function will be executed in * soft irq context + * HRTIMER_MODE_USER_DATA - Handler does touch user data. */ enum hrtimer_mode { HRTIMER_MODE_ABS = 0x00, @@ -48,6 +49,7 @@ enum hrtimer_mode { HRTIMER_MODE_ABS_PINNED_SOFT = HRTIMER_MODE_ABS_PINNED | HRTIMER_MODE_SOFT, HRTIMER_MODE_REL_PINNED_SOFT = HRTIMER_MODE_REL_PINNED | HRTIMER_MODE_SOFT, + HRTIMER_MODE_USER_DATA = 0x08, }; /* @@ -101,6 +103,7 @@ enum hrtimer_restart { * @state: state information (See bit values above) * @is_rel: Set if the timer was armed relative * @is_soft: Set if hrtimer will be expired in soft interrupt context. + * @user_data: function does touch user data. * * The hrtimer structure must be initialized by hrtimer_init() */ @@ -112,6 +115,7 @@ struct hrtimer { u8 state; u8 is_rel; u8 is_soft; + u8 user_data; }; /** diff --git a/include/linux/timer.h b/include/linux/timer.h index 7b066fd38248..78ae3602fbcd 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -56,10 +56,13 @@ struct timer_list { #define TIMER_DEFERRABLE 0x00080000 #define TIMER_PINNED 0x00100000 #define TIMER_IRQSAFE 0x00200000 -#define TIMER_ARRAYSHIFT 22 -#define TIMER_ARRAYMASK 0xFFC00000 +#define TIMER_USER_DATA 0x00400000 +#define TIMER_ARRAYSHIFT 23 +#define TIMER_ARRAYMASK 0xFF800000 -#define TIMER_TRACE_FLAGMASK (TIMER_MIGRATING | TIMER_DEFERRABLE | TIMER_PINNED | TIMER_IRQSAFE) +#define TIMER_TRACE_FLAGMASK \ + (TIMER_MIGRATING | TIMER_DEFERRABLE | TIMER_PINNED | TIMER_IRQSAFE | \ + TIMER_USER_DATA) #define __TIMER_INITIALIZER(_function, _flags) { \ .entry = { .next = TIMER_ENTRY_STATIC }, \ @@ -73,6 +76,11 @@ struct timer_list { struct timer_list _name = \ __TIMER_INITIALIZER(_function, 0) +#define DEFINE_TIMER_USERDATA(_name, _function) \ + struct timer_list _name = \ + __TIMER_INITIALIZER(_function, TIMER_USER_DATA) + + /* * LOCKDEP and DEBUG timer interfaces. */ diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index f5cfa1b73d6f..4d8f419ab55f 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -1276,6 +1277,7 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, clock_id = CLOCK_MONOTONIC; base += hrtimer_clockid_to_base(clock_id); + timer->user_data = !!(mode & HRTIMER_MODE_USER_DATA); timer->is_soft = softtimer; timer->base = &cpu_base->clock_base[base]; timerqueue_init(&timer->node); @@ -1390,6 +1392,9 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, trace_hrtimer_expire_exit(timer); raw_spin_lock_irq(&cpu_base->lock); + if (timer->user_data) + lazy_clear_cpu(); + /* * Note: We clear the running state after enqueue_hrtimer and * we do not reprogram the event hardware. Happens either in diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 444156debfa0..caaa87b91268 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -1338,6 +1339,13 @@ static void call_timer_fn(struct timer_list *timer, void (*fn)(struct timer_list */ preempt_count_set(count); } + + /* + * The timer might have touched user data. Schedule + * a cpu clear on the next kernel exit. + */ + if (timer->flags & TIMER_USER_DATA) + lazy_clear_cpu(); } static void expire_timers(struct timer_base *base, struct hlist_head *head) -- 2.17.2