Merge branch 'limits' of https://github.com/deepa-hub/vfs into y2038
The series is an update and a more complete version of the previously posted series at https://lore.kernel.org/linux-fsdevel/20180122020426.2988-1-deepa.kernel@gmail.com/ Thanks to Arnd Bergmann for doing a few preliminary reviews. They helped me fix a few issues I had overlooked. The limits (sometimes granularity also) for the filesystems updated here are according to the following table: File system Time type Start year Expiration year Granularity cramfs fixed 0 0 romfs fixed 0 0 pstore ascii seconds (27 digit ascii) S64_MIN S64_MAX 1 coda INT64 S64_MIN S64_MAX 1 omfs 64-bit milliseconds 0 U64_MAX/ 1000 NSEC_PER_MSEC befs unsigned 48-bit seconds 0 0xffffffffffff alloc_super bfs unsigned 32-bit seconds 0 U32_MAX alloc_super efs unsigned 32-bit seconds 0 U32_MAX alloc_super ext2 signed 32-bit seconds S32_MIN S32_MAX alloc_super ext3 signed 32-bit seconds S32_MIN S32_MAX alloc_super ext4 (old) signed 32-bit seconds S32_MIN S32_MAX alloc_super ext4 (extra) 34-bit seconds, 30-bit ns S32_MIN 0x37fffffff 1 freevxfs u32 secs/usecs 0 U32_MAX alloc_super jffs2 unsigned 32-bit seconds 0 U32_MAX alloc_super jfs unsigned 32-bit seconds/ns 0 U32_MAX 1 minix unsigned 32-bit seconds 0 U32_MAX alloc_super qnx4 unsigned 32-bit seconds 0 U32_MAX alloc_super qnx6 unsigned 32-bit seconds 0 U32_MAX alloc_super reiserfs unsigned 32-bit seconds 0 U32_MAX alloc_super squashfs unsigned 32-bit seconds 0 U32_MAX alloc_super ufs1 signed 32-bit seconds S32_MIN S32_MAX NSEC_PER_SEC ufs2 signed 64-bit seconds/u32 ns S64_MIN S64_MAX 1 xfs signed 32-bit seconds/ns S32_MIN S32_MAX 1 ceph unsigned 32-bit second/ns 0 U32_MAX 1000 sysv unsigned 32-bit seconds 0 U32_MAX alloc_super affs u32 day, min, ticks 1978 u32_max days NSEC_PER_SEC nfsv2 unsigned 32-bit seconds/ns 0 U32_MAX 1 nfsv3 unsigned 32-bit seconds/ns 0 U32_MAX 1000 nfsv4 u64 seconds/u32 ns S64_MIN S64_MAX 1000 isofs u8 year since 1900 (fixable) 1900 2155 alloc_super hpfs unsigned 32-bit seconds 1970 2106 alloc_super fat 7-bit years, 2s resolution 1980 2107 cifs (smb) 7-bit years 1980 2107 cifs (modern) 64-bit 100ns since 1601 1601 30828 9p (9P2000) unsigned 32-bit seconds 1970 2106 9p (9P2000.L) signed 64-bit seconds, ns 1970 S64_MAX Granularity column filled in by the alloc_super() in the above table indicates that the granularity is NSEC_PER_SEC. Note that anything not mentioned above still has the default limits S64_MIN..S64_MAX. The patches in the series are as structured below: 1. Add vfs support to maintain the limits per filesystem. 2. Add a new timestamp_truncate() api for clamping timestamps according to the filesystem limits. 3. Add a warning for mount syscall to indicate the impending expiry of timestamps. 4. Modify utimes to clamp the timestamps. 5. Fill in limits for filesystems. A test for checking file system timestamp limits has been posted at https://www.spinics.net/lists/fstests/msg12262.html Changes since v8: * Dropped orangefs patch because of ongoing discussion * Dropped adfs patch because a conflict with Russell's ADFS series Changes since v7: * Dropped fat modifications from timespec_truncate patch * Leverage timestamp_truncate function in utimes * Added a fix for pstore ramoops timestamps * Added ext4 warning for inodes without room for extended timestamps. * Made mount warning more human readable Changes since v6: * No change in mount behavior because of expiry of timestamps. * Included limits for more filesystems. Changes since v5: * Dropped y2038-specific changes Changes since v4: * Added documentation for boot param Changes since v3: * Remove redundant initializations in libfs.c * Change early_param to __setup similar to other root mount options. * Fix documentation warning Changes since v2: * Introduce early boot param override for checks. * Drop afs patch for timestamp limits. Changes since v1: * return EROFS on mount errors * fix mtime copy/paste error in utimes * 'limits' of https://github.com/deepa-hub/vfs: 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 Link: https://lore.kernel.org/lkml/20190730014924.2193-1-deepa.kernel@gmail.com/ Link: https://lore.kernel.org/lkml/20190830154744.4868-1-deepa.kernel@gmail.com/ Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
9d14545b05
|
@ -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;
|
||||
|
|
|
@ -828,11 +828,15 @@ 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)); \
|
||||
ext4_warning_inode(inode, "inode does not support timestamps beyond 2038"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode) \
|
||||
|
@ -1632,6 +1636,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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -741,15 +741,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;
|
||||
|
|
|
@ -229,6 +229,8 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
|
|||
|
||||
sbp->s_op = &vxfs_super_ops;
|
||||
sbp->s_fs_info = infp;
|
||||
sbp->s_time_min = 0;
|
||||
sbp->s_time_max = U32_MAX;
|
||||
|
||||
if (!vxfs_try_sb_magic(sbp, silent, 1,
|
||||
(__force __fs32)cpu_to_le32(VXFS_SUPER_MAGIC))) {
|
||||
|
|
|
@ -334,7 +334,7 @@ long hpfs_ioctl(struct file *file, unsigned cmd, unsigned long arg);
|
|||
* local time (HPFS) to GMT (Unix)
|
||||
*/
|
||||
|
||||
static inline time64_t local_to_gmt(struct super_block *s, time32_t t)
|
||||
static inline time64_t local_to_gmt(struct super_block *s, time64_t t)
|
||||
{
|
||||
extern struct timezone sys_tz;
|
||||
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)
|
|||
static inline time32_t gmt_to_local(struct super_block *s, time64_t t)
|
||||
{
|
||||
extern struct timezone sys_tz;
|
||||
t = t - sys_tz.tz_minuteswest * 60 - hpfs_sb(s)->sb_timeshift;
|
||||
|
||||
return clamp_t(time64_t, t, 0, U32_MAX);
|
||||
return t - sys_tz.tz_minuteswest * 60 - hpfs_sb(s)->sb_timeshift;
|
||||
}
|
||||
|
||||
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)
|
|||
s->s_magic = HPFS_SUPER_MAGIC;
|
||||
s->s_op = &hpfs_sops;
|
||||
s->s_d_op = &hpfs_dentry_operations;
|
||||
s->s_time_min = local_to_gmt(s, 0);
|
||||
s->s_time_max = local_to_gmt(s, U32_MAX);
|
||||
|
||||
sbi->sb_root = le32_to_cpu(superblock->root);
|
||||
sbi->sb_fs_size = le32_to_cpu(superblock->n_sectors);
|
||||
|
|
33
fs/inode.c
33
fs/inode.c
|
@ -2166,6 +2166,37 @@ struct timespec64 timespec64_trunc(struct timespec64 t, unsigned gran)
|
|||
}
|
||||
EXPORT_SYMBOL(timespec64_trunc);
|
||||
|
||||
/**
|
||||
* timestamp_truncate - Truncate timespec to a granularity
|
||||
* @t: Timespec
|
||||
* @inode: inode being updated
|
||||
*
|
||||
* Truncate a timespec to the granularity supported by the fs
|
||||
* containing the inode. Always rounds down. gran must
|
||||
* not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns).
|
||||
*/
|
||||
struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
unsigned int gran = sb->s_time_gran;
|
||||
|
||||
t.tv_sec = clamp(t.tv_sec, sb->s_time_min, sb->s_time_max);
|
||||
if (unlikely(t.tv_sec == sb->s_time_max || t.tv_sec == sb->s_time_min))
|
||||
t.tv_nsec = 0;
|
||||
|
||||
/* Avoid division in the common cases 1 ns and 1 s. */
|
||||
if (gran == 1)
|
||||
; /* nothing */
|
||||
else if (gran == NSEC_PER_SEC)
|
||||
t.tv_nsec = 0;
|
||||
else if (gran > 1 && gran < NSEC_PER_SEC)
|
||||
t.tv_nsec -= t.tv_nsec % gran;
|
||||
else
|
||||
WARN(1, "invalid file time granularity: %u", gran);
|
||||
return t;
|
||||
}
|
||||
EXPORT_SYMBOL(timestamp_truncate);
|
||||
|
||||
/**
|
||||
* current_time - Return FS time
|
||||
* @inode: inode.
|
||||
|
@ -2187,7 +2218,7 @@ struct timespec64 current_time(struct inode *inode)
|
|||
return now;
|
||||
}
|
||||
|
||||
return timespec64_trunc(now, inode->i_sb->s_time_gran);
|
||||
return timestamp_truncate(now, inode);
|
||||
}
|
||||
EXPORT_SYMBOL(current_time);
|
||||
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include "isofs.h"
|
||||
#include "zisofs.h"
|
||||
|
||||
/* max tz offset is 13 hours */
|
||||
#define MAX_TZ_OFFSET (52*15*60)
|
||||
|
||||
#define BEQUIET
|
||||
|
||||
static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
|
||||
|
@ -801,6 +804,10 @@ root_found:
|
|||
*/
|
||||
s->s_maxbytes = 0x80000000000LL;
|
||||
|
||||
/* ECMA-119 timestamp from 1900/1/1 with tz offset */
|
||||
s->s_time_min = mktime64(1900, 1, 1, 0, 0, 0) - MAX_TZ_OFFSET;
|
||||
s->s_time_max = mktime64(U8_MAX+1900, 12, 31, 23, 59, 59) + MAX_TZ_OFFSET;
|
||||
|
||||
/* Set this for reference. Its not currently used except on write
|
||||
which we don't have .. */
|
||||
|
||||
|
|
|
@ -590,6 +590,9 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
|
|||
sb->s_blocksize = PAGE_SIZE;
|
||||
sb->s_blocksize_bits = PAGE_SHIFT;
|
||||
sb->s_magic = JFFS2_SUPER_MAGIC;
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = U32_MAX;
|
||||
|
||||
if (!sb_rdonly(sb))
|
||||
jffs2_start_garbage_collect_thread(c);
|
||||
return 0;
|
||||
|
|
|
@ -503,6 +503,8 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
|
||||
sb->s_fs_info = sbi;
|
||||
sb->s_max_links = JFS_LINK_MAX;
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = U32_MAX;
|
||||
sbi->sb = sb;
|
||||
sbi->uid = INVALID_UID;
|
||||
sbi->gid = INVALID_GID;
|
||||
|
|
|
@ -158,12 +158,11 @@ static inline void set_default_inode_attr(struct inode *inode, umode_t mode)
|
|||
static inline void set_inode_attr(struct inode *inode,
|
||||
struct kernfs_iattrs *attrs)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
inode->i_uid = attrs->ia_uid;
|
||||
inode->i_gid = attrs->ia_gid;
|
||||
inode->i_atime = timespec64_trunc(attrs->ia_atime, sb->s_time_gran);
|
||||
inode->i_mtime = timespec64_trunc(attrs->ia_mtime, sb->s_time_gran);
|
||||
inode->i_ctime = timespec64_trunc(attrs->ia_ctime, sb->s_time_gran);
|
||||
inode->i_atime = timestamp_truncate(attrs->ia_atime, inode);
|
||||
inode->i_mtime = timestamp_truncate(attrs->ia_mtime, inode);
|
||||
inode->i_ctime = timestamp_truncate(attrs->ia_ctime, inode);
|
||||
}
|
||||
|
||||
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)
|
|||
|
||||
/* set up enough so that it can read an inode */
|
||||
s->s_op = &minix_sops;
|
||||
s->s_time_min = 0;
|
||||
s->s_time_max = U32_MAX;
|
||||
root_inode = minix_iget(s, MINIX_ROOT_INO);
|
||||
if (IS_ERR(root_inode)) {
|
||||
ret = PTR_ERR(root_inode);
|
||||
|
|
|
@ -2463,6 +2463,26 @@ static void set_mount_attributes(struct mount *mnt, unsigned int mnt_flags)
|
|||
unlock_mount_hash();
|
||||
}
|
||||
|
||||
static void mnt_warn_timestamp_expiry(struct path *mountpoint, struct vfsmount *mnt)
|
||||
{
|
||||
struct super_block *sb = mnt->mnt_sb;
|
||||
|
||||
if (!__mnt_is_readonly(mnt) &&
|
||||
(ktime_get_real_seconds() + TIME_UPTIME_SEC_MAX > sb->s_time_max)) {
|
||||
char *buf = (char *)__get_free_page(GFP_KERNEL);
|
||||
char *mntpath = buf ? d_path(mountpoint, buf, PAGE_SIZE) : ERR_PTR(-ENOMEM);
|
||||
struct tm tm;
|
||||
|
||||
time64_to_tm(sb->s_time_max, 0, &tm);
|
||||
|
||||
pr_warn("Mounted %s file system at %s supports timestamps until %04ld (0x%llx)\n",
|
||||
sb->s_type->name, mntpath,
|
||||
tm.tm_year+1900, (unsigned long long)sb->s_time_max);
|
||||
|
||||
free_page((unsigned long)buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle reconfiguration of the mountpoint only without alteration of the
|
||||
* superblock it refers to. This is triggered by specifying MS_REMOUNT|MS_BIND
|
||||
|
@ -2488,6 +2508,9 @@ static int do_reconfigure_mnt(struct path *path, unsigned int mnt_flags)
|
|||
if (ret == 0)
|
||||
set_mount_attributes(mnt, mnt_flags);
|
||||
up_write(&sb->s_umount);
|
||||
|
||||
mnt_warn_timestamp_expiry(path, &mnt->mnt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2528,6 +2551,9 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,
|
|||
}
|
||||
up_write(&sb->s_umount);
|
||||
}
|
||||
|
||||
mnt_warn_timestamp_expiry(path, &mnt->mnt);
|
||||
|
||||
put_fs_context(fc);
|
||||
return err;
|
||||
}
|
||||
|
@ -2736,8 +2762,13 @@ static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint,
|
|||
return PTR_ERR(mnt);
|
||||
|
||||
error = do_add_mount(real_mount(mnt), mountpoint, mnt_flags);
|
||||
if (error < 0)
|
||||
if (error < 0) {
|
||||
mntput(mnt);
|
||||
return error;
|
||||
}
|
||||
|
||||
mnt_warn_timestamp_expiry(mountpoint, mnt);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -2382,6 +2382,15 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
|
|||
sb->s_flags |= SB_POSIXACL;
|
||||
sb->s_time_gran = 1;
|
||||
sb->s_export_op = &nfs_export_ops;
|
||||
} else
|
||||
sb->s_time_gran = 1000;
|
||||
|
||||
if (server->nfs_client->rpc_ops->version != 4) {
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = U32_MAX;
|
||||
} else {
|
||||
sb->s_time_min = S64_MIN;
|
||||
sb->s_time_max = S64_MAX;
|
||||
}
|
||||
|
||||
nfs_initialise_sb(sb);
|
||||
|
@ -2402,7 +2411,6 @@ static void nfs_clone_super(struct super_block *sb,
|
|||
sb->s_maxbytes = old_sb->s_maxbytes;
|
||||
sb->s_xattr = old_sb->s_xattr;
|
||||
sb->s_op = old_sb->s_op;
|
||||
sb->s_time_gran = 1;
|
||||
sb->s_export_op = old_sb->s_export_op;
|
||||
|
||||
if (server->nfs_client->rpc_ops->version != 2) {
|
||||
|
@ -2410,6 +2418,16 @@ static void nfs_clone_super(struct super_block *sb,
|
|||
* so ourselves when necessary.
|
||||
*/
|
||||
sb->s_flags |= SB_POSIXACL;
|
||||
sb->s_time_gran = 1;
|
||||
} else
|
||||
sb->s_time_gran = 1000;
|
||||
|
||||
if (server->nfs_client->rpc_ops->version != 4) {
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = U32_MAX;
|
||||
} else {
|
||||
sb->s_time_min = S64_MIN;
|
||||
sb->s_time_max = S64_MAX;
|
||||
}
|
||||
|
||||
nfs_initialise_sb(sb);
|
||||
|
|
|
@ -2899,15 +2899,18 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
ia_valid |= ATTR_MTIME | ATTR_CTIME;
|
||||
}
|
||||
}
|
||||
if (ia_valid & ATTR_ATIME)
|
||||
vi->i_atime = timespec64_trunc(attr->ia_atime,
|
||||
vi->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_MTIME)
|
||||
vi->i_mtime = timespec64_trunc(attr->ia_mtime,
|
||||
vi->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_CTIME)
|
||||
vi->i_ctime = timespec64_trunc(attr->ia_ctime,
|
||||
vi->i_sb->s_time_gran);
|
||||
if (ia_valid & ATTR_ATIME) {
|
||||
vi->i_atime = timestamp_truncate(attr->ia_atime,
|
||||
vi);
|
||||
}
|
||||
if (ia_valid & ATTR_MTIME) {
|
||||
vi->i_mtime = timestamp_truncate(attr->ia_mtime,
|
||||
vi);
|
||||
}
|
||||
if (ia_valid & ATTR_CTIME) {
|
||||
vi->i_ctime = timestamp_truncate(attr->ia_ctime,
|
||||
vi);
|
||||
}
|
||||
mark_inode_dirty(vi);
|
||||
out:
|
||||
return err;
|
||||
|
|
|
@ -478,6 +478,10 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
|
||||
sb->s_maxbytes = 0xffffffff;
|
||||
|
||||
sb->s_time_gran = NSEC_PER_MSEC;
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = U64_MAX / MSEC_PER_SEC;
|
||||
|
||||
sb_set_blocksize(sb, 0x200);
|
||||
|
||||
bh = sb_bread(sb, 0);
|
||||
|
|
|
@ -144,6 +144,7 @@ static int ramoops_read_kmsg_hdr(char *buffer, struct timespec64 *time,
|
|||
if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lld.%lu-%c\n%n",
|
||||
(time64_t *)&time->tv_sec, &time->tv_nsec, &data_type,
|
||||
&header_length) == 3) {
|
||||
time->tv_nsec *= 1000;
|
||||
if (data_type == 'C')
|
||||
*compressed = true;
|
||||
else
|
||||
|
@ -151,6 +152,7 @@ static int ramoops_read_kmsg_hdr(char *buffer, struct timespec64 *time,
|
|||
} else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lld.%lu\n%n",
|
||||
(time64_t *)&time->tv_sec, &time->tv_nsec,
|
||||
&header_length) == 2) {
|
||||
time->tv_nsec *= 1000;
|
||||
*compressed = false;
|
||||
} else {
|
||||
time->tv_sec = 0;
|
||||
|
|
|
@ -201,6 +201,8 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
|
|||
s->s_op = &qnx4_sops;
|
||||
s->s_magic = QNX4_SUPER_MAGIC;
|
||||
s->s_flags |= SB_RDONLY; /* Yup, read-only yet */
|
||||
s->s_time_min = 0;
|
||||
s->s_time_max = U32_MAX;
|
||||
|
||||
/* Check the superblock signature. Since the qnx4 code is
|
||||
dangerous, we should leave as quickly as possible
|
||||
|
|
|
@ -429,6 +429,8 @@ mmi_success:
|
|||
s->s_op = &qnx6_sops;
|
||||
s->s_magic = QNX6_SUPER_MAGIC;
|
||||
s->s_flags |= SB_RDONLY; /* Yup, read-only yet */
|
||||
s->s_time_min = 0;
|
||||
s->s_time_max = U32_MAX;
|
||||
|
||||
/* ease the later tree level calculations */
|
||||
sbi = QNX6_SB(s);
|
||||
|
|
|
@ -1976,6 +1976,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
|
|||
goto error_unlocked;
|
||||
}
|
||||
|
||||
s->s_time_min = 0;
|
||||
s->s_time_max = U32_MAX;
|
||||
|
||||
rs = SB_DISK_SUPER_BLOCK(s);
|
||||
/*
|
||||
* 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)
|
|||
sb->s_maxbytes = 0xFFFFFFFF;
|
||||
sb->s_magic = ROMFS_MAGIC;
|
||||
sb->s_flags |= SB_RDONLY | SB_NOATIME;
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = 0;
|
||||
sb->s_op = &romfs_super_ops;
|
||||
|
||||
#ifdef CONFIG_ROMFS_ON_MTD
|
||||
|
|
|
@ -183,6 +183,8 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
(u64) le64_to_cpu(sblk->id_table_start));
|
||||
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = U32_MAX;
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
sb->s_op = &squashfs_super_ops;
|
||||
|
||||
|
|
|
@ -257,6 +257,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
|
|||
s->s_maxbytes = MAX_NON_LFS;
|
||||
s->s_op = &default_op;
|
||||
s->s_time_gran = 1000000000;
|
||||
s->s_time_min = TIME64_MIN;
|
||||
s->s_time_max = TIME64_MAX;
|
||||
s->cleancache_poolid = CLEANCACHE_NO_POOL;
|
||||
|
||||
s->s_shrink.seeks = DEFAULT_SEEKS;
|
||||
|
|
|
@ -368,7 +368,8 @@ static int sysv_fill_super(struct super_block *sb, void *data, int silent)
|
|||
sbi->s_block_base = 0;
|
||||
mutex_init(&sbi->s_lock);
|
||||
sb->s_fs_info = sbi;
|
||||
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = U32_MAX;
|
||||
sb_set_blocksize(sb, BLOCK_SIZE);
|
||||
|
||||
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)
|
|||
sbi->s_type = FSTYPE_V7;
|
||||
mutex_init(&sbi->s_lock);
|
||||
sb->s_fs_info = sbi;
|
||||
sb->s_time_min = 0;
|
||||
sb->s_time_max = U32_MAX;
|
||||
|
||||
sb_set_blocksize(sb, 512);
|
||||
|
||||
|
|
|
@ -1078,15 +1078,18 @@ static void do_attr_changes(struct inode *inode, const struct iattr *attr)
|
|||
inode->i_uid = attr->ia_uid;
|
||||
if (attr->ia_valid & ATTR_GID)
|
||||
inode->i_gid = attr->ia_gid;
|
||||
if (attr->ia_valid & ATTR_ATIME)
|
||||
inode->i_atime = timespec64_trunc(attr->ia_atime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (attr->ia_valid & ATTR_MTIME)
|
||||
inode->i_mtime = timespec64_trunc(attr->ia_mtime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (attr->ia_valid & ATTR_CTIME)
|
||||
inode->i_ctime = timespec64_trunc(attr->ia_ctime,
|
||||
inode->i_sb->s_time_gran);
|
||||
if (attr->ia_valid & ATTR_ATIME) {
|
||||
inode->i_atime = timestamp_truncate(attr->ia_atime,
|
||||
inode);
|
||||
}
|
||||
if (attr->ia_valid & ATTR_MTIME) {
|
||||
inode->i_mtime = timestamp_truncate(attr->ia_mtime,
|
||||
inode);
|
||||
}
|
||||
if (attr->ia_valid & ATTR_CTIME) {
|
||||
inode->i_ctime = timestamp_truncate(attr->ia_ctime,
|
||||
inode);
|
||||
}
|
||||
if (attr->ia_valid & ATTR_MODE) {
|
||||
umode_t mode = attr->ia_mode;
|
||||
|
||||
|
|
|
@ -843,6 +843,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
|
||||
sb->s_time_gran = NSEC_PER_SEC;
|
||||
sb->s_time_min = S32_MIN;
|
||||
sb->s_time_max = S32_MAX;
|
||||
|
||||
switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) {
|
||||
case UFS_MOUNT_UFSTYPE_44BSD:
|
||||
UFSD("ufstype=44bsd\n");
|
||||
|
@ -861,6 +865,9 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
uspi->s_fshift = 9;
|
||||
uspi->s_sbsize = super_block_size = 1536;
|
||||
uspi->s_sbbase = 0;
|
||||
sb->s_time_gran = 1;
|
||||
sb->s_time_min = S64_MIN;
|
||||
sb->s_time_max = S64_MAX;
|
||||
flags |= UFS_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
|
||||
break;
|
||||
|
||||
|
|
|
@ -36,16 +36,14 @@ static int utimes_common(const struct path *path, struct timespec64 *times)
|
|||
if (times[0].tv_nsec == UTIME_OMIT)
|
||||
newattrs.ia_valid &= ~ATTR_ATIME;
|
||||
else if (times[0].tv_nsec != UTIME_NOW) {
|
||||
newattrs.ia_atime.tv_sec = times[0].tv_sec;
|
||||
newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
|
||||
newattrs.ia_atime = timestamp_truncate(times[0], inode);
|
||||
newattrs.ia_valid |= ATTR_ATIME_SET;
|
||||
}
|
||||
|
||||
if (times[1].tv_nsec == UTIME_OMIT)
|
||||
newattrs.ia_valid &= ~ATTR_MTIME;
|
||||
else if (times[1].tv_nsec != UTIME_NOW) {
|
||||
newattrs.ia_mtime.tv_sec = times[1].tv_sec;
|
||||
newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
|
||||
newattrs.ia_mtime = timestamp_truncate(times[1], inode);
|
||||
newattrs.ia_valid |= ATTR_MTIME_SET;
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -1663,6 +1663,8 @@ xfs_fs_fill_super(
|
|||
sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits);
|
||||
sb->s_max_links = XFS_MAXLINK;
|
||||
sb->s_time_gran = 1;
|
||||
sb->s_time_min = S32_MIN;
|
||||
sb->s_time_max = S32_MAX;
|
||||
sb->s_iflags |= SB_I_CGROUPWB;
|
||||
|
||||
set_posix_acl_flag(sb);
|
||||
|
|
|
@ -726,6 +726,8 @@ struct inode {
|
|||
void *i_private; /* fs or device private pointer */
|
||||
} __randomize_layout;
|
||||
|
||||
struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode);
|
||||
|
||||
static inline unsigned int i_blocksize(const struct inode *node)
|
||||
{
|
||||
return (1 << node->i_blkbits);
|
||||
|
@ -1448,6 +1450,9 @@ struct super_block {
|
|||
|
||||
/* Granularity of c/m/atime in ns (cannot be worse than a second) */
|
||||
u32 s_time_gran;
|
||||
/* Time limits for c/m/atime in seconds */
|
||||
time64_t s_time_min;
|
||||
time64_t s_time_max;
|
||||
#ifdef CONFIG_FSNOTIFY
|
||||
__u32 s_fsnotify_mask;
|
||||
struct fsnotify_mark_connector __rcu *s_fsnotify_marks;
|
||||
|
|
|
@ -30,6 +30,8 @@ struct itimerspec64 {
|
|||
|
||||
/* Located here for timespec[64]_valid_strict */
|
||||
#define TIME64_MAX ((s64)~((u64)1 << 63))
|
||||
#define TIME64_MIN (-TIME64_MAX - 1)
|
||||
|
||||
#define KTIME_MAX ((s64)~((u64)1 << 63))
|
||||
#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
|
||||
|
||||
|
|
Loading…
Reference in New Issue