vfs: Add support for timestamp limits
Subsystems (31)
v8 cover vfs: Add support for timestamp limits
The series is an update and a more complete version of the previously posted series at
https://lore.kernel.org/linux-fsdevel/[email protected]/
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 orangefs u64 seconds 0 U64_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 adfs 40-bit cs since 1900 1900 2248 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 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
Deepa Dinamani (20):
vfs: Add file timestamp range support
vfs: Add timestamp_truncate() api
timestamp_truncate: Replace users of timespec64_trunc
mount: Add mount warning for impending timestamp expiry
utimes: Clamp the timestamps before update
fs: Fill in max and min timestamps in superblock 9p: Fill min and max timestamps in sb
adfs: Fill in max and min timestamps in sb
ext4: Initialize timestamps limits
fs: nfs: Initialize filesystem timestamp ranges
fs: cifs: Initialize filesystem timestamp ranges
fs: fat: Initialize filesystem timestamp ranges
fs: affs: Initialize filesystem timestamp ranges
fs: sysv: Initialize filesystem timestamp ranges
fs: ceph: Initialize filesystem timestamp ranges
fs: orangefs: Initialize filesystem timestamp ranges
fs: hpfs: Initialize filesystem timestamp ranges
fs: omfs: Initialize filesystem timestamp ranges
pstore: fs superblock limits
isofs: Initialize filesystem timestamp ranges
fs/9p/vfs_super.c | 6 +++++- fs/adfs/adfs.h | 13 +++++++++++++ fs/adfs/inode.c | 8 ++------ fs/adfs/super.c | 2 ++ fs/affs/amigaffs.c | 2 +- fs/affs/amigaffs.h | 3 +++ fs/affs/inode.c | 4 ++-- fs/affs/super.c | 4 ++++ fs/attr.c | 21 ++++++++++++--------- fs/befs/linuxvfs.c | 2 ++ fs/bfs/inode.c | 2 ++ fs/ceph/super.c | 2 ++ fs/cifs/cifsfs.c | 22 ++++++++++++++++++++++ fs/cifs/netmisc.c | 14 +++++++------- fs/coda/inode.c | 3 +++ fs/configfs/inode.c | 12 ++++++------ fs/cramfs/inode.c | 2 ++ fs/efs/super.c | 2 ++ fs/ext2/super.c | 2 ++ fs/ext4/ext4.h | 10 +++++++++- fs/ext4/super.c | 17 +++++++++++++++-- fs/f2fs/file.c | 21 ++++++++++++--------- fs/fat/inode.c | 12 ++++++++++++ fs/freevxfs/vxfs_super.c | 2 ++ fs/hpfs/hpfs_fn.h | 6 ++---- fs/hpfs/super.c | 2 ++ fs/inode.c | 33 ++++++++++++++++++++++++++++++++- fs/isofs/inode.c | 7 +++++++ fs/jffs2/fs.c | 3 +++ fs/jfs/super.c | 2 ++ fs/kernfs/inode.c | 7 +++---- fs/minix/inode.c | 2 ++ fs/namespace.c | 33 ++++++++++++++++++++++++++++++++- fs/nfs/super.c | 20 +++++++++++++++++++- fs/ntfs/inode.c | 21 ++++++++++++--------- fs/omfs/inode.c | 4 ++++ fs/orangefs/super.c | 2 ++ fs/pstore/ram.c | 2 ++ fs/qnx4/inode.c | 2 ++ fs/qnx6/inode.c | 2 ++ fs/reiserfs/super.c | 3 +++ fs/romfs/super.c | 2 ++ fs/squashfs/super.c | 2 ++ fs/super.c | 2 ++ fs/sysv/super.c | 5 ++++- fs/ubifs/file.c | 21 ++++++++++++--------- fs/ufs/super.c | 7 +++++++ fs/utimes.c | 6 ++---- fs/xfs/xfs_super.c | 2 ++ include/linux/fs.h | 5 +++++ include/linux/time64.h | 2 ++ 51 files changed, 315 insertions(+), 78 deletions(-)
Signature · 60 lines
2.17.1 Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected]
PATCH v8 1/20 vfs: Add file timestamp range support
Add fields to the superblock to track the min and max timestamps supported by filesystems.
Initially, when a superblock is allocated, initialize it to the max and min values the fields can hold. Individual filesystems override these to match their actual limits.
Pseudo filesystems are assumed to always support the min and max allowable values for the fields.
--- fs/super.c | 2 ++ include/linux/fs.h | 3 +++ include/linux/time64.h | 2 ++ 3 files changed, 7 insertions(+)
fs/super.c +2 -0
@@ -258,6 +258,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 ;
include/linux/fs.h +3 -0
@@ -1463,6 +1463,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;
include/linux/time64.h +2 -0
@@ -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)
Signature · 1 line
2.17.1
PATCH v8 2/20 vfs: Add timestamp_truncate() api
In reply to Deepa Dinamanitimespec_trunc() function is used to truncate a filesystem timestamp to the right granularity. But, the function does not clamp tv_sec part of the timestamps according to the filesystem timestamp limits.
The replacement api: timestamp_truncate() also alters the signature of the function to accommodate filesystem timestamp clamping according to flesystem limits.
Note that the tv_nsec part is set to 0 if tv_sec is not within the range supported for the filesystem.
--- fs/inode.c | 33 ++++++++++++++++++++++++++++++++- include/linux/fs.h | 2 ++ 2 files changed, 34 insertions(+), 1 deletion(-)
fs/inode.c +32 -1
@@ -2169,6 +2169,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.
@@ -2190,7 +2221,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);
include/linux/fs.h +2 -0
@@ -737,6 +737,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);
Signature · 1 line
2.17.1
PATCH v8 3/20 timestamp_truncate: Replace users of timespec64_trunc
In reply to Deepa DinamaniUpdate the inode timestamp updates to use timestamp_truncate() instead of timespec64_trunc().
The change was mostly generated by the following coccinelle script.
virtual context
virtual patch
@r1 depends on patch forall@
struct inode *inode;
identifier i_xtime =~ "^i_[acm]time$";
expression e;
@@
inode->i_xtime =
- timespec64_trunc(
+ timestamp_truncate(
...,
- e);
+ inode);
--- fs/attr.c | 21 ++++++++++++--------- fs/configfs/inode.c | 12 ++++++------ fs/f2fs/file.c | 21 ++++++++++++--------- fs/kernfs/inode.c | 7 +++---- fs/ntfs/inode.c | 21 ++++++++++++--------- fs/ubifs/file.c | 21 ++++++++++++--------- 6 files changed, 57 insertions(+), 46 deletions(-)
fs/attr.c +12 -9
@@ -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;
fs/configfs/inode.c +6 -6
@@ -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;
fs/f2fs/file.c +12 -9
@@ -749,15 +749,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;
fs/kernfs/inode.c +3 -4
@@ -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)
fs/ntfs/inode.c +12 -9
@@ -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;
fs/ubifs/file.c +12 -9
@@ -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;
Signature · 1 line
2.17.1
Re: [PATCH v8 03/20] timestamp_truncate: Replace users of timespec64_trunc
Quoted 35 lines · Deepa Dinamani
Update the inode timestamp updates to use
timestamp_truncate()instead oftimespec64_trunc().The change was mostly generated by the following coccinelle script.
virtual context
virtual patch@r1 depends on patch forall@
struct inode *inode;
identifieri_xtime=~ "^i_[acm]time$";
expression e;
@@
inode->i_xtime=
- timespec64_trunc(
+ timestamp_truncate(
...,
- e);
+ inode);
Quoted 8 lines
--- fs/attr.c | 21 ++++++++++++--------- fs/configfs/inode.c | 12 ++++++------ fs/f2fs/file.c | 21 ++++++++++++--------- fs/kernfs/inode.c | 7 +++---- fs/ntfs/inode.c | 21 ++++++++++++--------- fs/ubifs/file.c | 21 ++++++++++++--------- 6 files changed, 57 insertions(+), 46 deletions(-)
For kernfs:
PATCH v8 4/20 mount: Add mount warning for impending timestamp expiry
In reply to Deepa DinamaniThe warning reuses the uptime max of 30 years used by settimeofday().
Note that the warning is only emitted for writable filesystem mounts through the mount syscall. Automounts do not have the same warning.
Print out the warning in human readable format using the struct tm. After discussion with Arnd Bergmann, we chose to print only the year number. The raw s_time_max is also displayed, and the user can easily decode it e.g. "date -u -d @$((0x7fffffff))". We did not want to consolidate struct rtc_tm and struct tm just to print the date using a format specifier as part of this series.
Given that the rtc_tm is not compiled on all architectures, this is not a trivial patch. This can be added in the future.
--- fs/namespace.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-)
fs/namespace.c +32 -1
@@ -2468,6 +2468,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
@@ -2493,6 +2513,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; }
@@ -2533,6 +2556,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; }
@@ -2741,8 +2767,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; }
Signature · 1 line
2.17.1
PATCH v8 5/20 utimes: Clamp the timestamps before update
In reply to Deepa DinamaniPOSIX is ambiguous on the behavior of timestamps for futimens, utimensat and utimes. Whether to return an error or silently clamp a timestamp beyond the range supported by the underlying filesystems is not clear.
POSIX.1 section for futimens, utimensat and utimes says:
(http://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html)
The file's relevant timestamp shall be set to the greatest value supported by the file system that is not greater than the specified time.
If the tv_nsec field of a timespec structure has the special value UTIME_NOW, the file's relevant timestamp shall be set to the greatest value supported by the file system that is not greater than the current time.
[EINVAL]
A new file timestamp would be a value whose tv_sec component is not a value supported by the file system.
The patch chooses to clamp the timestamps according to the
filesystem timestamp ranges and does not return an error.
This is in line with the behavior of utime syscall also
since the POSIX page(http://pubs.opengroup.org/onlinepubs/009695399/functions/utime.html) for utime does not mention returning an error or clamping like above.
Same for utimes http://pubs.opengroup.org/onlinepubs/009695399/functions/utimes.html
--- fs/utimes.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
fs/utimes.c +2 -4
@@ -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 ; }/*
Signature · 1 line
2.17.1
PATCH v8 6/20 fs: Fill in max and min timestamps in superblock
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Even though some filesystems are read-only, fill in the timestamps to reflect the on-disk representation.
--- fs/befs/linuxvfs.c | 2 ++ fs/bfs/inode.c | 2 ++ fs/coda/inode.c | 3 +++ fs/cramfs/inode.c | 2 ++ fs/efs/super.c | 2 ++ fs/ext2/super.c | 2 ++ fs/freevxfs/vxfs_super.c | 2 ++ fs/jffs2/fs.c | 3 +++ fs/jfs/super.c | 2 ++ fs/minix/inode.c | 2 ++ fs/qnx4/inode.c | 2 ++ fs/qnx6/inode.c | 2 ++ fs/reiserfs/super.c | 3 +++ fs/romfs/super.c | 2 ++ fs/squashfs/super.c | 2 ++ fs/ufs/super.c | 7 +++++++ fs/xfs/xfs_super.c | 2 ++ 17 files changed, 42 insertions(+)
fs/befs/linuxvfs.c +2 -0
@@ -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);
fs/bfs/inode.c +2 -0
@@ -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 );
fs/coda/inode.c +3 -0
@@ -223,6 +223,9 @@ static int coda_fill_super(struct super_block *sb, struct fs_context *fc) 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)
fs/cramfs/inode.c +2 -0
@@ -599,6 +599,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))
fs/efs/super.c +2 -0
@@ -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 )) {
fs/ext2/super.c +2 -0
@@ -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 ;
fs/freevxfs/vxfs_super.c +2 -0
@@ -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 ))) {
fs/jffs2/fs.c +3 -0
@@ -591,6 +591,9 @@ int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc) 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 ;
fs/jfs/super.c +2 -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 ;
fs/minix/inode.c +2 -0
@@ -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);
fs/qnx4/inode.c +2 -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
fs/qnx6/inode.c +2 -0
@@ -429,6 +429,8 @@ static int qnx6_fill_super(struct super_block *s, void *data, int silent) 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);
fs/reiserfs/super.c +3 -0
@@ -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
fs/romfs/super.c +2 -0
@@ -477,6 +477,8 @@ static int romfs_fill_super(struct super_block *sb, struct fs_context *fc) 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
fs/squashfs/super.c +2 -0
@@ -186,6 +186,8 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc) (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;
fs/ufs/super.c +7 -0
@@ -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 ;
fs/xfs/xfs_super.c +2 -0
@@ -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);
Signature · 1 line
2.17.1
Re: [PATCH v8 06/20] fs: Fill in max and min timestamps in superblock
Quoted 30 lines · On Sunday, 2019-08-18 18:58 Deepa Dinamani wrote:
Fill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Even though some filesystems are read-only, fill in the timestamps to reflect the on-disk representation.
Signed-off-by Deepa Dinamani <[email protected]>Reviewed-by Darrick J. Wong <[email protected]>
Quoted 12 lines
--- fs/befs/linuxvfs.c | 2 ++ fs/bfs/inode.c | 2 ++ fs/coda/inode.c | 3 +++ fs/cramfs/inode.c | 2 ++ fs/efs/super.c | 2 ++ fs/ext2/super.c | 2 ++ fs/freevxfs/vxfs_super.c | 2 ++ fs/jffs2/fs.c | 3 +++ fs/jfs/super.c | 2 ++ fs/minix/inode.c | 2 ++ fs/qnx4/inode.c | 2 ++
wrt qnx4, feel free to add
_______________________________________________
Y2038 mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/y2038
Re: [PATCH v8 06/20] fs: Fill in max and min timestamps in superblock
In reply to Deepa DinamaniI see no problems for BFS.
Quoted 306 lines · Deepa Dinamani
Fill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Even though some filesystems are read-only, fill in the timestamps to reflect the on-disk representation.
Signed-off-by Deepa Dinamani <[email protected]>Reviewed-by Darrick J. Wong <[email protected]>--- fs/befs/linuxvfs.c | 2 ++ fs/bfs/inode.c | 2 ++ fs/coda/inode.c | 3 +++ fs/cramfs/inode.c | 2 ++ fs/efs/super.c | 2 ++ fs/ext2/super.c | 2 ++ fs/freevxfs/vxfs_super.c | 2 ++ fs/jffs2/fs.c | 3 +++ fs/jfs/super.c | 2 ++ fs/minix/inode.c | 2 ++ fs/qnx4/inode.c | 2 ++ fs/qnx6/inode.c | 2 ++ fs/reiserfs/super.c | 3 +++ fs/romfs/super.c | 2 ++ fs/squashfs/super.c | 2 ++ fs/ufs/super.c | 7 +++++++ fs/xfs/xfs_super.c | 2 ++ 17 files changed, 42 insertions(+)fs/befs/linuxvfs.c +2
-0@@ -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);fs/bfs/inode.c +2
-0@@ -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 );fs/coda/inode.c +3
-0@@ -223,6 +223,9 @@ static int coda_fill_super(struct super_block *sb, struct fs_context *fc) 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)
fs/cramfs/inode.c +2
-0@@ -599,6 +599,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))fs/efs/super.c +2
-0@@ -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)) {fs/ext2/super.c +2
-0@@ -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;fs/freevxfs/vxfs_super.c +2
-0@@ -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))) {fs/jffs2/fs.c +3
-0@@ -591,6 +591,9 @@ int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc) 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;fs/jfs/super.c +2
-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;fs/minix/inode.c +2
-0@@ -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);fs/qnx4/inode.c +2
-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
fs/qnx6/inode.c +2
-0@@ -429,6 +429,8 @@ static int qnx6_fill_super(struct super_block *s, void *data, int silent) 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);fs/reiserfs/super.c +3
-0@@ -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
notfs/romfs/super.c +2
-0@@ -477,6 +477,8 @@ static int romfs_fill_super(struct super_block *sb, struct fs_context *fc) 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_MTDfs/squashfs/super.c +2
-0@@ -186,6 +186,8 @@ static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc) (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;fs/ufs/super.c +4
-0@@ -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");fs/ufs/super.c +3
-0@@ -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;fs/xfs/xfs_super.c +2
-1@@ -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); --
Quoted 3 lines
2.17.1
_______________________________________________
Y2038 mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/y2038
Tigran Aivazian
Acked-byRe: [PATCH v8 06/20] fs: Fill in max and min timestamps in superblock
I see no problems for BFS.
PATCH v8 7/20 9p: Fill min and max timestamps in sb
In reply to Deepa Dinamanistruct p9_wstat and struct p9_stat_dotl indicate that the wire transport uses u32 and u64 fields for timestamps. Fill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Note that the upper bound for V9FS_PROTO_2000L is retained as S64_MAX. This is because that is the upper bound supported by vfs.
--- fs/9p/vfs_super.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/9p/vfs_super.c +5 -1
@@ -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)
Signature · 1 line
2.17.1
PATCH v8 8/20 adfs: Fill in max and min timestamps in sb
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Note that the min timestamp is assumed to be
01 Jan 1970 00:00:00 (Unix epoch). This is consistent with the way we convert timestamps in adfs_adfs2unix_time().
--- fs/adfs/adfs.h | 13 +++++++++++++ fs/adfs/inode.c | 8 ++------ fs/adfs/super.c | 2 ++ 3 files changed, 17 insertions(+), 6 deletions(-)
fs/adfs/adfs.h +13 -0
@@ -3,6 +3,19 @@#include <linux/fs.h> #include <linux/adfs_fs.h> +/* +* 01 Jan 1970 00:00:00 (Unix epoch) as seconds since +* 01 Jan 1900 00:00:00 (RISC OS epoch) +*/ +#define RISC_OS_EPOCH_DELTA 2208988800LL + +/* +* Convert 40 bit centi seconds to seconds +* since 01 Jan 1900 00:00:00 (RISC OS epoch) +* The result is 2248-06-03 06:57:57 GMT +*/ +#define ADFS_MAX_TIMESTAMP ((0xFFFFFFFFFFLL / 100) - RISC_OS_EPOCH_DELTA) +/* Internal data structures for ADFS */ #define ADFS_FREE_FRAG 0
fs/adfs/inode.c +2 -6
@@ -167,11 +167,7 @@ static void adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode) { unsigned int high, low; -/* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since -* 01 Jan 1900 00:00:00 (RISC OS epoch) -*/ -static const s64 nsec_unix_epoch_diff_risc_os_epoch = -2208988800000000000LL ; +static const s64 nsec_unix_epoch_diff_risc_os_epoch =RISC_OS_EPOCH_DELTA *NSEC_PER_SEC ;s64 nsec;if (!adfs_inode_is_stamped (inode))
@@ -216,7 +212,7 @@ adfs_unix2adfs_time(struct inode *inode, unsigned int secs)if (adfs_inode_is_stamped (inode)) {/* convert 32-bit seconds to 40-bit centi-seconds */ low = (secs &255 ) *100 ; - high = (secs /256 ) *100 + (low >>8 ) +0x336e996a ; + high = (secs /256 ) *100 + (low >>8 ) + (RISC_OS_EPOCH_DELTA *100 /256 );ADFS_I (inode)->loadaddr = (high >>24 ) | (ADFS_I (inode)->loadaddr & ~0xff );
fs/adfs/super.c +2 -0
@@ -463,6 +463,8 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) asb->s_map_size = dr->nzones | (dr->nzones_high <<8 ); asb->s_map2blk = dr->log2bpmb - dr->log2secsize; asb->s_log2sharesize = dr->log2sharesize; + sb->s_time_min =0 ; + sb->s_time_max =ADFS_MAX_TIMESTAMP ; asb->s_map =adfs_read_map (sb, dr);if (IS_ERR (asb->s_map)) {
Signature · 1 line
2.17.1
Re: [PATCH v8 08/20] adfs: Fill in max and min timestamps in sb
Quoted 3 lines · Deepa Dinamani
Note that the min timestamp is assumed to be
01 Jan 1970 00:00:00 (Unix epoch). This is consistent with the way we convert timestamps inadfs_adfs2unix_time().
That's not actually correct. RISC OS timestamps are centiseconds since 1900 stored in 5 bytes.
Quoted 73 lines
Signed-off-by Deepa Dinamani <[email protected]>--- fs/adfs/adfs.h | 13 +++++++++++++ fs/adfs/inode.c | 8 ++------ fs/adfs/super.c | 2 ++ 3 files changed, 17 insertions(+), 6 deletions(-)fs/adfs/adfs.h +13
-0@@ -3,6 +3,19 @@#include <linux/fs.h> #include <linux/adfs_fs.h> +/* +* 01 Jan 1970 00:00:00 (Unix epoch) as seconds since +* 01 Jan 1900 00:00:00 (RISC OS epoch) +*/ +#define RISC_OS_EPOCH_DELTA 2208988800LL + +/* +* Convert 40 bit centi seconds to seconds +* since 01 Jan 1900 00:00:00 (RISC OS epoch) +* The result is 2248-06-03 06:57:57 GMT +*/ +#define ADFS_MAX_TIMESTAMP ((0xFFFFFFFFFFLL / 100) - RISC_OS_EPOCH_DELTA) +/* Internal data structures for ADFS */ #define ADFS_FREE_FRAG 0fs/adfs/inode.c +2
-6@@ -167,11 +167,7 @@ static void adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode) { unsigned int high, low; -/* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since -* 01 Jan 1900 00:00:00 (RISC OS epoch) -*/ -static const s64 nsec_unix_epoch_diff_risc_os_epoch = -2208988800000000000LL ; +static const s64 nsec_unix_epoch_diff_risc_os_epoch =RISC_OS_EPOCH_DELTA *NSEC_PER_SEC ;s64 nsec;if (!adfs_inode_is_stamped (inode))@@ -216,7 +212,7 @@ adfs_unix2adfs_time(struct inode *inode, unsigned int secs)if (adfs_inode_is_stamped (inode)) {/* convert 32-bit seconds to 40-bit centi-seconds */ low = (secs &255 ) *100 ; - high = (secs /256 ) *100 + (low >>8 ) +0x336e996a ; + high = (secs /256 ) *100 + (low >>8 ) + (RISC_OS_EPOCH_DELTA *100 /256 );ADFS_I (inode)->loadaddr = (high >>24 ) | (ADFS_I (inode)->loadaddr & ~0xff );fs/adfs/super.c +2
-0@@ -463,6 +463,8 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) asb->s_map_size = dr->nzones | (dr->nzones_high <<8 ); asb->s_map2blk = dr->log2bpmb - dr->log2secsize; asb->s_log2sharesize = dr->log2sharesize; + sb->s_time_min =0 ; + sb->s_time_max =ADFS_MAX_TIMESTAMP ; asb->s_map =adfs_read_map (sb, dr);if (IS_ERR (asb->s_map)) {Signature · 1 line
2.17.1
Re: [PATCH v8 08/20] adfs: Fill in max and min timestamps in sb
Quoted 8 lines · Matthew Wilcox
Quoted 3 lines · Deepa Dinamani
Note that the min timestamp is assumed to be
01 Jan 1970 00:00:00 (Unix epoch). This is consistent with the way we convert timestamps inadfs_adfs2unix_time().That's not actually correct. RISC OS timestamps are centiseconds since 1900 stored in 5 bytes.
The timestamp can hold earlier values but the fs implementation explicitly rejects those in adfs_adfs2unix_time() too_early check. We could fix the implementation to not throw away times before 1970. Are you suggesting we want to do this?
I could post a separate patch to fix this or we could do it as part of the series.
static void
adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode) {
unsigned int high, low;
static const s64 nsec_unix_epoch_diff_risc_os_epoch =
RISC_OS_EPOCH_DELTA * NSEC_PER_SEC;
s64 nsec;
if (!adfs_inode_is_stamped(inode))
goto cur_time;
high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */
low = ADFS_I(inode)->execaddr; /* bottom 32 bits of timestamp */
/* convert 40-bit centi-seconds to 32-bit seconds
* going via nanoseconds to retain precision
*/
nsec = (((s64) high << 32) | (s64) low) * 10000000; /* cs to ns */
/* Files dated pre 01 Jan 1970 00:00:00. */
if (nsec < nsec_unix_epoch_diff_risc_os_epoch)
goto too_early;
/* convert from RISC OS to Unix epoch */
nsec -= nsec_unix_epoch_diff_risc_os_epoch;
*tv = ns_to_timespec64(nsec);
return; cur_time:
*tv = current_time(inode);
return; too_early:
tv->tv_sec = tv->tv_nsec = 0;
return;}
-Deepa
PATCH v8 9/20 ext4: Initialize timestamps limits
In reply to Deepa Dinamaniext4 has different overflow limits for max filesystem timestamps based on the extra bytes available.
The timestamp limits are calculated according to the encoding table ina4dad1ae24f85i(ext4: Fix handling of extended tv_sec):
* extra msb of adjust for signed * epoch 32-bit 32-bit tv_sec to * bits time decoded 64-bit tv_sec 64-bit tv_sec valid time range * 0 0 1 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31 * 0 0 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19 * 0 1 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07 * 0 1 0 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25 * 1 0 1 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16 * 1 0 0 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04 * 1 1 1 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22 * 1 1 0 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10
Note that the time limits are not correct for deletion times.
Added a warn when an inode cannot be extended to incorporate an extended timestamp.
--- fs/ext4/ext4.h | 10 +++++++++- fs/ext4/super.c | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-)
fs/ext4/ext4.h +9 -1
@@ -832,11 +832,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) \
@@ -1643,6 +1647,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 */
fs/ext4/super.c +15 -2
@@ -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);
Signature · 1 line
2.17.1
PATCH v8 10/20 fs: nfs: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
The time formats for various verious is detailed in the RFCs as below:
https://tools.ietf.org/html/rfc7862(time metadata)
https://tools.ietf.org/html/rfc7530:
nfstime4
struct nfstime4 {
int64_t seconds;
uint32_t nseconds;
};https://tools.ietf.org/html/rfc1094
struct timeval {
unsigned int seconds;
unsigned int useconds;
};https://tools.ietf.org/html/rfc1813
struct nfstime3 {
uint32 seconds;
uint32 nseconds;
};Use the limits as per the RFC.
--- fs/nfs/super.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
fs/nfs/super.c +19 -1
@@ -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);
Signature · 1 line
2.17.1
PATCH v8 11/20 fs: cifs: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Also fixed cnvrtDosUnixTm calculations to avoid int overflow while computing maximum date.
References:
--- fs/cifs/cifsfs.c | 22 ++++++++++++++++++++++ fs/cifs/netmisc.c | 14 +++++++------- 2 files changed, 29 insertions(+), 7 deletions(-)
fs/cifs/cifsfs.c +22 -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;
fs/cifs/netmisc.c +7 -7
@@ -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 ;
Signature · 1 line
2.17.1
PATCH v8 12/20 fs: fat: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Some FAT variants indicate that the years after 2099 are not supported. Since commit 7decd1cb0305 ("fat: Fix and cleanup timestamp conversion") we support the full range of years that can be represented, up to 2107.
--- fs/fat/inode.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/fat/inode.c +12 -0
@@ -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.
@@ -1617,6 +1622,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
@@ -1710,6 +1716,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;
Signature · 1 line
2.17.1
PATCH v8 13/20 fs: affs: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Also fix timestamp calculation to avoid overflow while converting from days to seconds.
--- fs/affs/amigaffs.c | 2 +- fs/affs/amigaffs.h | 3 +++ fs/affs/inode.c | 4 ++-- fs/affs/super.c | 4 ++++ 4 files changed, 10 insertions(+), 3 deletions(-)
fs/affs/amigaffs.c +1 -1
@@ -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);
fs/affs/amigaffs.h +3 -0
@@ -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;
fs/affs/inode.c +2 -2
@@ -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);
fs/affs/super.c +4 -0
@@ -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 ;
Signature · 1 line
2.17.1
PATCH v8 14/20 fs: sysv: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
--- fs/sysv/super.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/sysv/super.c +4 -1
@@ -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 );
Signature · 1 line
2.17.1
PATCH v8 15/20 fs: ceph: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
According to the disscussion in
https://patchwork.kernel.org/patch/8308691/ we agreed to use unsigned 32 bit timestamps on ceph.
Update the limits accordingly.
--- fs/ceph/super.c | 2 ++ 1 file changed, 2 insertions(+)
fs/ceph/super.c +2 -0
@@ -907,6 +907,8 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc) 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_fc (s, fc);if (ret !=0 )
Signature · 1 line
2.17.1
PATCH v8 16/20 fs: orangefs: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Assume the limits as unsigned according to the below commit 98e8eef557a9 ("changed PVFS_time from int64_t to uint64_t") in https://github.com/waltligon/orangefs
Author: Neill Miller <[email protected]> Date: Thu Sep 2 15:00:38 2004 +0000
--- fs/orangefs/super.c | 2 ++ 1 file changed, 2 insertions(+)
fs/orangefs/super.c +2 -0
@@ -425,6 +425,8 @@ static int orangefs_fill_sb(struct super_block *sb, sb->s_blocksize =PAGE_SIZE ; sb->s_blocksize_bits =PAGE_SHIFT ; sb->s_maxbytes =MAX_LFS_FILESIZE ; + sb->s_time_min =0 ; + sb->s_time_max =S64_MAX ; ret =super_setup_bdi (sb);if (ret)
Signature · 1 line
2.17.1
PATCH v8 17/20 fs: hpfs: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Also change the local_to_gmt() to use time64_t instead of time32_t.
--- fs/hpfs/hpfs_fn.h | 6 ++---- fs/hpfs/super.c | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-)
fs/hpfs/hpfs_fn.h +2 -4
@@ -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)
fs/hpfs/super.c +2 -0
@@ -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);
Signature · 1 line
2.17.1
PATCH v8 18/20 fs: omfs: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
--- fs/omfs/inode.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/omfs/inode.c +4 -0
@@ -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 );
Signature · 1 line
2.17.1
PATCH v8 19/20 pstore: fs superblock limits
In reply to Deepa DinamaniLeaving granularity at 1ns because it is dependent on the specific attached backing pstore module. ramoops has microsecond resolution.
Fix the readback of ramoops fractional timestamp microseconds, which has incorrectly been reporting the value as nanoseconds since 3f8f80f0 ("pstore/ram: Read and write to the 'compressed' flag of pstore").
--- fs/pstore/ram.c | 2 ++ 1 file changed, 2 insertions(+)
fs/pstore/ram.c +2 -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 ;
Signature · 1 line
2.17.1
Re: [PATCH v8 19/20] pstore: fs superblock limits
Quoted 6 lines · Deepa Dinamani
Leaving granularity at 1ns because it is dependent on the specific attached backing pstore module. ramoops has microsecond resolution.
Fix the readback of ramoops fractional timestamp microseconds, which has incorrectly been reporting the value as nanoseconds since
3f8f80f0("pstore/ram: Read and write to the 'compressed' flag of pstore").
As such, this should also have:
Quoted 2 lines
Signed-off-by Deepa Dinamani <[email protected]>Acked-by Kees Cook <[email protected]>
Also: this is going via some other tree, yes? (Or should I pick this up for the pstore tree?)
Thanks!
-Kees
Quoted 31 lines
--- fs/pstore/ram.c | 2 ++ 1 file changed, 2 insertions(+)fs/pstore/ram.c +2
-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 ;Signature · 1 line
2.17.1
Signature · 1 line
Kees Cook
Re: [PATCH v8 19/20] pstore: fs superblock limits
Quoted 5 lines · Kees Cook
Quoted 3 lines · Deepa Dinamani
Leaving granularity at 1ns because it is dependent on the specific attached backing pstore module. ramoops has microsecond resolution.
Quoted 7 lines
Quoted 3 lines
Fix the readback of ramoops fractional timestamp microseconds, which has incorrectly been reporting the value as nanoseconds since
3f8f80f0("pstore/ram: Read and write to the 'compressed' flag of pstore").As such, this should also have:
Fixes 3f8f80f0cfeb ("pstore/ram: Read and write to the 'compressed' flag of pstore")
Will add that in. Thanks.
Quoted 5 lines
Quoted 2 lines
Signed-off-by Deepa Dinamani <[email protected]>Acked-by Kees Cook <[email protected]>Also: this is going via some other tree, yes? (Or should I pick this up for the pstore tree?)
I am hoping Al can take the series as a whole.
-Deepa
PATCH v8 20/20 isofs: Initialize filesystem timestamp ranges
In reply to Deepa DinamaniFill in the appropriate limits to avoid inconsistencies in the vfs cached inode times when timestamps are outside the permitted range.
Reference: http://www.ecma-international.org/publications/standards/Ecma-119.htm
--- fs/isofs/inode.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/isofs/inode.c +7 -0
@@ -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 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)*/ 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 .. */
Signature · 1 line
2.17.1
Jeff Layton
maintainerQuoted 28 lines · Deepa Dinamani
The series is an update and a more complete version of the previously posted series at
https://lore.kernel.org/linux-fsdevel/[email protected]/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 orangefs u64 seconds 0 U64_MAX alloc_super
Quoted 8 lines
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
Looks reasonable, overall.
Note that the granularity changed recently for cephfs. See commit 0f7cf80ae96c2a (ceph: initialize superblock s_time_gran to 1).
In any case, you can add my Acked-by
Signature · 1 line
Jeff Layton <[email protected]>