All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/SEVERAL] xfs, xfstests, xfsprogs: quota timer updates
@ 2020-05-18 18:46 Eric Sandeen
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
                   ` (2 more replies)
  0 siblings, 3 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 18:46 UTC (permalink / raw)
  To: linux-xfs

This is work to enhance xfs quota timers for per-type timers and per-user
timer extension.

I'll do 3 sub-series here, for kernel, userspace, and fstests.

-Eric


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH 0/6] xfs: quota timer enhancements
  2020-05-18 18:46 [PATCH 0/SEVERAL] xfs, xfstests, xfsprogs: quota timer updates Eric Sandeen
@ 2020-05-18 18:48 ` Eric Sandeen
  2020-05-18 18:48   ` [PATCH 1/6] xfs: group quota should return EDQUOT when prj quota enabled Eric Sandeen
                     ` (5 more replies)
  2020-05-18 19:23 ` [PATCH 0/1] xfs_quota: allow individual timer extension Eric Sandeen
  2020-05-18 19:59 ` [PATCH 0/4] fstests: more quota related tests Eric Sandeen
  2 siblings, 6 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 18:48 UTC (permalink / raw)
  To: linux-xfs

This is the kernel series to allow per-type timers, as well as
per-user grace period extensions.

Thanks to Zorro for helping me revive, simplify, and fix the
per-type timer series.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH 1/6] xfs: group quota should return EDQUOT when prj quota enabled
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
@ 2020-05-18 18:48   ` Eric Sandeen
  2020-05-19 16:22     ` Darrick J. Wong
  2020-05-18 18:49   ` [PATCH 2/6] xfs: always return -ENOSPC on project quota reservation failure Eric Sandeen
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 18:48 UTC (permalink / raw)
  To: linux-xfs

Long ago, group & project quota were mutually exclusive, and so
when we turned on XFS_QMOPT_ENOSPC ("return ENOSPC if project quota
is exceeded") when project quota was enabled, we only needed to
disable it again for user quota.

When group & project quota got separated, this got missed, and as a
result if project quota is enabled and group quota is exceeded, the
error code returned is incorrectly returned as ENOSPC not EDQUOT.

Fix this by stripping XFS_QMOPT_ENOSPC out of flags for group
quota when we try to reserve the space.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/xfs_trans_dquot.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index d1b9869bc5fa..2c3557a80e69 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -758,7 +758,8 @@ xfs_trans_reserve_quota_bydquots(
 	}
 
 	if (gdqp) {
-		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
+		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos,
+					(flags & ~XFS_QMOPT_ENOSPC));
 		if (error)
 			goto unwind_usr;
 	}
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 2/6] xfs: always return -ENOSPC on project quota reservation failure
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
  2020-05-18 18:48   ` [PATCH 1/6] xfs: group quota should return EDQUOT when prj quota enabled Eric Sandeen
@ 2020-05-18 18:49   ` Eric Sandeen
  2020-05-19 16:18     ` Darrick J. Wong
  2020-05-18 18:49   ` [PATCH 3/6] xfs: fix up some whitespace in quota code Eric Sandeen
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 18:49 UTC (permalink / raw)
  To: linux-xfs

XFS project quota treats project hierarchies as "mini filesysems" and
so rather than -EDQUOT, the intent is to return -ENOSPC when a quota
reservation fails, but this behavior is not consistent.

The only place we make a decision between -EDQUOT and -ENOSPC
returns based on quota type is in xfs_trans_dqresv().

This behavior is currently controlled by whether or not the
XFS_QMOPT_ENOSPC flag gets passed into the quota reservation.  However,
its use is not consistent; paths such as xfs_create() and xfs_symlink()
don't set the flag, so a reservation failure will return -EDQUOT for
project quota reservation failures rather than -ENOSPC for these sorts
of operations, even for project quota:

# mkdir mnt/project
# xfs_quota -x -c "project -s -p mnt/project 42" mnt
# xfs_quota -x -c 'limit -p isoft=2 ihard=3 42' mnt
# touch mnt/project/file{1,2,3}
touch: cannot touch ‘mnt/project/file3’: Disk quota exceeded

We can make this consistent by not requiring the flag to be set at the
top of the callchain; instead we can simply test whether we are
reserving a project quota with XFS_QM_ISPDQ in xfs_trans_dqresv and if
so, return -ENOSPC for that failure.  This removes the need for the
XFS_QMOPT_ENOSPC altogether and simplifies the code a fair bit.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_quota_defs.h |  1 -
 fs/xfs/xfs_qm.c                |  9 +++------
 fs/xfs/xfs_trans_dquot.c       | 16 +++++-----------
 3 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
index b2113b17e53c..56d9dd787e7b 100644
--- a/fs/xfs/libxfs/xfs_quota_defs.h
+++ b/fs/xfs/libxfs/xfs_quota_defs.h
@@ -100,7 +100,6 @@ typedef uint16_t	xfs_qwarncnt_t;
 #define XFS_QMOPT_FORCE_RES	0x0000010 /* ignore quota limits */
 #define XFS_QMOPT_SBVERSION	0x0000040 /* change superblock version num */
 #define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
-#define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
 
 /*
  * flags to xfs_trans_mod_dquot to indicate which field needs to be
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index c225691fad15..591779aa2fd0 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -1808,7 +1808,7 @@ xfs_qm_vop_chown_reserve(
 {
 	struct xfs_mount	*mp = ip->i_mount;
 	uint64_t		delblks;
-	unsigned int		blkflags, prjflags = 0;
+	unsigned int		blkflags;
 	struct xfs_dquot	*udq_unres = NULL;
 	struct xfs_dquot	*gdq_unres = NULL;
 	struct xfs_dquot	*pdq_unres = NULL;
@@ -1849,7 +1849,6 @@ xfs_qm_vop_chown_reserve(
 
 	if (XFS_IS_PQUOTA_ON(ip->i_mount) && pdqp &&
 	    ip->i_d.di_projid != be32_to_cpu(pdqp->q_core.d_id)) {
-		prjflags = XFS_QMOPT_ENOSPC;
 		pdq_delblks = pdqp;
 		if (delblks) {
 			ASSERT(ip->i_pdquot);
@@ -1859,8 +1858,7 @@ xfs_qm_vop_chown_reserve(
 
 	error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
 				udq_delblks, gdq_delblks, pdq_delblks,
-				ip->i_d.di_nblocks, 1,
-				flags | blkflags | prjflags);
+				ip->i_d.di_nblocks, 1, flags | blkflags);
 	if (error)
 		return error;
 
@@ -1878,8 +1876,7 @@ xfs_qm_vop_chown_reserve(
 		ASSERT(udq_unres || gdq_unres || pdq_unres);
 		error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
 			    udq_delblks, gdq_delblks, pdq_delblks,
-			    (xfs_qcnt_t)delblks, 0,
-			    flags | blkflags | prjflags);
+			    (xfs_qcnt_t)delblks, 0, flags | blkflags);
 		if (error)
 			return error;
 		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 2c3557a80e69..2c07897a3c37 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -711,7 +711,7 @@ xfs_trans_dqresv(
 
 error_return:
 	xfs_dqunlock(dqp);
-	if (flags & XFS_QMOPT_ENOSPC)
+	if (XFS_QM_ISPDQ(dqp))
 		return -ENOSPC;
 	return -EDQUOT;
 }
@@ -751,15 +751,13 @@ xfs_trans_reserve_quota_bydquots(
 	ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
 
 	if (udqp) {
-		error = xfs_trans_dqresv(tp, mp, udqp, nblks, ninos,
-					(flags & ~XFS_QMOPT_ENOSPC));
+		error = xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags);
 		if (error)
 			return error;
 	}
 
 	if (gdqp) {
-		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos,
-					(flags & ~XFS_QMOPT_ENOSPC));
+		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
 		if (error)
 			goto unwind_usr;
 	}
@@ -804,16 +802,12 @@ xfs_trans_reserve_quota_nblks(
 
 	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
 		return 0;
-	if (XFS_IS_PQUOTA_ON(mp))
-		flags |= XFS_QMOPT_ENOSPC;
 
 	ASSERT(!xfs_is_quota_inode(&mp->m_sb, ip->i_ino));
 
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
-				XFS_TRANS_DQ_RES_RTBLKS ||
-	       (flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
-				XFS_TRANS_DQ_RES_BLKS);
+	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES)) == XFS_TRANS_DQ_RES_RTBLKS ||
+	       (flags & ~(XFS_QMOPT_FORCE_RES)) == XFS_TRANS_DQ_RES_BLKS);
 
 	/*
 	 * Reserve nblks against these dquots, with trans as the mediator.
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 3/6] xfs: fix up some whitespace in quota code
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
  2020-05-18 18:48   ` [PATCH 1/6] xfs: group quota should return EDQUOT when prj quota enabled Eric Sandeen
  2020-05-18 18:49   ` [PATCH 2/6] xfs: always return -ENOSPC on project quota reservation failure Eric Sandeen
@ 2020-05-18 18:49   ` Eric Sandeen
  2020-05-19 16:25     ` Darrick J. Wong
  2020-05-18 18:50   ` [PATCH 4/6] xfs: pass xfs_dquot to xfs_qm_adjust_dqtimers Eric Sandeen
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 18:49 UTC (permalink / raw)
  To: linux-xfs

There is a fair bit of whitespace damage in the quota code, so
fix up enough of it that subsequent patches are restricted to
functional change to aid review.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/xfs_dquot.c    | 16 ++++++++--------
 fs/xfs/xfs_qm.h       | 44 +++++++++++++++++++++----------------------
 fs/xfs/xfs_quotaops.c |  8 ++++----
 3 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index af2c8e5ceea0..96e33390c6a0 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -205,16 +205,16 @@ xfs_qm_adjust_dqtimers(
  */
 STATIC void
 xfs_qm_init_dquot_blk(
-	xfs_trans_t	*tp,
-	xfs_mount_t	*mp,
-	xfs_dqid_t	id,
-	uint		type,
-	xfs_buf_t	*bp)
+	struct xfs_trans	*tp,
+	struct xfs_mount	*mp,
+	xfs_dqid_t		id,
+	uint			type,
+	struct xfs_buf		*bp)
 {
 	struct xfs_quotainfo	*q = mp->m_quotainfo;
-	xfs_dqblk_t	*d;
-	xfs_dqid_t	curid;
-	int		i;
+	xfs_dqblk_t		*d;
+	xfs_dqid_t		curid;
+	int			i;
 
 	ASSERT(tp);
 	ASSERT(xfs_buf_islocked(bp));
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 4e57edca8bce..3a850401b102 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -42,12 +42,12 @@ extern struct kmem_zone	*xfs_qm_dqtrxzone;
 #define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
 
 struct xfs_def_quota {
-	xfs_qcnt_t       bhardlimit;     /* default data blk hard limit */
-	xfs_qcnt_t       bsoftlimit;	 /* default data blk soft limit */
-	xfs_qcnt_t       ihardlimit;	 /* default inode count hard limit */
-	xfs_qcnt_t       isoftlimit;	 /* default inode count soft limit */
-	xfs_qcnt_t	 rtbhardlimit;   /* default realtime blk hard limit */
-	xfs_qcnt_t	 rtbsoftlimit;   /* default realtime blk soft limit */
+	xfs_qcnt_t	bhardlimit;	/* default data blk hard limit */
+	xfs_qcnt_t	bsoftlimit;	/* default data blk soft limit */
+	xfs_qcnt_t	ihardlimit;	/* default inode count hard limit */
+	xfs_qcnt_t	isoftlimit;	/* default inode count soft limit */
+	xfs_qcnt_t	rtbhardlimit;	/* default realtime blk hard limit */
+	xfs_qcnt_t	rtbsoftlimit;	/* default realtime blk soft limit */
 };
 
 /*
@@ -55,28 +55,28 @@ struct xfs_def_quota {
  * The mount structure keeps a pointer to this.
  */
 struct xfs_quotainfo {
-	struct radix_tree_root qi_uquota_tree;
-	struct radix_tree_root qi_gquota_tree;
-	struct radix_tree_root qi_pquota_tree;
-	struct mutex qi_tree_lock;
+	struct radix_tree_root	qi_uquota_tree;
+	struct radix_tree_root	qi_gquota_tree;
+	struct radix_tree_root	qi_pquota_tree;
+	struct mutex		qi_tree_lock;
 	struct xfs_inode	*qi_uquotaip;	/* user quota inode */
 	struct xfs_inode	*qi_gquotaip;	/* group quota inode */
 	struct xfs_inode	*qi_pquotaip;	/* project quota inode */
-	struct list_lru	 qi_lru;
-	int		 qi_dquots;
-	time64_t	 qi_btimelimit;	 /* limit for blks timer */
-	time64_t	 qi_itimelimit;	 /* limit for inodes timer */
-	time64_t	 qi_rtbtimelimit;/* limit for rt blks timer */
-	xfs_qwarncnt_t	 qi_bwarnlimit;	 /* limit for blks warnings */
-	xfs_qwarncnt_t	 qi_iwarnlimit;	 /* limit for inodes warnings */
-	xfs_qwarncnt_t	 qi_rtbwarnlimit;/* limit for rt blks warnings */
-	struct mutex	 qi_quotaofflock;/* to serialize quotaoff */
-	xfs_filblks_t	 qi_dqchunklen;	 /* # BBs in a chunk of dqs */
-	uint		 qi_dqperchunk;	 /* # ondisk dqs in above chunk */
+	struct list_lru		qi_lru;
+	int			qi_dquots;
+	time64_t		qi_btimelimit;	/* limit for blks timer */
+	time64_t		qi_itimelimit;	/* limit for inodes timer */
+	time64_t		qi_rtbtimelimit;/* limit for rt blks timer */
+	xfs_qwarncnt_t		qi_bwarnlimit;	/* limit for blks warnings */
+	xfs_qwarncnt_t		qi_iwarnlimit;	/* limit for inodes warnings */
+	xfs_qwarncnt_t		qi_rtbwarnlimit;/* limit for rt blks warnings */
+	struct mutex		qi_quotaofflock;/* to serialize quotaoff */
+	xfs_filblks_t		qi_dqchunklen;	/* # BBs in a chunk of dqs */
+	uint			qi_dqperchunk;	/* # ondisk dq in above chunk */
 	struct xfs_def_quota	qi_usr_default;
 	struct xfs_def_quota	qi_grp_default;
 	struct xfs_def_quota	qi_prj_default;
-	struct shrinker	qi_shrinker;
+	struct shrinker		qi_shrinker;
 };
 
 static inline struct radix_tree_root *
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 38669e827206..cb16a91dd1d4 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -23,8 +23,8 @@ xfs_qm_fill_state(
 	struct xfs_inode	*ip,
 	xfs_ino_t		ino)
 {
-	struct xfs_quotainfo *q = mp->m_quotainfo;
-	bool tempqip = false;
+	struct xfs_quotainfo	*q = mp->m_quotainfo;
+	bool			tempqip = false;
 
 	tstate->ino = ino;
 	if (!ip && ino == NULLFSINO)
@@ -109,8 +109,8 @@ xfs_fs_set_info(
 	int			type,
 	struct qc_info		*info)
 {
-	struct xfs_mount *mp = XFS_M(sb);
-	struct qc_dqblk newlim;
+	struct xfs_mount	*mp = XFS_M(sb);
+	struct qc_dqblk		newlim;
 
 	if (sb_rdonly(sb))
 		return -EROFS;
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 4/6] xfs: pass xfs_dquot to xfs_qm_adjust_dqtimers
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
                     ` (2 preceding siblings ...)
  2020-05-18 18:49   ` [PATCH 3/6] xfs: fix up some whitespace in quota code Eric Sandeen
@ 2020-05-18 18:50   ` Eric Sandeen
  2020-05-19 16:26     ` Darrick J. Wong
  2020-05-18 18:51   ` [PATCH 5/6] xfs: per-type quota timers and warn limits Eric Sandeen
  2020-05-18 18:52   ` [PATCH 6/6] xfs: allow individual quota grace period extension Eric Sandeen
  5 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 18:50 UTC (permalink / raw)
  To: linux-xfs

Pass xfs_dquot rather than xfs_disk_dquot to xfs_qm_adjust_dqtimers;
this makes it symmetric with xfs_qm_adjust_dqlimits and will help
the next patch.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/xfs_dquot.c       | 3 ++-
 fs/xfs/xfs_dquot.h       | 2 +-
 fs/xfs/xfs_qm.c          | 2 +-
 fs/xfs/xfs_qm_syscalls.c | 2 +-
 fs/xfs/xfs_trans_dquot.c | 2 +-
 5 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 96e33390c6a0..6d6afc0297b3 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -114,8 +114,9 @@ xfs_qm_adjust_dqlimits(
 void
 xfs_qm_adjust_dqtimers(
 	struct xfs_mount	*mp,
-	struct xfs_disk_dquot	*d)
+	struct xfs_dquot	*dq)
 {
+	struct xfs_disk_dquot	*d = &dq->q_core;
 	ASSERT(d->d_id);
 
 #ifdef DEBUG
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index fe3e46df604b..71e36c85e20b 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -154,7 +154,7 @@ void		xfs_qm_dqdestroy(struct xfs_dquot *dqp);
 int		xfs_qm_dqflush(struct xfs_dquot *dqp, struct xfs_buf **bpp);
 void		xfs_qm_dqunpin_wait(struct xfs_dquot *dqp);
 void		xfs_qm_adjust_dqtimers(struct xfs_mount *mp,
-						struct xfs_disk_dquot *d);
+						struct xfs_dquot *d);
 void		xfs_qm_adjust_dqlimits(struct xfs_mount *mp,
 						struct xfs_dquot *d);
 xfs_dqid_t	xfs_qm_id_for_quotatype(struct xfs_inode *ip, uint type);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 591779aa2fd0..e97a3802939c 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -1116,7 +1116,7 @@ xfs_qm_quotacheck_dqadjust(
 	 */
 	if (dqp->q_core.d_id) {
 		xfs_qm_adjust_dqlimits(mp, dqp);
-		xfs_qm_adjust_dqtimers(mp, &dqp->q_core);
+		xfs_qm_adjust_dqtimers(mp, dqp);
 	}
 
 	dqp->dq_flags |= XFS_DQ_DIRTY;
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 5d5ac65aa1cc..301a284ee4f9 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -588,7 +588,7 @@ xfs_qm_scall_setqlim(
 		 * is on or off. We don't really want to bother with iterating
 		 * over all ondisk dquots and turning the timers on/off.
 		 */
-		xfs_qm_adjust_dqtimers(mp, ddq);
+		xfs_qm_adjust_dqtimers(mp, dqp);
 	}
 	dqp->dq_flags |= XFS_DQ_DIRTY;
 	xfs_trans_log_dquot(tp, dqp);
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 2c07897a3c37..20542076e32a 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -388,7 +388,7 @@ xfs_trans_apply_dquot_deltas(
 			 */
 			if (d->d_id) {
 				xfs_qm_adjust_dqlimits(tp->t_mountp, dqp);
-				xfs_qm_adjust_dqtimers(tp->t_mountp, d);
+				xfs_qm_adjust_dqtimers(tp->t_mountp, dqp);
 			}
 
 			dqp->dq_flags |= XFS_DQ_DIRTY;
-- 
2.17.0



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 5/6] xfs: per-type quota timers and warn limits
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
                     ` (3 preceding siblings ...)
  2020-05-18 18:50   ` [PATCH 4/6] xfs: pass xfs_dquot to xfs_qm_adjust_dqtimers Eric Sandeen
@ 2020-05-18 18:51   ` Eric Sandeen
  2020-05-19 16:27     ` Darrick J. Wong
                       ` (2 more replies)
  2020-05-18 18:52   ` [PATCH 6/6] xfs: allow individual quota grace period extension Eric Sandeen
  5 siblings, 3 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 18:51 UTC (permalink / raw)
  To: linux-xfs

From: Eric Sandeen <sandeen@redhat.com>

Move timers and warnings out of xfs_quotainfo and into xfs_def_quota
so that we can utilize them on a per-type basis, rather than enforcing
them based on the values found in the first enabled quota type.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
[zlang: new way to get defquota in xfs_qm_init_timelimits]
[zlang: remove redundant defq assign]
Signed-off-by: Zorro Lang <zlang@redhat.com>
---
 fs/xfs/xfs_dquot.c       |  9 ++++---
 fs/xfs/xfs_qm.c          | 54 +++++++++++++++++++---------------------
 fs/xfs/xfs_qm.h          | 13 +++++-----
 fs/xfs/xfs_qm_syscalls.c | 12 ++++-----
 fs/xfs/xfs_quotaops.c    | 22 ++++++++--------
 fs/xfs/xfs_trans_dquot.c |  6 ++---
 6 files changed, 58 insertions(+), 58 deletions(-)

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 6d6afc0297b3..0e0a15c17789 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -116,7 +116,10 @@ xfs_qm_adjust_dqtimers(
 	struct xfs_mount	*mp,
 	struct xfs_dquot	*dq)
 {
+	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 	struct xfs_disk_dquot	*d = &dq->q_core;
+	struct xfs_def_quota	*defq = xfs_get_defquota(dq, qi);
+
 	ASSERT(d->d_id);
 
 #ifdef DEBUG
@@ -139,7 +142,7 @@ xfs_qm_adjust_dqtimers(
 		     (be64_to_cpu(d->d_bcount) >
 		      be64_to_cpu(d->d_blk_hardlimit)))) {
 			d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
-					mp->m_quotainfo->qi_btimelimit);
+					defq->btimelimit);
 		} else {
 			d->d_bwarns = 0;
 		}
@@ -162,7 +165,7 @@ xfs_qm_adjust_dqtimers(
 		     (be64_to_cpu(d->d_icount) >
 		      be64_to_cpu(d->d_ino_hardlimit)))) {
 			d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
-					mp->m_quotainfo->qi_itimelimit);
+					defq->itimelimit);
 		} else {
 			d->d_iwarns = 0;
 		}
@@ -185,7 +188,7 @@ xfs_qm_adjust_dqtimers(
 		     (be64_to_cpu(d->d_rtbcount) >
 		      be64_to_cpu(d->d_rtb_hardlimit)))) {
 			d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
-					mp->m_quotainfo->qi_rtbtimelimit);
+					defq->rtbtimelimit);
 		} else {
 			d->d_rtbwarns = 0;
 		}
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index e97a3802939c..9eaab2368d3d 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -577,19 +577,26 @@ xfs_qm_set_defquota(
 static void
 xfs_qm_init_timelimits(
 	struct xfs_mount	*mp,
-	struct xfs_quotainfo	*qinf)
+	uint			type)
 {
+	struct xfs_quotainfo	*qinf = mp->m_quotainfo;
+	struct xfs_def_quota	*defq;
 	struct xfs_disk_dquot	*ddqp;
 	struct xfs_dquot	*dqp;
-	uint			type;
 	int			error;
 
-	qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
-	qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
-	qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
-	qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
-	qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
-	qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
+	error = xfs_qm_dqget_uncached(mp, 0, type, &dqp);
+	if (error)
+		return;
+
+	defq = xfs_get_defquota(dqp, qinf);
+
+	defq->btimelimit = XFS_QM_BTIMELIMIT;
+	defq->itimelimit = XFS_QM_ITIMELIMIT;
+	defq->rtbtimelimit = XFS_QM_RTBTIMELIMIT;
+	defq->bwarnlimit = XFS_QM_BWARNLIMIT;
+	defq->iwarnlimit = XFS_QM_IWARNLIMIT;
+	defq->rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
 
 	/*
 	 * We try to get the limits from the superuser's limits fields.
@@ -597,39 +604,26 @@ xfs_qm_init_timelimits(
 	 *
 	 * Since we may not have done a quotacheck by this point, just read
 	 * the dquot without attaching it to any hashtables or lists.
-	 *
-	 * Timers and warnings are globally set by the first timer found in
-	 * user/group/proj quota types, otherwise a default value is used.
-	 * This should be split into different fields per quota type.
 	 */
-	if (XFS_IS_UQUOTA_RUNNING(mp))
-		type = XFS_DQ_USER;
-	else if (XFS_IS_GQUOTA_RUNNING(mp))
-		type = XFS_DQ_GROUP;
-	else
-		type = XFS_DQ_PROJ;
-	error = xfs_qm_dqget_uncached(mp, 0, type, &dqp);
-	if (error)
-		return;
-
 	ddqp = &dqp->q_core;
+
 	/*
 	 * The warnings and timers set the grace period given to
 	 * a user or group before he or she can not perform any
 	 * more writing. If it is zero, a default is used.
 	 */
 	if (ddqp->d_btimer)
-		qinf->qi_btimelimit = be32_to_cpu(ddqp->d_btimer);
+		defq->btimelimit = be32_to_cpu(ddqp->d_btimer);
 	if (ddqp->d_itimer)
-		qinf->qi_itimelimit = be32_to_cpu(ddqp->d_itimer);
+		defq->itimelimit = be32_to_cpu(ddqp->d_itimer);
 	if (ddqp->d_rtbtimer)
-		qinf->qi_rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer);
+		defq->rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer);
 	if (ddqp->d_bwarns)
-		qinf->qi_bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
+		defq->bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
 	if (ddqp->d_iwarns)
-		qinf->qi_iwarnlimit = be16_to_cpu(ddqp->d_iwarns);
+		defq->iwarnlimit = be16_to_cpu(ddqp->d_iwarns);
 	if (ddqp->d_rtbwarns)
-		qinf->qi_rtbwarnlimit = be16_to_cpu(ddqp->d_rtbwarns);
+		defq->rtbwarnlimit = be16_to_cpu(ddqp->d_rtbwarns);
 
 	xfs_qm_dqdestroy(dqp);
 }
