@@ -184,4 +184,9 @@ extern xfs_mount_t *libxfs_mount (xfs_mount_t *, xfs_sb_t *,
int libxfs_umount(struct xfs_mount *mp);
extern void libxfs_rtmount_destroy (xfs_mount_t *);
+/* Dummy xfs_dquot so that libxfs compiles. */
+struct xfs_dquot {
+ int q_type;
+};
+
#endif /* __XFS_MOUNT_H__ */
@@ -67,6 +67,13 @@ xfs_dquot_verify(
ddq_type != XFS_DQTYPE_GROUP)
return __this_address;
+ if ((ddq->d_type & XFS_DQTYPE_BIGTIME) &&
+ !xfs_sb_version_hasbigtime(&mp->m_sb))
+ return __this_address;
+
+ if ((ddq->d_type & XFS_DQTYPE_BIGTIME) && !ddq->d_id)
+ return __this_address;
+
if (id != -1 && id != be32_to_cpu(ddq->d_id))
return __this_address;
@@ -294,6 +301,20 @@ xfs_dquot_from_disk_timestamp(
time64_t *timer,
__be32 dtimer)
{
+ /* Zero always means zero, regardless of encoding. */
+ if (!dtimer) {
+ *timer = 0;
+ return;
+ }
+
+ if (ddq->d_type & XFS_DQTYPE_BIGTIME) {
+ uint64_t t;
+
+ t = be32_to_cpu(dtimer);
+ *timer = t << XFS_DQ_BIGTIME_SHIFT;
+ return;
+ }
+
*timer = be32_to_cpu(dtimer);
}
@@ -304,5 +325,24 @@ xfs_dquot_to_disk_timestamp(
__be32 *dtimer,
time64_t timer)
{
+ /* Zero always means zero, regardless of encoding. */
+ if (!timer) {
+ *dtimer = cpu_to_be32(0);
+ return;
+ }
+
+ if (dqp->q_type & XFS_DQTYPE_BIGTIME) {
+ uint64_t t = timer;
+
+ /*
+ * Round the end of the grace period up to the nearest bigtime
+ * interval that we support, to give users the most time to fix
+ * the problems.
+ */
+ t = roundup_64(t, 1U << XFS_DQ_BIGTIME_SHIFT);
+ *dtimer = cpu_to_be32(t >> XFS_DQ_BIGTIME_SHIFT);
+ return;
+ }
+
*dtimer = cpu_to_be32(timer);
}
@@ -1228,13 +1228,15 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
#define XFS_DQTYPE_USER 0x01 /* user dquot record */
#define XFS_DQTYPE_PROJ 0x02 /* project dquot record */
#define XFS_DQTYPE_GROUP 0x04 /* group dquot record */
+#define XFS_DQTYPE_BIGTIME 0x08 /* large expiry timestamps */
/* bitmask to determine if this is a user/group/project dquot */
#define XFS_DQTYPE_REC_MASK (XFS_DQTYPE_USER | \
XFS_DQTYPE_PROJ | \
XFS_DQTYPE_GROUP)
-#define XFS_DQTYPE_ANY (XFS_DQTYPE_REC_MASK)
+#define XFS_DQTYPE_ANY (XFS_DQTYPE_REC_MASK | \
+ XFS_DQTYPE_BIGTIME)
/*
* XFS Quota Timers
@@ -1271,6 +1273,28 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
#define XFS_DQ_GRACE_MIN ((int64_t)0)
#define XFS_DQ_GRACE_MAX ((int64_t)U32_MAX)
+/*
+ * When bigtime is enabled, we trade a few bits of precision to expand the
+ * expiration timeout range to match that of big inode timestamps. The grace
+ * periods stored in dquot 0 are not shifted, since they record an interval,
+ * not a timestamp.
+ */
+#define XFS_DQ_BIGTIME_SHIFT (2)
+
+/*
+ * Smallest possible quota expiration with big timestamps, which is
+ * Jan 1 00:00:01 UTC 1970.
+ */
+#define XFS_DQ_BIGTIMEOUT_MIN (XFS_DQ_TIMEOUT_MIN)
+
+/*
+ * Largest supported quota expiration with traditional timestamps, which is
+ * the largest bigtime inode timestamp, or Jul 2 20:20:25 UTC 2486. The field
+ * is large enough that it's possible to fit expirations up to 2514, but we
+ * want to keep the maximum timestamp in sync.
+ */
+#define XFS_DQ_BIGTIMEOUT_MAX (XFS_INO_BIGTIME_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
@@ -23,7 +23,8 @@ typedef uint8_t xfs_dqtype_t;
#define XFS_DQTYPE_STRINGS \
{ XFS_DQTYPE_USER, "USER" }, \
{ XFS_DQTYPE_PROJ, "PROJ" }, \
- { XFS_DQTYPE_GROUP, "GROUP" }
+ { XFS_DQTYPE_GROUP, "GROUP" }, \
+ { XFS_DQTYPE_BIGTIME, "BIGTIME" }
/*
* flags for q_flags field in the dquot.