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

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