@@ -675,7 +669,9 @@ xfs_qm_init_quotainfo(
 
 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
-	xfs_qm_init_timelimits(mp, qinf);
+	xfs_qm_init_timelimits(mp, XFS_DQ_USER);
+	xfs_qm_init_timelimits(mp, XFS_DQ_GROUP);
+	xfs_qm_init_timelimits(mp, XFS_DQ_PROJ);
 
 	if (XFS_IS_UQUOTA_RUNNING(mp))
 		xfs_qm_set_defquota(mp, XFS_DQ_USER, qinf);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 3a850401b102..761286bf7fb2 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -41,7 +41,14 @@ extern struct kmem_zone	*xfs_qm_dqtrxzone;
  */
 #define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
 
+/* Defaults for each quota type: time limits, warn limits, usage limits */
 struct xfs_def_quota {
+	time64_t	btimelimit;	/* limit for blks timer */
+	time64_t	itimelimit;	/* limit for inodes timer */
+	time64_t	rtbtimelimit;	/* limit for rt blks timer */
+	xfs_qwarncnt_t	bwarnlimit;	/* limit for blks warnings */
+	xfs_qwarncnt_t	iwarnlimit;	/* limit for inodes warnings */
+	xfs_qwarncnt_t	rtbwarnlimit;	/* limit for rt blks warnings */
 	xfs_qcnt_t	bhardlimit;	/* default data blk hard limit */
 	xfs_qcnt_t	bsoftlimit;	/* default data blk soft limit */
 	xfs_qcnt_t	ihardlimit;	/* default inode count hard limit */
@@ -64,12 +71,6 @@ struct xfs_quotainfo {
 	struct xfs_inode	*qi_pquotaip;	/* project quota inode */
 	struct list_lru		qi_lru;
 	int			qi_dquots;
-	time64_t		qi_btimelimit;	/* limit for blks timer */
-	time64_t		qi_itimelimit;	/* limit for inodes timer */
-	time64_t		qi_rtbtimelimit;/* limit for rt blks timer */
-	xfs_qwarncnt_t		qi_bwarnlimit;	/* limit for blks warnings */
-	xfs_qwarncnt_t		qi_iwarnlimit;	/* limit for inodes warnings */
-	xfs_qwarncnt_t		qi_rtbwarnlimit;/* limit for rt blks warnings */
 	struct mutex		qi_quotaofflock;/* to serialize quotaoff */
 	xfs_filblks_t		qi_dqchunklen;	/* # BBs in a chunk of dqs */
 	uint			qi_dqperchunk;	/* # ondisk dq in above chunk */
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 301a284ee4f9..29c1d5d4104d 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -563,23 +563,23 @@ xfs_qm_scall_setqlim(
 		 * for warnings.
 		 */
 		if (newlim->d_fieldmask & QC_SPC_TIMER) {
-			q->qi_btimelimit = newlim->d_spc_timer;
+			defq->btimelimit = newlim->d_spc_timer;
 			ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
 		}
 		if (newlim->d_fieldmask & QC_INO_TIMER) {
-			q->qi_itimelimit = newlim->d_ino_timer;
+			defq->itimelimit = newlim->d_ino_timer;
 			ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
 		}
 		if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
-			q->qi_rtbtimelimit = newlim->d_rt_spc_timer;
+			defq->rtbtimelimit = newlim->d_rt_spc_timer;
 			ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
 		}
 		if (newlim->d_fieldmask & QC_SPC_WARNS)
-			q->qi_bwarnlimit = newlim->d_spc_warns;
+			defq->bwarnlimit = newlim->d_spc_warns;
 		if (newlim->d_fieldmask & QC_INO_WARNS)
-			q->qi_iwarnlimit = newlim->d_ino_warns;
+			defq->iwarnlimit = newlim->d_ino_warns;
 		if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
-			q->qi_rtbwarnlimit = newlim->d_rt_spc_warns;
+			defq->rtbwarnlimit = newlim->d_rt_spc_warns;
 	} else {
 		/*
 		 * If the user is now over quota, start the timelimit.
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index cb16a91dd1d4..51be282d28b3 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -21,9 +21,9 @@ xfs_qm_fill_state(
 	struct qc_type_state	*tstate,
 	struct xfs_mount	*mp,
 	struct xfs_inode	*ip,
-	xfs_ino_t		ino)
+	xfs_ino_t		ino,
+	struct xfs_def_quota	*defq)
 {
-	struct xfs_quotainfo	*q = mp->m_quotainfo;
 	bool			tempqip = false;
 
 	tstate->ino = ino;
@@ -37,12 +37,12 @@ xfs_qm_fill_state(
 	tstate->flags |= QCI_SYSFILE;
 	tstate->blocks = ip->i_d.di_nblocks;
 	tstate->nextents = ip->i_d.di_nextents;
-	tstate->spc_timelimit = (u32)q->qi_btimelimit;
-	tstate->ino_timelimit = (u32)q->qi_itimelimit;
-	tstate->rt_spc_timelimit = (u32)q->qi_rtbtimelimit;
-	tstate->spc_warnlimit = q->qi_bwarnlimit;
-	tstate->ino_warnlimit = q->qi_iwarnlimit;
-	tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
+	tstate->spc_timelimit = (u32)defq->btimelimit;
+	tstate->ino_timelimit = (u32)defq->itimelimit;
+	tstate->rt_spc_timelimit = (u32)defq->rtbtimelimit;
+	tstate->spc_warnlimit = defq->bwarnlimit;
+	tstate->ino_warnlimit = defq->iwarnlimit;
+	tstate->rt_spc_warnlimit = defq->rtbwarnlimit;
 	if (tempqip)
 		xfs_irele(ip);
 }
@@ -77,11 +77,11 @@ xfs_fs_get_quota_state(
 		state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED;
 
 	xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip,
-			  mp->m_sb.sb_uquotino);
+			  mp->m_sb.sb_uquotino, &q->qi_usr_default);
 	xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip,
-			  mp->m_sb.sb_gquotino);
+			  mp->m_sb.sb_gquotino, &q->qi_grp_default);
 	xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip,
-			  mp->m_sb.sb_pquotino);
+			  mp->m_sb.sb_pquotino, &q->qi_prj_default);
 	return 0;
 }
 
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 20542076e32a..aa25647e0864 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -602,7 +602,7 @@ xfs_trans_dqresv(
 			softlimit = defq->bsoftlimit;
 		timer = be32_to_cpu(dqp->q_core.d_btimer);
 		warns = be16_to_cpu(dqp->q_core.d_bwarns);
-		warnlimit = dqp->q_mount->m_quotainfo->qi_bwarnlimit;
+		warnlimit = defq->bwarnlimit;
 		resbcountp = &dqp->q_res_bcount;
 	} else {
 		ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
@@ -614,7 +614,7 @@ xfs_trans_dqresv(
 			softlimit = defq->rtbsoftlimit;
 		timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
 		warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
-		warnlimit = dqp->q_mount->m_quotainfo->qi_rtbwarnlimit;
+		warnlimit = defq->rtbwarnlimit;
 		resbcountp = &dqp->q_res_rtbcount;
 	}
 
@@ -650,7 +650,7 @@ xfs_trans_dqresv(
 			total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos;
 			timer = be32_to_cpu(dqp->q_core.d_itimer);
 			warns = be16_to_cpu(dqp->q_core.d_iwarns);
-			warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;
+			warnlimit = defq->iwarnlimit;
 			hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
 			if (!hardlimit)
 				hardlimit = defq->ihardlimit;
-- 
2.17.0



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 6/6] xfs: allow individual quota grace period extension
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
                     ` (4 preceding siblings ...)
  2020-05-18 18:51   ` [PATCH 5/6] xfs: per-type quota timers and warn limits Eric Sandeen
@ 2020-05-18 18:52   ` Eric Sandeen
  2020-05-19 16:39     ` Darrick J. Wong
  5 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 18:52 UTC (permalink / raw)
  To: linux-xfs

The only grace period which can be set in the kernel today is for id 0,
i.e. the default grace period for all users.  However, setting an
individual grace period is useful; for example:

 Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
 Alice uses 150 inodes, and enters a short grace period
 Alice really needs to use those 150 inodes past the grace period
 The administrator extends Alice's grace period until next Monday

vfs quota users such as ext4 can do this today, with setquota -T

To enable this for XFS, we simply move the timelimit assignment out
from under the (id == 0) test.  Default setting remains under (id == 0).
Note that this now is consistent with how we set warnings.

(Userspace requires updates to enable this as well; xfs_quota needs to
parse new options, and setquota needs to set appropriate field flags.)

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/xfs/xfs_qm_syscalls.c | 48 +++++++++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 29c1d5d4104d..94d374820c7e 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -555,32 +555,40 @@ xfs_qm_scall_setqlim(
 		ddq->d_rtbwarns = cpu_to_be16(newlim->d_rt_spc_warns);
 
 	if (id == 0) {
-		/*
-		 * Timelimits for the super user set the relative time
-		 * the other users can be over quota for this file system.
-		 * If it is zero a default is used.  Ditto for the default
-		 * soft and hard limit values (already done, above), and
-		 * for warnings.
-		 */
-		if (newlim->d_fieldmask & QC_SPC_TIMER) {
-			defq->btimelimit = newlim->d_spc_timer;
-			ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
-		}
-		if (newlim->d_fieldmask & QC_INO_TIMER) {
-			defq->itimelimit = newlim->d_ino_timer;
-			ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
-		}
-		if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
-			defq->rtbtimelimit = newlim->d_rt_spc_timer;
-			ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
-		}
 		if (newlim->d_fieldmask & QC_SPC_WARNS)
 			defq->bwarnlimit = newlim->d_spc_warns;
 		if (newlim->d_fieldmask & QC_INO_WARNS)
 			defq->iwarnlimit = newlim->d_ino_warns;
 		if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
 			defq->rtbwarnlimit = newlim->d_rt_spc_warns;
-	} else {
+	}
+
+	/*
+	 * Timelimits for the super user set the relative time the other users
+	 * can be over quota for this file system. If it is zero a default is
+	 * used.  Ditto for the default soft and hard limit values (already
+	 * done, above), and for warnings.
+	 *
+	 * For other IDs, userspace can bump out the grace period if over
+	 * the soft limit.
+	 */
+	if (newlim->d_fieldmask & QC_SPC_TIMER)
+		ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
+	if (newlim->d_fieldmask & QC_INO_TIMER)
+		ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
+	if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
+		ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
+
+	if (id == 0) {
+		if (newlim->d_fieldmask & QC_SPC_TIMER)
+			defq->btimelimit = newlim->d_spc_timer;
+		if (newlim->d_fieldmask & QC_INO_TIMER)
+			defq->itimelimit = newlim->d_ino_timer;
+		if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
+			defq->rtbtimelimit = newlim->d_rt_spc_timer;
+	}
+
+	if (id != 0) {
 		/*
 		 * If the user is now over quota, start the timelimit.
 		 * The user will not be 'warned'.
-- 
2.17.0



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 0/1] xfs_quota: allow individual timer extension
  2020-05-18 18:46 [PATCH 0/SEVERAL] xfs, xfstests, xfsprogs: quota timer updates Eric Sandeen
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
@ 2020-05-18 19:23 ` Eric Sandeen
  2020-05-18 19:24   ` [PATCH 1/1] " Eric Sandeen
  2020-05-18 19:59 ` [PATCH 0/4] fstests: more quota related tests Eric Sandeen
  2 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 19:23 UTC (permalink / raw)
  To: linux-xfs

0/1 just for thread symmmetry... single patch to follow.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH 1/1] xfs_quota: allow individual timer extension
  2020-05-18 19:23 ` [PATCH 0/1] xfs_quota: allow individual timer extension Eric Sandeen
@ 2020-05-18 19:24   ` Eric Sandeen
  2020-05-18 20:04     ` Eric Sandeen
  2020-05-18 20:09     ` [PATCH 1/1 V2] " Eric Sandeen
  0 siblings, 2 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 19:24 UTC (permalink / raw)
  To: linux-xfs

The only grace period which can be set via xfs_quota today is for id 0,
i.e. the default grace period for all users.  However, setting an
individual grace period is useful; for example:

 Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
 Alice uses 150 inodes, and enters a short grace period
 Alice really needs to use those 150 inodes past the grace period
 The administrator extends Alice's grace period until next Monday

vfs quota users such as ext4 can do this today, with setquota -T

xfs_quota can now accept an optional user id or name (symmetric with
how warn limits are specified), in which case that user's grace period
is extended to expire the given amount of time from now(). 

To maintain compatibility with old command lines, if none of 
[-d|id|name] are specified, default limits are set as before.

(kernelspace requires updates to enable all this as well.)

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

diff --git a/man/man8/xfs_quota.8 b/man/man8/xfs_quota.8
index e6fe7cd1..dd0479cd 100644
--- a/man/man8/xfs_quota.8
+++ b/man/man8/xfs_quota.8
@@ -457,14 +457,46 @@ must be specified.
 .B \-bir
 ]
 .I value
+[
+.B -d
+|
+.I id
+|
+.I name
+]
 .br
 Allows the quota enforcement timeout (i.e. the amount of time allowed
 to pass before the soft limits are enforced as the hard limits) to
 be modified. The current timeout setting can be displayed using the
 .B state
-command. The value argument is a number of seconds, but units of
-\&'minutes', 'hours', 'days', and 'weeks' are also understood
+command.
+.br
+When setting the default timer via the
+.B \-d
+option, or for
+.B id
+0, or if no argument is given after
+.I value
+the
+.I value
+argument is a number of seconds indicating the relative amount of time after
+soft limits are exceeded, before hard limits are enforced.
+.br
+When setting any other individual timer by
+.I id
+or
+.I name,
+the
+.I value
+is the number of seconds from now, at which time the hard limits will be enforced.
+This allows extending the grace time of an individual user who has exceeded soft
+limits.
+.br
+For
+.I value,
+units of \&'minutes', 'hours', 'days', and 'weeks' are also understood
 (as are their abbreviations 'm', 'h', 'd', and 'w').
+.br
 .HP
 .B warn
 [
diff --git a/quota/edit.c b/quota/edit.c
index 442b608c..b60d0b13 100644
--- a/quota/edit.c
+++ b/quota/edit.c
@@ -419,6 +419,7 @@ restore_f(
 
 static void
 set_timer(
+	uint32_t	id,
 	uint		type,
 	uint		mask,
 	char		*dev,
@@ -427,14 +428,41 @@ set_timer(
 	fs_disk_quota_t	d;
 
 	memset(&d, 0, sizeof(d));
+
+	/*
+	 * If id is specified we are extending grace time by value
+	 * Otherwise we are setting the default grace time
+	 */
+	if (id) {
+		time_t	now;
+
+		if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
+			exitcode = 1;
+			fprintf(stderr, _("%s: cannot get quota: %s\n"),
+					progname, strerror(errno));
+				return;
+		}
+
+		time(&now);
+
+		if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
+			d.d_btimer = now + value;
+		if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
+			d.d_itimer = now + value;
+		if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
+			d.d_rtbtimer = now + value;
+	} else {
+		d.d_btimer = value;
+		d.d_itimer = value;
+		d.d_rtbtimer = value;
+	}
+
 	d.d_version = FS_DQUOT_VERSION;
 	d.d_flags = type;
 	d.d_fieldmask = mask;
-	d.d_itimer = value;
-	d.d_btimer = value;
-	d.d_rtbtimer = value;
+	d.d_id = id;
 
-	if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
+	if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
 		exitcode = 1;
 		fprintf(stderr, _("%s: cannot set timer: %s\n"),
 				progname, strerror(errno));
@@ -447,10 +475,15 @@ timer_f(
 	char		**argv)
 {
 	uint		value;
-	int		c, type = 0, mask = 0;
+	char		*name = NULL;
+	uint32_t	id = 0;
+	int		c, type = 0, mask = 0, flags = 0;
 
-	while ((c = getopt(argc, argv, "bgipru")) != EOF) {
+	while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
 		switch (c) {
+		case 'd':
+			flags |= DEFAULTS_FLAG;
+			break;
 		case 'b':
 			mask |= FS_DQ_BTIMER;
 			break;
@@ -474,23 +507,45 @@ timer_f(
 		}
 	}
 
-	if (argc != optind + 1)
+	 /*
+	 * Older versions of the command did not accept -d|id|name,
+	 * so in that case we assume we're setting default timer,
+	 * and the last arg is the timer value.
+	 *
+	 * Otherwise, if the defaults flag is set, we expect 1 more arg for
+	 * timer value ; if not, 2 more args: 1 for value, one for id/name.
+	 */
+	if (!(flags & DEFAULTS_FLAG) && (argc == optind + 1)) {
+		value = cvttime(argv[optind++]);
+	} else if (flags & DEFAULTS_FLAG) {
+		if (argc != optind + 1)
+			return command_usage(&timer_cmd);
+		value = cvttime(argv[optind++]);
+	} else if (argc == optind + 2) {
+		value = cvttime(argv[optind++]);
+		name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
+	} else
 		return command_usage(&timer_cmd);
 
-	value = cvttime(argv[optind++]);
 
+	/* if none of -bir specified, set them all */
 	if (!mask)
 		mask = FS_DQ_TIMER_MASK;
 
 	if (!type) {
 		type = XFS_USER_QUOTA;
 	} else if (type != XFS_GROUP_QUOTA &&
-	           type != XFS_PROJ_QUOTA &&
-	           type != XFS_USER_QUOTA) {
+		   type != XFS_PROJ_QUOTA &&
+		   type != XFS_USER_QUOTA) {
 		return command_usage(&timer_cmd);
 	}
 
-	set_timer(type, mask, fs_path->fs_name, value);
+	if (name)
+		id = id_from_string(name, type);
+
+	if (id >= 0)
+		set_timer(id, type, mask, fs_path->fs_name, value);
+
 	return 0;
 }
 
@@ -616,9 +671,9 @@ edit_init(void)
 
 	timer_cmd.name = "timer";
 	timer_cmd.cfunc = timer_f;
-	timer_cmd.argmin = 2;
+	timer_cmd.argmin = 1;
 	timer_cmd.argmax = -1;
-	timer_cmd.args = _("[-bir] [-g|-p|-u] value");
+	timer_cmd.args = _("[-bir] [-g|-p|-u] value [-d|id|name]");
 	timer_cmd.oneline = _("set quota enforcement timeouts");
 	timer_cmd.help = timer_help;
 	timer_cmd.flags = CMD_FLAG_FOREIGN_OK;



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 0/4] fstests: more quota related tests
  2020-05-18 18:46 [PATCH 0/SEVERAL] xfs, xfstests, xfsprogs: quota timer updates Eric Sandeen
  2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
  2020-05-18 19:23 ` [PATCH 0/1] xfs_quota: allow individual timer extension Eric Sandeen
@ 2020-05-18 19:59 ` Eric Sandeen
  2020-05-18 19:59   ` [PATCH 1/4] xfs: make sure our default quota warning limits and grace periods survive quotacheck Eric Sandeen
                     ` (4 more replies)
  2 siblings, 5 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 19:59 UTC (permalink / raw)
  To: linux-xfs, fstests

This collects zorro's outstanding patch to test per-type quota
timers, as well as one test from darrick to test limit survival
after quotacheck,  plus 2 more from me to test grace time extension.

zorro's still needs ENOSPC vs. EDQUOT filtering, darrick's might
need to be made generic, and mine are new.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH 1/4] xfs: make sure our default quota warning limits and grace periods survive quotacheck
  2020-05-18 19:59 ` [PATCH 0/4] fstests: more quota related tests Eric Sandeen
@ 2020-05-18 19:59   ` Eric Sandeen
  2020-05-31 16:17     ` Eryu Guan
  2020-05-18 20:00   ` [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout Eric Sandeen
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 19:59 UTC (permalink / raw)
  To: linux-xfs, fstests

From: "Darrick J. Wong" <darrick.wong@oracle.com>

Make sure that the default quota grace period and maximum warning limits
set by the administrator survive quotacheck.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 tests/xfs/900     | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/900.out | 13 +++++++++
 tests/xfs/group   |  1 +
 3 files changed, 83 insertions(+)
 create mode 100755 tests/xfs/900
 create mode 100644 tests/xfs/900.out

diff --git a/tests/xfs/900 b/tests/xfs/900
new file mode 100755
index 00000000..106a7367
--- /dev/null
+++ b/tests/xfs/900
@@ -0,0 +1,69 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2020, Oracle and/or its affiliates.  All Rights Reserved.
+#
+# FS QA Test No. 900
+#
+# Make sure that the quota default grace period and maximum warning limits
+# survive quotacheck.
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1    # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/quota
+
+# real QA test starts here
+_supported_fs xfs
+_supported_os Linux
+_require_quota
+
+rm -f $seqres.full
+
+# Format filesystem and set up quota limits
+_scratch_mkfs > $seqres.full
+_qmount_option "usrquota"
+_scratch_mount >> $seqres.full
+
+$XFS_QUOTA_PROG -x -c 'timer -u 300m' $SCRATCH_MNT
+$XFS_QUOTA_PROG -x -c 'state' $SCRATCH_MNT | grep 'grace time'
+_scratch_unmount
+
+# Remount and check the limits
+_scratch_mount >> $seqres.full
+$XFS_QUOTA_PROG -x -c 'state' $SCRATCH_MNT | grep 'grace time'
+_scratch_unmount
+
+# Run repair to force quota check
+_scratch_xfs_repair >> $seqres.full 2>&1
+
+# Remount (this time to run quotacheck) and check the limits.  There's a bug
+# in quotacheck where we would reset the ondisk default grace period to zero
+# while the incore copy stays at whatever was read in prior to quotacheck.
+# This will show up after the /next/ remount.
+_scratch_mount >> $seqres.full
+$XFS_QUOTA_PROG -x -c 'state' $SCRATCH_MNT | grep 'grace time'
+_scratch_unmount
+
+# Remount and check the limits
+_scratch_mount >> $seqres.full
+$XFS_QUOTA_PROG -x -c 'state' $SCRATCH_MNT | grep 'grace time'
+_scratch_unmount
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/900.out b/tests/xfs/900.out
new file mode 100644
index 00000000..90d0482c
--- /dev/null
+++ b/tests/xfs/900.out
@@ -0,0 +1,13 @@
+QA output created by 900
+Blocks grace time: [0 days 05:00:00]
+Inodes grace time: [0 days 05:00:00]
+Realtime Blocks grace time: [0 days 05:00:00]
+Blocks grace time: [0 days 05:00:00]
+Inodes grace time: [0 days 05:00:00]
+Realtime Blocks grace time: [0 days 05:00:00]
+Blocks grace time: [0 days 05:00:00]
+Inodes grace time: [0 days 05:00:00]
+Realtime Blocks grace time: [0 days 05:00:00]
+Blocks grace time: [0 days 05:00:00]
+Inodes grace time: [0 days 05:00:00]
+Realtime Blocks grace time: [0 days 05:00:00]
diff --git a/tests/xfs/group b/tests/xfs/group
index 12eb55c9..0818c5c6 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -513,3 +513,4 @@
 513 auto mount
 514 auto quick db
 515 auto quick quota
+900 auto quick quota
-- 
2.17.0



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout
  2020-05-18 19:59 ` [PATCH 0/4] fstests: more quota related tests Eric Sandeen
  2020-05-18 19:59   ` [PATCH 1/4] xfs: make sure our default quota warning limits and grace periods survive quotacheck Eric Sandeen
@ 2020-05-18 20:00   ` Eric Sandeen
  2020-05-31 16:15     ` Eryu Guan
  2020-05-18 20:00   ` [PATCH 3/4] fstests: individual user grace period extension via setquota Eric Sandeen
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 20:00 UTC (permalink / raw)
  To: linux-xfs, fstests

From: Zorro Lang <zlang@redhat.com>

Set different block & inode grace timers for user, group and project
quotas, then test softlimit enforcement timeout, make sure different
grace timers as expected.

Signed-off-by: Zorro Lang <zlang@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 common/quota          |   4 +
 tests/generic/902     | 187 ++++++++++++++++++++++++++++++++++++++++++
 tests/generic/902.out |  41 +++++++++
 tests/generic/group   |   1 +
 4 files changed, 233 insertions(+)
 create mode 100755 tests/generic/902
 create mode 100644 tests/generic/902.out

diff --git a/common/quota b/common/quota
index 240e0bbc..1437d5f7 100644
--- a/common/quota
+++ b/common/quota
@@ -217,6 +217,10 @@ _qmount()
     if [ "$FSTYP" != "xfs" ]; then
         quotacheck -ug $SCRATCH_MNT >>$seqres.full 2>&1
         quotaon -ug $SCRATCH_MNT >>$seqres.full 2>&1
+        # try to turn on project quota if it's supported
+        if quotaon --help 2>&1 | grep -q '\-\-project'; then
+            quotaon --project $SCRATCH_MNT >>$seqres.full 2>&1
+        fi
     fi
     chmod ugo+rwx $SCRATCH_MNT
 }
diff --git a/tests/generic/902 b/tests/generic/902
new file mode 100755
index 00000000..03b4dcb3
--- /dev/null
+++ b/tests/generic/902
@@ -0,0 +1,187 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Red Hat, Inc.  All Rights Reserved.
+#
+# FS QA Test No. 902
+#
+# Test per-type(user, group and project) filesystem quota timers, make sure
+# enforcement
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	restore_project
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/quota
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+require_project()
+{
+	rm -f $tmp.projects $tmp.projid
+	if [ -f /etc/projects ];then
+		cat /etc/projects > $tmp.projects
+	fi
+	if [ -f /etc/projid ];then
+		cat /etc/projid > $tmp.projid
+	fi
+
+	cat >/etc/projects <<EOF
+100:$SCRATCH_MNT/t
+EOF
+	cat >/etc/projid <<EOF
+$qa_user:100
+EOF
+	PROJECT_CHANGED=1
+}
+
+restore_project()
+{
+	if [ "$PROJECT_CHANGED" = "1" ];then
+		rm -f /etc/projects /etc/projid
+		if [ -f $tmp.projects ];then
+			cat $tmp.projects > /etc/projects
+		fi
+		if [ -f $tmp.projid ];then
+			cat $tmp.projid > /etc/projid
+		fi
+	fi
+}
+
+init_files()
+{
+	local dir=$1
+
+	echo "### Initialize files, and their mode and ownership"
+	touch $dir/file{1,2} 2>/dev/null
+	chown $qa_user $dir/file{1,2} 2>/dev/null
+	chgrp $qa_user $dir/file{1,2} 2>/dev/null
+	chmod 777 $dir 2>/dev/null
+}
+
+cleanup_files()
+{
+	echo "### Remove all files"
+	rm -f ${1}/file{1,2,3,4,5,6}
+}
+
+test_grace()
+{
+	local type=$1
+	local dir=$2
+	local bgrace=$3
+	local igrace=$4
+
+	init_files $dir
+	echo "--- Test block quota ---"
+	# Firstly fit below block soft limit
+	echo "Write 225 blocks..."
+	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((225 * $BLOCK_SIZE))' \
+		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
+		_filter_xfs_io_error | tee -a $seqres.full
+	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
+	# Secondly overcome block soft limit
+	echo "Rewrite 250 blocks plus 1 byte, over the block softlimit..."
+	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((250 * $BLOCK_SIZE + 1))' \
+		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
+		_filter_xfs_io_error | tee -a $seqres.full
+	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
+	# Reset grace time here, make below grace time test more accurate
+	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
+	# Now sleep enough grace time and check that softlimit got enforced
+	sleep $((bgrace + 1))
+	echo "Try to write 1 one more block after grace..."
+	su $qa_user -c "$XFS_IO_PROG -c 'truncate 0' -c 'pwrite 0 $BLOCK_SIZE' \
+		$dir/file2" 2>&1 >>$seqres.full | _filter_xfs_io_error | \
+		tee -a $seqres.full
+	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
+	echo "--- Test inode quota ---"
+	# And now the softlimit test for inodes
+	# First reset space limits so that we don't have problems with
+	# space reservations on XFS
+	setquota -$type $qa_user 0 0 3 100 $SCRATCH_MNT
+	echo "Create 2 more files, over the inode softlimit..."
+	su $qa_user -c "touch $dir/file3 $dir/file4" 2>&1 >>$seqres.full | \
+		_filter_scratch | tee -a $seqres.full
+	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
+	# Reset grace time here, make below grace time test more accurate
+	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
+	# Wait and check grace time enforcement
+	sleep $((igrace+1))
+	echo "Try to create one more inode after grace..."
+	su $qa_user -c "touch $dir/file5" 2>&1 >>$seqres.full |
+		_filter_scratch | tee -a $seqres.full
+	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
+	cleanup_files $dir
+}
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+_require_scratch
+_require_setquota_project
+_require_quota
+_require_user
+_require_group
+
+_scratch_mkfs >$seqres.full 2>&1
+_scratch_enable_pquota
+_qmount_option "usrquota,grpquota,prjquota"
+_qmount
+_require_prjquota $SCRATCH_DEV
+BLOCK_SIZE=$(_get_file_block_size $SCRATCH_MNT)
+rm -rf $SCRATCH_MNT/t
+mkdir $SCRATCH_MNT/t
+$XFS_IO_PROG -r -c "chproj 100" -c "chattr +P" $SCRATCH_MNT/t
+require_project
+
+echo "### Set up different grace timers to each type of quota"
+UBGRACE=12
+UIGRACE=10
+GBGRACE=4
+GIGRACE=2
+PBGRACE=8
+PIGRACE=6
+
+setquota -u $qa_user $((250 * $BLOCK_SIZE / 1024)) \
+	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
+setquota -u -t $UBGRACE $UIGRACE $SCRATCH_MNT
+echo; echo "### Test user quota softlimit and grace time"
+test_grace u $SCRATCH_MNT $UBGRACE $UIGRACE
+# Reset the user quota space & inode limits, avoid it affect later test
+setquota -u $qa_user 0 0 0 0 $SCRATCH_MNT
+
+setquota -g $qa_user $((250 * $BLOCK_SIZE / 1024)) \
+	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
+setquota -g -t $GBGRACE $GIGRACE $SCRATCH_MNT
+echo; echo "### Test group quota softlimit and grace time"
+test_grace g $SCRATCH_MNT $GBGRACE $GIGRACE
+# Reset the group quota space & inode limits, avoid it affect later test
+setquota -g $qa_user 0 0 0 0 $SCRATCH_MNT
+
+setquota -P $qa_user $((250 * $BLOCK_SIZE / 1024)) \
+	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
+setquota -P -t $PBGRACE $PIGRACE $SCRATCH_MNT
+echo; echo "### Test project quota softlimit and grace time"
+test_grace P $SCRATCH_MNT/t $PBGRACE $PIGRACE
+# Reset the project quota space & inode limits
+setquota -P $qa_user 0 0 0 0 $SCRATCH_MNT
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/902.out b/tests/generic/902.out
new file mode 100644
index 00000000..6e15eaeb
--- /dev/null
+++ b/tests/generic/902.out
@@ -0,0 +1,41 @@
+QA output created by 902
+### Set up different grace timers to each type of quota
+
+### Test user quota softlimit and grace time
+### Initialize files, and their mode and ownership
+--- Test block quota ---
+Write 225 blocks...
+Rewrite 250 blocks plus 1 byte, over the block softlimit...
+Try to write 1 one more block after grace...
+pwrite: Disk quota exceeded
+--- Test inode quota ---
+Create 2 more files, over the inode softlimit...
+Try to create one more inode after grace...
+touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
+### Remove all files
+
+### Test group quota softlimit and grace time
+### Initialize files, and their mode and ownership
+--- Test block quota ---
+Write 225 blocks...
+Rewrite 250 blocks plus 1 byte, over the block softlimit...
+Try to write 1 one more block after grace...
+pwrite: Disk quota exceeded
+--- Test inode quota ---
+Create 2 more files, over the inode softlimit...
+Try to create one more inode after grace...
+touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
+### Remove all files
+
+### Test project quota softlimit and grace time
+### Initialize files, and their mode and ownership
+--- Test block quota ---
+Write 225 blocks...
+Rewrite 250 blocks plus 1 byte, over the block softlimit...
+Try to write 1 one more block after grace...
+pwrite: Disk quota exceeded
+--- Test inode quota ---
+Create 2 more files, over the inode softlimit...
+Try to create one more inode after grace...
+touch: cannot touch 'SCRATCH_MNT/t/file5': Disk quota exceeded
+### Remove all files
diff --git a/tests/generic/group b/tests/generic/group
index 50c340a6..66e71a70 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -601,3 +601,4 @@
 596 auto quick
 900 auto quick perms
 901 auto quick perms
+902 auto quick quota
-- 
2.17.0



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 3/4] fstests: individual user grace period extension via setquota
  2020-05-18 19:59 ` [PATCH 0/4] fstests: more quota related tests Eric Sandeen
  2020-05-18 19:59   ` [PATCH 1/4] xfs: make sure our default quota warning limits and grace periods survive quotacheck Eric Sandeen
  2020-05-18 20:00   ` [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout Eric Sandeen
@ 2020-05-18 20:00   ` Eric Sandeen
  2020-05-18 20:01   ` [PATCH 4/4] fstests: individual user grace period extension via xfs_quota Eric Sandeen
  2020-05-20 15:39   ` [PATCH 0/4] fstests: more quota related tests Darrick J. Wong
  4 siblings, 0 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 20:00 UTC (permalink / raw)
  To: linux-xfs, fstests

Test that we can extend an individual user's grace time once they
reach their soft limit.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 tests/generic/903     | 67 +++++++++++++++++++++++++++++++++++++++++++
 tests/generic/903.out |  1 +
 tests/generic/group   |  1 +
 3 files changed, 69 insertions(+)
 create mode 100755 tests/generic/903
 create mode 100644 tests/generic/903.out

diff --git a/tests/generic/903 b/tests/generic/903
new file mode 100755
index 00000000..1903755e
--- /dev/null
+++ b/tests/generic/903
@@ -0,0 +1,67 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Red Hat, Inc.  All Rights Reserved.
+#
+# FS QA Test No. 903
+#
+# Test individual user ID quota grace period extension
+# This is the linux quota-tools version of the test
+#
+# This test only exercises user quota because it's not known whether the
+# filesystem can set individual grace timers for each quota type
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/quota
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+_require_scratch
+_require_quota
+_require_user
+_require_setquota_project
+
+_scratch_mkfs >$seqres.full 2>&1
+_qmount_option "usrquota"
+_qmount
+
+# Set a default user inode grace period of 1 second
+setquota -t -u 0 1 $SCRATCH_MNT
+# Soft inode limit 1, hard limit 5
+setquota -u $qa_user 0 0 1 5 $SCRATCH_MNT
+# Run qa user over soft limit and go over grace period
+su $qa_user -c "touch $SCRATCH_MNT/file1 $SCRATCH_MNT/file2"
+sleep 3
+# Extend grace to now + 100s
+now=`date +%s`
+let set=now+100
+setquota -T -u $qa_user 0 100 $SCRATCH_MNT 2>&1 | grep -v "^setquota"
+get=`repquota -up $SCRATCH_MNT | grep  "^$qa_user" | awk '{print $NF}'`
+
+if [ "$get" != "$set" ]; then
+	echo "set grace to $set but got grace $get"
+fi
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/903.out b/tests/generic/903.out
new file mode 100644
index 00000000..c0f7f92a
--- /dev/null
+++ b/tests/generic/903.out
@@ -0,0 +1 @@
+QA output created by 903
diff --git a/tests/generic/group b/tests/generic/group
index 66e71a70..ab1b4b8f 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -602,3 +602,4 @@
 900 auto quick perms
 901 auto quick perms
 902 auto quick quota
+903 auto quick quota
-- 
2.17.0



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 4/4] fstests: individual user grace period extension via xfs_quota
  2020-05-18 19:59 ` [PATCH 0/4] fstests: more quota related tests Eric Sandeen
                     ` (2 preceding siblings ...)
  2020-05-18 20:00   ` [PATCH 3/4] fstests: individual user grace period extension via setquota Eric Sandeen
@ 2020-05-18 20:01   ` Eric Sandeen
  2020-05-20 15:39   ` [PATCH 0/4] fstests: more quota related tests Darrick J. Wong
  4 siblings, 0 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 20:01 UTC (permalink / raw)
  To: linux-xfs, fstests

Test that we can extend an individual user's grace time once they
reach their soft limit.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 tests/generic/904     | 78 +++++++++++++++++++++++++++++++++++++++++++
 tests/generic/904.out |  1 +
 tests/generic/group   |  1 +
 3 files changed, 80 insertions(+)
 create mode 100755 tests/generic/904
 create mode 100644 tests/generic/904.out

diff --git a/tests/generic/904 b/tests/generic/904
new file mode 100755
index 00000000..8a3b52f2
--- /dev/null
+++ b/tests/generic/904
@@ -0,0 +1,78 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Red Hat, Inc.  All Rights Reserved.
+#
+# FS QA Test No. 902
+#
+# Test individual user ID quota grace period extension
+# This is the xfs_quota version of the test
+#
+# This test only exercises user quota because it's not known whether the
+# filesystem can set individual grace timers for each quota type
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/quota
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs generic
+_supported_os Linux
+_require_scratch
+_require_quota
+_require_user
+# for xfs_quota on generic fs
+_require_xfs_quota_foreign
+# for repquota (if setquota supports it, repquota does too)
+_require_setquota_project
+
+_scratch_mkfs >$seqres.full 2>&1
+_qmount_option "usrquota"
+_qmount
+
+# Test individual timer update functionality; if "-d" is accepted
+# this is xfs_quota that can do default /or/ individual timers
+$XFS_QUOTA_PROG -x -c "timer 0 -d" $SCRATCH_MNT 2>&1 \
+	| grep -q ^timer \
+	&& _notrun "xfs_quota does not support individual grace extension"
+
+# Set a default user inode grace period of 1 second
+$XFS_QUOTA_PROG -x -c "timer -u -i -d 1" $SCRATCH_MNT
+# Soft inode limit 1, hard limit 5
+$XFS_QUOTA_PROG -x -c "limit -u isoft=1 ihard=5 $qa_user" $SCRATCH_MNT
+# Run qa user over soft limit and go over grace period
+su $qa_user -c "touch $SCRATCH_MNT/file1 $SCRATCH_MNT/file2"
+sleep 3
+# Extend grace to now + 100s
+now=`date +%s`
+let set=now+100
+$XFS_QUOTA_PROG -x -c "timer -u -i 100 $qa_user" $SCRATCH_MNT
+# XXX We use repquota because xfs_quota doesn't know how to return
+# raw ("since epoch") grace expiry
+get=`repquota -up $SCRATCH_MNT | grep  "^$qa_user" | awk '{print $NF}'`
+
+if [ "$get" != "$set" ]; then
+	echo "set grace to $set but got grace $get"
+fi
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/904.out b/tests/generic/904.out
new file mode 100644
index 00000000..c07a2a3c
--- /dev/null
+++ b/tests/generic/904.out
@@ -0,0 +1 @@
+QA output created by 904
diff --git a/tests/generic/group b/tests/generic/group
index ab1b4b8f..d19271aa 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -603,3 +603,4 @@
 901 auto quick perms
 902 auto quick quota
 903 auto quick quota
+904 auto quick quota
-- 
2.17.0



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH 1/1] xfs_quota: allow individual timer extension
  2020-05-18 19:24   ` [PATCH 1/1] " Eric Sandeen
@ 2020-05-18 20:04     ` Eric Sandeen
  2020-05-18 20:09     ` [PATCH 1/1 V2] " Eric Sandeen
  1 sibling, 0 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 20:04 UTC (permalink / raw)
  To: linux-xfs

On 5/18/20 2:24 PM, Eric Sandeen wrote:
> The only grace period which can be set via xfs_quota today is for id 0,
> i.e. the default grace period for all users.  However, setting an
> individual grace period is useful; for example:
> 
>  Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
>  Alice uses 150 inodes, and enters a short grace period
>  Alice really needs to use those 150 inodes past the grace period
>  The administrator extends Alice's grace period until next Monday
> 
> vfs quota users such as ext4 can do this today, with setquota -T
> 
> xfs_quota can now accept an optional user id or name (symmetric with
> how warn limits are specified), in which case that user's grace period
> is extended to expire the given amount of time from now(). 
> 
> To maintain compatibility with old command lines, if none of 
> [-d|id|name] are specified, default limits are set as before.
> 
> (kernelspace requires updates to enable all this as well.)
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>


> +	/*
> +	 * If id is specified we are extending grace time by value
> +	 * Otherwise we are setting the default grace time
> +	 */
> +	if (id) {
> +		time_t	now;
> +
> +		if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
> +			exitcode = 1;
> +			fprintf(stderr, _("%s: cannot get quota: %s\n"),
> +					progname, strerror(errno));
> +				return;
> +		}
> +
> +		time(&now);
> +
> +		if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
> +			d.d_btimer = now + value;
> +		if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
> +			d.d_itimer = now + value;
> +		if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
> +			d.d_rtbtimer = now + value;

realized this might need some clarity (probably a comment).  The idea is that
we don't extend (i.e set) grace period unless the user is already into their
grace period. setquota -T does the same thing:

                if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > q->dq_dqb.dqb_bsoftlimit)
                        q->dq_dqb.dqb_btime = toset.dqb_btime;
                else
                        errstr(_("Not setting block grace time on %s because softlimit is not exceeded.\n"), q->dq_h->qh_quotadev);

Ugh, but also just realized I have a hardlimit/softlimit typo in there, will resend.

-Eric


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH 1/1 V2] xfs_quota: allow individual timer extension
  2020-05-18 19:24   ` [PATCH 1/1] " Eric Sandeen
  2020-05-18 20:04     ` Eric Sandeen
@ 2020-05-18 20:09     ` Eric Sandeen
  2020-05-19 16:38       ` Darrick J. Wong
  1 sibling, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-18 20:09 UTC (permalink / raw)
  To: linux-xfs

The only grace period which can be set via xfs_quota today is for id 0,
i.e. the default grace period for all users.  However, setting an
individual grace period is useful; for example:

 Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
 Alice uses 150 inodes, and enters a short grace period
 Alice really needs to use those 150 inodes past the grace period
 The administrator extends Alice's grace period until next Monday

vfs quota users such as ext4 can do this today, with setquota -T

xfs_quota can now accept an optional user id or name (symmetric with
how warn limits are specified), in which case that user's grace period
is extended to expire the given amount of time from now(). 

To maintain compatibility with old command lines, if none of 
[-d|id|name] are specified, default limits are set as before.

(kernelspace requires updates to enable all this as well.)

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

V2: Add comments about only extending if past soft limits
    Fix typo/mistake checking block hard limits instead of soft

diff --git a/man/man8/xfs_quota.8 b/man/man8/xfs_quota.8
index e6fe7cd1..dd0479cd 100644
--- a/man/man8/xfs_quota.8
+++ b/man/man8/xfs_quota.8
@@ -457,14 +457,46 @@ must be specified.
 .B \-bir
 ]
 .I value
+[
+.B -d
+|
+.I id
+|
+.I name
+]
 .br
 Allows the quota enforcement timeout (i.e. the amount of time allowed
 to pass before the soft limits are enforced as the hard limits) to
 be modified. The current timeout setting can be displayed using the
 .B state
-command. The value argument is a number of seconds, but units of
-\&'minutes', 'hours', 'days', and 'weeks' are also understood
+command.
+.br
+When setting the default timer via the
+.B \-d
+option, or for
+.B id
+0, or if no argument is given after
+.I value
+the
+.I value
+argument is a number of seconds indicating the relative amount of time after
+soft limits are exceeded, before hard limits are enforced.
+.br
+When setting any other individual timer by
+.I id
+or
+.I name,
+the
+.I value
+is the number of seconds from now, at which time the hard limits will be enforced.
+This allows extending the grace time of an individual user who has exceeded soft
+limits.
+.br
+For
+.I value,
+units of \&'minutes', 'hours', 'days', and 'weeks' are also understood
 (as are their abbreviations 'm', 'h', 'd', and 'w').
+.br
 .HP
 .B warn
 [
diff --git a/quota/edit.c b/quota/edit.c
index 442b608c..5fdb8ce7 100644
--- a/quota/edit.c
+++ b/quota/edit.c
@@ -419,6 +419,7 @@ restore_f(
 
 static void
 set_timer(
+	uint32_t	id,
 	uint		type,
 	uint		mask,
 	char		*dev,
@@ -427,14 +428,43 @@ set_timer(
 	fs_disk_quota_t	d;
 
 	memset(&d, 0, sizeof(d));
+
+	/*
+	 * If id is specified we are extending grace time by value
+	 * Otherwise we are setting the default grace time
+	 */
+	if (id) {
+		time_t	now;
+
+		/* Get quota to find out whether user is past soft limits */
+		if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
+			exitcode = 1;
+			fprintf(stderr, _("%s: cannot get quota: %s\n"),
+					progname, strerror(errno));
+				return;
+		}
+
+		time(&now);
+
+		/* Only set grace time if user is already past soft limit */
+		if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
+			d.d_btimer = now + value;
+		if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
+			d.d_itimer = now + value;
+		if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
+			d.d_rtbtimer = now + value;
+	} else {
+		d.d_btimer = value;
+		d.d_itimer = value;
+		d.d_rtbtimer = value;
+	}
+
 	d.d_version = FS_DQUOT_VERSION;
 	d.d_flags = type;
 	d.d_fieldmask = mask;
-	d.d_itimer = value;
-	d.d_btimer = value;
-	d.d_rtbtimer = value;
+	d.d_id = id;
 
-	if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
+	if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
 		exitcode = 1;
 		fprintf(stderr, _("%s: cannot set timer: %s\n"),
 				progname, strerror(errno));
@@ -447,10 +477,15 @@ timer_f(
 	char		**argv)
 {
 	uint		value;
-	int		c, type = 0, mask = 0;
+	char		*name = NULL;
+	uint32_t	id = 0;
+	int		c, flags = 0, type = 0, mask = 0;
 
-	while ((c = getopt(argc, argv, "bgipru")) != EOF) {
+	while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
 		switch (c) {
+		case 'd':
+			flags |= DEFAULTS_FLAG;
+			break;
 		case 'b':
 			mask |= FS_DQ_BTIMER;
 			break;
@@ -474,23 +509,45 @@ timer_f(
 		}
 	}
 
-	if (argc != optind + 1)
+	 /*
+	 * Older versions of the command did not accept -d|id|name,
+	 * so in that case we assume we're setting default timer,
+	 * and the last arg is the timer value.
+	 *
+	 * Otherwise, if the defaults flag is set, we expect 1 more arg for
+	 * timer value ; if not, 2 more args: 1 for value, one for id/name.
+	 */
+	if (!(flags & DEFAULTS_FLAG) && (argc == optind + 1)) {
+		value = cvttime(argv[optind++]);
+	} else if (flags & DEFAULTS_FLAG) {
+		if (argc != optind + 1)
+			return command_usage(&timer_cmd);
+		value = cvttime(argv[optind++]);
+	} else if (argc == optind + 2) {
+		value = cvttime(argv[optind++]);
+		name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
+	} else
 		return command_usage(&timer_cmd);
 
-	value = cvttime(argv[optind++]);
 
+	/* if none of -bir specified, set them all */
 	if (!mask)
 		mask = FS_DQ_TIMER_MASK;
 
 	if (!type) {
 		type = XFS_USER_QUOTA;
 	} else if (type != XFS_GROUP_QUOTA &&
-	           type != XFS_PROJ_QUOTA &&
-	           type != XFS_USER_QUOTA) {
+		   type != XFS_PROJ_QUOTA &&
+		   type != XFS_USER_QUOTA) {
 		return command_usage(&timer_cmd);
 	}
 
-	set_timer(type, mask, fs_path->fs_name, value);
+	if (name)
+		id = id_from_string(name, type);
+
+	if (id >= 0)
+		set_timer(id, type, mask, fs_path->fs_name, value);
+
 	return 0;
 }
 
@@ -616,9 +673,9 @@ edit_init(void)
 
 	timer_cmd.name = "timer";
 	timer_cmd.cfunc = timer_f;
-	timer_cmd.argmin = 2;
+	timer_cmd.argmin = 1;
 	timer_cmd.argmax = -1;
-	timer_cmd.args = _("[-bir] [-g|-p|-u] value");
+	timer_cmd.args = _("[-bir] [-g|-p|-u] value [-d|id|name]");
 	timer_cmd.oneline = _("set quota enforcement timeouts");
 	timer_cmd.help = timer_help;
 	timer_cmd.flags = CMD_FLAG_FOREIGN_OK;


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH 2/6] xfs: always return -ENOSPC on project quota reservation failure
  2020-05-18 18:49   ` [PATCH 2/6] xfs: always return -ENOSPC on project quota reservation failure Eric Sandeen
@ 2020-05-19 16:18     ` Darrick J. Wong
  0 siblings, 0 replies; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-19 16:18 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Mon, May 18, 2020 at 01:49:14PM -0500, Eric Sandeen wrote:
> XFS project quota treats project hierarchies as "mini filesysems" and
> so rather than -EDQUOT, the intent is to return -ENOSPC when a quota
> reservation fails, but this behavior is not consistent.
> 
> The only place we make a decision between -EDQUOT and -ENOSPC
> returns based on quota type is in xfs_trans_dqresv().
> 
> This behavior is currently controlled by whether or not the
> XFS_QMOPT_ENOSPC flag gets passed into the quota reservation.  However,
> its use is not consistent; paths such as xfs_create() and xfs_symlink()
> don't set the flag, so a reservation failure will return -EDQUOT for
> project quota reservation failures rather than -ENOSPC for these sorts
> of operations, even for project quota:
> 
> # mkdir mnt/project
> # xfs_quota -x -c "project -s -p mnt/project 42" mnt
> # xfs_quota -x -c 'limit -p isoft=2 ihard=3 42' mnt
> # touch mnt/project/file{1,2,3}
> touch: cannot touch ‘mnt/project/file3’: Disk quota exceeded
> 
> We can make this consistent by not requiring the flag to be set at the
> top of the callchain; instead we can simply test whether we are
> reserving a project quota with XFS_QM_ISPDQ in xfs_trans_dqresv and if
> so, return -ENOSPC for that failure.  This removes the need for the
> XFS_QMOPT_ENOSPC altogether and simplifies the code a fair bit.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: Brian Foster <bfoster@redhat.com>

Random thoughts on this patch and the previous one--

I like the part where these two patches actually make xfs consistent
about returning EDQUOT for user/group quota, and ENOSPC for project.
Annoyingly, it looks like f2fs/ext4 return EDQUOT for project quotas,
and fstests definitely trips a few regressions over the changing error
message.

So we have a bit of a mess wrt what the expected behavior is when you
run out of project quota.  In theory XFS has precedence since it was
there first, though somewhat eroded due to the inconsistencies that
weren't fixed until now.  OTOH, does that just mean ext4/f2fs are
broken?

What do others think?  The patch submitter probably ought to start a
fsdevel thread about this. ;)

For the kernel patch, I'll say:
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/libxfs/xfs_quota_defs.h |  1 -
>  fs/xfs/xfs_qm.c                |  9 +++------
>  fs/xfs/xfs_trans_dquot.c       | 16 +++++-----------
>  3 files changed, 8 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h
> index b2113b17e53c..56d9dd787e7b 100644
> --- a/fs/xfs/libxfs/xfs_quota_defs.h
> +++ b/fs/xfs/libxfs/xfs_quota_defs.h
> @@ -100,7 +100,6 @@ typedef uint16_t	xfs_qwarncnt_t;
>  #define XFS_QMOPT_FORCE_RES	0x0000010 /* ignore quota limits */
>  #define XFS_QMOPT_SBVERSION	0x0000040 /* change superblock version num */
>  #define XFS_QMOPT_GQUOTA	0x0002000 /* group dquot requested */
> -#define XFS_QMOPT_ENOSPC	0x0004000 /* enospc instead of edquot (prj) */
>  
>  /*
>   * flags to xfs_trans_mod_dquot to indicate which field needs to be
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index c225691fad15..591779aa2fd0 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -1808,7 +1808,7 @@ xfs_qm_vop_chown_reserve(
>  {
>  	struct xfs_mount	*mp = ip->i_mount;
>  	uint64_t		delblks;
> -	unsigned int		blkflags, prjflags = 0;
> +	unsigned int		blkflags;
>  	struct xfs_dquot	*udq_unres = NULL;
>  	struct xfs_dquot	*gdq_unres = NULL;
>  	struct xfs_dquot	*pdq_unres = NULL;
> @@ -1849,7 +1849,6 @@ xfs_qm_vop_chown_reserve(
>  
>  	if (XFS_IS_PQUOTA_ON(ip->i_mount) && pdqp &&
>  	    ip->i_d.di_projid != be32_to_cpu(pdqp->q_core.d_id)) {
> -		prjflags = XFS_QMOPT_ENOSPC;
>  		pdq_delblks = pdqp;
>  		if (delblks) {
>  			ASSERT(ip->i_pdquot);
> @@ -1859,8 +1858,7 @@ xfs_qm_vop_chown_reserve(
>  
>  	error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
>  				udq_delblks, gdq_delblks, pdq_delblks,
> -				ip->i_d.di_nblocks, 1,
> -				flags | blkflags | prjflags);
> +				ip->i_d.di_nblocks, 1, flags | blkflags);
>  	if (error)
>  		return error;
>  
> @@ -1878,8 +1876,7 @@ xfs_qm_vop_chown_reserve(
>  		ASSERT(udq_unres || gdq_unres || pdq_unres);
>  		error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
>  			    udq_delblks, gdq_delblks, pdq_delblks,
> -			    (xfs_qcnt_t)delblks, 0,
> -			    flags | blkflags | prjflags);
> +			    (xfs_qcnt_t)delblks, 0, flags | blkflags);
>  		if (error)
>  			return error;
>  		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index 2c3557a80e69..2c07897a3c37 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -711,7 +711,7 @@ xfs_trans_dqresv(
>  
>  error_return:
>  	xfs_dqunlock(dqp);
> -	if (flags & XFS_QMOPT_ENOSPC)
> +	if (XFS_QM_ISPDQ(dqp))
>  		return -ENOSPC;
>  	return -EDQUOT;
>  }
> @@ -751,15 +751,13 @@ xfs_trans_reserve_quota_bydquots(
>  	ASSERT(flags & XFS_QMOPT_RESBLK_MASK);
>  
>  	if (udqp) {
> -		error = xfs_trans_dqresv(tp, mp, udqp, nblks, ninos,
> -					(flags & ~XFS_QMOPT_ENOSPC));
> +		error = xfs_trans_dqresv(tp, mp, udqp, nblks, ninos, flags);
>  		if (error)
>  			return error;
>  	}
>  
>  	if (gdqp) {
> -		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos,
> -					(flags & ~XFS_QMOPT_ENOSPC));
> +		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
>  		if (error)
>  			goto unwind_usr;
>  	}
> @@ -804,16 +802,12 @@ xfs_trans_reserve_quota_nblks(
>  
>  	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
>  		return 0;
> -	if (XFS_IS_PQUOTA_ON(mp))
> -		flags |= XFS_QMOPT_ENOSPC;
>  
>  	ASSERT(!xfs_is_quota_inode(&mp->m_sb, ip->i_ino));
>  
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
> -	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
> -				XFS_TRANS_DQ_RES_RTBLKS ||
> -	       (flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
> -				XFS_TRANS_DQ_RES_BLKS);
> +	ASSERT((flags & ~(XFS_QMOPT_FORCE_RES)) == XFS_TRANS_DQ_RES_RTBLKS ||
> +	       (flags & ~(XFS_QMOPT_FORCE_RES)) == XFS_TRANS_DQ_RES_BLKS);
>  
>  	/*
>  	 * Reserve nblks against these dquots, with trans as the mediator.
> -- 
> 2.17.0
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 1/6] xfs: group quota should return EDQUOT when prj quota enabled
  2020-05-18 18:48   ` [PATCH 1/6] xfs: group quota should return EDQUOT when prj quota enabled Eric Sandeen
@ 2020-05-19 16:22     ` Darrick J. Wong
  0 siblings, 0 replies; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-19 16:22 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Mon, May 18, 2020 at 01:48:46PM -0500, Eric Sandeen wrote:
> Long ago, group & project quota were mutually exclusive, and so
> when we turned on XFS_QMOPT_ENOSPC ("return ENOSPC if project quota
> is exceeded") when project quota was enabled, we only needed to
> disable it again for user quota.
> 
> When group & project quota got separated, this got missed, and as a
> result if project quota is enabled and group quota is exceeded, the
> error code returned is incorrectly returned as ENOSPC not EDQUOT.
> 
> Fix this by stripping XFS_QMOPT_ENOSPC out of flags for group
> quota when we try to reserve the space.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: Brian Foster <bfoster@redhat.com>

Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/xfs_trans_dquot.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index d1b9869bc5fa..2c3557a80e69 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -758,7 +758,8 @@ xfs_trans_reserve_quota_bydquots(
>  	}
>  
>  	if (gdqp) {
> -		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos, flags);
> +		error = xfs_trans_dqresv(tp, mp, gdqp, nblks, ninos,
> +					(flags & ~XFS_QMOPT_ENOSPC));
>  		if (error)
>  			goto unwind_usr;
>  	}
> -- 
> 2.17.0
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 3/6] xfs: fix up some whitespace in quota code
  2020-05-18 18:49   ` [PATCH 3/6] xfs: fix up some whitespace in quota code Eric Sandeen
@ 2020-05-19 16:25     ` Darrick J. Wong
  0 siblings, 0 replies; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-19 16:25 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Mon, May 18, 2020 at 01:49:42PM -0500, Eric Sandeen wrote:
> There is a fair bit of whitespace damage in the quota code, so
> fix up enough of it that subsequent patches are restricted to
> functional change to aid review.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> Reviewed-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>

Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/xfs_dquot.c    | 16 ++++++++--------
>  fs/xfs/xfs_qm.h       | 44 +++++++++++++++++++++----------------------
>  fs/xfs/xfs_quotaops.c |  8 ++++----
>  3 files changed, 34 insertions(+), 34 deletions(-)
> 
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index af2c8e5ceea0..96e33390c6a0 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -205,16 +205,16 @@ xfs_qm_adjust_dqtimers(
>   */
>  STATIC void
>  xfs_qm_init_dquot_blk(
> -	xfs_trans_t	*tp,
> -	xfs_mount_t	*mp,
> -	xfs_dqid_t	id,
> -	uint		type,
> -	xfs_buf_t	*bp)
> +	struct xfs_trans	*tp,
> +	struct xfs_mount	*mp,
> +	xfs_dqid_t		id,
> +	uint			type,
> +	struct xfs_buf		*bp)
>  {
>  	struct xfs_quotainfo	*q = mp->m_quotainfo;
> -	xfs_dqblk_t	*d;
> -	xfs_dqid_t	curid;
> -	int		i;
> +	xfs_dqblk_t		*d;
> +	xfs_dqid_t		curid;
> +	int			i;
>  
>  	ASSERT(tp);
>  	ASSERT(xfs_buf_islocked(bp));
> diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
> index 4e57edca8bce..3a850401b102 100644
> --- a/fs/xfs/xfs_qm.h
> +++ b/fs/xfs/xfs_qm.h
> @@ -42,12 +42,12 @@ extern struct kmem_zone	*xfs_qm_dqtrxzone;
>  #define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
>  
>  struct xfs_def_quota {
> -	xfs_qcnt_t       bhardlimit;     /* default data blk hard limit */
> -	xfs_qcnt_t       bsoftlimit;	 /* default data blk soft limit */
> -	xfs_qcnt_t       ihardlimit;	 /* default inode count hard limit */
> -	xfs_qcnt_t       isoftlimit;	 /* default inode count soft limit */
> -	xfs_qcnt_t	 rtbhardlimit;   /* default realtime blk hard limit */
> -	xfs_qcnt_t	 rtbsoftlimit;   /* default realtime blk soft limit */
> +	xfs_qcnt_t	bhardlimit;	/* default data blk hard limit */
> +	xfs_qcnt_t	bsoftlimit;	/* default data blk soft limit */
> +	xfs_qcnt_t	ihardlimit;	/* default inode count hard limit */
> +	xfs_qcnt_t	isoftlimit;	/* default inode count soft limit */
> +	xfs_qcnt_t	rtbhardlimit;	/* default realtime blk hard limit */
> +	xfs_qcnt_t	rtbsoftlimit;	/* default realtime blk soft limit */
>  };
>  
>  /*
> @@ -55,28 +55,28 @@ struct xfs_def_quota {
>   * The mount structure keeps a pointer to this.
>   */
>  struct xfs_quotainfo {
> -	struct radix_tree_root qi_uquota_tree;
> -	struct radix_tree_root qi_gquota_tree;
> -	struct radix_tree_root qi_pquota_tree;
> -	struct mutex qi_tree_lock;
> +	struct radix_tree_root	qi_uquota_tree;
> +	struct radix_tree_root	qi_gquota_tree;
> +	struct radix_tree_root	qi_pquota_tree;
> +	struct mutex		qi_tree_lock;
>  	struct xfs_inode	*qi_uquotaip;	/* user quota inode */
>  	struct xfs_inode	*qi_gquotaip;	/* group quota inode */
>  	struct xfs_inode	*qi_pquotaip;	/* project quota inode */
> -	struct list_lru	 qi_lru;
> -	int		 qi_dquots;
> -	time64_t	 qi_btimelimit;	 /* limit for blks timer */
> -	time64_t	 qi_itimelimit;	 /* limit for inodes timer */
> -	time64_t	 qi_rtbtimelimit;/* limit for rt blks timer */
> -	xfs_qwarncnt_t	 qi_bwarnlimit;	 /* limit for blks warnings */
> -	xfs_qwarncnt_t	 qi_iwarnlimit;	 /* limit for inodes warnings */
> -	xfs_qwarncnt_t	 qi_rtbwarnlimit;/* limit for rt blks warnings */
> -	struct mutex	 qi_quotaofflock;/* to serialize quotaoff */
> -	xfs_filblks_t	 qi_dqchunklen;	 /* # BBs in a chunk of dqs */
> -	uint		 qi_dqperchunk;	 /* # ondisk dqs in above chunk */
> +	struct list_lru		qi_lru;
> +	int			qi_dquots;
> +	time64_t		qi_btimelimit;	/* limit for blks timer */
> +	time64_t		qi_itimelimit;	/* limit for inodes timer */
> +	time64_t		qi_rtbtimelimit;/* limit for rt blks timer */
> +	xfs_qwarncnt_t		qi_bwarnlimit;	/* limit for blks warnings */
> +	xfs_qwarncnt_t		qi_iwarnlimit;	/* limit for inodes warnings */
> +	xfs_qwarncnt_t		qi_rtbwarnlimit;/* limit for rt blks warnings */
> +	struct mutex		qi_quotaofflock;/* to serialize quotaoff */
> +	xfs_filblks_t		qi_dqchunklen;	/* # BBs in a chunk of dqs */
> +	uint			qi_dqperchunk;	/* # ondisk dq in above chunk */
>  	struct xfs_def_quota	qi_usr_default;
>  	struct xfs_def_quota	qi_grp_default;
>  	struct xfs_def_quota	qi_prj_default;
> -	struct shrinker	qi_shrinker;
> +	struct shrinker		qi_shrinker;
>  };
>  
>  static inline struct radix_tree_root *
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index 38669e827206..cb16a91dd1d4 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -23,8 +23,8 @@ xfs_qm_fill_state(
>  	struct xfs_inode	*ip,
>  	xfs_ino_t		ino)
>  {
> -	struct xfs_quotainfo *q = mp->m_quotainfo;
> -	bool tempqip = false;
> +	struct xfs_quotainfo	*q = mp->m_quotainfo;
> +	bool			tempqip = false;
>  
>  	tstate->ino = ino;
>  	if (!ip && ino == NULLFSINO)
> @@ -109,8 +109,8 @@ xfs_fs_set_info(
>  	int			type,
>  	struct qc_info		*info)
>  {
> -	struct xfs_mount *mp = XFS_M(sb);
> -	struct qc_dqblk newlim;
> +	struct xfs_mount	*mp = XFS_M(sb);
> +	struct qc_dqblk		newlim;
>  
>  	if (sb_rdonly(sb))
>  		return -EROFS;
> -- 
> 2.17.0
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 4/6] xfs: pass xfs_dquot to xfs_qm_adjust_dqtimers
  2020-05-18 18:50   ` [PATCH 4/6] xfs: pass xfs_dquot to xfs_qm_adjust_dqtimers Eric Sandeen
@ 2020-05-19 16:26     ` Darrick J. Wong
  0 siblings, 0 replies; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-19 16:26 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Mon, May 18, 2020 at 01:50:18PM -0500, Eric Sandeen wrote:
> Pass xfs_dquot rather than xfs_disk_dquot to xfs_qm_adjust_dqtimers;
> this makes it symmetric with xfs_qm_adjust_dqlimits and will help
> the next patch.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> Reviewed-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>

Seems reasonable,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/xfs_dquot.c       | 3 ++-
>  fs/xfs/xfs_dquot.h       | 2 +-
>  fs/xfs/xfs_qm.c          | 2 +-
>  fs/xfs/xfs_qm_syscalls.c | 2 +-
>  fs/xfs/xfs_trans_dquot.c | 2 +-
>  5 files changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index 96e33390c6a0..6d6afc0297b3 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -114,8 +114,9 @@ xfs_qm_adjust_dqlimits(
>  void
>  xfs_qm_adjust_dqtimers(
>  	struct xfs_mount	*mp,
> -	struct xfs_disk_dquot	*d)
> +	struct xfs_dquot	*dq)
>  {
> +	struct xfs_disk_dquot	*d = &dq->q_core;
>  	ASSERT(d->d_id);
>  
>  #ifdef DEBUG
> diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
> index fe3e46df604b..71e36c85e20b 100644
> --- a/fs/xfs/xfs_dquot.h
> +++ b/fs/xfs/xfs_dquot.h
> @@ -154,7 +154,7 @@ void		xfs_qm_dqdestroy(struct xfs_dquot *dqp);
>  int		xfs_qm_dqflush(struct xfs_dquot *dqp, struct xfs_buf **bpp);
>  void		xfs_qm_dqunpin_wait(struct xfs_dquot *dqp);
>  void		xfs_qm_adjust_dqtimers(struct xfs_mount *mp,
> -						struct xfs_disk_dquot *d);
> +						struct xfs_dquot *d);
>  void		xfs_qm_adjust_dqlimits(struct xfs_mount *mp,
>  						struct xfs_dquot *d);
>  xfs_dqid_t	xfs_qm_id_for_quotatype(struct xfs_inode *ip, uint type);
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index 591779aa2fd0..e97a3802939c 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -1116,7 +1116,7 @@ xfs_qm_quotacheck_dqadjust(
>  	 */
>  	if (dqp->q_core.d_id) {
>  		xfs_qm_adjust_dqlimits(mp, dqp);
> -		xfs_qm_adjust_dqtimers(mp, &dqp->q_core);
> +		xfs_qm_adjust_dqtimers(mp, dqp);
>  	}
>  
>  	dqp->dq_flags |= XFS_DQ_DIRTY;
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 5d5ac65aa1cc..301a284ee4f9 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -588,7 +588,7 @@ xfs_qm_scall_setqlim(
>  		 * is on or off. We don't really want to bother with iterating
>  		 * over all ondisk dquots and turning the timers on/off.
>  		 */
> -		xfs_qm_adjust_dqtimers(mp, ddq);
> +		xfs_qm_adjust_dqtimers(mp, dqp);
>  	}
>  	dqp->dq_flags |= XFS_DQ_DIRTY;
>  	xfs_trans_log_dquot(tp, dqp);
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index 2c07897a3c37..20542076e32a 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -388,7 +388,7 @@ xfs_trans_apply_dquot_deltas(
>  			 */
>  			if (d->d_id) {
>  				xfs_qm_adjust_dqlimits(tp->t_mountp, dqp);
> -				xfs_qm_adjust_dqtimers(tp->t_mountp, d);
> +				xfs_qm_adjust_dqtimers(tp->t_mountp, dqp);
>  			}
>  
>  			dqp->dq_flags |= XFS_DQ_DIRTY;
> -- 
> 2.17.0
> 
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 5/6] xfs: per-type quota timers and warn limits
  2020-05-18 18:51   ` [PATCH 5/6] xfs: per-type quota timers and warn limits Eric Sandeen
@ 2020-05-19 16:27     ` Darrick J. Wong
  2020-05-20 18:41     ` [PATCH 4.5/6] xfs: switch xfs_get_defquota to take explicit type Eric Sandeen
  2020-05-20 18:43     ` [PATCH 5/6 V2] xfs: per-type quota timers and warn limits Eric Sandeen
  2 siblings, 0 replies; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-19 16:27 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Mon, May 18, 2020 at 01:51:44PM -0500, Eric Sandeen wrote:
> From: Eric Sandeen <sandeen@redhat.com>
> 
> Move timers and warnings out of xfs_quotainfo and into xfs_def_quota
> so that we can utilize them on a per-type basis, rather than enforcing
> them based on the values found in the first enabled quota type.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> Reviewed-by: Allison Collins <allison.henderson@oracle.com>
> [zlang: new way to get defquota in xfs_qm_init_timelimits]
> [zlang: remove redundant defq assign]
> Signed-off-by: Zorro Lang <zlang@redhat.com>

Makes sense, I was always confused by the old behavior of picking the
defaults from the first quota type we saw...

Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/xfs_dquot.c       |  9 ++++---
>  fs/xfs/xfs_qm.c          | 54 +++++++++++++++++++---------------------
>  fs/xfs/xfs_qm.h          | 13 +++++-----
>  fs/xfs/xfs_qm_syscalls.c | 12 ++++-----
>  fs/xfs/xfs_quotaops.c    | 22 ++++++++--------
>  fs/xfs/xfs_trans_dquot.c |  6 ++---
>  6 files changed, 58 insertions(+), 58 deletions(-)
> 
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index 6d6afc0297b3..0e0a15c17789 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -116,7 +116,10 @@ xfs_qm_adjust_dqtimers(
>  	struct xfs_mount	*mp,
>  	struct xfs_dquot	*dq)
>  {
> +	struct xfs_quotainfo	*qi = mp->m_quotainfo;
>  	struct xfs_disk_dquot	*d = &dq->q_core;
> +	struct xfs_def_quota	*defq = xfs_get_defquota(dq, qi);
> +
>  	ASSERT(d->d_id);
>  
>  #ifdef DEBUG
> @@ -139,7 +142,7 @@ xfs_qm_adjust_dqtimers(
>  		     (be64_to_cpu(d->d_bcount) >
>  		      be64_to_cpu(d->d_blk_hardlimit)))) {
>  			d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
> -					mp->m_quotainfo->qi_btimelimit);
> +					defq->btimelimit);
>  		} else {
>  			d->d_bwarns = 0;
>  		}
> @@ -162,7 +165,7 @@ xfs_qm_adjust_dqtimers(
>  		     (be64_to_cpu(d->d_icount) >
>  		      be64_to_cpu(d->d_ino_hardlimit)))) {
>  			d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
> -					mp->m_quotainfo->qi_itimelimit);
> +					defq->itimelimit);
>  		} else {
>  			d->d_iwarns = 0;
>  		}
> @@ -185,7 +188,7 @@ xfs_qm_adjust_dqtimers(
>  		     (be64_to_cpu(d->d_rtbcount) >
>  		      be64_to_cpu(d->d_rtb_hardlimit)))) {
>  			d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
> -					mp->m_quotainfo->qi_rtbtimelimit);
> +					defq->rtbtimelimit);
>  		} else {
>  			d->d_rtbwarns = 0;
>  		}
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index e97a3802939c..9eaab2368d3d 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -577,19 +577,26 @@ xfs_qm_set_defquota(
>  static void
>  xfs_qm_init_timelimits(
>  	struct xfs_mount	*mp,
> -	struct xfs_quotainfo	*qinf)
> +	uint			type)
>  {
> +	struct xfs_quotainfo	*qinf = mp->m_quotainfo;
> +	struct xfs_def_quota	*defq;
>  	struct xfs_disk_dquot	*ddqp;
>  	struct xfs_dquot	*dqp;
> -	uint			type;
>  	int			error;
>  
> -	qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
> -	qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
> -	qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
> -	qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
> -	qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
> -	qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
> +	error = xfs_qm_dqget_uncached(mp, 0, type, &dqp);
> +	if (error)
> +		return;
> +
> +	defq = xfs_get_defquota(dqp, qinf);
> +
> +	defq->btimelimit = XFS_QM_BTIMELIMIT;
> +	defq->itimelimit = XFS_QM_ITIMELIMIT;
> +	defq->rtbtimelimit = XFS_QM_RTBTIMELIMIT;
> +	defq->bwarnlimit = XFS_QM_BWARNLIMIT;
> +	defq->iwarnlimit = XFS_QM_IWARNLIMIT;
> +	defq->rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
>  
>  	/*
>  	 * We try to get the limits from the superuser's limits fields.
> @@ -597,39 +604,26 @@ xfs_qm_init_timelimits(
>  	 *
>  	 * Since we may not have done a quotacheck by this point, just read
>  	 * the dquot without attaching it to any hashtables or lists.
> -	 *
> -	 * Timers and warnings are globally set by the first timer found in
> -	 * user/group/proj quota types, otherwise a default value is used.
> -	 * This should be split into different fields per quota type.
>  	 */
> -	if (XFS_IS_UQUOTA_RUNNING(mp))
> -		type = XFS_DQ_USER;
> -	else if (XFS_IS_GQUOTA_RUNNING(mp))
> -		type = XFS_DQ_GROUP;
> -	else
> -		type = XFS_DQ_PROJ;
> -	error = xfs_qm_dqget_uncached(mp, 0, type, &dqp);
> -	if (error)
> -		return;
> -
>  	ddqp = &dqp->q_core;
> +
>  	/*
>  	 * The warnings and timers set the grace period given to
>  	 * a user or group before he or she can not perform any
>  	 * more writing. If it is zero, a default is used.
>  	 */
>  	if (ddqp->d_btimer)
> -		qinf->qi_btimelimit = be32_to_cpu(ddqp->d_btimer);
> +		defq->btimelimit = be32_to_cpu(ddqp->d_btimer);
>  	if (ddqp->d_itimer)
> -		qinf->qi_itimelimit = be32_to_cpu(ddqp->d_itimer);
> +		defq->itimelimit = be32_to_cpu(ddqp->d_itimer);
>  	if (ddqp->d_rtbtimer)
> -		qinf->qi_rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer);
> +		defq->rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer);
>  	if (ddqp->d_bwarns)
> -		qinf->qi_bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
> +		defq->bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
>  	if (ddqp->d_iwarns)
> -		qinf->qi_iwarnlimit = be16_to_cpu(ddqp->d_iwarns);
> +		defq->iwarnlimit = be16_to_cpu(ddqp->d_iwarns);
>  	if (ddqp->d_rtbwarns)
> -		qinf->qi_rtbwarnlimit = be16_to_cpu(ddqp->d_rtbwarns);
> +		defq->rtbwarnlimit = be16_to_cpu(ddqp->d_rtbwarns);
>  
>  	xfs_qm_dqdestroy(dqp);
>  }
> @@ -675,7 +669,9 @@ xfs_qm_init_quotainfo(
>  
>  	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
>  
> -	xfs_qm_init_timelimits(mp, qinf);
> +	xfs_qm_init_timelimits(mp, XFS_DQ_USER);
> +	xfs_qm_init_timelimits(mp, XFS_DQ_GROUP);
> +	xfs_qm_init_timelimits(mp, XFS_DQ_PROJ);
>  
>  	if (XFS_IS_UQUOTA_RUNNING(mp))
>  		xfs_qm_set_defquota(mp, XFS_DQ_USER, qinf);
> diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
> index 3a850401b102..761286bf7fb2 100644
> --- a/fs/xfs/xfs_qm.h
> +++ b/fs/xfs/xfs_qm.h
> @@ -41,7 +41,14 @@ extern struct kmem_zone	*xfs_qm_dqtrxzone;
>   */
>  #define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
>  
> +/* Defaults for each quota type: time limits, warn limits, usage limits */
>  struct xfs_def_quota {
> +	time64_t	btimelimit;	/* limit for blks timer */
> +	time64_t	itimelimit;	/* limit for inodes timer */
> +	time64_t	rtbtimelimit;	/* limit for rt blks timer */
> +	xfs_qwarncnt_t	bwarnlimit;	/* limit for blks warnings */
> +	xfs_qwarncnt_t	iwarnlimit;	/* limit for inodes warnings */
> +	xfs_qwarncnt_t	rtbwarnlimit;	/* limit for rt blks warnings */
>  	xfs_qcnt_t	bhardlimit;	/* default data blk hard limit */
>  	xfs_qcnt_t	bsoftlimit;	/* default data blk soft limit */
>  	xfs_qcnt_t	ihardlimit;	/* default inode count hard limit */
> @@ -64,12 +71,6 @@ struct xfs_quotainfo {
>  	struct xfs_inode	*qi_pquotaip;	/* project quota inode */
>  	struct list_lru		qi_lru;
>  	int			qi_dquots;
> -	time64_t		qi_btimelimit;	/* limit for blks timer */
> -	time64_t		qi_itimelimit;	/* limit for inodes timer */
> -	time64_t		qi_rtbtimelimit;/* limit for rt blks timer */
> -	xfs_qwarncnt_t		qi_bwarnlimit;	/* limit for blks warnings */
> -	xfs_qwarncnt_t		qi_iwarnlimit;	/* limit for inodes warnings */
> -	xfs_qwarncnt_t		qi_rtbwarnlimit;/* limit for rt blks warnings */
>  	struct mutex		qi_quotaofflock;/* to serialize quotaoff */
>  	xfs_filblks_t		qi_dqchunklen;	/* # BBs in a chunk of dqs */
>  	uint			qi_dqperchunk;	/* # ondisk dq in above chunk */
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 301a284ee4f9..29c1d5d4104d 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -563,23 +563,23 @@ xfs_qm_scall_setqlim(
>  		 * for warnings.
>  		 */
>  		if (newlim->d_fieldmask & QC_SPC_TIMER) {
> -			q->qi_btimelimit = newlim->d_spc_timer;
> +			defq->btimelimit = newlim->d_spc_timer;
>  			ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
>  		}
>  		if (newlim->d_fieldmask & QC_INO_TIMER) {
> -			q->qi_itimelimit = newlim->d_ino_timer;
> +			defq->itimelimit = newlim->d_ino_timer;
>  			ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
>  		}
>  		if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
> -			q->qi_rtbtimelimit = newlim->d_rt_spc_timer;
> +			defq->rtbtimelimit = newlim->d_rt_spc_timer;
>  			ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
>  		}
>  		if (newlim->d_fieldmask & QC_SPC_WARNS)
> -			q->qi_bwarnlimit = newlim->d_spc_warns;
> +			defq->bwarnlimit = newlim->d_spc_warns;
>  		if (newlim->d_fieldmask & QC_INO_WARNS)
> -			q->qi_iwarnlimit = newlim->d_ino_warns;
> +			defq->iwarnlimit = newlim->d_ino_warns;
>  		if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
> -			q->qi_rtbwarnlimit = newlim->d_rt_spc_warns;
> +			defq->rtbwarnlimit = newlim->d_rt_spc_warns;
>  	} else {
>  		/*
>  		 * If the user is now over quota, start the timelimit.
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index cb16a91dd1d4..51be282d28b3 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -21,9 +21,9 @@ xfs_qm_fill_state(
>  	struct qc_type_state	*tstate,
>  	struct xfs_mount	*mp,
>  	struct xfs_inode	*ip,
> -	xfs_ino_t		ino)
> +	xfs_ino_t		ino,
> +	struct xfs_def_quota	*defq)
>  {
> -	struct xfs_quotainfo	*q = mp->m_quotainfo;
>  	bool			tempqip = false;
>  
>  	tstate->ino = ino;
> @@ -37,12 +37,12 @@ xfs_qm_fill_state(
>  	tstate->flags |= QCI_SYSFILE;
>  	tstate->blocks = ip->i_d.di_nblocks;
>  	tstate->nextents = ip->i_d.di_nextents;
> -	tstate->spc_timelimit = (u32)q->qi_btimelimit;
> -	tstate->ino_timelimit = (u32)q->qi_itimelimit;
> -	tstate->rt_spc_timelimit = (u32)q->qi_rtbtimelimit;
> -	tstate->spc_warnlimit = q->qi_bwarnlimit;
> -	tstate->ino_warnlimit = q->qi_iwarnlimit;
> -	tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
> +	tstate->spc_timelimit = (u32)defq->btimelimit;
> +	tstate->ino_timelimit = (u32)defq->itimelimit;
> +	tstate->rt_spc_timelimit = (u32)defq->rtbtimelimit;
> +	tstate->spc_warnlimit = defq->bwarnlimit;
> +	tstate->ino_warnlimit = defq->iwarnlimit;
> +	tstate->rt_spc_warnlimit = defq->rtbwarnlimit;
>  	if (tempqip)
>  		xfs_irele(ip);
>  }
> @@ -77,11 +77,11 @@ xfs_fs_get_quota_state(
>  		state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED;
>  
>  	xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip,
> -			  mp->m_sb.sb_uquotino);
> +			  mp->m_sb.sb_uquotino, &q->qi_usr_default);
>  	xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip,
> -			  mp->m_sb.sb_gquotino);
> +			  mp->m_sb.sb_gquotino, &q->qi_grp_default);
>  	xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip,
> -			  mp->m_sb.sb_pquotino);
> +			  mp->m_sb.sb_pquotino, &q->qi_prj_default);
>  	return 0;
>  }
>  
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index 20542076e32a..aa25647e0864 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -602,7 +602,7 @@ xfs_trans_dqresv(
>  			softlimit = defq->bsoftlimit;
>  		timer = be32_to_cpu(dqp->q_core.d_btimer);
>  		warns = be16_to_cpu(dqp->q_core.d_bwarns);
> -		warnlimit = dqp->q_mount->m_quotainfo->qi_bwarnlimit;
> +		warnlimit = defq->bwarnlimit;
>  		resbcountp = &dqp->q_res_bcount;
>  	} else {
>  		ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
> @@ -614,7 +614,7 @@ xfs_trans_dqresv(
>  			softlimit = defq->rtbsoftlimit;
>  		timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
>  		warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
> -		warnlimit = dqp->q_mount->m_quotainfo->qi_rtbwarnlimit;
> +		warnlimit = defq->rtbwarnlimit;
>  		resbcountp = &dqp->q_res_rtbcount;
>  	}
>  
> @@ -650,7 +650,7 @@ xfs_trans_dqresv(
>  			total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos;
>  			timer = be32_to_cpu(dqp->q_core.d_itimer);
>  			warns = be16_to_cpu(dqp->q_core.d_iwarns);
> -			warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;
> +			warnlimit = defq->iwarnlimit;
>  			hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
>  			if (!hardlimit)
>  				hardlimit = defq->ihardlimit;
> -- 
> 2.17.0
> 
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 1/1 V2] xfs_quota: allow individual timer extension
  2020-05-18 20:09     ` [PATCH 1/1 V2] " Eric Sandeen
@ 2020-05-19 16:38       ` Darrick J. Wong
  2020-05-19 21:34         ` Darrick J. Wong
  0 siblings, 1 reply; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-19 16:38 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Mon, May 18, 2020 at 03:09:30PM -0500, Eric Sandeen wrote:
> The only grace period which can be set via xfs_quota today is for id 0,
> i.e. the default grace period for all users.  However, setting an
> individual grace period is useful; for example:
> 
>  Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
>  Alice uses 150 inodes, and enters a short grace period
>  Alice really needs to use those 150 inodes past the grace period
>  The administrator extends Alice's grace period until next Monday
> 
> vfs quota users such as ext4 can do this today, with setquota -T
> 
> xfs_quota can now accept an optional user id or name (symmetric with
> how warn limits are specified), in which case that user's grace period
> is extended to expire the given amount of time from now(). 
> 
> To maintain compatibility with old command lines, if none of 
> [-d|id|name] are specified, default limits are set as before.
> 
> (kernelspace requires updates to enable all this as well.)
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---
> 
> V2: Add comments about only extending if past soft limits
>     Fix typo/mistake checking block hard limits instead of soft
> 
> diff --git a/man/man8/xfs_quota.8 b/man/man8/xfs_quota.8
> index e6fe7cd1..dd0479cd 100644
> --- a/man/man8/xfs_quota.8
> +++ b/man/man8/xfs_quota.8
> @@ -457,14 +457,46 @@ must be specified.
>  .B \-bir
>  ]
>  .I value
> +[
> +.B -d
> +|
> +.I id
> +|
> +.I name
> +]
>  .br
>  Allows the quota enforcement timeout (i.e. the amount of time allowed
>  to pass before the soft limits are enforced as the hard limits) to
>  be modified. The current timeout setting can be displayed using the
>  .B state
> -command. The value argument is a number of seconds, but units of
> -\&'minutes', 'hours', 'days', and 'weeks' are also understood
> +command.
> +.br
> +When setting the default timer via the
> +.B \-d
> +option, or for
> +.B id
> +0, or if no argument is given after
> +.I value
> +the
> +.I value
> +argument is a number of seconds indicating the relative amount of time after
> +soft limits are exceeded, before hard limits are enforced.
> +.br
> +When setting any other individual timer by
> +.I id
> +or
> +.I name,
> +the
> +.I value
> +is the number of seconds from now, at which time the hard limits will be enforced.
> +This allows extending the grace time of an individual user who has exceeded soft
> +limits.
> +.br
> +For
> +.I value,
> +units of \&'minutes', 'hours', 'days', and 'weeks' are also understood
>  (as are their abbreviations 'm', 'h', 'd', and 'w').
> +.br
>  .HP
>  .B warn
>  [
> diff --git a/quota/edit.c b/quota/edit.c
> index 442b608c..5fdb8ce7 100644
> --- a/quota/edit.c
> +++ b/quota/edit.c
> @@ -419,6 +419,7 @@ restore_f(
>  
>  static void
>  set_timer(
> +	uint32_t	id,
>  	uint		type,
>  	uint		mask,
>  	char		*dev,
> @@ -427,14 +428,43 @@ set_timer(
>  	fs_disk_quota_t	d;
>  
>  	memset(&d, 0, sizeof(d));
> +
> +	/*
> +	 * If id is specified we are extending grace time by value
> +	 * Otherwise we are setting the default grace time
> +	 */
> +	if (id) {
> +		time_t	now;
> +
> +		/* Get quota to find out whether user is past soft limits */
> +		if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
> +			exitcode = 1;
> +			fprintf(stderr, _("%s: cannot get quota: %s\n"),
> +					progname, strerror(errno));
> +				return;
> +		}
> +
> +		time(&now);
> +
> +		/* Only set grace time if user is already past soft limit */
> +		if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
> +			d.d_btimer = now + value;
> +		if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
> +			d.d_itimer = now + value;
> +		if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
> +			d.d_rtbtimer = now + value;

Hmm, I /was/ going to complain about 32-bit wraparound, but then
realized that the whole ioctl interface is totally __s32 and needs
y2038 updates and meh.

Someone looking for a project could work on either fixing the xfs quota
ioctls, or the vfs quota ioctls, or both, assuming Arnd didn't already
fix the VFS...

Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> +	} else {
> +		d.d_btimer = value;
> +		d.d_itimer = value;
> +		d.d_rtbtimer = value;
> +	}
> +
>  	d.d_version = FS_DQUOT_VERSION;
>  	d.d_flags = type;
>  	d.d_fieldmask = mask;
> -	d.d_itimer = value;
> -	d.d_btimer = value;
> -	d.d_rtbtimer = value;
> +	d.d_id = id;
>  
> -	if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
> +	if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
>  		exitcode = 1;
>  		fprintf(stderr, _("%s: cannot set timer: %s\n"),
>  				progname, strerror(errno));
> @@ -447,10 +477,15 @@ timer_f(
>  	char		**argv)
>  {
>  	uint		value;
> -	int		c, type = 0, mask = 0;
> +	char		*name = NULL;
> +	uint32_t	id = 0;
> +	int		c, flags = 0, type = 0, mask = 0;
>  
> -	while ((c = getopt(argc, argv, "bgipru")) != EOF) {
> +	while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
>  		switch (c) {
> +		case 'd':
> +			flags |= DEFAULTS_FLAG;
> +			break;
>  		case 'b':
>  			mask |= FS_DQ_BTIMER;
>  			break;
> @@ -474,23 +509,45 @@ timer_f(
>  		}
>  	}
>  
> -	if (argc != optind + 1)
> +	 /*
> +	 * Older versions of the command did not accept -d|id|name,
> +	 * so in that case we assume we're setting default timer,
> +	 * and the last arg is the timer value.
> +	 *
> +	 * Otherwise, if the defaults flag is set, we expect 1 more arg for
> +	 * timer value ; if not, 2 more args: 1 for value, one for id/name.
> +	 */
> +	if (!(flags & DEFAULTS_FLAG) && (argc == optind + 1)) {
> +		value = cvttime(argv[optind++]);
> +	} else if (flags & DEFAULTS_FLAG) {
> +		if (argc != optind + 1)
> +			return command_usage(&timer_cmd);
> +		value = cvttime(argv[optind++]);
> +	} else if (argc == optind + 2) {
> +		value = cvttime(argv[optind++]);
> +		name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
> +	} else
>  		return command_usage(&timer_cmd);
>  
> -	value = cvttime(argv[optind++]);
>  
> +	/* if none of -bir specified, set them all */
>  	if (!mask)
>  		mask = FS_DQ_TIMER_MASK;
>  
>  	if (!type) {
>  		type = XFS_USER_QUOTA;
>  	} else if (type != XFS_GROUP_QUOTA &&
> -	           type != XFS_PROJ_QUOTA &&
> -	           type != XFS_USER_QUOTA) {
> +		   type != XFS_PROJ_QUOTA &&
> +		   type != XFS_USER_QUOTA) {
>  		return command_usage(&timer_cmd);
>  	}
>  
> -	set_timer(type, mask, fs_path->fs_name, value);
> +	if (name)
> +		id = id_from_string(name, type);
> +
> +	if (id >= 0)
> +		set_timer(id, type, mask, fs_path->fs_name, value);
> +
>  	return 0;
>  }
>  
> @@ -616,9 +673,9 @@ edit_init(void)
>  
>  	timer_cmd.name = "timer";
>  	timer_cmd.cfunc = timer_f;
> -	timer_cmd.argmin = 2;
> +	timer_cmd.argmin = 1;
>  	timer_cmd.argmax = -1;
> -	timer_cmd.args = _("[-bir] [-g|-p|-u] value");
> +	timer_cmd.args = _("[-bir] [-g|-p|-u] value [-d|id|name]");
>  	timer_cmd.oneline = _("set quota enforcement timeouts");
>  	timer_cmd.help = timer_help;
>  	timer_cmd.flags = CMD_FLAG_FOREIGN_OK;
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 6/6] xfs: allow individual quota grace period extension
  2020-05-18 18:52   ` [PATCH 6/6] xfs: allow individual quota grace period extension Eric Sandeen
@ 2020-05-19 16:39     ` Darrick J. Wong
  2020-05-19 17:21       ` Eric Sandeen
  0 siblings, 1 reply; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-19 16:39 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Mon, May 18, 2020 at 01:52:16PM -0500, Eric Sandeen wrote:
> The only grace period which can be set in the kernel today is for id 0,
> i.e. the default grace period for all users.  However, setting an
> individual grace period is useful; for example:
> 
>  Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
>  Alice uses 150 inodes, and enters a short grace period
>  Alice really needs to use those 150 inodes past the grace period
>  The administrator extends Alice's grace period until next Monday
> 
> vfs quota users such as ext4 can do this today, with setquota -T

Does setquota -T work on an XFS filesystem?  If so, does that mean that
xfs had a functionality gap where the admin could extend someone's grace
period on ext4 but trying the exact same command on xfs would do
nothing?  Or would it at least error out?

> To enable this for XFS, we simply move the timelimit assignment out
> from under the (id == 0) test.  Default setting remains under (id == 0).
> Note that this now is consistent with how we set warnings.
> 
> (Userspace requires updates to enable this as well; xfs_quota needs to
> parse new options, and setquota needs to set appropriate field flags.)

So ... xfs_quota simply never had the ability to do this, but what does
"setquota needs to set appropriate field flags" mean exactly?

--D

> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---
>  fs/xfs/xfs_qm_syscalls.c | 48 +++++++++++++++++++++++-----------------
>  1 file changed, 28 insertions(+), 20 deletions(-)
> 
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 29c1d5d4104d..94d374820c7e 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -555,32 +555,40 @@ xfs_qm_scall_setqlim(
>  		ddq->d_rtbwarns = cpu_to_be16(newlim->d_rt_spc_warns);
>  
>  	if (id == 0) {
> -		/*
> -		 * Timelimits for the super user set the relative time
> -		 * the other users can be over quota for this file system.
> -		 * If it is zero a default is used.  Ditto for the default
> -		 * soft and hard limit values (already done, above), and
> -		 * for warnings.
> -		 */
> -		if (newlim->d_fieldmask & QC_SPC_TIMER) {
> -			defq->btimelimit = newlim->d_spc_timer;
> -			ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
> -		}
> -		if (newlim->d_fieldmask & QC_INO_TIMER) {
> -			defq->itimelimit = newlim->d_ino_timer;
> -			ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
> -		}
> -		if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
> -			defq->rtbtimelimit = newlim->d_rt_spc_timer;
> -			ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
> -		}
>  		if (newlim->d_fieldmask & QC_SPC_WARNS)
>  			defq->bwarnlimit = newlim->d_spc_warns;
>  		if (newlim->d_fieldmask & QC_INO_WARNS)
>  			defq->iwarnlimit = newlim->d_ino_warns;
>  		if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
>  			defq->rtbwarnlimit = newlim->d_rt_spc_warns;
> -	} else {
> +	}
> +
> +	/*
> +	 * Timelimits for the super user set the relative time the other users
> +	 * can be over quota for this file system. If it is zero a default is
> +	 * used.  Ditto for the default soft and hard limit values (already
> +	 * done, above), and for warnings.
> +	 *
> +	 * For other IDs, userspace can bump out the grace period if over
> +	 * the soft limit.
> +	 */
> +	if (newlim->d_fieldmask & QC_SPC_TIMER)
> +		ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
> +	if (newlim->d_fieldmask & QC_INO_TIMER)
> +		ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
> +	if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
> +		ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
> +
> +	if (id == 0) {
> +		if (newlim->d_fieldmask & QC_SPC_TIMER)
> +			defq->btimelimit = newlim->d_spc_timer;
> +		if (newlim->d_fieldmask & QC_INO_TIMER)
> +			defq->itimelimit = newlim->d_ino_timer;
> +		if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
> +			defq->rtbtimelimit = newlim->d_rt_spc_timer;
> +	}
> +
> +	if (id != 0) {
>  		/*
>  		 * If the user is now over quota, start the timelimit.
>  		 * The user will not be 'warned'.
> -- 
> 2.17.0
> 
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 6/6] xfs: allow individual quota grace period extension
  2020-05-19 16:39     ` Darrick J. Wong
@ 2020-05-19 17:21       ` Eric Sandeen
  0 siblings, 0 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-19 17:21 UTC (permalink / raw)
  To: Darrick J. Wong, Eric Sandeen; +Cc: linux-xfs

On 5/19/20 11:39 AM, Darrick J. Wong wrote:
> On Mon, May 18, 2020 at 01:52:16PM -0500, Eric Sandeen wrote:
>> The only grace period which can be set in the kernel today is for id 0,
>> i.e. the default grace period for all users.  However, setting an
>> individual grace period is useful; for example:
>>
>>  Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
>>  Alice uses 150 inodes, and enters a short grace period
>>  Alice really needs to use those 150 inodes past the grace period
>>  The administrator extends Alice's grace period until next Monday
>>
>> vfs quota users such as ext4 can do this today, with setquota -T
> 
> Does setquota -T work on an XFS filesystem? 

With 

[PATCH] quota-tools: Set FS_DQ_TIMER_MASK for individual xfs grace times

it does.

> If so, does that mean that
> xfs had a functionality gap where the admin could extend someone's grace
> period on ext4 but trying the exact same command on xfs would do
> nothing?  Or would it at least error out?

The former; no error.  quota-tools didn't set the timer mask, so quotactl
wasn't set up to change it.  In addition, we ignored the change for id !=0.
 
>> To enable this for XFS, we simply move the timelimit assignment out
>> from under the (id == 0) test.  Default setting remains under (id == 0).
>> Note that this now is consistent with how we set warnings.
>>
>> (Userspace requires updates to enable this as well; xfs_quota needs to
>> parse new options, and setquota needs to set appropriate field flags.)
> 
> So ... xfs_quota simply never had the ability to do this, but what does
> "setquota needs to set appropriate field flags" mean exactly?

It means:

[PATCH] quota-tools: Set FS_DQ_TIMER_MASK for individual xfs grace times

+		if (flags & COMMIT_TIMES) /* indiv grace period */
+			xdqblk.d_fieldmask |= FS_DQ_TIMER_MASK;

-Eric
 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 1/1 V2] xfs_quota: allow individual timer extension
  2020-05-19 16:38       ` Darrick J. Wong
@ 2020-05-19 21:34         ` Darrick J. Wong
  0 siblings, 0 replies; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-19 21:34 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Tue, May 19, 2020 at 09:38:10AM -0700, Darrick J. Wong wrote:
> On Mon, May 18, 2020 at 03:09:30PM -0500, Eric Sandeen wrote:
> > The only grace period which can be set via xfs_quota today is for id 0,
> > i.e. the default grace period for all users.  However, setting an
> > individual grace period is useful; for example:
> > 
> >  Alice has a soft quota of 100 inodes, and a hard quota of 200 inodes
> >  Alice uses 150 inodes, and enters a short grace period
> >  Alice really needs to use those 150 inodes past the grace period
> >  The administrator extends Alice's grace period until next Monday
> > 
> > vfs quota users such as ext4 can do this today, with setquota -T
> > 
> > xfs_quota can now accept an optional user id or name (symmetric with
> > how warn limits are specified), in which case that user's grace period
> > is extended to expire the given amount of time from now(). 
> > 
> > To maintain compatibility with old command lines, if none of 
> > [-d|id|name] are specified, default limits are set as before.
> > 
> > (kernelspace requires updates to enable all this as well.)
> > 
> > Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> > ---
> > 
> > V2: Add comments about only extending if past soft limits
> >     Fix typo/mistake checking block hard limits instead of soft
> > 
> > diff --git a/man/man8/xfs_quota.8 b/man/man8/xfs_quota.8
> > index e6fe7cd1..dd0479cd 100644
> > --- a/man/man8/xfs_quota.8
> > +++ b/man/man8/xfs_quota.8
> > @@ -457,14 +457,46 @@ must be specified.
> >  .B \-bir
> >  ]
> >  .I value
> > +[
> > +.B -d
> > +|
> > +.I id
> > +|
> > +.I name
> > +]
> >  .br
> >  Allows the quota enforcement timeout (i.e. the amount of time allowed
> >  to pass before the soft limits are enforced as the hard limits) to
> >  be modified. The current timeout setting can be displayed using the
> >  .B state
> > -command. The value argument is a number of seconds, but units of
> > -\&'minutes', 'hours', 'days', and 'weeks' are also understood
> > +command.
> > +.br
> > +When setting the default timer via the
> > +.B \-d
> > +option, or for
> > +.B id
> > +0, or if no argument is given after
> > +.I value
> > +the
> > +.I value
> > +argument is a number of seconds indicating the relative amount of time after
> > +soft limits are exceeded, before hard limits are enforced.
> > +.br
> > +When setting any other individual timer by
> > +.I id
> > +or
> > +.I name,
> > +the
> > +.I value
> > +is the number of seconds from now, at which time the hard limits will be enforced.
> > +This allows extending the grace time of an individual user who has exceeded soft
> > +limits.
> > +.br
> > +For
> > +.I value,
> > +units of \&'minutes', 'hours', 'days', and 'weeks' are also understood
> >  (as are their abbreviations 'm', 'h', 'd', and 'w').
> > +.br
> >  .HP
> >  .B warn
> >  [
> > diff --git a/quota/edit.c b/quota/edit.c
> > index 442b608c..5fdb8ce7 100644
> > --- a/quota/edit.c
> > +++ b/quota/edit.c
> > @@ -419,6 +419,7 @@ restore_f(
> >  
> >  static void
> >  set_timer(
> > +	uint32_t	id,
> >  	uint		type,
> >  	uint		mask,
> >  	char		*dev,
> > @@ -427,14 +428,43 @@ set_timer(
> >  	fs_disk_quota_t	d;
> >  
> >  	memset(&d, 0, sizeof(d));
> > +
> > +	/*
> > +	 * If id is specified we are extending grace time by value
> > +	 * Otherwise we are setting the default grace time
> > +	 */
> > +	if (id) {
> > +		time_t	now;
> > +
> > +		/* Get quota to find out whether user is past soft limits */
> > +		if (xfsquotactl(XFS_GETQUOTA, dev, type, id, (void *)&d) < 0) {
> > +			exitcode = 1;
> > +			fprintf(stderr, _("%s: cannot get quota: %s\n"),
> > +					progname, strerror(errno));
> > +				return;
> > +		}
> > +
> > +		time(&now);
> > +
> > +		/* Only set grace time if user is already past soft limit */
> > +		if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
> > +			d.d_btimer = now + value;
> > +		if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
> > +			d.d_itimer = now + value;
> > +		if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
> > +			d.d_rtbtimer = now + value;
> 
> Hmm, I /was/ going to complain about 32-bit wraparound, but then
> realized that the whole ioctl interface is totally __s32 and needs
> y2038 updates and meh.
> 
> Someone looking for a project could work on either fixing the xfs quota
> ioctls, or the vfs quota ioctls, or both, assuming Arnd didn't already
> fix the VFS...
> 
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

...hmm, wait, so an old kernel won't /do/ anything, right?  It won't
error out, but the grace period for that non-root user won't have been
changed.  Perhaps this ought to re-check the grace period values
afterwards to assess efficacy.

--D

> --D
> 
> > +	} else {
> > +		d.d_btimer = value;
> > +		d.d_itimer = value;
> > +		d.d_rtbtimer = value;
> > +	}
> > +
> >  	d.d_version = FS_DQUOT_VERSION;
> >  	d.d_flags = type;
> >  	d.d_fieldmask = mask;
> > -	d.d_itimer = value;
> > -	d.d_btimer = value;
> > -	d.d_rtbtimer = value;
> > +	d.d_id = id;
> >  
> > -	if (xfsquotactl(XFS_SETQLIM, dev, type, 0, (void *)&d) < 0) {
> > +	if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
> >  		exitcode = 1;
> >  		fprintf(stderr, _("%s: cannot set timer: %s\n"),
> >  				progname, strerror(errno));
> > @@ -447,10 +477,15 @@ timer_f(
> >  	char		**argv)
> >  {
> >  	uint		value;
> > -	int		c, type = 0, mask = 0;
> > +	char		*name = NULL;
> > +	uint32_t	id = 0;
> > +	int		c, flags = 0, type = 0, mask = 0;
> >  
> > -	while ((c = getopt(argc, argv, "bgipru")) != EOF) {
> > +	while ((c = getopt(argc, argv, "bdgipru")) != EOF) {
> >  		switch (c) {
> > +		case 'd':
> > +			flags |= DEFAULTS_FLAG;
> > +			break;
> >  		case 'b':
> >  			mask |= FS_DQ_BTIMER;
> >  			break;
> > @@ -474,23 +509,45 @@ timer_f(
> >  		}
> >  	}
> >  
> > -	if (argc != optind + 1)
> > +	 /*
> > +	 * Older versions of the command did not accept -d|id|name,
> > +	 * so in that case we assume we're setting default timer,
> > +	 * and the last arg is the timer value.
> > +	 *
> > +	 * Otherwise, if the defaults flag is set, we expect 1 more arg for
> > +	 * timer value ; if not, 2 more args: 1 for value, one for id/name.
> > +	 */
> > +	if (!(flags & DEFAULTS_FLAG) && (argc == optind + 1)) {
> > +		value = cvttime(argv[optind++]);
> > +	} else if (flags & DEFAULTS_FLAG) {
> > +		if (argc != optind + 1)
> > +			return command_usage(&timer_cmd);
> > +		value = cvttime(argv[optind++]);
> > +	} else if (argc == optind + 2) {
> > +		value = cvttime(argv[optind++]);
> > +		name = (flags & DEFAULTS_FLAG) ? "0" : argv[optind++];
> > +	} else
> >  		return command_usage(&timer_cmd);
> >  
> > -	value = cvttime(argv[optind++]);
> >  
> > +	/* if none of -bir specified, set them all */
> >  	if (!mask)
> >  		mask = FS_DQ_TIMER_MASK;
> >  
> >  	if (!type) {
> >  		type = XFS_USER_QUOTA;
> >  	} else if (type != XFS_GROUP_QUOTA &&
> > -	           type != XFS_PROJ_QUOTA &&
> > -	           type != XFS_USER_QUOTA) {
> > +		   type != XFS_PROJ_QUOTA &&
> > +		   type != XFS_USER_QUOTA) {
> >  		return command_usage(&timer_cmd);
> >  	}
> >  
> > -	set_timer(type, mask, fs_path->fs_name, value);
> > +	if (name)
> > +		id = id_from_string(name, type);
> > +
> > +	if (id >= 0)
> > +		set_timer(id, type, mask, fs_path->fs_name, value);
> > +
> >  	return 0;
> >  }
> >  
> > @@ -616,9 +673,9 @@ edit_init(void)
> >  
> >  	timer_cmd.name = "timer";
> >  	timer_cmd.cfunc = timer_f;
> > -	timer_cmd.argmin = 2;
> > +	timer_cmd.argmin = 1;
> >  	timer_cmd.argmax = -1;
> > -	timer_cmd.args = _("[-bir] [-g|-p|-u] value");
> > +	timer_cmd.args = _("[-bir] [-g|-p|-u] value [-d|id|name]");
> >  	timer_cmd.oneline = _("set quota enforcement timeouts");
> >  	timer_cmd.help = timer_help;
> >  	timer_cmd.flags = CMD_FLAG_FOREIGN_OK;
> > 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 0/4] fstests: more quota related tests
  2020-05-18 19:59 ` [PATCH 0/4] fstests: more quota related tests Eric Sandeen
                     ` (3 preceding siblings ...)
  2020-05-18 20:01   ` [PATCH 4/4] fstests: individual user grace period extension via xfs_quota Eric Sandeen
@ 2020-05-20 15:39   ` Darrick J. Wong
  2020-05-20 15:46     ` Eric Sandeen
  4 siblings, 1 reply; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-20 15:39 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs, fstests

On Mon, May 18, 2020 at 02:59:01PM -0500, Eric Sandeen wrote:
> This collects zorro's outstanding patch to test per-type quota
> timers, as well as one test from darrick to test limit survival
> after quotacheck,  plus 2 more from me to test grace time extension.
> 
> zorro's still needs ENOSPC vs. EDQUOT filtering, darrick's might
> need to be made generic, and mine are new.

Err, I saw the following quota fstests regressions overnight.  Are these
expected?  Note that I didn't patch any of the userspace, nor have I
added any of the tests in this series...

--D

--- RESULTS FOR HOST: doh-mtr00.local
FSTESTS LOG DIR "/var/tmp/fstests":
SECTION      -- -no-sections-
FSTYP        -- xfs
MKFS_OPTIONS --  -m reflink=1,rmapbt=1, -i sparse=1,
MOUNT_OPTIONS --  -o usrquota,grpquota,prjquota,
HOST_OPTIONS -- local.config
CHECK_OPTIONS -- -g auto
XFS_MKFS_OPTIONS -- -bsize=4096
TIME_FACTOR  -- 1
LOAD_FACTOR  -- 1
TEST_DIR     -- /mnt
TEST_DEV     -- /dev/sda
SCRATCH_DEV  -- /dev/sdf
SCRATCH_MNT  -- /opt
OVL_UPPER    -- ovl-upper
OVL_LOWER    -- ovl-lower
OVL_WORK     -- ovl-work
KERNEL       -- 5.7.0-rc4-djw
--- xfs/106.out
+++ xfs/106.out.bad
@@ -151,7 +151,7 @@
 checking restore command (type=u)
 
 checking report command (type=u)
-fsgqa 1024 512 2048 00 [7 days] 15 10 20 00 [7 days]
+fsgqa 1024 512 2048 00 [0 days] 15 10 20 00 [0 days]
 
 
 checking state command (type=u)
@@ -159,9 +159,9 @@
  Accounting: ON
  Enforcement: ON
  Inode: #[INO] (X blocks, Y extents)
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 cleanup files
 ----------------------- gquota,sync ---------------------------
 init quota limit and timer, and dump it
@@ -315,7 +315,7 @@
 checking restore command (type=g)
 
 checking report command (type=g)
-fsgqa 1024 512 2048 00 [7 days] 15 10 20 00 [7 days]
+fsgqa 1024 512 2048 00 [0 days] 15 10 20 00 [0 days]
 
 
 checking state command (type=g)
@@ -323,9 +323,9 @@
  Accounting: ON
  Enforcement: ON
  Inode: #[INO] (X blocks, Y extents)
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 cleanup files
 ----------------------- pquota,sync ---------------------------
 init quota limit and timer, and dump it
@@ -479,7 +479,7 @@
 checking restore command (type=p)
 
 checking report command (type=p)
-fsgqa 1024 512 2048 00 [7 days] 15 10 20 00 [7 days]
+fsgqa 1024 512 2048 00 [0 days] 15 10 20 00 [0 days]
 
 
 checking state command (type=p)
@@ -487,7 +487,7 @@
  Accounting: ON
  Enforcement: ON
  Inode: #[INO] (X blocks, Y extents)
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 cleanup files
--- xfs/299.out
+++ xfs/299.out.bad
@@ -16,19 +16,19 @@
 
 *** push past the soft inode limit
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 0 100 500 00 [--------] 5 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 0 100 500 00 [--------] 5 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the soft block limit
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 200 100 500 00 [7 days] 6 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 200 100 500 00 [7 days] 6 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the hard inode limit (expect EDQUOT)
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 200 100 500 00 [7 days] 9 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 200 100 500 00 [7 days] 9 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the hard block limit (expect EDQUOT)
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] =OK= 100 500 0 [7 days] 9 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] =OK= 100 500 0 [7 days] 9 4 10 00 [0 days] 0 0 0 00 [--------]
 
 
 *** report no quota settings
--- xfs/050.out
+++ xfs/050.out.bad
@@ -16,19 +16,20 @@
 
 *** push past the soft inode limit
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 0 200 1000 00 [--------] 5 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 0 200 1000 00 [--------] 5 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the soft block limit
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 300 200 1000 00 [7 days] 6 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 0 200 1000 00 [--------] 5 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the hard inode limit (expect EDQUOT)
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 300 200 1000 00 [7 days] 10 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 0 200 1000 00 [--------] 5 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the hard block limit (expect EDQUOT)
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] =OK= 200 1000 0 [7 days] 10 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] =OK= 200 1000 0 [--------] 5 4 10 00 [0 days] 0 0 0 00 [--------]
+ URK 65534: 0 is out of range! [3481600,4096000]
 
 *** unmount
 *** group
