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

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