Message ID | 159847951097.2601708.4996467759505702991.stgit@magnolia (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | xfs: widen timestamps to deal with y2038 | expand |
Looks good,
Reviewed-by: Christoph Hellwig <hch@lst.de>
On 8/26/20 3:05 PM, Darrick J. Wong wrote: > From: Darrick J. Wong <darrick.wong@oracle.com> > > 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> Ok, looks ok Reviewed-by: Allison Collins <allison.henderson@oracle.com> > --- > fs/xfs/libxfs/xfs_format.h | 24 ++++++++++++++++++++++++ > fs/xfs/xfs_dquot.c | 22 ++++++++++++++++++---- > fs/xfs/xfs_dquot.h | 2 ++ > fs/xfs/xfs_qm.c | 2 ++ > fs/xfs/xfs_qm.h | 4 ++++ > fs/xfs/xfs_qm_syscalls.c | 16 +++++++++++----- > 6 files changed, 61 insertions(+), 9 deletions(-) > > > diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h > index e57360a8fd16..cb316053d3db 100644 > --- a/fs/xfs/libxfs/xfs_format.h > +++ b/fs/xfs/libxfs/xfs_format.h > @@ -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 > diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c > index bcd73b9c2994..f34841f98d44 100644 > --- a/fs/xfs/xfs_dquot.c > +++ b/fs/xfs/xfs_dquot.c > @@ -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); > } > > /* > diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h > index 282a65da93c7..0e449101c861 100644 > --- a/fs/xfs/xfs_dquot.h > +++ b/fs/xfs/xfs_dquot.h > @@ -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__ */ > diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c > index be67570badf8..b83a12ecfc35 100644 > --- a/fs/xfs/xfs_qm.c > +++ b/fs/xfs/xfs_qm.c > @@ -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); > > diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h > index 9c078c35d924..e3dabab44097 100644 > --- a/fs/xfs/xfs_qm.h > +++ b/fs/xfs/xfs_qm.h > @@ -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 * > diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c > index 1c542b4a5220..750f775ae915 100644 > --- a/fs/xfs/xfs_qm_syscalls.c > +++ b/fs/xfs/xfs_qm_syscalls.c > @@ -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) { > /* >
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h index e57360a8fd16..cb316053d3db 100644 --- a/fs/xfs/libxfs/xfs_format.h +++ b/fs/xfs/libxfs/xfs_format.h @@ -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 diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index bcd73b9c2994..f34841f98d44 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -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); } /* diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h index 282a65da93c7..0e449101c861 100644 --- a/fs/xfs/xfs_dquot.h +++ b/fs/xfs/xfs_dquot.h @@ -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__ */ diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index be67570badf8..b83a12ecfc35 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -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); diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h index 9c078c35d924..e3dabab44097 100644 --- a/fs/xfs/xfs_qm.h +++ b/fs/xfs/xfs_qm.h @@ -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 * diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 1c542b4a5220..750f775ae915 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c @@ -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) { /*