linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/11] xfs: widen timestamps to deal with y2038
@ 2020-08-26 22:04 Darrick J. Wong
  2020-08-26 22:05 ` [PATCH 01/11] xfs: explicitly define inode timestamp range Darrick J. Wong
                   ` (11 more replies)
  0 siblings, 12 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:04 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: Amir Goldstein, linux-xfs, amir73il, sandeen

Hi all,

This series performs some refactoring of our timestamp and inode
encoding functions, then retrofits the timestamp union to handle
timestamps as a 64-bit nanosecond counter.  Next, it adds bit shifting
to the non-root dquot timer fields to boost their effective size to 34
bits.  These two changes enable correct time handling on XFS through the
year 2486.

On a current V5 filesystem, inodes timestamps are a signed 32-bit
seconds counter, with 0 being the Unix epoch.  Quota timers are an
unsigned 32-bit seconds counter, with 0 also being the Unix epoch.

This means that inode timestamps can range from:
-(2^31-1) (13 Dec 1901) through (2^31-1) (19 Jan 2038).

And quota timers can range from:
0 (1 Jan 1970) through (2^32-1) (7 Feb 2106).

With the bigtime encoding turned on, inode timestamps are an unsigned
64-bit nanoseconds counter, with 0 being the 1901 epoch.  Quota timers
are a 34-bit unsigned second counter right shifted two bits, with 0
being the Unix epoch, and capped at the maximum inode timestamp value.

This means that inode timestamps can range from:
0 (13 Dec 1901) through (2^64-1 / 1e9) (2 Jul 2486)

Quota timers could theoretically range from:
0 (1 Jan 1970) through (((2^34-1) + (2^31-1)) & ~3) (16 Jun 2582).

But with the capping in place, the quota timers maximum is:
max((2^64-1 / 1e9) - (2^31-1), (((2^34-1) + (2^31-1)) & ~3) (2 Jul 2486).

v2: rebase to 5.9, having landed the quota refactoring
v3: various suggestions by Amir and Dave
v4: drop the timestamp unions, add "is bigtime?" predicates everywhere

If you're going to start using this mess, you probably ought to just
pull from my git trees, which are linked below.

This is an extraordinary way to destroy everything.  Enjoy!
Comments and questions are, as always, welcome.

--D

kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=bigtime

xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=bigtime

fstests git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=bigtime
---
 fs/xfs/libxfs/xfs_dquot_buf.c   |   35 +++++++
 fs/xfs/libxfs/xfs_format.h      |  188 ++++++++++++++++++++++++++++++++++++++-
 fs/xfs/libxfs/xfs_fs.h          |    1 
 fs/xfs/libxfs/xfs_ialloc.c      |    4 +
 fs/xfs/libxfs/xfs_inode_buf.c   |  134 ++++++++++++++--------------
 fs/xfs/libxfs/xfs_inode_buf.h   |   17 +++-
 fs/xfs/libxfs/xfs_log_format.h  |    5 -
 fs/xfs/libxfs/xfs_quota_defs.h  |    8 +-
 fs/xfs/libxfs/xfs_sb.c          |    2 
 fs/xfs/libxfs/xfs_shared.h      |    3 +
 fs/xfs/libxfs/xfs_trans_inode.c |   16 +++
 fs/xfs/scrub/inode.c            |   31 +++++-
 fs/xfs/xfs_dquot.c              |   52 +++++++++--
 fs/xfs/xfs_dquot.h              |    3 +
 fs/xfs/xfs_inode.c              |    4 -
 fs/xfs/xfs_inode.h              |    5 +
 fs/xfs/xfs_inode_item.c         |   43 +++++++--
 fs/xfs/xfs_inode_item_recover.c |   92 +++++++++++++++++++
 fs/xfs/xfs_ioctl.c              |    3 -
 fs/xfs/xfs_ondisk.h             |   22 ++++-
 fs/xfs/xfs_qm.c                 |   13 +++
 fs/xfs/xfs_qm.h                 |    4 +
 fs/xfs/xfs_qm_syscalls.c        |   18 ++--
 fs/xfs/xfs_super.c              |   14 ++-
 fs/xfs/xfs_trace.h              |   26 +++++
 fs/xfs/xfs_trans_dquot.c        |    6 +
 26 files changed, 628 insertions(+), 121 deletions(-)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 01/11] xfs: explicitly define inode timestamp range
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-27  6:42   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  2020-08-26 22:05 ` [PATCH 02/11] xfs: refactor quota expiration timer modification Darrick J. Wong
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: Amir Goldstein, linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Formally define the inode timestamp ranges that existing filesystems
support, and switch the vfs timetamp ranges to use it.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/xfs/libxfs/xfs_format.h |   22 ++++++++++++++++++++++
 fs/xfs/xfs_super.c         |    4 ++--
 2 files changed, 24 insertions(+), 2 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index fe129fe16d5f..e57360a8fd16 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -848,11 +848,33 @@ struct xfs_agfl {
 	    ASSERT(xfs_daddr_to_agno(mp, d) == \
 		   xfs_daddr_to_agno(mp, (d) + (len) - 1)))
 
+/*
+ * XFS Timestamps
+ * ==============
+ *
+ * Traditional ondisk inode timestamps consist of signed 32-bit counters for
+ * seconds and nanoseconds; time zero is the Unix epoch, Jan  1 00:00:00 UTC
+ * 1970, which means that the timestamp epoch is the same as the Unix epoch.
+ * Therefore, the ondisk min and max defined here can be used directly to
+ * constrain the incore timestamps on a Unix system.
+ */
 typedef struct xfs_timestamp {
 	__be32		t_sec;		/* timestamp seconds */
 	__be32		t_nsec;		/* timestamp nanoseconds */
 } xfs_timestamp_t;
 
+/*
+ * Smallest possible ondisk seconds value with traditional timestamps.  This
+ * corresponds exactly with the incore timestamp Dec 13 20:45:52 UTC 1901.
+ */
+#define XFS_LEGACY_TIME_MIN	((int64_t)S32_MIN)
+
+/*
+ * Largest possible ondisk seconds value with traditional timestamps.  This
+ * corresponds exactly with the incore timestamp Jan 19 03:14:07 UTC 2038.
+ */
+#define XFS_LEGACY_TIME_MAX	((int64_t)S32_MAX)
+
 /*
  * On-disk inode structure.
  *
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index c7ffcb57b586..b3b0e6154bf2 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1484,8 +1484,8 @@ xfs_fc_fill_super(
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	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_LEGACY_TIME_MIN;
+	sb->s_time_max = XFS_LEGACY_TIME_MAX;
 	sb->s_iflags |= SB_I_CGROUPWB;
 
 	set_posix_acl_flag(sb);


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 02/11] xfs: refactor quota expiration timer modification
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
  2020-08-26 22:05 ` [PATCH 01/11] xfs: explicitly define inode timestamp range Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-27  6:43   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  2020-08-26 22:05 ` [PATCH 03/11] xfs: refactor default quota grace period setting code Darrick J. Wong
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Define explicit limits on the range of quota grace period expiration
timeouts and refactor the code that modifies the timeouts into helpers
that clamp the values appropriately.  Note that we'll refactor the
default grace period timer separately.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_format.h |   24 ++++++++++++++++++++++++
 fs/xfs/xfs_dquot.c         |   22 ++++++++++++++++++----
 fs/xfs/xfs_dquot.h         |    2 ++
 fs/xfs/xfs_qm.c            |    2 ++
 fs/xfs/xfs_qm.h            |    4 ++++
 fs/xfs/xfs_qm_syscalls.c   |   16 +++++++++++-----
 6 files changed, 61 insertions(+), 9 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index e57360a8fd16..cb316053d3db 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1199,6 +1199,30 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
 
 #define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK)
 
+/*
+ * XFS Quota Timers
+ * ================
+ *
+ * Traditional quota grace period expiration timers are an unsigned 32-bit
+ * seconds counter; time zero is the Unix epoch, Jan  1 00:00:01 UTC 1970.
+ * Note that an expiration value of zero means that the quota limit has not
+ * been reached, and therefore no expiration has been set.  Therefore, the
+ * ondisk min and max defined here can be used directly to constrain the incore
+ * quota expiration timestamps on a Unix system.
+ */
+
+/*
+ * Smallest possible ondisk quota expiration value with traditional timestamps.
+ * This corresponds exactly with the incore expiration Jan  1 00:00:01 UTC 1970.
+ */
+#define XFS_DQ_LEGACY_EXPIRY_MIN	((int64_t)1)
+
+/*
+ * Largest possible ondisk quota expiration value with traditional timestamps.
+ * This corresponds exactly with the incore expiration Feb  7 06:28:15 UTC 2106.
+ */
+#define XFS_DQ_LEGACY_EXPIRY_MAX	((int64_t)U32_MAX)
+
 /*
  * This is the main portion of the on-disk representation of quota information
  * for a user.  We pad this with some more expansion room to construct the on
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index bcd73b9c2994..f34841f98d44 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -98,12 +98,25 @@ xfs_qm_adjust_dqlimits(
 		xfs_dquot_set_prealloc_limits(dq);
 }
 
+/* Set the expiration time of a quota's grace period. */
+time64_t
+xfs_dquot_set_timeout(
+	struct xfs_mount	*mp,
+	time64_t		timeout)
+{
+	struct xfs_quotainfo	*qi = mp->m_quotainfo;
+
+	return clamp_t(time64_t, timeout, qi->qi_expiry_min,
+					  qi->qi_expiry_max);
+}
+
 /*
  * Determine if this quota counter is over either limit and set the quota
  * timers as appropriate.
  */
 static inline void
 xfs_qm_adjust_res_timer(
+	struct xfs_mount	*mp,
 	struct xfs_dquot_res	*res,
 	struct xfs_quota_limits	*qlim)
 {
@@ -112,7 +125,8 @@ xfs_qm_adjust_res_timer(
 	if ((res->softlimit && res->count > res->softlimit) ||
 	    (res->hardlimit && res->count > res->hardlimit)) {
 		if (res->timer == 0)
-			res->timer = ktime_get_real_seconds() + qlim->time;
+			res->timer = xfs_dquot_set_timeout(mp,
+					ktime_get_real_seconds() + qlim->time);
 	} else {
 		if (res->timer == 0)
 			res->warnings = 0;
@@ -145,9 +159,9 @@ xfs_qm_adjust_dqtimers(
 	ASSERT(dq->q_id);
 	defq = xfs_get_defquota(qi, xfs_dquot_type(dq));
 
-	xfs_qm_adjust_res_timer(&dq->q_blk, &defq->blk);
-	xfs_qm_adjust_res_timer(&dq->q_ino, &defq->ino);
-	xfs_qm_adjust_res_timer(&dq->q_rtb, &defq->rtb);
+	xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_blk, &defq->blk);
+	xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_ino, &defq->ino);
+	xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_rtb, &defq->rtb);
 }
 
 /*
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index 282a65da93c7..0e449101c861 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -237,4 +237,6 @@ typedef int (*xfs_qm_dqiterate_fn)(struct xfs_dquot *dq,
 int xfs_qm_dqiterate(struct xfs_mount *mp, xfs_dqtype_t type,
 		xfs_qm_dqiterate_fn iter_fn, void *priv);
 
+time64_t xfs_dquot_set_timeout(struct xfs_mount *mp, time64_t timeout);
+
 #endif /* __XFS_DQUOT_H__ */
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index be67570badf8..b83a12ecfc35 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -661,6 +661,8 @@ xfs_qm_init_quotainfo(
 	/* Precalc some constants */
 	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
 	qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
+	qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
+	qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
 
 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 9c078c35d924..e3dabab44097 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -65,6 +65,10 @@ struct xfs_quotainfo {
 	struct xfs_def_quota	qi_grp_default;
 	struct xfs_def_quota	qi_prj_default;
 	struct shrinker		qi_shrinker;
+
+	/* Minimum and maximum quota expiration timestamp values. */
+	time64_t		qi_expiry_min;
+	time64_t		qi_expiry_max;
 };
 
 static inline struct radix_tree_root *
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 1c542b4a5220..750f775ae915 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -479,13 +479,19 @@ xfs_setqlim_warns(
 
 static inline void
 xfs_setqlim_timer(
+	struct xfs_mount	*mp,
 	struct xfs_dquot_res	*res,
 	struct xfs_quota_limits	*qlim,
 	s64			timer)
 {
-	res->timer = timer;
-	if (qlim)
+	if (qlim) {
+		/* Set the length of the default grace period. */
+		res->timer = timer;
 		qlim->time = timer;
+	} else {
+		/* Set the grace period expiration on a quota. */
+		res->timer = xfs_dquot_set_timeout(mp, timer);
+	}
 }
 
 /*
@@ -574,7 +580,7 @@ xfs_qm_scall_setqlim(
 	if (newlim->d_fieldmask & QC_SPC_WARNS)
 		xfs_setqlim_warns(res, qlim, newlim->d_spc_warns);
 	if (newlim->d_fieldmask & QC_SPC_TIMER)
-		xfs_setqlim_timer(res, qlim, newlim->d_spc_timer);
+		xfs_setqlim_timer(mp, res, qlim, newlim->d_spc_timer);
 
 	/* Blocks on the realtime device. */
 	hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
@@ -590,7 +596,7 @@ xfs_qm_scall_setqlim(
 	if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
 		xfs_setqlim_warns(res, qlim, newlim->d_rt_spc_warns);
 	if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
-		xfs_setqlim_timer(res, qlim, newlim->d_rt_spc_timer);
+		xfs_setqlim_timer(mp, res, qlim, newlim->d_rt_spc_timer);
 
 	/* Inodes */
 	hard = (newlim->d_fieldmask & QC_INO_HARD) ?
@@ -606,7 +612,7 @@ xfs_qm_scall_setqlim(
 	if (newlim->d_fieldmask & QC_INO_WARNS)
 		xfs_setqlim_warns(res, qlim, newlim->d_ino_warns);
 	if (newlim->d_fieldmask & QC_INO_TIMER)
-		xfs_setqlim_timer(res, qlim, newlim->d_ino_timer);
+		xfs_setqlim_timer(mp, res, qlim, newlim->d_ino_timer);
 
 	if (id != 0) {
 		/*


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 03/11] xfs: refactor default quota grace period setting code
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
  2020-08-26 22:05 ` [PATCH 01/11] xfs: explicitly define inode timestamp range Darrick J. Wong
  2020-08-26 22:05 ` [PATCH 02/11] xfs: refactor quota expiration timer modification Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-27  6:44   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  2020-08-26 22:05 ` [PATCH 04/11] xfs: refactor quota timestamp coding Darrick J. Wong
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: Amir Goldstein, linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Refactor the code that sets the default quota grace period into a helper
function so that we can override the ondisk behavior later.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/xfs/libxfs/xfs_format.h |   13 +++++++++++++
 fs/xfs/xfs_dquot.c         |    8 ++++++++
 fs/xfs/xfs_dquot.h         |    1 +
 fs/xfs/xfs_qm_syscalls.c   |    4 ++--
 4 files changed, 24 insertions(+), 2 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index cb316053d3db..4b68a473b090 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1209,6 +1209,11 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
  * been reached, and therefore no expiration has been set.  Therefore, the
  * ondisk min and max defined here can be used directly to constrain the incore
  * quota expiration timestamps on a Unix system.
+ *
+ * The grace period for each quota type is stored in the root dquot (id = 0)
+ * and is applied to a non-root dquot when it exceeds the soft or hard limits.
+ * The length of quota grace periods are unsigned 32-bit quantities measured in
+ * units of seconds.  A value of zero means to use the default period.
  */
 
 /*
@@ -1223,6 +1228,14 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
  */
 #define XFS_DQ_LEGACY_EXPIRY_MAX	((int64_t)U32_MAX)
 
+/*
+ * Default quota grace periods, ranging from zero (use the compiled defaults)
+ * to ~136 years.  These are applied to a non-root dquot that has exceeded
+ * either limit.
+ */
+#define XFS_DQ_GRACE_MIN		((int64_t)0)
+#define XFS_DQ_GRACE_MAX		((int64_t)U32_MAX)
+
 /*
  * This is the main portion of the on-disk representation of quota information
  * for a user.  We pad this with some more expansion room to construct the on
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index f34841f98d44..e63a933413a3 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -110,6 +110,14 @@ xfs_dquot_set_timeout(
 					  qi->qi_expiry_max);
 }
 
+/* Set the length of the default grace period. */
+time64_t
+xfs_dquot_set_grace_period(
+	time64_t		grace)
+{
+	return clamp_t(time64_t, grace, XFS_DQ_GRACE_MIN, XFS_DQ_GRACE_MAX);
+}
+
 /*
  * Determine if this quota counter is over either limit and set the quota
  * timers as appropriate.
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index 0e449101c861..f642884a6834 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -238,5 +238,6 @@ int xfs_qm_dqiterate(struct xfs_mount *mp, xfs_dqtype_t type,
 		xfs_qm_dqiterate_fn iter_fn, void *priv);
 
 time64_t xfs_dquot_set_timeout(struct xfs_mount *mp, time64_t timeout);
+time64_t xfs_dquot_set_grace_period(time64_t grace);
 
 #endif /* __XFS_DQUOT_H__ */
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 750f775ae915..ca1b57d291dc 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -486,8 +486,8 @@ xfs_setqlim_timer(
 {
 	if (qlim) {
 		/* Set the length of the default grace period. */
-		res->timer = timer;
-		qlim->time = timer;
+		res->timer = xfs_dquot_set_grace_period(timer);
+		qlim->time = res->timer;
 	} else {
 		/* Set the grace period expiration on a quota. */
 		res->timer = xfs_dquot_set_timeout(mp, timer);


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 04/11] xfs: refactor quota timestamp coding
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (2 preceding siblings ...)
  2020-08-26 22:05 ` [PATCH 03/11] xfs: refactor default quota grace period setting code Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-27  6:44   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  2020-08-26 22:05 ` [PATCH 05/11] xfs: move xfs_log_dinode_to_disk to the log recovery code Darrick J. Wong
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: Amir Goldstein, linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Refactor quota timestamp encoding and decoding into helper functions so
that we can add extra behavior in the next patch.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/xfs/libxfs/xfs_dquot_buf.c  |   18 ++++++++++++++++++
 fs/xfs/libxfs/xfs_quota_defs.h |    5 +++++
 fs/xfs/xfs_dquot.c             |   12 ++++++------
 3 files changed, 29 insertions(+), 6 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
index 5a2db00b9d5f..cf85bad8a894 100644
--- a/fs/xfs/libxfs/xfs_dquot_buf.c
+++ b/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -288,3 +288,21 @@ const struct xfs_buf_ops xfs_dquot_buf_ra_ops = {
 	.verify_read = xfs_dquot_buf_readahead_verify,
 	.verify_write = xfs_dquot_buf_write_verify,
 };
+
+/* Convert an on-disk timer value into an incore timer value. */
+time64_t
+xfs_dquot_from_disk_ts(
+	struct xfs_disk_dquot	*ddq,
+	__be32			dtimer)
+{
+	return be32_to_cpu(dtimer);
+}
+
+/* Convert an incore timer value into an on-disk timer value. */
+__be32
+xfs_dquot_to_disk_ts(
+	struct xfs_dquot	*dqp,
+	time64_t		timer)
+{
+	return cpu_to_be32(timer);
+}
diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index 076bdc7037ee..9a99910d857e 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -143,4 +143,9 @@ extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
 extern void xfs_dqblk_repair(struct xfs_mount *mp, struct xfs_dqblk *dqb,
 		xfs_dqid_t id, xfs_dqtype_t type);
 
+struct xfs_dquot;
+time64_t xfs_dquot_from_disk_ts(struct xfs_disk_dquot *ddq,
+		__be32 dtimer);
+__be32 xfs_dquot_to_disk_ts(struct xfs_dquot *ddq, time64_t timer);
+
 #endif	/* __XFS_QUOTA_H__ */
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index e63a933413a3..59c03e973741 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -536,9 +536,9 @@ xfs_dquot_from_disk(
 	dqp->q_ino.warnings = be16_to_cpu(ddqp->d_iwarns);
 	dqp->q_rtb.warnings = be16_to_cpu(ddqp->d_rtbwarns);
 
-	dqp->q_blk.timer = be32_to_cpu(ddqp->d_btimer);
-	dqp->q_ino.timer = be32_to_cpu(ddqp->d_itimer);
-	dqp->q_rtb.timer = be32_to_cpu(ddqp->d_rtbtimer);
+	dqp->q_blk.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_btimer);
+	dqp->q_ino.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_itimer);
+	dqp->q_rtb.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_rtbtimer);
 
 	/*
 	 * Reservation counters are defined as reservation plus current usage
@@ -581,9 +581,9 @@ xfs_dquot_to_disk(
 	ddqp->d_iwarns = cpu_to_be16(dqp->q_ino.warnings);
 	ddqp->d_rtbwarns = cpu_to_be16(dqp->q_rtb.warnings);
 
-	ddqp->d_btimer = cpu_to_be32(dqp->q_blk.timer);
-	ddqp->d_itimer = cpu_to_be32(dqp->q_ino.timer);
-	ddqp->d_rtbtimer = cpu_to_be32(dqp->q_rtb.timer);
+	ddqp->d_btimer = xfs_dquot_to_disk_ts(dqp, dqp->q_blk.timer);
+	ddqp->d_itimer = xfs_dquot_to_disk_ts(dqp, dqp->q_ino.timer);
+	ddqp->d_rtbtimer = xfs_dquot_to_disk_ts(dqp, dqp->q_rtb.timer);
 }
 
 /* Allocate and initialize the dquot buffer for this in-core dquot. */


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 05/11] xfs: move xfs_log_dinode_to_disk to the log recovery code
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (3 preceding siblings ...)
  2020-08-26 22:05 ` [PATCH 04/11] xfs: refactor quota timestamp coding Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-27  6:45   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  2020-08-26 22:05 ` [PATCH 06/11] xfs: kill struct xfs_timestamp Darrick J. Wong
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Move this function to xfs_inode_item_recover.c since there's only one
caller of it.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_inode_buf.c   |   52 ---------------------------------------
 fs/xfs/libxfs/xfs_inode_buf.h   |    2 --
 fs/xfs/xfs_inode_item_recover.c |   52 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 52 insertions(+), 54 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 8d5dd08eab75..fa83591ca89b 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -310,58 +310,6 @@ xfs_inode_to_disk(
 	}
 }
 
