From ec50e66fff566430054af37cc62187217a65926f Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 11 May 2023 15:12:33 -0400 Subject: [PATCH] Timespec64 changes for yr2038. Provide a fallback `current_time(inode)` implementation for older kernels. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++++ kmod/src/acl.c | 2 +- kmod/src/data.c | 4 ++-- kmod/src/dir.c | 14 +++++++------- kmod/src/inode.c | 4 ++-- kmod/src/inode.h | 2 +- kmod/src/kernelcompat.c | 30 ++++++++++++++++++++++++++++++ kmod/src/kernelcompat.h | 8 ++++++++ kmod/src/xattr.c | 2 +- 9 files changed, 61 insertions(+), 14 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 3f6991c6..346a8249 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -185,3 +185,12 @@ endif ifneq (,$(shell grep 'struct iov_iter.*msg_iter' include/linux/socket.h)) ccflags-y += -DKC_MSGHDR_STRUCT_IOV_ITER=1 endif + +# +# v4.17-rc6-7-g95582b008388 +# +# Kernel has current_time(inode) to uniformly retreive timespec in the right unit +# +ifneq (,$(shell grep 'extern struct timespec64 current_time' include/linux/fs.h)) +ccflags-y += -DKC_CURRENT_TIME_INODE=1 +endif diff --git a/kmod/src/acl.c b/kmod/src/acl.c index 93188f9d..9458f376 100644 --- a/kmod/src/acl.c +++ b/kmod/src/acl.c @@ -183,7 +183,7 @@ int scoutfs_set_acl_locked(struct inode *inode, struct posix_acl *acl, int type, if (!value) { /* can be setting an acl that only affects mode, didn't need xattr */ inode_inc_iversion(inode); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = current_time(inode); } } diff --git a/kmod/src/data.c b/kmod/src/data.c index 54009404..a51ee67b 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -1221,7 +1221,7 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off, struct data_ext_args from_args; struct data_ext_args to_args; struct scoutfs_extent ext; - struct timespec cur_time; + struct kc_timespec cur_time; LIST_HEAD(locks); bool done = false; loff_t from_size; @@ -1442,7 +1442,7 @@ int scoutfs_data_move_blocks(struct inode *from, u64 from_off, up_write(&from_si->extent_sem); up_write(&to_si->extent_sem); - cur_time = CURRENT_TIME; + cur_time = current_time(from); if (!is_stage) { to->i_ctime = to->i_mtime = cur_time; inode_inc_iversion(to); diff --git a/kmod/src/dir.c b/kmod/src/dir.c index aa1272af..f8bf50e9 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -735,7 +735,7 @@ static int scoutfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, set_dentry_fsdata(dentry, dir_lock); i_size_write(dir, i_size_read(dir) + dentry->d_name.len); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = current_time(inode); inode->i_mtime = inode->i_atime = inode->i_ctime = dir->i_mtime; si->crtime = inode->i_mtime; inode_inc_iversion(dir); @@ -859,7 +859,7 @@ retry: set_dentry_fsdata(dentry, dir_lock); i_size_write(dir, dir_size); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = current_time(inode); inode->i_ctime = dir->i_mtime; inc_nlink(inode); inode_inc_iversion(dir); @@ -900,7 +900,7 @@ static int scoutfs_unlink(struct inode *dir, struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode = dentry->d_inode; - struct timespec ts = current_kernel_time(); + struct kc_timespec ts = current_time(inode); struct scoutfs_lock *inode_lock = NULL; struct scoutfs_lock *orph_lock = NULL; struct scoutfs_lock *dir_lock = NULL; @@ -1204,7 +1204,7 @@ static int scoutfs_symlink(struct inode *dir, struct dentry *dentry, set_dentry_fsdata(dentry, dir_lock); i_size_write(dir, i_size_read(dir) + dentry->d_name.len); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_mtime = dir->i_ctime = current_time(inode); inode_inc_iversion(dir); inode->i_ctime = dir->i_mtime; @@ -1558,7 +1558,7 @@ static int scoutfs_rename_common(struct inode *old_dir, struct scoutfs_lock *orph_lock = NULL; struct scoutfs_dirent new_dent; struct scoutfs_dirent old_dent; - struct timespec now; + struct kc_timespec now; bool ins_new = false; bool del_new = false; bool ins_old = false; @@ -1724,7 +1724,7 @@ retry: inc_nlink(new_dir); } - now = CURRENT_TIME; + now = current_time(old_inode); old_dir->i_ctime = now; old_dir->i_mtime = now; if (new_dir != old_dir) { @@ -1861,7 +1861,7 @@ static int scoutfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mod if (ret < 0) goto out; /* XXX returning error but items created */ - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); si->crtime = inode->i_mtime; insert_inode_hash(inode); ihold(inode); /* need to update inode modifications in d_tmpfile */ diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 6016c0d2..54c9850d 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -384,7 +384,7 @@ static int set_inode_size(struct inode *inode, struct scoutfs_lock *lock, scoutfs_inode_inc_data_version(inode); truncate_setsize(inode, new_size); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_ctime = inode->i_mtime = current_time(inode); if (truncate) si->flags |= SCOUTFS_INO_FLAG_TRUNCATE; scoutfs_inode_set_data_seq(inode); @@ -1474,7 +1474,7 @@ int scoutfs_new_inode(struct super_block *sb, struct inode *dir, umode_t mode, d inode->i_ino = ino; /* XXX overflow */ inode_init_owner(inode, dir, mode); inode_set_bytes(inode, 0); - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); inode->i_rdev = rdev; set_inode_ops(inode); diff --git a/kmod/src/inode.h b/kmod/src/inode.h index 79eacde0..86e1b9fb 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -22,7 +22,7 @@ struct scoutfs_inode_info { u64 online_blocks; u64 offline_blocks; u32 flags; - struct timespec crtime; + struct kc_timespec crtime; /* * Protects per-inode extent items, most particularly readers diff --git a/kmod/src/kernelcompat.c b/kmod/src/kernelcompat.c index bb11a803..7ad197ee 100644 --- a/kmod/src/kernelcompat.c +++ b/kmod/src/kernelcompat.c @@ -28,3 +28,33 @@ int kc_shrink_wrapper_fn(struct shrinker *shrink, struct shrink_control *sc) return min_t(unsigned long, nr, INT_MAX); } #endif + +#ifndef KC_CURRENT_TIME_INODE +struct timespec64 kc_current_time(struct inode *inode) +{ + struct timespec64 now; + unsigned gran; + + getnstimeofday64(&now); + + if (unlikely(!inode->i_sb)) { + WARN(1, "current_time() called with uninitialized super_block in the inode"); + return now; + } + + gran = inode->i_sb->s_time_gran; + + /* Avoid division in the common cases 1 ns and 1 s. */ + if (gran == 1) { + /* nothing */ + } else if (gran == NSEC_PER_SEC) { + now.tv_nsec = 0; + } else if (gran > 1 && gran < NSEC_PER_SEC) { + now.tv_nsec -= now.tv_nsec % gran; + } else { + WARN(1, "illegal file time granularity: %u", gran); + } + + return now; +} +#endif diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index 2dad3400..b18fa847 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -178,6 +178,14 @@ do { \ #define SB_I_VERSION MS_I_VERSION #endif +#ifndef KC_CURRENT_TIME_INODE +struct timespec64 kc_current_time(struct inode *inode); +#define current_time kc_current_time +#define kc_timespec timespec +#else +#define kc_timespec timespec64 +#endif + #ifndef KC_SHRINKER_SHRINK #define KC_DEFINE_SHRINKER(name) struct shrinker name diff --git a/kmod/src/xattr.c b/kmod/src/xattr.c index 75fc35b4..da736ef5 100644 --- a/kmod/src/xattr.c +++ b/kmod/src/xattr.c @@ -773,7 +773,7 @@ int scoutfs_xattr_set_locked(struct inode *inode, const char *name, size_t name_ /* XXX do these want i_mutex or anything? */ inode_inc_iversion(inode); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = current_time(inode); ret = 0; out: