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.ker...@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
-- 
1.9.1

_______________________________________________
Y2038 mailing list
Y2038@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/y2038

Reply via email to