-void
-xfs_log_dinode_to_disk(
-	struct xfs_log_dinode	*from,
-	struct xfs_dinode	*to)
-{
-	to->di_magic = cpu_to_be16(from->di_magic);
-	to->di_mode = cpu_to_be16(from->di_mode);
-	to->di_version = from->di_version;
-	to->di_format = from->di_format;
-	to->di_onlink = 0;
-	to->di_uid = cpu_to_be32(from->di_uid);
-	to->di_gid = cpu_to_be32(from->di_gid);
-	to->di_nlink = cpu_to_be32(from->di_nlink);
-	to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
-	to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
-	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_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_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_size = cpu_to_be64(from->di_size);
-	to->di_nblocks = cpu_to_be64(from->di_nblocks);
-	to->di_extsize = cpu_to_be32(from->di_extsize);
-	to->di_nextents = cpu_to_be32(from->di_nextents);
-	to->di_anextents = cpu_to_be16(from->di_anextents);
-	to->di_forkoff = from->di_forkoff;
-	to->di_aformat = from->di_aformat;
-	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
-	to->di_dmstate = cpu_to_be16(from->di_dmstate);
-	to->di_flags = cpu_to_be16(from->di_flags);
-	to->di_gen = cpu_to_be32(from->di_gen);
-
-	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_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);
-		to->di_lsn = cpu_to_be64(from->di_lsn);
-		memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
-		uuid_copy(&to->di_uuid, &from->di_uuid);
-		to->di_flushiter = 0;
-	} else {
-		to->di_flushiter = cpu_to_be16(from->di_flushiter);
-	}
-}
-
 static xfs_failaddr_t
 xfs_dinode_verify_fork(
 	struct xfs_dinode	*dip,
diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
index 6b08b9d060c2..89f7bea8efd6 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.h
+++ b/fs/xfs/libxfs/xfs_inode_buf.h
@@ -49,8 +49,6 @@ void	xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *);
 void	xfs_inode_to_disk(struct xfs_inode *ip, struct xfs_dinode *to,
 			  xfs_lsn_t lsn);
 int	xfs_inode_from_disk(struct xfs_inode *ip, struct xfs_dinode *from);
-void	xfs_log_dinode_to_disk(struct xfs_log_dinode *from,
-			       struct xfs_dinode *to);
 
 xfs_failaddr_t xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino,
 			   struct xfs_dinode *dip);
diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
index 5e0d291835b3..1e417ace2912 100644
--- a/fs/xfs/xfs_inode_item_recover.c
+++ b/fs/xfs/xfs_inode_item_recover.c
@@ -115,6 +115,58 @@ xfs_recover_inode_owner_change(
 	return error;
 }
 
+STATIC void
+xfs_log_dinode_to_disk(
+	struct xfs_log_dinode	*from,
+	struct xfs_dinode	*to)
+{
+	to->di_magic = cpu_to_be16(from->di_magic);
+	to->di_mode = cpu_to_be16(from->di_mode);
+	to->di_version = from->di_version;
+	to->di_format = from->di_format;
+	to->di_onlink = 0;
+	to->di_uid = cpu_to_be32(from->di_uid);
+	to->di_gid = cpu_to_be32(from->di_gid);
+	to->di_nlink = cpu_to_be32(from->di_nlink);
+	to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
+	to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
+	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_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_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_size = cpu_to_be64(from->di_size);
+	to->di_nblocks = cpu_to_be64(from->di_nblocks);
+	to->di_extsize = cpu_to_be32(from->di_extsize);
+	to->di_nextents = cpu_to_be32(from->di_nextents);
+	to->di_anextents = cpu_to_be16(from->di_anextents);
+	to->di_forkoff = from->di_forkoff;
+	to->di_aformat = from->di_aformat;
+	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
+	to->di_dmstate = cpu_to_be16(from->di_dmstate);
+	to->di_flags = cpu_to_be16(from->di_flags);
+	to->di_gen = cpu_to_be32(from->di_gen);
+
+	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_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);
+		to->di_lsn = cpu_to_be64(from->di_lsn);
+		memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
+		uuid_copy(&to->di_uuid, &from->di_uuid);
+		to->di_flushiter = 0;
+	} else {
+		to->di_flushiter = cpu_to_be16(from->di_flushiter);
+	}
+}
+
 STATIC int
 xlog_recover_inode_commit_pass2(
 	struct xlog			*log,


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 06/11] xfs: kill struct xfs_timestamp
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (4 preceding siblings ...)
  2020-08-26 22:05 ` [PATCH 05/11] xfs: move xfs_log_dinode_to_disk to the log recovery code Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-28  4:08   ` Allison Collins
  2020-08-26 22:05 ` [PATCH 07/11] xfs: kill struct xfs_ictimestamp Darrick J. Wong
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Replace this struct with an encoded __be64 value and add conversion
helpers to deal with the change.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_format.h      |    8 ++---
 fs/xfs/libxfs/xfs_inode_buf.c   |   62 +++++++++++++++++++++++++++++----------
 fs/xfs/libxfs/xfs_inode_buf.h   |    2 +
 fs/xfs/scrub/inode.c            |   25 +++++++++++-----
 fs/xfs/xfs_inode_item_recover.c |   26 +++++++++++-----
 fs/xfs/xfs_ondisk.h             |    2 +
 6 files changed, 87 insertions(+), 38 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 4b68a473b090..96734ba9aa5f 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -856,12 +856,10 @@ struct xfs_agfl {
  * seconds and nanoseconds; time zero is the Unix epoch, Jan  1 00:00:00 UTC
  * 1970, which means that the timestamp epoch is the same as the Unix epoch.
  * Therefore, the ondisk min and max defined here can be used directly to
- * constrain the incore timestamps on a Unix system.
+ * constrain the incore timestamps on a Unix system.  Note that we actually
+ * encode a __be64 value on disk.
  */
-typedef struct xfs_timestamp {
-	__be32		t_sec;		/* timestamp seconds */
-	__be32		t_nsec;		/* timestamp nanoseconds */
-} xfs_timestamp_t;
+typedef __be64 xfs_timestamp_t;
 
 /*
  * Smallest possible ondisk seconds value with traditional timestamps.  This
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index fa83591ca89b..1e65e28a9386 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -157,6 +157,26 @@ xfs_imap_to_bp(
 	return 0;
 }
 
+/*
+ * Convert an ondisk timestamp to an incore timestamp.
+ *
+ * For traditional timestamps, the ondisk format specifies that the seconds
+ * are stored in the first four bytes and the nanoseconds in the second four.
+ * Let the be64 conversion rotate the seconds field into the upper 32-bits,
+ * then shift and mask to extract the two values.
+ */
+struct timespec64
+xfs_inode_from_disk_ts(
+	const xfs_timestamp_t	ts)
+{
+	struct timespec64	tv;
+	uint64_t		t = be64_to_cpu(ts);
+
+	tv.tv_sec = (int64_t)t >> 32;
+	tv.tv_nsec = (int32_t)(t & 0xffffffff);
+	return tv;
+}
+
 int
 xfs_inode_from_disk(
 	struct xfs_inode	*ip,
@@ -211,12 +231,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);
+	inode->i_atime = xfs_inode_from_disk_ts(from->di_atime);
+	inode->i_mtime = xfs_inode_from_disk_ts(from->di_mtime);
+	inode->i_ctime = xfs_inode_from_disk_ts(from->di_ctime);
 
 	to->di_size = be64_to_cpu(from->di_size);
 	to->di_nblocks = be64_to_cpu(from->di_nblocks);
@@ -229,8 +246,7 @@ xfs_inode_from_disk(
 	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
 		inode_set_iversion_queried(inode,
 					   be64_to_cpu(from->di_changecount));
-		to->di_crtime.tv_sec = be32_to_cpu(from->di_crtime.t_sec);
-		to->di_crtime.tv_nsec = be32_to_cpu(from->di_crtime.t_nsec);
+		to->di_crtime = xfs_inode_from_disk_ts(from->di_crtime);
 		to->di_flags2 = be64_to_cpu(from->di_flags2);
 		to->di_cowextsize = be32_to_cpu(from->di_cowextsize);
 	}
@@ -252,6 +268,24 @@ xfs_inode_from_disk(
 	return error;
 }
 
+/*
+ * Convert an incore timestamp to an ondisk timestamp.
+ *
+ * For traditional timestamps, the ondisk format specifies that the seconds
+ * are stored in the first four bytes and the nanoseconds in the second four.
+ * Shift the seconds into the upper 32-bits so that the be64 conversion will
+ * take care of rotating the bytes for us.
+ */
+static inline xfs_timestamp_t
+xfs_inode_to_disk_ts(
+	const struct timespec64	tv)
+{
+	uint64_t		t;
+
+	t = ((int64_t)tv.tv_sec << 32) | (tv.tv_nsec & 0xffffffff);
+	return cpu_to_be64(t);
+}
+
 void
 xfs_inode_to_disk(
 	struct xfs_inode	*ip,
@@ -271,12 +305,9 @@ xfs_inode_to_disk(
 	to->di_projid_hi = cpu_to_be16(from->di_projid >> 16);
 
 	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);
+	to->di_atime = xfs_inode_to_disk_ts(inode->i_atime);
+	to->di_mtime = xfs_inode_to_disk_ts(inode->i_mtime);
+	to->di_ctime = xfs_inode_to_disk_ts(inode->i_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);
@@ -295,8 +326,7 @@ xfs_inode_to_disk(
 	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
 		to->di_version = 3;
 		to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
-		to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.tv_sec);
-		to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.tv_nsec);
+		to->di_crtime = xfs_inode_to_disk_ts(from->di_crtime);
 		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);
diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
index 89f7bea8efd6..3060ecd24a2e 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.h
+++ b/fs/xfs/libxfs/xfs_inode_buf.h
@@ -58,4 +58,6 @@ xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
 		uint32_t cowextsize, uint16_t mode, uint16_t flags,
 		uint64_t flags2);
 
+struct timespec64 xfs_inode_from_disk_ts(const xfs_timestamp_t ts);
+
 #endif	/* __XFS_INODE_BUF_H__ */
diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index 6d483ab29e63..eb1cc013d4ca 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -195,6 +195,19 @@ xchk_inode_flags2(
 	xchk_ino_set_corrupt(sc, ino);
 }
 
+static inline void
+xchk_dinode_nsec(
+	struct xfs_scrub	*sc,
+	xfs_ino_t		ino,
+	const xfs_timestamp_t	ts)
+{
+	struct timespec64	tv;
+
+	tv = xfs_inode_from_disk_ts(ts);
+	if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
+		xchk_ino_set_corrupt(sc, ino);
+}
+
 /* Scrub all the ondisk inode fields. */
 STATIC void
 xchk_dinode(
@@ -293,12 +306,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)
-		xchk_ino_set_corrupt(sc, ino);
+	xchk_dinode_nsec(sc, ino, dip->di_atime);
+	xchk_dinode_nsec(sc, ino, dip->di_mtime);
+	xchk_dinode_nsec(sc, ino, dip->di_ctime);
 
 	/*
 	 * di_size.  xfs_dinode_verify checks for things that screw up
@@ -403,8 +413,7 @@ xchk_dinode(
 	}
 
 	if (dip->di_version >= 3) {
-		if (be32_to_cpu(dip->di_crtime.t_nsec) >= NSEC_PER_SEC)
-			xchk_ino_set_corrupt(sc, ino);
+		xchk_dinode_nsec(sc, ino, dip->di_crtime);
 		xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
 		xchk_inode_cowextsize(sc, dip, ino, mode, flags,
 				flags2);
diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
index 1e417ace2912..e7c6f2b95e17 100644
--- a/fs/xfs/xfs_inode_item_recover.c
+++ b/fs/xfs/xfs_inode_item_recover.c
@@ -115,6 +115,20 @@ xfs_recover_inode_owner_change(
 	return error;
 }
 
+/*
+ * Convert a log timestamp to an ondisk timestamp.  See notes about the ondisk
+ * encoding in the comments for xfs_inode_to_disk_ts.
+ */
+static inline xfs_timestamp_t
+xfs_log_dinode_to_disk_ts(
+	const xfs_ictimestamp_t	its)
+{
+	uint64_t		t;
+
+	t = ((int64_t)its.t_sec << 32) | (its.t_nsec & 0xffffffff);
+	return cpu_to_be64(t);
+}
+
 STATIC void
 xfs_log_dinode_to_disk(
 	struct xfs_log_dinode	*from,
@@ -132,12 +146,9 @@ xfs_log_dinode_to_disk(
 	to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
 	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_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_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_atime = xfs_log_dinode_to_disk_ts(from->di_atime);
+	to->di_mtime = xfs_log_dinode_to_disk_ts(from->di_mtime);
+	to->di_ctime = xfs_log_dinode_to_disk_ts(from->di_ctime);
 
 	to->di_size = cpu_to_be64(from->di_size);
 	to->di_nblocks = cpu_to_be64(from->di_nblocks);
@@ -153,8 +164,7 @@ 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 = xfs_log_dinode_to_disk_ts(from->di_crtime);
 		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/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index acb9b737fe6b..2f11a6f9e005 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -41,7 +41,7 @@ xfs_check_ondisk_structs(void)
 	XFS_CHECK_STRUCT_SIZE(struct xfs_refcount_rec,		12);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_key,		20);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_rec,		24);
-	XFS_CHECK_STRUCT_SIZE(struct xfs_timestamp,		8);
+	XFS_CHECK_STRUCT_SIZE(xfs_timestamp_t,			8);
 	XFS_CHECK_STRUCT_SIZE(xfs_alloc_key_t,			8);
 	XFS_CHECK_STRUCT_SIZE(xfs_alloc_ptr_t,			4);
 	XFS_CHECK_STRUCT_SIZE(xfs_alloc_rec_t,			8);


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 07/11] xfs: kill struct xfs_ictimestamp
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (5 preceding siblings ...)
  2020-08-26 22:05 ` [PATCH 06/11] xfs: kill struct xfs_timestamp Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-27  6:51   ` Christoph Hellwig
  2020-08-26 22:05 ` [PATCH 08/11] xfs: widen ondisk inode timestamps to deal with y2038+ Darrick J. Wong
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Replace this struct with an encoded uint64_t in preparation for the
bigtime functionality.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_log_format.h  |    5 +----
 fs/xfs/xfs_inode_item.c         |   39 +++++++++++++++++++++++++++++++--------
 fs/xfs/xfs_inode_item_recover.c |   23 +++++++++++++++++++++--
 fs/xfs/xfs_ondisk.h             |    2 +-
 4 files changed, 54 insertions(+), 15 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index e3400c9c71cd..86640f8cd66a 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -368,10 +368,7 @@ static inline int xfs_ilog_fdata(int w)
  * directly mirrors the xfs_dinode structure as it must contain all the same
  * information.
  */
