@@ -75,17 +75,17 @@ xfs_dquot_verify(
if (ddq->d_blk_softlimit &&
be64_to_cpu(ddq->d_bcount) > be64_to_cpu(ddq->d_blk_softlimit) &&
- !ddq->d_btimer)
+ !ddq->d_btimer && !ddq->d_btimer_high)
return __this_address;
if (ddq->d_ino_softlimit &&
be64_to_cpu(ddq->d_icount) > be64_to_cpu(ddq->d_ino_softlimit) &&
- !ddq->d_itimer)
+ !ddq->d_itimer && !ddq->d_itimer_high)
return __this_address;
if (ddq->d_rtb_softlimit &&
be64_to_cpu(ddq->d_rtbcount) > be64_to_cpu(ddq->d_rtb_softlimit) &&
- !ddq->d_rtbtimer)
+ !ddq->d_rtbtimer && !ddq->d_rtbtimer_high)
return __this_address;
return NULL;
@@ -1168,7 +1168,10 @@ typedef struct xfs_disk_dquot {
__be32 d_btimer; /* similar to above; for disk blocks */
__be16 d_iwarns; /* warnings issued wrt num inodes */
__be16 d_bwarns; /* warnings issued wrt disk blocks */
- __be32 d_pad0; /* 64 bit align */
+ __u8 d_itimer_high; /* upper bits of d_itimer */
+ __u8 d_btimer_high; /* upper bits of d_btimer */
+ __u8 d_rtbtimer_high;/* upper bits of d_rtbtimer */
+ __u8 d_pad0; /* 64 bit align */
__be64 d_rtb_hardlimit;/* absolute limit on realtime blks */
__be64 d_rtb_softlimit;/* preferred limit on RT disk blks */
__be64 d_rtbcount; /* realtime blocks owned */
@@ -116,6 +116,8 @@ xfs_qm_adjust_dqtimers(
xfs_mount_t *mp,
xfs_disk_dquot_t *d)
{
+ time64_t timer;
+
ASSERT(d->d_id);
#ifdef DEBUG
@@ -130,15 +132,17 @@ xfs_qm_adjust_dqtimers(
be64_to_cpu(d->d_rtb_hardlimit));
#endif
- if (!d->d_btimer) {
+ if (!d->d_btimer && !d->d_btimer_high) {
if ((d->d_blk_softlimit &&
(be64_to_cpu(d->d_bcount) >
be64_to_cpu(d->d_blk_softlimit))) ||
(d->d_blk_hardlimit &&
(be64_to_cpu(d->d_bcount) >
be64_to_cpu(d->d_blk_hardlimit)))) {
- d->d_btimer = cpu_to_be32(get_seconds() +
- mp->m_quotainfo->qi_btimelimit);
+ timer = ktime_get_real_seconds() +
+ mp->m_quotainfo->qi_btimelimit;
+ d->d_btimer = cpu_to_be32(lower_32_bits(timer));
+ d->d_btimer_high = (u8)upper_32_bits(timer);
} else {
d->d_bwarns = 0;
}
@@ -150,18 +154,21 @@ xfs_qm_adjust_dqtimers(
(be64_to_cpu(d->d_bcount) <=
be64_to_cpu(d->d_blk_hardlimit)))) {
d->d_btimer = 0;
+ d->d_btimer_high = 0;
}
}
- if (!d->d_itimer) {
+ if (!d->d_itimer && !d->d_itimer_high) {
if ((d->d_ino_softlimit &&
(be64_to_cpu(d->d_icount) >
be64_to_cpu(d->d_ino_softlimit))) ||
(d->d_ino_hardlimit &&
(be64_to_cpu(d->d_icount) >
be64_to_cpu(d->d_ino_hardlimit)))) {
- d->d_itimer = cpu_to_be32(get_seconds() +
- mp->m_quotainfo->qi_itimelimit);
+ timer = ktime_get_real_seconds() +
+ mp->m_quotainfo->qi_itimelimit;
+ d->d_itimer = cpu_to_be32(lower_32_bits(timer));
+ d->d_itimer_high = (u8)upper_32_bits(timer);
} else {
d->d_iwarns = 0;
}
@@ -173,18 +180,21 @@ xfs_qm_adjust_dqtimers(
(be64_to_cpu(d->d_icount) <=
be64_to_cpu(d->d_ino_hardlimit)))) {
d->d_itimer = 0;
+ d->d_itimer_high = 0;
}
}
- if (!d->d_rtbtimer) {
+ if (!d->d_rtbtimer && !d->d_rtbtimer_high) {
if ((d->d_rtb_softlimit &&
(be64_to_cpu(d->d_rtbcount) >
be64_to_cpu(d->d_rtb_softlimit))) ||
(d->d_rtb_hardlimit &&
(be64_to_cpu(d->d_rtbcount) >
be64_to_cpu(d->d_rtb_hardlimit)))) {
- d->d_rtbtimer = cpu_to_be32(get_seconds() +
- mp->m_quotainfo->qi_rtbtimelimit);
+ timer = ktime_get_real_seconds() +
+ mp->m_quotainfo->qi_rtbtimelimit;
+ d->d_rtbtimer = cpu_to_be32(lower_32_bits(timer));
+ d->d_rtbtimer_high = (u8)upper_32_bits(timer);
} else {
d->d_rtbwarns = 0;
}
@@ -196,6 +206,7 @@ xfs_qm_adjust_dqtimers(
(be64_to_cpu(d->d_rtbcount) <=
be64_to_cpu(d->d_rtb_hardlimit)))) {
d->d_rtbtimer = 0;
+ d->d_rtbtimer_high = 0;
}
}
}
@@ -613,12 +613,15 @@ 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 || ddqp->d_btimer_high)
+ qinf->qi_btimelimit = be32_to_cpu(ddqp->d_btimer) +
+ ((u64)ddqp->d_btimer_high << 32);
+ if (ddqp->d_itimer || ddqp->d_itimer_high)
+ qinf->qi_itimelimit = be32_to_cpu(ddqp->d_itimer) +
+ ((u64)ddqp->d_itimer_high << 32);
+ if (ddqp->d_rtbtimer || ddqp->d_rtbtimer_high)
+ qinf->qi_rtbtimelimit = be32_to_cpu(ddqp->d_rtbtimer) +
+ ((u64)ddqp->d_rtbtimer_high << 32);
if (ddqp->d_bwarns)
qinf->qi_bwarnlimit = be16_to_cpu(ddqp->d_bwarns);
if (ddqp->d_iwarns)
@@ -867,8 +870,11 @@ xfs_qm_reset_dqcounts(
ddq->d_icount = 0;
ddq->d_rtbcount = 0;
ddq->d_btimer = 0;
+ ddq->d_btimer_high = 0;
ddq->d_itimer = 0;
+ ddq->d_itimer_high = 0;
ddq->d_rtbtimer = 0;
+ ddq->d_rtbtimer_high = 0;
ddq->d_bwarns = 0;
ddq->d_iwarns = 0;
ddq->d_rtbwarns = 0;
@@ -64,9 +64,9 @@ typedef struct xfs_quotainfo {
struct xfs_inode *qi_pquotaip; /* project quota inode */
struct list_lru qi_lru;
int qi_dquots;
- time_t qi_btimelimit; /* limit for blks timer */
- time_t qi_itimelimit; /* limit for inodes timer */
- time_t qi_rtbtimelimit;/* limit for rt blks timer */
+ 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 */
@@ -500,15 +500,18 @@ xfs_qm_scall_setqlim(
*/
if (newlim->d_fieldmask & QC_SPC_TIMER) {
q->qi_btimelimit = newlim->d_spc_timer;
- ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
+ ddq->d_btimer = cpu_to_be32(lower_32_bits(newlim->d_spc_timer));
+ ddq->d_btimer_high = (u8)upper_32_bits(newlim->d_spc_timer);
}
if (newlim->d_fieldmask & QC_INO_TIMER) {
q->qi_itimelimit = newlim->d_ino_timer;
- ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
+ ddq->d_itimer = cpu_to_be32(lower_32_bits(newlim->d_ino_timer));
+ ddq->d_itimer_high = (u8)upper_32_bits(newlim->d_ino_timer);
}
if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
q->qi_rtbtimelimit = newlim->d_rt_spc_timer;
ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
+ ddq->d_rtbtimer_high = (u8)upper_32_bits(newlim->d_rt_spc_timer);
}
if (newlim->d_fieldmask & QC_SPC_WARNS)
q->qi_bwarnlimit = newlim->d_spc_warns;
@@ -623,8 +626,10 @@ 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);
dst->d_ino_count = dqp->q_res_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 = be32_to_cpu(dqp->q_core.d_btimer) +
+ ((u64)dqp->q_core.d_btimer_high << 32);
+ dst->d_ino_timer = be32_to_cpu(dqp->q_core.d_itimer) +
+ ((u64)dqp->q_core.d_itimer_high << 32);
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 =
@@ -632,7 +637,8 @@ xfs_qm_scall_getquota_fill_qc(
dst->d_rt_spc_softlimit =
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);
- dst->d_rt_spc_timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
+ dst->d_rt_spc_timer = be32_to_cpu(dqp->q_core.d_rtbtimer) +
+ ((u64)dqp->q_core.d_rtbtimer_high << 32);
dst->d_rt_spc_warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
/*
@@ -37,9 +37,9 @@ 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 = q->qi_btimelimit;
- tstate->ino_timelimit = q->qi_itimelimit;
- tstate->rt_spc_timelimit = q->qi_rtbtimelimit;
+ 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;
@@ -580,7 +580,7 @@ xfs_trans_dqresv(
{
xfs_qcnt_t hardlimit;
xfs_qcnt_t softlimit;
- time_t timer;
+ time64_t timer;
xfs_qwarncnt_t warns;
xfs_qwarncnt_t warnlimit;
xfs_qcnt_t total_count;
@@ -600,7 +600,8 @@ 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 = be32_to_cpu(dqp->q_core.d_btimer) +
+ ((u64)dqp->q_core.d_btimer_high << 32);
warns = be16_to_cpu(dqp->q_core.d_bwarns);
warnlimit = dqp->q_mount->m_quotainfo->qi_bwarnlimit;
resbcountp = &dqp->q_res_bcount;
@@ -612,7 +613,8 @@ 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 = be32_to_cpu(dqp->q_core.d_rtbtimer) +
+ ((u64)dqp->q_core.d_rtbtimer_high << 32);
warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
warnlimit = dqp->q_mount->m_quotainfo->qi_rtbwarnlimit;
resbcountp = &dqp->q_res_rtbcount;
@@ -635,7 +637,8 @@ xfs_trans_dqresv(
goto error_return;
}
if (softlimit && total_count > softlimit) {
- if ((timer != 0 && get_seconds() > timer) ||
+ if ((timer != 0 &&
+ ktime_get_real_seconds() > timer) ||
(warns != 0 && warns >= warnlimit)) {
xfs_quota_warn(mp, dqp,
QUOTA_NL_BSOFTLONGWARN);
@@ -647,7 +650,8 @@ 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 = be32_to_cpu(dqp->q_core.d_itimer) +
+ ((u64)dqp->q_core.d_itimer_high << 32);
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);
@@ -662,7 +666,8 @@ xfs_trans_dqresv(
goto error_return;
}
if (softlimit && total_count > softlimit) {
- if ((timer != 0 && get_seconds() > timer) ||
+ if ((timer != 0 &&
+ ktime_get_real_seconds() > timer) ||
(warns != 0 && warns >= warnlimit)) {
xfs_quota_warn(mp, dqp,
QUOTA_NL_ISOFTLONGWARN);
The quota handling in xfs is based around an in-memory representation of time_t, which overflows in year 2038 on 32-bit architectures, and an on-disk representation of __be32, which overflows in year 2106 based on interpreting the values as unsigned. Extend both to allow for much longer times: the in-memory representation should just use time64_t and the on-disk representation has to live with the spare bits in struct xfs_disk_dquot. As there is an unused 32-bit field, and three time limits in it, allocating 8 bits per timeout seems appropriate. Note: the quotactl() syscall is not affected by this, it has its own struct fs_disk_quota that may need a similar conversion. Signed-off-by: Arnd Bergmann <arnd@arndb.de> --- fs/xfs/libxfs/xfs_dquot_buf.c | 6 +++--- fs/xfs/libxfs/xfs_format.h | 5 ++++- fs/xfs/xfs_dquot.c | 29 ++++++++++++++++++++--------- fs/xfs/xfs_qm.c | 18 ++++++++++++------ fs/xfs/xfs_qm.h | 6 +++--- fs/xfs/xfs_qm_syscalls.c | 16 +++++++++++----- fs/xfs/xfs_quotaops.c | 6 +++--- fs/xfs/xfs_trans_dquot.c | 17 +++++++++++------ 8 files changed, 67 insertions(+), 36 deletions(-)