@@ -148,14 +148,14 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
if (ia_valid & ATTR_GID)
inode->i_gid = attr->ia_gid;
if (ia_valid & ATTR_ATIME)
- inode->i_atime = timespec_trunc(attr->ia_atime,
- inode->i_sb->s_time_gran);
+ VFS_INODE_SET_XTIME(i_atime, inode,
+ fs_time_trunc(attr->ia_atime, inode->i_sb));
if (ia_valid & ATTR_MTIME)
- inode->i_mtime = timespec_trunc(attr->ia_mtime,
- inode->i_sb->s_time_gran);
+ VFS_INODE_SET_XTIME(i_mtime, inode,
+ fs_time_trunc(attr->ia_mtime, inode->i_sb));
if (ia_valid & ATTR_CTIME)
- inode->i_ctime = timespec_trunc(attr->ia_ctime,
- inode->i_sb->s_time_gran);
+ VFS_INODE_SET_XTIME(i_ctime, inode,
+ fs_time_trunc(attr->ia_ctime, inode->i_sb));
if (ia_valid & ATTR_MODE) {
umode_t mode = attr->ia_mode;
@@ -192,7 +192,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
struct inode *inode = dentry->d_inode;
umode_t mode = inode->i_mode;
int error;
- struct timespec now;
+ struct inode_timespec now;
unsigned int ia_valid = attr->ia_valid;
WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
@@ -210,7 +210,6 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
}
now = current_fs_time(inode->i_sb);
-
attr->ia_ctime = now;
if (!(ia_valid & ATTR_ATIME_SET))
attr->ia_atime = now;
@@ -169,11 +169,17 @@ static const struct inode_operations bad_inode_ops =
void make_bad_inode(struct inode *inode)
{
+ struct inode_timespec now;
+
remove_inode_hash(inode);
inode->i_mode = S_IFREG;
- inode->i_atime = inode->i_mtime = inode->i_ctime =
- current_fs_time(inode->i_sb);
+
+ now = current_fs_time(inode->i_sb);
+
+ VFS_INODE_SET_XTIME(i_atime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, inode, now);
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
inode->i_op = &bad_inode_ops;
inode->i_fop = &bad_file_ops;
}
@@ -562,12 +562,15 @@ static void entry_status(Node *e, char *page)
static struct inode *bm_get_inode(struct super_block *sb, int mode)
{
struct inode *inode = new_inode(sb);
+ struct inode_timespec now;
if (inode) {
inode->i_ino = get_next_ino();
inode->i_mode = mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime =
- current_fs_time(inode->i_sb);
+ now = current_fs_time(inode->i_sb);
+ VFS_INODE_SET_XTIME(i_atime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, inode, now);
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
}
return inode;
}
@@ -1532,27 +1532,36 @@ EXPORT_SYMBOL(bmap);
* passed since the last atime update.
*/
static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
- struct timespec now)
+ struct inode_timespec now)
{
+ struct inode_timespec ctime;
+ struct inode_timespec mtime;
+ struct inode_timespec atime;
+
if (!(mnt->mnt_flags & MNT_RELATIME))
return 1;
+
+ atime = VFS_INODE_GET_XTIME(i_atime, inode);
+ ctime = VFS_INODE_GET_XTIME(i_ctime, inode);
+ mtime = VFS_INODE_GET_XTIME(i_mtime, inode);
+
/*
* Is mtime younger than atime? If yes, update atime:
*/
- if (timespec_compare(&inode->i_mtime, &inode->i_atime) >= 0)
+ if (inode_timespec_compare(&mtime, &atime) >= 0)
return 1;
/*
* Is ctime younger than atime? If yes, update atime:
*/
- if (timespec_compare(&inode->i_ctime, &inode->i_atime) >= 0)
+ if (inode_timespec_compare(&ctime, &atime) >= 0)
return 1;
/*
* Is the previous atime value older than a day? If yes,
* update atime:
*/
- if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60)
+ if ((long)(now.tv_sec - atime.tv_sec) >= 24*60*60)
return 1;
/*
* Good, we can skip the atime update:
@@ -1560,18 +1569,19 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
return 0;
}
-int generic_update_time(struct inode *inode, struct timespec *time, int flags)
+int generic_update_time(struct inode *inode, struct inode_timespec *time,
+ int flags)
{
int iflags = I_DIRTY_TIME;
if (flags & S_ATIME)
- inode->i_atime = *time;
+ VFS_INODE_SET_XTIME(i_atime, inode, *time);
if (flags & S_VERSION)
inode_inc_iversion(inode);
if (flags & S_CTIME)
- inode->i_ctime = *time;
+ VFS_INODE_SET_XTIME(i_ctime, inode, *time);
if (flags & S_MTIME)
- inode->i_mtime = *time;
+ VFS_INODE_SET_XTIME(i_mtime, inode, *time);
if (!(inode->i_sb->s_flags & MS_LAZYTIME) || (flags & S_VERSION))
iflags |= I_DIRTY_SYNC;
@@ -1584,9 +1594,10 @@ EXPORT_SYMBOL(generic_update_time);
* This does the actual work of updating an inodes time or version. Must have
* had called mnt_want_write() before calling this.
*/
-static int update_time(struct inode *inode, struct timespec *time, int flags)
+static int update_time(struct inode *inode, struct inode_timespec *time,
+ int flags)
{
- int (*update_time)(struct inode *, struct timespec *, int);
+ int (*update_time)(struct inode *, struct inode_timespec *, int);
update_time = inode->i_op->update_time ? inode->i_op->update_time :
generic_update_time;
@@ -1606,7 +1617,8 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
bool atime_needs_update(const struct path *path, struct inode *inode)
{
struct vfsmount *mnt = path->mnt;
- struct timespec now;
+ struct inode_timespec now;
+ struct inode_timespec atime;
if (inode->i_flags & S_NOATIME)
return false;
@@ -1621,11 +1633,11 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
return false;
now = current_fs_time(inode->i_sb);
-
if (!relatime_need_update(mnt, inode, now))
return false;
- if (timespec_equal(&inode->i_atime, &now))
+ atime = VFS_INODE_GET_XTIME(i_atime, inode);
+ if (inode_timespec_equal(&atime, &now))
return false;
return true;
@@ -1635,7 +1647,7 @@ void touch_atime(const struct path *path)
{
struct vfsmount *mnt = path->mnt;
struct inode *inode = d_inode(path->dentry);
- struct timespec now;
+ struct inode_timespec now;
if (!atime_needs_update(path, inode))
return;
@@ -1770,7 +1782,10 @@ EXPORT_SYMBOL(file_remove_privs);
int file_update_time(struct file *file)
{
struct inode *inode = file_inode(file);
- struct timespec now;
+ struct inode_timespec now;
+ struct inode_timespec mtime;
+ struct inode_timespec ctime;
+
int sync_it = 0;
int ret;
@@ -1779,10 +1794,14 @@ int file_update_time(struct file *file)
return 0;
now = current_fs_time(inode->i_sb);
- if (!timespec_equal(&inode->i_mtime, &now))
+
+ mtime = VFS_INODE_GET_XTIME(i_mtime, inode);
+ ctime = VFS_INODE_GET_XTIME(i_ctime, inode);
+
+ if (!inode_timespec_equal(&mtime, &now))
sync_it = S_MTIME;
- if (!timespec_equal(&inode->i_ctime, &now))
+ if (!inode_timespec_equal(&ctime, &now))
sync_it |= S_CTIME;
if (IS_I_VERSION(inode))
@@ -216,6 +216,7 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
struct dentry *dentry;
struct inode *root;
struct qstr d_name = QSTR_INIT(name, strlen(name));
+ struct inode_timespec now;
s = sget(fs_type, NULL, set_anon_super, MS_NOUSER, NULL);
if (IS_ERR(s))
@@ -240,7 +241,11 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
*/
root->i_ino = 1;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
- root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
+ now = current_fs_time(s);
+ VFS_INODE_SET_XTIME(i_atime, root, now);
+ VFS_INODE_SET_XTIME(i_ctime, root, now);
+ VFS_INODE_SET_XTIME(i_mtime, root, now);
+
dentry = __d_alloc(s, &d_name);
if (!dentry) {
iput(root);
@@ -269,8 +274,11 @@ EXPORT_SYMBOL(simple_open);
int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
struct inode *inode = d_inode(old_dentry);
+ struct inode_timespec now = current_fs_time(inode->i_sb);
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, dir, now);
+ VFS_INODE_SET_XTIME(i_ctime, dir, now);
inc_nlink(inode);
ihold(inode);
dget(dentry);
@@ -303,8 +311,11 @@ EXPORT_SYMBOL(simple_empty);
int simple_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
+ struct inode_timespec now = current_fs_time(inode->i_sb);
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, dir, now);
+ VFS_INODE_SET_XTIME(i_ctime, dir, now);
drop_nlink(inode);
dput(dentry);
return 0;
@@ -328,6 +339,7 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
{
struct inode *inode = d_inode(old_dentry);
int they_are_dirs = d_is_dir(old_dentry);
+ struct inode_timespec now;
if (!simple_empty(new_dentry))
return -ENOTEMPTY;
@@ -343,8 +355,13 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
inc_nlink(new_dir);
}
- old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
- new_dir->i_mtime = inode->i_ctime = CURRENT_TIME;
+ now = current_fs_time(inode->i_sb);
+
+ VFS_INODE_SET_XTIME(i_ctime, old_dir, now);
+ VFS_INODE_SET_XTIME(i_mtime, old_dir, now);
+ VFS_INODE_SET_XTIME(i_ctime, new_dir, now);
+ VFS_INODE_SET_XTIME(i_mtime, new_dir, now);
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
return 0;
}
@@ -478,6 +495,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
struct inode *inode;
struct dentry *root;
struct dentry *dentry;
+ struct inode_timespec now;
int i;
s->s_blocksize = PAGE_CACHE_SIZE;
@@ -497,7 +515,10 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
*/
inode->i_ino = 1;
inode->i_mode = S_IFDIR | 0755;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ now = current_fs_time(inode->i_sb);
+ VFS_INODE_SET_XTIME(i_atime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, inode, now);
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
set_nlink(inode, 2);
@@ -523,7 +544,10 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
goto out;
}
inode->i_mode = S_IFREG | files->mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ now = current_fs_time(inode->i_sb);
+ VFS_INODE_SET_XTIME(i_atime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, inode, now);
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
inode->i_fop = files->ops;
inode->i_ino = i;
d_add(dentry, inode);
@@ -1056,6 +1080,7 @@ struct inode *alloc_anon_inode(struct super_block *s)
.set_page_dirty = anon_set_page_dirty,
};
struct inode *inode = new_inode_pseudo(s);
+ struct inode_timespec now;
if (!inode)
return ERR_PTR(-ENOMEM);
@@ -1074,7 +1099,11 @@ struct inode *alloc_anon_inode(struct super_block *s)
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
inode->i_flags |= S_PRIVATE;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ now = current_fs_time(s);
+ VFS_INODE_SET_XTIME(i_atime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, inode, now);
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
+
return inode;
}
EXPORT_SYMBOL(alloc_anon_inode);
@@ -1491,7 +1491,7 @@ EXPORT_SYMBOL(__break_lease);
* exclusive leases. The justification is that if someone has an
* exclusive lease, then they could be modifying it.
*/
-void lease_get_mtime(struct inode *inode, struct timespec *time)
+void lease_get_mtime(struct inode *inode, struct inode_timespec *time)
{
bool has_lease = false;
struct file_lock_context *ctx;
@@ -1510,9 +1510,8 @@ void lease_get_mtime(struct inode *inode, struct timespec *time)
if (has_lease)
*time = current_fs_time(inode->i_sb);
else
- *time = inode->i_mtime;
+ *time = VFS_INODE_GET_XTIME(i_mtime, inode);
}
-
EXPORT_SYMBOL(lease_get_mtime);
/**
@@ -51,6 +51,7 @@ void *ns_get_path(struct path *path, struct task_struct *task,
struct qstr qname = { .name = "", };
struct dentry *dentry;
struct inode *inode;
+ struct inode_timespec now;
struct ns_common *ns;
unsigned long d;
@@ -82,7 +83,10 @@ slow:
return ERR_PTR(-ENOMEM);
}
inode->i_ino = ns->inum;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ now = current_fs_time(mnt->mnt_sb);
+ VFS_INODE_SET_XTIME(i_atime, inode, now);
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, inode, now);
inode->i_flags |= S_IMMUTABLE;
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_fop = &ns_file_operations;
@@ -637,6 +637,7 @@ static struct inode * get_pipe_inode(void)
{
struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb);
struct pipe_inode_info *pipe;
+ struct inode_timespec now;
if (!inode)
goto fail_inode;
@@ -662,7 +663,10 @@ static struct inode * get_pipe_inode(void)
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ now = current_fs_time(pipe_mnt->mnt_sb);
+ VFS_INODE_SET_XTIME(i_atime, inode, now);
+ VFS_INODE_SET_XTIME(i_ctime, inode, now);
+ VFS_INODE_SET_XTIME(i_mtime, inode, now);
return inode;
@@ -859,7 +859,7 @@ int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type)
acl = NULL;
}
- inode->i_ctime = CURRENT_TIME;
+ VFS_INODE_SET_XTIME(i_ctime, inode, current_fs_time(inode->i_sb));
set_cached_acl(inode, type, acl);
return 0;
}
@@ -66,9 +66,9 @@ void fsstack_copy_attr_all(struct inode *dest, const struct inode *src)
dest->i_uid = src->i_uid;
dest->i_gid = src->i_gid;
dest->i_rdev = src->i_rdev;
- dest->i_atime = src->i_atime;
- dest->i_mtime = src->i_mtime;
- dest->i_ctime = src->i_ctime;
+ VFS_INODE_SET_XTIME(i_atime, dest, VFS_INODE_GET_XTIME(i_atime, src));
+ VFS_INODE_SET_XTIME(i_mtime, dest, VFS_INODE_GET_XTIME(i_mtime, src));
+ VFS_INODE_SET_XTIME(i_ctime, dest, VFS_INODE_GET_XTIME(i_ctime, src));
dest->i_blkbits = src->i_blkbits;
dest->i_flags = src->i_flags;
set_nlink(dest, src->i_nlink);
@@ -28,9 +28,9 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
stat->gid = inode->i_gid;
stat->rdev = inode->i_rdev;
stat->size = i_size_read(inode);
- stat->atime = inode->i_atime;
- stat->mtime = inode->i_mtime;
- stat->ctime = inode->i_ctime;
+ stat->atime = VFS_INODE_GET_XTIME(i_atime, inode);
+ stat->mtime = VFS_INODE_GET_XTIME(i_mtime, inode);
+ stat->ctime = VFS_INODE_GET_XTIME(i_ctime, inode);
stat->blksize = (1 << inode->i_blkbits);
stat->blocks = inode->i_blocks;
}
@@ -48,11 +48,12 @@ static bool nsec_valid(long nsec)
return nsec >= 0 && nsec <= 999999999;
}
-static int utimes_common(struct path *path, struct timespec *times)
+static int utimes_common(struct path *path, struct inode_timespec *times)
{
int error;
struct iattr newattrs;
struct inode *inode = path->dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
struct inode *delegated_inode = NULL;
error = mnt_want_write(path->mnt);
@@ -133,7 +134,8 @@ out:
* must be owner or have write permission.
* Else, update from *times, must be owner or super user.
*/
-long do_utimes(int dfd, const char __user *filename, struct timespec *times,
+long do_utimes(int dfd, const char __user *filename,
+ struct inode_timespec *times,
int flags)
{
int error = -EINVAL;
@@ -15,15 +15,16 @@ extern void fsstack_copy_inode_size(struct inode *dst, struct inode *src);
static inline void fsstack_copy_attr_atime(struct inode *dest,
const struct inode *src)
{
- dest->i_atime = src->i_atime;
+ VFS_INODE_SET_XTIME(i_atime, dest, VFS_INODE_GET_XTIME(i_atime, src));
}
static inline void fsstack_copy_attr_times(struct inode *dest,
const struct inode *src)
{
- dest->i_atime = src->i_atime;
- dest->i_mtime = src->i_mtime;
- dest->i_ctime = src->i_ctime;
+ VFS_INODE_SET_XTIME(i_atime, dest, VFS_INODE_GET_XTIME(i_atime, src));
+ VFS_INODE_SET_XTIME(i_mtime, dest, VFS_INODE_GET_XTIME(i_mtime, src));
+ VFS_INODE_SET_XTIME(i_ctime, dest, VFS_INODE_GET_XTIME(i_ctime, src));
+
}
#endif /* _LINUX_FS_STACK_H */
VFS currently uses struct timespec timestamps which are not y2038 safe. Change all the struct inode timestamps accesses through accessor macros only. This will help the switch over to 64 bit times seamlessly. Use struct inode_timespec aliases everywhere. This will change timestamp data types to struct timespec64 when 64 bit time switch occurs. Change all calls to CURRENT_TIME to current_fs_time(). The CURRENT_TIME macro is not accurate for file system code as it does not perform range checks on timestamps nor does it cater to individual file system timestamp granularity. Change all calls to timespec_trunc() to fs_time_trunc(). The latter supports range checking on timestamps. Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com> --- fs/attr.c | 15 +++++++------- fs/bad_inode.c | 10 +++++++-- fs/binfmt_misc.c | 7 +++++-- fs/inode.c | 53 ++++++++++++++++++++++++++++++++---------------- fs/libfs.c | 45 ++++++++++++++++++++++++++++++++-------- fs/locks.c | 5 ++--- fs/nsfs.c | 6 +++++- fs/pipe.c | 6 +++++- fs/posix_acl.c | 2 +- fs/stack.c | 6 +++--- fs/stat.c | 6 +++--- fs/utimes.c | 6 ++++-- include/linux/fs_stack.h | 9 ++++---- 13 files changed, 121 insertions(+), 55 deletions(-)