-typedef struct xfs_ictimestamp {
-	int32_t		t_sec;		/* timestamp seconds */
-	int32_t		t_nsec;		/* timestamp nanoseconds */
-} xfs_ictimestamp_t;
+typedef uint64_t xfs_ictimestamp_t;
 
 /*
  * Define the format of the inode core that is logged. This structure must be
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 6c65938cee1c..6ebc332ae446 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -295,6 +295,33 @@ xfs_inode_item_format_attr_fork(
 	}
 }
 
+/*
+ * Convert an incore timestamp to a log timestamp.  Note that the log format
+ * specifies host endian format!
+ *
+ * For traditional timestamps, the log format specifies that the seconds are
+ * stored in the first four bytes and the nanoseconds in the second four.  On a
+ * little-endian system, this means that we shift tv_nsec to put it in the
+ * upper four bytes and mask tv_sec to put it in the lower four bytes.  On
+ * big-endian systems, we shift tv_sec to put it in the upper four bytes and
+ * mask tv_nsec to put it in the lower four bytes.
+ */
+static inline xfs_ictimestamp_t
+xfs_inode_to_log_dinode_ts(
+	const struct timespec64	tv)
+{
+	uint64_t		t;
+
+#ifdef __LITTLE_ENDIAN
+	t = ((uint64_t)tv.tv_nsec << 32) | ((uint64_t)tv.tv_sec & 0xffffffff);
+#elif __BIG_ENDIAN
+	t = ((int64_t)tv.tv_sec << 32) | ((uint64_t)tv.tv_nsec & 0xffffffff);
+#else
+# error System is neither little nor big endian?
+#endif
+	return t;
+}
+
 static void
 xfs_inode_to_log_dinode(
 	struct xfs_inode	*ip,
@@ -313,12 +340,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;
+	to->di_atime = xfs_inode_to_log_dinode_ts(inode->i_atime);
+	to->di_mtime = xfs_inode_to_log_dinode_ts(inode->i_mtime);
+	to->di_ctime = xfs_inode_to_log_dinode_ts(inode->i_ctime);
 	to->di_nlink = inode->i_nlink;
 	to->di_gen = inode->i_generation;
 	to->di_mode = inode->i_mode;
@@ -340,8 +364,7 @@ xfs_inode_to_log_dinode(
 	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
 		to->di_version = 3;
 		to->di_changecount = inode_peek_iversion(inode);
-		to->di_crtime.t_sec = from->di_crtime.tv_sec;
-		to->di_crtime.t_nsec = from->di_crtime.tv_nsec;
+		to->di_crtime = xfs_inode_to_log_dinode_ts(from->di_crtime);
 		to->di_flags2 = from->di_flags2;
 		to->di_cowextsize = from->di_cowextsize;
 		to->di_ino = ip->i_ino;
diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
index e7c6f2b95e17..bbb820579ea2 100644
--- a/fs/xfs/xfs_inode_item_recover.c
+++ b/fs/xfs/xfs_inode_item_recover.c
@@ -117,15 +117,34 @@ xfs_recover_inode_owner_change(
 
 /*
  * Convert a log timestamp to an ondisk timestamp.  See notes about the ondisk
- * encoding in the comments for xfs_inode_to_disk_ts.
+ * encoding in the comments for xfs_inode_to_disk_ts.  Note that the log format
+ * specifies host endian format!
+ *
+ * For traditional timestamps, the log format specifies that the seconds are
+ * stored in the first four bytes and the nanoseconds in the second four.  On a
+ * little-endian system, this means that we shift tv_nsec to extract it from
+ * the upper four bytes and mask tv_sec to extract it from the lower four
+ * bytes.  On big-endian systems, we shift tv_sec to extract it from the upper
+ * four bytes and mask tv_nsec to extract it from the lower four bytes.
  */
 static inline xfs_timestamp_t
 xfs_log_dinode_to_disk_ts(
 	const xfs_ictimestamp_t	its)
 {
+	struct timespec64	tv;
 	uint64_t		t;
 
-	t = ((int64_t)its.t_sec << 32) | (its.t_nsec & 0xffffffff);
+#ifdef __LITTLE_ENDIAN
+	tv.tv_sec = (time64_t)its & 0xffffffff;
+	tv.tv_nsec = (int64_t)its >> 32;
+#elif __BIG_ENDIAN
+	tv.tv_sec = (time64_t)its >> 32;
+	tv.tv_nsec = (int64_t)its & 0xffffffff;
+#else
+# error System is neither little nor big endian?
+#endif
+
+	t = ((int64_t)tv.tv_sec << 32) | (tv.tv_nsec & 0xffffffff);
 	return cpu_to_be64(t);
 }
 
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index 2f11a6f9e005..42b940e9b2b3 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -121,7 +121,7 @@ xfs_check_ondisk_structs(void)
 	XFS_CHECK_STRUCT_SIZE(struct xfs_extent_64,		16);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_log_dinode,		176);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_icreate_log,		28);
-	XFS_CHECK_STRUCT_SIZE(struct xfs_ictimestamp,		8);
+	XFS_CHECK_STRUCT_SIZE(xfs_ictimestamp_t,		8);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_32,	52);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format,	56);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat,	20);


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 08/11] xfs: widen ondisk inode timestamps to deal with y2038+
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (6 preceding siblings ...)
  2020-08-26 22:05 ` [PATCH 07/11] xfs: kill struct xfs_ictimestamp Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-27  6:58   ` Christoph Hellwig
  2020-08-26 22:05 ` [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+ Darrick J. Wong
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Redesign the ondisk inode timestamps to be a simple unsigned 64-bit
counter of nanoseconds since 14 Dec 1901 (i.e. the minimum time in the
32-bit unix time epoch).  This enables us to handle dates up to 2486,
which solves the y2038 problem.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_format.h      |   70 ++++++++++++++++++++++++++++++++++++++-
 fs/xfs/libxfs/xfs_fs.h          |    1 +
 fs/xfs/libxfs/xfs_ialloc.c      |    4 ++
 fs/xfs/libxfs/xfs_inode_buf.c   |   42 +++++++++++++++++------
 fs/xfs/libxfs/xfs_inode_buf.h   |   15 ++++++++
 fs/xfs/libxfs/xfs_sb.c          |    2 +
 fs/xfs/libxfs/xfs_shared.h      |    3 ++
 fs/xfs/libxfs/xfs_trans_inode.c |   16 +++++++++
 fs/xfs/scrub/inode.c            |   16 ++++++---
 fs/xfs/xfs_inode.c              |    4 +-
 fs/xfs/xfs_inode.h              |    5 +++
 fs/xfs/xfs_inode_item.c         |   12 ++++---
 fs/xfs/xfs_inode_item_recover.c |   19 ++++++++---
 fs/xfs/xfs_ioctl.c              |    3 +-
 fs/xfs/xfs_ondisk.h             |   13 +++++++
 fs/xfs/xfs_super.c              |   13 ++++++-
 16 files changed, 207 insertions(+), 31 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 96734ba9aa5f..972c740aaf7b 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -467,6 +467,7 @@ xfs_sb_has_ro_compat_feature(
 #define XFS_SB_FEAT_INCOMPAT_FTYPE	(1 << 0)	/* filetype in dirent */
 #define XFS_SB_FEAT_INCOMPAT_SPINODES	(1 << 1)	/* sparse inode chunks */
 #define XFS_SB_FEAT_INCOMPAT_META_UUID	(1 << 2)	/* metadata UUID */
+#define XFS_SB_FEAT_INCOMPAT_BIGTIME	(1 << 3)	/* large timestamps */
 #define XFS_SB_FEAT_INCOMPAT_ALL \
 		(XFS_SB_FEAT_INCOMPAT_FTYPE|	\
 		 XFS_SB_FEAT_INCOMPAT_SPINODES|	\
@@ -565,6 +566,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_hasbigtime(struct xfs_sb *sbp)
+{
+	return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_BIGTIME);
+}
+
 /*
  * Inode btree block counter.  We record the number of inobt and finobt blocks
  * in the AGI header so that we can skip the finobt walk at mount time when
@@ -858,6 +865,13 @@ struct xfs_agfl {
  * Therefore, the ondisk min and max defined here can be used directly to
  * constrain the incore timestamps on a Unix system.  Note that we actually
  * encode a __be64 value on disk.
+ *
+ * When the bigtime feature is enabled, ondisk inode timestamps become an
+ * unsigned 64-bit nanoseconds counter.  This means that the bigtime inode
+ * timestamp epoch is the start of the classic timestamp range, which is
+ * Dec 31 20:45:52 UTC 1901.  Because the epochs are not the same, callers
+ * /must/ use the bigtime conversion functions when encoding and decoding raw
+ * timestamps.
  */
 typedef __be64 xfs_timestamp_t;
 
@@ -873,6 +887,50 @@ typedef __be64 xfs_timestamp_t;
  */
 #define XFS_LEGACY_TIME_MAX	((int64_t)S32_MAX)
 
+/*
+ * Smallest possible ondisk seconds value with bigtime timestamps.  This
+ * corresponds (after conversion to a Unix timestamp) with the traditional
+ * minimum timestamp of Dec 13 20:45:52 UTC 1901.
+ */
+#define XFS_BIGTIME_TIME_MIN	((int64_t)0)
+
+/*
+ * Largest supported ondisk seconds value with bigtime timestamps.  This
+ * corresponds (after conversion to a Unix timestamp) with an incore timestamp
+ * of Jul  2 20:20:24 UTC 2486.
+ *
+ * We round down the ondisk limit so that the bigtime quota and inode max
+ * timestamps will be the same.
+ */
+#define XFS_BIGTIME_TIME_MAX	((int64_t)((-1ULL / NSEC_PER_SEC) & ~0x3ULL))
+
+/*
+ * Bigtime epoch is set exactly to the minimum time value that a traditional
+ * 32-bit timestamp can represent when using the Unix epoch as a reference.
+ * Hence the Unix epoch is at a fixed offset into the supported bigtime
+ * timestamp range.
+ *
+ * The bigtime epoch also matches the minimum value an on-disk 32-bit XFS
+ * timestamp can represent so we will not lose any fidelity in converting
+ * to/from unix and bigtime timestamps.
+ *
+ * The following conversion factor converts a seconds counter from the Unix
+ * epoch to the bigtime epoch.
+ */
+#define XFS_BIGTIME_EPOCH_OFFSET	(-(int64_t)S32_MIN)
+
+/* Convert a timestamp from the Unix epoch to the bigtime epoch. */
+static inline uint64_t xfs_unix_to_bigtime(time64_t unix_seconds)
+{
+	return (uint64_t)unix_seconds + XFS_BIGTIME_EPOCH_OFFSET;
+}
+
+/* Convert a timestamp from the bigtime epoch to the Unix epoch. */
+static inline time64_t xfs_bigtime_to_unix(uint64_t ondisk_seconds)
+{
+	return (time64_t)ondisk_seconds - XFS_BIGTIME_EPOCH_OFFSET;
+}
+
 /*
  * On-disk inode structure.
  *
@@ -1098,12 +1156,22 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
 #define XFS_DIFLAG2_DAX_BIT	0	/* use DAX for this inode */
 #define XFS_DIFLAG2_REFLINK_BIT	1	/* file's blocks may be shared */
 #define XFS_DIFLAG2_COWEXTSIZE_BIT   2  /* copy on write extent size hint */
+#define XFS_DIFLAG2_BIGTIME_BIT	3	/* big timestamps */
+
 #define XFS_DIFLAG2_DAX		(1 << XFS_DIFLAG2_DAX_BIT)
 #define XFS_DIFLAG2_REFLINK     (1 << XFS_DIFLAG2_REFLINK_BIT)
 #define XFS_DIFLAG2_COWEXTSIZE  (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
+#define XFS_DIFLAG2_BIGTIME	(1 << XFS_DIFLAG2_BIGTIME_BIT)
 
 #define XFS_DIFLAG2_ANY \
-	(XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE)
+	(XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
+	 XFS_DIFLAG2_BIGTIME)
+
+static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
+{
+	return dip->di_version >= 3 &&
+	       (dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_BIGTIME));
+}
 
 /*
  * Inode number format:
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 84bcffa87753..2a2e3cfd94f0 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -249,6 +249,7 @@ typedef struct xfs_fsop_resblks {
 #define XFS_FSOP_GEOM_FLAGS_SPINODES	(1 << 18) /* sparse inode chunks   */
 #define XFS_FSOP_GEOM_FLAGS_RMAPBT	(1 << 19) /* reverse mapping btree */
 #define XFS_FSOP_GEOM_FLAGS_REFLINK	(1 << 20) /* files can share blocks */
+#define XFS_FSOP_GEOM_FLAGS_BIGTIME	(1 << 21) /* 64-bit nsec timestamps */
 
 /*
  * Minimum and maximum sizes need for growth checks.
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index fef1d94c60a4..938753ee96c8 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2807,6 +2807,10 @@ xfs_ialloc_setup_geometry(
 	uint64_t		icount;
 	uint			inodes;
 
+	igeo->new_diflags2 = 0;
+	if (xfs_sb_version_hasbigtime(&mp->m_sb))
+		igeo->new_diflags2 |= XFS_DIFLAG2_BIGTIME;
+
 	/* Compute inode btree geometry. */
 	igeo->agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
 	igeo->inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 1e65e28a9386..9ed75910de9f 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -167,13 +167,23 @@ xfs_imap_to_bp(
  */
 struct timespec64
 xfs_inode_from_disk_ts(
+	struct xfs_dinode	*dip,
 	const xfs_timestamp_t	ts)
 {
 	struct timespec64	tv;
 	uint64_t		t = be64_to_cpu(ts);
+	uint64_t		s;
+	uint32_t		n;
 
-	tv.tv_sec = (int64_t)t >> 32;
-	tv.tv_nsec = (int32_t)(t & 0xffffffff);
+	if (xfs_dinode_has_bigtime(dip)) {
+		s = xfs_bigtime_to_unix(div_u64_rem(t, NSEC_PER_SEC, &n));
+	} else {
+		s = (int64_t)t >> 32;
+		n = (int32_t)(t & 0xffffffff);
+	}
+
+	tv.tv_sec = s;
+	tv.tv_nsec = n;
 	return tv;
 }
 
@@ -231,9 +241,9 @@ xfs_inode_from_disk(
 	 * a time before epoch is converted to a time long after epoch
 	 * on 64 bit systems.
 	 */
-	inode->i_atime = xfs_inode_from_disk_ts(from->di_atime);
-	inode->i_mtime = xfs_inode_from_disk_ts(from->di_mtime);
-	inode->i_ctime = xfs_inode_from_disk_ts(from->di_ctime);
+	inode->i_atime = xfs_inode_from_disk_ts(from, from->di_atime);
+	inode->i_mtime = xfs_inode_from_disk_ts(from, from->di_mtime);
+	inode->i_ctime = xfs_inode_from_disk_ts(from, from->di_ctime);
 
 	to->di_size = be64_to_cpu(from->di_size);
 	to->di_nblocks = be64_to_cpu(from->di_nblocks);
@@ -246,7 +256,7 @@ xfs_inode_from_disk(
 	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
 		inode_set_iversion_queried(inode,
 					   be64_to_cpu(from->di_changecount));
-		to->di_crtime = xfs_inode_from_disk_ts(from->di_crtime);
+		to->di_crtime = xfs_inode_from_disk_ts(from, from->di_crtime);
 		to->di_flags2 = be64_to_cpu(from->di_flags2);
 		to->di_cowextsize = be32_to_cpu(from->di_cowextsize);
 	}
@@ -278,11 +288,16 @@ xfs_inode_from_disk(
  */
 static inline xfs_timestamp_t
 xfs_inode_to_disk_ts(
+	struct xfs_inode	*ip,
 	const struct timespec64	tv)
 {
 	uint64_t		t;
 
-	t = ((int64_t)tv.tv_sec << 32) | (tv.tv_nsec & 0xffffffff);
+	if (xfs_inode_has_bigtime(ip))
+		t = xfs_inode_encode_bigtime(tv);
+	else
+		t = ((int64_t)tv.tv_sec << 32) | (tv.tv_nsec & 0xffffffff);
+
 	return cpu_to_be64(t);
 }
 
@@ -305,9 +320,9 @@ xfs_inode_to_disk(
 	to->di_projid_hi = cpu_to_be16(from->di_projid >> 16);
 
 	memset(to->di_pad, 0, sizeof(to->di_pad));
-	to->di_atime = xfs_inode_to_disk_ts(inode->i_atime);
-	to->di_mtime = xfs_inode_to_disk_ts(inode->i_mtime);
-	to->di_ctime = xfs_inode_to_disk_ts(inode->i_ctime);
+	to->di_atime = xfs_inode_to_disk_ts(ip, inode->i_atime);
+	to->di_mtime = xfs_inode_to_disk_ts(ip, inode->i_mtime);
+	to->di_ctime = xfs_inode_to_disk_ts(ip, inode->i_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);
@@ -326,7 +341,7 @@ xfs_inode_to_disk(
 	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
 		to->di_version = 3;
 		to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
-		to->di_crtime = xfs_inode_to_disk_ts(from->di_crtime);
+		to->di_crtime = xfs_inode_to_disk_ts(ip, from->di_crtime);
 		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);
@@ -546,6 +561,11 @@ xfs_dinode_verify(
 	if (fa)
 		return fa;
 
+	/* bigtime iflag can only happen on bigtime filesystems */
+	if (xfs_dinode_has_bigtime(dip) &&
+	    !xfs_sb_version_hasbigtime(&mp->m_sb))
+		return __this_address;
+
 	return NULL;
 }
 
diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
index 3060ecd24a2e..e05bfe52fd8f 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.h
+++ b/fs/xfs/libxfs/xfs_inode_buf.h
@@ -32,6 +32,11 @@ struct xfs_icdinode {
 	struct timespec64 di_crtime;	/* time created */
 };
 
+static inline bool xfs_icdinode_has_bigtime(const struct xfs_icdinode *icd)
+{
+	return icd->di_flags2 & XFS_DIFLAG2_BIGTIME;
+}
+
 /*
  * Inode location information.  Stored in the inode and passed to
  * xfs_imap_to_bp() to get a buffer and dinode for a given inode.
@@ -58,6 +63,14 @@ xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
 		uint32_t cowextsize, uint16_t mode, uint16_t flags,
 		uint64_t flags2);
 
-struct timespec64 xfs_inode_from_disk_ts(const xfs_timestamp_t ts);
+static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
+{
+	uint64_t	t = xfs_unix_to_bigtime(tv.tv_sec) * NSEC_PER_SEC;
+
+	return t + tv.tv_nsec;
+}
+
+struct timespec64 xfs_inode_from_disk_ts(struct xfs_dinode *dip,
+		const xfs_timestamp_t ts);
 
 #endif	/* __XFS_INODE_BUF_H__ */
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index ae9aaf1f34bf..d5d60cd1c2ea 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -1166,6 +1166,8 @@ xfs_fs_geometry(
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_RMAPBT;
 	if (xfs_sb_version_hasreflink(sbp))
 		geo->flags |= XFS_FSOP_GEOM_FLAGS_REFLINK;
+	if (xfs_sb_version_hasbigtime(sbp))
+		geo->flags |= XFS_FSOP_GEOM_FLAGS_BIGTIME;
 	if (xfs_sb_version_hassector(sbp))
 		geo->logsectsize = sbp->sb_logsectsize;
 	else
diff --git a/fs/xfs/libxfs/xfs_shared.h b/fs/xfs/libxfs/xfs_shared.h
index 708feb8eac76..c795ae47b3c9 100644
--- a/fs/xfs/libxfs/xfs_shared.h
+++ b/fs/xfs/libxfs/xfs_shared.h
@@ -176,6 +176,9 @@ struct xfs_ino_geometry {
 	unsigned int	ialloc_align;
 
 	unsigned int	agino_log;	/* #bits for agino in inum */
+
+	/* precomputed value for di_flags2 */
+	uint64_t	new_diflags2;
 };
 
 #endif /* __XFS_SHARED_H__ */
diff --git a/fs/xfs/libxfs/xfs_trans_inode.c b/fs/xfs/libxfs/xfs_trans_inode.c
index e15129647e00..0ccb4a1f1cd1 100644
--- a/fs/xfs/libxfs/xfs_trans_inode.c
+++ b/fs/xfs/libxfs/xfs_trans_inode.c
@@ -73,6 +73,12 @@ xfs_trans_ichgtime(
 		ip->i_d.di_crtime = tv;
 }
 
+static inline bool xfs_inode_want_bigtime_upgrade(struct xfs_inode *ip)
+{
+	return xfs_sb_version_hasbigtime(&ip->i_mount->m_sb) &&
+	       !xfs_inode_has_bigtime(ip);
+}
+
 /*
  * This is called to mark the fields indicated in fieldmask as needing to be
  * logged when the transaction is committed.  The inode must already be
@@ -131,6 +137,16 @@ xfs_trans_log_inode(
 			iversion_flags = XFS_ILOG_CORE;
 	}
 
+	/*
+	 * If we're updating the inode core or the timestamps and it's possible
+	 * to upgrade this inode to bigtime format, do so now.
+	 */
+	if ((flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
+	    xfs_inode_want_bigtime_upgrade(ip)) {
+		ip->i_d.di_flags2 |= XFS_DIFLAG2_BIGTIME;
+		flags |= XFS_ILOG_CORE;
+	}
+
 	/*
 	 * Record the specific change for fdatasync optimisation. This allows
 	 * fdatasync to skip log forces for inodes that are only timestamp
diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index eb1cc013d4ca..3aa85b64de36 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -190,6 +190,11 @@ xchk_inode_flags2(
 	if ((flags2 & XFS_DIFLAG2_DAX) && (flags2 & XFS_DIFLAG2_REFLINK))
 		goto bad;
 
+	/* no bigtime iflag without the bigtime feature */
+	if (xfs_dinode_has_bigtime(dip) &&
+	    !xfs_sb_version_hasbigtime(&mp->m_sb))
+		goto bad;
+
 	return;
 bad:
 	xchk_ino_set_corrupt(sc, ino);
@@ -199,11 +204,12 @@ static inline void
 xchk_dinode_nsec(
 	struct xfs_scrub	*sc,
 	xfs_ino_t		ino,
+	struct xfs_dinode	*dip,
 	const xfs_timestamp_t	ts)
 {
 	struct timespec64	tv;
 
-	tv = xfs_inode_from_disk_ts(ts);
+	tv = xfs_inode_from_disk_ts(dip, ts);
 	if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
 		xchk_ino_set_corrupt(sc, ino);
 }
@@ -306,9 +312,9 @@ xchk_dinode(
 	}
 
 	/* di_[amc]time.nsec */
-	xchk_dinode_nsec(sc, ino, dip->di_atime);
-	xchk_dinode_nsec(sc, ino, dip->di_mtime);
-	xchk_dinode_nsec(sc, ino, dip->di_ctime);
+	xchk_dinode_nsec(sc, ino, dip, dip->di_atime);
+	xchk_dinode_nsec(sc, ino, dip, dip->di_mtime);
+	xchk_dinode_nsec(sc, ino, dip, dip->di_ctime);
 
 	/*
 	 * di_size.  xfs_dinode_verify checks for things that screw up
@@ -413,7 +419,7 @@ xchk_dinode(
 	}
 
 	if (dip->di_version >= 3) {
-		xchk_dinode_nsec(sc, ino, dip->di_crtime);
+		xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
 		xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
 		xchk_inode_cowextsize(sc, dip, ino, mode, flags,
 				flags2);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index c06129cffba9..bf5e8b85773e 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -840,7 +840,7 @@ xfs_ialloc(
 
 	if (xfs_sb_version_has_v3inode(&mp->m_sb)) {
 		inode_set_iversion(inode, 1);
-		ip->i_d.di_flags2 = 0;
+		ip->i_d.di_flags2 = mp->m_ino_geo.new_diflags2;
 		ip->i_d.di_cowextsize = 0;
 		ip->i_d.di_crtime = tv;
 	}
@@ -2717,7 +2717,7 @@ xfs_ifree(
 
 	VFS_I(ip)->i_mode = 0;		/* mark incore inode as free */
 	ip->i_d.di_flags = 0;
-	ip->i_d.di_flags2 = 0;
+	ip->i_d.di_flags2 = ip->i_mount->m_ino_geo.new_diflags2;
 	ip->i_d.di_dmevmask = 0;
 	ip->i_d.di_forkoff = 0;		/* mark the attr fork not in use */
 	ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index e9a8bb184d1f..315908a352d3 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -194,6 +194,11 @@ static inline bool xfs_inode_has_cow_data(struct xfs_inode *ip)
 	return ip->i_cowfp && ip->i_cowfp->if_bytes;
 }
 
+static inline bool xfs_inode_has_bigtime(struct xfs_inode *ip)
+{
+	return ip->i_d.di_flags2 & XFS_DIFLAG2_BIGTIME;
+}
+
 /*
  * Return the buftarg used for data allocations on a given inode.
  */
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 6ebc332ae446..991070aa30ae 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -308,10 +308,14 @@ xfs_inode_item_format_attr_fork(
  */
 static inline xfs_ictimestamp_t
 xfs_inode_to_log_dinode_ts(
+	struct xfs_inode	*ip,
 	const struct timespec64	tv)
 {
 	uint64_t		t;
 
+	if (xfs_inode_has_bigtime(ip))
+		return xfs_inode_encode_bigtime(tv);
+
 #ifdef __LITTLE_ENDIAN
 	t = ((uint64_t)tv.tv_nsec << 32) | ((uint64_t)tv.tv_sec & 0xffffffff);
 #elif __BIG_ENDIAN
@@ -340,9 +344,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 = xfs_inode_to_log_dinode_ts(inode->i_atime);
-	to->di_mtime = xfs_inode_to_log_dinode_ts(inode->i_mtime);
-	to->di_ctime = xfs_inode_to_log_dinode_ts(inode->i_ctime);
+	to->di_atime = xfs_inode_to_log_dinode_ts(ip, inode->i_atime);
+	to->di_mtime = xfs_inode_to_log_dinode_ts(ip, inode->i_mtime);
+	to->di_ctime = xfs_inode_to_log_dinode_ts(ip, inode->i_ctime);
 	to->di_nlink = inode->i_nlink;
 	to->di_gen = inode->i_generation;
 	to->di_mode = inode->i_mode;
@@ -364,7 +368,7 @@ xfs_inode_to_log_dinode(
 	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
 		to->di_version = 3;
 		to->di_changecount = inode_peek_iversion(inode);
-		to->di_crtime = xfs_inode_to_log_dinode_ts(from->di_crtime);
+		to->di_crtime = xfs_inode_to_log_dinode_ts(ip, from->di_crtime);
 		to->di_flags2 = from->di_flags2;
 		to->di_cowextsize = from->di_cowextsize;
 		to->di_ino = ip->i_ino;
diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
index bbb820579ea2..65aa579dc072 100644
--- a/fs/xfs/xfs_inode_item_recover.c
+++ b/fs/xfs/xfs_inode_item_recover.c
@@ -115,6 +115,12 @@ xfs_recover_inode_owner_change(
 	return error;
 }
 
+static inline bool xfs_log_dinode_has_bigtime(const struct xfs_log_dinode *ld)
+{
+	return ld->di_version >= 3 &&
+	       (ld->di_flags2 & XFS_DIFLAG2_BIGTIME);
+}
+
 /*
  * Convert a log timestamp to an ondisk timestamp.  See notes about the ondisk
  * encoding in the comments for xfs_inode_to_disk_ts.  Note that the log format
@@ -129,11 +135,15 @@ xfs_recover_inode_owner_change(
  */
 static inline xfs_timestamp_t
 xfs_log_dinode_to_disk_ts(
+	struct xfs_log_dinode	*from,
 	const xfs_ictimestamp_t	its)
 {
 	struct timespec64	tv;
 	uint64_t		t;
 
+	if (xfs_log_dinode_has_bigtime(from))
+		return cpu_to_be64(its);
+
 #ifdef __LITTLE_ENDIAN
 	tv.tv_sec = (time64_t)its & 0xffffffff;
 	tv.tv_nsec = (int64_t)its >> 32;
@@ -165,9 +175,9 @@ xfs_log_dinode_to_disk(
 	to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
 	memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
 
-	to->di_atime = xfs_log_dinode_to_disk_ts(from->di_atime);
-	to->di_mtime = xfs_log_dinode_to_disk_ts(from->di_mtime);
-	to->di_ctime = xfs_log_dinode_to_disk_ts(from->di_ctime);
+	to->di_atime = xfs_log_dinode_to_disk_ts(from, from->di_atime);
+	to->di_mtime = xfs_log_dinode_to_disk_ts(from, from->di_mtime);
+	to->di_ctime = xfs_log_dinode_to_disk_ts(from, from->di_ctime);
 
 	to->di_size = cpu_to_be64(from->di_size);
 	to->di_nblocks = cpu_to_be64(from->di_nblocks);
@@ -183,7 +193,8 @@ xfs_log_dinode_to_disk(
 
 	if (from->di_version == 3) {
 		to->di_changecount = cpu_to_be64(from->di_changecount);
-		to->di_crtime = xfs_log_dinode_to_disk_ts(from->di_crtime);
+		to->di_crtime = xfs_log_dinode_to_disk_ts(from,
+							  from->di_crtime);
 		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/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 6f22a66777cd..13396c3665d1 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1190,7 +1190,8 @@ xfs_flags2diflags2(
 	unsigned int		xflags)
 {
 	uint64_t		di_flags2 =
-		(ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK);
+		(ip->i_d.di_flags2 & (XFS_DIFLAG2_REFLINK |
+				      XFS_DIFLAG2_BIGTIME));
 
 	if (xflags & FS_XFLAG_DAX)
 		di_flags2 |= XFS_DIFLAG2_DAX;
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index 42b940e9b2b3..52db8743def1 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -15,6 +15,10 @@
 		"XFS: offsetof(" #structname ", " #member ") is wrong, " \
 		"expected " #off)
 
+#define XFS_CHECK_VALUE(value, expected) \
+	BUILD_BUG_ON_MSG((value) != (expected), \
+		"XFS: value of " #value " is wrong, expected " #expected)
+
 static inline void __init
 xfs_check_ondisk_structs(void)
 {
@@ -152,6 +156,15 @@ xfs_check_ondisk_structs(void)
 	XFS_CHECK_STRUCT_SIZE(struct xfs_inumbers,		24);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_bulkstat_req,		64);
 	XFS_CHECK_STRUCT_SIZE(struct xfs_inumbers_req,		64);
+
+	/*
+	 * Make sure the incore inode timestamp range corresponds to hand
+	 * converted values based on the ondisk format specification.
+	 */
+	XFS_CHECK_VALUE(XFS_BIGTIME_TIME_MIN - XFS_BIGTIME_EPOCH_OFFSET,
+			XFS_LEGACY_TIME_MIN);
+	XFS_CHECK_VALUE(XFS_BIGTIME_TIME_MAX - XFS_BIGTIME_EPOCH_OFFSET,
+			16299260424LL);
 }
 
 #endif /* __XFS_ONDISK_H */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index b3b0e6154bf2..58be2220ae05 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1484,8 +1484,13 @@ xfs_fc_fill_super(
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	sb->s_max_links = XFS_MAXLINK;
 	sb->s_time_gran = 1;
-	sb->s_time_min = XFS_LEGACY_TIME_MIN;
-	sb->s_time_max = XFS_LEGACY_TIME_MAX;
+	if (xfs_sb_version_hasbigtime(&mp->m_sb)) {
+		sb->s_time_min = xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MIN);
+		sb->s_time_max = xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MAX);
+	} else {
+		sb->s_time_min = XFS_LEGACY_TIME_MIN;
+		sb->s_time_max = XFS_LEGACY_TIME_MAX;
+	}
 	sb->s_iflags |= SB_I_CGROUPWB;
 
 	set_posix_acl_flag(sb);
@@ -1494,6 +1499,10 @@ xfs_fc_fill_super(
 	if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5)
 		sb->s_flags |= SB_I_VERSION;
 
+	if (xfs_sb_version_hasbigtime(&mp->m_sb))
+		xfs_warn(mp,
+ "EXPERIMENTAL big timestamp feature in use. Use at your own risk!");
+
 	if (mp->m_flags & XFS_MOUNT_DAX_ALWAYS) {
 		bool rtdev_is_dax = false, datadev_is_dax;
 


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (7 preceding siblings ...)
  2020-08-26 22:05 ` [PATCH 08/11] xfs: widen ondisk inode timestamps to deal with y2038+ Darrick J. Wong