@@ -48,19 +49,19 @@
 
 *** push past the soft inode limit
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 0 200 1000 00 [--------] 5 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 0 200 1000 00 [--------] 5 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the soft block limit
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 300 200 1000 00 [7 days] 6 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 300 200 1000 00 [7 days] 6 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the hard inode limit (expect EDQUOT)
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 300 200 1000 00 [7 days] 10 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 300 200 1000 00 [7 days] 10 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the hard block limit (expect EDQUOT)
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] =OK= 200 1000 0 [7 days] 10 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] =OK= 200 1000 0 [7 days] 10 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** unmount
 *** uqnoenforce
@@ -144,19 +145,19 @@
 
 *** push past the soft inode limit
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 0 200 1000 00 [--------] 5 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 0 200 1000 00 [--------] 5 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the soft block limit
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 300 200 1000 00 [7 days] 6 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 300 200 1000 00 [7 days] 6 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the hard inode limit (expect EDQUOT)
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] 300 200 1000 00 [7 days] 9 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] 300 200 1000 00 [7 days] 9 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** push past the hard block limit (expect EDQUOT)
 [ROOT] 0 0 0 00 [--------] 3 0 0 00 [--------] 0 0 0 00 [--------]
-[NAME] =OK= 200 1000 0 [7 days] 9 4 10 00 [7 days] 0 0 0 00 [--------]
+[NAME] =OK= 200 1000 0 [7 days] 9 4 10 00 [0 days] 0 0 0 00 [--------]
 
 *** unmount
 *** pqnoenforce
