From patchwork Thu Jul 19 01:19:13 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 10134 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 D968D23F08 for ; Thu, 19 Jul 2012 01:19:28 +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 935E5A183FC for ; Thu, 19 Jul 2012 01:19:28 +0000 (UTC) Received: by yenq6 with SMTP id q6so2457472yen.11 for ; Wed, 18 Jul 2012 18:19:28 -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=oFWDxE/aQqubUaJlqBRAFtSgo/PWUIkVtYZn46DGw/s=; b=aFDkg8PHzKmMv1tzyDKsvR89a3YUcQfFy2m14dDkFGvG/75Yt9knVobxWRbk38fEsS EQpZzfe2PAoSW31F3zNq2gZ4XLZ19IuKjklBnYEepHolSdUtCHbQT1SJtRcycyxQW7LQ tnj93414HulT3Nx8oiH0XwNrJsxtw4CXVIVJSnT7KZfkdQOy/c2ch6MwKrM1Ni8k9pqu 0sA2GQlsvqF53mBe4DX5G1Ygp0Efs/BxeXIio8THdqT2Y/DbaNVP6gJK/itWI0Znzpwh 6/hxyCTfDBX3/Y/qhiTr11SAW3k7sxfMf/I56Wit24n5NrMBjNOptSsWx+qnRWSGU/8c uMPg== Received: by 10.43.63.140 with SMTP id xe12mr1671466icb.57.1342660767857; Wed, 18 Jul 2012 18:19:27 -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.153.7 with SMTP id i7csp5421ibw; Wed, 18 Jul 2012 18:19:26 -0700 (PDT) Received: by 10.50.156.196 with SMTP id wg4mr3833670igb.54.1342660766524; Wed, 18 Jul 2012 18:19:26 -0700 (PDT) Received: from e38.co.us.ibm.com (e38.co.us.ibm.com. [32.97.110.159]) by mx.google.com with ESMTPS id eg5si681923igc.24.2012.07.18.18.19.26 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 18 Jul 2012 18:19:26 -0700 (PDT) Received-SPF: neutral (google.com: 32.97.110.159 is neither permitted nor denied by best guess record for domain of john.stultz@linaro.org) client-ip=32.97.110.159; Authentication-Results: mx.google.com; spf=neutral (google.com: 32.97.110.159 is neither permitted nor denied by best guess record for domain of john.stultz@linaro.org) smtp.mail=john.stultz@linaro.org Received: from /spool/local by e38.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 18 Jul 2012 19:19:25 -0600 Received: from d03dlp01.boulder.ibm.com (9.17.202.177) by e38.co.us.ibm.com (192.168.1.138) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 18 Jul 2012 19:19:23 -0600 Received: from d03relay04.boulder.ibm.com (d03relay04.boulder.ibm.com [9.17.195.106]) by d03dlp01.boulder.ibm.com (Postfix) with ESMTP id 64A951FF001B; Thu, 19 Jul 2012 01:19:21 +0000 (WET) Received: from d03av05.boulder.ibm.com (d03av05.boulder.ibm.com [9.17.195.85]) by d03relay04.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q6J1JMuA135036; Wed, 18 Jul 2012 19:19:22 -0600 Received: from d03av05.boulder.ibm.com (loopback [127.0.0.1]) by d03av05.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q6J1JMG3016588; Wed, 18 Jul 2012 19:19:22 -0600 Received: from kernel.stglabs.ibm.com (kernel.stglabs.ibm.com [9.114.214.19]) by d03av05.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q6J1JJSZ016530; Wed, 18 Jul 2012 19:19:21 -0600 From: John Stultz To: lkml Cc: John Stultz , Ingo Molnar , Peter Zijlstra , Richard Cochran , Prarit Bhargava , Thomas Gleixner Subject: [PATCH 2/2] time: Cleanup offs_real/wall_to_mono and offs_boot/total_sleep_time updates Date: Wed, 18 Jul 2012 21:19:13 -0400 Message-Id: <1342660753-10382-3-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1342660753-10382-1-git-send-email-john.stultz@linaro.org> References: <1342660753-10382-1-git-send-email-john.stultz@linaro.org> X-Content-Scanned: Fidelis XPS MAILER x-cbid: 12071901-5518-0000-0000-00000624CF9C X-Gm-Message-State: ALoCoQlolajZdPESwAjlkkHSoYqWg879xcbIgDDrZTdPm7de3OfNsntI57Rovozb7pN4B89/xcgd For performance reasons, we maintain ktime_t based duplicates of wall_to_monotonic (offs_real) and total_sleep_time (offs_boot). Since large problems could occur (such as the resume regression on 3.5-rc7, or the leapsecond hrtimer issue) if these value pairs were to be inconsistently updated, this patch this cleans up how we modify these value pairs to ensure we are always consistent. As a side-effect this is also more efficient as we only caulculate the duplicate values when they are changed, rather then every update_wall_time call. This also provides WARN_ONs to detect if future changes break the invariants. Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Richard Cochran Cc: Prarit Bhargava Cc: Thomas Gleixner Signed-off-by: John Stultz --- kernel/time/timekeeping.c | 94 ++++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index f045cc5..0b780bd 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -65,14 +65,14 @@ struct timekeeper { * used instead. */ struct timespec wall_to_monotonic; - /* time spent in suspend */ - struct timespec total_sleep_time; - /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ - struct timespec raw_time; /* Offset clock monotonic -> clock realtime */ ktime_t offs_real; + /* time spent in suspend */ + struct timespec total_sleep_time; /* Offset clock monotonic -> clock boottime */ ktime_t offs_boot; + /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ + struct timespec raw_time; /* Seqlock for all timekeeper values */ seqlock_t lock; }; @@ -117,6 +117,36 @@ static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts) tk->xtime_nsec += ts->tv_nsec << tk->shift; } + +static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) +{ + struct timespec tmp; + + /* + * Verify consistency of: offset_real = -wall_to_monotonic + * before modifying anything + */ + set_normalized_timespec(&tmp, -tk->wall_to_monotonic.tv_sec, + -tk->wall_to_monotonic.tv_nsec); + WARN_ON_ONCE(tk->offs_real.tv64 != timespec_to_ktime(tmp).tv64); + tk->wall_to_monotonic = wtm; + set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec); + tk->offs_real = timespec_to_ktime(tmp); +} + + +static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) +{ + /* Verify consistency before modifying */ + WARN_ON_ONCE(tk->offs_boot.tv64 != + timespec_to_ktime(tk->total_sleep_time).tv64); + + tk->total_sleep_time = t; + tk->offs_boot = timespec_to_ktime(t); +} + + + /** * timekeeper_setup_internals - Set up internals to use clocksource clock. * @@ -217,13 +247,6 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) return nsec + arch_gettimeoffset(); } -static void update_rt_offset(struct timekeeper *tk) -{ - struct timespec tmp, *wtm = &tk->wall_to_monotonic; - - set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec); - tk->offs_real = timespec_to_ktime(tmp); -} /* must hold write on timekeeper.lock */ static void timekeeping_update(struct timekeeper *tk, bool clearntp) @@ -234,7 +257,6 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp) tk->ntp_error = 0; ntp_clear(); } - update_rt_offset(tk); xt = tk_xtime(tk); update_vsyscall(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult); } @@ -420,8 +442,8 @@ int do_settimeofday(const struct timespec *tv) ts_delta.tv_sec = tv->tv_sec - xt.tv_sec; ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec; - timekeeper.wall_to_monotonic = - timespec_sub(timekeeper.wall_to_monotonic, ts_delta); + tk_set_wall_to_mono(&timekeeper, + timespec_sub(timekeeper.wall_to_monotonic, ts_delta)); tk_set_xtime(&timekeeper, tv); @@ -456,8 +478,8 @@ int timekeeping_inject_offset(struct timespec *ts) tk_xtime_add(&timekeeper, ts); - timekeeper.wall_to_monotonic = - timespec_sub(timekeeper.wall_to_monotonic, *ts); + tk_set_wall_to_mono(&timekeeper, + timespec_sub(timekeeper.wall_to_monotonic, *ts)); timekeeping_update(&timekeeper, true); @@ -624,7 +646,7 @@ void __init timekeeping_init(void) { struct clocksource *clock; unsigned long flags; - struct timespec now, boot; + struct timespec now, boot, tmp; read_persistent_clock(&now); read_boot_clock(&boot); @@ -645,23 +667,19 @@ void __init timekeeping_init(void) if (boot.tv_sec == 0 && boot.tv_nsec == 0) boot = tk_xtime(&timekeeper); - set_normalized_timespec(&timekeeper.wall_to_monotonic, - -boot.tv_sec, -boot.tv_nsec); - update_rt_offset(&timekeeper); - timekeeper.total_sleep_time.tv_sec = 0; - timekeeper.total_sleep_time.tv_nsec = 0; + set_normalized_timespec(&tmp, -boot.tv_sec, -boot.tv_nsec); + tk_set_wall_to_mono(&timekeeper, tmp); + + tmp.tv_sec = 0; + tmp.tv_nsec = 0; + tk_set_sleep_time(&timekeeper, tmp); + write_sequnlock_irqrestore(&timekeeper.lock, flags); } /* time in seconds when suspend began */ static struct timespec timekeeping_suspend_time; -static void update_sleep_time(struct timespec t) -{ - timekeeper.total_sleep_time = t; - timekeeper.offs_boot = timespec_to_ktime(t); -} - /** * __timekeeping_inject_sleeptime - Internal function to add sleep interval * @delta: pointer to a timespec delta value @@ -677,10 +695,9 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, "sleep delta value!\n"); return; } - tk_xtime_add(tk, delta); - tk->wall_to_monotonic = timespec_sub(tk->wall_to_monotonic, *delta); - update_sleep_time(timespec_add(tk->total_sleep_time, *delta)); + tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *delta)); + tk_set_sleep_time(tk, timespec_add(tk->total_sleep_time, *delta)); } @@ -1024,11 +1041,18 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk) /* Figure out if its a leap sec and apply if needed */ leap = second_overflow(tk->xtime_sec); - tk->xtime_sec += leap; - tk->wall_to_monotonic.tv_sec -= leap; - if (leap) - clock_was_set_delayed(); + if (unlikely(leap)) { + struct timespec ts; + + tk->xtime_sec += leap; + ts.tv_sec = leap; + ts.tv_nsec = 0; + tk_set_wall_to_mono(tk, + timespec_sub(tk->wall_to_monotonic, ts)); + + clock_was_set_delayed(); + } } }