@ 2020-08-26 22:05 ` Darrick J. Wong
  2020-08-27  7:00   ` Christoph Hellwig
  2020-08-28  6:08   ` Allison Collins
  2020-08-26 22:06 ` [PATCH 10/11] xfs: trace timestamp limits Darrick J. Wong
                   ` (2 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:05 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Enable the bigtime feature for quota timers.  We decrease the accuracy
of the timers to ~4s in exchange for being able to set timers up to the
bigtime maximum.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/libxfs/xfs_dquot_buf.c  |   21 +++++++++++++++--
 fs/xfs/libxfs/xfs_format.h     |   50 +++++++++++++++++++++++++++++++++++++++-
 fs/xfs/libxfs/xfs_quota_defs.h |    3 ++
 fs/xfs/xfs_dquot.c             |   10 ++++++++
 fs/xfs/xfs_ondisk.h            |    5 ++++
 fs/xfs/xfs_qm.c                |   13 +++++++++-
 fs/xfs/xfs_trans_dquot.c       |    6 +++++
 7 files changed, 102 insertions(+), 6 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
index cf85bad8a894..6766417d5ba4 100644
--- a/fs/xfs/libxfs/xfs_dquot_buf.c
+++ b/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -69,6 +69,13 @@ xfs_dquot_verify(
 	    ddq_type != XFS_DQTYPE_GROUP)
 		return __this_address;
 
+	if ((ddq->d_type & XFS_DQTYPE_BIGTIME) &&
+	    !xfs_sb_version_hasbigtime(&mp->m_sb))
+		return __this_address;
+
+	if ((ddq->d_type & XFS_DQTYPE_BIGTIME) && !ddq->d_id)
+		return __this_address;
+
 	if (id != -1 && id != be32_to_cpu(ddq->d_id))
 		return __this_address;
 
@@ -295,7 +302,12 @@ xfs_dquot_from_disk_ts(
 	struct xfs_disk_dquot	*ddq,
 	__be32			dtimer)
 {
-	return be32_to_cpu(dtimer);
+	uint32_t		t = be32_to_cpu(dtimer);
+
+	if (t != 0 && (ddq->d_type & XFS_DQTYPE_BIGTIME))
+		return xfs_dq_bigtime_to_unix(t);
+
+	return t;
 }
 
 /* Convert an incore timer value into an on-disk timer value. */
@@ -304,5 +316,10 @@ xfs_dquot_to_disk_ts(
 	struct xfs_dquot	*dqp,
 	time64_t		timer)
 {
-	return cpu_to_be32(timer);
+	uint32_t		t = timer;
+
+	if (timer != 0 && (dqp->q_type & XFS_DQTYPE_BIGTIME))
+		t = xfs_dq_unix_to_bigtime(timer);
+
+	return cpu_to_be32(t);
 }
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 972c740aaf7b..9cf84b57e2ce 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1257,13 +1257,15 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
 #define XFS_DQTYPE_USER		0x01		/* user dquot record */
 #define XFS_DQTYPE_PROJ		0x02		/* project dquot record */
 #define XFS_DQTYPE_GROUP	0x04		/* group dquot record */
+#define XFS_DQTYPE_BIGTIME	0x08		/* large expiry timestamps */
 
 /* bitmask to determine if this is a user/group/project dquot */
 #define XFS_DQTYPE_REC_MASK	(XFS_DQTYPE_USER | \
 				 XFS_DQTYPE_PROJ | \
 				 XFS_DQTYPE_GROUP)
 
-#define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK)
+#define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK | \
+				 XFS_DQTYPE_BIGTIME)
 
 /*
  * XFS Quota Timers
@@ -1276,6 +1278,10 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
  * ondisk min and max defined here can be used directly to constrain the incore
  * quota expiration timestamps on a Unix system.
  *
+ * When bigtime is enabled, we trade two bits of precision to expand the
+ * expiration timeout range to match that of big inode timestamps.  The min and
+ * max recorded here are the on-disk limits, not a Unix timestamp.
+ *
  * The grace period for each quota type is stored in the root dquot (id = 0)
  * and is applied to a non-root dquot when it exceeds the soft or hard limits.
  * The length of quota grace periods are unsigned 32-bit quantities measured in
@@ -1294,6 +1300,48 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
  */
 #define XFS_DQ_LEGACY_EXPIRY_MAX	((int64_t)U32_MAX)
 
+/*
+ * Smallest possible ondisk quota expiration value with bigtime timestamps.
+ * This corresponds (after conversion to a Unix timestamp) with the incore
+ * expiration of Jan  1 00:00:04 UTC 1970.
+ */
+#define XFS_DQ_BIGTIME_EXPIRY_MIN	(XFS_DQ_LEGACY_EXPIRY_MIN)
+
+/*
+ * Largest supported ondisk quota expiration value with bigtime timestamps.
+ * This corresponds (after conversion to a Unix timestamp) with an incore
+ * expiration of Jul  2 20:20:24 UTC 2486.
+ *
+ * The ondisk field supports values up to -1U, which corresponds to an incore
+ * expiration in 2514.  This is beyond the maximum the bigtime inode timestamp,
+ * so we cap the maximum bigtime quota expiration to the max inode timestamp.
+ */
+#define XFS_DQ_BIGTIME_EXPIRY_MAX	((int64_t)4074815106U)
+
+/*
+ * The following conversion factors assist in converting a quota expiration
+ * timestamp between the incore and ondisk formats.
+ */
+#define XFS_DQ_BIGTIME_SHIFT	(2)
+#define XFS_DQ_BIGTIME_SLACK	((int64_t)(1ULL << XFS_DQ_BIGTIME_SHIFT) - 1)
+
+/* Convert an incore quota expiration timestamp to an ondisk bigtime value. */
+static inline uint32_t xfs_dq_unix_to_bigtime(time64_t unix_seconds)
+{
+	/*
+	 * Round the expiration timestamp up to the nearest bigtime timestamp
+	 * that we can store, to give users the most time to fix problems.
+	 */
+	return ((uint64_t)unix_seconds + XFS_DQ_BIGTIME_SLACK) >>
+			XFS_DQ_BIGTIME_SHIFT;
+}
+
+/* Convert an ondisk bigtime quota expiration value to an incore timestamp. */
+static inline time64_t xfs_dq_bigtime_to_unix(uint32_t ondisk_seconds)
+{
+	return (time64_t)ondisk_seconds << XFS_DQ_BIGTIME_SHIFT;
+}
+
 /*
  * Default quota grace periods, ranging from zero (use the compiled defaults)
  * to ~136 years.  These are applied to a non-root dquot that has exceeded
diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index 9a99910d857e..0f0af4e35032 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -23,7 +23,8 @@ typedef uint8_t		xfs_dqtype_t;
 #define XFS_DQTYPE_STRINGS \
 	{ XFS_DQTYPE_USER,	"USER" }, \
 	{ XFS_DQTYPE_PROJ,	"PROJ" }, \
-	{ XFS_DQTYPE_GROUP,	"GROUP" }
+	{ XFS_DQTYPE_GROUP,	"GROUP" }, \
+	{ XFS_DQTYPE_BIGTIME,	"BIGTIME" }
 
 /*
  * flags for q_flags field in the dquot.
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 59c03e973741..3f9e11c3df1e 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -223,6 +223,8 @@ xfs_qm_init_dquot_blk(
 		d->dd_diskdq.d_version = XFS_DQUOT_VERSION;
 		d->dd_diskdq.d_id = cpu_to_be32(curid);
 		d->dd_diskdq.d_type = type;
+		if (curid > 0 && xfs_sb_version_hasbigtime(&mp->m_sb))
+			d->dd_diskdq.d_type |= XFS_DQTYPE_BIGTIME;
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 			xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
@@ -1167,6 +1169,14 @@ xfs_qm_dqflush_check(
 	    !dqp->q_rtb.timer)
 		return __this_address;
 
+	/* bigtime flag should never be set on root dquots */
+	if (dqp->q_type & XFS_DQTYPE_BIGTIME) {
+		if (!xfs_sb_version_hasbigtime(&dqp->q_mount->m_sb))
+			return __this_address;
+		if (dqp->q_id == 0)
+			return __this_address;
+	}
+
 	return NULL;
 }
 
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index 52db8743def1..a13686ce0626 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -165,6 +165,11 @@ xfs_check_ondisk_structs(void)
 			XFS_LEGACY_TIME_MIN);
 	XFS_CHECK_VALUE(XFS_BIGTIME_TIME_MAX - XFS_BIGTIME_EPOCH_OFFSET,
 			16299260424LL);
+
+	/* Do the same with the incore quota expiration range. */
+	XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MIN << XFS_DQ_BIGTIME_SHIFT, 4);
+	XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MAX << XFS_DQ_BIGTIME_SHIFT,
+			16299260424LL);
 }
 
 #endif /* __XFS_ONDISK_H */
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index b83a12ecfc35..259588a4227d 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -661,8 +661,15 @@ xfs_qm_init_quotainfo(
 	/* Precalc some constants */
 	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
 	qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
-	qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
-	qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
+	if (xfs_sb_version_hasbigtime(&mp->m_sb)) {
+		qinf->qi_expiry_min =
+			xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MIN);
+		qinf->qi_expiry_max =
+			xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MAX);
+	} else {
+		qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
+		qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
+	}
 
 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
@@ -881,6 +888,8 @@ xfs_qm_reset_dqcounts(
 			ddq->d_bwarns = 0;
 			ddq->d_iwarns = 0;
 			ddq->d_rtbwarns = 0;
+			if (xfs_sb_version_hasbigtime(&mp->m_sb))
+				ddq->d_type |= XFS_DQTYPE_BIGTIME;
 		}
 
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index c6ba7ef18e06..133fc6fc3edd 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -55,6 +55,12 @@ xfs_trans_log_dquot(
 {
 	ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
+	/* Upgrade the dquot to bigtime format if possible. */
+	if (dqp->q_id != 0 &&
+	    xfs_sb_version_hasbigtime(&tp->t_mountp->m_sb) &&
+	    !(dqp->q_type & XFS_DQTYPE_BIGTIME))
+		dqp->q_type |= XFS_DQTYPE_BIGTIME;
+
 	tp->t_flags |= XFS_TRANS_DIRTY;
 	set_bit(XFS_LI_DIRTY, &dqp->q_logitem.qli_item.li_flags);
 }


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 10/11] xfs: trace timestamp limits
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (8 preceding siblings ...)
  2020-08-26 22:05 ` [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+ Darrick J. Wong
@ 2020-08-26 22:06 ` Darrick J. Wong
  2020-08-27  7:01   ` Christoph Hellwig
  2020-08-28  6:08   ` Allison Collins
  2020-08-26 22:06 ` [PATCH 11/11] xfs: enable big timestamps Darrick J. Wong
  2020-08-27  6:41 ` [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Christoph Hellwig
  11 siblings, 2 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:06 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Add a couple of tracepoints so that we can check the timestamp limits
being set on inodes and quotas.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/xfs_qm.c    |    2 ++
 fs/xfs/xfs_super.c |    1 +
 fs/xfs/xfs_trace.h |   26 ++++++++++++++++++++++++++
 3 files changed, 29 insertions(+)


diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 259588a4227d..3f82e0c92c2d 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -670,6 +670,8 @@ xfs_qm_init_quotainfo(
 		qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
 		qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
 	}
+	trace_xfs_quota_expiry_range(mp, qinf->qi_expiry_min,
+			qinf->qi_expiry_max);
 
 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 58be2220ae05..8230c902a813 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1491,6 +1491,7 @@ xfs_fc_fill_super(
 		sb->s_time_min = XFS_LEGACY_TIME_MIN;
 		sb->s_time_max = XFS_LEGACY_TIME_MAX;
 	}
+	trace_xfs_inode_timestamp_range(mp, sb->s_time_min, sb->s_time_max);
 	sb->s_iflags |= SB_I_CGROUPWB;
 
 	set_posix_acl_flag(sb);
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index abb1d859f226..a3a35a2d8ed9 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -3844,6 +3844,32 @@ TRACE_EVENT(xfs_btree_bload_block,
 		  __entry->nr_records)
 )
 
+DECLARE_EVENT_CLASS(xfs_timestamp_range_class,
+	TP_PROTO(struct xfs_mount *mp, time64_t min, time64_t max),
+	TP_ARGS(mp, min, max),
+	TP_STRUCT__entry(
+		__field(dev_t, dev)
+		__field(long long, min)
+		__field(long long, max)
+	),
+	TP_fast_assign(
+		__entry->dev = mp->m_super->s_dev;
+		__entry->min = min;
+		__entry->max = max;
+	),
+	TP_printk("dev %d:%d min %lld max %lld",
+		  MAJOR(__entry->dev), MINOR(__entry->dev),
+		  __entry->min,
+		  __entry->max)
+)
+
+#define DEFINE_TIMESTAMP_RANGE_EVENT(name) \
+DEFINE_EVENT(xfs_timestamp_range_class, name, \
+	TP_PROTO(struct xfs_mount *mp, long long min, long long max), \
+	TP_ARGS(mp, min, max))
+DEFINE_TIMESTAMP_RANGE_EVENT(xfs_inode_timestamp_range);
+DEFINE_TIMESTAMP_RANGE_EVENT(xfs_quota_expiry_range);
+
 #endif /* _TRACE_XFS_H */
 
 #undef TRACE_INCLUDE_PATH


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 11/11] xfs: enable big timestamps
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (9 preceding siblings ...)
  2020-08-26 22:06 ` [PATCH 10/11] xfs: trace timestamp limits Darrick J. Wong
@ 2020-08-26 22:06 ` Darrick J. Wong
  2020-08-28  6:09   ` Allison Collins
  2020-08-27  6:41 ` [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Christoph Hellwig
  11 siblings, 1 reply; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-26 22:06 UTC (permalink / raw)
  To: darrick.wong, david, hch; +Cc: Amir Goldstein, linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Enable the big timestamp feature.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/xfs/libxfs/xfs_format.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)


diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 9cf84b57e2ce..4ba92b8fb0a7 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -471,7 +471,8 @@ xfs_sb_has_ro_compat_feature(
 #define XFS_SB_FEAT_INCOMPAT_ALL \
 		(XFS_SB_FEAT_INCOMPAT_FTYPE|	\
 		 XFS_SB_FEAT_INCOMPAT_SPINODES|	\
-		 XFS_SB_FEAT_INCOMPAT_META_UUID)
+		 XFS_SB_FEAT_INCOMPAT_META_UUID| \
+		 XFS_SB_FEAT_INCOMPAT_BIGTIME)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 00/11] xfs: widen timestamps to deal with y2038
  2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
                   ` (10 preceding siblings ...)
  2020-08-26 22:06 ` [PATCH 11/11] xfs: enable big timestamps Darrick J. Wong
@ 2020-08-27  6:41 ` Christoph Hellwig
  11 siblings, 0 replies; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  6:41 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, Amir Goldstein, linux-xfs, sandeen


That was quick - I haven't managed to get back to questions on my
reviews of the last one.  I'll just review this series and see if
anything sticks, sorry if I haven't taken account of earlier comments.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 01/11] xfs: explicitly define inode timestamp range
  2020-08-26 22:05 ` [PATCH 01/11] xfs: explicitly define inode timestamp range Darrick J. Wong
@ 2020-08-27  6:42   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  6:42 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, Amir Goldstein, linux-xfs, sandeen

On Wed, Aug 26, 2020 at 03:05:04PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Formally define the inode timestamp ranges that existing filesystems
> support, and switch the vfs timetamp ranges to use it.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 02/11] xfs: refactor quota expiration timer modification
  2020-08-26 22:05 ` [PATCH 02/11] xfs: refactor quota expiration timer modification Darrick J. Wong
@ 2020-08-27  6:43   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  6:43 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, linux-xfs, amir73il, sandeen

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 03/11] xfs: refactor default quota grace period setting code
  2020-08-26 22:05 ` [PATCH 03/11] xfs: refactor default quota grace period setting code Darrick J. Wong
@ 2020-08-27  6:44   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  6:44 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, Amir Goldstein, linux-xfs, sandeen

On Wed, Aug 26, 2020 at 03:05:17PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Refactor the code that sets the default quota grace period into a helper
> function so that we can override the ondisk behavior later.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 04/11] xfs: refactor quota timestamp coding
  2020-08-26 22:05 ` [PATCH 04/11] xfs: refactor quota timestamp coding Darrick J. Wong
@ 2020-08-27  6:44   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  6:44 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, Amir Goldstein, linux-xfs, sandeen

On Wed, Aug 26, 2020 at 03:05:24PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Refactor quota timestamp encoding and decoding into helper functions so
> that we can add extra behavior in the next patch.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 05/11] xfs: move xfs_log_dinode_to_disk to the log recovery code
  2020-08-26 22:05 ` [PATCH 05/11] xfs: move xfs_log_dinode_to_disk to the log recovery code Darrick J. Wong
@ 2020-08-27  6:45   ` Christoph Hellwig
  2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  6:45 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, linux-xfs, amir73il, sandeen

On Wed, Aug 26, 2020 at 03:05:30PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Move this function to xfs_inode_item_recover.c since there's only one
> caller of it.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 07/11] xfs: kill struct xfs_ictimestamp
  2020-08-26 22:05 ` [PATCH 07/11] xfs: kill struct xfs_ictimestamp Darrick J. Wong
@ 2020-08-27  6:51   ` Christoph Hellwig
  2020-08-27  8:17     ` Amir Goldstein
  2020-08-27 15:31     ` Darrick J. Wong
  0 siblings, 2 replies; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  6:51 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, linux-xfs, amir73il, sandeen