--- generic/594.out
+++ generic/594.out.bad
@@ -5,31 +5,31 @@
 *** Report for group quotas on device SCRATCH_DEV
 Block grace time: DEF_TIME; Inode grace time: DEF_TIME
 *** Report for project quotas on device SCRATCH_DEV
-Block grace time: 00:10; Inode grace time: 00:20
+Block grace time: DEF_TIME; Inode grace time: DEF_TIME
 
 2. set group quota timer
 *** Report for user quotas on device SCRATCH_DEV
 Block grace time: DEF_TIME; Inode grace time: DEF_TIME
 *** Report for group quotas on device SCRATCH_DEV
-Block grace time: 00:30; Inode grace time: 00:40
+Block grace time: DEF_TIME; Inode grace time: DEF_TIME
 *** Report for project quotas on device SCRATCH_DEV
-Block grace time: 00:10; Inode grace time: 00:20
+Block grace time: DEF_TIME; Inode grace time: DEF_TIME
 
 3. set user quota timer
 *** Report for user quotas on device SCRATCH_DEV
 Block grace time: 00:50; Inode grace time: 01:00
 *** Report for group quotas on device SCRATCH_DEV
-Block grace time: 00:30; Inode grace time: 00:40
+Block grace time: 00:50; Inode grace time: 01:00
 *** Report for project quotas on device SCRATCH_DEV
