Blame SOURCES/xfsprogs-5.7.0-xfs_quota-allow-individual-timer-extension.patch

1569e6
From 36dc471cc9bb17868b79cf8dea8151b207387539 Mon Sep 17 00:00:00 2001
1569e6
From: Eric Sandeen <sandeen@redhat.com>
1569e6
Date: Tue, 26 May 2020 14:36:26 -0400
1569e6
Subject: [PATCH] xfs_quota: allow individual timer extension
1569e6
1569e6
The only grace period which can be set via xfs_quota today is for id 0,
1569e6
i.e. the default grace period for all users.  However, setting an
1569e6
individual grace period is useful; for example:
1569e6
1569e6
 Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
1569e6
 Alice uses 150 inodes, and enters a short grace period
1569e6
 Alice really needs to use those 150 inodes past the grace period
1569e6
 The administrator extends Alice's grace period until next Monday
1569e6
1569e6
vfs quota users such as ext4 can do this today, with setquota -T
1569e6
1569e6
xfs_quota can now accept an optional user id or name (symmetric with
1569e6
how warn limits are specified), in which case that user's grace period
1569e6
is extended to expire the given amount of time from now().
1569e6
1569e6
To maintain compatibility with old command lines, if none of
1569e6
[-d|id|name] are specified, default limits are set as before.
1569e6
1569e6
(kernelspace requires updates to enable all this as well.)
1569e6
1569e6
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
1569e6
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
1569e6
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
1569e6
---
1569e6
 man/man8/xfs_quota.8 | 36 +++++++++++++++++--
1569e6
 quota/edit.c         | 83 +++++++++++++++++++++++++++++++++++++-------
1569e6
 2 files changed, 104 insertions(+), 15 deletions(-)
1569e6
1569e6
Index: xfsprogs-5.0.0/man/man8/xfs_quota.8
1569e6
===================================================================
1569e6
--- xfsprogs-5.0.0.orig/man/man8/xfs_quota.8
1569e6
+++ xfsprogs-5.0.0/man/man8/xfs_quota.8
1569e6
@@ -460,14 +460,46 @@ must be specified.
1569e6
 .B \-bir
1569e6
 ]
1569e6
 .I value
1569e6
+[
1569e6
+.B -d
1569e6
+|
1569e6
+.I id
1569e6
+|
1569e6
+.I name
1569e6
+]
1569e6
 .br
1569e6
 Allows the quota enforcement timeout (i.e. the amount of time allowed
1569e6
 to pass before the soft limits are enforced as the hard limits) to
1569e6
 be modified. The current timeout setting can be displayed using the
1569e6
 .B state
1569e6
-command. The value argument is a number of seconds, but units of
1569e6
-\&'minutes', 'hours', 'days', and 'weeks' are also understood
1569e6
+command.
1569e6
+.br
1569e6
+When setting the default timer via the
1569e6
+.B \-d
1569e6
+option, or for
1569e6
+.B id
1569e6
+0, or if no argument is given after
1569e6
+.I value
1569e6
+the
1569e6
+.I value
1569e6
+argument is a number of seconds indicating the relative amount of time after
1569e6
+soft limits are exceeded, before hard limits are enforced.
1569e6
+.br
1569e6
+When setting any other individual timer by
1569e6
+.I id
1569e6
+or
1569e6
+.I name,
1569e6
+the
1569e6
+.I value
1569e6
+is the number of seconds from now, at which time the hard limits will be enforced.
1569e6
+This allows extending the grace time of an individual user who has exceeded soft
1569e6
+limits.
1569e6
+.br
1569e6
+For
1569e6
+.I value,
1569e6
+units of \&'minutes', 'hours', 'days', and 'weeks' are also understood
1569e6
 (as are their abbreviations 'm', 'h', 'd', and 'w').
1569e6
+.br
1569e6
 .HP
1569e6
 .B warn
