On Mon, Jul 29, 2019 at 06:49:13PM -0700, Deepa Dinamani wrote:
ext4 has different overflow limits for max filesystem timestamps based on the extra bytes available.
The timestamp limits are calculated according to the encoding table in a4dad1ae24f85i(ext4: Fix handling of extended tv_sec):
- 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
My recollection of ext4 has gotten rusty, so this could be a bogus question:
Say you have a filesystem with s_inode_size > 128 where not all of the ondisk inodes have been upgraded to i_extra_isize > 0 and therefore don't support nanoseconds or times beyond 2038. I think this happens on ext3 filesystems that reserved extra space for inode attrs that are subsequently converted to ext4?
In any case, that means that you have some inodes that support 34-bit tv_sec and some inodes that only support 32-bit tv_sec. For the inodes with 32-bit tv_sec, I think all that happens is that a large timestamp will be truncated further, right?
And no mount time warning because at least /some/ of the inodes are ready to go for the next 30 years?
--D
Note that the time limits are not correct for deletion times.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com Reviewed-by: Andreas Dilger adilger@dilger.ca Cc: tytso@mit.edu Cc: adilger.kernel@dilger.ca Cc: linux-ext4@vger.kernel.org
fs/ext4/ext4.h | 4 ++++ fs/ext4/super.c | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 1cb67859e051..3f13cf12ae7f 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1631,6 +1631,10 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei) #define EXT4_GOOD_OLD_INODE_SIZE 128 +#define EXT4_EXTRA_TIMESTAMP_MAX (((s64)1 << 34) - 1 + S32_MIN) +#define EXT4_NON_EXTRA_TIMESTAMP_MAX S32_MAX +#define EXT4_TIMESTAMP_MIN S32_MIN
/*
- Feature set definitions
*/ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 4079605d437a..3ea2d60f33aa 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4035,8 +4035,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sbi->s_inode_size); goto failed_mount; }
if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE)
sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2);
/*
* i_atime_extra is the last extra field available for [acm]times in
* struct ext4_inode. Checking for that field should suffice to ensure
* we have extra space for all three.
*/
if (sbi->s_inode_size >= offsetof(struct ext4_inode, i_atime_extra) +
sizeof(((struct ext4_inode *)0)->i_atime_extra)) {
sb->s_time_gran = 1;
sb->s_time_max = EXT4_EXTRA_TIMESTAMP_MAX;
} else {
sb->s_time_gran = NSEC_PER_SEC;
sb->s_time_max = EXT4_NON_EXTRA_TIMESTAMP_MAX;
}
}sb->s_time_min = EXT4_TIMESTAMP_MIN;
sbi->s_desc_size = le16_to_cpu(es->s_desc_size); -- 2.17.1