diff mbox series

[14/18] xfs_db: report bigtime format timestamps

Message ID 159770522219.3958786.9075094123951100725.stgit@magnolia
State Superseded
Headers show
Series xfsprogs: widen timestamps to deal with y2038 | expand

Commit Message

Darrick J. Wong Aug. 17, 2020, 11 p.m. UTC
From: Darrick J. Wong <darrick.wong@oracle.com>

Report the large format timestamps.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 db/dquot.c               |   31 +++++++++++-
 db/field.c               |    6 ++
 db/field.h               |    3 +
 db/fprint.c              |  120 ++++++++++++++++++++++++++++++++++++++++++++++
 db/fprint.h              |    6 ++
 db/inode.c               |   28 ++++++++++-
 db/sb.c                  |    2 +
 libxfs/libxfs_api_defs.h |    3 +
 8 files changed, 194 insertions(+), 5 deletions(-)

Comments

Darrick J. Wong Aug. 18, 2020, 3:37 p.m. UTC | #1
On Mon, Aug 17, 2020 at 04:00:22PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Report the large format timestamps.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
>  db/dquot.c               |   31 +++++++++++-
>  db/field.c               |    6 ++
>  db/field.h               |    3 +
>  db/fprint.c              |  120 ++++++++++++++++++++++++++++++++++++++++++++++
>  db/fprint.h              |    6 ++
>  db/inode.c               |   28 ++++++++++-
>  db/sb.c                  |    2 +
>  libxfs/libxfs_api_defs.h |    3 +
>  8 files changed, 194 insertions(+), 5 deletions(-)
> 
> 
> diff --git a/db/dquot.c b/db/dquot.c
> index edfcb0ca0744..30f4e6523c39 100644
> --- a/db/dquot.c
> +++ b/db/dquot.c
> @@ -44,6 +44,22 @@ const field_t	dqblk_flds[] = {
>  	{ NULL }
>  };
>  
> +static int
> +dquot_timestamp_count(
> +	void		*obj,
> +	int		startoff)
> +{
> +	return xfs_sb_version_hasbigtime(&mp->m_sb) ? 0 : 1;
> +}
> +
> +static int
> +dquot_bigtimestamp_count(
> +	void		*obj,
> +	int		startoff)
> +{
> +	return xfs_sb_version_hasbigtime(&mp->m_sb) ? 1 : 0;
> +}
> +
>  #define	DOFF(f)		bitize(offsetof(struct xfs_disk_dquot, d_ ## f))
>  const field_t	disk_dquot_flds[] = {
>  	{ "magic", FLDT_UINT16X, OI(DOFF(magic)), C1, 0, TYP_NONE },
> @@ -60,8 +76,14 @@ const field_t	disk_dquot_flds[] = {
>  	  TYP_NONE },
>  	{ "bcount", FLDT_QCNT, OI(DOFF(bcount)), C1, 0, TYP_NONE },
>  	{ "icount", FLDT_QCNT, OI(DOFF(icount)), C1, 0, TYP_NONE },
> -	{ "itimer", FLDT_INT32D, OI(DOFF(itimer)), C1, 0, TYP_NONE },
> -	{ "btimer", FLDT_INT32D, OI(DOFF(btimer)), C1, 0, TYP_NONE },
> +	{ "itimer", FLDT_INT32D, OI(DOFF(itimer)), dquot_timestamp_count,
> +	  FLD_COUNT, TYP_NONE },
> +	{ "btimer", FLDT_INT32D, OI(DOFF(btimer)), dquot_timestamp_count,
> +	  FLD_COUNT, TYP_NONE },
> +	{ "itimer", FLDT_BTQTIMER, OI(DOFF(itimer)), dquot_bigtimestamp_count,
> +	  FLD_COUNT, TYP_NONE },
> +	{ "btimer", FLDT_BTQTIMER, OI(DOFF(btimer)), dquot_bigtimestamp_count,
> +	  FLD_COUNT, TYP_NONE },
>  	{ "iwarns", FLDT_QWARNCNT, OI(DOFF(iwarns)), C1, 0, TYP_NONE },
>  	{ "bwarns", FLDT_QWARNCNT, OI(DOFF(bwarns)), C1, 0, TYP_NONE },
>  	{ "pad0", FLDT_UINT32X, OI(DOFF(pad0)), C1, FLD_SKIPALL, TYP_NONE },
> @@ -70,7 +92,10 @@ const field_t	disk_dquot_flds[] = {
>  	{ "rtb_softlimit", FLDT_QCNT, OI(DOFF(rtb_softlimit)), C1, 0,
>  	  TYP_NONE },
>  	{ "rtbcount", FLDT_QCNT, OI(DOFF(rtbcount)), C1, 0, TYP_NONE },
> -	{ "rtbtimer", FLDT_INT32D, OI(DOFF(rtbtimer)), C1, 0, TYP_NONE },
> +	{ "rtbtimer", FLDT_INT32D, OI(DOFF(rtbtimer)), dquot_timestamp_count,
> +	  FLD_COUNT, TYP_NONE },
> +	{ "rtbtimer", FLDT_BTQTIMER, OI(DOFF(rtbtimer)),
> +	  dquot_bigtimestamp_count, FLD_COUNT, TYP_NONE },
>  	{ "rtbwarns", FLDT_QWARNCNT, OI(DOFF(rtbwarns)), C1, 0, TYP_NONE },
>  	{ "pad", FLDT_UINT16X, OI(DOFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
>  	{ NULL }
> diff --git a/db/field.c b/db/field.c
> index cf3002c730e6..fad17b1f082e 100644
> --- a/db/field.c
> +++ b/db/field.c
> @@ -351,6 +351,12 @@ const ftattr_t	ftattrtab[] = {
>  	  NULL, NULL },
>  	{ FLDT_TIMESTAMP, "timestamp", NULL, (char *)timestamp_flds,
>  	  SI(bitsz(union xfs_timestamp)), 0, NULL, timestamp_flds },
> +	{ FLDT_BTSEC, "btsec", fp_btsec, NULL, SI(bitsz(uint64_t)), 0, NULL,
> +	  NULL },
> +	{ FLDT_BTNSEC, "btnsec", fp_btnsec, NULL, SI(bitsz(uint64_t)), 0, NULL,
> +	  NULL },
> +	{ FLDT_BTQTIMER, "btqtimer", fp_btqtimer, NULL, SI(bitsz(uint32_t)), 0,
> +	  NULL, NULL },
>  	{ FLDT_UINT1, "uint1", fp_num, "%u", SI(1), 0, NULL, NULL },
>  	{ FLDT_UINT16D, "uint16d", fp_num, "%u", SI(bitsz(uint16_t)), 0, NULL,
>  	  NULL },
> diff --git a/db/field.h b/db/field.h
> index 15065373de39..0d27cd085b13 100644
> --- a/db/field.h
> +++ b/db/field.h
> @@ -170,6 +170,9 @@ typedef enum fldt	{
>  
>  	FLDT_TIME,
>  	FLDT_TIMESTAMP,
> +	FLDT_BTSEC,
> +	FLDT_BTNSEC,
> +	FLDT_BTQTIMER,
>  	FLDT_UINT1,
>  	FLDT_UINT16D,
>  	FLDT_UINT16O,
> diff --git a/db/fprint.c b/db/fprint.c
> index c9d07e1bca7e..3a4f839b355d 100644
> --- a/db/fprint.c
> +++ b/db/fprint.c
> @@ -19,6 +19,7 @@
>  #include "sig.h"
>  #include "malloc.h"
>  #include "io.h"
> +#include "init.h"
>  
>  int
>  fp_charns(
> @@ -145,6 +146,125 @@ fp_time(
>  	return 1;
>  }
>  
> +static void
> +fp_timespec64(
> +	struct timespec64	*ts)
> +{
> +	BUILD_BUG_ON(sizeof(long) != sizeof(time_t));
> +
> +	if (ts->tv_sec > LONG_MAX || ts->tv_sec < LONG_MIN) {
> +		dbprintf("%lld", (long long)ts->tv_sec);
> +	} else {
> +		time_t	tt = ts->tv_sec;
> +		char	*c;
> +
> +		c = ctime(&tt);

Hmm, this really ought to fall back to the %lld printf if an error
occurs.

--D

> +		dbprintf("%24.24s", c);
> +	}
> +}
> +
> +int
> +fp_btsec(
> +	void			*obj,
> +	int			bit,
> +	int			count,
> +	char			*fmtstr,
> +	int			size,
> +	int			arg,
> +	int			base,
> +	int			array)
> +{
> +	struct timespec64	ts;
> +	union xfs_timestamp	*xts;
> +	int			bitpos;
> +	int			i;
> +
> +	ASSERT(bitoffs(bit) == 0);
> +	for (i = 0, bitpos = bit;
> +	     i < count && !seenint();
> +	     i++, bitpos += size) {
> +		if (array)
> +			dbprintf("%d:", i + base);
> +		xts = obj + byteize(bitpos);
> +		libxfs_inode_from_disk_timestamp(obj, &ts, xts);
> +		fp_timespec64(&ts);
> +		if (i < count - 1)
> +			dbprintf(" ");
> +	}
> +	return 1;
> +}
> +
> +int
> +fp_btnsec(
> +	void			*obj,
> +	int			bit,
> +	int			count,
> +	char			*fmtstr,
> +	int			size,
> +	int			arg,
> +	int			base,
> +	int			array)
> +{
> +	struct timespec64	ts;
> +	union xfs_timestamp	*xts;
> +	int			bitpos;
> +	int			i;
> +
> +	ASSERT(bitoffs(bit) == 0);
> +	for (i = 0, bitpos = bit;
> +	     i < count && !seenint();
> +	     i++, bitpos += size) {
> +		if (array)
> +			dbprintf("%d:", i + base);
> +		xts = obj + byteize(bitpos);
> +		libxfs_inode_from_disk_timestamp(obj, &ts, xts);
> +		dbprintf("%u", ts.tv_nsec);
> +		if (i < count - 1)
> +			dbprintf(" ");
> +	}
> +	return 1;
> +}
> +
> +int
> +fp_btqtimer(
> +	void			*obj,
> +	int			bit,
> +	int			count,
> +	char			*fmtstr,
> +	int			size,
> +	int			arg,
> +	int			base,
> +	int			array)
> +{
> +	struct timespec64	ts = { 0 };
> +	struct xfs_disk_dquot	*ddq = obj;
> +	__be32			*t;
> +	int			bitpos;
> +	int			i;
> +
> +	ASSERT(bitoffs(bit) == 0);
> +	for (i = 0, bitpos = bit;
> +	     i < count && !seenint();
> +	     i++, bitpos += size) {
> +		if (array)
> +			dbprintf("%d:", i + base);
> +		t = obj + byteize(bitpos);
> +		libxfs_dquot_from_disk_timestamp(ddq, &ts.tv_sec, *t);
> +
> +		/*
> +		 * Display the raw value if it's the default grace expiration
> +		 * period (root dquot) or if the quota has not expired.
> +		 */
> +		if (ddq->d_id == 0 || ts.tv_sec == 0)
> +			dbprintf("%llu", (unsigned long long)ts.tv_sec);
> +		else
> +			fp_timespec64(&ts);
> +		if (i < count - 1)
> +			dbprintf(" ");
> +	}
> +	return 1;
> +}
> +
>  /*ARGSUSED*/
>  int
>  fp_uuid(
> diff --git a/db/fprint.h b/db/fprint.h
> index c958dca0ed92..a33dcd11248d 100644
> --- a/db/fprint.h
> +++ b/db/fprint.h
> @@ -15,6 +15,12 @@ extern int	fp_sarray(void *obj, int bit, int count, char *fmtstr, int size,
>  			  int arg, int base, int array);
>  extern int	fp_time(void *obj, int bit, int count, char *fmtstr, int size,
>  			int arg, int base, int array);
> +extern int	fp_btsec(void *obj, int bit, int count, char *fmtstr, int size,
> +			int arg, int base, int array);
> +extern int	fp_btnsec(void *obj, int bit, int count, char *fmtstr, int size,
> +			int arg, int base, int array);
> +extern int	fp_btqtimer(void *obj, int bit, int count, char *fmtstr,
> +			int size, int arg, int base, int array);
>  extern int	fp_uuid(void *obj, int bit, int count, char *fmtstr, int size,
>  			int arg, int base, int array);
>  extern int	fp_crc(void *obj, int bit, int count, char *fmtstr, int size,
> diff --git a/db/inode.c b/db/inode.c
> index 25112bb5e4d8..5fbfd4ddb5f5 100644
> --- a/db/inode.c
> +++ b/db/inode.c
> @@ -175,14 +175,38 @@ const field_t	inode_v3_flds[] = {
>  	{ "dax", FLDT_UINT1,
>  	  OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_DAX_BIT - 1), C1,
>  	  0, TYP_NONE },
> +	{ "bigtime", FLDT_UINT1,
> +	  OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_BIGTIME_BIT - 1), C1,
> +	  0, TYP_NONE },
>  	{ NULL }
>  };
>  
> +static int
> +inode_timestamp_count(
> +	void		*obj,
> +	int		startoff)
> +{
> +	return xfs_sb_version_hasbigtime(&mp->m_sb) ? 0 : 1;
> +}
> +
> +static int
> +inode_bigtimestamp_count(
> +	void		*obj,
> +	int		startoff)
> +{
> +	return xfs_sb_version_hasbigtime(&mp->m_sb) ? 1 : 0;
> +}
>  
>  #define	TOFF(f)	bitize(offsetof(union xfs_timestamp, t_ ## f))
>  const field_t	timestamp_flds[] = {
> -	{ "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE },
> -	{ "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE },
> +	{ "sec", FLDT_TIME, OI(TOFF(sec)), inode_timestamp_count, FLD_COUNT,
> +		TYP_NONE },
> +	{ "nsec", FLDT_NSEC, OI(TOFF(nsec)), inode_timestamp_count, FLD_COUNT,
> +		TYP_NONE },
> +	{ "sec", FLDT_BTSEC, OI(TOFF(bigtime)), inode_bigtimestamp_count,
> +		FLD_COUNT, TYP_NONE },
> +	{ "nsec", FLDT_BTNSEC, OI(TOFF(bigtime)), inode_bigtimestamp_count,
> +		FLD_COUNT, TYP_NONE },
>  	{ NULL }
>  };
>  
> diff --git a/db/sb.c b/db/sb.c
> index 33d9f7df49bb..c68bb9a958e7 100644
> --- a/db/sb.c
> +++ b/db/sb.c
> @@ -727,6 +727,8 @@ version_string(
>  		strcat(s, ",REFLINK");
>  	if (xfs_sb_version_hasinobtcounts(sbp))
>  		strcat(s, ",INOBTCNT");
> +	if (xfs_sb_version_hasbigtime(sbp))
> +		strcat(s, ",BIGTIME");
>  	return s;
>  }
>  
> diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
> index 4ee02473df0d..b83dc48a4802 100644
> --- a/libxfs/libxfs_api_defs.h
> +++ b/libxfs/libxfs_api_defs.h
> @@ -116,6 +116,7 @@ struct timespec64 {
>  #define xfs_dir_replace			libxfs_dir_replace
>  
>  #define xfs_dqblk_repair		libxfs_dqblk_repair
> +#define xfs_dquot_from_disk_timestamp	libxfs_dquot_from_disk_timestamp
>  #define xfs_dquot_verify		libxfs_dquot_verify
>  
>  #define xfs_finobt_calc_reserves	libxfs_finobt_calc_reserves
> @@ -137,7 +138,9 @@ struct timespec64 {
>  #define xfs_inobt_maxrecs		libxfs_inobt_maxrecs
>  #define xfs_inobt_stage_cursor		libxfs_inobt_stage_cursor
>  #define xfs_inode_from_disk		libxfs_inode_from_disk
> +#define xfs_inode_from_disk_timestamp	libxfs_inode_from_disk_timestamp
>  #define xfs_inode_to_disk		libxfs_inode_to_disk
> +#define xfs_inode_to_disk_timestamp	libxfs_inode_to_disk_timestamp
>  #define xfs_inode_validate_cowextsize	libxfs_inode_validate_cowextsize
>  #define xfs_inode_validate_extsize	libxfs_inode_validate_extsize
>  
>
diff mbox series

Patch

diff --git a/db/dquot.c b/db/dquot.c
index edfcb0ca0744..30f4e6523c39 100644
--- a/db/dquot.c
+++ b/db/dquot.c
@@ -44,6 +44,22 @@  const field_t	dqblk_flds[] = {
 	{ NULL }
 };
 
+static int
+dquot_timestamp_count(
+	void		*obj,
+	int		startoff)
+{
+	return xfs_sb_version_hasbigtime(&mp->m_sb) ? 0 : 1;
+}
+
+static int
+dquot_bigtimestamp_count(
+	void		*obj,
+	int		startoff)
+{
+	return xfs_sb_version_hasbigtime(&mp->m_sb) ? 1 : 0;
+}
+
 #define	DOFF(f)		bitize(offsetof(struct xfs_disk_dquot, d_ ## f))
 const field_t	disk_dquot_flds[] = {
 	{ "magic", FLDT_UINT16X, OI(DOFF(magic)), C1, 0, TYP_NONE },
@@ -60,8 +76,14 @@  const field_t	disk_dquot_flds[] = {
 	  TYP_NONE },
 	{ "bcount", FLDT_QCNT, OI(DOFF(bcount)), C1, 0, TYP_NONE },
 	{ "icount", FLDT_QCNT, OI(DOFF(icount)), C1, 0, TYP_NONE },
-	{ "itimer", FLDT_INT32D, OI(DOFF(itimer)), C1, 0, TYP_NONE },
-	{ "btimer", FLDT_INT32D, OI(DOFF(btimer)), C1, 0, TYP_NONE },
+	{ "itimer", FLDT_INT32D, OI(DOFF(itimer)), dquot_timestamp_count,
+	  FLD_COUNT, TYP_NONE },
+	{ "btimer", FLDT_INT32D, OI(DOFF(btimer)), dquot_timestamp_count,
+	  FLD_COUNT, TYP_NONE },
+	{ "itimer", FLDT_BTQTIMER, OI(DOFF(itimer)), dquot_bigtimestamp_count,
+	  FLD_COUNT, TYP_NONE },
+	{ "btimer", FLDT_BTQTIMER, OI(DOFF(btimer)), dquot_bigtimestamp_count,
+	  FLD_COUNT, TYP_NONE },
 	{ "iwarns", FLDT_QWARNCNT, OI(DOFF(iwarns)), C1, 0, TYP_NONE },
 	{ "bwarns", FLDT_QWARNCNT, OI(DOFF(bwarns)), C1, 0, TYP_NONE },
 	{ "pad0", FLDT_UINT32X, OI(DOFF(pad0)), C1, FLD_SKIPALL, TYP_NONE },
@@ -70,7 +92,10 @@  const field_t	disk_dquot_flds[] = {
 	{ "rtb_softlimit", FLDT_QCNT, OI(DOFF(rtb_softlimit)), C1, 0,
 	  TYP_NONE },
 	{ "rtbcount", FLDT_QCNT, OI(DOFF(rtbcount)), C1, 0, TYP_NONE },
-	{ "rtbtimer", FLDT_INT32D, OI(DOFF(rtbtimer)), C1, 0, TYP_NONE },
+	{ "rtbtimer", FLDT_INT32D, OI(DOFF(rtbtimer)), dquot_timestamp_count,
+	  FLD_COUNT, TYP_NONE },
+	{ "rtbtimer", FLDT_BTQTIMER, OI(DOFF(rtbtimer)),
+	  dquot_bigtimestamp_count, FLD_COUNT, TYP_NONE },
 	{ "rtbwarns", FLDT_QWARNCNT, OI(DOFF(rtbwarns)), C1, 0, TYP_NONE },
 	{ "pad", FLDT_UINT16X, OI(DOFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
 	{ NULL }
diff --git a/db/field.c b/db/field.c
index cf3002c730e6..fad17b1f082e 100644
--- a/db/field.c
+++ b/db/field.c
@@ -351,6 +351,12 @@  const ftattr_t	ftattrtab[] = {
 	  NULL, NULL },
 	{ FLDT_TIMESTAMP, "timestamp", NULL, (char *)timestamp_flds,
 	  SI(bitsz(union xfs_timestamp)), 0, NULL, timestamp_flds },
+	{ FLDT_BTSEC, "btsec", fp_btsec, NULL, SI(bitsz(uint64_t)), 0, NULL,
+	  NULL },
+	{ FLDT_BTNSEC, "btnsec", fp_btnsec, NULL, SI(bitsz(uint64_t)), 0, NULL,
+	  NULL },
+	{ FLDT_BTQTIMER, "btqtimer", fp_btqtimer, NULL, SI(bitsz(uint32_t)), 0,
+	  NULL, NULL },
 	{ FLDT_UINT1, "uint1", fp_num, "%u", SI(1), 0, NULL, NULL },
 	{ FLDT_UINT16D, "uint16d", fp_num, "%u", SI(bitsz(uint16_t)), 0, NULL,
 	  NULL },
diff --git a/db/field.h b/db/field.h
index 15065373de39..0d27cd085b13 100644
--- a/db/field.h
+++ b/db/field.h
@@ -170,6 +170,9 @@  typedef enum fldt	{
 
 	FLDT_TIME,
 	FLDT_TIMESTAMP,
+	FLDT_BTSEC,
+	FLDT_BTNSEC,
+	FLDT_BTQTIMER,
 	FLDT_UINT1,
 	FLDT_UINT16D,
 	FLDT_UINT16O,
diff --git a/db/fprint.c b/db/fprint.c
index c9d07e1bca7e..3a4f839b355d 100644
--- a/db/fprint.c
+++ b/db/fprint.c
@@ -19,6 +19,7 @@ 
 #include "sig.h"
 #include "malloc.h"
 #include "io.h"
+#include "init.h"
 
 int
 fp_charns(
@@ -145,6 +146,125 @@  fp_time(
 	return 1;
 }
 
+static void
+fp_timespec64(
+	struct timespec64	*ts)
+{
+	BUILD_BUG_ON(sizeof(long) != sizeof(time_t));
+
+	if (ts->tv_sec > LONG_MAX || ts->tv_sec < LONG_MIN) {
+		dbprintf("%lld", (long long)ts->tv_sec);
+	} else {
+		time_t	tt = ts->tv_sec;
+		char	*c;
+
+		c = ctime(&tt);
+		dbprintf("%24.24s", c);
+	}
+}
+
+int
+fp_btsec(
+	void			*obj,
+	int			bit,
+	int			count,
+	char			*fmtstr,
+	int			size,
+	int			arg,
+	int			base,
+	int			array)
+{
+	struct timespec64	ts;
+	union xfs_timestamp	*xts;
+	int			bitpos;
+	int			i;
+
+	ASSERT(bitoffs(bit) == 0);
+	for (i = 0, bitpos = bit;
+	     i < count && !seenint();
+	     i++, bitpos += size) {
+		if (array)
+			dbprintf("%d:", i + base);
+		xts = obj + byteize(bitpos);
+		libxfs_inode_from_disk_timestamp(obj, &ts, xts);
+		fp_timespec64(&ts);
+		if (i < count - 1)
+			dbprintf(" ");
+	}
+	return 1;
+}
+
+int
+fp_btnsec(
+	void			*obj,
+	int			bit,
+	int			count,
+	char			*fmtstr,
+	int			size,
+	int			arg,
+	int			base,
+	int			array)
+{
+	struct timespec64	ts;
+	union xfs_timestamp	*xts;
+	int			bitpos;
+	int			i;
+
+	ASSERT(bitoffs(bit) == 0);
+	for (i = 0, bitpos = bit;
+	     i < count && !seenint();
+	     i++, bitpos += size) {
+		if (array)
+			dbprintf("%d:", i + base);
+		xts = obj + byteize(bitpos);
+		libxfs_inode_from_disk_timestamp(obj, &ts, xts);
+		dbprintf("%u", ts.tv_nsec);
+		if (i < count - 1)
+			dbprintf(" ");
+	}
+	return 1;
+}
+
+int
+fp_btqtimer(
+	void			*obj,
+	int			bit,
+	int			count,
+	char			*fmtstr,
+	int			size,
+	int			arg,
+	int			base,
+	int			array)
+{
+	struct timespec64	ts = { 0 };
+	struct xfs_disk_dquot	*ddq = obj;
+	__be32			*t;
+	int			bitpos;
+	int			i;
+
+	ASSERT(bitoffs(bit) == 0);
+	for (i = 0, bitpos = bit;
+	     i < count && !seenint();
+	     i++, bitpos += size) {
+		if (array)
+			dbprintf("%d:", i + base);
+		t = obj + byteize(bitpos);
+		libxfs_dquot_from_disk_timestamp(ddq, &ts.tv_sec, *t);
+
+		/*
+		 * Display the raw value if it's the default grace expiration
+		 * period (root dquot) or if the quota has not expired.
+		 */
+		if (ddq->d_id == 0 || ts.tv_sec == 0)
+			dbprintf("%llu", (unsigned long long)ts.tv_sec);
+		else
+			fp_timespec64(&ts);
+		if (i < count - 1)
+			dbprintf(" ");
+	}
+	return 1;
+}
+
 /*ARGSUSED*/
 int
 fp_uuid(
diff --git a/db/fprint.h b/db/fprint.h
index c958dca0ed92..a33dcd11248d 100644
--- a/db/fprint.h
+++ b/db/fprint.h
@@ -15,6 +15,12 @@  extern int	fp_sarray(void *obj, int bit, int count, char *fmtstr, int size,
 			  int arg, int base, int array);
 extern int	fp_time(void *obj, int bit, int count, char *fmtstr, int size,
 			int arg, int base, int array);
+extern int	fp_btsec(void *obj, int bit, int count, char *fmtstr, int size,
+			int arg, int base, int array);
+extern int	fp_btnsec(void *obj, int bit, int count, char *fmtstr, int size,
+			int arg, int base, int array);
+extern int	fp_btqtimer(void *obj, int bit, int count, char *fmtstr,
+			int size, int arg, int base, int array);
 extern int	fp_uuid(void *obj, int bit, int count, char *fmtstr, int size,
 			int arg, int base, int array);
 extern int	fp_crc(void *obj, int bit, int count, char *fmtstr, int size,
diff --git a/db/inode.c b/db/inode.c
index 25112bb5e4d8..5fbfd4ddb5f5 100644
--- a/db/inode.c
+++ b/db/inode.c
@@ -175,14 +175,38 @@  const field_t	inode_v3_flds[] = {
 	{ "dax", FLDT_UINT1,
 	  OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_DAX_BIT - 1), C1,
 	  0, TYP_NONE },
+	{ "bigtime", FLDT_UINT1,
+	  OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_BIGTIME_BIT - 1), C1,
+	  0, TYP_NONE },
 	{ NULL }
 };
 
+static int
+inode_timestamp_count(
+	void		*obj,
+	int		startoff)
+{
+	return xfs_sb_version_hasbigtime(&mp->m_sb) ? 0 : 1;
+}
+
+static int
+inode_bigtimestamp_count(
+	void		*obj,
+	int		startoff)
+{
+	return xfs_sb_version_hasbigtime(&mp->m_sb) ? 1 : 0;
+}
 
 #define	TOFF(f)	bitize(offsetof(union xfs_timestamp, t_ ## f))
 const field_t	timestamp_flds[] = {
-	{ "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE },
-	{ "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE },
+	{ "sec", FLDT_TIME, OI(TOFF(sec)), inode_timestamp_count, FLD_COUNT,
+		TYP_NONE },
+	{ "nsec", FLDT_NSEC, OI(TOFF(nsec)), inode_timestamp_count, FLD_COUNT,
+		TYP_NONE },
+	{ "sec", FLDT_BTSEC, OI(TOFF(bigtime)), inode_bigtimestamp_count,
+		FLD_COUNT, TYP_NONE },
+	{ "nsec", FLDT_BTNSEC, OI(TOFF(bigtime)), inode_bigtimestamp_count,
+		FLD_COUNT, TYP_NONE },
 	{ NULL }
 };
 
diff --git a/db/sb.c b/db/sb.c
index 33d9f7df49bb..c68bb9a958e7 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -727,6 +727,8 @@  version_string(
 		strcat(s, ",REFLINK");
 	if (xfs_sb_version_hasinobtcounts(sbp))
 		strcat(s, ",INOBTCNT");
+	if (xfs_sb_version_hasbigtime(sbp))
+		strcat(s, ",BIGTIME");
 	return s;
 }
 
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 4ee02473df0d..b83dc48a4802 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -116,6 +116,7 @@  struct timespec64 {
 #define xfs_dir_replace			libxfs_dir_replace
 
 #define xfs_dqblk_repair		libxfs_dqblk_repair
+#define xfs_dquot_from_disk_timestamp	libxfs_dquot_from_disk_timestamp
 #define xfs_dquot_verify		libxfs_dquot_verify
 
 #define xfs_finobt_calc_reserves	libxfs_finobt_calc_reserves
@@ -137,7 +138,9 @@  struct timespec64 {
 #define xfs_inobt_maxrecs		libxfs_inobt_maxrecs
 #define xfs_inobt_stage_cursor		libxfs_inobt_stage_cursor
 #define xfs_inode_from_disk		libxfs_inode_from_disk
+#define xfs_inode_from_disk_timestamp	libxfs_inode_from_disk_timestamp
 #define xfs_inode_to_disk		libxfs_inode_to_disk
+#define xfs_inode_to_disk_timestamp	libxfs_inode_to_disk_timestamp
 #define xfs_inode_validate_cowextsize	libxfs_inode_validate_cowextsize
 #define xfs_inode_validate_extsize	libxfs_inode_validate_extsize