1569e6
 [
1569e6
Index: xfsprogs-5.0.0/quota/edit.c
1569e6
===================================================================
1569e6
--- xfsprogs-5.0.0.orig/quota/edit.c
1569e6
+++ xfsprogs-5.0.0/quota/edit.c
1569e6
@@ -419,6 +419,7 @@ restore_f(
1569e6
 
1569e6
 static void
1569e6
 set_timer(
1569e6
+	uint32_t	id,
1569e6
 	uint		type,
1569e6
 	uint		mask,
1569e6
 	char		*dev,
1569e6
@@ -427,14 +428,43 @@ set_timer(
1569e6
 	fs_disk_quota_t	d;
1569e6
 
1569e6
 	memset(&d, 0, sizeof(d));
1569e6
+
1569e6
+	/*
1569e6
+	 * If id is specified we are extending grace time by value
1569e6
+	 * Otherwise we are setting the default grace time
1569e6
+	 */
1569e6
+	if (id) {
1569e6
+		time_t	now;
1569e6
+
1569e6
+		/* Get quota to find out whether user is past soft limits */
1569e6
+		if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
1569e6
+			exitcode = 1;
1569e6
+			fprintf(stderr, _("%s: cannot get quota: %s\n"),
1569e6
+					progname, strerror(errno));
1569e6
+				return;
1569e6
+		}
1569e6
+
1569e6
+		time(&now;;
1569e6
+
1569e6
+		/* Only set grace time if user is already past soft limit */
1569e6
+		if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
1569e6
+			d.d_btimer = now + value;
1569e6
+		if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
1569e6
+			d.d_itimer = now + value;
1569e6
+		if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
1569e6
+			d.d_rtbtimer = now + value;
1569e6
+	} else {
1569e6
+		d.d_btimer = value;
1569e6
+		d.d_itimer = value;
1569e6
+		d.d_rtbtimer = value;
1569e6
+	}
1569e6
+
1569e6
 	d.d_version = FS_DQUOT_VERSION;
1569e6
 	d.d_flags = type;
1569e6
 	d.d_fieldmask = mask;
1569e6
-	d.d_itimer = value;
1569e6
-	d.d_btimer = value;
1569e6
-	d.d_rtbtimer = value;
1569e6
+	d.d_id = id;
1569e6
 
1569e6
-	if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
1569e6
+	if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
1569e6
 		exitcode = 1;
1569e6
 		fprintf(stderr, _("%s: cannot set timer: %s\n"),
1569e6
 				progname, strerror(errno));
1569e6
@@ -447,10 +477,15 @@ timer_f(
1569e6
 	char		**argv)
1569e6
 {
1569e6
 	uint		value;
1569e6
-	int		c, type = 0, mask = 0;
1569e6
+	char		*name = NULL;
1569e6
+	uint32_t	id = 0;
1569e6
+	int		c, flags = 0, type = 0, mask = 0;
1569e6
 
1569e6
-	while ((c = getopt(argc, argv, "bgipru")) != EOF) {
1569e6
+	while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
1569e6
 		switch (c) {
1569e6
+		case 'd':
1569e6
+			flags |= DEFAULTS_FLAG;
1569e6
+			break;
1569e6
 		case 'b':
1569e6
 			mask |= FS_DQ_BTIMER;
1569e6
 			break;
1569e6
@@ -474,23 +509,45 @@ timer_f(
1569e6
 		}
1569e6
 	}
1569e6
 
1569e6
-	if (argc != optind + 1)
1569e6
+	 /*
1569e6
+	 * Older versions of the command did not accept -d|id|name,
1569e6
+	 * so in that case we assume we're setting default timer,
1569e6
+	 * and the last arg is the timer value.
1569e6
+	 *
1569e6
+	 * Otherwise, if the defaults flag is set, we expect 1 more arg for
1569e6
+	 * timer value ; if not, 2 more args: 1 for value, one for id/name.
1569e6
+	 */
1569e6
+	if (!(flags & DEFAULTS_FLAG) && (argc == optind + 1)) {
1569e6
+		value = cvttime(argv[optind++]);
1569e6
+	} else if (flags & DEFAULTS_FLAG) {
1569e6
+		if (argc != optind + 1)
1569e6
+			return command_usage(&timer_cmd);
1569e6
+		value = cvttime(argv[optind++]);
1569e6
+	} else if (argc == optind + 2) {
1569e6
+		value = cvttime(argv[optind++]);
1569e6
+		name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
1569e6
+	} else
1569e6
 		return command_usage(&timer_cmd);
1569e6
 
1569e6
-	value = cvttime(argv[optind++]);
1569e6
 
1569e6
+	/* if none of -bir specified, set them all */
1569e6
 	if (!mask)
1569e6
 		mask = FS_DQ_TIMER_MASK;
1569e6
 
1569e6
 	if (!type) {
1569e6
 		type = XFS_USER_QUOTA;
1569e6
 	} else if (type != XFS_GROUP_QUOTA &&
1569e6
-	           type != XFS_PROJ_QUOTA &&
1569e6
-	           type != XFS_USER_QUOTA) {
1569e6
+		   type != XFS_PROJ_QUOTA &&
1569e6
+		   type != XFS_USER_QUOTA) {
1569e6
 		return command_usage(&timer_cmd);
1569e6
 	}
1569e6
 
1569e6
-	set_timer(type, mask, fs_path->fs_name, value);
1569e6
+	if (name)
1569e6
+		id = id_from_string(name, type);
1569e6
+
1569e6
+	if (id >= 0)
1569e6
+		set_timer(id, type, mask, fs_path->fs_name, value);
1569e6
+
1569e6
 	return 0;
1569e6
 }
1569e6
 
1569e6
@@ -616,9 +673,9 @@ edit_init(void)
1569e6
 
1569e6
 	timer_cmd.name = "timer";
1569e6
 	timer_cmd.cfunc = timer_f;
1569e6
-	timer_cmd.argmin = 2;
1569e6
+	timer_cmd.argmin = 1;
1569e6
 	timer_cmd.argmax = -1;
1569e6
-	timer_cmd.args = _("[-bir] [-g|-p|-u] value");
1569e6
+	timer_cmd.args = _("[-bir] [-g|-p|-u] value [-d|id|name]");
1569e6
 	timer_cmd.oneline = _("set quota enforcement timeouts");
1569e6
 	timer_cmd.help = timer_help;
1569e6
 	timer_cmd.flags = CMD_FLAG_FOREIGN_OK;