[PATCH v2 20/26] xfs_db: report bigtime format timestamps

Darrick J. Wong
2020-11-17T17:45:27Z

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

Report the large format timestamps in a human-readable manner if it is
possible to do so without loss of information.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
v2: skip the build bug stuff and check directly for information loss in
the time64_t -> time_t conversion
---
db/fprint.c | 73 +++++++++++++++++++++++++++++++++-------------
db/inode.c | 4 ++-
db/sb.c | 2 +
libxfs/libxfs_api_defs.h | 1 +
4 files changed, 59 insertions(+), 21 deletions(-)

diff --git a/db/fprint.c b/db/fprint.c
index 7ceab29cc608..65accfda3fe4 100644
--- a/db/fprint.c
+++ b/db/fprint.c
@@ -112,23 +112,50 @@ fp_sarray(
return 1;
}

-int
-fp_time(
- void *obj,
- int bit,
- int count,
- char *fmtstr,
- int size,
- int arg,
- int base,
- int array)
+static void
+fp_time64(
+ time64_t sec)
{
- struct timespec64 tv;
- xfs_timestamp_t *ts;
- int bitpos;
+ time_t tt = sec;
+ time64_t tt_sec = tt;
char *c;
+
+ /*
+ * Stupid time_t shenanigans -- POSIX.1-2017 only requires that this
+ * type represent a time in seconds. Since we have no idea if our
+ * time64_t filesystem timestamps can actually be represented by the C
+ * library, we resort to converting the input value from time64_t to
+ * time_t and back to time64_t to check for information loss. If so,
+ * we print the raw value; otherwise we print a human-readable value.
+ */
+ if (tt_sec != sec)
+ goto raw;
+
+ c = ctime(&tt);
+ if (!c)
+ goto raw;
+
+ dbprintf("%24.24s", c);
+ return;
+raw:
+ dbprintf("%lld", sec);
+}
+
+int
+fp_time(
+ void *obj,
+ int bit,
+ int count,
+ char *fmtstr,
+ int size,
+ int arg,
+ int base,
+ int array)
+{
+ struct timespec64 tv;
+ xfs_timestamp_t *ts;
+ int bitpos;
int i;
- time_t t;

ASSERT(bitoffs(bit) == 0);
for (i = 0, bitpos = bit;
@@ -139,10 +166,8 @@ fp_time(

ts = obj + byteize(bitpos);
tv = libxfs_inode_from_disk_ts(obj, *ts);
- t = tv.tv_sec;

- c = ctime(&t);
- dbprintf("%24.24s", c);
+ fp_time64(tv.tv_sec);

if (i < count - 1)
dbprintf(" ");
@@ -195,7 +220,8 @@ fp_qtimer(
int base,
int array)
{
- uint32_t sec;
+ struct xfs_disk_dquot *ddq = obj;
+ time64_t sec;
__be32 *t;
int bitpos;
int i;
@@ -208,9 +234,16 @@ fp_qtimer(
dbprintf("%d:", i + base);

t = obj + byteize(bitpos);
- sec = be32_to_cpu(*t);
+ sec = libxfs_dquot_from_disk_ts(ddq, *t);

- dbprintf("%u", sec);
+ /*
+ * 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 || sec == 0)
+ dbprintf("%lld", sec);
+ else
+ fp_time64(sec);

if (i < count - 1)
dbprintf(" ");
diff --git a/db/inode.c b/db/inode.c
index cc0e680aadea..f0e08ebf5ad9 100644
--- a/db/inode.c
+++ b/db/inode.c
@@ -175,10 +175,12 @@ 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 }
};

-
const field_t timestamp_flds[] = {
{ "sec", FLDT_TIME, OI(0), C1, 0, TYP_NONE },
{ "nsec", FLDT_NSEC, OI(0), C1, 0, TYP_NONE },
diff --git a/db/sb.c b/db/sb.c
index cfc2e32023fc..3608508a7eb8 100644
--- a/db/sb.c
+++ b/db/sb.c
@@ -800,6 +800,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 40da71ab3163..419e6d9888cf 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -99,6 +99,7 @@
#define xfs_dir_replace libxfs_dir_replace

#define xfs_dqblk_repair libxfs_dqblk_repair
+#define xfs_dquot_from_disk_ts libxfs_dquot_from_disk_ts
#define xfs_dquot_verify libxfs_dquot_verify

#define xfs_finobt_calc_reserves libxfs_finobt_calc_reserves