Blame SOURCES/xfsprogs-5.10.0-xfs_quota-support-editing-and-reporting-quotas-with-.patch

0bf83d
From f3eb31d9c005558ce975e2806f8dc73b0ecbd7f7 Mon Sep 17 00:00:00 2001
0bf83d
From: "Darrick J. Wong" <darrick.wong@oracle.com>
0bf83d
Date: Fri, 20 Nov 2020 17:03:28 -0500
0bf83d
Subject: [PATCH] xfs_quota: support editing and reporting quotas with bigtime
0bf83d
0bf83d
Enhance xfs_quota to detect and report grace period expirations past
0bf83d
2038.
0bf83d
0bf83d
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
0bf83d
Reviewed-by: Christoph Hellwig <hch@lst.de>
0bf83d
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
0bf83d
---
0bf83d
0bf83d
diff --git a/include/xqm.h b/include/xqm.h
0bf83d
index 8ab1907..573441d 100644
0bf83d
--- a/include/xqm.h
0bf83d
+++ b/include/xqm.h
0bf83d
@@ -47,7 +47,10 @@ typedef struct fs_disk_quota {
0bf83d
 	__s32		d_btimer;	/* similar to above; for disk blocks */
0bf83d
 	__u16		d_iwarns;	/* # warnings issued wrt num inodes */
0bf83d
 	__u16		d_bwarns;	/* # warnings issued wrt disk blocks */
0bf83d
-	__s32		d_padding2;	/* padding2 - for future use */
0bf83d
+	__s8		d_itimer_hi;	/* upper 8 bits of timer values */
0bf83d
+	__s8		d_btimer_hi;
0bf83d
+	__s8		d_rtbtimer_hi;
0bf83d
+	__s8		d_padding2;	/* padding2 - for future use */
0bf83d
 	__u64		d_rtb_hardlimit;/* absolute limit on realtime blks */
0bf83d
 	__u64		d_rtb_softlimit;/* preferred limit on RT disk blks */
0bf83d
 	__u64		d_rtbcount;	/* # realtime blocks owned */
0bf83d
@@ -93,6 +96,21 @@ typedef struct fs_disk_quota {
0bf83d
 #define FS_DQ_RTBWARNS	(1<<11)
0bf83d
 #define FS_DQ_WARNS_MASK	(FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS)
0bf83d
 
0bf83d
+/*
0bf83d
+ * Accounting values.  These can only be set for filesystem with
0bf83d
+ * non-transactional quotas that require quotacheck(8) in userspace.
0bf83d
+ */
0bf83d
+#define FS_DQ_BCOUNT		(1<<12)
0bf83d
+#define FS_DQ_ICOUNT		(1<<13)
0bf83d
+#define FS_DQ_RTBCOUNT		(1<<14)
0bf83d
+#define FS_DQ_ACCT_MASK		(FS_DQ_BCOUNT | FS_DQ_ICOUNT | FS_DQ_RTBCOUNT)
0bf83d
+
0bf83d
+/*
0bf83d
+ * Quota expiration timestamps are 40-bit signed integers, with the upper 8
0bf83d
+ * bits encoded in the _hi fields.
0bf83d
+ */
0bf83d
+#define FS_DQ_BIGTIME		(1<<15)
0bf83d
+
0bf83d
 /*
0bf83d
  * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
0bf83d
  */
0bf83d
diff --git a/quota/edit.c b/quota/edit.c
0bf83d
index b3cad02..1a3b2d9 100644
0bf83d
--- a/quota/edit.c
0bf83d
+++ b/quota/edit.c
0bf83d
@@ -417,6 +417,53 @@ restore_f(
0bf83d
 	return 0;
0bf83d
 }
0bf83d
 
0bf83d
+time64_t
0bf83d
+decode_timer(
0bf83d
+	const struct fs_disk_quota *d,
0bf83d
+	__s32			timer_lo,
0bf83d
+	__s8			timer_hi)
0bf83d
+{
0bf83d
+	if (d->d_fieldmask & FS_DQ_BIGTIME)
0bf83d
+		return (uint32_t)timer_lo | (int64_t)timer_hi << 32;
0bf83d
+	return timer_lo;
0bf83d
+}
0bf83d
+
0bf83d
+static inline void
0bf83d
+encode_timer(
0bf83d
+	const struct fs_disk_quota *d,
0bf83d
+	__s32			*timer_lo,
0bf83d
+	__s8			*timer_hi,
0bf83d
+	time64_t		timer)
0bf83d
+{
0bf83d
+	*timer_lo = timer;
0bf83d
+	if (d->d_fieldmask & FS_DQ_BIGTIME)
0bf83d
+		*timer_hi = timer >> 32;
0bf83d
+	else
0bf83d
+		*timer_hi = 0;
0bf83d
+}
0bf83d
+
0bf83d
+static inline bool want_bigtime(time64_t timer)
0bf83d
+{
0bf83d
+	return timer > INT32_MAX || timer < INT32_MIN;
0bf83d
+}
0bf83d
+
0bf83d
+static void
0bf83d
+encode_timers(
0bf83d
+	struct fs_disk_quota	*d,
0bf83d
+	time64_t		btimer,
0bf83d
+	time64_t		itimer,
0bf83d
+	time64_t		rtbtimer)
0bf83d
+{
0bf83d
+	d->d_fieldmask &= ~FS_DQ_BIGTIME;
0bf83d
+	if (want_bigtime(btimer) || want_bigtime(itimer) ||
0bf83d
+	    want_bigtime(rtbtimer))
0bf83d
+		d->d_fieldmask |= FS_DQ_BIGTIME;
0bf83d
+
0bf83d
+	encode_timer(d, &d->d_btimer, &d->d_btimer_hi, btimer);
0bf83d
+	encode_timer(d, &d->d_itimer, &d->d_itimer_hi, itimer);
0bf83d
+	encode_timer(d, &d->d_rtbtimer, &d->d_rtbtimer_hi, rtbtimer);
0bf83d
+}
0bf83d
+
0bf83d
 static void
0bf83d
 set_timer(
0bf83d
 	uint32_t		id,
0bf83d
@@ -426,6 +473,7 @@ set_timer(
0bf83d
 	time64_t		value)
0bf83d
 {
0bf83d
 	struct fs_disk_quota	d;
0bf83d
+	time64_t		btimer, itimer, rtbtimer;
0bf83d
 
0bf83d
 	memset(&d, 0, sizeof(d));
0bf83d
 
0bf83d
@@ -446,23 +494,28 @@ set_timer(
0bf83d
 
0bf83d
 		time(&now;;
0bf83d
 
0bf83d
+		btimer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
0bf83d
+		itimer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
0bf83d
+		rtbtimer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
0bf83d
+
0bf83d
 		/* Only set grace time if user is already past soft limit */
0bf83d
 		if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
0bf83d
-			d.d_btimer = now + value;
0bf83d
+			btimer = now + value;
0bf83d
 		if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
0bf83d
-			d.d_itimer = now + value;
0bf83d
+			itimer = now + value;
0bf83d
 		if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
0bf83d
-			d.d_rtbtimer = now + value;
0bf83d
+			rtbtimer = now + value;
0bf83d
 	} else {
0bf83d
-		d.d_btimer = value;
0bf83d
-		d.d_itimer = value;
0bf83d
-		d.d_rtbtimer = value;
0bf83d
+		btimer = value;
0bf83d
+		itimer = value;
0bf83d
+		rtbtimer = value;
0bf83d
 	}
0bf83d
 
0bf83d
 	d.d_version = FS_DQUOT_VERSION;
0bf83d
 	d.d_flags = type;
0bf83d
 	d.d_fieldmask = mask;
0bf83d
 	d.d_id = id;
0bf83d
+	encode_timers(&d, btimer, itimer, rtbtimer);
0bf83d
 
0bf83d
 	if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
0bf83d
 		exitcode = 1;
0bf83d
diff --git a/quota/quota.c b/quota/quota.c
0bf83d
index 8ba0995..0747ced 100644
0bf83d
--- a/quota/quota.c
0bf83d
+++ b/quota/quota.c
0bf83d
@@ -101,7 +101,7 @@ quota_mount(
0bf83d
 	}
0bf83d
 
0bf83d
 	if (form & XFS_BLOCK_QUOTA) {
0bf83d
-		timer = d.d_btimer;
0bf83d
+		timer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
0bf83d
 		qflags = (flags & HUMAN_FLAG);
0bf83d
 		if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
0bf83d
 			qflags |= LIMIT_FLAG;
0bf83d
@@ -123,7 +123,7 @@ quota_mount(
0bf83d
 				time_to_string(timer, qflags));
0bf83d
 	}
0bf83d
 	if (form & XFS_INODE_QUOTA) {
0bf83d
-		timer = d.d_itimer;
0bf83d
+		timer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
0bf83d
 		qflags = (flags & HUMAN_FLAG);
0bf83d
 		if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
0bf83d
 			qflags |= LIMIT_FLAG;
0bf83d
@@ -145,7 +145,7 @@ quota_mount(
0bf83d
 				time_to_string(timer, qflags));
0bf83d
 	}
0bf83d
 	if (form & XFS_RTBLOCK_QUOTA) {
0bf83d
-		timer = d.d_rtbtimer;
0bf83d
+		timer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
0bf83d
 		qflags = (flags & HUMAN_FLAG);
0bf83d
 		if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
0bf83d
 			qflags |= LIMIT_FLAG;
0bf83d
diff --git a/quota/quota.h b/quota/quota.h
0bf83d
index 13ae450..74eb146 100644
0bf83d
--- a/quota/quota.h
0bf83d
+++ b/quota/quota.h
0bf83d
@@ -3,6 +3,8 @@
0bf83d
  * Copyright (c) 2005 Silicon Graphics, Inc.
0bf83d
  * All Rights Reserved.
0bf83d
  */
0bf83d
+#ifndef XFS_QUOTA_QUOTA_H_
0bf83d
+#define XFS_QUOTA_QUOTA_H_
0bf83d
 
0bf83d
 #include "xqm.h"
0bf83d
 #include "path.h"
0bf83d
@@ -73,3 +75,8 @@ extern char *uid_to_name(uint32_t __uid);
0bf83d
 extern char *gid_to_name(uint32_t __gid);
0bf83d
 extern char *prid_to_name(uint32_t __prid);
0bf83d
 extern bool isdigits_only(const char *);
0bf83d
+
0bf83d
+time64_t decode_timer(const struct fs_disk_quota *d, __s32 timer_lo,
0bf83d
+		__s8 timer_hi);
0bf83d
+
0bf83d
+#endif /* XFS_QUOTA_QUOTA_H_ */
0bf83d
diff --git a/quota/report.c b/quota/report.c
0bf83d
index 2d5024e..6ac5549 100644
0bf83d
--- a/quota/report.c
0bf83d
+++ b/quota/report.c
0bf83d
@@ -398,7 +398,7 @@ report_mount(
0bf83d
 	}
0bf83d
 
0bf83d
 	if (form & XFS_BLOCK_QUOTA) {
0bf83d
-		timer = d.d_btimer;
0bf83d
+		timer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
0bf83d
 		qflags = (flags & HUMAN_FLAG);
0bf83d
 		if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
0bf83d
 			qflags |= LIMIT_FLAG;
0bf83d
@@ -420,7 +420,7 @@ report_mount(
0bf83d
 				time_to_string(timer, qflags));
0bf83d
 	}
0bf83d
 	if (form & XFS_INODE_QUOTA) {
0bf83d
-		timer = d.d_itimer;
0bf83d
+		timer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
0bf83d
 		qflags = (flags & HUMAN_FLAG);
0bf83d
 		if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
0bf83d
 			qflags |= LIMIT_FLAG;
0bf83d
@@ -442,7 +442,7 @@ report_mount(
0bf83d
 				time_to_string(timer, qflags));
0bf83d
 	}
0bf83d
 	if (form & XFS_RTBLOCK_QUOTA) {
0bf83d
-		timer = d.d_rtbtimer;
0bf83d
+		timer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
0bf83d
 		qflags = (flags & HUMAN_FLAG);
0bf83d
 		if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
0bf83d
 			qflags |= LIMIT_FLAG;