> + */
> +static inline xfs_ictimestamp_t
> +xfs_inode_to_log_dinode_ts(
> +	const struct timespec64	tv)
> +{
> +	uint64_t		t;
> +
> +#ifdef __LITTLE_ENDIAN
> +	t = ((uint64_t)tv.tv_nsec << 32) | ((uint64_t)tv.tv_sec & 0xffffffff);
> +#elif __BIG_ENDIAN
> +	t = ((int64_t)tv.tv_sec << 32) | ((uint64_t)tv.tv_nsec & 0xffffffff);
> +#else
> +# error System is neither little nor big endian?
> +#endif
> +	return t;

Looking at this I wonder if we should just keep the struct and cast
to it locally in the conversion functions, as that should take
care of everything.  Or just keep the union from the previous version,
sorry..

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 08/11] xfs: widen ondisk inode timestamps to deal with y2038+
  2020-08-26 22:05 ` [PATCH 08/11] xfs: widen ondisk inode timestamps to deal with y2038+ Darrick J. Wong
@ 2020-08-27  6:58   ` Christoph Hellwig
  2020-08-27 15:38     ` Darrick J. Wong
  0 siblings, 1 reply; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  6:58 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, linux-xfs, amir73il, sandeen

> -	tv.tv_sec = (int64_t)t >> 32;
> -	tv.tv_nsec = (int32_t)(t & 0xffffffff);
> +	if (xfs_dinode_has_bigtime(dip)) {
> +		s = xfs_bigtime_to_unix(div_u64_rem(t, NSEC_PER_SEC, &n));
> +	} else {
> +		s = (int64_t)t >> 32;
> +		n = (int32_t)(t & 0xffffffff);

Move this branche into a xfs_legacytime_to_unix helper just to be
symmetric?

This also made me think of the encoding:  another sensible option
would be to always read the time stamps as two 32-bit values using the
struct type, and just add them up for the bigtime case.

> +	if (xfs_inode_has_bigtime(ip))
> +		t = xfs_inode_encode_bigtime(tv);
> +	else
> +		t = ((int64_t)tv.tv_sec << 32) | (tv.tv_nsec & 0xffffffff);
> +

Same here.

> @@ -305,9 +320,9 @@ xfs_inode_to_disk(
>  	to->di_projid_hi = cpu_to_be16(from->di_projid >> 16);
>  
>  	memset(to->di_pad, 0, sizeof(to->di_pad));
> -	to->di_atime = xfs_inode_to_disk_ts(inode->i_atime);
> -	to->di_mtime = xfs_inode_to_disk_ts(inode->i_mtime);
> -	to->di_ctime = xfs_inode_to_disk_ts(inode->i_ctime);
> +	to->di_atime = xfs_inode_to_disk_ts(ip, inode->i_atime);
> +	to->di_mtime = xfs_inode_to_disk_ts(ip, inode->i_mtime);
> +	to->di_ctime = xfs_inode_to_disk_ts(ip, inode->i_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);
> @@ -326,7 +341,7 @@ xfs_inode_to_disk(
>  	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
>  		to->di_version = 3;
>  		to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
> -		to->di_crtime = xfs_inode_to_disk_ts(from->di_crtime);
> +		to->di_crtime = xfs_inode_to_disk_ts(ip, from->di_crtime);
>  		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);
> @@ -546,6 +561,11 @@ xfs_dinode_verify(
>  	if (fa)
>  		return fa;
>  
> +	/* bigtime iflag can only happen on bigtime filesystems */
> +	if (xfs_dinode_has_bigtime(dip) &&
> +	    !xfs_sb_version_hasbigtime(&mp->m_sb))
> +		return __this_address;
> +
>  	return NULL;
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
> index 3060ecd24a2e..e05bfe52fd8f 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.h
> +++ b/fs/xfs/libxfs/xfs_inode_buf.h
> @@ -32,6 +32,11 @@ struct xfs_icdinode {
>  	struct timespec64 di_crtime;	/* time created */
>  };
>  
> +static inline bool xfs_icdinode_has_bigtime(const struct xfs_icdinode *icd)
> +{
> +	return icd->di_flags2 & XFS_DIFLAG2_BIGTIME;
> +}
> +
>  /*
>   * Inode location information.  Stored in the inode and passed to
>   * xfs_imap_to_bp() to get a buffer and dinode for a given inode.
> @@ -58,6 +63,14 @@ xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
>  		uint32_t cowextsize, uint16_t mode, uint16_t flags,
>  		uint64_t flags2);
>  
> -struct timespec64 xfs_inode_from_disk_ts(const xfs_timestamp_t ts);
> +static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
> +{
> +	uint64_t	t = xfs_unix_to_bigtime(tv.tv_sec) * NSEC_PER_SEC;
> +
> +	return t + tv.tv_nsec;

Why not:

	return xfs_unix_to_bigtime(tv.tv_sec) * NSEC_PER_SEC + tv.tv_nsec;

?

> +static inline bool xfs_inode_want_bigtime_upgrade(struct xfs_inode *ip)
> +{
> +	return xfs_sb_version_hasbigtime(&ip->i_mount->m_sb) &&
> +	       !xfs_inode_has_bigtime(ip);
> +}
> +
>  /*
>   * This is called to mark the fields indicated in fieldmask as needing to be
>   * logged when the transaction is committed.  The inode must already be
> @@ -131,6 +137,16 @@ xfs_trans_log_inode(
>  			iversion_flags = XFS_ILOG_CORE;
>  	}
>  
> +	/*
> +	 * If we're updating the inode core or the timestamps and it's possible
> +	 * to upgrade this inode to bigtime format, do so now.
> +	 */
> +	if ((flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
> +	    xfs_inode_want_bigtime_upgrade(ip)) {
> +		ip->i_d.di_flags2 |= XFS_DIFLAG2_BIGTIME;
> +		flags |= XFS_ILOG_CORE;
> +	}

I find the way to directly set XFS_DIFLAG2_BIGTIME but using a helper
to check it here rather confusing.

Why not:

	if (xfs_sb_version_hasbigtime(&ip->i_mount->m_sb) &&
	    (flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
	    !(ip->i_d.di_flags2 & XFS_DIFLAG2_BIGTIME)) {
		ip->i_d.di_flags2 |= XFS_DIFLAG2_BIGTIME;
		flags |= XFS_ILOG_CORE;
	}

?

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+
  2020-08-26 22:05 ` [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+ Darrick J. Wong
@ 2020-08-27  7:00   ` Christoph Hellwig
  2020-08-27 17:49     ` Darrick J. Wong
  2020-08-28  6:08   ` Allison Collins
  1 sibling, 1 reply; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  7:00 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, linux-xfs, amir73il, sandeen

> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 972c740aaf7b..9cf84b57e2ce 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -1257,13 +1257,15 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
>  #define XFS_DQTYPE_USER		0x01		/* user dquot record */
>  #define XFS_DQTYPE_PROJ		0x02		/* project dquot record */
>  #define XFS_DQTYPE_GROUP	0x04		/* group dquot record */
> +#define XFS_DQTYPE_BIGTIME	0x08		/* large expiry timestamps */

Maybe make this the high bit in the field to keep space for adding more
actual quota types if we need them?

Otherwise looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 10/11] xfs: trace timestamp limits
  2020-08-26 22:06 ` [PATCH 10/11] xfs: trace timestamp limits Darrick J. Wong
@ 2020-08-27  7:01   ` Christoph Hellwig
  2020-08-28  6:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  7:01 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: david, hch, linux-xfs, amir73il, sandeen

On Wed, Aug 26, 2020 at 03:06:03PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Add a couple of tracepoints so that we can check the timestamp limits
> being set on inodes and quotas.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 07/11] xfs: kill struct xfs_ictimestamp
  2020-08-27  6:51   ` Christoph Hellwig
@ 2020-08-27  8:17     ` Amir Goldstein
  2020-08-27  8:18       ` Christoph Hellwig
  2020-08-27 15:31     ` Darrick J. Wong
  1 sibling, 1 reply; 39+ messages in thread
From: Amir Goldstein @ 2020-08-27  8:17 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Darrick J. Wong, Dave Chinner, linux-xfs, Eric Sandeen

On Thu, Aug 27, 2020 at 9:51 AM Christoph Hellwig <hch@infradead.org> wrote:
>
> > + */
> > +static inline xfs_ictimestamp_t
> > +xfs_inode_to_log_dinode_ts(
> > +     const struct timespec64 tv)
> > +{
> > +     uint64_t                t;
> > +
> > +#ifdef __LITTLE_ENDIAN
> > +     t = ((uint64_t)tv.tv_nsec << 32) | ((uint64_t)tv.tv_sec & 0xffffffff);
> > +#elif __BIG_ENDIAN
> > +     t = ((int64_t)tv.tv_sec << 32) | ((uint64_t)tv.tv_nsec & 0xffffffff);
> > +#else
> > +# error System is neither little nor big endian?
> > +#endif
> > +     return t;
>
> Looking at this I wonder if we should just keep the struct and cast
> to it locally in the conversion functions, as that should take
> care of everything.  Or just keep the union from the previous version,
> sorry..

Looking at this my eyes pop out.
I realize that maintaining on-disk format of the log is challenging,
so if there is no other technical solution that will be easier for humans
to review and maintain going forward, I will step back and let others
review this code.

But it bears the question: do we have to support replaying on BE a
log that was recorded on LE? Especially with so little BE machines
around these days, this sounds like over design to me.
Wouldn't it be better just to keep a bit in the log if it is LE or BE and refuse
to replay it on the wrong architecture?

Sure, we need to support whatever we supported up to now, but "bigtime"
can require a new incompat log feature "host order" (or something).

Anyway, I am probably mumbling utter garbage, do feel free to ignore
or set me straight.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 07/11] xfs: kill struct xfs_ictimestamp
  2020-08-27  8:17     ` Amir Goldstein
@ 2020-08-27  8:18       ` Christoph Hellwig
  2020-08-27  8:56         ` Amir Goldstein
  0 siblings, 1 reply; 39+ messages in thread
From: Christoph Hellwig @ 2020-08-27  8:18 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: Christoph Hellwig, Darrick J. Wong, Dave Chinner, linux-xfs,
	Eric Sandeen

On Thu, Aug 27, 2020 at 11:17:34AM +0300, Amir Goldstein wrote:
> Looking at this my eyes pop out.
> I realize that maintaining on-disk format of the log is challenging,
> so if there is no other technical solution that will be easier for humans
> to review and maintain going forward, I will step back and let others
> review this code.
> 
> But it bears the question: do we have to support replaying on BE a
> log that was recorded on LE? Especially with so little BE machines
> around these days, this sounds like over design to me.
> Wouldn't it be better just to keep a bit in the log if it is LE or BE and refuse
> to replay it on the wrong architecture?

XFS has never supported replaying a BE log on LE machine or vice versa.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 07/11] xfs: kill struct xfs_ictimestamp
  2020-08-27  8:18       ` Christoph Hellwig
@ 2020-08-27  8:56         ` Amir Goldstein
  0 siblings, 0 replies; 39+ messages in thread
From: Amir Goldstein @ 2020-08-27  8:56 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Darrick J. Wong, Dave Chinner, linux-xfs, Eric Sandeen

On Thu, Aug 27, 2020 at 11:18 AM Christoph Hellwig <hch@infradead.org> wrote:
>
> On Thu, Aug 27, 2020 at 11:17:34AM +0300, Amir Goldstein wrote:
> > Looking at this my eyes pop out.
> > I realize that maintaining on-disk format of the log is challenging,
> > so if there is no other technical solution that will be easier for humans
> > to review and maintain going forward, I will step back and let others
> > review this code.
> >
> > But it bears the question: do we have to support replaying on BE a
> > log that was recorded on LE? Especially with so little BE machines
> > around these days, this sounds like over design to me.
> > Wouldn't it be better just to keep a bit in the log if it is LE or BE and refuse
> > to replay it on the wrong architecture?
>
> XFS has never supported replaying a BE log on LE machine or vice versa.

Right. Makes sense.
I guess I read this backwards:
https://lore.kernel.org/linux-xfs/20200825003945.GA6096@magnolia/T/#u

Sorry for the noise.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 07/11] xfs: kill struct xfs_ictimestamp
  2020-08-27  6:51   ` Christoph Hellwig
  2020-08-27  8:17     ` Amir Goldstein
@ 2020-08-27 15:31     ` Darrick J. Wong
  1 sibling, 0 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-27 15:31 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: david, linux-xfs, amir73il, sandeen

On Thu, Aug 27, 2020 at 07:51:14AM +0100, Christoph Hellwig wrote:
> > + */
> > +static inline xfs_ictimestamp_t
> > +xfs_inode_to_log_dinode_ts(
> > +	const struct timespec64	tv)
> > +{
> > +	uint64_t		t;
> > +
> > +#ifdef __LITTLE_ENDIAN
> > +	t = ((uint64_t)tv.tv_nsec << 32) | ((uint64_t)tv.tv_sec & 0xffffffff);
> > +#elif __BIG_ENDIAN
> > +	t = ((int64_t)tv.tv_sec << 32) | ((uint64_t)tv.tv_nsec & 0xffffffff);
> > +#else
> > +# error System is neither little nor big endian?
> > +#endif
> > +	return t;
> 
> Looking at this I wonder if we should just keep the struct and cast
> to it locally in the conversion functions, as that should take
> care of everything.  Or just keep the union from the previous version,
> sorry..

Yeah, thinking about this ugliness some more I think I'd rather just use
a pointer cast here since the ifdef stuff is gross.

--D

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 08/11] xfs: widen ondisk inode timestamps to deal with y2038+
  2020-08-27  6:58   ` Christoph Hellwig
@ 2020-08-27 15:38     ` Darrick J. Wong
  0 siblings, 0 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-27 15:38 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: david, linux-xfs, amir73il, sandeen

On Thu, Aug 27, 2020 at 07:58:16AM +0100, Christoph Hellwig wrote:
> > -	tv.tv_sec = (int64_t)t >> 32;
> > -	tv.tv_nsec = (int32_t)(t & 0xffffffff);
> > +	if (xfs_dinode_has_bigtime(dip)) {
> > +		s = xfs_bigtime_to_unix(div_u64_rem(t, NSEC_PER_SEC, &n));
> > +	} else {
> > +		s = (int64_t)t >> 32;
> > +		n = (int32_t)(t & 0xffffffff);
> 
> Move this branche into a xfs_legacytime_to_unix helper just to be
> symmetric?
> 
> This also made me think of the encoding:  another sensible option
> would be to always read the time stamps as two 32-bit values using the
> struct type, and just add them up for the bigtime case.
> 
> > +	if (xfs_inode_has_bigtime(ip))
> > +		t = xfs_inode_encode_bigtime(tv);
> > +	else
> > +		t = ((int64_t)tv.tv_sec << 32) | (tv.tv_nsec & 0xffffffff);
> > +
> 
> Same here.

<shrug> I think I'd rather just keep the legacy struct xfs_{ic,}timestamp,
change the xfs_dinode/xfs_log_dinode structs to have a be64/u64
timestamp, and cast pointers as needed to support the legacy formats.

> > @@ -305,9 +320,9 @@ xfs_inode_to_disk(
> >  	to->di_projid_hi = cpu_to_be16(from->di_projid >> 16);
> >  
> >  	memset(to->di_pad, 0, sizeof(to->di_pad));
> > -	to->di_atime = xfs_inode_to_disk_ts(inode->i_atime);
> > -	to->di_mtime = xfs_inode_to_disk_ts(inode->i_mtime);
> > -	to->di_ctime = xfs_inode_to_disk_ts(inode->i_ctime);
> > +	to->di_atime = xfs_inode_to_disk_ts(ip, inode->i_atime);
> > +	to->di_mtime = xfs_inode_to_disk_ts(ip, inode->i_mtime);
> > +	to->di_ctime = xfs_inode_to_disk_ts(ip, inode->i_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);
> > @@ -326,7 +341,7 @@ xfs_inode_to_disk(
> >  	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
> >  		to->di_version = 3;
> >  		to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
> > -		to->di_crtime = xfs_inode_to_disk_ts(from->di_crtime);
> > +		to->di_crtime = xfs_inode_to_disk_ts(ip, from->di_crtime);
> >  		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);
> > @@ -546,6 +561,11 @@ xfs_dinode_verify(
> >  	if (fa)
> >  		return fa;
> >  
> > +	/* bigtime iflag can only happen on bigtime filesystems */
> > +	if (xfs_dinode_has_bigtime(dip) &&
> > +	    !xfs_sb_version_hasbigtime(&mp->m_sb))
> > +		return __this_address;
> > +
> >  	return NULL;
> >  }
> >  
> > diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
> > index 3060ecd24a2e..e05bfe52fd8f 100644
> > --- a/fs/xfs/libxfs/xfs_inode_buf.h
> > +++ b/fs/xfs/libxfs/xfs_inode_buf.h
> > @@ -32,6 +32,11 @@ struct xfs_icdinode {
> >  	struct timespec64 di_crtime;	/* time created */
> >  };
> >  
> > +static inline bool xfs_icdinode_has_bigtime(const struct xfs_icdinode *icd)
> > +{
> > +	return icd->di_flags2 & XFS_DIFLAG2_BIGTIME;
> > +}
> > +
> >  /*
> >   * Inode location information.  Stored in the inode and passed to
> >   * xfs_imap_to_bp() to get a buffer and dinode for a given inode.
> > @@ -58,6 +63,14 @@ xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
> >  		uint32_t cowextsize, uint16_t mode, uint16_t flags,
> >  		uint64_t flags2);
> >  
> > -struct timespec64 xfs_inode_from_disk_ts(const xfs_timestamp_t ts);
> > +static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
> > +{
> > +	uint64_t	t = xfs_unix_to_bigtime(tv.tv_sec) * NSEC_PER_SEC;
> > +
> > +	return t + tv.tv_nsec;
> 
> Why not:
> 
> 	return xfs_unix_to_bigtime(tv.tv_sec) * NSEC_PER_SEC + tv.tv_nsec;
> 
> ?

Heh, ok, will do.

> > +static inline bool xfs_inode_want_bigtime_upgrade(struct xfs_inode *ip)
> > +{
> > +	return xfs_sb_version_hasbigtime(&ip->i_mount->m_sb) &&
> > +	       !xfs_inode_has_bigtime(ip);
> > +}
> > +
> >  /*
> >   * This is called to mark the fields indicated in fieldmask as needing to be
> >   * logged when the transaction is committed.  The inode must already be
> > @@ -131,6 +137,16 @@ xfs_trans_log_inode(
> >  			iversion_flags = XFS_ILOG_CORE;
> >  	}
> >  
> > +	/*
> > +	 * If we're updating the inode core or the timestamps and it's possible
> > +	 * to upgrade this inode to bigtime format, do so now.
> > +	 */
> > +	if ((flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
> > +	    xfs_inode_want_bigtime_upgrade(ip)) {
> > +		ip->i_d.di_flags2 |= XFS_DIFLAG2_BIGTIME;
> > +		flags |= XFS_ILOG_CORE;
> > +	}
> 
> I find the way to directly set XFS_DIFLAG2_BIGTIME but using a helper
> to check it here rather confusing.
> 
> Why not:
> 
> 	if (xfs_sb_version_hasbigtime(&ip->i_mount->m_sb) &&
> 	    (flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
> 	    !(ip->i_d.di_flags2 & XFS_DIFLAG2_BIGTIME)) {
> 		ip->i_d.di_flags2 |= XFS_DIFLAG2_BIGTIME;
> 		flags |= XFS_ILOG_CORE;
> 	}
> 
> ?

The previous version had it that way; Dave asked me to make it a helper.

--D

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+
  2020-08-27  7:00   ` Christoph Hellwig
