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

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