xfs: refactor quota expiration timer modification
authorDarrick J. Wong <darrick.wong@oracle.com>
Mon, 17 Aug 2020 16:58:36 +0000 (09:58 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 16 Sep 2020 03:52:40 +0000 (20:52 -0700)
Define explicit limits on the range of quota grace period expiration
timeouts and refactor the code that modifies the timeouts into helpers
that clamp the values appropriately.  Note that we'll refactor the
default grace period timer separately.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/libxfs/xfs_format.h
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm.h
fs/xfs/xfs_qm_syscalls.c

index e57360a8fd164d843c2548677110531e66ad860f..cb316053d3db01b9157984477a7a75d565be1d83 100644 (file)
@@ -1199,6 +1199,30 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
 
 #define XFS_DQTYPE_ANY         (XFS_DQTYPE_REC_MASK)
 
+/*
+ * XFS Quota Timers
+ * ================
+ *
+ * Traditional quota grace period expiration timers are an unsigned 32-bit
+ * seconds counter; time zero is the Unix epoch, Jan  1 00:00:01 UTC 1970.
+ * Note that an expiration value of zero means that the quota limit has not
+ * been reached, and therefore no expiration has been set.  Therefore, the
+ * ondisk min and max defined here can be used directly to constrain the incore
+ * quota expiration timestamps on a Unix system.
+ */
+
+/*
+ * Smallest possible ondisk quota expiration value with traditional timestamps.
+ * This corresponds exactly with the incore expiration Jan  1 00:00:01 UTC 1970.
+ */
+#define XFS_DQ_LEGACY_EXPIRY_MIN       ((int64_t)1)
+
+/*
+ * Largest possible ondisk quota expiration value with traditional timestamps.
+ * This corresponds exactly with the incore expiration Feb  7 06:28:15 UTC 2106.
+ */
+#define XFS_DQ_LEGACY_EXPIRY_MAX       ((int64_t)U32_MAX)
+
 /*
  * This is the main portion of the on-disk representation of quota information
  * for a user.  We pad this with some more expansion room to construct the on
index 0dcd912befb199b45600cd8bd8d3244d1498fe9e..efe8a71998fc0868ddd1a0057779a0753e3d48b6 100644 (file)
@@ -98,12 +98,25 @@ xfs_qm_adjust_dqlimits(
                xfs_dquot_set_prealloc_limits(dq);
 }
 
+/* Set the expiration time of a quota's grace period. */
+time64_t
+xfs_dquot_set_timeout(
+       struct xfs_mount        *mp,
+       time64_t                timeout)
+{
+       struct xfs_quotainfo    *qi = mp->m_quotainfo;
+
+       return clamp_t(time64_t, timeout, qi->qi_expiry_min,
+                                         qi->qi_expiry_max);
+}
+
 /*
  * Determine if this quota counter is over either limit and set the quota
  * timers as appropriate.
  */
 static inline void
 xfs_qm_adjust_res_timer(
+       struct xfs_mount        *mp,
        struct xfs_dquot_res    *res,
        struct xfs_quota_limits *qlim)
 {
@@ -112,7 +125,8 @@ xfs_qm_adjust_res_timer(
        if ((res->softlimit && res->count > res->softlimit) ||
            (res->hardlimit && res->count > res->hardlimit)) {
                if (res->timer == 0)
-                       res->timer = ktime_get_real_seconds() + qlim->time;
+                       res->timer = xfs_dquot_set_timeout(mp,
+                                       ktime_get_real_seconds() + qlim->time);
        } else {
                if (res->timer == 0)
                        res->warnings = 0;
@@ -145,9 +159,9 @@ xfs_qm_adjust_dqtimers(
        ASSERT(dq->q_id);
        defq = xfs_get_defquota(qi, xfs_dquot_type(dq));
 
-       xfs_qm_adjust_res_timer(&dq->q_blk, &defq->blk);
-       xfs_qm_adjust_res_timer(&dq->q_ino, &defq->ino);
-       xfs_qm_adjust_res_timer(&dq->q_rtb, &defq->rtb);
+       xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_blk, &defq->blk);
+       xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_ino, &defq->ino);
+       xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_rtb, &defq->rtb);
 }
 
 /*
index 282a65da93c799ea6e9cf1d54234b1b4d9e40b3c..0e449101c8610cc827d088abf164b97565937f0d 100644 (file)
@@ -237,4 +237,6 @@ typedef int (*xfs_qm_dqiterate_fn)(struct xfs_dquot *dq,
 int xfs_qm_dqiterate(struct xfs_mount *mp, xfs_dqtype_t type,
                xfs_qm_dqiterate_fn iter_fn, void *priv);
 
+time64_t xfs_dquot_set_timeout(struct xfs_mount *mp, time64_t timeout);
+
 #endif /* __XFS_DQUOT_H__ */
index be67570badf8d38a6fbd83c0c46a0fa4c6066d42..b83a12ecfc35a7c32c4ef539bcdd12ab7079b614 100644 (file)
@@ -661,6 +661,8 @@ xfs_qm_init_quotainfo(
        /* Precalc some constants */
        qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
        qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
+       qinf->qi_expiry_min = XFS_DQ_LEGACY_EXPIRY_MIN;
+       qinf->qi_expiry_max = XFS_DQ_LEGACY_EXPIRY_MAX;
 
        mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
 
index 9c078c35d924d0b6d655abd947f1eab23299b0c6..e3dabab440971ec70c6db2a0d2083d319bab9fd3 100644 (file)
@@ -65,6 +65,10 @@ struct xfs_quotainfo {
        struct xfs_def_quota    qi_grp_default;
        struct xfs_def_quota    qi_prj_default;
        struct shrinker         qi_shrinker;
+
+       /* Minimum and maximum quota expiration timestamp values. */
+       time64_t                qi_expiry_min;
+       time64_t                qi_expiry_max;
 };
 
 static inline struct radix_tree_root *
index 1c542b4a522046098914727a26e63ae40386871c..750f775ae915f8160d864f1bcd7679f6c1734245 100644 (file)
@@ -479,13 +479,19 @@ xfs_setqlim_warns(
 
 static inline void
 xfs_setqlim_timer(
+       struct xfs_mount        *mp,
        struct xfs_dquot_res    *res,
        struct xfs_quota_limits *qlim,
        s64                     timer)
 {
-       res->timer = timer;
-       if (qlim)
+       if (qlim) {
+               /* Set the length of the default grace period. */
+               res->timer = timer;
                qlim->time = timer;
+       } else {
+               /* Set the grace period expiration on a quota. */
+               res->timer = xfs_dquot_set_timeout(mp, timer);
+       }
 }
 
 /*
@@ -574,7 +580,7 @@ xfs_qm_scall_setqlim(
        if (newlim->d_fieldmask & QC_SPC_WARNS)
                xfs_setqlim_warns(res, qlim, newlim->d_spc_warns);
        if (newlim->d_fieldmask & QC_SPC_TIMER)
-               xfs_setqlim_timer(res, qlim, newlim->d_spc_timer);
+               xfs_setqlim_timer(mp, res, qlim, newlim->d_spc_timer);
 
        /* Blocks on the realtime device. */
        hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
@@ -590,7 +596,7 @@ xfs_qm_scall_setqlim(
        if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
                xfs_setqlim_warns(res, qlim, newlim->d_rt_spc_warns);
        if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
-               xfs_setqlim_timer(res, qlim, newlim->d_rt_spc_timer);
+               xfs_setqlim_timer(mp, res, qlim, newlim->d_rt_spc_timer);
 
        /* Inodes */
        hard = (newlim->d_fieldmask & QC_INO_HARD) ?
@@ -606,7 +612,7 @@ xfs_qm_scall_setqlim(
        if (newlim->d_fieldmask & QC_INO_WARNS)
                xfs_setqlim_warns(res, qlim, newlim->d_ino_warns);
        if (newlim->d_fieldmask & QC_INO_TIMER)
-               xfs_setqlim_timer(res, qlim, newlim->d_ino_timer);
+               xfs_setqlim_timer(mp, res, qlim, newlim->d_ino_timer);
 
        if (id != 0) {
                /*