-Block grace time: 00:10; Inode grace time: 00:20
+Block grace time: 00:50; Inode grace time: 01:00
 
 4. cycle mount test-1
 *** Report for user quotas on device SCRATCH_DEV
 Block grace time: 00:50; Inode grace time: 01:00
 *** Report for group quotas on device SCRATCH_DEV
-Block grace time: 00:30; Inode grace time: 00:40
+Block grace time: 00:50; Inode grace time: 01:00
 *** Report for project quotas on device SCRATCH_DEV
-Block grace time: 00:10; Inode grace time: 00:20
+Block grace time: 00:50; Inode grace time: 01:00
 
 5. fsck to force quota check
 
@@ -37,14 +37,14 @@
 *** Report for user quotas on device SCRATCH_DEV
 Block grace time: 00:50; Inode grace time: 01:00
 *** Report for group quotas on device SCRATCH_DEV
-Block grace time: 00:30; Inode grace time: 00:40
+Block grace time: 00:50; Inode grace time: 01:00
 *** Report for project quotas on device SCRATCH_DEV
-Block grace time: 00:10; Inode grace time: 00:20
+Block grace time: 00:50; Inode grace time: 01:00
 
 7. cycle mount test-3
 *** Report for user quotas on device SCRATCH_DEV
 Block grace time: 00:50; Inode grace time: 01:00
 *** Report for group quotas on device SCRATCH_DEV
-Block grace time: 00:30; Inode grace time: 00:40
+Block grace time: 00:50; Inode grace time: 01:00
 *** Report for project quotas on device SCRATCH_DEV
-Block grace time: 00:10; Inode grace time: 00:20
+Block grace time: 00:50; Inode grace time: 01:00
--- generic/235.out
+++ generic/235.out.bad
@@ -1,25 +1,25 @@
 QA output created by 235
 *** Report for user quotas on device SCRATCH_DEV
-Block grace time: 7days; Inode grace time: 7days
+Block grace time: 00:00; Inode grace time: 00:00
                         Block limits                File limits
 User            used    soft    hard  grace    used  soft  hard  grace
 ----------------------------------------------------------------------
 fsgqa     --       0       0       0              1     0     0       
 *** Report for group quotas on device SCRATCH_DEV
-Block grace time: 7days; Inode grace time: 7days
+Block grace time: 00:00; Inode grace time: 00:00
                         Block limits                File limits
 Group           used    soft    hard  grace    used  soft  hard  grace
 ----------------------------------------------------------------------
 fsgqa     --       0       0       0              1     0     0       
 touch: cannot touch 'SCRATCH_MNT/failed': Read-only file system
 *** Report for user quotas on device SCRATCH_DEV
-Block grace time: 7days; Inode grace time: 7days
+Block grace time: 00:00; Inode grace time: 00:00
                         Block limits                File limits
 User            used    soft    hard  grace    used  soft  hard  grace
 ----------------------------------------------------------------------
 fsgqa     --       0       0       0              2     0     0       
 *** Report for group quotas on device SCRATCH_DEV
-Block grace time: 7days; Inode grace time: 7days
+Block grace time: 00:00; Inode grace time: 00:00
                         Block limits                File limits
 Group           used    soft    hard  grace    used  soft  hard  grace
 ----------------------------------------------------------------------
--- xfs/263.out
+++ xfs/263.out.bad
@@ -14,9 +14,9 @@
   Accounting: OFF
   Enforcement: OFF
   Inode: N/A
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 == Options: grpquota,rw ==
 User quota state on SCRATCH_MNT (SCRATCH_DEV)
   Accounting: OFF
@@ -30,9 +30,9 @@
   Accounting: OFF
   Enforcement: OFF
   Inode: N/A
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 == Options: usrquota,grpquota,rw ==
 User quota state on SCRATCH_MNT (SCRATCH_DEV)
   Accounting: ON
@@ -62,9 +62,9 @@
   Accounting: ON
   Enforcement: ON
   Inode #XXX (1 blocks, 1 extents)
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 == Options: usrquota,prjquota,rw ==
 User quota state on SCRATCH_MNT (SCRATCH_DEV)
   Accounting: ON
@@ -98,9 +98,9 @@
   Accounting: OFF
   Enforcement: OFF
   Inode: N/A
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 == Options: grpquota,rw ==
 User quota state on SCRATCH_MNT (SCRATCH_DEV)
   Accounting: OFF
@@ -114,9 +114,9 @@
   Accounting: OFF
   Enforcement: OFF
   Inode: N/A
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 == Options: usrquota,grpquota,rw ==
 User quota state on SCRATCH_MNT (SCRATCH_DEV)
   Accounting: ON
@@ -146,9 +146,9 @@
   Accounting: ON
   Enforcement: ON
   Inode #XXX (1 blocks, 1 extents)
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 == Options: usrquota,prjquota,rw ==
 User quota state on SCRATCH_MNT (SCRATCH_DEV)
   Accounting: ON
@@ -178,9 +178,9 @@
   Accounting: ON
   Enforcement: ON
   Inode #XXX (1 blocks, 1 extents)
-Blocks grace time: [7 days]
-Inodes grace time: [7 days]
-Realtime Blocks grace time: [7 days]
+Blocks grace time: [--------]
+Inodes grace time: [--------]
+Realtime Blocks grace time: [--------]
 == Options: usrquota,grpquota,prjquota,rw ==
 User quota state on SCRATCH_MNT (SCRATCH_DEV)
   Accounting: ON

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 0/4] fstests: more quota related tests
  2020-05-20 15:39   ` [PATCH 0/4] fstests: more quota related tests Darrick J. Wong
@ 2020-05-20 15:46     ` Eric Sandeen
  0 siblings, 0 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-20 15:46 UTC (permalink / raw)
  To: Darrick J. Wong, Eric Sandeen; +Cc: linux-xfs, fstests

On 5/20/20 10:39 AM, Darrick J. Wong wrote:
> On Mon, May 18, 2020 at 02:59:01PM -0500, Eric Sandeen wrote:
>> This collects zorro's outstanding patch to test per-type quota
>> timers, as well as one test from darrick to test limit survival
>> after quotacheck,  plus 2 more from me to test grace time extension.
>>
>> zorro's still needs ENOSPC vs. EDQUOT filtering, darrick's might
>> need to be made generic, and mine are new.
> 
> Err, I saw the following quota fstests regressions overnight.  Are these
> expected?  Note that I didn't patch any of the userspace, nor have I
> added any of the tests in this series...

hrmph, let me dig into this.  I'm not actually sure.
sorry,
-Eric

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH 4.5/6] xfs: switch xfs_get_defquota to take explicit type
  2020-05-18 18:51   ` [PATCH 5/6] xfs: per-type quota timers and warn limits Eric Sandeen
  2020-05-19 16:27     ` Darrick J. Wong
@ 2020-05-20 18:41     ` Eric Sandeen
  2020-05-20 20:36       ` Darrick J. Wong
  2020-05-20 18:43     ` [PATCH 5/6 V2] xfs: per-type quota timers and warn limits Eric Sandeen
  2 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-20 18:41 UTC (permalink / raw)
  To: linux-xfs

xfs_get_defquota() currently takes an xfs_dquot, and from that obtains
the type of default quota we should get (user/group/project).

But early in init, we don't have access to a fully set up quota, and
so we will fail to set these defaults.

Switch xfs_get_defquota to take an explicit type, and add a helper 
function to obtain that type from an xfs_dquot for the existing
callers.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 6d6afc0297b3..fdeaccc67d91 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -75,7 +75,7 @@ xfs_qm_adjust_dqlimits(
 	int			prealloc = 0;
 
 	ASSERT(d->d_id);
-	defq = xfs_get_defquota(dq, q);
+	defq = xfs_get_defquota(q, xfs_dquot_type(dq));
 
 	if (defq->bsoftlimit && !d->d_blk_softlimit) {
 		d->d_blk_softlimit = cpu_to_be64(defq->bsoftlimit);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index e97a3802939c..64ba943e0675 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -558,7 +558,7 @@ xfs_qm_set_defquota(
 		return;
 
 	ddqp = &dqp->q_core;
-	defq = xfs_get_defquota(dqp, qinf);
+	defq = xfs_get_defquota(qinf, xfs_dquot_type(dqp));
 
 	/*
 	 * Timers and warnings have been already set, let's just set the
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 3a850401b102..06df406fdf72 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -113,6 +113,19 @@ xfs_quota_inode(xfs_mount_t *mp, uint dq_flags)
 	return NULL;
 }
 
+static inline int
+xfs_dquot_type(struct xfs_dquot *dqp)
+{
+	if (XFS_QM_ISUDQ(dqp))
+		return XFS_DQ_USER;
+	else if (XFS_QM_ISGDQ(dqp))
+		return XFS_DQ_GROUP;
+	else {
+		ASSERT(XFS_QM_ISPDQ(dqp));
+		return XFS_DQ_PROJ;
+	}
+}
+
 extern void	xfs_trans_mod_dquot(struct xfs_trans *tp, struct xfs_dquot *dqp,
 				    uint field, int64_t delta);
 extern void	xfs_trans_dqjoin(struct xfs_trans *, struct xfs_dquot *);
@@ -164,17 +177,22 @@ extern int		xfs_qm_scall_quotaon(struct xfs_mount *, uint);
 extern int		xfs_qm_scall_quotaoff(struct xfs_mount *, uint);
 
 static inline struct xfs_def_quota *
-xfs_get_defquota(struct xfs_dquot *dqp, struct xfs_quotainfo *qi)
+xfs_get_defquota(struct xfs_quotainfo *qi, int type)
 {
 	struct xfs_def_quota *defq;
 
-	if (XFS_QM_ISUDQ(dqp))
+	switch (type) {
+	case XFS_DQ_USER:
 		defq = &qi->qi_usr_default;
-	else if (XFS_QM_ISGDQ(dqp))
+		break;
+	case XFS_DQ_GROUP:
 		defq = &qi->qi_grp_default;
-	else {
-		ASSERT(XFS_QM_ISPDQ(dqp));
+		break;
+	case XFS_DQ_PROJ:
 		defq = &qi->qi_prj_default;
+		break;
+	default:
+		ASSERT(0);
 	}
 	return defq;
 }
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 301a284ee4f9..13196d07c84e 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -479,7 +479,7 @@ xfs_qm_scall_setqlim(
 		goto out_unlock;
 	}
 
-	defq = xfs_get_defquota(dqp, q);
+	defq = xfs_get_defquota(q, xfs_dquot_type(dqp));
 	xfs_dqunlock(dqp);
 
 	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_setqlim, 0, 0, 0, &tp);
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 20542076e32a..edde366ca8e9 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -591,7 +591,7 @@ xfs_trans_dqresv(
 
 	xfs_dqlock(dqp);
 
-	defq = xfs_get_defquota(dqp, q);
+	defq = xfs_get_defquota(q, xfs_dquot_type(dqp));
 
 	if (flags & XFS_TRANS_DQ_RES_BLKS) {
 		hardlimit = be64_to_cpu(dqp->q_core.d_blk_hardlimit);


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 5/6 V2] xfs: per-type quota timers and warn limits
  2020-05-18 18:51   ` [PATCH 5/6] xfs: per-type quota timers and warn limits Eric Sandeen
  2020-05-19 16:27     ` Darrick J. Wong
  2020-05-20 18:41     ` [PATCH 4.5/6] xfs: switch xfs_get_defquota to take explicit type Eric Sandeen
@ 2020-05-20 18:43     ` Eric Sandeen
  2020-05-20 20:31       ` Darrick J. Wong
  2 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-20 18:43 UTC (permalink / raw)
  To: linux-xfs

From: Eric Sandeen <sandeen@redhat.com>

Move timers and warnings out of xfs_quotainfo and into xfs_def_quota
so that we can utilize them on a per-type basis, rather than enforcing
them based on the values found in the first enabled quota type.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
[zlang: new way to get defquota in xfs_qm_init_timelimits]
[zlang: remove redundant defq assign]
Signed-off-by: Zorro Lang <zlang@redhat.com>
---

V2: Use the by-type defquota-getter

diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index fdeaccc67d91..49c235c5d42c 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -116,8 +116,12 @@ xfs_qm_adjust_dqtimers(
 	struct xfs_mount	*mp,
 	struct xfs_dquot	*dq)
 {
+	struct xfs_quotainfo	*qi = mp->m_quotainfo;
 	struct xfs_disk_dquot	*d = &dq->q_core;
+	struct xfs_def_quota	*defq;
+
 	ASSERT(d->d_id);
+	*defq = xfs_get_defquota(qi, xfs_dquot_type(dq));
 
 #ifdef DEBUG
 	if (d->d_blk_hardlimit)
@@ -139,7 +143,7 @@ xfs_qm_adjust_dqtimers(
 		     (be64_to_cpu(d->d_bcount) >
 		      be64_to_cpu(d->d_blk_hardlimit)))) {
 			d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
-					mp->m_quotainfo->qi_btimelimit);
+					defq->btimelimit);
 		} else {
 			d->d_bwarns = 0;
 		}
@@ -162,7 +166,7 @@ xfs_qm_adjust_dqtimers(
 		     (be64_to_cpu(d->d_icount) >
 		      be64_to_cpu(d->d_ino_hardlimit)))) {
 			d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
-					mp->m_quotainfo->qi_itimelimit);
+					defq->itimelimit);
 		} else {
 			d->d_iwarns = 0;
 		}
@@ -185,7 +189,7 @@ xfs_qm_adjust_dqtimers(
 		     (be64_to_cpu(d->d_rtbcount) >
 		      be64_to_cpu(d->d_rtb_hardlimit)))) {
 			d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
-					mp->m_quotainfo->qi_rtbtimelimit);
+					defq->rtbtimelimit);
 		} else {
 			d->d_rtbwarns = 0;
 		}
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 64ba943e0675..dd38c73ce36e 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -577,19 +577,22 @@ xfs_qm_set_defquota(
 static void
 xfs_qm_init_timelimits(
 	struct xfs_mount	*mp,
-	struct xfs_quotainfo	*qinf)
+	uint			type)
 {
+	struct xfs_quotainfo	*qinf = mp->m_quotainfo;
+	struct xfs_def_quota	*defq;
 	struct xfs_disk_dquot	*ddqp;
 	struct xfs_dquot	*dqp;
-	uint			type;
 	int			error;
 
-	qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
-	qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
-	qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
-	qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
-	qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
-	qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
+	defq = xfs_get_defquota(qinf, type);
+
+	defq->btimelimit = XFS_QM_BTIMELIMIT;
+	defq->itimelimit = XFS_QM_ITIMELIMIT;
+	defq->rtbtimelimit = XFS_QM_RTBTIMELIMIT;
+	defq->bwarnlimit = XFS_QM_BWARNLIMIT;
+	defq->iwarnlimit = XFS_QM_IWARNLIMIT;
+	defq->rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
 
 	/*
 	 * We try to get the limits from the superuser's limits fields.
@@ -597,39 +600,30 @@ xfs_qm_init_timelimits(
 	 *
 	 * Since we may not have done a quotacheck by this point, just read
 	 * the dquot without attaching it to any hashtables or lists.
-	 *
-	 * Timers and warnings are globally set by the first timer found in
-	 * user/group/proj quota types, otherwise a default value is used.
-	 * This should be split into different fields per quota type.
 	 */
-	if (XFS_IS_UQUOTA_RUNNING(mp))
-		type = XFS_DQ_USER;
-	else if (XFS_IS_GQUOTA_RUNNING(mp))
-		type = XFS_DQ_GROUP;
-	else
-		type = XFS_DQ_PROJ;
 	error = xfs_qm_dqget_uncached(mp, 0, type, &dqp);
 	if (error)
 		return;
 
 	ddqp = &dqp->q_core;
+
 	/*
 	 * The warnings and timers set the grace period given to
 	 * a user or group before he or she can not perform any
 	 * more writing. If it is zero, a default is used.
 	 */
 	if (ddqp->d_btimer)
-		qinf->qi_btimelimit = be32_to_cpu(ddqp->d_btimer);
+		defq->btimelimit = be32_to_cpu(ddqp->d_btimer);
 	if (ddqp->d_itimer)
-		qinf->qi_itimelimit = be32_to_cpu(ddqp->d_itimer);
+		defq->itimelimit = be32_to_cpu(ddqp->d_itimer);
 	if (ddqp->d_rtbtimer)
-		qinf->qi_rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer);
+		defq->rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer);
 	if (ddqp->d_bwarns)
-		qinf->qi_bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
+		defq->bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
 	if (ddqp->d_iwarns)
-		qinf->qi_iwarnlimit = be16_to_cpu(ddqp->d_iwarns);
+		defq->iwarnlimit = be16_to_cpu(ddqp->d_iwarns);
 	if (ddqp->d_rtbwarns)
-		qinf->qi_rtbwarnlimit = be16_to_cpu(ddqp->d_rtbwarns);
+		defq->rtbwarnlimit = be16_to_cpu(ddqp->d_rtbwarns);
 
 	xfs_qm_dqdestroy(dqp);
 }
