The first two patches contain the basic framework for the 64 bit time migration for filesystems. The next two patches shows how the framework has been adapted to vfs layer and cifs filesystem.
There might be some minor changes or additions required as I start adapting to other filesystems.
The change to timestamp conversion functions(to and from unix format to others) and range checks will be part of a separate series.
Changes since v1: * move SYSTEM_TIME macros to fs.h * add 64 bit version of CURRENT_TIME macros.
Deepa Dinamani (4): vfs: Add 64 bit time support kernel: time: Add macros and functions to support 64 bit time vfs: Add support for vfs code to use 64 bit time. fs: cifs: Add support for cifs to use 64 bit time
fs/attr.c | 14 ++++----- fs/bad_inode.c | 9 ++++-- fs/binfmt_misc.c | 7 +++-- fs/cifs/cache.c | 16 ++++++---- fs/cifs/cifsencrypt.c | 2 +- fs/cifs/cifsglob.h | 6 ++-- fs/cifs/cifsproto.h | 7 +++-- fs/cifs/cifssmb.c | 9 ++++-- fs/cifs/file.c | 9 ++++-- fs/cifs/inode.c | 68 +++++++++++++++++++++++++--------------- fs/cifs/netmisc.c | 10 +++--- fs/inode.c | 44 ++++++++++++++++---------- fs/libfs.c | 58 +++++++++++++++++++++++++--------- fs/locks.c | 5 ++- fs/nsfs.c | 6 +++- fs/pipe.c | 6 +++- fs/posix_acl.c | 2 +- fs/stat.c | 6 ++-- fs/utimes.c | 4 +-- include/linux/fs.h | 85 +++++++++++++++++++++++++++++++++++++++++++------- include/linux/stat.h | 6 ++-- include/linux/time64.h | 39 +++++++++++++++++++++++ kernel/time/time.c | 65 +++++++++++++++++++++++++++++++++++++- 23 files changed, 366 insertions(+), 117 deletions(-)
The current representation of inode times in struct inode, struct iattr, and struct kstat use struct timespec. timespec is not y2038 safe.
Use struct inode_time for struct inode timestamp fields to maintain same size for times across 32 bit and 64 bit architectures. In addition, inode_time is defined as packed and aligned to a 4 byte boundary to make the structure use 12 bytes instead of 16 bytes. This will help save RAM space as inode structure is cached in memory. The other structures are transient and do not benefit from these changes. The pahole tool shows that this also uses up a 4 byte hole(on 64 bit arch) in the inode structure also contributing to space savings.
Add accessors for inode times. These provide a way to access the packed structure. Accessors abstract the timestamp representation so that any logic to convert between the struct inode timestamps and other interfaces can be placed here. This helps contain the inode_time structure within the context of struct inode.
The plan is to globally change all references to these types through these accessors only. So when the actual internal representation changes, it will be transparent to the outside world.
Add inode_timespec aliases to help convert kstat and iattr times to use 64 bit times. These hide the internal data type. Use uapi exposed data types here to keep minimal timstamp data type conversions in API's interfacing with vfs.
After the CONFIG_FS_USES_64BIT_TIME is enabled, all inode_timespec aliases will be removed and timespec64 data types and API's will be used directly.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com --- include/linux/fs.h | 69 ++++++++++++++++++++++++++++++++++++++++++-------- include/linux/stat.h | 6 ++--- include/linux/time64.h | 35 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 13 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h index 14ffad4..3b018c6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -245,13 +245,13 @@ typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate); */ struct iattr { unsigned int ia_valid; - umode_t ia_mode; - kuid_t ia_uid; - kgid_t ia_gid; - loff_t ia_size; - struct timespec ia_atime; - struct timespec ia_mtime; - struct timespec ia_ctime; + umode_t ia_mode; + kuid_t ia_uid; + kgid_t ia_gid; + loff_t ia_size; + struct inode_timespec ia_atime; + struct inode_timespec ia_mtime; + struct inode_timespec ia_ctime;
/* * Not an attribute, but an auxiliary info for filesystems wanting to @@ -616,9 +616,9 @@ struct inode { }; dev_t i_rdev; loff_t i_size; - struct timespec i_atime; - struct timespec i_mtime; - struct timespec i_ctime; + struct inode_time i_atime; + struct inode_time i_mtime; + struct inode_time i_ctime; spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ unsigned short i_bytes; unsigned int i_blkbits; @@ -679,6 +679,55 @@ struct inode { void *i_private; /* fs or device private pointer */ };
+#ifdef CONFIG_FS_USES_64BIT_TIME + +#if __BITS_PER_LONG == 64 +static inline struct timespec64 +inode_get_inode_time(const struct inode_time *itime) +{ + return (struct timespec64) { + .tv_sec = itime->tv_sec; + .tv_nsec = itime->tv_nsec; + }; +} + +static inline void +inode_set_inode_time(struct inode_time *itime, const struct timespec64 ts64) +{ + itime->tv_sec = ts64.tv_sec; + itime->tv_nsec = ts64.tv_nsec; +} + +#else + +static inline struct timespec64 +inode_get_inode_time(const struct inode_time *itime) +{ + return *itime; +} + +static inline void +inode_set_inode_time(struct inode_time *itime, const struct timespec64 ts64) +{ + *itime = ts64; +} + +#endif +#else +static inline struct timespec +inode_get_inode_time(const struct timespec *itime) +{ + return *itime; +} + +static inline void +inode_set_inode_time(struct timespec *itime, const struct timespec ts) +{ + *itime = ts; +} + +#endif + static inline int inode_unhashed(struct inode *inode) { return hlist_unhashed(&inode->i_hash); diff --git a/include/linux/stat.h b/include/linux/stat.h index 075cb0c..559983f 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h @@ -27,9 +27,9 @@ struct kstat { kgid_t gid; dev_t rdev; loff_t size; - struct timespec atime; - struct timespec mtime; - struct timespec ctime; + struct inode_timespec atime; + struct inode_timespec mtime; + struct inode_timespec ctime; unsigned long blksize; unsigned long long blocks; }; diff --git a/include/linux/time64.h b/include/linux/time64.h index 367d5af..43ad63b 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -26,6 +26,41 @@ struct itimerspec64 {
#endif
+#ifdef CONFIG_FS_USES_64BIT_TIME + +/* + * Internal kernel representation of inode time fields. + * This structure is not exposed to userspace. + * Use struct timespec64 representation for all userspace. + */ +#if __BITS_PER_LONG == 64 +struct inode_time { + time64_t tv_sec; + s32 tv_nsec; +} __aligned(4) __packed; +#else +#define inode_time timespec64 +#endif +/* A place holder define until CONFIG_FS_USES_64BIT_TIME + * is enabled. + * timespec64 data type and functions will be used at that + * time directly and these defines will be deleted. + */ +#define inode_timespec timespec64 + +#define inode_timespec_compare timespec64_compare +#define inode_timespec_equal timespec64_equal + +#else +#define inode_time timespec + +#define inode_timespec timespec + +#define inode_timespec_compare timespec_compare +#define inode_timespec_equal timespec_equal + +#endif + /* Parameters used to convert the timespec values: */ #define MSEC_PER_SEC 1000L #define USEC_PER_MSEC 1000L
The current_fs_time function is not y2038 safe because of the use of struct timespec.
The macros CURRENT_TIME and CURRENT_TIME_SEC do not represent file system times correctly as they cannnot perform range checks or truncations. These are also not y2038 safe. Add 64 bit versions of the above macros.
Provide a new set of SYSTEM_TIME macros which will return time in timespec or timespec64 based on CONFIG_FS_USES_64_BIT_TIME. These are meant to be used only within file systems because of being tied to the above config. Once the config is enabled, the timespec version of it can be deleted and the 64 bit time version can be used elsewhere also.
Add struct timespec64 version for current_fs_time(). Current version of current_fs_time() can be dropped after enabling CONFIG_FS_USES_64BIT_TIME.
Provide an alternative to timespec_trunc(): fs_time_trunc(). This function takes super block as an argument in addition to timestamp so that it can include range and precision checks. Additionally, the function uses y2038 safe timespec64 instead of timespec for timestamp representation.
Add function: current_fs_time_sec() to obtain only the seconds portion of the current time(Equivalent to CURRENT_TIME_SEC). This function has two versions selected by the config CONFIG_FS_USES_64BIT_TIME. The 32 bit version support can be dropped after the above config is enabled globally.
All calls to timespec_trunc() will be eventually replaced by fs_time_trunc(). At which point, timespec_trunc() can be deleted.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com --- include/linux/fs.h | 16 ++++++++++++- include/linux/time64.h | 4 ++++ kernel/time/time.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h index 3b018c6..004982a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1424,7 +1424,21 @@ struct super_block { struct list_head s_inodes; /* all inodes */ };
-extern struct timespec current_fs_time(struct super_block *sb); +/* Temporary macros to be used within fs code for current times. + * To aid moving all of fs code to timespec64. + */ +#ifdef CONFIG_FS_USES_64BIT_TIME +#define SYSTEM_TIME CURRENT_TIME64 +#define SYSTEM_TIME_SEC CURRENT_TIME64_SEC +#else +#define SYSTEM_TIME CURRENT_TIME +#define SYSTEM_TIME_SEC CURRENT_TIME_SEC +#endif + +extern struct inode_timespec current_fs_time(struct super_block *sb); +extern struct inode_timespec current_fs_time_sec(struct super_block *sb); +extern struct inode_timespec +fs_time_trunc(struct inode_timespec ts, struct super_block *sb);
/* * Snapshotting support. diff --git a/include/linux/time64.h b/include/linux/time64.h index 43ad63b..1556efc 100644 --- a/include/linux/time64.h +++ b/include/linux/time64.h @@ -28,6 +28,10 @@ struct itimerspec64 {
#ifdef CONFIG_FS_USES_64BIT_TIME
+#define CURRENT_TIME64 (current_kernel_time64()) +#define CURRENT_TIME64_SEC \ + ((struct timespec64) { ktime_get_real_seconds(), 0 }) + /* * Internal kernel representation of inode time fields. * This structure is not exposed to userspace. diff --git a/kernel/time/time.c b/kernel/time/time.c index 86751c6..3b8ba4a 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -237,13 +237,42 @@ SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p) * Return the current time truncated to the time granularity supported by * the fs. */ +#ifdef CONFIG_FS_USES_64BIT_TIME +struct timespec64 current_fs_time(struct super_block *sb) +{ + struct timespec64 now = current_kernel_time64(); + + return fs_time_trunc(now, sb); +} +EXPORT_SYMBOL(current_fs_time); + +struct timespec64 current_fs_time_sec(struct super_block *sb) +{ + struct timespec64 ts = {ktime_get_real_seconds(), 0}; + + /* TODO: Add range check for time. */ + return ts; +} +EXPORT_SYMBOL(current_fs_time_sec); +#else struct timespec current_fs_time(struct super_block *sb) { struct timespec now = current_kernel_time(); - return timespec_trunc(now, sb->s_time_gran); + + return fs_time_trunc(now, sb); } EXPORT_SYMBOL(current_fs_time);
+struct timespec current_fs_time_sec(struct super_block *sb) +{ + struct timespec ts = { get_seconds(), 0 }; + + /* TODO: Add range check for time. */ + return ts; +} +EXPORT_SYMBOL(current_fs_time_sec); +#endif + /* * Convert jiffies to milliseconds and back. * @@ -286,6 +315,36 @@ unsigned int jiffies_to_usecs(const unsigned long j) } EXPORT_SYMBOL(jiffies_to_usecs);
+/* + * fs_time_trunc - Truncate inode_timespec to a granularity + * @t: inode_timespec + * @sb: Super block. + * + * Truncate a timespec to a granularity. Always rounds down. Granularity + * must * not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns). + */ + +struct inode_timespec +fs_time_trunc(struct inode_timespec t, struct super_block *sb) +{ + u32 gran = sb->s_time_gran; + + /* TODO: Add range check for time. */ + + /* 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, "illegal file time granularity: %u", gran); + + return t; +} +EXPORT_SYMBOL(fs_time_trunc); + /** * timespec_trunc - Truncate timespec to a granularity * @t: Timespec @@ -293,6 +352,9 @@ EXPORT_SYMBOL(jiffies_to_usecs); * * Truncate a timespec to a granularity. Always rounds down. gran must * not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns). + * + * This function is deprecated and should no longer be used for filesystems. + * fs_time_trunc should be used instead. */ struct timespec timespec_trunc(struct timespec t, unsigned gran) { @@ -308,6 +370,7 @@ struct timespec timespec_trunc(struct timespec t, unsigned gran) } return t; } + EXPORT_SYMBOL(timespec_trunc);
/*
VFS currently uses struct timespec timestamps which are not y2038 safe.
Change all the struct inode timestamps accesses through accessor functions only. This will help the switch over to 64 bit times seamlessly.
Change all struct iattr and struct kstat timestamps to use struct inode_timespec. This will use 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 later will be extended to support range checking on timestamps.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com --- fs/attr.c | 14 +++++++------- fs/bad_inode.c | 9 +++++++-- fs/binfmt_misc.c | 7 +++++-- fs/inode.c | 44 ++++++++++++++++++++++++++---------------- fs/libfs.c | 58 +++++++++++++++++++++++++++++++++++++++++--------------- fs/locks.c | 5 ++--- fs/nsfs.c | 6 +++++- fs/pipe.c | 6 +++++- fs/posix_acl.c | 2 +- fs/stat.c | 6 +++--- fs/utimes.c | 4 ++-- 11 files changed, 108 insertions(+), 53 deletions(-)
diff --git a/fs/attr.c b/fs/attr.c index 6530ced..d42af4c 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -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); + inode_set_inode_time(&inode->i_atime, 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); + inode_set_inode_time(&inode->i_mtime, 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); + inode_set_inode_time(&inode->i_ctime, 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)); diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 103f5d7..20cf831 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -169,11 +169,16 @@ 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); + inode_set_inode_time(&inode->i_atime, now); + inode_set_inode_time(&inode->i_mtime, now); + inode_set_inode_time(&inode->i_ctime, now); inode->i_op = &bad_inode_ops; inode->i_fop = &bad_file_ops; } diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 78f005f..48ae5ff 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -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); + inode_set_inode_time(&inode->i_atime, now); + inode_set_inode_time(&inode->i_mtime, now); + inode_set_inode_time(&inode->i_ctime, now); } return inode; } diff --git a/fs/inode.c b/fs/inode.c index 59e55ee..0318472 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -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 = inode_get_inode_time(&inode->i_atime); + ctime = inode_get_inode_time(&inode->i_ctime); + mtime = inode_get_inode_time(&inode->i_mtime); + /* * 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,18 @@ 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; + inode_set_inode_time(&inode->i_atime, *time); if (flags & S_VERSION) inode_inc_iversion(inode); if (flags & S_CTIME) - inode->i_ctime = *time; + inode_set_inode_time(&inode->i_ctime, *time); if (flags & S_MTIME) - inode->i_mtime = *time; + inode_set_inode_time(&inode->i_mtime, *time);
if (!(inode->i_sb->s_flags & MS_LAZYTIME) || (flags & S_VERSION)) iflags |= I_DIRTY_SYNC; @@ -1584,9 +1593,9 @@ 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 +1615,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; @@ -1625,7 +1635,8 @@ bool atime_needs_update(const struct path *path, struct inode *inode) if (!relatime_need_update(mnt, inode, now)) return false;
- if (timespec_equal(&inode->i_atime, &now)) + atime = inode_get_inode_time(&inode->i_atime); + if (inode_timespec_equal(&atime, &now)) return false;
return true; @@ -1635,7 +1646,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 +1781,8 @@ 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; + int sync_it = 0; int ret;
@@ -1779,10 +1791,10 @@ int file_update_time(struct file *file) return 0;
now = current_fs_time(inode->i_sb); - if (!timespec_equal(&inode->i_mtime, &now)) + if (!inode_timespec_equal(&inode->i_mtime, &now)) sync_it = S_MTIME;
- if (!timespec_equal(&inode->i_ctime, &now)) + if (!inode_timespec_equal(&inode->i_ctime, &now)) sync_it |= S_CTIME;
if (IS_I_VERSION(inode)) diff --git a/fs/libfs.c b/fs/libfs.c index c7cbfb0..dc68627 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -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)) @@ -237,7 +238,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); + inode_set_inode_time(&root->i_atime, now); + inode_set_inode_time(&root->i_ctime, now); + inode_set_inode_time(&root->i_mtime, now); + dentry = __d_alloc(s, &d_name); if (!dentry) { iput(root); @@ -266,8 +271,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; + inode_set_inode_time(&inode->i_ctime, now); + inode_set_inode_time(&dir->i_mtime, now); + inode_set_inode_time(&dir->i_ctime, now); inc_nlink(inode); ihold(inode); dget(dentry); @@ -300,8 +308,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; + inode_set_inode_time(&inode->i_ctime, now); + inode_set_inode_time(&dir->i_mtime, now); + inode_set_inode_time(&dir->i_ctime, now); drop_nlink(inode); dput(dentry); return 0; @@ -325,6 +336,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; @@ -340,8 +352,12 @@ 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); + inode_set_inode_time(&old_dir->i_ctime, now); + inode_set_inode_time(&old_dir->i_mtime, now); + inode_set_inode_time(&new_dir->i_ctime, now); + inode_set_inode_time(&new_dir->i_mtime, now); + inode_set_inode_time(&inode->i_ctime, now);
return 0; } @@ -415,13 +431,13 @@ EXPORT_SYMBOL(simple_write_begin); /** * simple_write_end - .write_end helper for non-block-device FSes * @available: See .write_end of address_space_operations - * @file: " - * @mapping: " - * @pos: " - * @len: " - * @copied: " - * @page: " - * @fsdata: " + * @file: " + * @mapping: " + * @pos: " + * @len: " + * @copied: " + * @page: " + * @fsdata: " * * simple_write_end does the minimum needed for updating a page after writing is * done. It has the same API signature as the .write_end of @@ -475,6 +491,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; @@ -492,7 +509,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); + inode_set_inode_time(&inode->i_atime, now); + inode_set_inode_time(&inode->i_mtime, now); + inode_set_inode_time(&inode->i_ctime, now); inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; set_nlink(inode, 2); @@ -518,7 +538,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); + inode_set_inode_time(&inode->i_atime, now); + inode_set_inode_time(&inode->i_mtime, now); + inode_set_inode_time(&inode->i_ctime, now); inode->i_fop = files->ops; inode->i_ino = i; d_add(dentry, inode); @@ -1051,6 +1074,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); @@ -1069,7 +1093,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); + inode_set_inode_time(&inode->i_atime, now); + inode_set_inode_time(&inode->i_mtime, now); + inode_set_inode_time(&inode->i_ctime, now); + return inode; } EXPORT_SYMBOL(alloc_anon_inode); diff --git a/fs/locks.c b/fs/locks.c index d2ee8e3..0f3705e 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1496,7 +1496,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; @@ -1515,9 +1515,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 = inode_get_inode_time(&inode->i_mtime); } - EXPORT_SYMBOL(lease_get_mtime);
/** diff --git a/fs/nsfs.c b/fs/nsfs.c index 8f20d60..a94e1e5 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -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); + inode_set_inode_time(&inode->i_atime, now); + inode_set_inode_time(&inode->i_ctime, now); + inode_set_inode_time(&inode->i_mtime, now); inode->i_flags |= S_IMMUTABLE; inode->i_mode = S_IFREG | S_IRUGO; inode->i_fop = &ns_file_operations; diff --git a/fs/pipe.c b/fs/pipe.c index 42cf8dd..ae5dca7 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -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); + inode_set_inode_time(&inode->i_atime, now); + inode_set_inode_time(&inode->i_ctime, now); + inode_set_inode_time(&inode->i_mtime, now);
return inode;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 4adde1e..8edcdac 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -874,7 +874,7 @@ int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type) acl = NULL; }
- inode->i_ctime = CURRENT_TIME; + inode_set_inode_time(&inode->i_ctime, current_fs_time(inode->i_sb)); set_cached_acl(inode, type, acl); return 0; } diff --git a/fs/stat.c b/fs/stat.c index bc045c7..a789ff2 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -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 = inode_get_inode_time(&inode->i_atime); + stat->mtime = inode_get_inode_time(&inode->i_mtime); + stat->ctime = inode_get_inode_time(&inode->i_ctime); stat->blksize = (1 << inode->i_blkbits); stat->blocks = inode->i_blocks; } diff --git a/fs/utimes.c b/fs/utimes.c index aa138d6..9f62694 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -48,7 +48,7 @@ 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; @@ -133,7 +133,7 @@ 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;
Change all struct timespec references to struct inode_timespec. This will help the switch to struct timespec64 when CONFIG_FS_USES_64BIT_TIME is enabled.
Use current_fs_time() instead of CURRENT_TIME macros to help range and precesion checks.
Truncate and perform range checks before saving the times in struct inode.
Switch over connection times to use SYSTEM_TIME macro instead of CURRENT_TIME. Since SYSTEM_TIME is also under the CONFIG_FS_USES_64BIT_TIME this will help the switch to use timespec64.
The time conversion api's will be moved to kernel/time with more generic implementations for all file systems to share. This will be in a separate patch series.
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com --- fs/cifs/cache.c | 16 +++++++----- fs/cifs/cifsencrypt.c | 2 +- fs/cifs/cifsglob.h | 6 ++--- fs/cifs/cifsproto.h | 7 +++--- fs/cifs/cifssmb.c | 9 ++++--- fs/cifs/file.c | 9 ++++--- fs/cifs/inode.c | 68 ++++++++++++++++++++++++++++++++------------------- fs/cifs/netmisc.c | 10 ++++---- 8 files changed, 78 insertions(+), 49 deletions(-)
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index 6c665bf..b662e8a 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c @@ -221,8 +221,8 @@ const struct fscache_cookie_def cifs_fscache_super_index_def = { * Auxiliary data attached to CIFS inode within the cache */ struct cifs_fscache_inode_auxdata { - struct timespec last_write_time; - struct timespec last_change_time; + struct inode_timespec last_write_time; + struct inode_timespec last_change_time; u64 eof; };
@@ -259,8 +259,10 @@ cifs_fscache_inode_get_aux(const void *cookie_netfs_data, void *buffer,
memset(&auxdata, 0, sizeof(auxdata)); auxdata.eof = cifsi->server_eof; - auxdata.last_write_time = cifsi->vfs_inode.i_mtime; - auxdata.last_change_time = cifsi->vfs_inode.i_ctime; + auxdata.last_write_time = + inode_get_inode_time(&cifsi->vfs_inode.i_mtime); + auxdata.last_change_time = + inode_get_inode_time(&cifsi->vfs_inode.i_ctime);
if (maxbuf > sizeof(auxdata)) maxbuf = sizeof(auxdata); @@ -283,8 +285,10 @@ fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data,
memset(&auxdata, 0, sizeof(auxdata)); auxdata.eof = cifsi->server_eof; - auxdata.last_write_time = cifsi->vfs_inode.i_mtime; - auxdata.last_change_time = cifsi->vfs_inode.i_ctime; + auxdata.last_write_time = + inode_get_inode_time(&cifsi->vfs_inode.i_mtime); + auxdata.last_change_time = + inode_get_inode_time(&cifsi->vfs_inode.i_ctime);
if (memcmp(data, &auxdata, datalen) != 0) return FSCACHE_CHECKAUX_OBSOLETE; diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index afa09fc..721676e 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -483,7 +483,7 @@ find_timestamp(struct cifs_ses *ses) blobptr += attrsize; /* advance attr value */ }
- return cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + return cpu_to_le64(cifs_UnixTimeToNT(SYSTEM_TIME)); }
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 472daeb..a25b2e6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1389,9 +1389,9 @@ struct cifs_fattr { dev_t cf_rdev; unsigned int cf_nlink; unsigned int cf_dtype; - struct timespec cf_atime; - struct timespec cf_mtime; - struct timespec cf_ctime; + struct inode_timespec cf_atime; + struct inode_timespec cf_mtime; + struct inode_timespec cf_ctime; };
static inline void free_dfs_info_param(struct dfs_info3_param *param) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index eed7ff5..d2f8fd4 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -126,9 +126,10 @@ extern enum securityEnum select_sectype(struct TCP_Server_Info *server, enum securityEnum requested); extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, const struct nls_table *nls_cp); -extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); -extern u64 cifs_UnixTimeToNT(struct timespec); -extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, +extern struct inode_timespec + cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); +extern u64 cifs_UnixTimeToNT(struct inode_timespec); +extern struct inode_timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset); extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); extern int cifs_get_writer(struct cifsInodeInfo *cinode); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 90b4f9f..2c8b550 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -478,8 +478,9 @@ decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) * this requirement. */ int val, seconds, remain, result; - struct timespec ts, utc; - utc = CURRENT_TIME; + struct inode_timespec ts, utc; + + utc = SYSTEM_TIME; ts = cnvrtDosUnixTm(rsp->SrvTime.Date, rsp->SrvTime.Time, 0); cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n", @@ -4000,7 +4001,9 @@ QInfRetry: if (rc) { cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc); } else if (data) { - struct timespec ts; + + struct inode_timespec ts; + __u32 time = le32_to_cpu(pSMBr->last_write_time);
/* decode response */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0a2752b..a79c664 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1839,6 +1839,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) int bytes_written = 0; struct inode *inode; struct cifsFileInfo *open_file; + struct inode_timespec now;
if (!mapping || !mapping->host) return -EFAULT; @@ -1870,7 +1871,9 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) write_data, to - from, &offset); cifsFileInfo_put(open_file); /* Does mm or vfs already set times? */ - inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); + now = current_fs_time(inode->i_sb); + inode_set_inode_time(&inode->i_atime, now); + inode_set_inode_time(&inode->i_mtime, now); if ((bytes_written > 0) && (offset)) rc = 0; else if (bytes_written < 0) @@ -3567,6 +3570,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, loff_t *poffset) { char *read_data; + struct inode *inode = file_inode(file); int rc;
/* Is the page cached? */ @@ -3584,8 +3588,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, else cifs_dbg(FYI, "Bytes read %d\n", rc);
- file_inode(file)->i_atime = - current_fs_time(file_inode(file)->i_sb); + inode_set_inode_time(&inode->i_atime, current_fs_time(inode->i_sb));
if (PAGE_CACHE_SIZE > rc) memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6b66dd5..fde63b8 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -92,6 +92,7 @@ static void cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) { struct cifsInodeInfo *cifs_i = CIFS_I(inode); + struct inode_timespec mtime;
cifs_dbg(FYI, "%s: revalidating inode %llu\n", __func__, cifs_i->uniqueid); @@ -110,12 +111,13 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr) }
/* revalidate if mtime or size have changed */ - if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) && - cifs_i->server_eof == fattr->cf_eof) { + mtime = inode_get_inode_time(&inode->i_mtime); + if (inode_timespec_equal(&mtime, &fattr->cf_mtime) + && cifs_i->server_eof == fattr->cf_eof) { cifs_dbg(FYI, "%s: inode %llu is unchanged\n", - __func__, cifs_i->uniqueid); - return; - } + __func__, cifs_i->uniqueid); + return; + }
cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n", __func__, cifs_i->uniqueid); @@ -155,13 +157,17 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) { struct cifsInodeInfo *cifs_i = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + struct super_block *sb = inode->i_sb;
cifs_revalidate_cache(inode, fattr);
spin_lock(&inode->i_lock); - inode->i_atime = fattr->cf_atime; - inode->i_mtime = fattr->cf_mtime; - inode->i_ctime = fattr->cf_ctime; + inode_set_inode_time(&inode->i_atime, + fs_time_trunc(fattr->cf_atime, sb)); + inode_set_inode_time(&inode->i_mtime, + fs_time_trunc(fattr->cf_mtime, sb)); + inode_set_inode_time(&inode->i_ctime, + fs_time_trunc(fattr->cf_ctime, sb)); inode->i_rdev = fattr->cf_rdev; cifs_nlink_fattr_to_inode(inode, fattr); inode->i_uid = fattr->cf_uid; @@ -227,10 +233,10 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, fattr->cf_uniqueid = le64_to_cpu(info->UniqueId); fattr->cf_bytes = le64_to_cpu(info->NumOfBytes); fattr->cf_eof = le64_to_cpu(info->EndOfFile); - fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); + fattr->cf_mode = le64_to_cpu(info->Permissions);
/* @@ -288,7 +294,7 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, fattr->cf_uid = uid; } } - + fattr->cf_gid = cifs_sb->mnt_gid; if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) { u64 id = le64_to_cpu(info->Gid); @@ -313,6 +319,7 @@ static void cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) { struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct inode_timespec now;
cifs_dbg(FYI, "creating fake fattr for DFS referral\n");
@@ -320,9 +327,10 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; fattr->cf_uid = cifs_sb->mnt_uid; fattr->cf_gid = cifs_sb->mnt_gid; - fattr->cf_atime = CURRENT_TIME; - fattr->cf_ctime = CURRENT_TIME; - fattr->cf_mtime = CURRENT_TIME; + now = current_fs_time(sb); + fattr->cf_atime = now; + fattr->cf_ctime = now; + fattr->cf_mtime = now; fattr->cf_nlink = 2; fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; } @@ -584,9 +592,10 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ static void cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, - struct cifs_sb_info *cifs_sb, bool adjust_tz, + struct super_block *sb, bool adjust_tz, bool symlink) { + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
memset(fattr, 0, sizeof(*fattr)); @@ -597,7 +606,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, if (info->LastAccessTime) fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); else - fattr->cf_atime = CURRENT_TIME; + fattr->cf_atime = current_fs_time(sb);
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); @@ -657,7 +666,6 @@ cifs_get_file_info(struct file *filp) FILE_ALL_INFO find_data; struct cifs_fattr fattr; struct inode *inode = file_inode(filp); - struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsFileInfo *cfile = filp->private_data; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; @@ -669,7 +677,7 @@ cifs_get_file_info(struct file *filp) rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data); switch (rc) { case 0: - cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false, + cifs_all_info_to_fattr(&fattr, &find_data, inode->i_sb, false, false); break; case -EREMOTE: @@ -751,7 +759,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, }
if (!rc) { - cifs_all_info_to_fattr(&fattr, data, cifs_sb, adjust_tz, + cifs_all_info_to_fattr(&fattr, data, sb, adjust_tz, symlink); } else if (rc == -EREMOTE) { cifs_create_dfs_fattr(&fattr, sb); @@ -1146,7 +1154,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, fid.netfid, current->tgid); /* although we would like to mark the file hidden - if that fails we will still try to rename it */ + if that fails we will still try to rename it */ if (!rc) cifsInode->cifsAttrs = dosattr; else @@ -1232,6 +1240,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) unsigned int xid; char *full_path = NULL; struct inode *inode = d_inode(dentry); + struct inode_timespec now; struct cifsInodeInfo *cifs_inode; struct super_block *sb = dir->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); @@ -1323,9 +1332,11 @@ out_reval: cifs_inode = CIFS_I(inode); cifs_inode->time = 0; /* will force revalidate to get info when needed */ - inode->i_ctime = current_fs_time(sb); + inode_set_inode_time(&inode->i_ctime, current_fs_time(sb)); } - dir->i_ctime = dir->i_mtime = current_fs_time(sb); + now = current_fs_time(sb); + inode_set_inode_time(&dir->i_ctime, now); + inode_set_inode_time(&dir->i_mtime, now); cifs_inode = CIFS_I(dir); CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ unlink_out: @@ -1545,6 +1556,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) struct TCP_Server_Info *server; char *full_path = NULL; struct cifsInodeInfo *cifsInode; + struct inode_timespec now;
cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode);
@@ -1592,8 +1604,10 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) */ cifsInode->time = 0;
- d_inode(direntry)->i_ctime = inode->i_ctime = inode->i_mtime = - current_fs_time(inode->i_sb); + now = current_fs_time(inode->i_sb); + inode_set_inode_time(&d_inode(direntry)->i_ctime, now); + inode_set_inode_time(&inode->i_ctime, now); + inode_set_inode_time(&inode->i_mtime, now);
rmdir_exit: kfree(full_path); @@ -1672,6 +1686,7 @@ cifs_rename2(struct inode *source_dir, struct dentry *source_dentry, struct cifs_tcon *tcon; FILE_UNIX_BASIC_INFO *info_buf_source = NULL; FILE_UNIX_BASIC_INFO *info_buf_target; + struct inode_timespec now; unsigned int xid; int rc, tmprc;
@@ -1765,8 +1780,11 @@ unlink_target: /* force revalidate to go get info when needed */ CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
- source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime = - target_dir->i_mtime = current_fs_time(source_dir->i_sb); + now = current_fs_time(source_dir->i_sb); + inode_set_inode_time(&source_dir->i_ctime, now); + inode_set_inode_time(&source_dir->i_mtime, now); + inode_set_inode_time(&target_dir->i_ctime, now); + inode_set_inode_time(&target_dir->i_mtime, now);
cifs_rename_exit: kfree(info_buf_source); diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index abae6dd..adcc88c 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -918,10 +918,10 @@ smbCalcSize(void *buf) * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) * into Unix UTC (based 1970-01-01, in seconds). */ -struct timespec +struct inode_timespec cifs_NTtimeToUnix(__le64 ntutc) { - struct timespec ts; + struct inode_timespec ts; /* BB what about the timezone? BB */
/* Subtract the NTFS time offset, then convert to 1s intervals. */ @@ -949,7 +949,7 @@ cifs_NTtimeToUnix(__le64 ntutc)
/* Convert the Unix UTC into NT UTC. */ u64 -cifs_UnixTimeToNT(struct timespec t) +cifs_UnixTimeToNT(struct inode_timespec t) { /* Convert to 100ns intervals and then add the NTFS time offset. */ return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; @@ -959,9 +959,9 @@ static const int total_days_of_prev_months[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) +struct inode_timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) { - struct timespec ts; + struct inode_timespec ts; int sec, min, days, month, year; u16 date = le16_to_cpu(le_date); u16 time = le16_to_cpu(le_time);