All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Turner <novalis@novalis.org>
To: Andreas Dilger <adilger@dilger.ca>
Cc: "Theodore Ts'o" <tytso@mit.edu>, Mark Harris <mhlk@osj.us>,
	Jan Kara <jack@suse.cz>,
	Ext4 Developers List <linux-ext4@vger.kernel.org>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: [PATCH v5 1/2] ext4: Fix handling of extended tv_sec (bug 23732)
Date: Thu, 14 Nov 2013 03:38:53 -0500	[thread overview]
Message-ID: <1384418333.8994.203.camel@chiang> (raw)
In-Reply-To: <276FA06E-1EE0-4FB4-94E1-B6D9F05F0B5B@dilger.ca>

Thanks for your patient and detailed comments.
--

In ext4, the bottom two bits of {a,c,m}time_extra are used to extend
the {a,c,m}time fields, deferring the year 2038 problem to the year
2446.

When decoding these extended fields, for times whose bottom 32 bits
would represent a negative number, sign extension causes the 64-bit
extended timestamp to be negative as well, which is not what's
intended.  This patch corrects that issue, so that the only negative
{a,c,m}times are those between 1901 and 1970 (as per 32-bit signed
timestamps).

Some older kernels might have written pre-1970 dates with 1,1 in the
extra bits.  This patch treats those incorrectly-encoded dates as
pre-1970, instead of post-2311, until kernel 4.20 is released.
Hopefully by then e2fsck will have fixed up the bad data.

Signed-off-by: David Turner <novalis@novalis.org>
Reported-by: Mark Harris <mh8928@yahoo.com>
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=23732
---
 fs/ext4/ext4.h | 61 +++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 22 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 18aa56b..ac54dac 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -26,6 +26,7 @@
 #include <linux/seqlock.h>
 #include <linux/mutex.h>
 #include <linux/timer.h>
+#include <linux/version.h>
 #include <linux/wait.h>
 #include <linux/blockgroup_lock.h>
 #include <linux/percpu_counter.h>
@@ -713,38 +714,54 @@ struct move_extent {
 	  sizeof((ext4_inode)->field))			\
 	<= (EXT4_GOOD_OLD_INODE_SIZE +			\
 	    (einode)->i_extra_isize))			\
+
 /*
- * We use the bottom 34 bits of the signed 64-bit time value, with
- * the top two of these bits in the bottom of extra.  This leads
- * to a slightly odd encoding, which works like this:
+ * We need is an encoding that preserves the times for extra epoch "00":
  *
- * extra  msb of
- * epoch  32-bit
- * bits   time    decoded 64-bit tv_sec   valid time range
- * 0 0    0    0x000000000..0x07fffffff  1970-01-01..2038-01-19
- * 0 0    1    0x080000000..0x0ffffffff  2038-01-19..2106-02-07
- * 0 1    0    0x100000000..0x17fffffff  2106-02-07..2174-02-25
- * 0 1    1    0x180000000..0x1ffffffff  2174-02-25..2242-03-16
- * 1 0    0    0x200000000..0x27fffffff  2242-03-16..2310-04-04
- * 1 0    1    0x280000000..0x2ffffffff  2310-04-04..2378-04-22
- * 1 1    0    0x300000000..0x37fffffff  2378-04-22..2446-05-10
-
- * 1 1    1    -0x80000000..-0x00000001  1901-12-13..1969-12-31
+ * extra  msb of                         adjust for signed
+ * epoch  32-bit                         32-bit tv_sec to
+ * bits   time    decoded 64-bit tv_sec  64-bit tv_sec      valid time range
+ * 0 0    1    -0x80000000..-0x00000001  0x000000000     1901-12-13..1969-12-31
+ * 0 0    0    0x000000000..0x07fffffff  0x000000000     1970-01-01..2038-01-19
+ * 0 1    1    0x080000000..0x0ffffffff  0x100000000     2038-01-19..2106-02-07
+ * 0 1    0    0x100000000..0x17fffffff  0x100000000     2106-02-07..2174-02-25
+ * 1 0    1    0x180000000..0x1ffffffff  0x200000000     2174-02-25..2242-03-16
+ * 1 0    0    0x200000000..0x27fffffff  0x200000000     2242-03-16..2310-04-04
+ * 1 1    1    0x280000000..0x2ffffffff  0x300000000     2310-04-04..2378-04-22
+ * 1 1    0    0x300000000..0x37fffffff  0x300000000     2378-04-22..2446-05-10
+ *
+ * Note that previous versions of the kernel on 64-bit systems would
+ * incorrectly use extra epoch bits 1,1 for dates between 1901 and
+ * 1970.  e2fsck will correct this, assuming that it is run on the
+ * affected filesystem before 2242.
  */
 
 static inline __le32 ext4_encode_extra_time(struct timespec *time)
 {
-       return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
-			   (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
-                          ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK));
+	u32 extra = sizeof(time->tv_sec) > 4 ?
+		((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0;
+	return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS));
 }
 
 static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
 {
-       if (sizeof(time->tv_sec) > 4)
-	       time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
-			       << 32;
-       time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
+	if (unlikely(sizeof(time->tv_sec) > 4 &&
+			(extra & cpu_to_le32(EXT4_EPOCH_MASK)))) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
+		/* Handle legacy encoding of pre-1970 dates with epoch
+		 * bits 1,1.  We assume that by kernel version 4.20,
+		 * everyone will have run fsck over the affected
+		 * filesystems to correct the problem.
+		 */
+		u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK;
+		if (extra_bits == 3)
+			extra_bits = 0;
+		time->tv_sec += extra_bits << 32;
+#else
+		time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32;
+#endif
+	}
+	time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
 }
 
 #define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)			       \
