mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'y2038-vfs' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground
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
This commit is contained in:
@@ -69,8 +69,12 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
|
||||
if (v9fs_proto_dotl(v9ses)) {
|
||||
sb->s_op = &v9fs_super_ops_dotl;
|
||||
sb->s_xattr = v9fs_xattr_handlers;
|
||||
} else
|
||||
} else {
|
||||
sb->s_op = &v9fs_super_ops;
|
||||
sb->s_time_max = U32_MAX;
|
||||
}
|
||||
|
||||
sb->s_time_min = 0;
|
||||
|
||||
ret = super_setup_bdi(sb);
|
||||
if (ret)
|
||||
|
||||
@@ -375,7 +375,7 @@ affs_secs_to_datestamp(time64_t secs, struct affs_date *ds)
|
||||
u32 minute;
|
||||
s32 rem;
|
||||
|
||||
secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60);
|
||||
secs -= sys_tz.tz_minuteswest * 60 + AFFS_EPOCH_DELTA;
|
||||
if (secs < 0)
|
||||
secs = 0;
|
||||
days = div_s64_rem(secs, 86400, &rem);
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
|
||||
#define AFFS_ROOT_BMAPS 25
|
||||
|
||||
/* Seconds since Amiga epoch of 1978/01/01 to UNIX */
|
||||
#define AFFS_EPOCH_DELTA ((8 * 365 + 2) * 86400LL)
|
||||
|
||||
struct affs_date {
|
||||
__be32 days;
|
||||
__be32 mins;
|
||||
|
||||
@@ -150,10 +150,10 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
|
||||
}
|
||||
|
||||
inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec
|
||||
= (be32_to_cpu(tail->change.days) * (24 * 60 * 60) +
|
||||
= (be32_to_cpu(tail->change.days) * 86400LL +
|
||||
be32_to_cpu(tail->change.mins) * 60 +
|
||||
be32_to_cpu(tail->change.ticks) / 50 +
|
||||
((8 * 365 + 2) * 24 * 60 * 60)) +
|
||||
AFFS_EPOCH_DELTA) +
|
||||
sys_tz.tz_minuteswest * 60;
|
||||
inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
|
||||
affs_brelse(bh);
|
||||
|
||||
@@ -355,6 +355,10 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sb->s_op = &affs_sops;
|
||||
sb->s_flags |= SB_NODIRATIME;
|
||||
|
||||
sb->s_time_gran = NSEC_PER_SEC;
|
||||
sb->s_time_min = sys_tz.tz_minuteswest * 60 + AFFS_EPOCH_DELTA;
|
||||
sb->s_time_max = 86400LL * U32_MAX + 86400 + sb->s_time_min;
|
||||
|
||||
sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
|
||||
if (!sbi)
|
||||
return -ENOMEM;
|
||||
|
||||
21
fs/attr.c
21
fs/attr.c
@@ -183,15 +183,18 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
|
||||
inode->i_uid = attr->ia_uid;
|
||||
if (ia_valid & ATTR_GID)
|
||||
inode->i_gid = attr->ia_gid;
|
||||
if (ia_valid & ATTR_ATIME)
|
||||
inode->i_atime = timespec64_trunc(attr->ia_atime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_MTIME)
|
||||
inode->i_mtime = timespec64_trunc(attr->ia_mtime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_CTIME)
|
||||
inode->i_ctime = timespec64_trunc(attr->ia_ctime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_ATIME) {
|
||||
inode->i_atime = timestamp_truncate(attr->ia_atime,
|
||||
inode);
|
||||
}
|
||||
if (ia_valid & ATTR_MTIME) {
|
||||
inode->i_mtime = timestamp_truncate(attr->ia_mtime,
|
||||
inode);
|
||||
}
|
||||
if (ia_valid & ATTR_CTIME) {
|
||||
inode->i_ctime = timestamp_truncate(attr->ia_ctime,
|
||||
inode);
|
||||
}
|
||||
if (ia_valid & ATTR_MODE) {
|
||||
umode_t mode = attr->ia_mode;
|
||||
|
||||
|
||||
@@ -893,6 +893,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sb_set_blocksize(sb, (ulong) befs_sb->block_size);
|
||||
sb->s_op = &befs_sops;
|
||||
sb->s_export_op = &befs_export_operations;
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = 0xffffffffffffll;
|
||||
root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
|
||||
if (IS_ERR(root)) {
|
||||
ret = PTR_ERR(root);
|
||||
|
||||
@@ -324,6 +324,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
|
||||
return -ENOMEM;
|
||||
mutex_init(&info->bfs_lock);
|
||||
s->s_fs_info = info;
|
||||
s->s_time_min = 0;
|
||||
s->s_time_max = U32_MAX;
|
||||
|
||||
sb_set_blocksize(s, BFS_BSIZE);
|
||||
|
||||
|
||||
@@ -979,6 +979,8 @@ static int ceph_set_super(struct super_block *s, void *data)
|
||||
s->s_export_op = &ceph_export_ops;
|
||||
|
||||
s->s_time_gran = 1;
|
||||
s->s_time_min = 0;
|
||||
s->s_time_max = U32_MAX;
|
||||
|
||||
ret = set_anon_super(s, NULL); /* what is that second arg for? */
|
||||
if (ret != 0)
|
||||
|
||||
@@ -56,6 +56,15 @@
|
||||
#include "dfs_cache.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DOS dates from 1980/1/1 through 2107/12/31
|
||||
* Protocol specifications indicate the range should be to 119, which
|
||||
* limits maximum year to 2099. But this range has not been checked.
|
||||
*/
|
||||
#define SMB_DATE_MAX (127<<9 | 12<<5 | 31)
|
||||
#define SMB_DATE_MIN (0<<9 | 1<<5 | 1)
|
||||
#define SMB_TIME_MAX (23<<11 | 59<<5 | 29)
|
||||
|
||||
int cifsFYI = 0;
|
||||
bool traceSMB;
|
||||
bool enable_oplocks = true;
|
||||
@@ -142,6 +151,7 @@ cifs_read_super(struct super_block *sb)
|
||||
struct inode *inode;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifs_tcon *tcon;
|
||||
struct timespec64 ts;
|
||||
int rc = 0;
|
||||
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
@@ -161,6 +171,18 @@ cifs_read_super(struct super_block *sb)
|
||||
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
|
||||
sb->s_time_gran = 100;
|
||||
|
||||
if (tcon->unix_ext) {
|
||||
ts = cifs_NTtimeToUnix(0);
|
||||
sb->s_time_min = ts.tv_sec;
|
||||
ts = cifs_NTtimeToUnix(cpu_to_le64(S64_MAX));
|
||||
sb->s_time_max = ts.tv_sec;
|
||||
} else {
|
||||
ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MIN), 0, 0);
|
||||
sb->s_time_min = ts.tv_sec;
|
||||
ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MAX), cpu_to_le16(SMB_TIME_MAX), 0);
|
||||
sb->s_time_max = ts.tv_sec;
|
||||
}
|
||||
|
||||
sb->s_magic = CIFS_MAGIC_NUMBER;
|
||||
sb->s_op = &cifs_super_ops;
|
||||
sb->s_xattr = cifs_xattr_handlers;
|
||||
|
||||
@@ -949,8 +949,8 @@ static const int total_days_of_prev_months[] = {
|
||||
struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
|
||||
{
|
||||
struct timespec64 ts;
|
||||
time64_t sec;
|
||||
int min, days, month, year;
|
||||
time64_t sec, days;
|
||||
int min, day, month, year;
|
||||
u16 date = le16_to_cpu(le_date);
|
||||
u16 time = le16_to_cpu(le_time);
|
||||
SMB_TIME *st = (SMB_TIME *)&time;
|
||||
@@ -966,15 +966,15 @@ struct timespec64 cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset)
|
||||
sec += 60 * 60 * st->Hours;
|
||||
if (st->Hours > 24)
|
||||
cifs_dbg(VFS, "illegal hours %d\n", st->Hours);
|
||||
days = sd->Day;
|
||||
day = sd->Day;
|
||||
month = sd->Month;
|
||||
if (days < 1 || days > 31 || month < 1 || month > 12) {
|
||||
cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, days);
|
||||
days = clamp(days, 1, 31);
|
||||
if (day < 1 || day > 31 || month < 1 || month > 12) {
|
||||
cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, day);
|
||||
day = clamp(day, 1, 31);
|
||||
month = clamp(month, 1, 12);
|
||||
}
|
||||
month -= 1;
|
||||
days += total_days_of_prev_months[month];
|
||||
days = day + total_days_of_prev_months[month];
|
||||
days += 3652; /* account for difference in days between 1980 and 1970 */
|
||||
year = sd->Year;
|
||||
days += year * 365;
|
||||
|
||||
@@ -188,6 +188,9 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sb->s_magic = CODA_SUPER_MAGIC;
|
||||
sb->s_op = &coda_super_operations;
|
||||
sb->s_d_op = &coda_dentry_operations;
|
||||
sb->s_time_gran = 1;
|
||||
sb->s_time_min = S64_MIN;
|
||||
sb->s_time_max = S64_MAX;
|
||||
|
||||
error = super_setup_bdi(sb);
|
||||
if (error)
|
||||
|
||||
@@ -76,14 +76,14 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
|
||||
if (ia_valid & ATTR_GID)
|
||||
sd_iattr->ia_gid = iattr->ia_gid;
|
||||
if (ia_valid & ATTR_ATIME)
|
||||
sd_iattr->ia_atime = timespec64_trunc(iattr->ia_atime,
|
||||
inode->i_sb->s_time_gran);
|
||||
sd_iattr->ia_atime = timestamp_truncate(iattr->ia_atime,
|
||||
inode);
|
||||
if (ia_valid & ATTR_MTIME)
|
||||
sd_iattr->ia_mtime = timespec64_trunc(iattr->ia_mtime,
|
||||
inode->i_sb->s_time_gran);
|
||||
sd_iattr->ia_mtime = timestamp_truncate(iattr->ia_mtime,
|
||||
inode);
|
||||
if (ia_valid & ATTR_CTIME)
|
||||
sd_iattr->ia_ctime = timespec64_trunc(iattr->ia_ctime,
|
||||
inode->i_sb->s_time_gran);
|
||||
sd_iattr->ia_ctime = timestamp_truncate(iattr->ia_ctime,
|
||||
inode);
|
||||
if (ia_valid & ATTR_MODE) {
|
||||
umode_t mode = iattr->ia_mode;
|
||||
|
||||
|
||||
@@ -597,6 +597,8 @@ static int cramfs_finalize_super(struct super_block *sb,
|
||||
|
||||
/* Set it all up.. */
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = 0;
|
||||
sb->s_op = &cramfs_ops;
|
||||
root = get_cramfs_inode(sb, cramfs_root, 0);
|
||||
if (IS_ERR(root))
|
||||
|
||||
@@ -257,6 +257,8 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
|
||||
if (!sb)
|
||||
return -ENOMEM;
|
||||
s->s_fs_info = sb;
|
||||
s->s_time_min = 0;
|
||||
s->s_time_max = U32_MAX;
|
||||
|
||||
s->s_magic = EFS_SUPER_MAGIC;
|
||||
if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) {
|
||||
|
||||
@@ -1002,6 +1002,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
|
||||
|
||||
sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);
|
||||
sb->s_max_links = EXT2_LINK_MAX;
|
||||
sb->s_time_min = S32_MIN;
|
||||
sb->s_time_max = S32_MAX;
|
||||
|
||||
if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
|
||||
sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
|
||||
|
||||
@@ -832,11 +832,13 @@ static inline void ext4_decode_extra_time(struct timespec64 *time,
|
||||
|
||||
#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \
|
||||
do { \
|
||||
(raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
|
||||
if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) {\
|
||||
(raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
|
||||
(raw_inode)->xtime ## _extra = \
|
||||
ext4_encode_extra_time(&(inode)->xtime); \
|
||||
} \
|
||||
else \
|
||||
(raw_inode)->xtime = cpu_to_le32(clamp_t(int32_t, (inode)->xtime.tv_sec, S32_MIN, S32_MAX)); \
|
||||
} while (0)
|
||||
|
||||
#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode) \
|
||||
@@ -1643,6 +1645,10 @@ static inline bool ext4_verity_in_progress(struct inode *inode)
|
||||
|
||||
#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
|
||||
*/
|
||||
|
||||
@@ -4039,8 +4039,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);
|
||||
|
||||
@@ -745,15 +745,18 @@ static void __setattr_copy(struct inode *inode, const struct iattr *attr)
|
||||
inode->i_uid = attr->ia_uid;
|
||||
if (ia_valid & ATTR_GID)
|
||||
inode->i_gid = attr->ia_gid;
|
||||
if (ia_valid & ATTR_ATIME)
|
||||
inode->i_atime = timespec64_trunc(attr->ia_atime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_MTIME)
|
||||
inode->i_mtime = timespec64_trunc(attr->ia_mtime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_CTIME)
|
||||
inode->i_ctime = timespec64_trunc(attr->ia_ctime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_ATIME) {
|
||||
inode->i_atime = timestamp_truncate(attr->ia_atime,
|
||||
inode);
|
||||
}
|
||||
if (ia_valid & ATTR_MTIME) {
|
||||
inode->i_mtime = timestamp_truncate(attr->ia_mtime,
|
||||
inode);
|
||||
}
|
||||
if (ia_valid & ATTR_CTIME) {
|
||||
inode->i_ctime = timestamp_truncate(attr->ia_ctime,
|
||||
inode);
|
||||
}
|
||||
if (ia_valid & ATTR_MODE) {
|
||||
umode_t mode = attr->ia_mode;
|
||||
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
|
||||
#define KB_IN_SECTORS 2
|
||||
|
||||
/* DOS dates from 1980/1/1 through 2107/12/31 */
|
||||
#define FAT_DATE_MIN (0<<9 | 1<<5 | 1)
|
||||
#define FAT_DATE_MAX (127<<9 | 12<<5 | 31)
|
||||
#define FAT_TIME_MAX (23<<11 | 59<<5 | 29)
|
||||
|
||||
/*
|
||||
* A deserialized copy of the on-disk structure laid out in struct
|
||||
* fat_boot_sector.
|
||||
@@ -1605,6 +1610,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
|
||||
int debug;
|
||||
long error;
|
||||
char buf[50];
|
||||
struct timespec64 ts;
|
||||
|
||||
/*
|
||||
* 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,
|
||||
sbi->free_clus_valid = 0;
|
||||
sbi->prev_free = FAT_START_ENT;
|
||||
sb->s_maxbytes = 0xffffffff;
|
||||
fat_time_fat2unix(sbi, &ts, 0, cpu_to_le16(FAT_DATE_MIN), 0);
|
||||
sb->s_time_min = ts.tv_sec;
|
||||
|
||||
fat_time_fat2unix(sbi, &ts, cpu_to_le16(FAT_TIME_MAX),
|
||||
cpu_to_le16(FAT_DATE_MAX), 0);
|
||||
sb->s_time_max = ts.tv_sec;
|
||||
|
||||
if (!sbi->fat_length && bpb.fat32_length) {
|
||||
struct fat_boot_fsinfo *fsinfo;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user