Re: [RFC][PATCH] xfs: extended timestamp range

Darrick J. Wong
2019-11-11T22:35:17Z

On Mon, Nov 11, 2019 at 11:36:30PM +0200, Amir Goldstein wrote:
> Use similar on-disk encoding for timestamps as ext4 to push back
> the y2038 deadline to 2446.
>
> The encoding uses the 2 free MSB in 32bit nsec field to extend the
> seconds field storage size to 34bit.
>
> Those 2 bits should be zero on existing xfs inodes, so the extended
> timestamp range feature is declared read-only compatible with old
> on-disk format.

What do you think about making the timestamp field a uint64_t counting
nanoseconds since Dec 14 09:15:53 UTC 1901 (a.k.a. the minimum datetime
we support with the existing encoding scheme)? Instead of using the
upper 2 bits of the nsec field for an epoch encoding, which ext4 screwed
up years ago and has not fully fixed?

Also, please change struct xfs_inode.i_crtime to a timespec64 to match
the other three timestamps in struct inode...

...and following the usual xfs indenting style for all the new functions.

--D

> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>
> Hi,
>
> This is a very lightly tested RFC patch.
> Naming and splitting to patches aside, I'd like to know what folks think
> about this direction for fixing y2038 xfs support.
>
> With XFS_TIMESTAMP_DEBUG defined, it provides correct output for test
> generic/402 (timestamp range test), when matching xfs expected timestamp
> ranges to those of ext4 (_filesystem_timestamp_range).
> And then the test (naturally) fails on corrupted fs check.
>
> If this direction is acceptable, I will proceed with patching xfsprogs.
>
> I'd also like to hear your thoughts about migration process.
> Should the new feature be ro_compat as I defined it or incompat?
> In pricipal, all user would need to do is set the feature flag, but
> I am not aware of any precedent of a similar format upgrade in xfs.
>
> Thanks,
> Amir.
>
> fs/xfs/libxfs/xfs_format.h | 14 ++-
> fs/xfs/libxfs/xfs_inode_buf.c | 36 ++++----
> fs/xfs/libxfs/xfs_log_format.h | 4 +-
> fs/xfs/libxfs/xfs_timestamp.h | 151 ++++++++++++++++++++++++++++++++
> fs/xfs/libxfs/xfs_trans_inode.c | 7 +-
> fs/xfs/scrub/inode.c | 11 ++-
> fs/xfs/xfs_inode.c | 4 +-
> fs/xfs/xfs_inode_item.c | 13 ++-
> fs/xfs/xfs_iops.c | 5 +-
> fs/xfs/xfs_itable.c | 3 +-
> fs/xfs/xfs_super.c | 5 +-
> 11 files changed, 208 insertions(+), 45 deletions(-)
> create mode 100644 fs/xfs/libxfs/xfs_timestamp.h
>
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index c968b60cee15..227a775a9889 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -449,10 +449,12 @@ xfs_sb_has_compat_feature(
> #define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */
> #define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */
> #define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */
> +#define XFS_SB_FEAT_RO_COMPAT_EXTTIME (1 << 3) /* extended time_max */
> #define XFS_SB_FEAT_RO_COMPAT_ALL \
> (XFS_SB_FEAT_RO_COMPAT_FINOBT | \
> XFS_SB_FEAT_RO_COMPAT_RMAPBT | \
> - XFS_SB_FEAT_RO_COMPAT_REFLINK)
> + XFS_SB_FEAT_RO_COMPAT_REFLINK | \
> + XFS_SB_FEAT_RO_COMPAT_EXTTIME)
> #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL
> static inline bool
> xfs_sb_has_ro_compat_feature(
> @@ -546,6 +548,12 @@ static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp)
> (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK);
> }
>
> +static inline bool xfs_sb_version_hasexttime(struct xfs_sb *sbp)
> +{
> + return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
> + (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_EXTTIME);
> +}
> +
> /*
> * end of superblock version macros
> */
> @@ -824,8 +832,8 @@ typedef struct xfs_agfl {
> xfs_daddr_to_agno(mp, (d) + (len) - 1)))
>
> typedef struct xfs_timestamp {
> - __be32 t_sec; /* timestamp seconds */
> - __be32 t_nsec; /* timestamp nanoseconds */
> + __be32 t_sec; /* timestamp seconds */
> + __be32 t_nsec_epoch; /* timestamp nanoseconds | extra epoch */
> } xfs_timestamp_t;
>
> /*
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 28ab3c5255e1..aaf411da6263 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -17,6 +17,7 @@
> #include "xfs_trans.h"
> #include "xfs_ialloc.h"
> #include "xfs_dir2.h"
> +#include "xfs_timestamp.h"
>
> #include <linux/iversion.h>
>
> @@ -204,6 +205,7 @@ xfs_inode_from_disk(
> {
> struct xfs_icdinode *to = &ip->i_d;
> struct inode *inode = VFS_I(ip);
> + struct xfs_sb *sbp = &ip->i_mount->m_sb;
>
>
> /*
> @@ -233,12 +235,9 @@ xfs_inode_from_disk(
> * a time before epoch is converted to a time long after epoch
> * on 64 bit systems.
> */
> - inode->i_atime.tv_sec = (int)be32_to_cpu(from->di_atime.t_sec);
> - inode->i_atime.tv_nsec = (int)be32_to_cpu(from->di_atime.t_nsec);
> - inode->i_mtime.tv_sec = (int)be32_to_cpu(from->di_mtime.t_sec);
> - inode->i_mtime.tv_nsec = (int)be32_to_cpu(from->di_mtime.t_nsec);
> - inode->i_ctime.tv_sec = (int)be32_to_cpu(from->di_ctime.t_sec);
> - inode->i_ctime.tv_nsec = (int)be32_to_cpu(from->di_ctime.t_nsec);
> + xfs_timestamp_di_decode(sbp, &inode->i_atime, &from->di_atime);
> + xfs_timestamp_di_decode(sbp, &inode->i_mtime, &from->di_mtime);
> + xfs_timestamp_di_decode(sbp, &inode->i_ctime, &from->di_ctime);
> inode->i_generation = be32_to_cpu(from->di_gen);
> inode->i_mode = be16_to_cpu(from->di_mode);
>
> @@ -257,7 +256,8 @@ xfs_inode_from_disk(
> inode_set_iversion_queried(inode,
> be64_to_cpu(from->di_changecount));
> to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec);
> - to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec);
> + to->di_crtime.t_nsec_epoch =
> + be32_to_cpu(from->di_crtime.t_nsec_epoch);
> to->di_flags2 = be64_to_cpu(from->di_flags2);
> to->di_cowextsize = be32_to_cpu(from->di_cowextsize);
> }
> @@ -271,6 +271,7 @@ xfs_inode_to_disk(
> {
> struct xfs_icdinode *from = &ip->i_d;
> struct inode *inode = VFS_I(ip);
> + struct xfs_sb *sbp = &ip->i_mount->m_sb;
>
> to->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
> to->di_onlink = 0;
> @@ -283,12 +284,9 @@ xfs_inode_to_disk(
> to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
>
> memset(to->di_pad, 0, sizeof(to->di_pad));
> - to->di_atime.t_sec = cpu_to_be32(inode->i_atime.tv_sec);
> - to->di_atime.t_nsec = cpu_to_be32(inode->i_atime.tv_nsec);
> - to->di_mtime.t_sec = cpu_to_be32(inode->i_mtime.tv_sec);
> - to->di_mtime.t_nsec = cpu_to_be32(inode->i_mtime.tv_nsec);
> - to->di_ctime.t_sec = cpu_to_be32(inode->i_ctime.tv_sec);
> - to->di_ctime.t_nsec = cpu_to_be32(inode->i_ctime.tv_nsec);
> + xfs_timestamp_di_encode(sbp, &inode->i_atime, &to->di_atime);
> + xfs_timestamp_di_encode(sbp, &inode->i_mtime, &to->di_mtime);
> + xfs_timestamp_di_encode(sbp, &inode->i_ctime, &to->di_ctime);
> to->di_nlink = cpu_to_be32(inode->i_nlink);
> to->di_gen = cpu_to_be32(inode->i_generation);
> to->di_mode = cpu_to_be16(inode->i_mode);
> @@ -307,7 +305,8 @@ xfs_inode_to_disk(
> if (from->di_version == 3) {
> to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
> to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec);
> - to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec);
> + to->di_crtime.t_nsec_epoch =
> + cpu_to_be32(from->di_crtime.t_nsec_epoch);
> to->di_flags2 = cpu_to_be64(from->di_flags2);
> to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
> to->di_ino = cpu_to_be64(ip->i_ino);
> @@ -338,11 +337,11 @@ xfs_log_dinode_to_disk(
> memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
>
> to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec);
> - to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec);
> + to->di_atime.t_nsec_epoch = cpu_to_be32(from->di_atime.t_nsec_epoch);
> to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec);
> - to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec);
> + to->di_mtime.t_nsec_epoch = cpu_to_be32(from->di_mtime.t_nsec_epoch);
> to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec);
> - to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec);
> + to->di_ctime.t_nsec_epoch = cpu_to_be32(from->di_ctime.t_nsec_epoch);
>
> to->di_size = cpu_to_be64(from->di_size);
> to->di_nblocks = cpu_to_be64(from->di_nblocks);
> @@ -359,7 +358,8 @@ xfs_log_dinode_to_disk(
> if (from->di_version == 3) {
> to->di_changecount = cpu_to_be64(from->di_changecount);
> to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec);
> - to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec);
> + to->di_crtime.t_nsec_epoch =
> + cpu_to_be32(from->di_crtime.t_nsec_epoch);
> to->di_flags2 = cpu_to_be64(from->di_flags2);
> to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
> to->di_ino = cpu_to_be64(from->di_ino);
> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
> index e5f97c69b320..08f9d119e0d5 100644
> --- a/fs/xfs/libxfs/xfs_log_format.h
> +++ b/fs/xfs/libxfs/xfs_log_format.h
> @@ -369,8 +369,8 @@ static inline int xfs_ilog_fdata(int w)
> * information.
> */
> typedef struct xfs_ictimestamp {
> - int32_t t_sec; /* timestamp seconds */
> - int32_t t_nsec; /* timestamp nanoseconds */
> + int32_t t_sec; /* timestamp seconds */
> + uint32_t t_nsec_epoch; /* timestamp nanoseconds | extra epoch */
> } xfs_ictimestamp_t;
>
> /*
> diff --git a/fs/xfs/libxfs/xfs_timestamp.h b/fs/xfs/libxfs/xfs_timestamp.h
> new file mode 100644
> index 000000000000..b514a9f40704
> --- /dev/null
> +++ b/fs/xfs/libxfs/xfs_timestamp.h
> @@ -0,0 +1,151 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2019 CTERA Networks.
> + * All Rights Reserved.
> + */
> +#ifndef __XFS_TIMESTAMP_H__
> +#define __XFS_TIMESTAMP_H__
> +
> +//#define XFS_TIMESTAMP_DEBUG
> +
> +#ifdef XFS_TIMESTAMP_DEBUG
> +#define XFS_TIMESTAMP_EXTENDED(sbp) 1
> +#else
> +#define XFS_TIMESTAMP_EXTENDED(sbp) xfs_sb_version_hasexttime(sbp)
> +#endif
> +
> +/*
> + * We use 2 unused msb of 32bit t_nsec to encode time ranges beyond y2038.
> + *
> + * We use an encoding that preserves the times for extra epoch "00":
> + *
> + * 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
> + */
> +
> +#define XFS_TIMESTAMP_NSEC_BITS 30
> +#define XFS_TIMESTAMP_NSEC_MASK ((1U << XFS_TIMESTAMP_NSEC_BITS) - 1)
> +#define XFS_TIMESTAMP_NSEC(nsec_epoch) ((nsec_epoch) & XFS_TIMESTAMP_NSEC_MASK)
> +#define XFS_TIMESTAMP_EPOCH_SHIFT XFS_TIMESTAMP_NSEC_BITS
> +#define XFS_TIMESTAMP_EPOCH_BITS (32 - XFS_TIMESTAMP_NSEC_BITS)
> +#define XFS_TIMESTAMP_EPOCH_MASK (((1U << XFS_TIMESTAMP_EPOCH_BITS) \
> + - 1) << XFS_TIMESTAMP_EPOCH_SHIFT)
> +#define XFS_TIMESTAMP_SEC_BITS (32 + XFS_TIMESTAMP_EPOCH_BITS)
> +
> +#define XFS_TIMESTAMP_SEC_MIN S32_MIN
> +#define XFS_TIMESTAMP_SEC32_MAX S32_MAX
> +#define XFS_TIMESTAMP_SEC64_MAX ((1LL << XFS_TIMESTAMP_SEC_BITS) \
> + - 1 + S32_MIN)
> +#define XFS_TIMESTAMP_SEC_MAX(sbp) \
> + (XFS_TIMESTAMP_EXTENDED(sbp) ? XFS_TIMESTAMP_SEC64_MAX : \
> + XFS_TIMESTAMP_SEC32_MAX)
> +
> +
> +static inline int64_t xfs_timestamp_decode_sec64(int32_t sec32,
> + uint32_t nsec_epoch)
> +{
> + int64_t sec64 = sec32;
> +
> + if (unlikely(nsec_epoch & XFS_TIMESTAMP_EPOCH_MASK)) {
> + sec64 += ((int64_t)(nsec_epoch & XFS_TIMESTAMP_EPOCH_MASK)) <<
> + XFS_TIMESTAMP_EPOCH_BITS;
> +#ifdef XFS_TIMESTAMP_DEBUG
> + pr_info("%s: %lld.%d epoch=%x sec32=%d", __func__, sec64,
> + XFS_TIMESTAMP_NSEC(nsec_epoch),
> + (nsec_epoch & XFS_TIMESTAMP_EPOCH_MASK), sec32);
> +#endif
> + }
> + return sec64;
> +}
> +
> +static inline int64_t xfs_timestamp_sec64(struct xfs_sb *sbp, int32_t sec32,
> + uint32_t nsec_epoch)
> +{
> + return XFS_TIMESTAMP_EXTENDED(sbp) ?
> + xfs_timestamp_decode_sec64(sec32, nsec_epoch) : sec32;
> +}
> +
> +static inline bool xfs_timestamp_nsec_is_valid(struct xfs_sb *sbp,
> + uint32_t nsec_epoch)
> +{
> + if (!XFS_TIMESTAMP_EXTENDED(sbp) &&
> + (nsec_epoch & XFS_TIMESTAMP_EPOCH_MASK))
> + return false;
> +
> + return XFS_TIMESTAMP_NSEC(nsec_epoch) < NSEC_PER_SEC;
> +}
> +
> +static inline bool xfs_timestamp_is_valid(struct xfs_sb *sbp,
> + xfs_timestamp_t *dtsp)
> +{
> + return xfs_timestamp_nsec_is_valid(sbp,
> + be32_to_cpu(dtsp->t_nsec_epoch));
> +}
> +
> +static inline void xfs_timestamp_ic_decode(struct xfs_sb *sbp,
> + struct timespec64 *time,
> + xfs_ictimestamp_t *itsp)
> +{
> + time->tv_sec = xfs_timestamp_sec64(sbp, itsp->t_sec,
> + itsp->t_nsec_epoch);
> + time->tv_nsec = XFS_TIMESTAMP_NSEC(itsp->t_nsec_epoch);
> +}
> +
> +static inline void xfs_timestamp_di_decode(struct xfs_sb *sbp,
> + struct timespec64 *time,
> + xfs_timestamp_t *dtsp)
> +{
> + time->tv_sec = xfs_timestamp_sec64(sbp, be32_to_cpu(dtsp->t_sec),
> + be32_to_cpu(dtsp->t_nsec_epoch));
> + time->tv_nsec = XFS_TIMESTAMP_NSEC(be32_to_cpu(dtsp->t_nsec_epoch));
> +}
> +
> +static inline int32_t xfs_timestamp_encode_nsec_epoch(int64_t sec64,
> + int32_t nsec)
> +{
> + int32_t epoch = ((sec64 - (int32_t)sec64) >> XFS_TIMESTAMP_EPOCH_BITS) &
> + XFS_TIMESTAMP_EPOCH_MASK;
> +
> +#ifdef XFS_TIMESTAMP_DEBUG
> + if (epoch)
> + pr_info("%s: %lld.%d epoch=%x sec32=%d", __func__, sec64, nsec,
> + epoch, (int32_t)sec64);
> +#endif
> + return (nsec & XFS_TIMESTAMP_NSEC_MASK) | epoch;
> +}
> +
> +static inline int32_t xfs_timestamp_nsec_epoch(struct xfs_sb *sbp,
> + int64_t sec64, int32_t nsec)
> +{
> + return XFS_TIMESTAMP_EXTENDED(sbp) ?
> + xfs_timestamp_encode_nsec_epoch(sec64, nsec) : nsec;
> +}
> +
> +static inline void xfs_timestamp_ic_encode(struct xfs_sb *sbp,
> + struct timespec64 *time,
> + xfs_ictimestamp_t *itsp)
> +{
> + itsp->t_sec = (int32_t)time->tv_sec;
> + itsp->t_nsec_epoch = xfs_timestamp_nsec_epoch(sbp, time->tv_sec,
> + time->tv_nsec);
> +}
> +
> +static inline void xfs_timestamp_di_encode(struct xfs_sb *sbp,
> + struct timespec64 *time,
> + xfs_timestamp_t *dtsp)
> +{
> + dtsp->t_sec = cpu_to_be32(time->tv_sec);
> + dtsp->t_nsec_epoch = cpu_to_be32(xfs_timestamp_nsec_epoch(sbp,
> + time->tv_sec, time->tv_nsec));
> +}
> +
> +#endif /* __XFS_TIMESTAMP_H__ */
> diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
> index a9ad90926b87..48c9c9e3654d 100644
> --- a/fs/xfs/libxfs/xfs_trans_inode.c
> +++ b/fs/xfs/libxfs/xfs_trans_inode.c
> @@ -8,10 +8,13 @@
> #include "xfs_shared.h"
> #include "xfs_format.h"
> #include "xfs_log_format.h"
> +#include "xfs_trans_resv.h"
> +#include "xfs_mount.h"
> #include "xfs_inode.h"
> #include "xfs_trans.h"
> #include "xfs_trans_priv.h"
> #include "xfs_inode_item.h"
> +#include "xfs_timestamp.h"
>
> #include <linux/iversion.h>
>
> @@ -67,8 +70,8 @@ xfs_trans_ichgtime(
> if (flags & XFS_ICHGTIME_CHG)
> inode->i_ctime = tv;
> if (flags & XFS_ICHGTIME_CREATE) {
> - ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec;
> - ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec;
> + xfs_timestamp_ic_encode(&ip->i_mount->m_sb, &tv,
> + &ip->i_d.di_crtime);
> }
> }
>
> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
> index 6d483ab29e63..981f86387dc3 100644
> --- a/fs/xfs/scrub/inode.c
> +++ b/fs/xfs/scrub/inode.c
> @@ -17,6 +17,7 @@
> #include "xfs_reflink.h"
> #include "xfs_rmap.h"
> #include "xfs_bmap_util.h"
> +#include "xfs_timestamp.h"
> #include "scrub/scrub.h"
> #include "scrub/common.h"
> #include "scrub/btree.h"
> @@ -293,11 +294,9 @@ xchk_dinode(
> }
>
> /* di_[amc]time.nsec */
> - if (be32_to_cpu(dip->di_atime.t_nsec) >= NSEC_PER_SEC)
> - xchk_ino_set_corrupt(sc, ino);
> - if (be32_to_cpu(dip->di_mtime.t_nsec) >= NSEC_PER_SEC)
> - xchk_ino_set_corrupt(sc, ino);
> - if (be32_to_cpu(dip->di_ctime.t_nsec) >= NSEC_PER_SEC)
> + if (!xfs_timestamp_is_valid(&mp->m_sb, &dip->di_atime) ||
> + !xfs_timestamp_is_valid(&mp->m_sb, &dip->di_mtime) ||
> + !xfs_timestamp_is_valid(&mp->m_sb, &dip->di_ctime))
> xchk_ino_set_corrupt(sc, ino);
>
> /*
> @@ -403,7 +402,7 @@ xchk_dinode(
> }
>
> if (dip->di_version >= 3) {
> - if (be32_to_cpu(dip->di_crtime.t_nsec) >= NSEC_PER_SEC)
> + if (!xfs_timestamp_is_valid(&mp->m_sb, &dip->di_crtime))
> xchk_ino_set_corrupt(sc, ino);
> xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
> xchk_inode_cowextsize(sc, dip, ino, mode, flags,
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index a92d4521748d..ca1538b31170 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -35,6 +35,7 @@
> #include "xfs_log.h"
> #include "xfs_bmap_btree.h"
> #include "xfs_reflink.h"
> +#include "xfs_timestamp.h"
>
> kmem_zone_t *xfs_inode_zone;
>
> @@ -851,8 +852,7 @@ xfs_ialloc(
> inode_set_iversion(inode, 1);
> ip->i_d.di_flags2 = 0;
> ip->i_d.di_cowextsize = 0;
> - ip->i_d.di_crtime.t_sec = (int32_t)tv.tv_sec;
> - ip->i_d.di_crtime.t_nsec = (int32_t)tv.tv_nsec;
> + xfs_timestamp_ic_encode(&mp->m_sb, &tv, &ip->i_d.di_crtime);
> }
>
>
> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
> index 726aa3bfd6e8..2b5db9af6a9d 100644
> --- a/fs/xfs/xfs_inode_item.c
> +++ b/fs/xfs/xfs_inode_item.c
> @@ -18,6 +18,7 @@
> #include "xfs_buf_item.h"
> #include "xfs_log.h"
> #include "xfs_error.h"
> +#include "xfs_timestamp.h"
>
> #include <linux/iversion.h>
>
> @@ -303,6 +304,7 @@ xfs_inode_to_log_dinode(
> {
> struct xfs_icdinode *from = &ip->i_d;
> struct inode *inode = VFS_I(ip);
> + struct xfs_sb *sbp = &ip->i_mount->m_sb;
>
> to->di_magic = XFS_DINODE_MAGIC;
>
> @@ -315,12 +317,9 @@ xfs_inode_to_log_dinode(
>
> memset(to->di_pad, 0, sizeof(to->di_pad));
> memset(to->di_pad3, 0, sizeof(to->di_pad3));
> - to->di_atime.t_sec = inode->i_atime.tv_sec;
> - to->di_atime.t_nsec = inode->i_atime.tv_nsec;
> - to->di_mtime.t_sec = inode->i_mtime.tv_sec;
> - to->di_mtime.t_nsec = inode->i_mtime.tv_nsec;
> - to->di_ctime.t_sec = inode->i_ctime.tv_sec;
> - to->di_ctime.t_nsec = inode->i_ctime.tv_nsec;
> + xfs_timestamp_ic_encode(sbp, &inode->i_atime, &to->di_atime);
> + xfs_timestamp_ic_encode(sbp, &inode->i_mtime, &to->di_mtime);
> + xfs_timestamp_ic_encode(sbp, &inode->i_ctime, &to->di_ctime);
> to->di_nlink = inode->i_nlink;
> to->di_gen = inode->i_generation;
> to->di_mode = inode->i_mode;
> @@ -342,7 +341,7 @@ xfs_inode_to_log_dinode(
> if (from->di_version == 3) {
> to->di_changecount = inode_peek_iversion(inode);
> to->di_crtime.t_sec = from->di_crtime.t_sec;
> - to->di_crtime.t_nsec = from->di_crtime.t_nsec;
> + to->di_crtime.t_nsec_epoch = from->di_crtime.t_nsec_epoch;
> to->di_flags2 = from->di_flags2;
> to->di_cowextsize = from->di_cowextsize;
> to->di_ino = ip->i_ino;
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 4c7962ccb0c4..aa294597d16f 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -21,6 +21,7 @@
> #include "xfs_dir2.h"
> #include "xfs_iomap.h"
> #include "xfs_error.h"
> +#include "xfs_timestamp.h"
>
> #include <linux/xattr.h>
> #include <linux/posix_acl.h>
> @@ -556,8 +557,8 @@ xfs_vn_getattr(
> if (ip->i_d.di_version == 3) {
> if (request_mask & STATX_BTIME) {
> stat->result_mask |= STATX_BTIME;
> - stat->btime.tv_sec = ip->i_d.di_crtime.t_sec;
> - stat->btime.tv_nsec = ip->i_d.di_crtime.t_nsec;
> + xfs_timestamp_ic_decode(&mp->m_sb, &stat->btime,
> + &ip->i_d.di_crtime);
> }
> }
>
> diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
> index 884950adbd16..3e55cf029414 100644
> --- a/fs/xfs/xfs_itable.c
> +++ b/fs/xfs/xfs_itable.c
> @@ -19,6 +19,7 @@
> #include "xfs_error.h"
> #include "xfs_icache.h"
> #include "xfs_health.h"
> +#include "xfs_timestamp.h"
>
> /*
> * Bulk Stat
> @@ -98,7 +99,7 @@ xfs_bulkstat_one_int(
> buf->bs_ctime = inode->i_ctime.tv_sec;
> buf->bs_ctime_nsec = inode->i_ctime.tv_nsec;
> buf->bs_btime = dic->di_crtime.t_sec;
> - buf->bs_btime_nsec = dic->di_crtime.t_nsec;
> + buf->bs_btime_nsec = XFS_TIMESTAMP_NSEC(dic->di_crtime.t_nsec_epoch);
> buf->bs_gen = inode->i_generation;
> buf->bs_mode = inode->i_mode;
>
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index b3188ea49413..b940ce6dac07 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -35,6 +35,7 @@
> #include "xfs_refcount_item.h"
> #include "xfs_bmap_item.h"
> #include "xfs_reflink.h"
> +#include "xfs_timestamp.h"
>
> #include <linux/magic.h>
> #include <linux/fs_context.h>
> @@ -1438,8 +1439,8 @@ xfs_fc_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_time_min = XFS_TIMESTAMP_SEC_MIN;
> + sb->s_time_max = XFS_TIMESTAMP_SEC_MAX(&mp->m_sb);
> sb->s_iflags |= SB_I_CGROUPWB;
>
> set_posix_acl_flag(sb);
> --
> 2.17.1
>