@ 2020-08-27 17:49     ` Darrick J. Wong
  0 siblings, 0 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-27 17:49 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: david, linux-xfs, amir73il, sandeen

On Thu, Aug 27, 2020 at 08:00:50AM +0100, Christoph Hellwig wrote:
> > diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> > index 972c740aaf7b..9cf84b57e2ce 100644
> > --- a/fs/xfs/libxfs/xfs_format.h
> > +++ b/fs/xfs/libxfs/xfs_format.h
> > @@ -1257,13 +1257,15 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
> >  #define XFS_DQTYPE_USER		0x01		/* user dquot record */
> >  #define XFS_DQTYPE_PROJ		0x02		/* project dquot record */
> >  #define XFS_DQTYPE_GROUP	0x04		/* group dquot record */
> > +#define XFS_DQTYPE_BIGTIME	0x08		/* large expiry timestamps */
> 
> Maybe make this the high bit in the field to keep space for adding more
> actual quota types if we need them?

Ok.  0x80 it is.

--D

> Otherwise looks good:
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 01/11] xfs: explicitly define inode timestamp range
  2020-08-26 22:05 ` [PATCH 01/11] xfs: explicitly define inode timestamp range Darrick J. Wong
  2020-08-27  6:42   ` Christoph Hellwig
@ 2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  4:08 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: Amir Goldstein, linux-xfs, sandeen



On 8/26/20 3:05 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Formally define the inode timestamp ranges that existing filesystems
> support, and switch the vfs timetamp ranges to use it.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Looks ok to me:
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/libxfs/xfs_format.h |   22 ++++++++++++++++++++++
>   fs/xfs/xfs_super.c         |    4 ++--
>   2 files changed, 24 insertions(+), 2 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index fe129fe16d5f..e57360a8fd16 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -848,11 +848,33 @@ struct xfs_agfl {
>   	    ASSERT(xfs_daddr_to_agno(mp, d) == \
>   		   xfs_daddr_to_agno(mp, (d) + (len) - 1)))
>   
> +/*
> + * XFS Timestamps
> + * ==============
> + *
> + * Traditional ondisk inode timestamps consist of signed 32-bit counters for
> + * seconds and nanoseconds; time zero is the Unix epoch, Jan  1 00:00:00 UTC
> + * 1970, which means that the timestamp epoch is the same as the Unix epoch.
> + * Therefore, the ondisk min and max defined here can be used directly to
> + * constrain the incore timestamps on a Unix system.
> + */
>   typedef struct xfs_timestamp {
>   	__be32		t_sec;		/* timestamp seconds */
>   	__be32		t_nsec;		/* timestamp nanoseconds */
>   } xfs_timestamp_t;
>   
> +/*
> + * Smallest possible ondisk seconds value with traditional timestamps.  This
> + * corresponds exactly with the incore timestamp Dec 13 20:45:52 UTC 1901.
> + */
> +#define XFS_LEGACY_TIME_MIN	((int64_t)S32_MIN)
> +
> +/*
> + * Largest possible ondisk seconds value with traditional timestamps.  This
> + * corresponds exactly with the incore timestamp Jan 19 03:14:07 UTC 2038.
> + */
> +#define XFS_LEGACY_TIME_MAX	((int64_t)S32_MAX)
> +
>   /*
>    * On-disk inode structure.
>    *
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index c7ffcb57b586..b3b0e6154bf2 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -1484,8 +1484,8 @@ xfs_fc_fill_super(
>   	sb->s_maxbytes = MAX_LFS_FILESIZE;
>   	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_LEGACY_TIME_MIN;
> +	sb->s_time_max = XFS_LEGACY_TIME_MAX;
>   	sb->s_iflags |= SB_I_CGROUPWB;
>   
>   	set_posix_acl_flag(sb);
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 02/11] xfs: refactor quota expiration timer modification
  2020-08-26 22:05 ` [PATCH 02/11] xfs: refactor quota expiration timer modification Darrick J. Wong
  2020-08-27  6:43   ` Christoph Hellwig
@ 2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  4:08 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: linux-xfs, amir73il, sandeen



On 8/26/20 3:05 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Define explicit limits on the range of quota grace period expiration
> timeouts and refactor the code that modifies the timeouts into helpers
> that clamp the values appropriately.  Note that we'll refactor the
> default grace period timer separately.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Ok, looks ok
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/libxfs/xfs_format.h |   24 ++++++++++++++++++++++++
>   fs/xfs/xfs_dquot.c         |   22 ++++++++++++++++++----
>   fs/xfs/xfs_dquot.h         |    2 ++
>   fs/xfs/xfs_qm.c            |    2 ++
>   fs/xfs/xfs_qm.h            |    4 ++++
>   fs/xfs/xfs_qm_syscalls.c   |   16 +++++++++++-----
>   6 files changed, 61 insertions(+), 9 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index e57360a8fd16..cb316053d3db 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -1199,6 +1199,30 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
>   
>   #define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK)
>   
> +/*
> + * XFS Quota Timers
> + * ================
> + *
> + * Traditional quota grace period expiration timers are an unsigned 32-bit
> + * seconds counter; time zero is the Unix epoch, Jan  1 00:00:01 UTC 1970.
> + * Note that an expiration value of zero means that the quota limit has not
> + * been reached, and therefore no expiration has been set.  Therefore, the
> + * ondisk min and max defined here can be used directly to constrain the incore
> + * quota expiration timestamps on a Unix system.
> + */
> +
> +/*
> + * Smallest possible ondisk quota expiration value with traditional timestamps.
> + * This corresponds exactly with the incore expiration Jan  1 00:00:01 UTC 1970.
> + */
> +#define XFS_DQ_LEGACY_EXPIRY_MIN	((int64_t)1)
> +
> +/*
> + * Largest possible ondisk quota expiration value with traditional timestamps.
> + * This corresponds exactly with the incore expiration Feb  7 06:28:15 UTC 2106.
> + */
> +#define XFS_DQ_LEGACY_EXPIRY_MAX	((int64_t)U32_MAX)
> +
>   /*
>    * This is the main portion of the on-disk representation of quota information
>    * for a user.  We pad this with some more expansion room to construct the on
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index bcd73b9c2994..f34841f98d44 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -98,12 +98,25 @@ xfs_qm_adjust_dqlimits(
>   		xfs_dquot_set_prealloc_limits(dq);
>   }
>   
> +/* Set the expiration time of a quota's grace period. */
> +time64_t
> +xfs_dquot_set_timeout(
> +	struct xfs_mount	*mp,
> +	time64_t		timeout)
> +{
> +	struct xfs_quotainfo	*qi = mp->m_quotainfo;
> +
> +	return clamp_t(time64_t, timeout, qi->qi_expiry_min,
> +					  qi->qi_expiry_max);
> +}
> +
>   /*
>    * Determine if this quota counter is over either limit and set the quota
>    * timers as appropriate.
>    */
>   static inline void
>   xfs_qm_adjust_res_timer(
> +	struct xfs_mount	*mp,
>   	struct xfs_dquot_res	*res,
>   	struct xfs_quota_limits	*qlim)
>   {
> @@ -112,7 +125,8 @@ xfs_qm_adjust_res_timer(
>   	if ((res->softlimit && res->count > res->softlimit) ||
>   	    (res->hardlimit && res->count > res->hardlimit)) {
>   		if (res->timer == 0)
> -			res->timer = ktime_get_real_seconds() + qlim->time;
> +			res->timer = xfs_dquot_set_timeout(mp,
> +					ktime_get_real_seconds() + qlim->time);
>   	} else {
>   		if (res->timer == 0)
>   			res->warnings = 0;
> @@ -145,9 +159,9 @@ xfs_qm_adjust_dqtimers(
>   	ASSERT(dq->q_id);
>   	defq = xfs_get_defquota(qi, xfs_dquot_type(dq));
>   
> -	xfs_qm_adjust_res_timer(&dq->q_blk, &defq->blk);
> -	xfs_qm_adjust_res_timer(&dq->q_ino, &defq->ino);
> -	xfs_qm_adjust_res_timer(&dq->q_rtb, &defq->rtb);
> +	xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_blk, &defq->blk);
> +	xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_ino, &defq->ino);
> +	xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_rtb, &defq->rtb);
>   }
>   
>   /*
> diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
> index 282a65da93c7..0e449101c861 100644
> --- a/fs/xfs/xfs_dquot.h
> +++ b/fs/xfs/xfs_dquot.h
> @@ -237,4 +237,6 @@ typedef int (*xfs_qm_dqiterate_fn)(struct xfs_dquot *dq,
>   int xfs_qm_dqiterate(struct xfs_mount *mp, xfs_dqtype_t type,
>   		xfs_qm_dqiterate_fn iter_fn, void *priv);
>   
> +time64_t xfs_dquot_set_timeout(struct xfs_mount *mp, time64_t timeout);
> +
>   #endif /* __XFS_DQUOT_H__ */
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index be67570badf8..b83a12ecfc35 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -661,6 +661,8 @@ xfs_qm_init_quotainfo(
>   	/* Precalc some constants */
>   	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
>   	qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
> +	qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
> +	qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
>   
>   	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
>   
> diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
> index 9c078c35d924..e3dabab44097 100644
> --- a/fs/xfs/xfs_qm.h
> +++ b/fs/xfs/xfs_qm.h
> @@ -65,6 +65,10 @@ struct xfs_quotainfo {
>   	struct xfs_def_quota	qi_grp_default;
>   	struct xfs_def_quota	qi_prj_default;
>   	struct shrinker		qi_shrinker;
> +
> +	/* Minimum and maximum quota expiration timestamp values. */
> +	time64_t		qi_expiry_min;
> +	time64_t		qi_expiry_max;
>   };
>   
>   static inline struct radix_tree_root *
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 1c542b4a5220..750f775ae915 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -479,13 +479,19 @@ xfs_setqlim_warns(
>   
>   static inline void
>   xfs_setqlim_timer(
> +	struct xfs_mount	*mp,
>   	struct xfs_dquot_res	*res,
>   	struct xfs_quota_limits	*qlim,
>   	s64			timer)
>   {
> -	res->timer = timer;
> -	if (qlim)
> +	if (qlim) {
> +		/* Set the length of the default grace period. */
> +		res->timer = timer;
>   		qlim->time = timer;
> +	} else {
> +		/* Set the grace period expiration on a quota. */
> +		res->timer = xfs_dquot_set_timeout(mp, timer);
> +	}
>   }
>   
>   /*
> @@ -574,7 +580,7 @@ xfs_qm_scall_setqlim(
>   	if (newlim->d_fieldmask & QC_SPC_WARNS)
>   		xfs_setqlim_warns(res, qlim, newlim->d_spc_warns);
>   	if (newlim->d_fieldmask & QC_SPC_TIMER)
> -		xfs_setqlim_timer(res, qlim, newlim->d_spc_timer);
> +		xfs_setqlim_timer(mp, res, qlim, newlim->d_spc_timer);
>   
>   	/* Blocks on the realtime device. */
>   	hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
> @@ -590,7 +596,7 @@ xfs_qm_scall_setqlim(
>   	if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
>   		xfs_setqlim_warns(res, qlim, newlim->d_rt_spc_warns);
>   	if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
> -		xfs_setqlim_timer(res, qlim, newlim->d_rt_spc_timer);
> +		xfs_setqlim_timer(mp, res, qlim, newlim->d_rt_spc_timer);
>   
>   	/* Inodes */
>   	hard = (newlim->d_fieldmask & QC_INO_HARD) ?
> @@ -606,7 +612,7 @@ xfs_qm_scall_setqlim(
>   	if (newlim->d_fieldmask & QC_INO_WARNS)
>   		xfs_setqlim_warns(res, qlim, newlim->d_ino_warns);
>   	if (newlim->d_fieldmask & QC_INO_TIMER)
> -		xfs_setqlim_timer(res, qlim, newlim->d_ino_timer);
> +		xfs_setqlim_timer(mp, res, qlim, newlim->d_ino_timer);
>   
>   	if (id != 0) {
>   		/*
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 03/11] xfs: refactor default quota grace period setting code
  2020-08-26 22:05 ` [PATCH 03/11] xfs: refactor default quota grace period setting code Darrick J. Wong
  2020-08-27  6:44   ` Christoph Hellwig
@ 2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  4:08 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: Amir Goldstein, linux-xfs, sandeen



On 8/26/20 3:05 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Refactor the code that sets the default quota grace period into a helper
> function so that we can override the ondisk behavior later.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Looks ok
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/libxfs/xfs_format.h |   13 +++++++++++++
>   fs/xfs/xfs_dquot.c         |    8 ++++++++
>   fs/xfs/xfs_dquot.h         |    1 +
>   fs/xfs/xfs_qm_syscalls.c   |    4 ++--
>   4 files changed, 24 insertions(+), 2 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index cb316053d3db..4b68a473b090 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -1209,6 +1209,11 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
>    * been reached, and therefore no expiration has been set.  Therefore, the
>    * ondisk min and max defined here can be used directly to constrain the incore
>    * quota expiration timestamps on a Unix system.
> + *
> + * The grace period for each quota type is stored in the root dquot (id = 0)
> + * and is applied to a non-root dquot when it exceeds the soft or hard limits.
> + * The length of quota grace periods are unsigned 32-bit quantities measured in
> + * units of seconds.  A value of zero means to use the default period.
>    */
>   
>   /*
> @@ -1223,6 +1228,14 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
>    */
>   #define XFS_DQ_LEGACY_EXPIRY_MAX	((int64_t)U32_MAX)
>   
> +/*
> + * Default quota grace periods, ranging from zero (use the compiled defaults)
> + * to ~136 years.  These are applied to a non-root dquot that has exceeded
> + * either limit.
> + */
> +#define XFS_DQ_GRACE_MIN		((int64_t)0)
> +#define XFS_DQ_GRACE_MAX		((int64_t)U32_MAX)
> +
>   /*
>    * This is the main portion of the on-disk representation of quota information
>    * for a user.  We pad this with some more expansion room to construct the on
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index f34841f98d44..e63a933413a3 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -110,6 +110,14 @@ xfs_dquot_set_timeout(
>   					  qi->qi_expiry_max);
>   }
>   
> +/* Set the length of the default grace period. */
> +time64_t
> +xfs_dquot_set_grace_period(
> +	time64_t		grace)
> +{
> +	return clamp_t(time64_t, grace, XFS_DQ_GRACE_MIN, XFS_DQ_GRACE_MAX);
> +}
> +
>   /*
>    * Determine if this quota counter is over either limit and set the quota
>    * timers as appropriate.
> diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
> index 0e449101c861..f642884a6834 100644
> --- a/fs/xfs/xfs_dquot.h
> +++ b/fs/xfs/xfs_dquot.h
> @@ -238,5 +238,6 @@ int xfs_qm_dqiterate(struct xfs_mount *mp, xfs_dqtype_t type,
>   		xfs_qm_dqiterate_fn iter_fn, void *priv);
>   
>   time64_t xfs_dquot_set_timeout(struct xfs_mount *mp, time64_t timeout);
> +time64_t xfs_dquot_set_grace_period(time64_t grace);
>   
>   #endif /* __XFS_DQUOT_H__ */
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 750f775ae915..ca1b57d291dc 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -486,8 +486,8 @@ xfs_setqlim_timer(
>   {
>   	if (qlim) {
>   		/* Set the length of the default grace period. */
> -		res->timer = timer;
> -		qlim->time = timer;
> +		res->timer = xfs_dquot_set_grace_period(timer);
> +		qlim->time = res->timer;
>   	} else {
>   		/* Set the grace period expiration on a quota. */
>   		res->timer = xfs_dquot_set_timeout(mp, timer);
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 04/11] xfs: refactor quota timestamp coding
  2020-08-26 22:05 ` [PATCH 04/11] xfs: refactor quota timestamp coding Darrick J. Wong
  2020-08-27  6:44   ` Christoph Hellwig
@ 2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  4:08 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: Amir Goldstein, linux-xfs, sandeen



On 8/26/20 3:05 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Refactor quota timestamp encoding and decoding into helper functions so
> that we can add extra behavior in the next patch.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Looks fine
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/libxfs/xfs_dquot_buf.c  |   18 ++++++++++++++++++
>   fs/xfs/libxfs/xfs_quota_defs.h |    5 +++++
>   fs/xfs/xfs_dquot.c             |   12 ++++++------
>   3 files changed, 29 insertions(+), 6 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
> index 5a2db00b9d5f..cf85bad8a894 100644
> --- a/fs/xfs/libxfs/xfs_dquot_buf.c
> +++ b/fs/xfs/libxfs/xfs_dquot_buf.c
> @@ -288,3 +288,21 @@ const struct xfs_buf_ops xfs_dquot_buf_ra_ops = {
>   	.verify_read = xfs_dquot_buf_readahead_verify,
>   	.verify_write = xfs_dquot_buf_write_verify,
>   };
> +
> +/* Convert an on-disk timer value into an incore timer value. */
> +time64_t
> +xfs_dquot_from_disk_ts(
> +	struct xfs_disk_dquot	*ddq,
> +	__be32			dtimer)
> +{
> +	return be32_to_cpu(dtimer);
> +}
> +
> +/* Convert an incore timer value into an on-disk timer value. */
> +__be32
> +xfs_dquot_to_disk_ts(
> +	struct xfs_dquot	*dqp,
> +	time64_t		timer)
> +{
> +	return cpu_to_be32(timer);
> +}
> diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
> index 076bdc7037ee..9a99910d857e 100644
> --- a/fs/xfs/libxfs/xfs_quota_defs.h
> +++ b/fs/xfs/libxfs/xfs_quota_defs.h
> @@ -143,4 +143,9 @@ extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
>   extern void xfs_dqblk_repair(struct xfs_mount *mp, struct xfs_dqblk *dqb,
>   		xfs_dqid_t id, xfs_dqtype_t type);
>   
> +struct xfs_dquot;
> +time64_t xfs_dquot_from_disk_ts(struct xfs_disk_dquot *ddq,
> +		__be32 dtimer);
> +__be32 xfs_dquot_to_disk_ts(struct xfs_dquot *ddq, time64_t timer);
> +
>   #endif	/* __XFS_QUOTA_H__ */
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index e63a933413a3..59c03e973741 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -536,9 +536,9 @@ xfs_dquot_from_disk(
>   	dqp->q_ino.warnings = be16_to_cpu(ddqp->d_iwarns);
>   	dqp->q_rtb.warnings = be16_to_cpu(ddqp->d_rtbwarns);
>   
> -	dqp->q_blk.timer = be32_to_cpu(ddqp->d_btimer);
> -	dqp->q_ino.timer = be32_to_cpu(ddqp->d_itimer);
> -	dqp->q_rtb.timer = be32_to_cpu(ddqp->d_rtbtimer);
> +	dqp->q_blk.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_btimer);
> +	dqp->q_ino.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_itimer);
> +	dqp->q_rtb.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_rtbtimer);
>   
>   	/*
>   	 * Reservation counters are defined as reservation plus current usage
> @@ -581,9 +581,9 @@ xfs_dquot_to_disk(
>   	ddqp->d_iwarns = cpu_to_be16(dqp->q_ino.warnings);
>   	ddqp->d_rtbwarns = cpu_to_be16(dqp->q_rtb.warnings);
>   
> -	ddqp->d_btimer = cpu_to_be32(dqp->q_blk.timer);
> -	ddqp->d_itimer = cpu_to_be32(dqp->q_ino.timer);
> -	ddqp->d_rtbtimer = cpu_to_be32(dqp->q_rtb.timer);
> +	ddqp->d_btimer = xfs_dquot_to_disk_ts(dqp, dqp->q_blk.timer);
> +	ddqp->d_itimer = xfs_dquot_to_disk_ts(dqp, dqp->q_ino.timer);
> +	ddqp->d_rtbtimer = xfs_dquot_to_disk_ts(dqp, dqp->q_rtb.timer);
>   }
>   
>   /* Allocate and initialize the dquot buffer for this in-core dquot. */
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 05/11] xfs: move xfs_log_dinode_to_disk to the log recovery code
  2020-08-26 22:05 ` [PATCH 05/11] xfs: move xfs_log_dinode_to_disk to the log recovery code Darrick J. Wong
  2020-08-27  6:45   ` Christoph Hellwig
@ 2020-08-28  4:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  4:08 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: linux-xfs, amir73il, sandeen



On 8/26/20 3:05 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Move this function to xfs_inode_item_recover.c since there's only one
> caller of it.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Looks fine
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/libxfs/xfs_inode_buf.c   |   52 ---------------------------------------
>   fs/xfs/libxfs/xfs_inode_buf.h   |    2 --
>   fs/xfs/xfs_inode_item_recover.c |   52 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 52 insertions(+), 54 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 8d5dd08eab75..fa83591ca89b 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -310,58 +310,6 @@ xfs_inode_to_disk(
>   	}
>   }
>   
> -void
> -xfs_log_dinode_to_disk(
> -	struct xfs_log_dinode	*from,
> -	struct xfs_dinode	*to)
> -{
> -	to->di_magic = cpu_to_be16(from->di_magic);
> -	to->di_mode = cpu_to_be16(from->di_mode);
> -	to->di_version = from->di_version;
> -	to->di_format = from->di_format;
> -	to->di_onlink = 0;
> -	to->di_uid = cpu_to_be32(from->di_uid);
> -	to->di_gid = cpu_to_be32(from->di_gid);
> -	to->di_nlink = cpu_to_be32(from->di_nlink);
> -	to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
> -	to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
> -	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_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_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_size = cpu_to_be64(from->di_size);
> -	to->di_nblocks = cpu_to_be64(from->di_nblocks);
> -	to->di_extsize = cpu_to_be32(from->di_extsize);
> -	to->di_nextents = cpu_to_be32(from->di_nextents);
> -	to->di_anextents = cpu_to_be16(from->di_anextents);
> -	to->di_forkoff = from->di_forkoff;
> -	to->di_aformat = from->di_aformat;
> -	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
> -	to->di_dmstate = cpu_to_be16(from->di_dmstate);
> -	to->di_flags = cpu_to_be16(from->di_flags);
> -	to->di_gen = cpu_to_be32(from->di_gen);
> -
> -	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_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);
> -		to->di_lsn = cpu_to_be64(from->di_lsn);
> -		memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
> -		uuid_copy(&to->di_uuid, &from->di_uuid);
> -		to->di_flushiter = 0;
> -	} else {
> -		to->di_flushiter = cpu_to_be16(from->di_flushiter);
> -	}
> -}
> -
>   static xfs_failaddr_t
>   xfs_dinode_verify_fork(
>   	struct xfs_dinode	*dip,
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
> index 6b08b9d060c2..89f7bea8efd6 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.h
> +++ b/fs/xfs/libxfs/xfs_inode_buf.h
> @@ -49,8 +49,6 @@ void	xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *);
>   void	xfs_inode_to_disk(struct xfs_inode *ip, struct xfs_dinode *to,
>   			  xfs_lsn_t lsn);
>   int	xfs_inode_from_disk(struct xfs_inode *ip, struct xfs_dinode *from);
> -void	xfs_log_dinode_to_disk(struct xfs_log_dinode *from,
> -			       struct xfs_dinode *to);
>   
>   xfs_failaddr_t xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino,
>   			   struct xfs_dinode *dip);
> diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
> index 5e0d291835b3..1e417ace2912 100644
> --- a/fs/xfs/xfs_inode_item_recover.c
> +++ b/fs/xfs/xfs_inode_item_recover.c
> @@ -115,6 +115,58 @@ xfs_recover_inode_owner_change(
>   	return error;
>   }
>   
> +STATIC void
> +xfs_log_dinode_to_disk(
> +	struct xfs_log_dinode	*from,
> +	struct xfs_dinode	*to)
> +{
> +	to->di_magic = cpu_to_be16(from->di_magic);
> +	to->di_mode = cpu_to_be16(from->di_mode);
> +	to->di_version = from->di_version;
> +	to->di_format = from->di_format;
> +	to->di_onlink = 0;
> +	to->di_uid = cpu_to_be32(from->di_uid);
> +	to->di_gid = cpu_to_be32(from->di_gid);
> +	to->di_nlink = cpu_to_be32(from->di_nlink);
> +	to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
> +	to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
> +	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_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_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_size = cpu_to_be64(from->di_size);
> +	to->di_nblocks = cpu_to_be64(from->di_nblocks);
> +	to->di_extsize = cpu_to_be32(from->di_extsize);
> +	to->di_nextents = cpu_to_be32(from->di_nextents);
> +	to->di_anextents = cpu_to_be16(from->di_anextents);
> +	to->di_forkoff = from->di_forkoff;
> +	to->di_aformat = from->di_aformat;
> +	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
> +	to->di_dmstate = cpu_to_be16(from->di_dmstate);
> +	to->di_flags = cpu_to_be16(from->di_flags);
> +	to->di_gen = cpu_to_be32(from->di_gen);
> +
> +	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_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);
> +		to->di_lsn = cpu_to_be64(from->di_lsn);
> +		memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
> +		uuid_copy(&to->di_uuid, &from->di_uuid);
> +		to->di_flushiter = 0;
> +	} else {
> +		to->di_flushiter = cpu_to_be16(from->di_flushiter);
> +	}
> +}
> +
>   STATIC int
>   xlog_recover_inode_commit_pass2(
>   	struct xlog			*log,
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 06/11] xfs: kill struct xfs_timestamp
  2020-08-26 22:05 ` [PATCH 06/11] xfs: kill struct xfs_timestamp Darrick J. Wong
