From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> Create an in-core timestamp that will tell us when a quota's grace period expires. In the subsequent bigtime patchset we will sacrifice precision in the on-disk grace period timestamp to enable larger timestamps across the filesystem, but we'll maintain an incore copy so that we can maintain precision so long as the filesystem isn't unmounted. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_dquot_buf.c | 17 +++++++++++++++++ fs/xfs/libxfs/xfs_quota_defs.h | 2 ++ fs/xfs/xfs_dquot.c | 40 +++++++++++++++++++++++++++------------- fs/xfs/xfs_dquot.h | 8 ++++++++ fs/xfs/xfs_qm.c | 38 ++++++++++++++++++++++++++------------ fs/xfs/xfs_qm_syscalls.c | 26 +++++++++++++++----------- fs/xfs/xfs_trans_dquot.c | 8 ++++---- 7 files changed, 99 insertions(+), 40 deletions(-) diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c index bedc1e752b60..72e0fcfef580 100644 --- a/fs/xfs/libxfs/xfs_dquot_buf.c +++ b/fs/xfs/libxfs/xfs_dquot_buf.c @@ -287,3 +287,20 @@ const struct xfs_buf_ops xfs_dquot_buf_ra_ops = { .verify_read = xfs_dquot_buf_readahead_verify, .verify_write = xfs_dquot_buf_write_verify, }; + +void +xfs_dquot_from_disk_timestamp( + struct timespec64 *tv, + __be32 dtimer) +{ + tv->tv_nsec = 0; + tv->tv_sec = be32_to_cpu(dtimer); +} + +void +xfs_dquot_to_disk_timestamp( + __be32 *dtimer, + const struct timespec64 *tv) +{ + *dtimer = cpu_to_be32(tv->tv_sec); +} diff --git a/fs/xfs/libxfs/xfs_quota_defs.h b/fs/xfs/libxfs/xfs_quota_defs.h index b2113b17e53c..c453611ade3b 100644 --- a/fs/xfs/libxfs/xfs_quota_defs.h +++ b/fs/xfs/libxfs/xfs_quota_defs.h @@ -144,5 +144,7 @@ extern xfs_failaddr_t xfs_dqblk_verify(struct xfs_mount *mp, extern int xfs_calc_dquots_per_chunk(unsigned int nbblks); extern void xfs_dqblk_repair(struct xfs_mount *mp, struct xfs_dqblk *dqb, xfs_dqid_t id, uint type); +void xfs_dquot_from_disk_timestamp(struct timespec64 *tv, __be32 dtimer); +void xfs_dquot_to_disk_timestamp(__be32 *dtimer, const struct timespec64 *tv); #endif /* __XFS_QUOTA_H__ */ diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index 44bae5f16b55..763e974f7aad 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c @@ -126,21 +126,27 @@ xfs_dquot_clamp_timer( /* Set a quota grace period expiration timer. */ static inline void xfs_quota_set_timer( + time64_t *itimer, __be32 *dtimer, time_t limit) { - time64_t new_timeout; + struct timespec64 tv = { 0 }; - new_timeout = xfs_dquot_clamp_timer(get_seconds() + limit); - *dtimer = cpu_to_be32(new_timeout); + tv.tv_sec = xfs_dquot_clamp_timer(ktime_get_real_seconds() + limit); + *itimer = tv.tv_sec; + xfs_dquot_to_disk_timestamp(dtimer, &tv); } /* Clear a quota grace period expiration timer. */ static inline void xfs_quota_clear_timer( + time64_t *itimer, __be32 *dtimer) { - *dtimer = cpu_to_be32(0); + struct timespec64 tv = { 0 }; + + *itimer = tv.tv_sec; + xfs_dquot_to_disk_timestamp(dtimer, &tv); } /* @@ -180,46 +186,46 @@ xfs_qm_adjust_dqtimers( over = xfs_quota_exceeded(&d->d_bcount, dqp->q_ina_bcount, &d->d_blk_softlimit, &d->d_blk_hardlimit); - if (!d->d_btimer) { + if (!dqp->q_btimer) { if (over) { - xfs_quota_set_timer(&d->d_btimer, + xfs_quota_set_timer(&dqp->q_btimer, &d->d_btimer, mp->m_quotainfo->qi_btimelimit); } else { d->d_bwarns = 0; } } else { if (!over) { - xfs_quota_clear_timer(&d->d_btimer); + xfs_quota_clear_timer(&dqp->q_btimer, &d->d_btimer); } } over = xfs_quota_exceeded(&d->d_icount, dqp->q_ina_icount, &d->d_ino_softlimit, &d->d_ino_hardlimit); - if (!d->d_itimer) { + if (!dqp->q_itimer) { if (over) { - xfs_quota_set_timer(&d->d_itimer, + xfs_quota_set_timer(&dqp->q_itimer, &d->d_itimer, mp->m_quotainfo->qi_itimelimit); } else { d->d_iwarns = 0; } } else { if (!over) { - xfs_quota_clear_timer(&d->d_itimer); + xfs_quota_clear_timer(&dqp->q_itimer, &d->d_itimer); } } over = xfs_quota_exceeded(&d->d_rtbcount, dqp->q_ina_rtbcount, &d->d_rtb_softlimit, &d->d_rtb_hardlimit); - if (!d->d_rtbtimer) { + if (!dqp->q_rtbtimer) { if (over) { - xfs_quota_set_timer(&d->d_rtbtimer, + xfs_quota_set_timer(&dqp->q_rtbtimer, &d->d_rtbtimer, mp->m_quotainfo->qi_rtbtimelimit); } else { d->d_rtbwarns = 0; } } else { if (!over) { - xfs_quota_clear_timer(&d->d_rtbtimer); + xfs_quota_clear_timer(&dqp->q_rtbtimer, &d->d_rtbtimer); } } } @@ -520,6 +526,7 @@ xfs_dquot_from_disk( struct xfs_dquot *dqp, struct xfs_buf *bp) { + struct timespec64 tv; struct xfs_disk_dquot *ddqp = bp->b_addr + dqp->q_bufoffset; /* copy everything from disk dquot to the incore dquot */ @@ -533,6 +540,13 @@ xfs_dquot_from_disk( dqp->q_res_icount = be64_to_cpu(ddqp->d_icount); dqp->q_res_rtbcount = be64_to_cpu(ddqp->d_rtbcount); + xfs_dquot_from_disk_timestamp(&tv, ddqp->d_btimer); + dqp->q_btimer = tv.tv_sec; + xfs_dquot_from_disk_timestamp(&tv, ddqp->d_itimer); + dqp->q_itimer = tv.tv_sec; + xfs_dquot_from_disk_timestamp(&tv, ddqp->d_rtbtimer); + dqp->q_rtbtimer = tv.tv_sec; + /* initialize the dquot speculative prealloc thresholds */ xfs_dquot_set_prealloc_limits(dqp); } diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h index d924da98f66a..99c0d6266fd8 100644 --- a/fs/xfs/xfs_dquot.h +++ b/fs/xfs/xfs_dquot.h @@ -60,6 +60,14 @@ struct xfs_dquot { xfs_qcnt_t q_prealloc_lo_wmark; xfs_qcnt_t q_prealloc_hi_wmark; int64_t q_low_space[XFS_QLOWSP_MAX]; + + /* incore block grace timeout */ + time64_t q_btimer; + /* incore inode grace timeout */ + time64_t q_itimer; + /* incore rt block grace timeout */ + time64_t q_rtbtimer; + struct mutex q_qlock; struct completion q_flush; atomic_t q_pincount; diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 268e028c9ec8..9be123a0902e 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -589,6 +589,7 @@ xfs_qm_init_timelimits( struct xfs_mount *mp, struct xfs_quotainfo *qinf) { + struct timespec64 tv; struct xfs_disk_dquot *ddqp; struct xfs_dquot *dqp; uint type; @@ -628,12 +629,18 @@ xfs_qm_init_timelimits( * 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); - if (ddqp->d_itimer) - qinf->qi_itimelimit = be32_to_cpu(ddqp->d_itimer); - if (ddqp->d_rtbtimer) - qinf->qi_rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer); + if (ddqp->d_btimer) { + xfs_dquot_from_disk_timestamp(&tv, ddqp->d_btimer); + qinf->qi_btimelimit = tv.tv_sec; + } + if (ddqp->d_itimer) { + xfs_dquot_from_disk_timestamp(&tv, ddqp->d_itimer); + qinf->qi_itimelimit = tv.tv_sec; + } + if (ddqp->d_rtbtimer) { + xfs_dquot_from_disk_timestamp(&tv, ddqp->d_rtbtimer); + qinf->qi_rtbtimelimit = tv.tv_sec; + } if (ddqp->d_bwarns) qinf->qi_bwarnlimit = be16_to_cpu(ddqp->d_bwarns); if (ddqp->d_iwarns) @@ -848,16 +855,23 @@ xfs_qm_reset_dqintervals( struct xfs_mount *mp, struct xfs_disk_dquot *ddq) { + struct timespec64 tv = { 0 }; struct xfs_quotainfo *qinf = mp->m_quotainfo; - if (qinf->qi_btimelimit != XFS_QM_BTIMELIMIT) - ddq->d_btimer = cpu_to_be32(qinf->qi_btimelimit); + if (qinf->qi_btimelimit != XFS_QM_BTIMELIMIT) { + tv.tv_sec = qinf->qi_btimelimit; + xfs_dquot_to_disk_timestamp(&ddq->d_btimer, &tv); + } - if (qinf->qi_itimelimit != XFS_QM_ITIMELIMIT) - ddq->d_itimer = cpu_to_be32(qinf->qi_itimelimit); + if (qinf->qi_itimelimit != XFS_QM_ITIMELIMIT) { + tv.tv_sec = qinf->qi_itimelimit; + xfs_dquot_to_disk_timestamp(&ddq->d_itimer, &tv); + } - if (qinf->qi_rtbtimelimit != XFS_QM_RTBTIMELIMIT) - ddq->d_rtbtimer = cpu_to_be32(qinf->qi_rtbtimelimit); + if (qinf->qi_rtbtimelimit != XFS_QM_RTBTIMELIMIT) { + tv.tv_sec = qinf->qi_rtbtimelimit; + xfs_dquot_to_disk_timestamp(&ddq->d_rtbtimer, &tv); + } } STATIC void diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 20a6d304d1be..bd9db42b89b9 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c @@ -442,14 +442,17 @@ xfs_qm_scall_quotaon( static inline void xfs_qm_set_grace( time_t *qi_limit, + time64_t *itimer, __be32 *dtimer, const s64 grace) { - time64_t new_grace; + struct timespec64 tv = { 0 }; - new_grace = clamp_t(time64_t, grace, XFS_DQ_GRACE_MIN, + tv.tv_sec = clamp_t(time64_t, grace, XFS_DQ_GRACE_MIN, XFS_DQ_GRACE_MAX); - *dtimer = cpu_to_be32(new_grace); + *qi_limit = tv.tv_sec; + *itimer = tv.tv_sec; + xfs_dquot_to_disk_timestamp(dtimer, &tv); } #define XFS_QC_MASK \ @@ -582,13 +585,14 @@ xfs_qm_scall_setqlim( * for warnings. */ if (newlim->d_fieldmask & QC_SPC_TIMER) - xfs_qm_set_grace(&q->qi_btimelimit, &ddq->d_btimer, - newlim->d_spc_timer); + xfs_qm_set_grace(&q->qi_btimelimit, &dqp->q_btimer, + &ddq->d_btimer, newlim->d_spc_timer); if (newlim->d_fieldmask & QC_INO_TIMER) - xfs_qm_set_grace(&q->qi_itimelimit, &ddq->d_itimer, - newlim->d_ino_timer); + xfs_qm_set_grace(&q->qi_itimelimit, &dqp->q_itimer, + &ddq->d_itimer, newlim->d_ino_timer); if (newlim->d_fieldmask & QC_RT_SPC_TIMER) - xfs_qm_set_grace(&q->qi_rtbtimelimit, &ddq->d_rtbtimer, + xfs_qm_set_grace(&q->qi_rtbtimelimit, &dqp->q_rtbtimer, + &ddq->d_rtbtimer, newlim->d_rt_spc_timer); if (newlim->d_fieldmask & QC_SPC_WARNS) q->qi_bwarnlimit = newlim->d_spc_warns; @@ -635,8 +639,8 @@ xfs_qm_scall_getquota_fill_qc( dst->d_ino_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit); dst->d_space = XFS_FSB_TO_B(mp, dqp->q_res_bcount - dqp->q_ina_bcount); dst->d_ino_count = dqp->q_res_icount - dqp->q_ina_icount; - dst->d_spc_timer = be32_to_cpu(dqp->q_core.d_btimer); - dst->d_ino_timer = be32_to_cpu(dqp->q_core.d_itimer); + dst->d_spc_timer = dqp->q_btimer; + dst->d_ino_timer = dqp->q_itimer; dst->d_ino_warns = be16_to_cpu(dqp->q_core.d_iwarns); dst->d_spc_warns = be16_to_cpu(dqp->q_core.d_bwarns); dst->d_rt_spc_hardlimit = @@ -645,7 +649,7 @@ xfs_qm_scall_getquota_fill_qc( XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit)); dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_res_rtbcount - dqp->q_ina_rtbcount); - dst->d_rt_spc_timer = be32_to_cpu(dqp->q_core.d_rtbtimer); + dst->d_rt_spc_timer = dqp->q_rtbtimer; dst->d_rt_spc_warns = be16_to_cpu(dqp->q_core.d_rtbwarns); /* diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c index 7a2a3bd11db9..62ef99f705df 100644 --- a/fs/xfs/xfs_trans_dquot.c +++ b/fs/xfs/xfs_trans_dquot.c @@ -568,7 +568,7 @@ static inline bool xfs_quota_timer_exceeded( time64_t timer) { - return timer != 0 && get_seconds() > timer; + return timer != 0 && ktime_get_real_seconds() > timer; } /* @@ -608,7 +608,7 @@ xfs_trans_dqresv( softlimit = be64_to_cpu(dqp->q_core.d_blk_softlimit); if (!softlimit) softlimit = defq->bsoftlimit; - timer = be32_to_cpu(dqp->q_core.d_btimer); + timer = dqp->q_btimer; warns = be16_to_cpu(dqp->q_core.d_bwarns); warnlimit = dqp->q_mount->m_quotainfo->qi_bwarnlimit; resbcountp = &dqp->q_res_bcount; @@ -620,7 +620,7 @@ xfs_trans_dqresv( softlimit = be64_to_cpu(dqp->q_core.d_rtb_softlimit); if (!softlimit) softlimit = defq->rtbsoftlimit; - timer = be32_to_cpu(dqp->q_core.d_rtbtimer); + timer = dqp->q_rtbtimer; warns = be16_to_cpu(dqp->q_core.d_rtbwarns); warnlimit = dqp->q_mount->m_quotainfo->qi_rtbwarnlimit; resbcountp = &dqp->q_res_rtbcount; @@ -655,7 +655,7 @@ xfs_trans_dqresv( } if (ninos > 0) { total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos; - timer = be32_to_cpu(dqp->q_core.d_itimer); + timer = dqp->q_itimer; warns = be16_to_cpu(dqp->q_core.d_iwarns); warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit; hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);