From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> 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. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_format.h | 22 ++++++++++++++++++++++ fs/xfs/xfs_dquot.c | 42 ++++++++++++++++++++++++++++++++++++------ fs/xfs/xfs_ondisk.h | 2 ++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index 82b15832ba32..95761b38fe86 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -1180,6 +1180,28 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev) #define XFS_DQUOT_MAGIC 0x4451 /* 'DQ' */ #define XFS_DQUOT_VERSION (uint8_t)0x01 /* latest version number */ +/* + * XFS Quota Timers + * ================ + * + * 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. An expiration value + * of zero means that the quota limit has not been reached, and therefore no + * expiration has been set. + */ + +/* + * Smallest possible quota expiration with traditional timestamps, which is + * Jan 1 00:00:01 UTC 1970. + */ +#define XFS_DQ_TIMEOUT_MIN ((int64_t)1) + +/* + * Largest possible quota expiration with traditional timestamps, which is + * Feb 7 06:28:15 UTC 2106. + */ +#define XFS_DQ_TIMEOUT_MAX ((int64_t)U32_MAX) + /* * This is the main portion of the on-disk representation of quota * information for a user. This is the q_core of the struct xfs_dquot that diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index ae7bb6361a99..44bae5f16b55 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -113,6 +113,36 @@ xfs_quota_exceeded( return *hardlimit && count > be64_to_cpup(hardlimit); } +/* + * Clamp a quota grace period expiration timer to the range that we support. + */ +static inline time64_t +xfs_dquot_clamp_timer( + time64_t timer) +{ + return clamp_t(time64_t, timer, XFS_DQ_TIMEOUT_MIN, XFS_DQ_TIMEOUT_MAX); +} + +/* Set a quota grace period expiration timer. */ +static inline void +xfs_quota_set_timer( + __be32 *dtimer, + time_t limit) +{ + time64_t new_timeout; + + new_timeout = xfs_dquot_clamp_timer(get_seconds() + limit); + *dtimer = cpu_to_be32(new_timeout); +} + +/* Clear a quota grace period expiration timer. */ +static inline void +xfs_quota_clear_timer( + __be32 *dtimer) +{ + *dtimer = cpu_to_be32(0); +} + /* * Check the limits and timers of a dquot and start or reset timers * if necessary. @@ -152,14 +182,14 @@ xfs_qm_adjust_dqtimers( &d->d_blk_softlimit, &d->d_blk_hardlimit); if (!d->d_btimer) { if (over) { - d->d_btimer = cpu_to_be32(get_seconds() + + xfs_quota_set_timer(&d->d_btimer, mp->m_quotainfo->qi_btimelimit); } else { d->d_bwarns = 0; } } else { if (!over) { - d->d_btimer = 0; + xfs_quota_clear_timer(&d->d_btimer); } } @@ -167,14 +197,14 @@ xfs_qm_adjust_dqtimers( &d->d_ino_softlimit, &d->d_ino_hardlimit); if (!d->d_itimer) { if (over) { - d->d_itimer = cpu_to_be32(get_seconds() + + xfs_quota_set_timer(&d->d_itimer, mp->m_quotainfo->qi_itimelimit); } else { d->d_iwarns = 0; } } else { if (!over) { - d->d_itimer = 0; + xfs_quota_clear_timer(&d->d_itimer); } } @@ -182,14 +212,14 @@ xfs_qm_adjust_dqtimers( &d->d_rtb_softlimit, &d->d_rtb_hardlimit); if (!d->d_rtbtimer) { if (over) { - d->d_rtbtimer = cpu_to_be32(get_seconds() + + xfs_quota_set_timer(&d->d_rtbtimer, mp->m_quotainfo->qi_rtbtimelimit); } else { d->d_rtbwarns = 0; } } else { if (!over) { - d->d_rtbtimer = 0; + xfs_quota_clear_timer(&d->d_rtbtimer); } } } diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h index f67f3645efcd..52dc5326b7bf 100644 --- a/fs/xfs/xfs_ondisk.h +++ b/fs/xfs/xfs_ondisk.h @@ -25,6 +25,8 @@ xfs_check_ondisk_structs(void) /* make sure timestamp limits are correct */ XFS_CHECK_VALUE(XFS_INO_TIME_MIN, -2147483648LL); XFS_CHECK_VALUE(XFS_INO_TIME_MAX, 2147483647LL); + XFS_CHECK_VALUE(XFS_DQ_TIMEOUT_MIN, 1LL); + XFS_CHECK_VALUE(XFS_DQ_TIMEOUT_MAX, 4294967295LL); /* ag/file structures */ XFS_CHECK_STRUCT_SIZE(struct xfs_acl, 4);