@ 2020-08-28  4:08   ` Allison Collins
  0 siblings, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  4:08 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: linux-xfs, amir73il, sandeen



On 8/26/20 3:05 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Replace this struct with an encoded __be64 value and add conversion
> helpers to deal with the change.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Ok, looks good
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/libxfs/xfs_format.h      |    8 ++---
>   fs/xfs/libxfs/xfs_inode_buf.c   |   62 +++++++++++++++++++++++++++++----------
>   fs/xfs/libxfs/xfs_inode_buf.h   |    2 +
>   fs/xfs/scrub/inode.c            |   25 +++++++++++-----
>   fs/xfs/xfs_inode_item_recover.c |   26 +++++++++++-----
>   fs/xfs/xfs_ondisk.h             |    2 +
>   6 files changed, 87 insertions(+), 38 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 4b68a473b090..96734ba9aa5f 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -856,12 +856,10 @@ struct xfs_agfl {
>    * seconds and nanoseconds; time zero is the Unix epoch, Jan  1 00:00:00 UTC
>    * 1970, which means that the timestamp epoch is the same as the Unix epoch.
>    * Therefore, the ondisk min and max defined here can be used directly to
> - * constrain the incore timestamps on a Unix system.
> + * constrain the incore timestamps on a Unix system.  Note that we actually
> + * encode a __be64 value on disk.
>    */
> -typedef struct xfs_timestamp {
> -	__be32		t_sec;		/* timestamp seconds */
> -	__be32		t_nsec;		/* timestamp nanoseconds */
> -} xfs_timestamp_t;
> +typedef __be64 xfs_timestamp_t;
>   
>   /*
>    * Smallest possible ondisk seconds value with traditional timestamps.  This
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index fa83591ca89b..1e65e28a9386 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -157,6 +157,26 @@ xfs_imap_to_bp(
>   	return 0;
>   }
>   
> +/*
> + * Convert an ondisk timestamp to an incore timestamp.
> + *
> + * For traditional timestamps, the ondisk format specifies that the seconds
> + * are stored in the first four bytes and the nanoseconds in the second four.
> + * Let the be64 conversion rotate the seconds field into the upper 32-bits,
> + * then shift and mask to extract the two values.
> + */
> +struct timespec64
> +xfs_inode_from_disk_ts(
> +	const xfs_timestamp_t	ts)
> +{
> +	struct timespec64	tv;
> +	uint64_t		t = be64_to_cpu(ts);
> +
> +	tv.tv_sec = (int64_t)t >> 32;
> +	tv.tv_nsec = (int32_t)(t & 0xffffffff);
> +	return tv;
> +}
> +
>   int
>   xfs_inode_from_disk(
>   	struct xfs_inode	*ip,
> @@ -211,12 +231,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);
> +	inode->i_atime = xfs_inode_from_disk_ts(from->di_atime);
> +	inode->i_mtime = xfs_inode_from_disk_ts(from->di_mtime);
> +	inode->i_ctime = xfs_inode_from_disk_ts(from->di_ctime);
>   
>   	to->di_size = be64_to_cpu(from->di_size);
>   	to->di_nblocks = be64_to_cpu(from->di_nblocks);
> @@ -229,8 +246,7 @@ xfs_inode_from_disk(
>   	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
>   		inode_set_iversion_queried(inode,
>   					   be64_to_cpu(from->di_changecount));
> -		to->di_crtime.tv_sec = be32_to_cpu(from->di_crtime.t_sec);
> -		to->di_crtime.tv_nsec = be32_to_cpu(from->di_crtime.t_nsec);
> +		to->di_crtime = xfs_inode_from_disk_ts(from->di_crtime);
>   		to->di_flags2 = be64_to_cpu(from->di_flags2);
>   		to->di_cowextsize = be32_to_cpu(from->di_cowextsize);
>   	}
> @@ -252,6 +268,24 @@ xfs_inode_from_disk(
>   	return error;
>   }
>   
> +/*
> + * Convert an incore timestamp to an ondisk timestamp.
> + *
> + * For traditional timestamps, the ondisk format specifies that the seconds
> + * are stored in the first four bytes and the nanoseconds in the second four.
> + * Shift the seconds into the upper 32-bits so that the be64 conversion will
> + * take care of rotating the bytes for us.
> + */
> +static inline xfs_timestamp_t
> +xfs_inode_to_disk_ts(
> +	const struct timespec64	tv)
> +{
> +	uint64_t		t;
> +
> +	t = ((int64_t)tv.tv_sec << 32) | (tv.tv_nsec & 0xffffffff);
> +	return cpu_to_be64(t);
> +}
> +
>   void
>   xfs_inode_to_disk(
>   	struct xfs_inode	*ip,
> @@ -271,12 +305,9 @@ xfs_inode_to_disk(
>   	to->di_projid_hi = cpu_to_be16(from->di_projid >> 16);
>   
>   	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);
> +	to->di_atime = xfs_inode_to_disk_ts(inode->i_atime);
> +	to->di_mtime = xfs_inode_to_disk_ts(inode->i_mtime);
> +	to->di_ctime = xfs_inode_to_disk_ts(inode->i_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);
> @@ -295,8 +326,7 @@ xfs_inode_to_disk(
>   	if (xfs_sb_version_has_v3inode(&ip->i_mount->m_sb)) {
>   		to->di_version = 3;
>   		to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));
> -		to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.tv_sec);
> -		to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.tv_nsec);
> +		to->di_crtime = xfs_inode_to_disk_ts(from->di_crtime);
>   		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);
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
> index 89f7bea8efd6..3060ecd24a2e 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.h
> +++ b/fs/xfs/libxfs/xfs_inode_buf.h
> @@ -58,4 +58,6 @@ xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
>   		uint32_t cowextsize, uint16_t mode, uint16_t flags,
>   		uint64_t flags2);
>   
> +struct timespec64 xfs_inode_from_disk_ts(const xfs_timestamp_t ts);
> +
>   #endif	/* __XFS_INODE_BUF_H__ */
> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
> index 6d483ab29e63..eb1cc013d4ca 100644
> --- a/fs/xfs/scrub/inode.c
> +++ b/fs/xfs/scrub/inode.c
> @@ -195,6 +195,19 @@ xchk_inode_flags2(
>   	xchk_ino_set_corrupt(sc, ino);
>   }
>   
> +static inline void
> +xchk_dinode_nsec(
> +	struct xfs_scrub	*sc,
> +	xfs_ino_t		ino,
> +	const xfs_timestamp_t	ts)
> +{
> +	struct timespec64	tv;
> +
> +	tv = xfs_inode_from_disk_ts(ts);
> +	if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
> +		xchk_ino_set_corrupt(sc, ino);
> +}
> +
>   /* Scrub all the ondisk inode fields. */
>   STATIC void
>   xchk_dinode(
> @@ -293,12 +306,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)
> -		xchk_ino_set_corrupt(sc, ino);
> +	xchk_dinode_nsec(sc, ino, dip->di_atime);
> +	xchk_dinode_nsec(sc, ino, dip->di_mtime);
> +	xchk_dinode_nsec(sc, ino, dip->di_ctime);
>   
>   	/*
>   	 * di_size.  xfs_dinode_verify checks for things that screw up
> @@ -403,8 +413,7 @@ xchk_dinode(
>   	}
>   
>   	if (dip->di_version >= 3) {
> -		if (be32_to_cpu(dip->di_crtime.t_nsec) >= NSEC_PER_SEC)
> -			xchk_ino_set_corrupt(sc, ino);
> +		xchk_dinode_nsec(sc, ino, dip->di_crtime);
>   		xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
>   		xchk_inode_cowextsize(sc, dip, ino, mode, flags,
>   				flags2);
> diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
> index 1e417ace2912..e7c6f2b95e17 100644
> --- a/fs/xfs/xfs_inode_item_recover.c
> +++ b/fs/xfs/xfs_inode_item_recover.c
> @@ -115,6 +115,20 @@ xfs_recover_inode_owner_change(
>   	return error;
>   }
>   
> +/*
> + * Convert a log timestamp to an ondisk timestamp.  See notes about the ondisk
> + * encoding in the comments for xfs_inode_to_disk_ts.
> + */
> +static inline xfs_timestamp_t
> +xfs_log_dinode_to_disk_ts(
> +	const xfs_ictimestamp_t	its)
> +{
> +	uint64_t		t;
> +
> +	t = ((int64_t)its.t_sec << 32) | (its.t_nsec & 0xffffffff);
> +	return cpu_to_be64(t);
> +}
> +
>   STATIC void
>   xfs_log_dinode_to_disk(
>   	struct xfs_log_dinode	*from,
> @@ -132,12 +146,9 @@ xfs_log_dinode_to_disk(
>   	to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
>   	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_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_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_atime = xfs_log_dinode_to_disk_ts(from->di_atime);
> +	to->di_mtime = xfs_log_dinode_to_disk_ts(from->di_mtime);
> +	to->di_ctime = xfs_log_dinode_to_disk_ts(from->di_ctime);
>   
>   	to->di_size = cpu_to_be64(from->di_size);
>   	to->di_nblocks = cpu_to_be64(from->di_nblocks);
> @@ -153,8 +164,7 @@ 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 = xfs_log_dinode_to_disk_ts(from->di_crtime);
>   		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/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
> index acb9b737fe6b..2f11a6f9e005 100644
> --- a/fs/xfs/xfs_ondisk.h
> +++ b/fs/xfs/xfs_ondisk.h
> @@ -41,7 +41,7 @@ xfs_check_ondisk_structs(void)
>   	XFS_CHECK_STRUCT_SIZE(struct xfs_refcount_rec,		12);
>   	XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_key,		20);
>   	XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_rec,		24);
> -	XFS_CHECK_STRUCT_SIZE(struct xfs_timestamp,		8);
> +	XFS_CHECK_STRUCT_SIZE(xfs_timestamp_t,			8);
>   	XFS_CHECK_STRUCT_SIZE(xfs_alloc_key_t,			8);
>   	XFS_CHECK_STRUCT_SIZE(xfs_alloc_ptr_t,			4);
>   	XFS_CHECK_STRUCT_SIZE(xfs_alloc_rec_t,			8);
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+
  2020-08-26 22:05 ` [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+ Darrick J. Wong
  2020-08-27  7:00   ` Christoph Hellwig
@ 2020-08-28  6:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  6:08 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: linux-xfs, amir73il, sandeen



On 8/26/20 3:05 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Enable the bigtime feature for quota timers.  We decrease the accuracy
> of the timers to ~4s in exchange for being able to set timers up to the
> bigtime maximum.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
ok, looks ok to me
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/libxfs/xfs_dquot_buf.c  |   21 +++++++++++++++--
>   fs/xfs/libxfs/xfs_format.h     |   50 +++++++++++++++++++++++++++++++++++++++-
>   fs/xfs/libxfs/xfs_quota_defs.h |    3 ++
>   fs/xfs/xfs_dquot.c             |   10 ++++++++
>   fs/xfs/xfs_ondisk.h            |    5 ++++
>   fs/xfs/xfs_qm.c                |   13 +++++++++-
>   fs/xfs/xfs_trans_dquot.c       |    6 +++++
>   7 files changed, 102 insertions(+), 6 deletions(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
> index cf85bad8a894..6766417d5ba4 100644
> --- a/fs/xfs/libxfs/xfs_dquot_buf.c
> +++ b/fs/xfs/libxfs/xfs_dquot_buf.c
> @@ -69,6 +69,13 @@ xfs_dquot_verify(
>   	    ddq_type != XFS_DQTYPE_GROUP)
>   		return __this_address;
>   
> +	if ((ddq->d_type & XFS_DQTYPE_BIGTIME) &&
> +	    !xfs_sb_version_hasbigtime(&mp->m_sb))
> +		return __this_address;
> +
> +	if ((ddq->d_type & XFS_DQTYPE_BIGTIME) && !ddq->d_id)
> +		return __this_address;
> +
>   	if (id != -1 && id != be32_to_cpu(ddq->d_id))
>   		return __this_address;
>   
> @@ -295,7 +302,12 @@ xfs_dquot_from_disk_ts(
>   	struct xfs_disk_dquot	*ddq,
>   	__be32			dtimer)
>   {
> -	return be32_to_cpu(dtimer);
> +	uint32_t		t = be32_to_cpu(dtimer);
> +
> +	if (t != 0 && (ddq->d_type & XFS_DQTYPE_BIGTIME))
> +		return xfs_dq_bigtime_to_unix(t);
> +
> +	return t;
>   }
>   
>   /* Convert an incore timer value into an on-disk timer value. */
> @@ -304,5 +316,10 @@ xfs_dquot_to_disk_ts(
>   	struct xfs_dquot	*dqp,
>   	time64_t		timer)
>   {
> -	return cpu_to_be32(timer);
> +	uint32_t		t = timer;
> +
> +	if (timer != 0 && (dqp->q_type & XFS_DQTYPE_BIGTIME))
> +		t = xfs_dq_unix_to_bigtime(timer);
> +
> +	return cpu_to_be32(t);
>   }
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 972c740aaf7b..9cf84b57e2ce 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -1257,13 +1257,15 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
>   #define XFS_DQTYPE_USER		0x01		/* user dquot record */
>   #define XFS_DQTYPE_PROJ		0x02		/* project dquot record */
>   #define XFS_DQTYPE_GROUP	0x04		/* group dquot record */
> +#define XFS_DQTYPE_BIGTIME	0x08		/* large expiry timestamps */
>   
>   /* bitmask to determine if this is a user/group/project dquot */
>   #define XFS_DQTYPE_REC_MASK	(XFS_DQTYPE_USER | \
>   				 XFS_DQTYPE_PROJ | \
>   				 XFS_DQTYPE_GROUP)
>   
> -#define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK)
> +#define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK | \
> +				 XFS_DQTYPE_BIGTIME)
>   
>   /*
>    * XFS Quota Timers
> @@ -1276,6 +1278,10 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
>    * ondisk min and max defined here can be used directly to constrain the incore
>    * quota expiration timestamps on a Unix system.
>    *
> + * When bigtime is enabled, we trade two bits of precision to expand the
> + * expiration timeout range to match that of big inode timestamps.  The min and
> + * max recorded here are the on-disk limits, not a Unix timestamp.
> + *
>    * The grace period for each quota type is stored in the root dquot (id = 0)
>    * and is applied to a non-root dquot when it exceeds the soft or hard limits.
>    * The length of quota grace periods are unsigned 32-bit quantities measured in
> @@ -1294,6 +1300,48 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
>    */
>   #define XFS_DQ_LEGACY_EXPIRY_MAX	((int64_t)U32_MAX)
>   
> +/*
> + * Smallest possible ondisk quota expiration value with bigtime timestamps.
> + * This corresponds (after conversion to a Unix timestamp) with the incore
> + * expiration of Jan  1 00:00:04 UTC 1970.
> + */
> +#define XFS_DQ_BIGTIME_EXPIRY_MIN	(XFS_DQ_LEGACY_EXPIRY_MIN)
> +
> +/*
> + * Largest supported ondisk quota expiration value with bigtime timestamps.
> + * This corresponds (after conversion to a Unix timestamp) with an incore
> + * expiration of Jul  2 20:20:24 UTC 2486.
> + *
> + * The ondisk field supports values up to -1U, which corresponds to an incore
> + * expiration in 2514.  This is beyond the maximum the bigtime inode timestamp,
> + * so we cap the maximum bigtime quota expiration to the max inode timestamp.
> + */
> +#define XFS_DQ_BIGTIME_EXPIRY_MAX	((int64_t)4074815106U)
> +
> +/*
> + * The following conversion factors assist in converting a quota expiration
> + * timestamp between the incore and ondisk formats.
> + */
> +#define XFS_DQ_BIGTIME_SHIFT	(2)
> +#define XFS_DQ_BIGTIME_SLACK	((int64_t)(1ULL << XFS_DQ_BIGTIME_SHIFT) - 1)
> +
> +/* Convert an incore quota expiration timestamp to an ondisk bigtime value. */
> +static inline uint32_t xfs_dq_unix_to_bigtime(time64_t unix_seconds)
> +{
> +	/*
> +	 * Round the expiration timestamp up to the nearest bigtime timestamp
> +	 * that we can store, to give users the most time to fix problems.
> +	 */
> +	return ((uint64_t)unix_seconds + XFS_DQ_BIGTIME_SLACK) >>
> +			XFS_DQ_BIGTIME_SHIFT;
> +}
> +
> +/* Convert an ondisk bigtime quota expiration value to an incore timestamp. */
> +static inline time64_t xfs_dq_bigtime_to_unix(uint32_t ondisk_seconds)
> +{
> +	return (time64_t)ondisk_seconds << XFS_DQ_BIGTIME_SHIFT;
> +}
> +
>   /*
>    * Default quota grace periods, ranging from zero (use the compiled defaults)
>    * to ~136 years.  These are applied to a non-root dquot that has exceeded
> diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
> index 9a99910d857e..0f0af4e35032 100644
> --- a/fs/xfs/libxfs/xfs_quota_defs.h
> +++ b/fs/xfs/libxfs/xfs_quota_defs.h
> @@ -23,7 +23,8 @@ typedef uint8_t		xfs_dqtype_t;
>   #define XFS_DQTYPE_STRINGS \
>   	{ XFS_DQTYPE_USER,	"USER" }, \
>   	{ XFS_DQTYPE_PROJ,	"PROJ" }, \
> -	{ XFS_DQTYPE_GROUP,	"GROUP" }
> +	{ XFS_DQTYPE_GROUP,	"GROUP" }, \
> +	{ XFS_DQTYPE_BIGTIME,	"BIGTIME" }
>   
>   /*
>    * flags for q_flags field in the dquot.
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index 59c03e973741..3f9e11c3df1e 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -223,6 +223,8 @@ xfs_qm_init_dquot_blk(
>   		d->dd_diskdq.d_version = XFS_DQUOT_VERSION;
>   		d->dd_diskdq.d_id = cpu_to_be32(curid);
>   		d->dd_diskdq.d_type = type;
> +		if (curid > 0 && xfs_sb_version_hasbigtime(&mp->m_sb))
> +			d->dd_diskdq.d_type |= XFS_DQTYPE_BIGTIME;
>   		if (xfs_sb_version_hascrc(&mp->m_sb)) {
>   			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
>   			xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
> @@ -1167,6 +1169,14 @@ xfs_qm_dqflush_check(
>   	    !dqp->q_rtb.timer)
>   		return __this_address;
>   
> +	/* bigtime flag should never be set on root dquots */
> +	if (dqp->q_type & XFS_DQTYPE_BIGTIME) {
> +		if (!xfs_sb_version_hasbigtime(&dqp->q_mount->m_sb))
> +			return __this_address;
> +		if (dqp->q_id == 0)
> +			return __this_address;
> +	}
> +
>   	return NULL;
>   }
>   
> diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
> index 52db8743def1..a13686ce0626 100644
> --- a/fs/xfs/xfs_ondisk.h
> +++ b/fs/xfs/xfs_ondisk.h
> @@ -165,6 +165,11 @@ xfs_check_ondisk_structs(void)
>   			XFS_LEGACY_TIME_MIN);
>   	XFS_CHECK_VALUE(XFS_BIGTIME_TIME_MAX - XFS_BIGTIME_EPOCH_OFFSET,
>   			16299260424LL);
> +
> +	/* Do the same with the incore quota expiration range. */
> +	XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MIN << XFS_DQ_BIGTIME_SHIFT, 4);
> +	XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MAX << XFS_DQ_BIGTIME_SHIFT,
> +			16299260424LL);
>   }
>   
>   #endif /* __XFS_ONDISK_H */
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index b83a12ecfc35..259588a4227d 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -661,8 +661,15 @@ xfs_qm_init_quotainfo(
>   	/* Precalc some constants */
>   	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
>   	qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
> -	qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
> -	qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
> +	if (xfs_sb_version_hasbigtime(&mp->m_sb)) {
> +		qinf->qi_expiry_min =
> +			xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MIN);
> +		qinf->qi_expiry_max =
> +			xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MAX);
> +	} else {
> +		qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
> +		qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
> +	}
>   
>   	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
>   
> @@ -881,6 +888,8 @@ xfs_qm_reset_dqcounts(
>   			ddq->d_bwarns = 0;
>   			ddq->d_iwarns = 0;
>   			ddq->d_rtbwarns = 0;
> +			if (xfs_sb_version_hasbigtime(&mp->m_sb))
> +				ddq->d_type |= XFS_DQTYPE_BIGTIME;
>   		}
>   
>   		if (xfs_sb_version_hascrc(&mp->m_sb)) {
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index c6ba7ef18e06..133fc6fc3edd 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -55,6 +55,12 @@ xfs_trans_log_dquot(
>   {
>   	ASSERT(XFS_DQ_IS_LOCKED(dqp));
>   
> +	/* Upgrade the dquot to bigtime format if possible. */
> +	if (dqp->q_id != 0 &&
> +	    xfs_sb_version_hasbigtime(&tp->t_mountp->m_sb) &&
> +	    !(dqp->q_type & XFS_DQTYPE_BIGTIME))
> +		dqp->q_type |= XFS_DQTYPE_BIGTIME;
> +
>   	tp->t_flags |= XFS_TRANS_DIRTY;
>   	set_bit(XFS_LI_DIRTY, &dqp->q_logitem.qli_item.li_flags);
>   }
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 10/11] xfs: trace timestamp limits
  2020-08-26 22:06 ` [PATCH 10/11] xfs: trace timestamp limits Darrick J. Wong
  2020-08-27  7:01   ` Christoph Hellwig
@ 2020-08-28  6:08   ` Allison Collins
  1 sibling, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  6:08 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: linux-xfs, amir73il, sandeen



On 8/26/20 3:06 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Add a couple of tracepoints so that we can check the timestamp limits
> being set on inodes and quotas.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Looks ok
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/xfs_qm.c    |    2 ++
>   fs/xfs/xfs_super.c |    1 +
>   fs/xfs/xfs_trace.h |   26 ++++++++++++++++++++++++++
>   3 files changed, 29 insertions(+)
> 
> 
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index 259588a4227d..3f82e0c92c2d 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -670,6 +670,8 @@ xfs_qm_init_quotainfo(
>   		qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
>   		qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
>   	}
> +	trace_xfs_quota_expiry_range(mp, qinf->qi_expiry_min,
> +			qinf->qi_expiry_max);
>   
>   	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
>   
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index 58be2220ae05..8230c902a813 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -1491,6 +1491,7 @@ xfs_fc_fill_super(
>   		sb->s_time_min = XFS_LEGACY_TIME_MIN;
>   		sb->s_time_max = XFS_LEGACY_TIME_MAX;
>   	}
> +	trace_xfs_inode_timestamp_range(mp, sb->s_time_min, sb->s_time_max);
>   	sb->s_iflags |= SB_I_CGROUPWB;
>   
>   	set_posix_acl_flag(sb);
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index abb1d859f226..a3a35a2d8ed9 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -3844,6 +3844,32 @@ TRACE_EVENT(xfs_btree_bload_block,
>   		  __entry->nr_records)
>   )
>   
> +DECLARE_EVENT_CLASS(xfs_timestamp_range_class,
> +	TP_PROTO(struct xfs_mount *mp, time64_t min, time64_t max),
> +	TP_ARGS(mp, min, max),
> +	TP_STRUCT__entry(
> +		__field(dev_t, dev)
> +		__field(long long, min)
> +		__field(long long, max)
> +	),
> +	TP_fast_assign(
> +		__entry->dev = mp->m_super->s_dev;
> +		__entry->min = min;
> +		__entry->max = max;
> +	),
> +	TP_printk("dev %d:%d min %lld max %lld",
> +		  MAJOR(__entry->dev), MINOR(__entry->dev),
> +		  __entry->min,
> +		  __entry->max)
> +)
> +
> +#define DEFINE_TIMESTAMP_RANGE_EVENT(name) \
> +DEFINE_EVENT(xfs_timestamp_range_class, name, \
> +	TP_PROTO(struct xfs_mount *mp, long long min, long long max), \
> +	TP_ARGS(mp, min, max))
> +DEFINE_TIMESTAMP_RANGE_EVENT(xfs_inode_timestamp_range);
> +DEFINE_TIMESTAMP_RANGE_EVENT(xfs_quota_expiry_range);
> +
>   #endif /* _TRACE_XFS_H */
>   
>   #undef TRACE_INCLUDE_PATH
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 11/11] xfs: enable big timestamps
  2020-08-26 22:06 ` [PATCH 11/11] xfs: enable big timestamps Darrick J. Wong
@ 2020-08-28  6:09   ` Allison Collins
  0 siblings, 0 replies; 39+ messages in thread
From: Allison Collins @ 2020-08-28  6:09 UTC (permalink / raw)
  To: Darrick J. Wong, david, hch; +Cc: Amir Goldstein, linux-xfs, sandeen



On 8/26/20 3:06 PM, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Enable the big timestamp feature.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Looks ok
Reviewed-by: Allison Collins <allison.henderson@oracle.com>

