Pull y2038 vfs updates from Arnd Bergmann: "Add inode timestamp clamping. This series from Deepa Dinamani adds a per-superblock minimum/maximum timestamp limit for a file system, and clamps timestamps as they are written, to avoid random behavior from integer overflow as well as having different time stamps on disk vs in memory. At mount time, a warning is now printed for any file system that can represent current timestamps but not future timestamps more than 30 years into the future, similar to the arbitrary 30 year limit that was added to settimeofday(). This was picked as a compromise to warn users to migrate to other file systems (e.g. ext4 instead of ext3) when they need the file system to survive beyond 2038 (or similar limits in other file systems), but not get in the way of normal usage" * tag 'y2038-vfs' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground: ext4: Reduce ext4 timestamp warnings isofs: Initialize filesystem timestamp ranges pstore: fs superblock limits fs: omfs: Initialize filesystem timestamp ranges fs: hpfs: Initialize filesystem timestamp ranges fs: ceph: Initialize filesystem timestamp ranges fs: sysv: Initialize filesystem timestamp ranges fs: affs: Initialize filesystem timestamp ranges fs: fat: Initialize filesystem timestamp ranges fs: cifs: Initialize filesystem timestamp ranges fs: nfs: Initialize filesystem timestamp ranges ext4: Initialize timestamps limits 9p: Fill min and max timestamps in sb fs: Fill in max and min timestamps in superblock utimes: Clamp the timestamps before update mount: Add mount warning for impending timestamp expiry timestamp_truncate: Replace users of timespec64_trunc vfs: Add timestamp_truncate() api vfs: Add file timestamp range support
Unified · Split
| @@ -69,8 +69,12 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, · 68 unmodified lines | ||
| 69 | 69 | if (v9fs_proto_dotl(v9ses)) { |
| 70 | 70 | sb->s_op = &v9fs_super_ops_dotl; |
| 71 | 71 | sb->s_xattr = v9fs_xattr_handlers; |
| 72 | − } else | |
| 72 | + } else { | |
| 73 | 73 | sb->s_op = &v9fs_super_ops; |
| 74 | + sb->s_time_max = U32_MAX; | |
| 75 | + } | |
| 76 | + | |
| 77 | + sb->s_time_min = 0; | |
| 74 | 78 | |
| 75 | 79 | ret = super_setup_bdi(sb); |
| 76 | 80 | if (ret) |
| @@ -375,7 +375,7 @@ affs_secs_to_datestamp(time64_t secs, struct affs_date *ds) · 374 unmodified lines | ||
| 375 | 375 | u32 minute; |
| 376 | 376 | s32 rem; |
| 377 | 377 | |
| 378 | − secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60); | |
| 378 | + secs -= sys_tz.tz_minuteswest * 60 + AFFS_EPOCH_DELTA; | |
| 379 | 379 | if (secs < 0) |
| 380 | 380 | secs = 0; |
| 381 | 381 | days = div_s64_rem(secs, 86400, &rem); |
| @@ -32,6 +32,9 @@ · 31 unmodified lines | ||
| 32 | 32 | |
| 33 | 33 | #define AFFS_ROOT_BMAPS 25 |
| 34 | 34 | |
| 35 | +/* Seconds since Amiga epoch of 1978/01/01 to UNIX */ | |
| 36 | +#define AFFS_EPOCH_DELTA ((8 * 365 + 2) * 86400LL) | |
| 37 | + | |
| 35 | 38 | struct affs_date { |
| 36 | 39 | __be32 days; |
| 37 | 40 | __be32 mins; |
| @@ -150,10 +150,10 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) · 149 unmodified lines | ||
| 150 | 150 | } |
| 151 | 151 | |
| 152 | 152 | inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec |
| 153 | − = (be32_to_cpu(tail->change.days) * (24 * 60 * 60) + | |
| 153 | + = (be32_to_cpu(tail->change.days) * 86400LL + | |
| 154 | 154 | be32_to_cpu(tail->change.mins) * 60 + |
| 155 | 155 | be32_to_cpu(tail->change.ticks) / 50 + |
| 156 | − ((8 * 365 + 2) * 24 * 60 * 60)) + | |
| 156 | + AFFS_EPOCH_DELTA) + | |
| 157 | 157 | sys_tz.tz_minuteswest * 60; |
| 158 | 158 | inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0; |
| 159 | 159 | affs_brelse(bh); |
| @@ -355,6 +355,10 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) · 354 unmodified lines | ||
| 355 | 355 | sb->s_op = &affs_sops; |
| 356 | 356 | sb->s_flags |= SB_NODIRATIME; |
| 357 | 357 | |
| 358 | + sb->s_time_gran = NSEC_PER_SEC; | |
| 359 | + sb->s_time_min = sys_tz.tz_minuteswest * 60 + AFFS_EPOCH_DELTA; | |
| 360 | + sb->s_time_max = 86400LL * U32_MAX + 86400 + sb->s_time_min; | |
| 361 | + | |
| 358 | 362 | sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL); |
| 359 | 363 | if (!sbi) |
| 360 | 364 | return -ENOMEM; |
| @@ -183,15 +183,18 @@ void setattr_copy(struct inode *inode, const struct iattr *attr) · 182 unmodified lines | ||
| 183 | 183 | inode->i_uid = attr->ia_uid; |
| 184 | 184 | if (ia_valid & ATTR_GID) |
| 185 | 185 | inode->i_gid = attr->ia_gid; |
| 186 | − if (ia_valid & ATTR_ATIME) | |
| 187 | − inode->i_atime = timespec64_trunc(attr->ia_atime, | |
| 188 | − inode->i_sb->s_time_gran); | |
| 189 | − if (ia_valid & ATTR_MTIME) | |
| 190 | − inode->i_mtime = timespec64_trunc(attr->ia_mtime, | |
| 191 | − inode->i_sb->s_time_gran); | |
| 192 | − if (ia_valid & ATTR_CTIME) | |
| 193 | − inode->i_ctime = timespec64_trunc(attr->ia_ctime, | |
| 194 | − inode->i_sb->s_time_gran); | |
| 186 | + if (ia_valid & ATTR_ATIME) { | |
| 187 | + inode->i_atime = timestamp_truncate(attr->ia_atime, | |
| 188 | + inode); | |
| 189 | + } | |
| 190 | + if (ia_valid & ATTR_MTIME) { | |
| 191 | + inode->i_mtime = timestamp_truncate(attr->ia_mtime, | |
| 192 | + inode); | |
| 193 | + } | |
| 194 | + if (ia_valid & ATTR_CTIME) { | |
| 195 | + inode->i_ctime = timestamp_truncate(attr->ia_ctime, | |
| 196 | + inode); | |
| 197 | + } | |
| 195 | 198 | if (ia_valid & ATTR_MODE) { |
| 196 | 199 | umode_t mode = attr->ia_mode; |
| 197 | 200 | |
| @@ -893,6 +893,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent) · 892 unmodified lines | ||
| 893 | 893 | sb_set_blocksize(sb, (ulong) befs_sb->block_size); |
| 894 | 894 | sb->s_op = &befs_sops; |
| 895 | 895 | sb->s_export_op = &befs_export_operations; |
| 896 | + sb->s_time_min = 0; | |
| 897 | + sb->s_time_max = 0xffffffffffffll; | |
| 896 | 898 | root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir))); |
| 897 | 899 | if (IS_ERR(root)) { |
| 898 | 900 | ret = PTR_ERR(root); |
| @@ -324,6 +324,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) · 323 unmodified lines | ||
| 324 | 324 | return -ENOMEM; |
| 325 | 325 | mutex_init(&info->bfs_lock); |
| 326 | 326 | s->s_fs_info = info; |
| 327 | + s->s_time_min = 0; | |
| 328 | + s->s_time_max = U32_MAX; | |
| 327 | 329 | |
| 328 | 330 | sb_set_blocksize(s, BFS_BSIZE); |
| 329 | 331 | |
| @@ -979,6 +979,8 @@ static int ceph_set_super(struct super_block *s, void *data) · 978 unmodified lines | ||
| 979 | 979 | s->s_export_op = &ceph_export_ops; |
| 980 | 980 | |
| 981 | 981 | s->s_time_gran = 1; |
| 982 | + s->s_time_min = 0; | |
| 983 | + s->s_time_max = U32_MAX; | |
| 982 | 984 | |
| 983 | 985 | ret = set_anon_super(s, NULL); /* what is that second arg for? */ |
| 984 | 986 | if (ret != 0) |
| @@ -56,6 +56,15 @@ · 55 unmodified lines | ||
| 56 | 56 | #include "dfs_cache.h" |
| 57 | 57 | #endif |
| 58 | 58 | |
| 59 | +/* | |
| 60 | + * DOS dates from 1980/1/1 through 2107/12/31 | |
| 61 | + * Protocol specifications indicate the range should be to 119, which | |
| 62 | + * limits maximum year to 2099. But this range has not been checked. | |
| 63 | + */ | |
| 64 | +#define SMB_DATE_MAX (127<<9 | 12<<5 | 31) | |
| 65 | +#define SMB_DATE_MIN (0<<9 | 1<<5 | 1) | |
| 66 | +#define SMB_TIME_MAX (23<<11 | 59<<5 | 29) | |
| 67 | + | |
| 59 | 68 | int cifsFYI = 0; |
| 60 | 69 | bool traceSMB; |
| 61 | 70 | bool enable_oplocks = true; |
| @@ -142,6 +151,7 @@ cifs_read_super(struct super_block *sb) · 80 unmodified lines | ||
| 142 | 151 | struct inode *inode; |
| 143 | 152 | struct cifs_sb_info *cifs_sb; |
| 144 | 153 | struct cifs_tcon *tcon; |
| 154 | + struct timespec64 ts; | |
| 145 | 155 | int rc = 0; |
| 146 | 156 | |
| 147 | 157 | cifs_sb = CIFS_SB(sb); |
| @@ -161,6 +171,18 @@ cifs_read_super(struct super_block *sb) · 13 unmodified lines | ||
| 161 | 171 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
| 162 | 172 | sb->s_time_gran = 100; |
| 163 | 173 | |
| 174 | + if (tcon->unix_ext) { | |
| 175 | + ts = cifs_NTtimeToUnix(0); | |
| 176 | + sb->s_time_min = ts.tv_sec; | |
| 177 | + ts = cifs_NTtimeToUnix(cpu_to_le64(S64_MAX)); | |
| 178 | + sb->s_time_max = ts.tv_sec; | |
| 179 | + } else { | |
| 180 | + ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MIN), 0, 0); | |
| 181 | + sb->s_time_min = ts.tv_sec; | |
| 182 | + ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MAX), cpu_to_le16(SMB_TIME_MAX), 0); | |
| 183 | + sb->s_time_max = ts.tv_sec; | |
| 184 | + } | |
| 185 | + | |
| 164 | 186 | sb->s_magic = CIFS_MAGIC_NUMBER; |
| 165 | 187 | sb->s_op = &cifs_super_ops; |
| 166 | 188 | sb->s_xattr = cifs_xattr_handlers; |
| @@ -949,8 +949,8 @@ static const int total_days_of_prev_months[] = { · 948 unmodified lines | ||
| 949 | 949 | struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) |
| 950 | 950 | { |
| 951 | 951 | struct timespec64 ts; |
| 952 | − time64_t sec; | |
| 953 | − int min, days, month, year; | |
| 952 | + time64_t sec, days; | |
| 953 | + int min, day, month, year; | |
| 954 | 954 | u16 date = le16_to_cpu(le_date); |
| 955 | 955 | u16 time = le16_to_cpu(le_time); |
| 956 | 956 | SMB_TIME *st = (SMB_TIME *)&time; |
| @@ -966,15 +966,15 @@ struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) · 9 unmodified lines | ||
| 966 | 966 | sec += 60 * 60 * st->Hours; |
| 967 | 967 | if (st->Hours > 24) |
| 968 | 968 | cifs_dbg(VFS, "illegal hours %d\n", st->Hours); |
| 969 | − days = sd->Day; | |
| 969 | + day = sd->Day; | |
| 970 | 970 | month = sd->Month; |
| 971 | − if (days < 1 || days > 31 || month < 1 || month > 12) { | |
| 972 | − cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, days); | |
| 973 | − days = clamp(days, 1, 31); | |
| 971 | + if (day < 1 || day > 31 || month < 1 || month > 12) { | |
| 972 | + cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, day); | |
| 973 | + day = clamp(day, 1, 31); | |
| 974 | 974 | month = clamp(month, 1, 12); |
| 975 | 975 | } |
| 976 | 976 | month -= 1; |
| 977 | − days += total_days_of_prev_months[month]; | |
| 977 | + days = day + total_days_of_prev_months[month]; | |
| 978 | 978 | days += 3652; /* account for difference in days between 1980 and 1970 */ |
| 979 | 979 | year = sd->Year; |
| 980 | 980 | days += year * 365; |
| @@ -188,6 +188,9 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent) · 187 unmodified lines | ||
| 188 | 188 | sb->s_magic = CODA_SUPER_MAGIC; |
| 189 | 189 | sb->s_op = &coda_super_operations; |
| 190 | 190 | sb->s_d_op = &coda_dentry_operations; |
| 191 | + sb->s_time_gran = 1; | |
| 192 | + sb->s_time_min = S64_MIN; | |
| 193 | + sb->s_time_max = S64_MAX; | |
| 191 | 194 | |
| 192 | 195 | error = super_setup_bdi(sb); |
| 193 | 196 | if (error) |
| @@ -76,14 +76,14 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr) · 75 unmodified lines | ||
| 76 | 76 | if (ia_valid & ATTR_GID) |
| 77 | 77 | sd_iattr->ia_gid = iattr->ia_gid; |
| 78 | 78 | if (ia_valid & ATTR_ATIME) |
| 79 | − sd_iattr->ia_atime = timespec64_trunc(iattr->ia_atime, | |
| 80 | − inode->i_sb->s_time_gran); | |
| 79 | + sd_iattr->ia_atime = timestamp_truncate(iattr->ia_atime, | |
| 80 | + inode); | |
| 81 | 81 | if (ia_valid & ATTR_MTIME) |
| 82 | − sd_iattr->ia_mtime = timespec64_trunc(iattr->ia_mtime, | |
| 83 | − inode->i_sb->s_time_gran); | |
| 82 | + sd_iattr->ia_mtime = timestamp_truncate(iattr->ia_mtime, | |
| 83 | + inode); | |
| 84 | 84 | if (ia_valid & ATTR_CTIME) |
| 85 | − sd_iattr->ia_ctime = timespec64_trunc(iattr->ia_ctime, | |
| 86 | − inode->i_sb->s_time_gran); | |
| 85 | + sd_iattr->ia_ctime = timestamp_truncate(iattr->ia_ctime, | |
| 86 | + inode); | |
| 87 | 87 | if (ia_valid & ATTR_MODE) { |
| 88 | 88 | umode_t mode = iattr->ia_mode; |
| 89 | 89 | |
| @@ -597,6 +597,8 @@ static int cramfs_finalize_super(struct super_block *sb, · 596 unmodified lines | ||
| 597 | 597 | |
| 598 | 598 | /* Set it all up.. */ |
| 599 | 599 | sb->s_flags |= SB_RDONLY; |
| 600 | + sb->s_time_min = 0; | |
| 601 | + sb->s_time_max = 0; | |
| 600 | 602 | sb->s_op = &cramfs_ops; |
| 601 | 603 | root = get_cramfs_inode(sb, cramfs_root, 0); |
| 602 | 604 | if (IS_ERR(root)) |
| @@ -257,6 +257,8 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) · 256 unmodified lines | ||
| 257 | 257 | if (!sb) |
| 258 | 258 | return -ENOMEM; |
| 259 | 259 | s->s_fs_info = sb; |
| 260 | + s->s_time_min = 0; | |
| 261 | + s->s_time_max = U32_MAX; | |
| 260 | 262 | |
| 261 | 263 | s->s_magic = EFS_SUPER_MAGIC; |
| 262 | 264 | if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) { |
| @@ -1002,6 +1002,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) · 1001 unmodified lines | ||
| 1002 | 1002 | |
| 1003 | 1003 | sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); |
| 1004 | 1004 | sb->s_max_links = EXT2_LINK_MAX; |
| 1005 | + sb->s_time_min = S32_MIN; | |
| 1006 | + sb->s_time_max = S32_MAX; | |
| 1005 | 1007 | |
| 1006 | 1008 | if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { |
| 1007 | 1009 | sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; |
| @@ -832,11 +832,13 @@ static inline void ext4_decode_extra_time(struct timespec64 *time, · 831 unmodified lines | ||
| 832 | 832 | |
| 833 | 833 | #define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \ |
| 834 | 834 | do { \ |
| 835 | − (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \ | |
| 836 | 835 | if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) {\ |
| 836 | + (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \ | |
| 837 | 837 | (raw_inode)->xtime ## _extra = \ |
| 838 | 838 | ext4_encode_extra_time(&(inode)->xtime); \ |
| 839 | 839 | } \ |
| 840 | + else \ | |
| 841 | + (raw_inode)->xtime = cpu_to_le32(clamp_t(int32_t, (inode)->xtime.tv_sec, S32_MIN, S32_MAX)); \ | |
| 840 | 842 | } while (0) |
| 841 | 843 | |
| 842 | 844 | #define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode) \ |
| @@ -1643,6 +1645,10 @@ static inline bool ext4_verity_in_progress(struct inode *inode) · 800 unmodified lines | ||
| 1643 | 1645 | |
| 1644 | 1646 | #define EXT4_GOOD_OLD_INODE_SIZE 128 |
| 1645 | 1647 | |
| 1648 | +#define EXT4_EXTRA_TIMESTAMP_MAX (((s64)1 << 34) - 1 + S32_MIN) | |
| 1649 | +#define EXT4_NON_EXTRA_TIMESTAMP_MAX S32_MAX | |
| 1650 | +#define EXT4_TIMESTAMP_MIN S32_MIN | |
| 1651 | + | |
| 1646 | 1652 | /* |
| 1647 | 1653 | * Feature set definitions |
| 1648 | 1654 | */ |
| @@ -4039,8 +4039,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) · 4038 unmodified lines | ||
| 4039 | 4039 | sbi->s_inode_size); |
| 4040 | 4040 | goto failed_mount; |
| 4041 | 4041 | } |
| 4042 | − if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) | |
| 4043 | − sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2); | |
| 4042 | + /* | |
| 4043 | + * i_atime_extra is the last extra field available for [acm]times in | |
| 4044 | + * struct ext4_inode. Checking for that field should suffice to ensure | |
| 4045 | + * we have extra space for all three. | |
| 4046 | + */ | |
| 4047 | + if (sbi->s_inode_size >= offsetof(struct ext4_inode, i_atime_extra) + | |
| 4048 | + sizeof(((struct ext4_inode *)0)->i_atime_extra)) { | |
| 4049 | + sb->s_time_gran = 1; | |
| 4050 | + sb->s_time_max = EXT4_EXTRA_TIMESTAMP_MAX; | |
| 4051 | + } else { | |
| 4052 | + sb->s_time_gran = NSEC_PER_SEC; | |
| 4053 | + sb->s_time_max = EXT4_NON_EXTRA_TIMESTAMP_MAX; | |
| 4054 | + } | |
| 4055 | + | |
| 4056 | + sb->s_time_min = EXT4_TIMESTAMP_MIN; | |
| 4044 | 4057 | } |
| 4045 | 4058 | |
| 4046 | 4059 | sbi->s_desc_size = le16_to_cpu(es->s_desc_size); |
| @@ -745,15 +745,18 @@ static void __setattr_copy(struct inode *inode, const struct iattr *attr) · 744 unmodified lines | ||
| 745 | 745 | inode->i_uid = attr->ia_uid; |
| 746 | 746 | if (ia_valid & ATTR_GID) |
| 747 | 747 | inode->i_gid = attr->ia_gid; |
| 748 | − if (ia_valid & ATTR_ATIME) | |
| 749 | − inode->i_atime = timespec64_trunc(attr->ia_atime, | |
| 750 | − inode->i_sb->s_time_gran); | |
| 751 | − if (ia_valid & ATTR_MTIME) | |
| 752 | − inode->i_mtime = timespec64_trunc(attr->ia_mtime, | |
| 753 | − inode->i_sb->s_time_gran); | |
| 754 | − if (ia_valid & ATTR_CTIME) | |
| 755 | − inode->i_ctime = timespec64_trunc(attr->ia_ctime, | |
| 756 | − inode->i_sb->s_time_gran); | |
| 748 | + if (ia_valid & ATTR_ATIME) { | |
| 749 | + inode->i_atime = timestamp_truncate(attr->ia_atime, | |
| 750 | + inode); | |
| 751 | + } | |
| 752 | + if (ia_valid & ATTR_MTIME) { | |
| 753 | + inode->i_mtime = timestamp_truncate(attr->ia_mtime, | |
| 754 | + inode); | |
| 755 | + } | |
| 756 | + if (ia_valid & ATTR_CTIME) { | |
| 757 | + inode->i_ctime = timestamp_truncate(attr->ia_ctime, | |
| 758 | + inode); | |
| 759 | + } | |
| 757 | 760 | if (ia_valid & ATTR_MODE) { |
| 758 | 761 | umode_t mode = attr->ia_mode; |
| 759 | 762 | |
| @@ -31,6 +31,11 @@ · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | #define KB_IN_SECTORS 2 |
| 33 | 33 | |
| 34 | +/* DOS dates from 1980/1/1 through 2107/12/31 */ | |
| 35 | +#define FAT_DATE_MIN (0<<9 | 1<<5 | 1) | |
| 36 | +#define FAT_DATE_MAX (127<<9 | 12<<5 | 31) | |
| 37 | +#define FAT_TIME_MAX (23<<11 | 59<<5 | 29) | |
| 38 | + | |
| 34 | 39 | /* |
| 35 | 40 | * A deserialized copy of the on-disk structure laid out in struct |
| 36 | 41 | * fat_boot_sector. |
| @@ -1605,6 +1610,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, · 1568 unmodified lines | ||
| 1605 | 1610 | int debug; |
| 1606 | 1611 | long error; |
| 1607 | 1612 | char buf[50]; |
| 1613 | + struct timespec64 ts; | |
| 1608 | 1614 | |
| 1609 | 1615 | /* |
| 1610 | 1616 | * GFP_KERNEL is ok here, because while we do hold the |
| @@ -1698,6 +1704,12 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, · 87 unmodified lines | ||
| 1698 | 1704 | sbi->free_clus_valid = 0; |
| 1699 | 1705 | sbi->prev_free = FAT_START_ENT; |
| 1700 | 1706 | sb->s_maxbytes = 0xffffffff; |
| 1707 | + fat_time_fat2unix(sbi, &ts, 0, cpu_to_le16(FAT_DATE_MIN), 0); | |
| 1708 | + sb->s_time_min = ts.tv_sec; | |
| 1709 | + | |
| 1710 | + fat_time_fat2unix(sbi, &ts, cpu_to_le16(FAT_TIME_MAX), | |
| 1711 | + cpu_to_le16(FAT_DATE_MAX), 0); | |
| 1712 | + sb->s_time_max = ts.tv_sec; | |
| 1701 | 1713 | |
| 1702 | 1714 | if (!sbi->fat_length && bpb.fat32_length) { |
| 1703 | 1715 | struct fat_boot_fsinfo *fsinfo; |
| @@ -229,6 +229,8 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent) · 228 unmodified lines | ||
| 229 | 229 | |
| 230 | 230 | sbp->s_op = &vxfs_super_ops; |
| 231 | 231 | sbp->s_fs_info = infp; |
| 232 | + sbp->s_time_min = 0; | |
| 233 | + sbp->s_time_max = U32_MAX; | |
| 232 | 234 | |
| 233 | 235 | if (!vxfs_try_sb_magic(sbp, silent, 1, |
| 234 | 236 | (__force __fs32)cpu_to_le32(VXFS_SUPER_MAGIC))) { |
| @@ -334,7 +334,7 @@ long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg); · 333 unmodified lines | ||
| 334 | 334 | * local time (HPFS) to GMT (Unix) |
| 335 | 335 | */ |
| 336 | 336 | |
| 337 | −static inline time64_t local_to_gmt(struct super_block *s, time32_t t) | |
| 337 | +static inline time64_t local_to_gmt(struct super_block *s, time64_t t) | |
| 338 | 338 | { |
| 339 | 339 | extern struct timezone sys_tz; |
| 340 | 340 | return t + sys_tz.tz_minuteswest * 60 + hpfs_sb(s)->sb_timeshift; |
| @@ -343,9 +343,7 @@ static inline time64_t local_to_gmt(struct super_block *s, time32_t t) · 2 unmodified lines | ||
| 343 | 343 | static inline time32_t gmt_to_local(struct super_block *s, time64_t t) |
| 344 | 344 | { |
| 345 | 345 | extern struct timezone sys_tz; |
| 346 | − t = t - sys_tz.tz_minuteswest * 60 - hpfs_sb(s)->sb_timeshift; | |
| 347 | − | |
| 348 | − return clamp_t(time64_t, t, 0, U32_MAX); | |
| 346 | + return t - sys_tz.tz_minuteswest * 60 - hpfs_sb(s)->sb_timeshift; | |
| 349 | 347 | } |
| 350 | 348 | |
| 351 | 349 | static inline time32_t local_get_seconds(struct super_block *s) |
| @@ -614,6 +614,8 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) · 613 unmodified lines | ||
| 614 | 614 | s->s_magic = HPFS_SUPER_MAGIC; |
| 615 | 615 | s->s_op = &hpfs_sops; |
| 616 | 616 | s->s_d_op = &hpfs_dentry_operations; |
| 617 | + s->s_time_min = local_to_gmt(s, 0); | |
| 618 | + s->s_time_max = local_to_gmt(s, U32_MAX); | |
| 617 | 619 | |
| 618 | 620 | sbi->sb_root = le32_to_cpu(superblock->root); |
| 619 | 621 | sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors); |
| @@ -2166,6 +2166,37 @@ struct timespec64 timespec64_trunc(struct timespec64 t, unsigned gran) · 2165 unmodified lines | ||
| 2166 | 2166 | } |
| 2167 | 2167 | EXPORT_SYMBOL(timespec64_trunc); |
| 2168 | 2168 | |
| 2169 | +/** | |
| 2170 | + * timestamp_truncate - Truncate timespec to a granularity | |
| 2171 | + * @t: Timespec | |
| 2172 | + * @inode: inode being updated | |
| 2173 | + * | |
| 2174 | + * Truncate a timespec to the granularity supported by the fs | |
| 2175 | + * containing the inode. Always rounds down. gran must | |
| 2176 | + * not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns). | |
| 2177 | + */ | |
| 2178 | +struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode) | |
| 2179 | +{ | |
| 2180 | + struct super_block *sb = inode->i_sb; | |
| 2181 | + unsigned int gran = sb->s_time_gran; | |
| 2182 | + | |
| 2183 | + t.tv_sec = clamp(t.tv_sec, sb->s_time_min, sb->s_time_max); | |
| 2184 | + if (unlikely(t.tv_sec == sb->s_time_max || t.tv_sec == sb->s_time_min)) | |
| 2185 | + t.tv_nsec = 0; | |
| 2186 | + | |
| 2187 | + /* Avoid division in the common cases 1 ns and 1 s. */ | |
| 2188 | + if (gran == 1) | |
| 2189 | + ; /* nothing */ | |
| 2190 | + else if (gran == NSEC_PER_SEC) | |
| 2191 | + t.tv_nsec = 0; | |
| 2192 | + else if (gran > 1 && gran < NSEC_PER_SEC) | |
| 2193 | + t.tv_nsec -= t.tv_nsec % gran; | |
| 2194 | + else | |
| 2195 | + WARN(1, "invalid file time granularity: %u", gran); | |
| 2196 | + return t; | |
| 2197 | +} | |
| 2198 | +EXPORT_SYMBOL(timestamp_truncate); | |
| 2199 | + | |
| 2169 | 2200 | /** |
| 2170 | 2201 | * current_time - Return FS time |
| 2171 | 2202 | * @inode: inode. |
| @@ -2187,7 +2218,7 @@ struct timespec64 current_time(struct inode *inode) · 15 unmodified lines | ||
| 2187 | 2218 | return now; |
| 2188 | 2219 | } |
| 2189 | 2220 | |
| 2190 | − return timespec64_trunc(now, inode->i_sb->s_time_gran); | |
| 2221 | + return timestamp_truncate(now, inode); | |
| 2191 | 2222 | } |
| 2192 | 2223 | EXPORT_SYMBOL(current_time); |
| 2193 | 2224 | |
| @@ -30,6 +30,9 @@ · 29 unmodified lines | ||
| 30 | 30 | #include "isofs.h" |
| 31 | 31 | #include "zisofs.h" |
| 32 | 32 | |
| 33 | +/* max tz offset is 13 hours */ | |
| 34 | +#define MAX_TZ_OFFSET (52*15*60) | |
| 35 | + | |
| 33 | 36 | #define BEQUIET |
| 34 | 37 | |
| 35 | 38 | static int isofs_hashi(const struct dentry *parent, struct qstr *qstr); |
| @@ -801,6 +804,10 @@ root_found: · 765 unmodified lines | ||
| 801 | 804 | */ |
| 802 | 805 | s->s_maxbytes = 0x80000000000LL; |
| 803 | 806 | |
| 807 | + /* ECMA-119 timestamp from 1900/1/1 with tz offset */ | |
| 808 | + s->s_time_min = mktime64(1900, 1, 1, 0, 0, 0) - MAX_TZ_OFFSET; | |
| 809 | + s->s_time_max = mktime64(U8_MAX+1900, 12, 31, 23, 59, 59) + MAX_TZ_OFFSET; | |
| 810 | + | |
| 804 | 811 | /* Set this for reference. Its not currently used except on write |
| 805 | 812 | which we don't have .. */ |
| 806 | 813 | |
| @@ -590,6 +590,9 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) · 589 unmodified lines | ||
| 590 | 590 | sb->s_blocksize = PAGE_SIZE; |
| 591 | 591 | sb->s_blocksize_bits = PAGE_SHIFT; |
| 592 | 592 | sb->s_magic = JFFS2_SUPER_MAGIC; |
| 593 | + sb->s_time_min = 0; | |
| 594 | + sb->s_time_max = U32_MAX; | |
| 595 | + | |
| 593 | 596 | if (!sb_rdonly(sb)) |
| 594 | 597 | jffs2_start_garbage_collect_thread(c); |
| 595 | 598 | return 0; |
| @@ -503,6 +503,8 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) · 502 unmodified lines | ||
| 503 | 503 | |
| 504 | 504 | sb->s_fs_info = sbi; |
| 505 | 505 | sb->s_max_links = JFS_LINK_MAX; |
| 506 | + sb->s_time_min = 0; | |
| 507 | + sb->s_time_max = U32_MAX; | |
| 506 | 508 | sbi->sb = sb; |
| 507 | 509 | sbi->uid = INVALID_UID; |
| 508 | 510 | sbi->gid = INVALID_GID; |
| @@ -158,12 +158,11 @@ static inline void set_default_inode_attr(struct inode *inode, umode_t mode) · 157 unmodified lines | ||
| 158 | 158 | static inline void set_inode_attr(struct inode *inode, |
| 159 | 159 | struct kernfs_iattrs *attrs) |
| 160 | 160 | { |
| 161 | − struct super_block *sb = inode->i_sb; | |
| 162 | 161 | inode->i_uid = attrs->ia_uid; |
| 163 | 162 | inode->i_gid = attrs->ia_gid; |
| 164 | − inode->i_atime = timespec64_trunc(attrs->ia_atime, sb->s_time_gran); | |
| 165 | − inode->i_mtime = timespec64_trunc(attrs->ia_mtime, sb->s_time_gran); | |
| 166 | − inode->i_ctime = timespec64_trunc(attrs->ia_ctime, sb->s_time_gran); | |
| 163 | + inode->i_atime = timestamp_truncate(attrs->ia_atime, inode); | |
| 164 | + inode->i_mtime = timestamp_truncate(attrs->ia_mtime, inode); | |
| 165 | + inode->i_ctime = timestamp_truncate(attrs->ia_ctime, inode); | |
| 167 | 166 | } |
| 168 | 167 | |
| 169 | 168 | static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) |
| @@ -277,6 +277,8 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) · 276 unmodified lines | ||
| 277 | 277 | |
| 278 | 278 | /* set up enough so that it can read an inode */ |
| 279 | 279 | s->s_op = &minix_sops; |
| 280 | + s->s_time_min = 0; | |
| 281 | + s->s_time_max = U32_MAX; | |
| 280 | 282 | root_inode = minix_iget(s, MINIX_ROOT_INO); |
| 281 | 283 | if (IS_ERR(root_inode)) { |
| 282 | 284 | ret = PTR_ERR(root_inode); |
| @@ -2466,6 +2466,26 @@ static void set_mount_attributes(struct mount *mnt, unsigned int mnt_flags) · 2465 unmodified lines | ||
| 2466 | 2466 | unlock_mount_hash(); |
| 2467 | 2467 | } |
| 2468 | 2468 | |
| 2469 | +static void mnt_warn_timestamp_expiry(struct path *mountpoint, struct vfsmount *mnt) | |
| 2470 | +{ | |
| 2471 | + struct super_block *sb = mnt->mnt_sb; | |
| 2472 | + | |
| 2473 | + if (!__mnt_is_readonly(mnt) && | |
| 2474 | + (ktime_get_real_seconds() + TIME_UPTIME_SEC_MAX > sb->s_time_max)) { | |
| 2475 | + char *buf = (char *)__get_free_page(GFP_KERNEL); | |
| 2476 | + char *mntpath = buf ? d_path(mountpoint, buf, PAGE_SIZE) : ERR_PTR(-ENOMEM); | |
| 2477 | + struct tm tm; | |
| 2478 | + | |
| 2479 | + time64_to_tm(sb->s_time_max, 0, &tm); | |
| 2480 | + | |
| 2481 | + pr_warn("Mounted %s file system at %s supports timestamps until %04ld (0x%llx)\n", | |
| 2482 | + sb->s_type->name, mntpath, | |
| 2483 | + tm.tm_year+1900, (unsigned long long)sb->s_time_max); | |
| 2484 | + | |
| 2485 | + free_page((unsigned long)buf); | |
| 2486 | + } | |
| 2487 | +} | |
| 2488 | + | |
| 2469 | 2489 | /* |
| 2470 | 2490 | * Handle reconfiguration of the mountpoint only without alteration of the |
| 2471 | 2491 | * superblock it refers to. This is triggered by specifying MS_REMOUNT|MS_BIND |
| @@ -2491,6 +2511,9 @@ static int do_reconfigure_mnt(struct path *path, unsigned int mnt_flags) · 19 unmodified lines | ||
| 2491 | 2511 | if (ret == 0) |
| 2492 | 2512 | set_mount_attributes(mnt, mnt_flags); |
| 2493 | 2513 | up_write(&sb->s_umount); |
| 2514 | + | |
| 2515 | + mnt_warn_timestamp_expiry(path, &mnt->mnt); | |
| 2516 | + | |
| 2494 | 2517 | return ret; |
| 2495 | 2518 | } |
| 2496 | 2519 | |
| @@ -2531,6 +2554,9 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags, · 34 unmodified lines | ||
| 2531 | 2554 | } |
| 2532 | 2555 | up_write(&sb->s_umount); |
| 2533 | 2556 | } |
| 2557 | + | |
| 2558 | + mnt_warn_timestamp_expiry(path, &mnt->mnt); | |
| 2559 | + | |
| 2534 | 2560 | put_fs_context(fc); |
| 2535 | 2561 | return err; |
| 2536 | 2562 | } |
| @@ -2739,8 +2765,13 @@ static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint, · 202 unmodified lines | ||
| 2739 | 2765 | return PTR_ERR(mnt); |
| 2740 | 2766 | |
| 2741 | 2767 | error = do_add_mount(real_mount(mnt), mountpoint, mnt_flags); |
| 2742 | − if (error < 0) | |
| 2768 | + if (error < 0) { | |
| 2743 | 2769 | mntput(mnt); |
| 2770 | + return error; | |
| 2771 | + } | |
| 2772 | + | |
| 2773 | + mnt_warn_timestamp_expiry(mountpoint, mnt); | |
| 2774 | + | |
| 2744 | 2775 | return error; |
| 2745 | 2776 | } |
| 2746 | 2777 | |
| @@ -2382,6 +2382,15 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) · 2381 unmodified lines | ||
| 2382 | 2382 | sb->s_flags |= SB_POSIXACL; |
| 2383 | 2383 | sb->s_time_gran = 1; |
| 2384 | 2384 | sb->s_export_op = &nfs_export_ops; |
| 2385 | + } else | |
| 2386 | + sb->s_time_gran = 1000; | |
| 2387 | + | |
| 2388 | + if (server->nfs_client->rpc_ops->version != 4) { | |
| 2389 | + sb->s_time_min = 0; | |
| 2390 | + sb->s_time_max = U32_MAX; | |
| 2391 | + } else { | |
| 2392 | + sb->s_time_min = S64_MIN; | |
| 2393 | + sb->s_time_max = S64_MAX; | |
| 2385 | 2394 | } |
| 2386 | 2395 | |
| 2387 | 2396 | nfs_initialise_sb(sb); |
| @@ -2402,7 +2411,6 @@ static void nfs_clone_super(struct super_block *sb, · 14 unmodified lines | ||
| 2402 | 2411 | sb->s_maxbytes = old_sb->s_maxbytes; |
| 2403 | 2412 | sb->s_xattr = old_sb->s_xattr; |
| 2404 | 2413 | sb->s_op = old_sb->s_op; |
| 2405 | − sb->s_time_gran = 1; | |
| 2406 | 2414 | sb->s_export_op = old_sb->s_export_op; |
| 2407 | 2415 | |
| 2408 | 2416 | if (server->nfs_client->rpc_ops->version != 2) { |
| @@ -2410,6 +2418,16 @@ static void nfs_clone_super(struct super_block *sb, · 1 unmodified line | ||
| 2410 | 2418 | * so ourselves when necessary. |
| 2411 | 2419 | */ |
| 2412 | 2420 | sb->s_flags |= SB_POSIXACL; |
| 2421 | + sb->s_time_gran = 1; | |
| 2422 | + } else | |
| 2423 | + sb->s_time_gran = 1000; | |
| 2424 | + | |
| 2425 | + if (server->nfs_client->rpc_ops->version != 4) { | |
| 2426 | + sb->s_time_min = 0; | |
| 2427 | + sb->s_time_max = U32_MAX; | |
| 2428 | + } else { | |
| 2429 | + sb->s_time_min = S64_MIN; | |
| 2430 | + sb->s_time_max = S64_MAX; | |
| 2413 | 2431 | } |
| 2414 | 2432 | |
| 2415 | 2433 | nfs_initialise_sb(sb); |
| @@ -2899,15 +2899,18 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) · 2898 unmodified lines | ||
| 2899 | 2899 | ia_valid |= ATTR_MTIME | ATTR_CTIME; |
| 2900 | 2900 | } |
| 2901 | 2901 | } |
| 2902 | − if (ia_valid & ATTR_ATIME) | |
| 2903 | − vi->i_atime = timespec64_trunc(attr->ia_atime, | |
| 2904 | − vi->i_sb->s_time_gran); | |
| 2905 | − if (ia_valid & ATTR_MTIME) | |
| 2906 | − vi->i_mtime = timespec64_trunc(attr->ia_mtime, | |
| 2907 | − vi->i_sb->s_time_gran); | |
| 2908 | − if (ia_valid & ATTR_CTIME) | |
| 2909 | − vi->i_ctime = timespec64_trunc(attr->ia_ctime, | |
| 2910 | − vi->i_sb->s_time_gran); | |
| 2902 | + if (ia_valid & ATTR_ATIME) { | |
| 2903 | + vi->i_atime = timestamp_truncate(attr->ia_atime, | |
| 2904 | + vi); | |
| 2905 | + } | |
| 2906 | + if (ia_valid & ATTR_MTIME) { | |
| 2907 | + vi->i_mtime = timestamp_truncate(attr->ia_mtime, | |
| 2908 | + vi); | |
| 2909 | + } | |
| 2910 | + if (ia_valid & ATTR_CTIME) { | |
| 2911 | + vi->i_ctime = timestamp_truncate(attr->ia_ctime, | |
| 2912 | + vi); | |
| 2913 | + } | |
| 2911 | 2914 | mark_inode_dirty(vi); |
| 2912 | 2915 | out: |
| 2913 | 2916 | return err; |
| @@ -478,6 +478,10 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) · 477 unmodified lines | ||
| 478 | 478 | |
| 479 | 479 | sb->s_maxbytes = 0xffffffff; |
| 480 | 480 | |
| 481 | + sb->s_time_gran = NSEC_PER_MSEC; | |
| 482 | + sb->s_time_min = 0; | |
| 483 | + sb->s_time_max = U64_MAX / MSEC_PER_SEC; | |
| 484 | + | |
| 481 | 485 | sb_set_blocksize(sb, 0x200); |
| 482 | 486 | |
| 483 | 487 | bh = sb_bread(sb, 0); |
| @@ -144,6 +144,7 @@ static int ramoops_read_kmsg_hdr(char *buffer, struct timespec64 *time, · 143 unmodified lines | ||
| 144 | 144 | if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lld.%lu-%c\n%n", |
| 145 | 145 | (time64_t *)&time->tv_sec, &time->tv_nsec, &data_type, |
| 146 | 146 | &header_length) == 3) { |
| 147 | + time->tv_nsec *= 1000; | |
| 147 | 148 | if (data_type == 'C') |
| 148 | 149 | *compressed = true; |
| 149 | 150 | else |
| @@ -151,6 +152,7 @@ static int ramoops_read_kmsg_hdr(char *buffer, struct timespec64 *time, · 1 unmodified line | ||
| 151 | 152 | } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lld.%lu\n%n", |
| 152 | 153 | (time64_t *)&time->tv_sec, &time->tv_nsec, |
| 153 | 154 | &header_length) == 2) { |
| 155 | + time->tv_nsec *= 1000; | |
| 154 | 156 | *compressed = false; |
| 155 | 157 | } else { |
| 156 | 158 | time->tv_sec = 0; |
| @@ -201,6 +201,8 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) · 200 unmodified lines | ||
| 201 | 201 | s->s_op = &qnx4_sops; |
| 202 | 202 | s->s_magic = QNX4_SUPER_MAGIC; |
| 203 | 203 | s->s_flags |= SB_RDONLY; /* Yup, read-only yet */ |
| 204 | + s->s_time_min = 0; | |
| 205 | + s->s_time_max = U32_MAX; | |
| 204 | 206 | |
| 205 | 207 | /* Check the superblock signature. Since the qnx4 code is |
| 206 | 208 | dangerous, we should leave as quickly as possible |
| @@ -429,6 +429,8 @@ mmi_success: · 428 unmodified lines | ||
| 429 | 429 | s->s_op = &qnx6_sops; |
| 430 | 430 | s->s_magic = QNX6_SUPER_MAGIC; |
| 431 | 431 | s->s_flags |= SB_RDONLY; /* Yup, read-only yet */ |
| 432 | + s->s_time_min = 0; | |
| 433 | + s->s_time_max = U32_MAX; | |
| 432 | 434 | |
| 433 | 435 | /* ease the later tree level calculations */ |
| 434 | 436 | sbi = QNX6_SB(s); |
| @@ -1976,6 +1976,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) · 1975 unmodified lines | ||
| 1976 | 1976 | goto error_unlocked; |
| 1977 | 1977 | } |
| 1978 | 1978 | |
| 1979 | + s->s_time_min = 0; | |
| 1980 | + s->s_time_max = U32_MAX; | |
| 1981 | + | |
| 1979 | 1982 | rs = SB_DISK_SUPER_BLOCK(s); |
| 1980 | 1983 | /* |
| 1981 | 1984 | * Let's do basic sanity check to verify that underlying device is not |
| @@ -478,6 +478,8 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent) · 477 unmodified lines | ||
| 478 | 478 | sb->s_maxbytes = 0xFFFFFFFF; |
| 479 | 479 | sb->s_magic = ROMFS_MAGIC; |
| 480 | 480 | sb->s_flags |= SB_RDONLY | SB_NOATIME; |
| 481 | + sb->s_time_min = 0; | |
| 482 | + sb->s_time_max = 0; | |
| 481 | 483 | sb->s_op = &romfs_super_ops; |
| 482 | 484 | |
| 483 | 485 | #ifdef CONFIG_ROMFS_ON_MTD |
| @@ -183,6 +183,8 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) · 182 unmodified lines | ||
| 183 | 183 | (u64) le64_to_cpu(sblk->id_table_start)); |
| 184 | 184 | |
| 185 | 185 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
| 186 | + sb->s_time_min = 0; | |
| 187 | + sb->s_time_max = U32_MAX; | |
| 186 | 188 | sb->s_flags |= SB_RDONLY; |
| 187 | 189 | sb->s_op = &squashfs_super_ops; |
| 188 | 190 | |
| @@ -258,6 +258,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, · 257 unmodified lines | ||
| 258 | 258 | s->s_maxbytes = MAX_NON_LFS; |
| 259 | 259 | s->s_op = &default_op; |
| 260 | 260 | s->s_time_gran = 1000000000; |
| 261 | + s->s_time_min = TIME64_MIN; | |
| 262 | + s->s_time_max = TIME64_MAX; | |
| 261 | 263 | s->cleancache_poolid = CLEANCACHE_NO_POOL; |
| 262 | 264 | |
| 263 | 265 | s->s_shrink.seeks = DEFAULT_SEEKS; |
| @@ -368,7 +368,8 @@ static int sysv_fill_super(struct super_block *sb, void *data, int silent) · 367 unmodified lines | ||
| 368 | 368 | sbi->s_block_base = 0; |
| 369 | 369 | mutex_init(&sbi->s_lock); |
| 370 | 370 | sb->s_fs_info = sbi; |
| 371 | − | |
| 371 | + sb->s_time_min = 0; | |
| 372 | + sb->s_time_max = U32_MAX; | |
| 372 | 373 | sb_set_blocksize(sb, BLOCK_SIZE); |
| 373 | 374 | |
| 374 | 375 | for (i = 0; i < ARRAY_SIZE(flavours) && !size; i++) { |
| @@ -487,6 +488,8 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent) · 112 unmodified lines | ||
| 487 | 488 | sbi->s_type = FSTYPE_V7; |
| 488 | 489 | mutex_init(&sbi->s_lock); |
| 489 | 490 | sb->s_fs_info = sbi; |
| 491 | + sb->s_time_min = 0; | |
| 492 | + sb->s_time_max = U32_MAX; | |
| 490 | 493 | |
| 491 | 494 | sb_set_blocksize(sb, 512); |
| 492 | 495 | |
| @@ -1078,15 +1078,18 @@ static void do_attr_changes(struct inode *inode, const struct iattr *attr) · 1077 unmodified lines | ||
| 1078 | 1078 | inode->i_uid = attr->ia_uid; |
| 1079 | 1079 | if (attr->ia_valid & ATTR_GID) |
| 1080 | 1080 | inode->i_gid = attr->ia_gid; |
| 1081 | − if (attr->ia_valid & ATTR_ATIME) | |
| 1082 | − inode->i_atime = timespec64_trunc(attr->ia_atime, | |
| 1083 | − inode->i_sb->s_time_gran); | |
| 1084 | − if (attr->ia_valid & ATTR_MTIME) | |
| 1085 | − inode->i_mtime = timespec64_trunc(attr->ia_mtime, | |
| 1086 | − inode->i_sb->s_time_gran); | |
| 1087 | − if (attr->ia_valid & ATTR_CTIME) | |
| 1088 | − inode->i_ctime = timespec64_trunc(attr->ia_ctime, | |
| 1089 | − inode->i_sb->s_time_gran); | |
| 1081 | + if (attr->ia_valid & ATTR_ATIME) { | |
| 1082 | + inode->i_atime = timestamp_truncate(attr->ia_atime, | |
| 1083 | + inode); | |
| 1084 | + } | |
| 1085 | + if (attr->ia_valid & ATTR_MTIME) { | |
| 1086 | + inode->i_mtime = timestamp_truncate(attr->ia_mtime, | |
| 1087 | + inode); | |
| 1088 | + } | |
| 1089 | + if (attr->ia_valid & ATTR_CTIME) { | |
| 1090 | + inode->i_ctime = timestamp_truncate(attr->ia_ctime, | |
| 1091 | + inode); | |
| 1092 | + } | |
| 1090 | 1093 | if (attr->ia_valid & ATTR_MODE) { |
| 1091 | 1094 | umode_t mode = attr->ia_mode; |
| 1092 | 1095 | |
| @@ -843,6 +843,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) · 842 unmodified lines | ||
| 843 | 843 | |
| 844 | 844 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
| 845 | 845 | |
| 846 | + sb->s_time_gran = NSEC_PER_SEC; | |
| 847 | + sb->s_time_min = S32_MIN; | |
| 848 | + sb->s_time_max = S32_MAX; | |
| 849 | + | |
| 846 | 850 | switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) { |
| 847 | 851 | case UFS_MOUNT_UFSTYPE_44BSD: |
| 848 | 852 | UFSD("ufstype=44bsd\n"); |
| @@ -861,6 +865,9 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) · 12 unmodified lines | ||
| 861 | 865 | uspi->s_fshift = 9; |
| 862 | 866 | uspi->s_sbsize = super_block_size = 1536; |
| 863 | 867 | uspi->s_sbbase = 0; |
| 868 | + sb->s_time_gran = 1; | |
| 869 | + sb->s_time_min = S64_MIN; | |
| 870 | + sb->s_time_max = S64_MAX; | |
| 864 | 871 | flags |= UFS_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; |
| 865 | 872 | break; |
| 866 | 873 | |
| @@ -36,16 +36,14 @@ static int utimes_common(const struct path *path, struct timespec64 *times) · 35 unmodified lines | ||
| 36 | 36 | if (times[0].tv_nsec == UTIME_OMIT) |
| 37 | 37 | newattrs.ia_valid &= ~ATTR_ATIME; |
| 38 | 38 | else if (times[0].tv_nsec != UTIME_NOW) { |
| 39 | − newattrs.ia_atime.tv_sec = times[0].tv_sec; | |
| 40 | − newattrs.ia_atime.tv_nsec = times[0].tv_nsec; | |
| 39 | + newattrs.ia_atime = timestamp_truncate(times[0], inode); | |
| 41 | 40 | newattrs.ia_valid |= ATTR_ATIME_SET; |
| 42 | 41 | } |
| 43 | 42 | |
| 44 | 43 | if (times[1].tv_nsec == UTIME_OMIT) |
| 45 | 44 | newattrs.ia_valid &= ~ATTR_MTIME; |
| 46 | 45 | else if (times[1].tv_nsec != UTIME_NOW) { |
| 47 | − newattrs.ia_mtime.tv_sec = times[1].tv_sec; | |
| 48 | − newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; | |
| 46 | + newattrs.ia_mtime = timestamp_truncate(times[1], inode); | |
| 49 | 47 | newattrs.ia_valid |= ATTR_MTIME_SET; |
| 50 | 48 | } |
| 51 | 49 | /* |
| @@ -1664,6 +1664,8 @@ xfs_fs_fill_super( · 1663 unmodified lines | ||
| 1664 | 1664 | sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); |
| 1665 | 1665 | sb->s_max_links = XFS_MAXLINK; |
| 1666 | 1666 | sb->s_time_gran = 1; |
| 1667 | + sb->s_time_min = S32_MIN; | |
| 1668 | + sb->s_time_max = S32_MAX; | |
| 1667 | 1669 | sb->s_iflags |= SB_I_CGROUPWB; |
| 1668 | 1670 | |
| 1669 | 1671 | set_posix_acl_flag(sb); |
| @@ -732,6 +732,8 @@ struct inode { · 731 unmodified lines | ||
| 732 | 732 | void *i_private; /* fs or device private pointer */ |
| 733 | 733 | } __randomize_layout; |
| 734 | 734 | |
| 735 | +struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode); | |
| 736 | + | |
| 735 | 737 | static inline unsigned int i_blocksize(const struct inode *node) |
| 736 | 738 | { |
| 737 | 739 | return (1 << node->i_blkbits); |
| @@ -1458,6 +1460,9 @@ struct super_block { · 720 unmodified lines | ||
| 1458 | 1460 | |
| 1459 | 1461 | /* Granularity of c/m/atime in ns (cannot be worse than a second) */ |
| 1460 | 1462 | u32 s_time_gran; |
| 1463 | + /* Time limits for c/m/atime in seconds */ | |
| 1464 | + time64_t s_time_min; | |
| 1465 | + time64_t s_time_max; | |
| 1461 | 1466 | #ifdef CONFIG_FSNOTIFY |
| 1462 | 1467 | __u32 s_fsnotify_mask; |
| 1463 | 1468 | struct fsnotify_mark_connector __rcu *s_fsnotify_marks; |
| @@ -30,6 +30,8 @@ struct itimerspec64 { · 29 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | /* Located here for timespec[64]_valid_strict */ |
| 32 | 32 | #define TIME64_MAX ((s64)~((u64)1 << 63)) |
| 33 | +#define TIME64_MIN (-TIME64_MAX - 1) | |
| 34 | + | |
| 33 | 35 | #define KTIME_MAX ((s64)~((u64)1 << 63)) |
| 34 | 36 | #define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) |
| 35 | 37 | |