From patchwork Tue Jul 3 02:16:06 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: john stultz X-Patchwork-Id: 9773 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 5995E23E37 for ; Tue, 3 Jul 2012 02:17:46 +0000 (UTC) Received: from mail-yx0-f180.google.com (mail-yx0-f180.google.com [209.85.213.180]) by fiordland.canonical.com (Postfix) with ESMTP id 29E84A1816C for ; Tue, 3 Jul 2012 02:17:46 +0000 (UTC) Received: by mail-yx0-f180.google.com with SMTP id q6so5197696yen.11 for ; Mon, 02 Jul 2012 19:17:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :x-content-scanned:x-cbid:x-gm-message-state; bh=zYHzYM9CzUDIIGLbNapZoBP5D/bld1ANQOUiQMwE0iA=; b=RW6Ycd2T8VY+pwItv4s3AByeHVl/a9cNvpmBRZSkG5zb/F0cIonxVZgQpo7b+KmrDh y4teasZxyzLys+4HMn1LWuZaxOvjBuYWgLPTg31Q4RfgWbeFSNaFtCnsyNPfxGC/tzC6 LzoqCmzR99dlp6md4cS3lQ0X8jXKyis9AOYjNhc0IX92dU1Gl2PyYXdTDD6D52VnAinc WTHvyhWb8328QsDdrLjIcB98zLrVCfUMD4k+piEI5wPXLFCVemj1cOEfkx93FRyp20Dw CQslFb/j66G9Yt3DK8Ja4+A/HNgB8a4gjTSjwGqnzLPrGHuk5DAaqGO6iiE0E5nZTjLE Ox+w== Received: by 10.50.87.227 with SMTP id bb3mr6934474igb.57.1341281865777; Mon, 02 Jul 2012 19:17:45 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.24.148 with SMTP id v20csp33995ibb; Mon, 2 Jul 2012 19:17:45 -0700 (PDT) Received: by 10.68.218.101 with SMTP id pf5mr2943376pbc.152.1341281865173; Mon, 02 Jul 2012 19:17:45 -0700 (PDT) Received: from e37.co.us.ibm.com (e37.co.us.ibm.com. [32.97.110.158]) by mx.google.com with ESMTPS id gg3si24587301pbc.169.2012.07.02.19.17.44 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 02 Jul 2012 19:17:45 -0700 (PDT) Received-SPF: pass (google.com: domain of johnstul@us.ibm.com designates 32.97.110.158 as permitted sender) client-ip=32.97.110.158; Authentication-Results: mx.google.com; spf=pass (google.com: domain of johnstul@us.ibm.com designates 32.97.110.158 as permitted sender) smtp.mail=johnstul@us.ibm.com Received: from /spool/local by e37.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 2 Jul 2012 20:17:44 -0600 Received: from d03dlp02.boulder.ibm.com (9.17.202.178) by e37.co.us.ibm.com (192.168.1.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 2 Jul 2012 20:17:42 -0600 Received: from d03relay04.boulder.ibm.com (d03relay04.boulder.ibm.com [9.17.195.106]) by d03dlp02.boulder.ibm.com (Postfix) with ESMTP id BE6453E40048 for ; Tue, 3 Jul 2012 02:17:25 +0000 (WET) Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d03relay04.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q632GjvV131014 for ; Mon, 2 Jul 2012 20:17:09 -0600 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q632GUA9003684 for ; Mon, 2 Jul 2012 20:16:30 -0600 Received: from kernel.stglabs.ibm.com (kernel.stglabs.ibm.com [9.114.214.19]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q632GMSD003254; Mon, 2 Jul 2012 20:16:28 -0600 From: John Stultz To: Linux Kernel Cc: John Stultz , Prarit Bhargava , stable@vger.kernel.org, Thomas Gleixner Subject: [PATCH 3/3] [RFC] hrtimer: Update hrtimer base offsets each hrtimer_interrupt Date: Mon, 2 Jul 2012 22:16:06 -0400 Message-Id: <1341281766-22722-4-git-send-email-johnstul@us.ibm.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1341281766-22722-1-git-send-email-johnstul@us.ibm.com> References: <1341281766-22722-1-git-send-email-johnstul@us.ibm.com> X-Content-Scanned: Fidelis XPS MAILER x-cbid: 12070302-7408-0000-0000-0000066D0432 X-Gm-Message-State: ALoCoQm13lekUS2c+wnp3dvWGaD+NnfYa6eBeOaGjSovf9sc9njUCWLCt1y61c+weoGfjqoT+jO5 This patch introduces a new funciton which captures the CLOCK_MONOTONIC time, along with the CLOCK_REALTIME and CLOCK_BOOTTIME offsets at the same moment. This new function is then used in place of ktime_get() when hrtimer_interrupt() is expiring timers. This ensures that any changes to realtime or boottime offsets are noticed and stored into the per-cpu hrtimer base structures, prior to doing any hrtimer expiration. This should ensure that timers are not expired early if the offsets changes under us. This is useful in the case where clock_was_set() is called from atomic context and have to schedule the hrtimer base offset update via a timer, as it provides extra robustness in the face of any possible timer delay. CC: Prarit Bhargava CC: stable@vger.kernel.org CC: Thomas Gleixner Signed-off-by: John Stultz --- include/linux/hrtimer.h | 3 +++ kernel/hrtimer.c | 14 +++++++++++--- kernel/time/timekeeping.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index fd0dc30..f6b2a74 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -320,6 +320,9 @@ extern ktime_t ktime_get(void); extern ktime_t ktime_get_real(void); extern ktime_t ktime_get_boottime(void); extern ktime_t ktime_get_monotonic_offset(void); +extern void ktime_get_and_real_and_sleep_offset(ktime_t *monotonic, + ktime_t *real_offset, + ktime_t *sleep_offset); DECLARE_PER_CPU(struct tick_device, tick_cpu_device); diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 393fd4d..0e78b3e 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1260,18 +1260,26 @@ static void __run_hrtimer(struct hrtimer *timer, ktime_t *now) void hrtimer_interrupt(struct clock_event_device *dev) { struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); - ktime_t expires_next, now, entry_time, delta; + ktime_t expires_next, now, entry_time, delta, real_offset, sleep_offset; int i, retries = 0; BUG_ON(!cpu_base->hres_active); cpu_base->nr_events++; dev->next_event.tv64 = KTIME_MAX; - entry_time = now = ktime_get(); + + ktime_get_and_real_and_sleep_offset(&now, &real_offset, &sleep_offset); + + entry_time = now; retry: expires_next.tv64 = KTIME_MAX; raw_spin_lock(&cpu_base->lock); + + /* Update base offsets, to avoid early wakeups */ + cpu_base->clock_base[HRTIMER_BASE_REALTIME].offset = real_offset; + cpu_base->clock_base[HRTIMER_BASE_BOOTTIME].offset = sleep_offset; + /* * We set expires_next to KTIME_MAX here with cpu_base->lock * held to prevent that a timer is enqueued in our queue via @@ -1348,7 +1356,7 @@ retry: * interrupt routine. We give it 3 attempts to avoid * overreacting on some spurious event. */ - now = ktime_get(); + ktime_get_and_real_and_sleep_offset(&now, &real_offset, &sleep_offset); cpu_base->nr_retries++; if (++retries < 3) goto retry; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index cc2991d..c2ba132 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1250,6 +1250,41 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim, } while (read_seqretry(&timekeeper.lock, seq)); } + +void ktime_get_and_real_and_sleep_offset(ktime_t *monotonic, + ktime_t *real_offset, + ktime_t *sleep_offset) +{ + unsigned long seq; + struct timespec wtom, sleep; + u64 secs, nsecs; + + do { + seq = read_seqbegin(&timekeeper.lock); + + secs = timekeeper.xtime.tv_sec + + timekeeper.wall_to_monotonic.tv_sec; + nsecs = timekeeper.xtime.tv_nsec + + timekeeper.wall_to_monotonic.tv_nsec; + nsecs += timekeeping_get_ns(); + /* If arch requires, add in gettimeoffset() */ + nsecs += arch_gettimeoffset(); + + wtom = timekeeper.wall_to_monotonic; + sleep = timekeeper.total_sleep_time; + } while (read_seqretry(&timekeeper.lock, seq)); + + + *monotonic = ktime_add_ns(ktime_set(secs, 0), nsecs); + set_normalized_timespec(&wtom, -wtom.tv_sec, -wtom.tv_nsec); + *real_offset = timespec_to_ktime(wtom); + *sleep_offset = timespec_to_ktime(sleep); +} + + + + + /** * ktime_get_monotonic_offset() - get wall_to_monotonic in ktime_t format */