@@ -675,7 +669,9 @@ xfs_qm_init_quotainfo(
 
 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
-	xfs_qm_init_timelimits(mp, qinf);
+	xfs_qm_init_timelimits(mp, XFS_DQ_USER);
+	xfs_qm_init_timelimits(mp, XFS_DQ_GROUP);
+	xfs_qm_init_timelimits(mp, XFS_DQ_PROJ);
 
 	if (XFS_IS_UQUOTA_RUNNING(mp))
 		xfs_qm_set_defquota(mp, XFS_DQ_USER, qinf);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 06df406fdf72..c2d141715e91 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -41,7 +41,14 @@ extern struct kmem_zone	*xfs_qm_dqtrxzone;
  */
 #define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
 
+/* Defaults for each quota type: time limits, warn limits, usage limits */
 struct xfs_def_quota {
+	time64_t	btimelimit;	/* limit for blks timer */
+	time64_t	itimelimit;	/* limit for inodes timer */
+	time64_t	rtbtimelimit;	/* limit for rt blks timer */
+	xfs_qwarncnt_t	bwarnlimit;	/* limit for blks warnings */
+	xfs_qwarncnt_t	iwarnlimit;	/* limit for inodes warnings */
+	xfs_qwarncnt_t	rtbwarnlimit;	/* limit for rt blks warnings */
 	xfs_qcnt_t	bhardlimit;	/* default data blk hard limit */
 	xfs_qcnt_t	bsoftlimit;	/* default data blk soft limit */
 	xfs_qcnt_t	ihardlimit;	/* default inode count hard limit */
@@ -64,12 +71,6 @@ struct xfs_quotainfo {
 	struct xfs_inode	*qi_pquotaip;	/* project quota inode */
 	struct list_lru		qi_lru;
 	int			qi_dquots;
-	time64_t		qi_btimelimit;	/* limit for blks timer */
-	time64_t		qi_itimelimit;	/* limit for inodes timer */
-	time64_t		qi_rtbtimelimit;/* limit for rt blks timer */
-	xfs_qwarncnt_t		qi_bwarnlimit;	/* limit for blks warnings */
-	xfs_qwarncnt_t		qi_iwarnlimit;	/* limit for inodes warnings */
-	xfs_qwarncnt_t		qi_rtbwarnlimit;/* limit for rt blks warnings */
 	struct mutex		qi_quotaofflock;/* to serialize quotaoff */
 	xfs_filblks_t		qi_dqchunklen;	/* # BBs in a chunk of dqs */
 	uint			qi_dqperchunk;	/* # ondisk dq in above chunk */
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 13196d07c84e..4dbcc27eba23 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -563,23 +563,23 @@ xfs_qm_scall_setqlim(
 		 * for warnings.
 		 */
 		if (newlim->d_fieldmask & QC_SPC_TIMER) {
-			q->qi_btimelimit = newlim->d_spc_timer;
+			defq->btimelimit = newlim->d_spc_timer;
 			ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
 		}
 		if (newlim->d_fieldmask & QC_INO_TIMER) {
-			q->qi_itimelimit = newlim->d_ino_timer;
+			defq->itimelimit = newlim->d_ino_timer;
 			ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
 		}
 		if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
-			q->qi_rtbtimelimit = newlim->d_rt_spc_timer;
+			defq->rtbtimelimit = newlim->d_rt_spc_timer;
 			ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
 		}
 		if (newlim->d_fieldmask & QC_SPC_WARNS)
-			q->qi_bwarnlimit = newlim->d_spc_warns;
+			defq->bwarnlimit = newlim->d_spc_warns;
 		if (newlim->d_fieldmask & QC_INO_WARNS)
-			q->qi_iwarnlimit = newlim->d_ino_warns;
+			defq->iwarnlimit = newlim->d_ino_warns;
 		if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
-			q->qi_rtbwarnlimit = newlim->d_rt_spc_warns;
+			defq->rtbwarnlimit = newlim->d_rt_spc_warns;
 	} else {
 		/*
 		 * If the user is now over quota, start the timelimit.
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index cb16a91dd1d4..51be282d28b3 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -21,9 +21,9 @@ xfs_qm_fill_state(
 	struct qc_type_state	*tstate,
 	struct xfs_mount	*mp,
 	struct xfs_inode	*ip,
-	xfs_ino_t		ino)
+	xfs_ino_t		ino,
+	struct xfs_def_quota	*defq)
 {
-	struct xfs_quotainfo	*q = mp->m_quotainfo;
 	bool			tempqip = false;
 
 	tstate->ino = ino;
@@ -37,12 +37,12 @@ xfs_qm_fill_state(
 	tstate->flags |= QCI_SYSFILE;
 	tstate->blocks = ip->i_d.di_nblocks;
 	tstate->nextents = ip->i_d.di_nextents;
-	tstate->spc_timelimit = (u32)q->qi_btimelimit;
-	tstate->ino_timelimit = (u32)q->qi_itimelimit;
-	tstate->rt_spc_timelimit = (u32)q->qi_rtbtimelimit;
-	tstate->spc_warnlimit = q->qi_bwarnlimit;
-	tstate->ino_warnlimit = q->qi_iwarnlimit;
-	tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
+	tstate->spc_timelimit = (u32)defq->btimelimit;
+	tstate->ino_timelimit = (u32)defq->itimelimit;
+	tstate->rt_spc_timelimit = (u32)defq->rtbtimelimit;
+	tstate->spc_warnlimit = defq->bwarnlimit;
+	tstate->ino_warnlimit = defq->iwarnlimit;
+	tstate->rt_spc_warnlimit = defq->rtbwarnlimit;
 	if (tempqip)
 		xfs_irele(ip);
 }
@@ -77,11 +77,11 @@ xfs_fs_get_quota_state(
 		state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED;
 
 	xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip,
-			  mp->m_sb.sb_uquotino);
+			  mp->m_sb.sb_uquotino, &q->qi_usr_default);
 	xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip,
-			  mp->m_sb.sb_gquotino);
+			  mp->m_sb.sb_gquotino, &q->qi_grp_default);
 	xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip,
-			  mp->m_sb.sb_pquotino);
+			  mp->m_sb.sb_pquotino, &q->qi_prj_default);
 	return 0;
 }
 
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index edde366ca8e9..c0f73b82c055 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -602,7 +602,7 @@ xfs_trans_dqresv(
 			softlimit = defq->bsoftlimit;
 		timer = be32_to_cpu(dqp->q_core.d_btimer);
 		warns = be16_to_cpu(dqp->q_core.d_bwarns);
-		warnlimit = dqp->q_mount->m_quotainfo->qi_bwarnlimit;
+		warnlimit = defq->bwarnlimit;
 		resbcountp = &dqp->q_res_bcount;
 	} else {
 		ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
@@ -614,7 +614,7 @@ xfs_trans_dqresv(
 			softlimit = defq->rtbsoftlimit;
 		timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
 		warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
-		warnlimit = dqp->q_mount->m_quotainfo->qi_rtbwarnlimit;
+		warnlimit = defq->rtbwarnlimit;
 		resbcountp = &dqp->q_res_rtbcount;
 	}
 
@@ -650,7 +650,7 @@ xfs_trans_dqresv(
 			total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos;
 			timer = be32_to_cpu(dqp->q_core.d_itimer);
 			warns = be16_to_cpu(dqp->q_core.d_iwarns);
-			warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;
+			warnlimit = defq->iwarnlimit;
 			hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
 			if (!hardlimit)
 				hardlimit = defq->ihardlimit;



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH 5/6 V2] xfs: per-type quota timers and warn limits
  2020-05-20 18:43     ` [PATCH 5/6 V2] xfs: per-type quota timers and warn limits Eric Sandeen
@ 2020-05-20 20:31       ` Darrick J. Wong
  2020-05-20 20:42         ` Eric Sandeen
  0 siblings, 1 reply; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-20 20:31 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Wed, May 20, 2020 at 01:43:15PM -0500, Eric Sandeen wrote:
> From: Eric Sandeen <sandeen@redhat.com>
> 
> Move timers and warnings out of xfs_quotainfo and into xfs_def_quota
> so that we can utilize them on a per-type basis, rather than enforcing
> them based on the values found in the first enabled quota type.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> Reviewed-by: Allison Collins <allison.henderson@oracle.com>

There's been kind of a lot of changes to keep Allison's RVB, especially
since you didn't add mine...

(...says the king of forgetting to apply RVBs :P)

> [zlang: new way to get defquota in xfs_qm_init_timelimits]
> [zlang: remove redundant defq assign]
> Signed-off-by: Zorro Lang <zlang@redhat.com>
> ---
> 
> V2: Use the by-type defquota-getter
> 
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index fdeaccc67d91..49c235c5d42c 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -116,8 +116,12 @@ xfs_qm_adjust_dqtimers(
>  	struct xfs_mount	*mp,
>  	struct xfs_dquot	*dq)
>  {
> +	struct xfs_quotainfo	*qi = mp->m_quotainfo;
>  	struct xfs_disk_dquot	*d = &dq->q_core;
> +	struct xfs_def_quota	*defq;
> +
>  	ASSERT(d->d_id);
> +	*defq = xfs_get_defquota(qi, xfs_dquot_type(dq));

This isn't supposed to be a structure copy, right?

--D

>  
>  #ifdef DEBUG
>  	if (d->d_blk_hardlimit)
> @@ -139,7 +143,7 @@ xfs_qm_adjust_dqtimers(
>  		     (be64_to_cpu(d->d_bcount) >
>  		      be64_to_cpu(d->d_blk_hardlimit)))) {
>  			d->d_btimer = cpu_to_be32(ktime_get_real_seconds() +
> -					mp->m_quotainfo->qi_btimelimit);
> +					defq->btimelimit);
>  		} else {
>  			d->d_bwarns = 0;
>  		}
> @@ -162,7 +166,7 @@ xfs_qm_adjust_dqtimers(
>  		     (be64_to_cpu(d->d_icount) >
>  		      be64_to_cpu(d->d_ino_hardlimit)))) {
>  			d->d_itimer = cpu_to_be32(ktime_get_real_seconds() +
> -					mp->m_quotainfo->qi_itimelimit);
> +					defq->itimelimit);
>  		} else {
>  			d->d_iwarns = 0;
>  		}
> @@ -185,7 +189,7 @@ xfs_qm_adjust_dqtimers(
>  		     (be64_to_cpu(d->d_rtbcount) >
>  		      be64_to_cpu(d->d_rtb_hardlimit)))) {
>  			d->d_rtbtimer = cpu_to_be32(ktime_get_real_seconds() +
> -					mp->m_quotainfo->qi_rtbtimelimit);
> +					defq->rtbtimelimit);
>  		} else {
>  			d->d_rtbwarns = 0;
>  		}
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index 64ba943e0675..dd38c73ce36e 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -577,19 +577,22 @@ xfs_qm_set_defquota(
>  static void
>  xfs_qm_init_timelimits(
>  	struct xfs_mount	*mp,
> -	struct xfs_quotainfo	*qinf)
> +	uint			type)
>  {
> +	struct xfs_quotainfo	*qinf = mp->m_quotainfo;
> +	struct xfs_def_quota	*defq;
>  	struct xfs_disk_dquot	*ddqp;
>  	struct xfs_dquot	*dqp;
> -	uint			type;
>  	int			error;
>  
> -	qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
> -	qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
> -	qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
> -	qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
> -	qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
> -	qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
> +	defq = xfs_get_defquota(qinf, type);
> +
> +	defq->btimelimit = XFS_QM_BTIMELIMIT;
> +	defq->itimelimit = XFS_QM_ITIMELIMIT;
> +	defq->rtbtimelimit = XFS_QM_RTBTIMELIMIT;
> +	defq->bwarnlimit = XFS_QM_BWARNLIMIT;
> +	defq->iwarnlimit = XFS_QM_IWARNLIMIT;
> +	defq->rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
>  
>  	/*
>  	 * We try to get the limits from the superuser's limits fields.
> @@ -597,39 +600,30 @@ xfs_qm_init_timelimits(
>  	 *
>  	 * Since we may not have done a quotacheck by this point, just read
>  	 * the dquot without attaching it to any hashtables or lists.
> -	 *
> -	 * Timers and warnings are globally set by the first timer found in
> -	 * user/group/proj quota types, otherwise a default value is used.
> -	 * This should be split into different fields per quota type.
>  	 */
> -	if (XFS_IS_UQUOTA_RUNNING(mp))
> -		type = XFS_DQ_USER;
> -	else if (XFS_IS_GQUOTA_RUNNING(mp))
> -		type = XFS_DQ_GROUP;
> -	else
> -		type = XFS_DQ_PROJ;
>  	error = xfs_qm_dqget_uncached(mp, 0, type, &dqp);
>  	if (error)
>  		return;
>  
>  	ddqp = &dqp->q_core;
> +
>  	/*
>  	 * The warnings and timers set the grace period given to
>  	 * a user or group before he or she can not perform any
>  	 * more writing. If it is zero, a default is used.
>  	 */
>  	if (ddqp->d_btimer)
> -		qinf->qi_btimelimit = be32_to_cpu(ddqp->d_btimer);
> +		defq->btimelimit = be32_to_cpu(ddqp->d_btimer);
>  	if (ddqp->d_itimer)
> -		qinf->qi_itimelimit = be32_to_cpu(ddqp->d_itimer);
> +		defq->itimelimit = be32_to_cpu(ddqp->d_itimer);
>  	if (ddqp->d_rtbtimer)
> -		qinf->qi_rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer);
> +		defq->rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer);
>  	if (ddqp->d_bwarns)
> -		qinf->qi_bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
> +		defq->bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
>  	if (ddqp->d_iwarns)
> -		qinf->qi_iwarnlimit = be16_to_cpu(ddqp->d_iwarns);
> +		defq->iwarnlimit = be16_to_cpu(ddqp->d_iwarns);
>  	if (ddqp->d_rtbwarns)
> -		qinf->qi_rtbwarnlimit = be16_to_cpu(ddqp->d_rtbwarns);
> +		defq->rtbwarnlimit = be16_to_cpu(ddqp->d_rtbwarns);
>  
>  	xfs_qm_dqdestroy(dqp);
>  }
> @@ -675,7 +669,9 @@ xfs_qm_init_quotainfo(
>  
>  	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
>  
> -	xfs_qm_init_timelimits(mp, qinf);
> +	xfs_qm_init_timelimits(mp, XFS_DQ_USER);
> +	xfs_qm_init_timelimits(mp, XFS_DQ_GROUP);
> +	xfs_qm_init_timelimits(mp, XFS_DQ_PROJ);
>  
>  	if (XFS_IS_UQUOTA_RUNNING(mp))
>  		xfs_qm_set_defquota(mp, XFS_DQ_USER, qinf);
> diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
> index 06df406fdf72..c2d141715e91 100644
> --- a/fs/xfs/xfs_qm.h
> +++ b/fs/xfs/xfs_qm.h
> @@ -41,7 +41,14 @@ extern struct kmem_zone	*xfs_qm_dqtrxzone;
>   */
>  #define XFS_DQUOT_CLUSTER_SIZE_FSB	(xfs_filblks_t)1
>  
> +/* Defaults for each quota type: time limits, warn limits, usage limits */
>  struct xfs_def_quota {
> +	time64_t	btimelimit;	/* limit for blks timer */
> +	time64_t	itimelimit;	/* limit for inodes timer */
> +	time64_t	rtbtimelimit;	/* limit for rt blks timer */
> +	xfs_qwarncnt_t	bwarnlimit;	/* limit for blks warnings */
> +	xfs_qwarncnt_t	iwarnlimit;	/* limit for inodes warnings */
> +	xfs_qwarncnt_t	rtbwarnlimit;	/* limit for rt blks warnings */
>  	xfs_qcnt_t	bhardlimit;	/* default data blk hard limit */
>  	xfs_qcnt_t	bsoftlimit;	/* default data blk soft limit */
>  	xfs_qcnt_t	ihardlimit;	/* default inode count hard limit */
> @@ -64,12 +71,6 @@ struct xfs_quotainfo {
>  	struct xfs_inode	*qi_pquotaip;	/* project quota inode */
>  	struct list_lru		qi_lru;
>  	int			qi_dquots;
> -	time64_t		qi_btimelimit;	/* limit for blks timer */
> -	time64_t		qi_itimelimit;	/* limit for inodes timer */
> -	time64_t		qi_rtbtimelimit;/* limit for rt blks timer */
> -	xfs_qwarncnt_t		qi_bwarnlimit;	/* limit for blks warnings */
> -	xfs_qwarncnt_t		qi_iwarnlimit;	/* limit for inodes warnings */
> -	xfs_qwarncnt_t		qi_rtbwarnlimit;/* limit for rt blks warnings */
>  	struct mutex		qi_quotaofflock;/* to serialize quotaoff */
>  	xfs_filblks_t		qi_dqchunklen;	/* # BBs in a chunk of dqs */
>  	uint			qi_dqperchunk;	/* # ondisk dq in above chunk */
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 13196d07c84e..4dbcc27eba23 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -563,23 +563,23 @@ xfs_qm_scall_setqlim(
>  		 * for warnings.
>  		 */
>  		if (newlim->d_fieldmask & QC_SPC_TIMER) {
> -			q->qi_btimelimit = newlim->d_spc_timer;
> +			defq->btimelimit = newlim->d_spc_timer;
>  			ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
>  		}
>  		if (newlim->d_fieldmask & QC_INO_TIMER) {
> -			q->qi_itimelimit = newlim->d_ino_timer;
> +			defq->itimelimit = newlim->d_ino_timer;
>  			ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
>  		}
>  		if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
> -			q->qi_rtbtimelimit = newlim->d_rt_spc_timer;
> +			defq->rtbtimelimit = newlim->d_rt_spc_timer;
>  			ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
>  		}
>  		if (newlim->d_fieldmask & QC_SPC_WARNS)
> -			q->qi_bwarnlimit = newlim->d_spc_warns;
> +			defq->bwarnlimit = newlim->d_spc_warns;
>  		if (newlim->d_fieldmask & QC_INO_WARNS)
> -			q->qi_iwarnlimit = newlim->d_ino_warns;
> +			defq->iwarnlimit = newlim->d_ino_warns;
>  		if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
> -			q->qi_rtbwarnlimit = newlim->d_rt_spc_warns;
> +			defq->rtbwarnlimit = newlim->d_rt_spc_warns;
>  	} else {
>  		/*
>  		 * If the user is now over quota, start the timelimit.
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index cb16a91dd1d4..51be282d28b3 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -21,9 +21,9 @@ xfs_qm_fill_state(
>  	struct qc_type_state	*tstate,
>  	struct xfs_mount	*mp,
>  	struct xfs_inode	*ip,
> -	xfs_ino_t		ino)
> +	xfs_ino_t		ino,
> +	struct xfs_def_quota	*defq)
>  {
> -	struct xfs_quotainfo	*q = mp->m_quotainfo;
>  	bool			tempqip = false;
>  
>  	tstate->ino = ino;
> @@ -37,12 +37,12 @@ xfs_qm_fill_state(
>  	tstate->flags |= QCI_SYSFILE;
>  	tstate->blocks = ip->i_d.di_nblocks;
>  	tstate->nextents = ip->i_d.di_nextents;
> -	tstate->spc_timelimit = (u32)q->qi_btimelimit;
> -	tstate->ino_timelimit = (u32)q->qi_itimelimit;
> -	tstate->rt_spc_timelimit = (u32)q->qi_rtbtimelimit;
> -	tstate->spc_warnlimit = q->qi_bwarnlimit;
> -	tstate->ino_warnlimit = q->qi_iwarnlimit;
> -	tstate->rt_spc_warnlimit = q->qi_rtbwarnlimit;
> +	tstate->spc_timelimit = (u32)defq->btimelimit;
> +	tstate->ino_timelimit = (u32)defq->itimelimit;
> +	tstate->rt_spc_timelimit = (u32)defq->rtbtimelimit;
> +	tstate->spc_warnlimit = defq->bwarnlimit;
> +	tstate->ino_warnlimit = defq->iwarnlimit;
> +	tstate->rt_spc_warnlimit = defq->rtbwarnlimit;
>  	if (tempqip)
>  		xfs_irele(ip);
>  }
> @@ -77,11 +77,11 @@ xfs_fs_get_quota_state(
>  		state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED;
>  
>  	xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip,
> -			  mp->m_sb.sb_uquotino);
> +			  mp->m_sb.sb_uquotino, &q->qi_usr_default);
>  	xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip,
> -			  mp->m_sb.sb_gquotino);
> +			  mp->m_sb.sb_gquotino, &q->qi_grp_default);
>  	xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip,
> -			  mp->m_sb.sb_pquotino);
> +			  mp->m_sb.sb_pquotino, &q->qi_prj_default);
>  	return 0;
>  }
>  
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index edde366ca8e9..c0f73b82c055 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -602,7 +602,7 @@ xfs_trans_dqresv(
>  			softlimit = defq->bsoftlimit;
>  		timer = be32_to_cpu(dqp->q_core.d_btimer);
>  		warns = be16_to_cpu(dqp->q_core.d_bwarns);
> -		warnlimit = dqp->q_mount->m_quotainfo->qi_bwarnlimit;
> +		warnlimit = defq->bwarnlimit;
>  		resbcountp = &dqp->q_res_bcount;
>  	} else {
>  		ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS);
> @@ -614,7 +614,7 @@ xfs_trans_dqresv(
>  			softlimit = defq->rtbsoftlimit;
>  		timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
>  		warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
> -		warnlimit = dqp->q_mount->m_quotainfo->qi_rtbwarnlimit;
> +		warnlimit = defq->rtbwarnlimit;
>  		resbcountp = &dqp->q_res_rtbcount;
>  	}
>  
> @@ -650,7 +650,7 @@ xfs_trans_dqresv(
>  			total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos;
>  			timer = be32_to_cpu(dqp->q_core.d_itimer);
>  			warns = be16_to_cpu(dqp->q_core.d_iwarns);
> -			warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;
> +			warnlimit = defq->iwarnlimit;
>  			hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
>  			if (!hardlimit)
>  				hardlimit = defq->ihardlimit;
> 
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 4.5/6] xfs: switch xfs_get_defquota to take explicit type
  2020-05-20 18:41     ` [PATCH 4.5/6] xfs: switch xfs_get_defquota to take explicit type Eric Sandeen
@ 2020-05-20 20:36       ` Darrick J. Wong
  2020-05-20 20:41         ` Eric Sandeen
  0 siblings, 1 reply; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-20 20:36 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Wed, May 20, 2020 at 01:41:25PM -0500, Eric Sandeen wrote:
> xfs_get_defquota() currently takes an xfs_dquot, and from that obtains
> the type of default quota we should get (user/group/project).
> 
> But early in init, we don't have access to a fully set up quota, and
> so we will fail to set these defaults.
> 
> Switch xfs_get_defquota to take an explicit type, and add a helper 
> function to obtain that type from an xfs_dquot for the existing
> callers.

Ah, so this patch isn't itself fixing anything, it's preparing code for
something that happens in the next patch.

> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---
> 
> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
> index 6d6afc0297b3..fdeaccc67d91 100644
> --- a/fs/xfs/xfs_dquot.c
> +++ b/fs/xfs/xfs_dquot.c
> @@ -75,7 +75,7 @@ xfs_qm_adjust_dqlimits(
>  	int			prealloc = 0;
>  
>  	ASSERT(d->d_id);
> -	defq = xfs_get_defquota(dq, q);
> +	defq = xfs_get_defquota(q, xfs_dquot_type(dq));
>  
>  	if (defq->bsoftlimit && !d->d_blk_softlimit) {
>  		d->d_blk_softlimit = cpu_to_be64(defq->bsoftlimit);
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index e97a3802939c..64ba943e0675 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -558,7 +558,7 @@ xfs_qm_set_defquota(
>  		return;
>  
>  	ddqp = &dqp->q_core;
> -	defq = xfs_get_defquota(dqp, qinf);
> +	defq = xfs_get_defquota(qinf, xfs_dquot_type(dqp));
>  
>  	/*
>  	 * Timers and warnings have been already set, let's just set the
> diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
> index 3a850401b102..06df406fdf72 100644
> --- a/fs/xfs/xfs_qm.h
> +++ b/fs/xfs/xfs_qm.h
> @@ -113,6 +113,19 @@ xfs_quota_inode(xfs_mount_t *mp, uint dq_flags)
>  	return NULL;
>  }
>  
> +static inline int
> +xfs_dquot_type(struct xfs_dquot *dqp)
> +{
> +	if (XFS_QM_ISUDQ(dqp))
> +		return XFS_DQ_USER;
> +	else if (XFS_QM_ISGDQ(dqp))
> +		return XFS_DQ_GROUP;
> +	else {
> +		ASSERT(XFS_QM_ISPDQ(dqp));
> +		return XFS_DQ_PROJ;

/me suspects this could be tidier, e.g.

if (UDQ)
	return XFS_DQ_USER;
if (GDQ)
	return XFS_DQ_GROUP;
ASSERT(PDQ);
return XFS_DQ_PROJ;

Otherwise the rest looks ok.

--D


> +	}
> +}
> +
>  extern void	xfs_trans_mod_dquot(struct xfs_trans *tp, struct xfs_dquot *dqp,
>  				    uint field, int64_t delta);
>  extern void	xfs_trans_dqjoin(struct xfs_trans *, struct xfs_dquot *);
> @@ -164,17 +177,22 @@ extern int		xfs_qm_scall_quotaon(struct xfs_mount *, uint);
>  extern int		xfs_qm_scall_quotaoff(struct xfs_mount *, uint);
>  
>  static inline struct xfs_def_quota *
> -xfs_get_defquota(struct xfs_dquot *dqp, struct xfs_quotainfo *qi)
> +xfs_get_defquota(struct xfs_quotainfo *qi, int type)
>  {
>  	struct xfs_def_quota *defq;
>  
> -	if (XFS_QM_ISUDQ(dqp))
> +	switch (type) {
> +	case XFS_DQ_USER:
>  		defq = &qi->qi_usr_default;
> -	else if (XFS_QM_ISGDQ(dqp))
> +		break;
> +	case XFS_DQ_GROUP:
>  		defq = &qi->qi_grp_default;
> -	else {
> -		ASSERT(XFS_QM_ISPDQ(dqp));
> +		break;
> +	case XFS_DQ_PROJ:
>  		defq = &qi->qi_prj_default;
> +		break;
> +	default:
> +		ASSERT(0);
>  	}
>  	return defq;
>  }
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index 301a284ee4f9..13196d07c84e 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -479,7 +479,7 @@ xfs_qm_scall_setqlim(
>  		goto out_unlock;
>  	}
>  
> -	defq = xfs_get_defquota(dqp, q);
> +	defq = xfs_get_defquota(q, xfs_dquot_type(dqp));
>  	xfs_dqunlock(dqp);
>  
>  	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_setqlim, 0, 0, 0, &tp);
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index 20542076e32a..edde366ca8e9 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -591,7 +591,7 @@ xfs_trans_dqresv(
>  
>  	xfs_dqlock(dqp);
>  
> -	defq = xfs_get_defquota(dqp, q);
> +	defq = xfs_get_defquota(q, xfs_dquot_type(dqp));
>  
>  	if (flags & XFS_TRANS_DQ_RES_BLKS) {
>  		hardlimit = be64_to_cpu(dqp->q_core.d_blk_hardlimit);
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 4.5/6] xfs: switch xfs_get_defquota to take explicit type
  2020-05-20 20:36       ` Darrick J. Wong
@ 2020-05-20 20:41         ` Eric Sandeen
  2020-05-20 20:49           ` Darrick J. Wong
  0 siblings, 1 reply; 42+ messages in thread
From: Eric Sandeen @ 2020-05-20 20:41 UTC (permalink / raw)
  To: Darrick J. Wong, Eric Sandeen; +Cc: linux-xfs

On 5/20/20 3:36 PM, Darrick J. Wong wrote:
> On Wed, May 20, 2020 at 01:41:25PM -0500, Eric Sandeen wrote:
>> xfs_get_defquota() currently takes an xfs_dquot, and from that obtains
>> the type of default quota we should get (user/group/project).
>>
>> But early in init, we don't have access to a fully set up quota, and
>> so we will fail to set these defaults.
>>
>> Switch xfs_get_defquota to take an explicit type, and add a helper 
>> function to obtain that type from an xfs_dquot for the existing
>> callers.
> 
> Ah, so this patch isn't itself fixing anything, it's preparing code for
> something that happens in the next patch.

yeah sorry that could be clearer, "fix" on the brain, can edit commit log.

>> Signed-off-by: Eric Sandeen <sandeen@redhat.com>

...

>>  
>> +static inline int
>> +xfs_dquot_type(struct xfs_dquot *dqp)
>> +{
>> +	if (XFS_QM_ISUDQ(dqp))
>> +		return XFS_DQ_USER;
>> +	else if (XFS_QM_ISGDQ(dqp))
>> +		return XFS_DQ_GROUP;
>> +	else {
>> +		ASSERT(XFS_QM_ISPDQ(dqp));
>> +		return XFS_DQ_PROJ;
> 
> /me suspects this could be tidier, e.g.
> 
> if (UDQ)
> 	return XFS_DQ_USER;
> if (GDQ)
> 	return XFS_DQ_GROUP;
> ASSERT(PDQ);
> return XFS_DQ_PROJ;
> 
> Otherwise the rest looks ok.

I suppose, so respin or no?

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 5/6 V2] xfs: per-type quota timers and warn limits
  2020-05-20 20:31       ` Darrick J. Wong
@ 2020-05-20 20:42         ` Eric Sandeen
  0 siblings, 0 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-05-20 20:42 UTC (permalink / raw)
  To: Darrick J. Wong, Eric Sandeen; +Cc: linux-xfs

On 5/20/20 3:31 PM, Darrick J. Wong wrote:
> On Wed, May 20, 2020 at 01:43:15PM -0500, Eric Sandeen wrote:
>> From: Eric Sandeen <sandeen@redhat.com>
>>
>> Move timers and warnings out of xfs_quotainfo and into xfs_def_quota
>> so that we can utilize them on a per-type basis, rather than enforcing
>> them based on the values found in the first enabled quota type.
>>
>> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
>> Reviewed-by: Allison Collins <allison.henderson@oracle.com>
> 
> There's been kind of a lot of changes to keep Allison's RVB, especially
> since you didn't add mine...
> 
> (...says the king of forgetting to apply RVBs :P)
> 
>> [zlang: new way to get defquota in xfs_qm_init_timelimits]
>> [zlang: remove redundant defq assign]
>> Signed-off-by: Zorro Lang <zlang@redhat.com>
>> ---
>>
>> V2: Use the by-type defquota-getter
>>
>> diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
>> index fdeaccc67d91..49c235c5d42c 100644
>> --- a/fs/xfs/xfs_dquot.c
>> +++ b/fs/xfs/xfs_dquot.c
>> @@ -116,8 +116,12 @@ xfs_qm_adjust_dqtimers(
>>  	struct xfs_mount	*mp,
>>  	struct xfs_dquot	*dq)
>>  {
>> +	struct xfs_quotainfo	*qi = mp->m_quotainfo;
>>  	struct xfs_disk_dquot	*d = &dq->q_core;
>> +	struct xfs_def_quota	*defq;
>> +
>>  	ASSERT(d->d_id);
>> +	*defq = xfs_get_defquota(qi, xfs_dquot_type(dq));
> 
> This isn't supposed to be a structure copy, right?

Oh good grief (moved the original init-on-declare down and forgot to delete the *) :/

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 4.5/6] xfs: switch xfs_get_defquota to take explicit type
  2020-05-20 20:41         ` Eric Sandeen
@ 2020-05-20 20:49           ` Darrick J. Wong
  0 siblings, 0 replies; 42+ messages in thread
From: Darrick J. Wong @ 2020-05-20 20:49 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Eric Sandeen, linux-xfs

On Wed, May 20, 2020 at 03:41:03PM -0500, Eric Sandeen wrote:
> On 5/20/20 3:36 PM, Darrick J. Wong wrote:
> > On Wed, May 20, 2020 at 01:41:25PM -0500, Eric Sandeen wrote:
> >> xfs_get_defquota() currently takes an xfs_dquot, and from that obtains
> >> the type of default quota we should get (user/group/project).
> >>
> >> But early in init, we don't have access to a fully set up quota, and
> >> so we will fail to set these defaults.
> >>
> >> Switch xfs_get_defquota to take an explicit type, and add a helper 
> >> function to obtain that type from an xfs_dquot for the existing
> >> callers.
> > 
> > Ah, so this patch isn't itself fixing anything, it's preparing code for
> > something that happens in the next patch.
> 
> yeah sorry that could be clearer, "fix" on the brain, can edit commit log.

Sorry, stream of consciosuness on my part, nothing in this patch
actually said "fix".

> >> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> 
> ...
> 
> >>  
> >> +static inline int
> >> +xfs_dquot_type(struct xfs_dquot *dqp)
> >> +{
> >> +	if (XFS_QM_ISUDQ(dqp))
> >> +		return XFS_DQ_USER;
> >> +	else if (XFS_QM_ISGDQ(dqp))
> >> +		return XFS_DQ_GROUP;
> >> +	else {
> >> +		ASSERT(XFS_QM_ISPDQ(dqp));
> >> +		return XFS_DQ_PROJ;
> > 
> > /me suspects this could be tidier, e.g.
> > 
> > if (UDQ)
> > 	return XFS_DQ_USER;
> > if (GDQ)
> > 	return XFS_DQ_GROUP;
> > ASSERT(PDQ);
> > return XFS_DQ_PROJ;
> > 
> > Otherwise the rest looks ok.
> 
> I suppose, so respin or no?

I fixed up this patch and the next one in my test tree, let's see what
breaks.  I retested all the tests I whined about earlier and they're
fixed now except for generic/594 which might just be ... busted?  Or
maybe I forgot to send a patch...?

--D

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout
  2020-05-18 20:00   ` [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout Eric Sandeen
@ 2020-05-31 16:15     ` Eryu Guan
  2020-06-01 12:48       ` Zorro Lang
  0 siblings, 1 reply; 42+ messages in thread
From: Eryu Guan @ 2020-05-31 16:15 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs, fstests, zlang

On Mon, May 18, 2020 at 03:00:11PM -0500, Eric Sandeen wrote:
> From: Zorro Lang <zlang@redhat.com>
> 
> Set different block & inode grace timers for user, group and project
> quotas, then test softlimit enforcement timeout, make sure different
> grace timers as expected.
> 
> Signed-off-by: Zorro Lang <zlang@redhat.com>
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---

I saw the following failure as well on xfs (as Zorro mentioned in his v3
patch)

     -pwrite: Disk quota exceeded                                                                                                                                                                                   
     +pwrite: No space left on device

So this is an xfs issue that needs to be fixed? Just want to make sure
the current expected test result.

>  common/quota          |   4 +
>  tests/generic/600     | 187 ++++++++++++++++++++++++++++++++++++++++++
>  tests/generic/600.out |  41 +++++++++
>  tests/generic/group   |   1 +
>  4 files changed, 233 insertions(+)
>  create mode 100755 tests/generic/600
>  create mode 100644 tests/generic/600.out
> 
> diff --git a/common/quota b/common/quota
> index 240e0bbc..1437d5f7 100644
> --- a/common/quota
> +++ b/common/quota
> @@ -217,6 +217,10 @@ _qmount()
>      if [ "$FSTYP" != "xfs" ]; then
>          quotacheck -ug $SCRATCH_MNT >>$seqres.full 2>&1
>          quotaon -ug $SCRATCH_MNT >>$seqres.full 2>&1
> +        # try to turn on project quota if it's supported
> +        if quotaon --help 2>&1 | grep -q '\-\-project'; then
> +            quotaon --project $SCRATCH_MNT >>$seqres.full 2>&1
> +        fi
>      fi
>      chmod ugo+rwx $SCRATCH_MNT
>  }
> diff --git a/tests/generic/600 b/tests/generic/600
> new file mode 100755
> index 00000000..03b4dcb3
> --- /dev/null
> +++ b/tests/generic/600
> @@ -0,0 +1,187 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Red Hat, Inc.  All Rights Reserved.
> +#
> +# FS QA Test No. 600
> +#
> +# Test per-type(user, group and project) filesystem quota timers, make sure
> +# enforcement
> +#
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	restore_project
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/quota
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +require_project()
> +{
> +	rm -f $tmp.projects $tmp.projid
> +	if [ -f /etc/projects ];then
> +		cat /etc/projects > $tmp.projects
> +	fi
> +	if [ -f /etc/projid ];then
> +		cat /etc/projid > $tmp.projid
> +	fi
> +
> +	cat >/etc/projects <<EOF
> +100:$SCRATCH_MNT/t
> +EOF
> +	cat >/etc/projid <<EOF
> +$qa_user:100
> +EOF
> +	PROJECT_CHANGED=1
> +}
> +
> +restore_project()
> +{
> +	if [ "$PROJECT_CHANGED" = "1" ];then
> +		rm -f /etc/projects /etc/projid
> +		if [ -f $tmp.projects ];then
> +			cat $tmp.projects > /etc/projects
> +		fi
> +		if [ -f $tmp.projid ];then
> +			cat $tmp.projid > /etc/projid
> +		fi
> +	fi
> +}
> +
> +init_files()
> +{
> +	local dir=$1
> +
> +	echo "### Initialize files, and their mode and ownership"
> +	touch $dir/file{1,2} 2>/dev/null
> +	chown $qa_user $dir/file{1,2} 2>/dev/null
> +	chgrp $qa_user $dir/file{1,2} 2>/dev/null
> +	chmod 777 $dir 2>/dev/null
> +}
> +
> +cleanup_files()
> +{
> +	echo "### Remove all files"
> +	rm -f ${1}/file{1,2,3,4,5,6}
> +}
> +
> +test_grace()
> +{
> +	local type=$1
> +	local dir=$2
> +	local bgrace=$3
> +	local igrace=$4
> +
> +	init_files $dir
> +	echo "--- Test block quota ---"
> +	# Firstly fit below block soft limit
> +	echo "Write 225 blocks..."
> +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((225 * $BLOCK_SIZE))' \
> +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> +		_filter_xfs_io_error | tee -a $seqres.full
> +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> +	# Secondly overcome block soft limit
> +	echo "Rewrite 250 blocks plus 1 byte, over the block softlimit..."
> +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((250 * $BLOCK_SIZE + 1))' \
> +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> +		_filter_xfs_io_error | tee -a $seqres.full
> +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> +	# Reset grace time here, make below grace time test more accurate
> +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> +	# Now sleep enough grace time and check that softlimit got enforced
> +	sleep $((bgrace + 1))
> +	echo "Try to write 1 one more block after grace..."
> +	su $qa_user -c "$XFS_IO_PROG -c 'truncate 0' -c 'pwrite 0 $BLOCK_SIZE' \
> +		$dir/file2" 2>&1 >>$seqres.full | _filter_xfs_io_error | \
> +		tee -a $seqres.full
> +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> +	echo "--- Test inode quota ---"
> +	# And now the softlimit test for inodes
> +	# First reset space limits so that we don't have problems with
> +	# space reservations on XFS
> +	setquota -$type $qa_user 0 0 3 100 $SCRATCH_MNT
> +	echo "Create 2 more files, over the inode softlimit..."
> +	su $qa_user -c "touch $dir/file3 $dir/file4" 2>&1 >>$seqres.full | \
> +		_filter_scratch | tee -a $seqres.full
> +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> +	# Reset grace time here, make below grace time test more accurate
> +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> +	# Wait and check grace time enforcement
> +	sleep $((igrace+1))
> +	echo "Try to create one more inode after grace..."
> +	su $qa_user -c "touch $dir/file5" 2>&1 >>$seqres.full |
> +		_filter_scratch | tee -a $seqres.full
> +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> +	cleanup_files $dir
> +}
> +
> +# real QA test starts here
> +_supported_fs generic
> +_supported_os Linux
> +_require_scratch
> +_require_setquota_project
> +_require_quota
> +_require_user
> +_require_group

Hmm, also needs _require_scratch_xfs_crc when FSTYP is xfs, otherwise v4
xfs fails as

+mount: /mnt/scratch: wrong fs type, bad option, bad superblock on /dev/mapper/testvg-lv2, missing codepage or helper program, or other error.
+qmount failed

and dmesg says

XFS (dm-2): Super block does not support project and group quota together

Thanks,
Eryu

> +
> +_scratch_mkfs >$seqres.full 2>&1
> +_scratch_enable_pquota
> +_qmount_option "usrquota,grpquota,prjquota"
> +_qmount
> +_require_prjquota $SCRATCH_DEV
> +BLOCK_SIZE=$(_get_file_block_size $SCRATCH_MNT)
> +rm -rf $SCRATCH_MNT/t
> +mkdir $SCRATCH_MNT/t
> +$XFS_IO_PROG -r -c "chproj 100" -c "chattr +P" $SCRATCH_MNT/t
> +require_project
> +
> +echo "### Set up different grace timers to each type of quota"
> +UBGRACE=12
> +UIGRACE=10
> +GBGRACE=4
> +GIGRACE=2
> +PBGRACE=8
> +PIGRACE=6
> +
> +setquota -u $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> +setquota -u -t $UBGRACE $UIGRACE $SCRATCH_MNT
> +echo; echo "### Test user quota softlimit and grace time"
> +test_grace u $SCRATCH_MNT $UBGRACE $UIGRACE
> +# Reset the user quota space & inode limits, avoid it affect later test
> +setquota -u $qa_user 0 0 0 0 $SCRATCH_MNT
> +
> +setquota -g $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> +setquota -g -t $GBGRACE $GIGRACE $SCRATCH_MNT
> +echo; echo "### Test group quota softlimit and grace time"
> +test_grace g $SCRATCH_MNT $GBGRACE $GIGRACE
> +# Reset the group quota space & inode limits, avoid it affect later test
> +setquota -g $qa_user 0 0 0 0 $SCRATCH_MNT
> +
> +setquota -P $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> +setquota -P -t $PBGRACE $PIGRACE $SCRATCH_MNT
> +echo; echo "### Test project quota softlimit and grace time"
> +test_grace P $SCRATCH_MNT/t $PBGRACE $PIGRACE
> +# Reset the project quota space & inode limits
> +setquota -P $qa_user 0 0 0 0 $SCRATCH_MNT
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/600.out b/tests/generic/600.out
> new file mode 100644
> index 00000000..6e15eaeb
> --- /dev/null
> +++ b/tests/generic/600.out
> @@ -0,0 +1,41 @@
> +QA output created by 600
> +### Set up different grace timers to each type of quota
> +
> +### Test user quota softlimit and grace time
> +### Initialize files, and their mode and ownership
> +--- Test block quota ---
> +Write 225 blocks...
> +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> +Try to write 1 one more block after grace...
> +pwrite: Disk quota exceeded
> +--- Test inode quota ---
> +Create 2 more files, over the inode softlimit...
> +Try to create one more inode after grace...
> +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> +### Remove all files
> +
> +### Test group quota softlimit and grace time
> +### Initialize files, and their mode and ownership
> +--- Test block quota ---
> +Write 225 blocks...
> +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> +Try to write 1 one more block after grace...
> +pwrite: Disk quota exceeded
> +--- Test inode quota ---
> +Create 2 more files, over the inode softlimit...
> +Try to create one more inode after grace...
> +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> +### Remove all files
> +
> +### Test project quota softlimit and grace time
> +### Initialize files, and their mode and ownership
> +--- Test block quota ---
> +Write 225 blocks...
> +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> +Try to write 1 one more block after grace...
> +pwrite: Disk quota exceeded
> +--- Test inode quota ---
> +Create 2 more files, over the inode softlimit...
> +Try to create one more inode after grace...
> +touch: cannot touch 'SCRATCH_MNT/t/file5': Disk quota exceeded
> +### Remove all files

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 1/4] xfs: make sure our default quota warning limits and grace periods survive quotacheck
  2020-05-18 19:59   ` [PATCH 1/4] xfs: make sure our default quota warning limits and grace periods survive quotacheck Eric Sandeen
@ 2020-05-31 16:17     ` Eryu Guan
  0 siblings, 0 replies; 42+ messages in thread
From: Eryu Guan @ 2020-05-31 16:17 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs, fstests

On Mon, May 18, 2020 at 02:59:39PM -0500, Eric Sandeen wrote:
> From: "Darrick J. Wong" <darrick.wong@oracle.com>
> 
> Make sure that the default quota grace period and maximum warning limits
> set by the administrator survive quotacheck.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> Reviewed-by: Eric Sandeen <sandeen@redhat.com>
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>

Ah, this was already merged in last update. Thanks anyway :)

Eryu

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout
  2020-05-31 16:15     ` Eryu Guan
@ 2020-06-01 12:48       ` Zorro Lang
  2020-06-01 14:36         ` Eric Sandeen
  2020-06-01 16:39         ` Darrick J. Wong
  0 siblings, 2 replies; 42+ messages in thread
From: Zorro Lang @ 2020-06-01 12:48 UTC (permalink / raw)
  To: Eryu Guan; +Cc: Eric Sandeen, linux-xfs, fstests

On Mon, Jun 01, 2020 at 12:15:17AM +0800, Eryu Guan wrote:
> On Mon, May 18, 2020 at 03:00:11PM -0500, Eric Sandeen wrote:
> > From: Zorro Lang <zlang@redhat.com>
> > 
> > Set different block & inode grace timers for user, group and project
> > quotas, then test softlimit enforcement timeout, make sure different
> > grace timers as expected.
> > 
> > Signed-off-by: Zorro Lang <zlang@redhat.com>
> > Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> > ---
> 
> I saw the following failure as well on xfs (as Zorro mentioned in his v3
> patch)
> 
>      -pwrite: Disk quota exceeded
>      +pwrite: No space left on device
> 
> So this is an xfs issue that needs to be fixed? Just want to make sure
> the current expected test result.

Hmm.... I think I'd better to filter ENOSPC|EDQUOT. I can't be sure all
filesystems will return EDQUOT or ENOSPC 100%, especially for group and project
quota.

But I think Eric's trying to change a return value of XFS quota. I don't know the
current status.

Thanks,
Zorro

> 
> >  common/quota          |   4 +
> >  tests/generic/600     | 187 ++++++++++++++++++++++++++++++++++++++++++
> >  tests/generic/600.out |  41 +++++++++
> >  tests/generic/group   |   1 +
> >  4 files changed, 233 insertions(+)
> >  create mode 100755 tests/generic/600
> >  create mode 100644 tests/generic/600.out
> > 
> > diff --git a/common/quota b/common/quota
> > index 240e0bbc..1437d5f7 100644
> > --- a/common/quota
> > +++ b/common/quota
> > @@ -217,6 +217,10 @@ _qmount()
> >      if [ "$FSTYP" != "xfs" ]; then
> >          quotacheck -ug $SCRATCH_MNT >>$seqres.full 2>&1
> >          quotaon -ug $SCRATCH_MNT >>$seqres.full 2>&1
> > +        # try to turn on project quota if it's supported
> > +        if quotaon --help 2>&1 | grep -q '\-\-project'; then
> > +            quotaon --project $SCRATCH_MNT >>$seqres.full 2>&1
> > +        fi
> >      fi
> >      chmod ugo+rwx $SCRATCH_MNT
> >  }
> > diff --git a/tests/generic/600 b/tests/generic/600
> > new file mode 100755
> > index 00000000..03b4dcb3
> > --- /dev/null
> > +++ b/tests/generic/600
> > @@ -0,0 +1,187 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Red Hat, Inc.  All Rights Reserved.
> > +#
> > +# FS QA Test No. 600
> > +#
> > +# Test per-type(user, group and project) filesystem quota timers, make sure
> > +# enforcement
> > +#
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	restore_project
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/quota
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +require_project()
> > +{
> > +	rm -f $tmp.projects $tmp.projid
> > +	if [ -f /etc/projects ];then
> > +		cat /etc/projects > $tmp.projects
> > +	fi
> > +	if [ -f /etc/projid ];then
> > +		cat /etc/projid > $tmp.projid
> > +	fi
> > +
> > +	cat >/etc/projects <<EOF
> > +100:$SCRATCH_MNT/t
> > +EOF
> > +	cat >/etc/projid <<EOF
> > +$qa_user:100
> > +EOF
> > +	PROJECT_CHANGED=1
> > +}
> > +
> > +restore_project()
> > +{
> > +	if [ "$PROJECT_CHANGED" = "1" ];then
> > +		rm -f /etc/projects /etc/projid
> > +		if [ -f $tmp.projects ];then
> > +			cat $tmp.projects > /etc/projects
> > +		fi
> > +		if [ -f $tmp.projid ];then
> > +			cat $tmp.projid > /etc/projid
> > +		fi
> > +	fi
> > +}
> > +
> > +init_files()
> > +{
> > +	local dir=$1
> > +
> > +	echo "### Initialize files, and their mode and ownership"
> > +	touch $dir/file{1,2} 2>/dev/null
> > +	chown $qa_user $dir/file{1,2} 2>/dev/null
> > +	chgrp $qa_user $dir/file{1,2} 2>/dev/null
> > +	chmod 777 $dir 2>/dev/null
> > +}
> > +
> > +cleanup_files()
> > +{
> > +	echo "### Remove all files"
> > +	rm -f ${1}/file{1,2,3,4,5,6}
> > +}
> > +
> > +test_grace()
> > +{
> > +	local type=$1
> > +	local dir=$2
> > +	local bgrace=$3
> > +	local igrace=$4
> > +
> > +	init_files $dir
> > +	echo "--- Test block quota ---"
> > +	# Firstly fit below block soft limit
> > +	echo "Write 225 blocks..."
> > +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((225 * $BLOCK_SIZE))' \
> > +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> > +		_filter_xfs_io_error | tee -a $seqres.full
> > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > +	# Secondly overcome block soft limit
> > +	echo "Rewrite 250 blocks plus 1 byte, over the block softlimit..."
> > +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((250 * $BLOCK_SIZE + 1))' \
> > +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> > +		_filter_xfs_io_error | tee -a $seqres.full
> > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > +	# Reset grace time here, make below grace time test more accurate
> > +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> > +	# Now sleep enough grace time and check that softlimit got enforced
> > +	sleep $((bgrace + 1))
> > +	echo "Try to write 1 one more block after grace..."
> > +	su $qa_user -c "$XFS_IO_PROG -c 'truncate 0' -c 'pwrite 0 $BLOCK_SIZE' \
> > +		$dir/file2" 2>&1 >>$seqres.full | _filter_xfs_io_error | \
> > +		tee -a $seqres.full
> > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > +	echo "--- Test inode quota ---"
> > +	# And now the softlimit test for inodes
> > +	# First reset space limits so that we don't have problems with
> > +	# space reservations on XFS
> > +	setquota -$type $qa_user 0 0 3 100 $SCRATCH_MNT
> > +	echo "Create 2 more files, over the inode softlimit..."
> > +	su $qa_user -c "touch $dir/file3 $dir/file4" 2>&1 >>$seqres.full | \
> > +		_filter_scratch | tee -a $seqres.full
> > +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> > +	# Reset grace time here, make below grace time test more accurate
> > +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> > +	# Wait and check grace time enforcement
> > +	sleep $((igrace+1))
> > +	echo "Try to create one more inode after grace..."
> > +	su $qa_user -c "touch $dir/file5" 2>&1 >>$seqres.full |
> > +		_filter_scratch | tee -a $seqres.full
> > +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> > +	cleanup_files $dir
> > +}
> > +
> > +# real QA test starts here
> > +_supported_fs generic
> > +_supported_os Linux
> > +_require_scratch
> > +_require_setquota_project
> > +_require_quota
> > +_require_user
> > +_require_group
> 
> Hmm, also needs _require_scratch_xfs_crc when FSTYP is xfs, otherwise v4
> xfs fails as
> 
> +mount: /mnt/scratch: wrong fs type, bad option, bad superblock on /dev/mapper/testvg-lv2, missing codepage or helper program, or other error.
> +qmount failed
> 
> and dmesg says
> 
> XFS (dm-2): Super block does not support project and group quota together
> 
> Thanks,
> Eryu
> 
> > +
> > +_scratch_mkfs >$seqres.full 2>&1
> > +_scratch_enable_pquota
> > +_qmount_option "usrquota,grpquota,prjquota"
> > +_qmount
> > +_require_prjquota $SCRATCH_DEV
> > +BLOCK_SIZE=$(_get_file_block_size $SCRATCH_MNT)
> > +rm -rf $SCRATCH_MNT/t
> > +mkdir $SCRATCH_MNT/t
> > +$XFS_IO_PROG -r -c "chproj 100" -c "chattr +P" $SCRATCH_MNT/t
> > +require_project
> > +
> > +echo "### Set up different grace timers to each type of quota"
> > +UBGRACE=12
> > +UIGRACE=10
> > +GBGRACE=4
> > +GIGRACE=2
> > +PBGRACE=8
> > +PIGRACE=6
> > +
> > +setquota -u $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > +setquota -u -t $UBGRACE $UIGRACE $SCRATCH_MNT
> > +echo; echo "### Test user quota softlimit and grace time"
> > +test_grace u $SCRATCH_MNT $UBGRACE $UIGRACE
> > +# Reset the user quota space & inode limits, avoid it affect later test
> > +setquota -u $qa_user 0 0 0 0 $SCRATCH_MNT
> > +
> > +setquota -g $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > +setquota -g -t $GBGRACE $GIGRACE $SCRATCH_MNT
> > +echo; echo "### Test group quota softlimit and grace time"
> > +test_grace g $SCRATCH_MNT $GBGRACE $GIGRACE
> > +# Reset the group quota space & inode limits, avoid it affect later test
> > +setquota -g $qa_user 0 0 0 0 $SCRATCH_MNT
> > +
> > +setquota -P $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > +setquota -P -t $PBGRACE $PIGRACE $SCRATCH_MNT
> > +echo; echo "### Test project quota softlimit and grace time"
> > +test_grace P $SCRATCH_MNT/t $PBGRACE $PIGRACE
> > +# Reset the project quota space & inode limits
> > +setquota -P $qa_user 0 0 0 0 $SCRATCH_MNT
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/generic/600.out b/tests/generic/600.out
> > new file mode 100644
> > index 00000000..6e15eaeb
> > --- /dev/null
> > +++ b/tests/generic/600.out
> > @@ -0,0 +1,41 @@
> > +QA output created by 600
> > +### Set up different grace timers to each type of quota
> > +
> > +### Test user quota softlimit and grace time
> > +### Initialize files, and their mode and ownership
> > +--- Test block quota ---
> > +Write 225 blocks...
> > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > +Try to write 1 one more block after grace...
> > +pwrite: Disk quota exceeded
> > +--- Test inode quota ---
> > +Create 2 more files, over the inode softlimit...
> > +Try to create one more inode after grace...
> > +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> > +### Remove all files
> > +
> > +### Test group quota softlimit and grace time
> > +### Initialize files, and their mode and ownership
> > +--- Test block quota ---
> > +Write 225 blocks...
> > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > +Try to write 1 one more block after grace...
> > +pwrite: Disk quota exceeded
> > +--- Test inode quota ---
> > +Create 2 more files, over the inode softlimit...
> > +Try to create one more inode after grace...
> > +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> > +### Remove all files
> > +
> > +### Test project quota softlimit and grace time
> > +### Initialize files, and their mode and ownership
> > +--- Test block quota ---
> > +Write 225 blocks...
> > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > +Try to write 1 one more block after grace...
> > +pwrite: Disk quota exceeded
> > +--- Test inode quota ---
> > +Create 2 more files, over the inode softlimit...
> > +Try to create one more inode after grace...
> > +touch: cannot touch 'SCRATCH_MNT/t/file5': Disk quota exceeded
> > +### Remove all files
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout
  2020-06-01 12:48       ` Zorro Lang
@ 2020-06-01 14:36         ` Eric Sandeen
  2020-06-01 16:39         ` Darrick J. Wong
  1 sibling, 0 replies; 42+ messages in thread
From: Eric Sandeen @ 2020-06-01 14:36 UTC (permalink / raw)
  To: Eryu Guan, linux-xfs, fstests

On 6/1/20 7:48 AM, Zorro Lang wrote:
> On Mon, Jun 01, 2020 at 12:15:17AM +0800, Eryu Guan wrote:
>> On Mon, May 18, 2020 at 03:00:11PM -0500, Eric Sandeen wrote:
>>> From: Zorro Lang <zlang@redhat.com>
>>>
>>> Set different block & inode grace timers for user, group and project
>>> quotas, then test softlimit enforcement timeout, make sure different
>>> grace timers as expected.
>>>
>>> Signed-off-by: Zorro Lang <zlang@redhat.com>
>>> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
>>> ---
>>
>> I saw the following failure as well on xfs (as Zorro mentioned in his v3
>> patch)
>>
>>      -pwrite: Disk quota exceeded
>>      +pwrite: No space left on device
>>
>> So this is an xfs issue that needs to be fixed? Just want to make sure
>> the current expected test result.
> 
> Hmm.... I think I'd better to filter ENOSPC|EDQUOT. I can't be sure all
> filesystems will return EDQUOT or ENOSPC 100%, especially for group and project
> quota.
> 
> But I think Eric's trying to change a return value of XFS quota. I don't know the
> current status.

This test will need to be updated, it sounds like ext4 does not plan to switch
to ENOSPC for project quota, so we'll need modify it to accept either one.

Zorro, didn't you do that for another test?  Maybe you can do the same here?

Thanks,
-Eric


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout
  2020-06-01 12:48       ` Zorro Lang
  2020-06-01 14:36         ` Eric Sandeen
@ 2020-06-01 16:39         ` Darrick J. Wong
  2020-06-11  5:12           ` Zorro Lang
  1 sibling, 1 reply; 42+ messages in thread
From: Darrick J. Wong @ 2020-06-01 16:39 UTC (permalink / raw)
  To: Eryu Guan, Eric Sandeen, linux-xfs, fstests

On Mon, Jun 01, 2020 at 08:48:44PM +0800, Zorro Lang wrote:
> On Mon, Jun 01, 2020 at 12:15:17AM +0800, Eryu Guan wrote:
> > On Mon, May 18, 2020 at 03:00:11PM -0500, Eric Sandeen wrote:
> > > From: Zorro Lang <zlang@redhat.com>
> > > 
> > > Set different block & inode grace timers for user, group and project
> > > quotas, then test softlimit enforcement timeout, make sure different
> > > grace timers as expected.
> > > 
> > > Signed-off-by: Zorro Lang <zlang@redhat.com>
> > > Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> > > ---
> > 
> > I saw the following failure as well on xfs (as Zorro mentioned in his v3
> > patch)
> > 
> >      -pwrite: Disk quota exceeded
> >      +pwrite: No space left on device
> > 
> > So this is an xfs issue that needs to be fixed? Just want to make sure
> > the current expected test result.
> 
> Hmm.... I think I'd better to filter ENOSPC|EDQUOT. I can't be sure all
> filesystems will return EDQUOT or ENOSPC 100%, especially for group and project
> quota.
> 
> But I think Eric's trying to change a return value of XFS quota. I don't know the
> current status.

Yeah, Eric fixed a few problems where a group quota overage would return
ENOSPC instead of EDQUOT; and a few more problems where a project quota
overage would return EDQUOT instead of ENOSPC.

That'll be coming in the 5.8 merge, which I should get on...

--D

> Thanks,
> Zorro
> 
> > 
> > >  common/quota          |   4 +
> > >  tests/generic/600     | 187 ++++++++++++++++++++++++++++++++++++++++++
> > >  tests/generic/600.out |  41 +++++++++
> > >  tests/generic/group   |   1 +
> > >  4 files changed, 233 insertions(+)
> > >  create mode 100755 tests/generic/600
> > >  create mode 100644 tests/generic/600.out
> > > 
> > > diff --git a/common/quota b/common/quota
> > > index 240e0bbc..1437d5f7 100644
> > > --- a/common/quota
> > > +++ b/common/quota
> > > @@ -217,6 +217,10 @@ _qmount()
> > >      if [ "$FSTYP" != "xfs" ]; then
> > >          quotacheck -ug $SCRATCH_MNT >>$seqres.full 2>&1
> > >          quotaon -ug $SCRATCH_MNT >>$seqres.full 2>&1
> > > +        # try to turn on project quota if it's supported
> > > +        if quotaon --help 2>&1 | grep -q '\-\-project'; then
> > > +            quotaon --project $SCRATCH_MNT >>$seqres.full 2>&1
> > > +        fi
> > >      fi
> > >      chmod ugo+rwx $SCRATCH_MNT
> > >  }
> > > diff --git a/tests/generic/600 b/tests/generic/600
> > > new file mode 100755
> > > index 00000000..03b4dcb3
> > > --- /dev/null
> > > +++ b/tests/generic/600
> > > @@ -0,0 +1,187 @@
> > > +#! /bin/bash
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# Copyright (c) 2020 Red Hat, Inc.  All Rights Reserved.
> > > +#
> > > +# FS QA Test No. 600
> > > +#
> > > +# Test per-type(user, group and project) filesystem quota timers, make sure
> > > +# enforcement
> > > +#
> > > +seq=`basename $0`
> > > +seqres=$RESULT_DIR/$seq
> > > +echo "QA output created by $seq"
> > > +
> > > +here=`pwd`
> > > +tmp=/tmp/$$
> > > +status=1	# failure is the default!
> > > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > > +
> > > +_cleanup()
> > > +{
> > > +	restore_project
> > > +	cd /
> > > +	rm -f $tmp.*
> > > +}
> > > +
> > > +# get standard environment, filters and checks
> > > +. ./common/rc
> > > +. ./common/filter
> > > +. ./common/quota
> > > +
> > > +# remove previous $seqres.full before test
> > > +rm -f $seqres.full
> > > +
> > > +require_project()
> > > +{
> > > +	rm -f $tmp.projects $tmp.projid
> > > +	if [ -f /etc/projects ];then
> > > +		cat /etc/projects > $tmp.projects
> > > +	fi
> > > +	if [ -f /etc/projid ];then
> > > +		cat /etc/projid > $tmp.projid
> > > +	fi
> > > +
> > > +	cat >/etc/projects <<EOF
> > > +100:$SCRATCH_MNT/t
> > > +EOF
> > > +	cat >/etc/projid <<EOF
> > > +$qa_user:100
> > > +EOF
> > > +	PROJECT_CHANGED=1
> > > +}
> > > +
> > > +restore_project()
> > > +{
> > > +	if [ "$PROJECT_CHANGED" = "1" ];then
> > > +		rm -f /etc/projects /etc/projid
> > > +		if [ -f $tmp.projects ];then
> > > +			cat $tmp.projects > /etc/projects
> > > +		fi
> > > +		if [ -f $tmp.projid ];then
> > > +			cat $tmp.projid > /etc/projid
> > > +		fi
> > > +	fi
> > > +}
> > > +
> > > +init_files()
> > > +{
> > > +	local dir=$1
> > > +
> > > +	echo "### Initialize files, and their mode and ownership"
> > > +	touch $dir/file{1,2} 2>/dev/null
> > > +	chown $qa_user $dir/file{1,2} 2>/dev/null
> > > +	chgrp $qa_user $dir/file{1,2} 2>/dev/null
> > > +	chmod 777 $dir 2>/dev/null
> > > +}
> > > +
> > > +cleanup_files()
> > > +{
> > > +	echo "### Remove all files"
> > > +	rm -f ${1}/file{1,2,3,4,5,6}
> > > +}
> > > +
> > > +test_grace()
> > > +{
> > > +	local type=$1
> > > +	local dir=$2
> > > +	local bgrace=$3
> > > +	local igrace=$4
> > > +
> > > +	init_files $dir
> > > +	echo "--- Test block quota ---"
> > > +	# Firstly fit below block soft limit
> > > +	echo "Write 225 blocks..."
> > > +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((225 * $BLOCK_SIZE))' \
> > > +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> > > +		_filter_xfs_io_error | tee -a $seqres.full
> > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > +	# Secondly overcome block soft limit
> > > +	echo "Rewrite 250 blocks plus 1 byte, over the block softlimit..."
> > > +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((250 * $BLOCK_SIZE + 1))' \
> > > +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> > > +		_filter_xfs_io_error | tee -a $seqres.full
> > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > +	# Reset grace time here, make below grace time test more accurate
> > > +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> > > +	# Now sleep enough grace time and check that softlimit got enforced
> > > +	sleep $((bgrace + 1))
> > > +	echo "Try to write 1 one more block after grace..."
> > > +	su $qa_user -c "$XFS_IO_PROG -c 'truncate 0' -c 'pwrite 0 $BLOCK_SIZE' \
> > > +		$dir/file2" 2>&1 >>$seqres.full | _filter_xfs_io_error | \
> > > +		tee -a $seqres.full
> > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > +	echo "--- Test inode quota ---"
> > > +	# And now the softlimit test for inodes
> > > +	# First reset space limits so that we don't have problems with
> > > +	# space reservations on XFS
> > > +	setquota -$type $qa_user 0 0 3 100 $SCRATCH_MNT
> > > +	echo "Create 2 more files, over the inode softlimit..."
> > > +	su $qa_user -c "touch $dir/file3 $dir/file4" 2>&1 >>$seqres.full | \
> > > +		_filter_scratch | tee -a $seqres.full
> > > +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> > > +	# Reset grace time here, make below grace time test more accurate
> > > +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> > > +	# Wait and check grace time enforcement
> > > +	sleep $((igrace+1))
> > > +	echo "Try to create one more inode after grace..."
> > > +	su $qa_user -c "touch $dir/file5" 2>&1 >>$seqres.full |
> > > +		_filter_scratch | tee -a $seqres.full
> > > +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> > > +	cleanup_files $dir
> > > +}
> > > +
> > > +# real QA test starts here
> > > +_supported_fs generic
> > > +_supported_os Linux
> > > +_require_scratch
> > > +_require_setquota_project
> > > +_require_quota
> > > +_require_user
> > > +_require_group
> > 
> > Hmm, also needs _require_scratch_xfs_crc when FSTYP is xfs, otherwise v4
> > xfs fails as
> > 
> > +mount: /mnt/scratch: wrong fs type, bad option, bad superblock on /dev/mapper/testvg-lv2, missing codepage or helper program, or other error.
> > +qmount failed
> > 
> > and dmesg says
> > 
> > XFS (dm-2): Super block does not support project and group quota together
> > 
> > Thanks,
> > Eryu
> > 
> > > +
> > > +_scratch_mkfs >$seqres.full 2>&1
> > > +_scratch_enable_pquota
> > > +_qmount_option "usrquota,grpquota,prjquota"
> > > +_qmount
> > > +_require_prjquota $SCRATCH_DEV
> > > +BLOCK_SIZE=$(_get_file_block_size $SCRATCH_MNT)
> > > +rm -rf $SCRATCH_MNT/t
> > > +mkdir $SCRATCH_MNT/t
> > > +$XFS_IO_PROG -r -c "chproj 100" -c "chattr +P" $SCRATCH_MNT/t
> > > +require_project
> > > +
> > > +echo "### Set up different grace timers to each type of quota"
> > > +UBGRACE=12
> > > +UIGRACE=10
> > > +GBGRACE=4
> > > +GIGRACE=2
> > > +PBGRACE=8
> > > +PIGRACE=6
> > > +
> > > +setquota -u $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > +setquota -u -t $UBGRACE $UIGRACE $SCRATCH_MNT
> > > +echo; echo "### Test user quota softlimit and grace time"
> > > +test_grace u $SCRATCH_MNT $UBGRACE $UIGRACE
> > > +# Reset the user quota space & inode limits, avoid it affect later test
> > > +setquota -u $qa_user 0 0 0 0 $SCRATCH_MNT
> > > +
> > > +setquota -g $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > +setquota -g -t $GBGRACE $GIGRACE $SCRATCH_MNT
> > > +echo; echo "### Test group quota softlimit and grace time"
> > > +test_grace g $SCRATCH_MNT $GBGRACE $GIGRACE
> > > +# Reset the group quota space & inode limits, avoid it affect later test
> > > +setquota -g $qa_user 0 0 0 0 $SCRATCH_MNT
> > > +
> > > +setquota -P $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > +setquota -P -t $PBGRACE $PIGRACE $SCRATCH_MNT
> > > +echo; echo "### Test project quota softlimit and grace time"
> > > +test_grace P $SCRATCH_MNT/t $PBGRACE $PIGRACE
> > > +# Reset the project quota space & inode limits
> > > +setquota -P $qa_user 0 0 0 0 $SCRATCH_MNT
> > > +
> > > +# success, all done
> > > +status=0
> > > +exit
> > > diff --git a/tests/generic/600.out b/tests/generic/600.out
> > > new file mode 100644
> > > index 00000000..6e15eaeb
> > > --- /dev/null
> > > +++ b/tests/generic/600.out
> > > @@ -0,0 +1,41 @@
> > > +QA output created by 600
> > > +### Set up different grace timers to each type of quota
> > > +
> > > +### Test user quota softlimit and grace time
> > > +### Initialize files, and their mode and ownership
> > > +--- Test block quota ---
> > > +Write 225 blocks...
> > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > +Try to write 1 one more block after grace...
> > > +pwrite: Disk quota exceeded
> > > +--- Test inode quota ---
> > > +Create 2 more files, over the inode softlimit...
> > > +Try to create one more inode after grace...
> > > +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> > > +### Remove all files
> > > +
> > > +### Test group quota softlimit and grace time
> > > +### Initialize files, and their mode and ownership
> > > +--- Test block quota ---
> > > +Write 225 blocks...
> > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > +Try to write 1 one more block after grace...
> > > +pwrite: Disk quota exceeded
> > > +--- Test inode quota ---
> > > +Create 2 more files, over the inode softlimit...
> > > +Try to create one more inode after grace...
> > > +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> > > +### Remove all files
> > > +
> > > +### Test project quota softlimit and grace time
> > > +### Initialize files, and their mode and ownership
> > > +--- Test block quota ---
> > > +Write 225 blocks...
> > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > +Try to write 1 one more block after grace...
> > > +pwrite: Disk quota exceeded
> > > +--- Test inode quota ---
> > > +Create 2 more files, over the inode softlimit...
> > > +Try to create one more inode after grace...
> > > +touch: cannot touch 'SCRATCH_MNT/t/file5': Disk quota exceeded
> > > +### Remove all files
> > 
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout
  2020-06-01 16:39         ` Darrick J. Wong
@ 2020-06-11  5:12           ` Zorro Lang
  2020-06-11 15:40             ` Darrick J. Wong
  0 siblings, 1 reply; 42+ messages in thread
From: Zorro Lang @ 2020-06-11  5:12 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Eryu Guan, Eric Sandeen, linux-xfs, fstests

On Mon, Jun 01, 2020 at 09:39:57AM -0700, Darrick J. Wong wrote:
> On Mon, Jun 01, 2020 at 08:48:44PM +0800, Zorro Lang wrote:
> > On Mon, Jun 01, 2020 at 12:15:17AM +0800, Eryu Guan wrote:
> > > On Mon, May 18, 2020 at 03:00:11PM -0500, Eric Sandeen wrote:
> > > > From: Zorro Lang <zlang@redhat.com>
> > > > 
> > > > Set different block & inode grace timers for user, group and project
> > > > quotas, then test softlimit enforcement timeout, make sure different
> > > > grace timers as expected.
> > > > 
> > > > Signed-off-by: Zorro Lang <zlang@redhat.com>
> > > > Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> > > > ---
> > > 
> > > I saw the following failure as well on xfs (as Zorro mentioned in his v3
> > > patch)
> > > 
> > >      -pwrite: Disk quota exceeded
> > >      +pwrite: No space left on device
> > > 
> > > So this is an xfs issue that needs to be fixed? Just want to make sure
> > > the current expected test result.
> > 
> > Hmm.... I think I'd better to filter ENOSPC|EDQUOT. I can't be sure all
> > filesystems will return EDQUOT or ENOSPC 100%, especially for group and project
> > quota.
> > 
> > But I think Eric's trying to change a return value of XFS quota. I don't know the
> > current status.
> 
> Yeah, Eric fixed a few problems where a group quota overage would return
> ENOSPC instead of EDQUOT; and a few more problems where a project quota
> overage would return EDQUOT instead of ENOSPC.
> 
> That'll be coming in the 5.8 merge, which I should get on...

To make sure I don't misunderstand, so the expected output is as below?
1) User quota test:
pwrite: Disk quota exceeded

2) Group quota test:
pwrite: Disk quota exceeded

3) Project quota test:
pwrite: No space left on device / Disk quota exceeded (need a filter)

Thanks,
Zorro

> 
> --D
> 
> > Thanks,
> > Zorro
> > 
> > > 
> > > >  common/quota          |   4 +
> > > >  tests/generic/600     | 187 ++++++++++++++++++++++++++++++++++++++++++
> > > >  tests/generic/600.out |  41 +++++++++
> > > >  tests/generic/group   |   1 +
> > > >  4 files changed, 233 insertions(+)
> > > >  create mode 100755 tests/generic/600
> > > >  create mode 100644 tests/generic/600.out
> > > > 
> > > > diff --git a/common/quota b/common/quota
> > > > index 240e0bbc..1437d5f7 100644
> > > > --- a/common/quota
> > > > +++ b/common/quota
> > > > @@ -217,6 +217,10 @@ _qmount()
> > > >      if [ "$FSTYP" != "xfs" ]; then
> > > >          quotacheck -ug $SCRATCH_MNT >>$seqres.full 2>&1
> > > >          quotaon -ug $SCRATCH_MNT >>$seqres.full 2>&1
> > > > +        # try to turn on project quota if it's supported
> > > > +        if quotaon --help 2>&1 | grep -q '\-\-project'; then
> > > > +            quotaon --project $SCRATCH_MNT >>$seqres.full 2>&1
> > > > +        fi
> > > >      fi
> > > >      chmod ugo+rwx $SCRATCH_MNT
> > > >  }
> > > > diff --git a/tests/generic/600 b/tests/generic/600
> > > > new file mode 100755
> > > > index 00000000..03b4dcb3
> > > > --- /dev/null
> > > > +++ b/tests/generic/600
> > > > @@ -0,0 +1,187 @@
> > > > +#! /bin/bash
> > > > +# SPDX-License-Identifier: GPL-2.0
> > > > +# Copyright (c) 2020 Red Hat, Inc.  All Rights Reserved.
> > > > +#
> > > > +# FS QA Test No. 600
> > > > +#
> > > > +# Test per-type(user, group and project) filesystem quota timers, make sure
> > > > +# enforcement
> > > > +#
> > > > +seq=`basename $0`
> > > > +seqres=$RESULT_DIR/$seq
> > > > +echo "QA output created by $seq"
> > > > +
> > > > +here=`pwd`
> > > > +tmp=/tmp/$$
> > > > +status=1	# failure is the default!
> > > > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > > > +
> > > > +_cleanup()
> > > > +{
> > > > +	restore_project
> > > > +	cd /
> > > > +	rm -f $tmp.*
> > > > +}
> > > > +
> > > > +# get standard environment, filters and checks
> > > > +. ./common/rc
> > > > +. ./common/filter
> > > > +. ./common/quota
> > > > +
> > > > +# remove previous $seqres.full before test
> > > > +rm -f $seqres.full
> > > > +
> > > > +require_project()
> > > > +{
> > > > +	rm -f $tmp.projects $tmp.projid
> > > > +	if [ -f /etc/projects ];then
> > > > +		cat /etc/projects > $tmp.projects
> > > > +	fi
> > > > +	if [ -f /etc/projid ];then
> > > > +		cat /etc/projid > $tmp.projid
> > > > +	fi
> > > > +
> > > > +	cat >/etc/projects <<EOF
> > > > +100:$SCRATCH_MNT/t
> > > > +EOF
> > > > +	cat >/etc/projid <<EOF
> > > > +$qa_user:100
> > > > +EOF
> > > > +	PROJECT_CHANGED=1
> > > > +}
> > > > +
> > > > +restore_project()
> > > > +{
> > > > +	if [ "$PROJECT_CHANGED" = "1" ];then
> > > > +		rm -f /etc/projects /etc/projid
> > > > +		if [ -f $tmp.projects ];then
> > > > +			cat $tmp.projects > /etc/projects
> > > > +		fi
> > > > +		if [ -f $tmp.projid ];then
> > > > +			cat $tmp.projid > /etc/projid
> > > > +		fi
> > > > +	fi
> > > > +}
> > > > +
> > > > +init_files()
> > > > +{
> > > > +	local dir=$1
> > > > +
> > > > +	echo "### Initialize files, and their mode and ownership"
> > > > +	touch $dir/file{1,2} 2>/dev/null
> > > > +	chown $qa_user $dir/file{1,2} 2>/dev/null
> > > > +	chgrp $qa_user $dir/file{1,2} 2>/dev/null
> > > > +	chmod 777 $dir 2>/dev/null
> > > > +}
> > > > +
> > > > +cleanup_files()
> > > > +{
> > > > +	echo "### Remove all files"
> > > > +	rm -f ${1}/file{1,2,3,4,5,6}
> > > > +}
> > > > +
> > > > +test_grace()
> > > > +{
> > > > +	local type=$1
> > > > +	local dir=$2
> > > > +	local bgrace=$3
> > > > +	local igrace=$4
> > > > +
> > > > +	init_files $dir
> > > > +	echo "--- Test block quota ---"
> > > > +	# Firstly fit below block soft limit
> > > > +	echo "Write 225 blocks..."
> > > > +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((225 * $BLOCK_SIZE))' \
> > > > +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> > > > +		_filter_xfs_io_error | tee -a $seqres.full
> > > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > > +	# Secondly overcome block soft limit
> > > > +	echo "Rewrite 250 blocks plus 1 byte, over the block softlimit..."
> > > > +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((250 * $BLOCK_SIZE + 1))' \
> > > > +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> > > > +		_filter_xfs_io_error | tee -a $seqres.full
> > > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > > +	# Reset grace time here, make below grace time test more accurate
> > > > +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> > > > +	# Now sleep enough grace time and check that softlimit got enforced
> > > > +	sleep $((bgrace + 1))
> > > > +	echo "Try to write 1 one more block after grace..."
> > > > +	su $qa_user -c "$XFS_IO_PROG -c 'truncate 0' -c 'pwrite 0 $BLOCK_SIZE' \
> > > > +		$dir/file2" 2>&1 >>$seqres.full | _filter_xfs_io_error | \
> > > > +		tee -a $seqres.full
> > > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > > +	echo "--- Test inode quota ---"
> > > > +	# And now the softlimit test for inodes
> > > > +	# First reset space limits so that we don't have problems with
> > > > +	# space reservations on XFS
> > > > +	setquota -$type $qa_user 0 0 3 100 $SCRATCH_MNT
> > > > +	echo "Create 2 more files, over the inode softlimit..."
> > > > +	su $qa_user -c "touch $dir/file3 $dir/file4" 2>&1 >>$seqres.full | \
> > > > +		_filter_scratch | tee -a $seqres.full
> > > > +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> > > > +	# Reset grace time here, make below grace time test more accurate
> > > > +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> > > > +	# Wait and check grace time enforcement
> > > > +	sleep $((igrace+1))
> > > > +	echo "Try to create one more inode after grace..."
> > > > +	su $qa_user -c "touch $dir/file5" 2>&1 >>$seqres.full |
> > > > +		_filter_scratch | tee -a $seqres.full
> > > > +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> > > > +	cleanup_files $dir
> > > > +}
> > > > +
> > > > +# real QA test starts here
> > > > +_supported_fs generic
> > > > +_supported_os Linux
> > > > +_require_scratch
> > > > +_require_setquota_project
> > > > +_require_quota
> > > > +_require_user
> > > > +_require_group
> > > 
> > > Hmm, also needs _require_scratch_xfs_crc when FSTYP is xfs, otherwise v4
> > > xfs fails as
> > > 
> > > +mount: /mnt/scratch: wrong fs type, bad option, bad superblock on /dev/mapper/testvg-lv2, missing codepage or helper program, or other error.
> > > +qmount failed
> > > 
> > > and dmesg says
> > > 
> > > XFS (dm-2): Super block does not support project and group quota together
> > > 
> > > Thanks,
> > > Eryu
> > > 
> > > > +
> > > > +_scratch_mkfs >$seqres.full 2>&1
> > > > +_scratch_enable_pquota
> > > > +_qmount_option "usrquota,grpquota,prjquota"
> > > > +_qmount
> > > > +_require_prjquota $SCRATCH_DEV
> > > > +BLOCK_SIZE=$(_get_file_block_size $SCRATCH_MNT)
> > > > +rm -rf $SCRATCH_MNT/t
> > > > +mkdir $SCRATCH_MNT/t
> > > > +$XFS_IO_PROG -r -c "chproj 100" -c "chattr +P" $SCRATCH_MNT/t
> > > > +require_project
> > > > +
> > > > +echo "### Set up different grace timers to each type of quota"
> > > > +UBGRACE=12
> > > > +UIGRACE=10
> > > > +GBGRACE=4
> > > > +GIGRACE=2
> > > > +PBGRACE=8
> > > > +PIGRACE=6
> > > > +
> > > > +setquota -u $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > > +setquota -u -t $UBGRACE $UIGRACE $SCRATCH_MNT
> > > > +echo; echo "### Test user quota softlimit and grace time"
> > > > +test_grace u $SCRATCH_MNT $UBGRACE $UIGRACE
> > > > +# Reset the user quota space & inode limits, avoid it affect later test
> > > > +setquota -u $qa_user 0 0 0 0 $SCRATCH_MNT
> > > > +
> > > > +setquota -g $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > > +setquota -g -t $GBGRACE $GIGRACE $SCRATCH_MNT
> > > > +echo; echo "### Test group quota softlimit and grace time"
> > > > +test_grace g $SCRATCH_MNT $GBGRACE $GIGRACE
> > > > +# Reset the group quota space & inode limits, avoid it affect later test
> > > > +setquota -g $qa_user 0 0 0 0 $SCRATCH_MNT
> > > > +
> > > > +setquota -P $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > > +setquota -P -t $PBGRACE $PIGRACE $SCRATCH_MNT
> > > > +echo; echo "### Test project quota softlimit and grace time"
> > > > +test_grace P $SCRATCH_MNT/t $PBGRACE $PIGRACE
> > > > +# Reset the project quota space & inode limits
> > > > +setquota -P $qa_user 0 0 0 0 $SCRATCH_MNT
> > > > +
> > > > +# success, all done
> > > > +status=0
> > > > +exit
> > > > diff --git a/tests/generic/600.out b/tests/generic/600.out
> > > > new file mode 100644
> > > > index 00000000..6e15eaeb
> > > > --- /dev/null
> > > > +++ b/tests/generic/600.out
> > > > @@ -0,0 +1,41 @@
> > > > +QA output created by 600
> > > > +### Set up different grace timers to each type of quota
> > > > +
> > > > +### Test user quota softlimit and grace time
> > > > +### Initialize files, and their mode and ownership
> > > > +--- Test block quota ---
> > > > +Write 225 blocks...
> > > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > > +Try to write 1 one more block after grace...
> > > > +pwrite: Disk quota exceeded
> > > > +--- Test inode quota ---
> > > > +Create 2 more files, over the inode softlimit...
> > > > +Try to create one more inode after grace...
> > > > +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> > > > +### Remove all files
> > > > +
> > > > +### Test group quota softlimit and grace time
> > > > +### Initialize files, and their mode and ownership
> > > > +--- Test block quota ---
> > > > +Write 225 blocks...
> > > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > > +Try to write 1 one more block after grace...
> > > > +pwrite: Disk quota exceeded
> > > > +--- Test inode quota ---
> > > > +Create 2 more files, over the inode softlimit...
> > > > +Try to create one more inode after grace...
> > > > +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> > > > +### Remove all files
> > > > +
> > > > +### Test project quota softlimit and grace time
> > > > +### Initialize files, and their mode and ownership
> > > > +--- Test block quota ---
> > > > +Write 225 blocks...
> > > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > > +Try to write 1 one more block after grace...
> > > > +pwrite: Disk quota exceeded
> > > > +--- Test inode quota ---
> > > > +Create 2 more files, over the inode softlimit...
> > > > +Try to create one more inode after grace...
> > > > +touch: cannot touch 'SCRATCH_MNT/t/file5': Disk quota exceeded
> > > > +### Remove all files
> > > 
> > 
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout
  2020-06-11  5:12           ` Zorro Lang
@ 2020-06-11 15:40             ` Darrick J. Wong
  0 siblings, 0 replies; 42+ messages in thread
From: Darrick J. Wong @ 2020-06-11 15:40 UTC (permalink / raw)
  To: Eryu Guan, Eric Sandeen, linux-xfs, fstests

On Thu, Jun 11, 2020 at 01:12:43PM +0800, Zorro Lang wrote:
> On Mon, Jun 01, 2020 at 09:39:57AM -0700, Darrick J. Wong wrote:
> > On Mon, Jun 01, 2020 at 08:48:44PM +0800, Zorro Lang wrote:
> > > On Mon, Jun 01, 2020 at 12:15:17AM +0800, Eryu Guan wrote:
> > > > On Mon, May 18, 2020 at 03:00:11PM -0500, Eric Sandeen wrote:
> > > > > From: Zorro Lang <zlang@redhat.com>
> > > > > 
> > > > > Set different block & inode grace timers for user, group and project
> > > > > quotas, then test softlimit enforcement timeout, make sure different
> > > > > grace timers as expected.
> > > > > 
> > > > > Signed-off-by: Zorro Lang <zlang@redhat.com>
> > > > > Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> > > > > ---
> > > > 
> > > > I saw the following failure as well on xfs (as Zorro mentioned in his v3
> > > > patch)
> > > > 
> > > >      -pwrite: Disk quota exceeded
> > > >      +pwrite: No space left on device
> > > > 
> > > > So this is an xfs issue that needs to be fixed? Just want to make sure
> > > > the current expected test result.
> > > 
> > > Hmm.... I think I'd better to filter ENOSPC|EDQUOT. I can't be sure all
> > > filesystems will return EDQUOT or ENOSPC 100%, especially for group and project
> > > quota.
> > > 
> > > But I think Eric's trying to change a return value of XFS quota. I don't know the
> > > current status.
> > 
> > Yeah, Eric fixed a few problems where a group quota overage would return
> > ENOSPC instead of EDQUOT; and a few more problems where a project quota
> > overage would return EDQUOT instead of ENOSPC.
> > 
> > That'll be coming in the 5.8 merge, which I should get on...
> 
> To make sure I don't misunderstand, so the expected output is as below?
> 1) User quota test:
> pwrite: Disk quota exceeded
> 
> 2) Group quota test:
> pwrite: Disk quota exceeded
> 
> 3) Project quota test:
> pwrite: No space left on device / Disk quota exceeded (need a filter)

Yes, that's my understanding of the *intended* behavior. :)

--D

> Thanks,
> Zorro
> 
> > 
> > --D
> > 
> > > Thanks,
> > > Zorro
> > > 
> > > > 
> > > > >  common/quota          |   4 +
> > > > >  tests/generic/600     | 187 ++++++++++++++++++++++++++++++++++++++++++
> > > > >  tests/generic/600.out |  41 +++++++++
> > > > >  tests/generic/group   |   1 +
> > > > >  4 files changed, 233 insertions(+)
> > > > >  create mode 100755 tests/generic/600
> > > > >  create mode 100644 tests/generic/600.out
> > > > > 
> > > > > diff --git a/common/quota b/common/quota
> > > > > index 240e0bbc..1437d5f7 100644
> > > > > --- a/common/quota
> > > > > +++ b/common/quota
> > > > > @@ -217,6 +217,10 @@ _qmount()
> > > > >      if [ "$FSTYP" != "xfs" ]; then
> > > > >          quotacheck -ug $SCRATCH_MNT >>$seqres.full 2>&1
> > > > >          quotaon -ug $SCRATCH_MNT >>$seqres.full 2>&1
> > > > > +        # try to turn on project quota if it's supported
> > > > > +        if quotaon --help 2>&1 | grep -q '\-\-project'; then
> > > > > +            quotaon --project $SCRATCH_MNT >>$seqres.full 2>&1
> > > > > +        fi
> > > > >      fi
> > > > >      chmod ugo+rwx $SCRATCH_MNT
> > > > >  }
> > > > > diff --git a/tests/generic/600 b/tests/generic/600
> > > > > new file mode 100755
> > > > > index 00000000..03b4dcb3
> > > > > --- /dev/null
> > > > > +++ b/tests/generic/600
> > > > > @@ -0,0 +1,187 @@
> > > > > +#! /bin/bash
> > > > > +# SPDX-License-Identifier: GPL-2.0
> > > > > +# Copyright (c) 2020 Red Hat, Inc.  All Rights Reserved.
> > > > > +#
> > > > > +# FS QA Test No. 600
> > > > > +#
> > > > > +# Test per-type(user, group and project) filesystem quota timers, make sure
> > > > > +# enforcement
> > > > > +#
> > > > > +seq=`basename $0`
> > > > > +seqres=$RESULT_DIR/$seq
> > > > > +echo "QA output created by $seq"
> > > > > +
> > > > > +here=`pwd`
> > > > > +tmp=/tmp/$$
> > > > > +status=1	# failure is the default!
> > > > > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > > > > +
> > > > > +_cleanup()
> > > > > +{
> > > > > +	restore_project
> > > > > +	cd /
> > > > > +	rm -f $tmp.*
> > > > > +}
> > > > > +
> > > > > +# get standard environment, filters and checks
> > > > > +. ./common/rc
> > > > > +. ./common/filter
> > > > > +. ./common/quota
> > > > > +
> > > > > +# remove previous $seqres.full before test
> > > > > +rm -f $seqres.full
> > > > > +
> > > > > +require_project()
> > > > > +{
> > > > > +	rm -f $tmp.projects $tmp.projid
> > > > > +	if [ -f /etc/projects ];then
> > > > > +		cat /etc/projects > $tmp.projects
> > > > > +	fi
> > > > > +	if [ -f /etc/projid ];then
> > > > > +		cat /etc/projid > $tmp.projid
> > > > > +	fi
> > > > > +
> > > > > +	cat >/etc/projects <<EOF
> > > > > +100:$SCRATCH_MNT/t
> > > > > +EOF
> > > > > +	cat >/etc/projid <<EOF
> > > > > +$qa_user:100
> > > > > +EOF
> > > > > +	PROJECT_CHANGED=1
> > > > > +}
> > > > > +
> > > > > +restore_project()
> > > > > +{
> > > > > +	if [ "$PROJECT_CHANGED" = "1" ];then
> > > > > +		rm -f /etc/projects /etc/projid
> > > > > +		if [ -f $tmp.projects ];then
> > > > > +			cat $tmp.projects > /etc/projects
> > > > > +		fi
> > > > > +		if [ -f $tmp.projid ];then
> > > > > +			cat $tmp.projid > /etc/projid
> > > > > +		fi
> > > > > +	fi
> > > > > +}
> > > > > +
> > > > > +init_files()
> > > > > +{
> > > > > +	local dir=$1
> > > > > +
> > > > > +	echo "### Initialize files, and their mode and ownership"
> > > > > +	touch $dir/file{1,2} 2>/dev/null
> > > > > +	chown $qa_user $dir/file{1,2} 2>/dev/null
> > > > > +	chgrp $qa_user $dir/file{1,2} 2>/dev/null
> > > > > +	chmod 777 $dir 2>/dev/null
> > > > > +}
> > > > > +
> > > > > +cleanup_files()
> > > > > +{
> > > > > +	echo "### Remove all files"
> > > > > +	rm -f ${1}/file{1,2,3,4,5,6}
> > > > > +}
> > > > > +
> > > > > +test_grace()
> > > > > +{
> > > > > +	local type=$1
> > > > > +	local dir=$2
> > > > > +	local bgrace=$3
> > > > > +	local igrace=$4
> > > > > +
> > > > > +	init_files $dir
> > > > > +	echo "--- Test block quota ---"
> > > > > +	# Firstly fit below block soft limit
> > > > > +	echo "Write 225 blocks..."
> > > > > +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((225 * $BLOCK_SIZE))' \
> > > > > +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> > > > > +		_filter_xfs_io_error | tee -a $seqres.full
> > > > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > > > +	# Secondly overcome block soft limit
> > > > > +	echo "Rewrite 250 blocks plus 1 byte, over the block softlimit..."
> > > > > +	su $qa_user -c "$XFS_IO_PROG -c 'pwrite 0 $((250 * $BLOCK_SIZE + 1))' \
> > > > > +		-c fsync $dir/file1" 2>&1 >>$seqres.full | \
> > > > > +		_filter_xfs_io_error | tee -a $seqres.full
> > > > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > > > +	# Reset grace time here, make below grace time test more accurate
> > > > > +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> > > > > +	# Now sleep enough grace time and check that softlimit got enforced
> > > > > +	sleep $((bgrace + 1))
> > > > > +	echo "Try to write 1 one more block after grace..."
> > > > > +	su $qa_user -c "$XFS_IO_PROG -c 'truncate 0' -c 'pwrite 0 $BLOCK_SIZE' \
> > > > > +		$dir/file2" 2>&1 >>$seqres.full | _filter_xfs_io_error | \
> > > > > +		tee -a $seqres.full
> > > > > +	repquota -v -$type $SCRATCH_MNT | grep -v "^root" >>$seqres.full 2>&1
> > > > > +	echo "--- Test inode quota ---"
> > > > > +	# And now the softlimit test for inodes
> > > > > +	# First reset space limits so that we don't have problems with
> > > > > +	# space reservations on XFS
> > > > > +	setquota -$type $qa_user 0 0 3 100 $SCRATCH_MNT
> > > > > +	echo "Create 2 more files, over the inode softlimit..."
> > > > > +	su $qa_user -c "touch $dir/file3 $dir/file4" 2>&1 >>$seqres.full | \
> > > > > +		_filter_scratch | tee -a $seqres.full
> > > > > +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> > > > > +	# Reset grace time here, make below grace time test more accurate
> > > > > +	setquota -$type $qa_user -T $bgrace $igrace $SCRATCH_MNT 2>/dev/null
> > > > > +	# Wait and check grace time enforcement
> > > > > +	sleep $((igrace+1))
> > > > > +	echo "Try to create one more inode after grace..."
> > > > > +	su $qa_user -c "touch $dir/file5" 2>&1 >>$seqres.full |
> > > > > +		_filter_scratch | tee -a $seqres.full
> > > > > +	repquota -v -$type $SCRATCH_MNT  | grep -v "^root" >>$seqres.full 2>&1
> > > > > +	cleanup_files $dir
> > > > > +}
> > > > > +
> > > > > +# real QA test starts here
> > > > > +_supported_fs generic
> > > > > +_supported_os Linux
> > > > > +_require_scratch
> > > > > +_require_setquota_project
> > > > > +_require_quota
> > > > > +_require_user
> > > > > +_require_group
> > > > 
> > > > Hmm, also needs _require_scratch_xfs_crc when FSTYP is xfs, otherwise v4
> > > > xfs fails as
> > > > 
> > > > +mount: /mnt/scratch: wrong fs type, bad option, bad superblock on /dev/mapper/testvg-lv2, missing codepage or helper program, or other error.
> > > > +qmount failed
> > > > 
> > > > and dmesg says
> > > > 
> > > > XFS (dm-2): Super block does not support project and group quota together
> > > > 
> > > > Thanks,
> > > > Eryu
> > > > 
> > > > > +
> > > > > +_scratch_mkfs >$seqres.full 2>&1
> > > > > +_scratch_enable_pquota
> > > > > +_qmount_option "usrquota,grpquota,prjquota"
> > > > > +_qmount
> > > > > +_require_prjquota $SCRATCH_DEV
> > > > > +BLOCK_SIZE=$(_get_file_block_size $SCRATCH_MNT)
> > > > > +rm -rf $SCRATCH_MNT/t
> > > > > +mkdir $SCRATCH_MNT/t
> > > > > +$XFS_IO_PROG -r -c "chproj 100" -c "chattr +P" $SCRATCH_MNT/t
> > > > > +require_project
> > > > > +
> > > > > +echo "### Set up different grace timers to each type of quota"
> > > > > +UBGRACE=12
> > > > > +UIGRACE=10
> > > > > +GBGRACE=4
> > > > > +GIGRACE=2
> > > > > +PBGRACE=8
> > > > > +PIGRACE=6
> > > > > +
> > > > > +setquota -u $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > > > +setquota -u -t $UBGRACE $UIGRACE $SCRATCH_MNT
> > > > > +echo; echo "### Test user quota softlimit and grace time"
> > > > > +test_grace u $SCRATCH_MNT $UBGRACE $UIGRACE
> > > > > +# Reset the user quota space & inode limits, avoid it affect later test
> > > > > +setquota -u $qa_user 0 0 0 0 $SCRATCH_MNT
> > > > > +
> > > > > +setquota -g $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > > > +setquota -g -t $GBGRACE $GIGRACE $SCRATCH_MNT
> > > > > +echo; echo "### Test group quota softlimit and grace time"
> > > > > +test_grace g $SCRATCH_MNT $GBGRACE $GIGRACE
> > > > > +# Reset the group quota space & inode limits, avoid it affect later test
> > > > > +setquota -g $qa_user 0 0 0 0 $SCRATCH_MNT
> > > > > +
> > > > > +setquota -P $qa_user $((250 * $BLOCK_SIZE / 1024)) \
> > > > > +	$((1000 * $BLOCK_SIZE / 1024)) 3 100 $SCRATCH_MNT
> > > > > +setquota -P -t $PBGRACE $PIGRACE $SCRATCH_MNT
> > > > > +echo; echo "### Test project quota softlimit and grace time"
> > > > > +test_grace P $SCRATCH_MNT/t $PBGRACE $PIGRACE
> > > > > +# Reset the project quota space & inode limits
> > > > > +setquota -P $qa_user 0 0 0 0 $SCRATCH_MNT
> > > > > +
> > > > > +# success, all done
> > > > > +status=0
> > > > > +exit
> > > > > diff --git a/tests/generic/600.out b/tests/generic/600.out
> > > > > new file mode 100644
> > > > > index 00000000..6e15eaeb
> > > > > --- /dev/null
> > > > > +++ b/tests/generic/600.out
> > > > > @@ -0,0 +1,41 @@
> > > > > +QA output created by 600
> > > > > +### Set up different grace timers to each type of quota
> > > > > +
> > > > > +### Test user quota softlimit and grace time
> > > > > +### Initialize files, and their mode and ownership
> > > > > +--- Test block quota ---
> > > > > +Write 225 blocks...
> > > > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > > > +Try to write 1 one more block after grace...
> > > > > +pwrite: Disk quota exceeded
> > > > > +--- Test inode quota ---
> > > > > +Create 2 more files, over the inode softlimit...
> > > > > +Try to create one more inode after grace...
> > > > > +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> > > > > +### Remove all files
> > > > > +
> > > > > +### Test group quota softlimit and grace time
> > > > > +### Initialize files, and their mode and ownership
> > > > > +--- Test block quota ---
> > > > > +Write 225 blocks...
> > > > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > > > +Try to write 1 one more block after grace...
> > > > > +pwrite: Disk quota exceeded
> > > > > +--- Test inode quota ---
> > > > > +Create 2 more files, over the inode softlimit...
> > > > > +Try to create one more inode after grace...
> > > > > +touch: cannot touch 'SCRATCH_MNT/file5': Disk quota exceeded
> > > > > +### Remove all files
> > > > > +
> > > > > +### Test project quota softlimit and grace time
> > > > > +### Initialize files, and their mode and ownership
> > > > > +--- Test block quota ---
> > > > > +Write 225 blocks...
> > > > > +Rewrite 250 blocks plus 1 byte, over the block softlimit...
> > > > > +Try to write 1 one more block after grace...
> > > > > +pwrite: Disk quota exceeded
> > > > > +--- Test inode quota ---
> > > > > +Create 2 more files, over the inode softlimit...
> > > > > +Try to create one more inode after grace...
> > > > > +touch: cannot touch 'SCRATCH_MNT/t/file5': Disk quota exceeded
> > > > > +### Remove all files
> > > > 
> > > 
> > 
> 

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2020-06-11 15:40 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-18 18:46 [PATCH 0/SEVERAL] xfs, xfstests, xfsprogs: quota timer updates Eric Sandeen
2020-05-18 18:48 ` [PATCH 0/6] xfs: quota timer enhancements Eric Sandeen
2020-05-18 18:48   ` [PATCH 1/6] xfs: group quota should return EDQUOT when prj quota enabled Eric Sandeen
2020-05-19 16:22     ` Darrick J. Wong
2020-05-18 18:49   ` [PATCH 2/6] xfs: always return -ENOSPC on project quota reservation failure Eric Sandeen
2020-05-19 16:18     ` Darrick J. Wong
2020-05-18 18:49   ` [PATCH 3/6] xfs: fix up some whitespace in quota code Eric Sandeen
2020-05-19 16:25     ` Darrick J. Wong
2020-05-18 18:50   ` [PATCH 4/6] xfs: pass xfs_dquot to xfs_qm_adjust_dqtimers Eric Sandeen
2020-05-19 16:26     ` Darrick J. Wong
2020-05-18 18:51   ` [PATCH 5/6] xfs: per-type quota timers and warn limits Eric Sandeen
2020-05-19 16:27     ` Darrick J. Wong
2020-05-20 18:41     ` [PATCH 4.5/6] xfs: switch xfs_get_defquota to take explicit type Eric Sandeen
2020-05-20 20:36       ` Darrick J. Wong
2020-05-20 20:41         ` Eric Sandeen
2020-05-20 20:49           ` Darrick J. Wong
2020-05-20 18:43     ` [PATCH 5/6 V2] xfs: per-type quota timers and warn limits Eric Sandeen
2020-05-20 20:31       ` Darrick J. Wong
2020-05-20 20:42         ` Eric Sandeen
2020-05-18 18:52   ` [PATCH 6/6] xfs: allow individual quota grace period extension Eric Sandeen
2020-05-19 16:39     ` Darrick J. Wong
2020-05-19 17:21       ` Eric Sandeen
2020-05-18 19:23 ` [PATCH 0/1] xfs_quota: allow individual timer extension Eric Sandeen
2020-05-18 19:24   ` [PATCH 1/1] " Eric Sandeen
2020-05-18 20:04     ` Eric Sandeen
2020-05-18 20:09     ` [PATCH 1/1 V2] " Eric Sandeen
2020-05-19 16:38       ` Darrick J. Wong
2020-05-19 21:34         ` Darrick J. Wong
2020-05-18 19:59 ` [PATCH 0/4] fstests: more quota related tests Eric Sandeen
2020-05-18 19:59   ` [PATCH 1/4] xfs: make sure our default quota warning limits and grace periods survive quotacheck Eric Sandeen
2020-05-31 16:17     ` Eryu Guan
2020-05-18 20:00   ` [PATCH 2/4] generic: test per-type quota softlimit enforcement timeout Eric Sandeen
2020-05-31 16:15     ` Eryu Guan
2020-06-01 12:48       ` Zorro Lang
2020-06-01 14:36         ` Eric Sandeen
2020-06-01 16:39         ` Darrick J. Wong
2020-06-11  5:12           ` Zorro Lang
2020-06-11 15:40             ` Darrick J. Wong
2020-05-18 20:00   ` [PATCH 3/4] fstests: individual user grace period extension via setquota Eric Sandeen
2020-05-18 20:01   ` [PATCH 4/4] fstests: individual user grace period extension via xfs_quota Eric Sandeen
2020-05-20 15:39   ` [PATCH 0/4] fstests: more quota related tests Darrick J. Wong
2020-05-20 15:46     ` Eric Sandeen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.