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);
