diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-11 16:23:42 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-11 16:23:42 -0700 |
commit | 785d92866ac53e56e3fea0d424dedc037d41d485 (patch) | |
tree | 1acd439aa111c683e58df7c70d7229f6ecede5ee | |
parent | 33d903d86508c82ecd16ddd2034aefc31be92511 (diff) | |
download | longterm-queue-2.6.32-785d92866ac53e56e3fea0d424dedc037d41d485.tar.gz |
.32 patches
-rw-r--r-- | queue-2.6.32/fix-time-inconsistencies-caused-by-intermediate-xtime_cache-values-being-read.patch | 82 | ||||
-rw-r--r-- | queue-2.6.32/series | 1 |
2 files changed, 83 insertions, 0 deletions
diff --git a/queue-2.6.32/fix-time-inconsistencies-caused-by-intermediate-xtime_cache-values-being-read.patch b/queue-2.6.32/fix-time-inconsistencies-caused-by-intermediate-xtime_cache-values-being-read.patch new file mode 100644 index 0000000..8020ff3 --- /dev/null +++ b/queue-2.6.32/fix-time-inconsistencies-caused-by-intermediate-xtime_cache-values-being-read.patch @@ -0,0 +1,82 @@ +From johnstul@us.ibm.com Wed May 11 16:20:57 2011 +From: john stultz <johnstul@us.ibm.com> +Date: Wed, 11 May 2011 16:10:28 -0700 +Subject: Fix time() inconsistencies caused by intermediate xtime_cache values being read +To: stable@kernel.org +Cc: Greg KH <gregkh@suse.de>, Eric Dumazet <eric.dumazet@gmail.com>, sfr@au1.ibm.com, Max Asbock <masbock@linux.vnet.ibm.com>, "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>, Andi Kleen <andi@firstfloor.org> +Message-ID: <1305155428.2680.2.camel@work-vm> + + +Currently with 2.6.32-longterm, its possible for time() to occasionally +return values one second earlier then the previous time() call. + +This happens because update_xtime_cache() does: + xtime_cache = xtime; + timespec_add_ns(&xtime_cache, nsec); + +Its possible that xtime is 1sec,999msecs, and nsecs is 1ms, resulting in +a xtime_cache that is 2sec,0ms. + +get_seconds() (which is used by sys_time()) does not take the +xtime_lock, which is ok as the xtime.tv_sec value is a long and can be +atomically read safely. + +The problem occurs the next call to update_xtime_cache() if xtime has +not increased: + /* This sets xtime_cache back to 1sec, 999msec */ + xtime_cache = xtime; + /* get_seconds, calls here, and sees a 1second inconsistency */ + timespec_add_ns(&xtime_cache, nsec); + + +In order to resolve this, we could add locking to get_seconds(), but it +needs to be lock free, as it is called from the machine check handler, +opening a possible deadlock. + +So instead, this patch introduces an intermediate value for the +calculations, so that we only assign xtime_cache once with the correct +time, using ACCESS_ONCE to make sure the compiler doesn't optimize out +any intermediate values. + +The xtime_cache manipulations were removed with 2.6.35, so that kernel +and later do not need this change. + +In 2.6.33 and 2.6.34 the logarithmic accumulation should make it so +xtime is updated each tick, so it is unlikely that two updates to +xtime_cache could occur while the difference between xtime and +xtime_cache crosses the second boundary. However, the paranoid might +want to pull this into 2.6.33/34-longterm just to be sure. + +Thanks to Stephen for helping finally narrow down the root cause and +many hours of help with testing and validation. Also thanks to Max, +Andi, Eric and Paul for review of earlier attempts and helping clarify +what is possible with regard to out of order execution. + +Acked-by: Eric Dumazet <eric.dumazet@gmail.com> +Signed-off-by: John Stultz <johnstul@us.ibm.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + kernel/time/timekeeping.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -168,8 +168,15 @@ int __read_mostly timekeeping_suspended; + static struct timespec xtime_cache __attribute__ ((aligned (16))); + void update_xtime_cache(u64 nsec) + { +- xtime_cache = xtime; +- timespec_add_ns(&xtime_cache, nsec); ++ /* ++ * Use temporary variable so get_seconds() cannot catch ++ * an intermediate xtime_cache.tv_sec value. ++ * The ACCESS_ONCE() keeps the compiler from optimizing ++ * out the intermediate value. ++ */ ++ struct timespec ts = xtime; ++ timespec_add_ns(&ts, nsec); ++ ACCESS_ONCE(xtime_cache) = ts; + } + + /* must hold xtime_lock */ diff --git a/queue-2.6.32/series b/queue-2.6.32/series index 9db9496..0c61008 100644 --- a/queue-2.6.32/series +++ b/queue-2.6.32/series @@ -2,3 +2,4 @@ cifs-check-for-bytes_remaining-going-to-zero-in-cifs_sesssetup.patch validate-size-of-efi-guid-partition-entries.patch dccp-handle-invalid-feature-options-length.patch cifs-fix-memory-over-bound-bug-in-cifs_parse_mount_options.patch +fix-time-inconsistencies-caused-by-intermediate-xtime_cache-values-being-read.patch |