From patchwork Fri Dec 4 21:57:54 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 57727 Delivered-To: patches@linaro.org Received: by 10.112.155.196 with SMTP id vy4csp817487lbb; Fri, 4 Dec 2015 13:58:00 -0800 (PST) X-Received: by 10.66.227.102 with SMTP id rz6mr24763636pac.4.1449266280655; Fri, 04 Dec 2015 13:58:00 -0800 (PST) Return-Path: Received: from mail-pf0-x235.google.com (mail-pf0-x235.google.com. [2607:f8b0:400e:c00::235]) by mx.google.com with ESMTPS id f2si21808505pfj.59.2015.12.04.13.58.00 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 04 Dec 2015 13:58:00 -0800 (PST) Received-SPF: pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c00::235 as permitted sender) client-ip=2607:f8b0:400e:c00::235; Authentication-Results: mx.google.com; spf=pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c00::235 as permitted sender) smtp.mailfrom=john.stultz@linaro.org; dkim=pass header.i=@linaro-org.20150623.gappssmtp.com Received: by pfdd184 with SMTP id d184so32111838pfd.3 for ; Fri, 04 Dec 2015 13:58:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=E8OOkWkNoJEuIYSbEffWEQmSlxTjArrIfHn69pn20iE=; b=sbJOo8Tmj6L3XDDDVaPneICMkLzZOJ3a5FBBhbSmp+oV1HAFGSEAHkBRa65P/BNMhS lTrOPUR6uD3jqokf330t1q28qVAn9q/4VZB2z9+DSVQigLtAB7h3DgjJKaAGU6bsGCPu jBiTuf2EFtrw/siM/kS9s3jEZ47BgPcKMMF/XxBiw87/WicQtjHuRRAZQrDmEAGzuu/k nSn1zoCyW0Z8OX8R33CBxuFIoSzy2uGI7TgXjQ21I8jmDTT15a6poxnAMOj4IQm+gPvT w9gdzQUtD5vlX07JmxkaxQ7UlEkQajYyBwaBXxCJyVS3NHf859VKbXqYUiOml+iniPfI n+FQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=E8OOkWkNoJEuIYSbEffWEQmSlxTjArrIfHn69pn20iE=; b=TMLxZGLxGrKbC7lTDnlwho4Xger+39j3WoAJ4mDI6OycA7yik4dJr0vUuHld7MZXBn uLVGeRdesd5QjP5ZXDfkcdd24WlFS/bhezWyiwxD5o4efTqqbJQz3QpaqarTkHrx3kWP jLp2jBsf6QzLykyNN6M/bg9vxi2khDlitFNTnyT0neNPUdXk9n5bfKPxY1pe2WIZk2l8 ieasbo5fYUriq2/HOTfXSm7rDhfiYgK6FCu+yDo+sWGGUOvYkG8jtJQz+9nlB9NnUCTD yirgpAUNiAUYcZT9VGR0a7H69U269/TXhq685pvqumFmV7eQOO+eqNkDhvHDuDZForb+ jjLQ== X-Gm-Message-State: ALoCoQlJmkexTnEhJCF9EjlX/XN6ORhvHrNFXMl9McbNApGzGfrBXtRJf/N8Xh5FC0zRutmrMTfL X-Received: by 10.98.71.138 with SMTP id p10mr24985035pfi.61.1449266280225; Fri, 04 Dec 2015 13:58:00 -0800 (PST) Return-Path: Received: from localhost.localdomain (c-76-115-103-22.hsd1.or.comcast.net. [76.115.103.22]) by smtp.gmail.com with ESMTPSA id 24sm19061807pfr.27.2015.12.04.13.57.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 04 Dec 2015 13:57:59 -0800 (PST) From: John Stultz To: linux-kernel@vger.kernel.org Cc: John Stultz , Miroslav Lichvar , Thomas Gleixner , Richard Cochran , Prarit Bhargava , Andy Lutomirski Subject: [RFC][PATCH] timekeeping: Cap adjustments so they don't exceede the maxadj value Date: Fri, 4 Dec 2015 13:57:54 -0800 Message-Id: <1449266274-26517-1-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.9.1 Thus its been occasionally noted that users have seen confusing warnings like: Adjusting tsc more than 11% (5941981 vs 7759439) We try to limit the maximum total adjustment to 11% (10% tick adjustment + 0.5% frequency adjustment). But this is done by bounding the requested adjustment values, and the internal steering that is done by tracking the error from what was requested and what was applied, does not have any such limits. This is usually not problematic, but in some cases has a risk that an adjustment could cause the clocksource mult value to overflow, so its an indication things are outside of what is expected. It ends up most of the reports of this 11% warning are on systems using chrony, which utilizes the adjtimex() ADJ_TICK interface (which allows a +-10% adjustment). The original ratonal for ADJ_TICK unlcear to me but my assumption it was originally added to allow broken systems to get a big constant correction at boot (see adjtimex userspace package for an example) which would allow the system to work w/ ntpd's 0.5% adjustment limit. Chrony uses ADJ_TICK to make very aggressive short term corrections (usually right at startup). Which push us close enough to the max bound that a few late ticks can cause the internal steering to push past the max adjust value (tripping the warning). Thus this patch adds some extra logic to enforce the max adjustment cap in the internal steering. Note: This has the potential to slow corrections when the ADJ_TICK value is furthest away from the default value. So it would be good to get some testing from folks using Chrony, to make sure we don't cause any troubles there. Cc: Miroslav Lichvar Cc: Thomas Gleixner Cc: Richard Cochran Cc: Prarit Bhargava Cc: Andy Lutomirski Reported-by: Andy Lutomirski Signed-off-by: John Stultz --- kernel/time/timekeeping.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) -- 1.9.1 diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 6cdf92e..8a5c06d 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1593,7 +1593,7 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk, s64 xinterval = tk->xtime_interval; s64 tick_error; bool negative; - u32 adj; + u32 adj_scale; /* Remove any current error adj from freq calculation */ if (tk->ntp_err_mult) @@ -1612,13 +1612,30 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk, /* preserve the direction of correction */ negative = (tick_error < 0); - /* Sort out the magnitude of the correction */ + /* + * Sort out the magnitude of the correction, but + * avoid making so large a correction that we go + * over the max adjustment. + */ + adj_scale = 0; tick_error = abs(tick_error); - for (adj = 0; tick_error > interval; adj++) + while (tick_error > interval) { + u32 base = tk->tkr_mono.clock->mult; + u32 max = tk->tkr_mono.clock->maxadj; + u32 cur_adj = tk->tkr_mono.mult; + u32 adj = 1 << (adj_scale + 1); + + if (negative && (cur_adj - adj) < (base - max)) + break; + if (!negative && (cur_adj + adj) > (base + max)) + break; + + adj_scale++; tick_error >>= 1; + } /* scale the corrections */ - timekeeping_apply_adjustment(tk, offset, negative, adj); + timekeeping_apply_adjustment(tk, offset, negative, adj_scale); } /*