-- 
1.8.1.2




  reply	other threads:[~2013-11-14  8:39 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-11-07  7:16 [PATCH] ext4: Fix reading of extended tv_sec (bug 23732) David Turner
2013-11-07 16:03 ` Jan Kara
2013-11-07 22:54   ` [PATCH v2] " David Turner
2013-11-07 23:14     ` Jan Kara
2013-11-07 23:26       ` [PATCH v3] " David Turner
2013-11-08  5:17         ` Theodore Ts'o
2013-11-08 21:37         ` Andreas Dilger
2013-11-09  7:19           ` [PATCH] ext4: explain encoding of 34-bit a,c,mtime values David Turner
2013-11-09  7:19             ` David Turner
2013-11-09 23:51             ` Mark Harris
2013-11-09 23:51               ` Mark Harris
2013-11-10  7:56               ` David Turner
2013-11-12  0:30                 ` Theodore Ts'o
2013-11-12 21:35                   ` Andreas Dilger
2013-11-13  7:00                     ` [PATCH v4 1/2] ext4: Fix handling of extended tv_sec (bug 23732) David Turner
2013-11-13  8:19                       ` Darrick J. Wong
2013-11-13  7:00                     ` [PATCH v4 2/2] e2fsck: Correct ext4 dates generated by old kernels David Turner
2013-11-13  7:56                       ` Andreas Dilger
2013-11-14  8:38                         ` David Turner [this message]
2013-11-14  8:44                         ` [PATCH v5 " David Turner
2013-11-14 10:15                           ` Mark Harris
2013-11-14 21:06                             ` [PATCH v6] " David Turner
2013-11-29 21:54                               ` David Turner
2013-11-29 22:11                                 ` Andreas Dilger
2013-12-07 20:02                                   ` [PATCH v7 1/2] " David Turner
2013-12-07 22:33                                     ` Andreas Dilger
2013-12-08  0:53                                     ` Theodore Ts'o
2013-12-08  2:58                                       ` David Turner
2013-12-08  3:21                                         ` Theodore Ts'o
2013-12-07 20:02                                   ` [PATCH v7 2/2] debugfs: Decode {a,c,cr,m}time_extra fields in stat David Turner
2013-11-12 23:03                   ` [PATCH] ext4: explain encoding of 34-bit a,c,mtime values Darrick J. Wong
2013-11-13  2:36                     ` David Turner
2014-01-22  6:22                   ` Darrick J. Wong
2014-02-11  5:12                     ` David Turner
2014-02-11  7:07                       ` Andreas Dilger
2014-02-14  3:47                         ` [PATCH v8 1/2] ext4: Fix handling of extended tv_sec (bug 23732) David Turner
2014-02-14  3:47                         ` [PATCH v8 2/2] e2fsck: Correct ext4 dates generated by old kernels David Turner
2014-02-14  5:40                           ` Andreas Dilger
2014-02-14 22:11                             ` Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1384418333.8994.203.camel@chiang \
    --to=novalis@novalis.org \
    --cc=adilger@dilger.ca \
    --cc=jack@suse.cz \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mhlk@osj.us \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.