> ---
>   fs/xfs/libxfs/xfs_format.h |    3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 9cf84b57e2ce..4ba92b8fb0a7 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -471,7 +471,8 @@ xfs_sb_has_ro_compat_feature(
>   #define XFS_SB_FEAT_INCOMPAT_ALL \
>   		(XFS_SB_FEAT_INCOMPAT_FTYPE|	\
>   		 XFS_SB_FEAT_INCOMPAT_SPINODES|	\
> -		 XFS_SB_FEAT_INCOMPAT_META_UUID)
> +		 XFS_SB_FEAT_INCOMPAT_META_UUID| \
> +		 XFS_SB_FEAT_INCOMPAT_BIGTIME)
>   
>   #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
>   static inline bool
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+
  2020-09-02  2:56 [PATCH v6 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
@ 2020-09-02  2:57 ` Darrick J. Wong
  0 siblings, 0 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-09-02  2:57 UTC (permalink / raw)
  To: darrick.wong, david, hch
  Cc: Christoph Hellwig, Allison Collins, linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Enable the bigtime feature for quota timers.  We decrease the accuracy
of the timers to ~4s in exchange for being able to set timers up to the
bigtime maximum.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_dquot_buf.c  |   21 +++++++++++++++--
 fs/xfs/libxfs/xfs_format.h     |   50 +++++++++++++++++++++++++++++++++++++++-
 fs/xfs/libxfs/xfs_quota_defs.h |    3 ++
 fs/xfs/xfs_dquot.c             |   10 ++++++++
 fs/xfs/xfs_ondisk.h            |    5 ++++
 fs/xfs/xfs_qm.c                |   13 +++++++++-
 fs/xfs/xfs_trans_dquot.c       |    6 +++++
 7 files changed, 102 insertions(+), 6 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
index cf85bad8a894..6766417d5ba4 100644
--- a/fs/xfs/libxfs/xfs_dquot_buf.c
+++ b/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -69,6 +69,13 @@ xfs_dquot_verify(
 	    ddq_type != XFS_DQTYPE_GROUP)
 		return __this_address;
 
+	if ((ddq->d_type & XFS_DQTYPE_BIGTIME) &&
+	    !xfs_sb_version_hasbigtime(&mp->m_sb))
+		return __this_address;
+
+	if ((ddq->d_type & XFS_DQTYPE_BIGTIME) && !ddq->d_id)
+		return __this_address;
+
 	if (id != -1 && id != be32_to_cpu(ddq->d_id))
 		return __this_address;
 
@@ -295,7 +302,12 @@ xfs_dquot_from_disk_ts(
 	struct xfs_disk_dquot	*ddq,
 	__be32			dtimer)
 {
-	return be32_to_cpu(dtimer);
+	uint32_t		t = be32_to_cpu(dtimer);
+
+	if (t != 0 && (ddq->d_type & XFS_DQTYPE_BIGTIME))
+		return xfs_dq_bigtime_to_unix(t);
+
+	return t;
 }
 
 /* Convert an incore timer value into an on-disk timer value. */
@@ -304,5 +316,10 @@ xfs_dquot_to_disk_ts(
 	struct xfs_dquot	*dqp,
 	time64_t		timer)
 {
-	return cpu_to_be32(timer);
+	uint32_t		t = timer;
+
+	if (timer != 0 && (dqp->q_type & XFS_DQTYPE_BIGTIME))
+		t = xfs_dq_unix_to_bigtime(timer);
+
+	return cpu_to_be32(t);
 }
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 6aabe15786b8..394159808ffa 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1263,13 +1263,15 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
 #define XFS_DQTYPE_USER		0x01		/* user dquot record */
 #define XFS_DQTYPE_PROJ		0x02		/* project dquot record */
 #define XFS_DQTYPE_GROUP	0x04		/* group dquot record */
+#define XFS_DQTYPE_BIGTIME	0x80		/* large expiry timestamps */
 
 /* bitmask to determine if this is a user/group/project dquot */
 #define XFS_DQTYPE_REC_MASK	(XFS_DQTYPE_USER | \
 				 XFS_DQTYPE_PROJ | \
 				 XFS_DQTYPE_GROUP)
 
-#define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK)
+#define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK | \
+				 XFS_DQTYPE_BIGTIME)
 
 /*
  * XFS Quota Timers
@@ -1282,6 +1284,10 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
  * ondisk min and max defined here can be used directly to constrain the incore
  * quota expiration timestamps on a Unix system.
  *
+ * When bigtime is enabled, we trade two bits of precision to expand the
+ * expiration timeout range to match that of big inode timestamps.  The min and
+ * max recorded here are the on-disk limits, not a Unix timestamp.
+ *
  * The grace period for each quota type is stored in the root dquot (id = 0)
  * and is applied to a non-root dquot when it exceeds the soft or hard limits.
  * The length of quota grace periods are unsigned 32-bit quantities measured in
@@ -1300,6 +1306,48 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
  */
 #define XFS_DQ_LEGACY_EXPIRY_MAX	((int64_t)U32_MAX)
 
+/*
+ * Smallest possible ondisk quota expiration value with bigtime timestamps.
+ * This corresponds (after conversion to a Unix timestamp) with the incore
+ * expiration of Jan  1 00:00:04 UTC 1970.
+ */
+#define XFS_DQ_BIGTIME_EXPIRY_MIN	(XFS_DQ_LEGACY_EXPIRY_MIN)
+
+/*
+ * Largest supported ondisk quota expiration value with bigtime timestamps.
+ * This corresponds (after conversion to a Unix timestamp) with an incore
+ * expiration of Jul  2 20:20:24 UTC 2486.
+ *
+ * The ondisk field supports values up to -1U, which corresponds to an incore
+ * expiration in 2514.  This is beyond the maximum the bigtime inode timestamp,
+ * so we cap the maximum bigtime quota expiration to the max inode timestamp.
+ */
+#define XFS_DQ_BIGTIME_EXPIRY_MAX	((int64_t)4074815106U)
+
+/*
+ * The following conversion factors assist in converting a quota expiration
+ * timestamp between the incore and ondisk formats.
+ */
+#define XFS_DQ_BIGTIME_SHIFT	(2)
+#define XFS_DQ_BIGTIME_SLACK	((int64_t)(1ULL << XFS_DQ_BIGTIME_SHIFT) - 1)
+
+/* Convert an incore quota expiration timestamp to an ondisk bigtime value. */
+static inline uint32_t xfs_dq_unix_to_bigtime(time64_t unix_seconds)
+{
+	/*
+	 * Round the expiration timestamp up to the nearest bigtime timestamp
+	 * that we can store, to give users the most time to fix problems.
+	 */
+	return ((uint64_t)unix_seconds + XFS_DQ_BIGTIME_SLACK) >>
+			XFS_DQ_BIGTIME_SHIFT;
+}
+
+/* Convert an ondisk bigtime quota expiration value to an incore timestamp. */
+static inline time64_t xfs_dq_bigtime_to_unix(uint32_t ondisk_seconds)
+{
+	return (time64_t)ondisk_seconds << XFS_DQ_BIGTIME_SHIFT;
+}
+
 /*
  * Default quota grace periods, ranging from zero (use the compiled defaults)
  * to ~136 years.  These are applied to a non-root dquot that has exceeded
diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index 9a99910d857e..0f0af4e35032 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -23,7 +23,8 @@ typedef uint8_t		xfs_dqtype_t;
 #define XFS_DQTYPE_STRINGS \
 	{ XFS_DQTYPE_USER,	"USER" }, \
 	{ XFS_DQTYPE_PROJ,	"PROJ" }, \
-	{ XFS_DQTYPE_GROUP,	"GROUP" }
+	{ XFS_DQTYPE_GROUP,	"GROUP" }, \
+	{ XFS_DQTYPE_BIGTIME,	"BIGTIME" }
 
 /*
  * flags for q_flags field in the dquot.
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 59c03e973741..3f9e11c3df1e 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -223,6 +223,8 @@ xfs_qm_init_dquot_blk(
 		d->dd_diskdq.d_version = XFS_DQUOT_VERSION;
 		d->dd_diskdq.d_id = cpu_to_be32(curid);
 		d->dd_diskdq.d_type = type;
+		if (curid > 0 && xfs_sb_version_hasbigtime(&mp->m_sb))
+			d->dd_diskdq.d_type |= XFS_DQTYPE_BIGTIME;
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 			xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
@@ -1167,6 +1169,14 @@ xfs_qm_dqflush_check(
 	    !dqp->q_rtb.timer)
 		return __this_address;
 
+	/* bigtime flag should never be set on root dquots */
+	if (dqp->q_type & XFS_DQTYPE_BIGTIME) {
+		if (!xfs_sb_version_hasbigtime(&dqp->q_mount->m_sb))
+			return __this_address;
+		if (dqp->q_id == 0)
+			return __this_address;
+	}
+
 	return NULL;
 }
 
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index a9dbf21f13d8..f6956c98b2f0 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -167,6 +167,11 @@ xfs_check_ondisk_structs(void)
 			XFS_LEGACY_TIME_MIN);
 	XFS_CHECK_VALUE(XFS_BIGTIME_TIME_MAX - XFS_BIGTIME_EPOCH_OFFSET,
 			16299260424LL);
+
+	/* Do the same with the incore quota expiration range. */
+	XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MIN << XFS_DQ_BIGTIME_SHIFT, 4);
+	XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MAX << XFS_DQ_BIGTIME_SHIFT,
+			16299260424LL);
 }
 
 #endif /* __XFS_ONDISK_H */
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index b83a12ecfc35..259588a4227d 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -661,8 +661,15 @@ xfs_qm_init_quotainfo(
 	/* Precalc some constants */
 	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
 	qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
-	qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
-	qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
+	if (xfs_sb_version_hasbigtime(&mp->m_sb)) {
+		qinf->qi_expiry_min =
+			xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MIN);
+		qinf->qi_expiry_max =
+			xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MAX);
+	} else {
+		qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
+		qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
+	}
 
 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
@@ -881,6 +888,8 @@ xfs_qm_reset_dqcounts(
 			ddq->d_bwarns = 0;
 			ddq->d_iwarns = 0;
 			ddq->d_rtbwarns = 0;
+			if (xfs_sb_version_hasbigtime(&mp->m_sb))
+				ddq->d_type |= XFS_DQTYPE_BIGTIME;
 		}
 
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index c6ba7ef18e06..133fc6fc3edd 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -55,6 +55,12 @@ xfs_trans_log_dquot(
 {
 	ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
+	/* Upgrade the dquot to bigtime format if possible. */
+	if (dqp->q_id != 0 &&
+	    xfs_sb_version_hasbigtime(&tp->t_mountp->m_sb) &&
+	    !(dqp->q_type & XFS_DQTYPE_BIGTIME))
+		dqp->q_type |= XFS_DQTYPE_BIGTIME;
+
 	tp->t_flags |= XFS_TRANS_DIRTY;
 	set_bit(XFS_LI_DIRTY, &dqp->q_logitem.qli_item.li_flags);
 }


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+
  2020-08-31  6:06 [PATCH v5 " Darrick J. Wong
@ 2020-08-31  6:07 ` Darrick J. Wong
  0 siblings, 0 replies; 39+ messages in thread
From: Darrick J. Wong @ 2020-08-31  6:07 UTC (permalink / raw)
  To: darrick.wong, david, hch
  Cc: Christoph Hellwig, Allison Collins, linux-xfs, amir73il, sandeen

From: Darrick J. Wong <darrick.wong@oracle.com>

Enable the bigtime feature for quota timers.  We decrease the accuracy
of the timers to ~4s in exchange for being able to set timers up to the
bigtime maximum.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_dquot_buf.c  |   21 +++++++++++++++--
 fs/xfs/libxfs/xfs_format.h     |   50 +++++++++++++++++++++++++++++++++++++++-
 fs/xfs/libxfs/xfs_quota_defs.h |    3 ++
 fs/xfs/xfs_dquot.c             |   10 ++++++++
 fs/xfs/xfs_ondisk.h            |    5 ++++
 fs/xfs/xfs_qm.c                |   13 +++++++++-
 fs/xfs/xfs_trans_dquot.c       |    6 +++++
 7 files changed, 102 insertions(+), 6 deletions(-)


diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c
index cf85bad8a894..6766417d5ba4 100644
--- a/fs/xfs/libxfs/xfs_dquot_buf.c
+++ b/fs/xfs/libxfs/xfs_dquot_buf.c
@@ -69,6 +69,13 @@ xfs_dquot_verify(
 	    ddq_type != XFS_DQTYPE_GROUP)
 		return __this_address;
 
+	if ((ddq->d_type & XFS_DQTYPE_BIGTIME) &&
+	    !xfs_sb_version_hasbigtime(&mp->m_sb))
+		return __this_address;
+
+	if ((ddq->d_type & XFS_DQTYPE_BIGTIME) && !ddq->d_id)
+		return __this_address;
+
 	if (id != -1 && id != be32_to_cpu(ddq->d_id))
 		return __this_address;
 
@@ -295,7 +302,12 @@ xfs_dquot_from_disk_ts(
 	struct xfs_disk_dquot	*ddq,
 	__be32			dtimer)
 {
-	return be32_to_cpu(dtimer);
+	uint32_t		t = be32_to_cpu(dtimer);
+
+	if (t != 0 && (ddq->d_type & XFS_DQTYPE_BIGTIME))
+		return xfs_dq_bigtime_to_unix(t);
+
+	return t;
 }
 
 /* Convert an incore timer value into an on-disk timer value. */
@@ -304,5 +316,10 @@ xfs_dquot_to_disk_ts(
 	struct xfs_dquot	*dqp,
 	time64_t		timer)
 {
-	return cpu_to_be32(timer);
+	uint32_t		t = timer;
+
+	if (timer != 0 && (dqp->q_type & XFS_DQTYPE_BIGTIME))
+		t = xfs_dq_unix_to_bigtime(timer);
+
+	return cpu_to_be32(t);
 }
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 6aabe15786b8..394159808ffa 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1263,13 +1263,15 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
 #define XFS_DQTYPE_USER		0x01		/* user dquot record */
 #define XFS_DQTYPE_PROJ		0x02		/* project dquot record */
 #define XFS_DQTYPE_GROUP	0x04		/* group dquot record */
+#define XFS_DQTYPE_BIGTIME	0x80		/* large expiry timestamps */
 
 /* bitmask to determine if this is a user/group/project dquot */
 #define XFS_DQTYPE_REC_MASK	(XFS_DQTYPE_USER | \
 				 XFS_DQTYPE_PROJ | \
 				 XFS_DQTYPE_GROUP)
 
-#define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK)
+#define XFS_DQTYPE_ANY		(XFS_DQTYPE_REC_MASK | \
+				 XFS_DQTYPE_BIGTIME)
 
 /*
  * XFS Quota Timers
@@ -1282,6 +1284,10 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
  * ondisk min and max defined here can be used directly to constrain the incore
  * quota expiration timestamps on a Unix system.
  *
+ * When bigtime is enabled, we trade two bits of precision to expand the
+ * expiration timeout range to match that of big inode timestamps.  The min and
+ * max recorded here are the on-disk limits, not a Unix timestamp.
+ *
  * The grace period for each quota type is stored in the root dquot (id = 0)
  * and is applied to a non-root dquot when it exceeds the soft or hard limits.
  * The length of quota grace periods are unsigned 32-bit quantities measured in
@@ -1300,6 +1306,48 @@ static inline bool xfs_dinode_has_bigtime(const struct xfs_dinode *dip)
  */
 #define XFS_DQ_LEGACY_EXPIRY_MAX	((int64_t)U32_MAX)
 
+/*
+ * Smallest possible ondisk quota expiration value with bigtime timestamps.
+ * This corresponds (after conversion to a Unix timestamp) with the incore
+ * expiration of Jan  1 00:00:04 UTC 1970.
+ */
+#define XFS_DQ_BIGTIME_EXPIRY_MIN	(XFS_DQ_LEGACY_EXPIRY_MIN)
+
+/*
+ * Largest supported ondisk quota expiration value with bigtime timestamps.
+ * This corresponds (after conversion to a Unix timestamp) with an incore
+ * expiration of Jul  2 20:20:24 UTC 2486.
+ *
+ * The ondisk field supports values up to -1U, which corresponds to an incore
+ * expiration in 2514.  This is beyond the maximum the bigtime inode timestamp,
+ * so we cap the maximum bigtime quota expiration to the max inode timestamp.
+ */
+#define XFS_DQ_BIGTIME_EXPIRY_MAX	((int64_t)4074815106U)
+
+/*
+ * The following conversion factors assist in converting a quota expiration
+ * timestamp between the incore and ondisk formats.
+ */
+#define XFS_DQ_BIGTIME_SHIFT	(2)
+#define XFS_DQ_BIGTIME_SLACK	((int64_t)(1ULL << XFS_DQ_BIGTIME_SHIFT) - 1)
+
+/* Convert an incore quota expiration timestamp to an ondisk bigtime value. */
+static inline uint32_t xfs_dq_unix_to_bigtime(time64_t unix_seconds)
+{
+	/*
+	 * Round the expiration timestamp up to the nearest bigtime timestamp
+	 * that we can store, to give users the most time to fix problems.
+	 */
+	return ((uint64_t)unix_seconds + XFS_DQ_BIGTIME_SLACK) >>
+			XFS_DQ_BIGTIME_SHIFT;
+}
+
+/* Convert an ondisk bigtime quota expiration value to an incore timestamp. */
+static inline time64_t xfs_dq_bigtime_to_unix(uint32_t ondisk_seconds)
+{
+	return (time64_t)ondisk_seconds << XFS_DQ_BIGTIME_SHIFT;
+}
+
 /*
  * Default quota grace periods, ranging from zero (use the compiled defaults)
  * to ~136 years.  These are applied to a non-root dquot that has exceeded
diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index 9a99910d857e..0f0af4e35032 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -23,7 +23,8 @@ typedef uint8_t		xfs_dqtype_t;
 #define XFS_DQTYPE_STRINGS \
 	{ XFS_DQTYPE_USER,	"USER" }, \
 	{ XFS_DQTYPE_PROJ,	"PROJ" }, \
-	{ XFS_DQTYPE_GROUP,	"GROUP" }
+	{ XFS_DQTYPE_GROUP,	"GROUP" }, \
+	{ XFS_DQTYPE_BIGTIME,	"BIGTIME" }
 
 /*
  * flags for q_flags field in the dquot.
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 59c03e973741..3f9e11c3df1e 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -223,6 +223,8 @@ xfs_qm_init_dquot_blk(
 		d->dd_diskdq.d_version = XFS_DQUOT_VERSION;
 		d->dd_diskdq.d_id = cpu_to_be32(curid);
 		d->dd_diskdq.d_type = type;
+		if (curid > 0 && xfs_sb_version_hasbigtime(&mp->m_sb))
+			d->dd_diskdq.d_type |= XFS_DQTYPE_BIGTIME;
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
 			uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid);
 			xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
@@ -1167,6 +1169,14 @@ xfs_qm_dqflush_check(
 	    !dqp->q_rtb.timer)
 		return __this_address;
 
+	/* bigtime flag should never be set on root dquots */
+	if (dqp->q_type & XFS_DQTYPE_BIGTIME) {
+		if (!xfs_sb_version_hasbigtime(&dqp->q_mount->m_sb))
+			return __this_address;
+		if (dqp->q_id == 0)
+			return __this_address;
+	}
+
 	return NULL;
 }
 
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index a9dbf21f13d8..f6956c98b2f0 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -167,6 +167,11 @@ xfs_check_ondisk_structs(void)
 			XFS_LEGACY_TIME_MIN);
 	XFS_CHECK_VALUE(XFS_BIGTIME_TIME_MAX - XFS_BIGTIME_EPOCH_OFFSET,
 			16299260424LL);
+
+	/* Do the same with the incore quota expiration range. */
+	XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MIN << XFS_DQ_BIGTIME_SHIFT, 4);
+	XFS_CHECK_VALUE(XFS_DQ_BIGTIME_EXPIRY_MAX << XFS_DQ_BIGTIME_SHIFT,
+			16299260424LL);
 }
 
 #endif /* __XFS_ONDISK_H */
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index b83a12ecfc35..259588a4227d 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -661,8 +661,15 @@ xfs_qm_init_quotainfo(
 	/* Precalc some constants */
 	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
 	qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
-	qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
-	qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
+	if (xfs_sb_version_hasbigtime(&mp->m_sb)) {
+		qinf->qi_expiry_min =
+			xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MIN);
+		qinf->qi_expiry_max =
+			xfs_dq_bigtime_to_unix(XFS_DQ_BIGTIME_EXPIRY_MAX);
+	} else {
+		qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
+		qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
+	}
 
 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
@@ -881,6 +888,8 @@ xfs_qm_reset_dqcounts(
 			ddq->d_bwarns = 0;
 			ddq->d_iwarns = 0;
 			ddq->d_rtbwarns = 0;
+			if (xfs_sb_version_hasbigtime(&mp->m_sb))
+				ddq->d_type |= XFS_DQTYPE_BIGTIME;
 		}
 
 		if (xfs_sb_version_hascrc(&mp->m_sb)) {
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index c6ba7ef18e06..133fc6fc3edd 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -55,6 +55,12 @@ xfs_trans_log_dquot(
 {
 	ASSERT(XFS_DQ_IS_LOCKED(dqp));
 
+	/* Upgrade the dquot to bigtime format if possible. */
+	if (dqp->q_id != 0 &&
+	    xfs_sb_version_hasbigtime(&tp->t_mountp->m_sb) &&
+	    !(dqp->q_type & XFS_DQTYPE_BIGTIME))
+		dqp->q_type |= XFS_DQTYPE_BIGTIME;
+
 	tp->t_flags |= XFS_TRANS_DIRTY;
 	set_bit(XFS_LI_DIRTY, &dqp->q_logitem.qli_item.li_flags);
 }


^ permalink raw reply related	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2020-09-02  2:59 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-26 22:04 [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
2020-08-26 22:05 ` [PATCH 01/11] xfs: explicitly define inode timestamp range Darrick J. Wong
2020-08-27  6:42   ` Christoph Hellwig
2020-08-28  4:08   ` Allison Collins
2020-08-26 22:05 ` [PATCH 02/11] xfs: refactor quota expiration timer modification Darrick J. Wong
2020-08-27  6:43   ` Christoph Hellwig
2020-08-28  4:08   ` Allison Collins
2020-08-26 22:05 ` [PATCH 03/11] xfs: refactor default quota grace period setting code Darrick J. Wong
2020-08-27  6:44   ` Christoph Hellwig
2020-08-28  4:08   ` Allison Collins
2020-08-26 22:05 ` [PATCH 04/11] xfs: refactor quota timestamp coding Darrick J. Wong
2020-08-27  6:44   ` Christoph Hellwig
2020-08-28  4:08   ` Allison Collins
2020-08-26 22:05 ` [PATCH 05/11] xfs: move xfs_log_dinode_to_disk to the log recovery code Darrick J. Wong
2020-08-27  6:45   ` Christoph Hellwig
2020-08-28  4:08   ` Allison Collins
2020-08-26 22:05 ` [PATCH 06/11] xfs: kill struct xfs_timestamp Darrick J. Wong
2020-08-28  4:08   ` Allison Collins
2020-08-26 22:05 ` [PATCH 07/11] xfs: kill struct xfs_ictimestamp Darrick J. Wong
2020-08-27  6:51   ` Christoph Hellwig
2020-08-27  8:17     ` Amir Goldstein
2020-08-27  8:18       ` Christoph Hellwig
2020-08-27  8:56         ` Amir Goldstein
2020-08-27 15:31     ` Darrick J. Wong
2020-08-26 22:05 ` [PATCH 08/11] xfs: widen ondisk inode timestamps to deal with y2038+ Darrick J. Wong
2020-08-27  6:58   ` Christoph Hellwig
2020-08-27 15:38     ` Darrick J. Wong
2020-08-26 22:05 ` [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+ Darrick J. Wong
2020-08-27  7:00   ` Christoph Hellwig
2020-08-27 17:49     ` Darrick J. Wong
2020-08-28  6:08   ` Allison Collins
2020-08-26 22:06 ` [PATCH 10/11] xfs: trace timestamp limits Darrick J. Wong
2020-08-27  7:01   ` Christoph Hellwig
2020-08-28  6:08   ` Allison Collins
2020-08-26 22:06 ` [PATCH 11/11] xfs: enable big timestamps Darrick J. Wong
2020-08-28  6:09   ` Allison Collins
2020-08-27  6:41 ` [PATCH v4 00/11] xfs: widen timestamps to deal with y2038 Christoph Hellwig
2020-08-31  6:06 [PATCH v5 " Darrick J. Wong
2020-08-31  6:07 ` [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+ Darrick J. Wong
2020-09-02  2:56 [PATCH v6 00/11] xfs: widen timestamps to deal with y2038 Darrick J. Wong
2020-09-02  2:57 ` [PATCH 09/11] xfs: widen ondisk quota expiration timestamps to handle y2038+ Darrick J. Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).