]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_quota: support editing and reporting quotas with bigtime
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 20 Nov 2020 22:03:28 +0000 (17:03 -0500)
committerEric Sandeen <sandeen@sandeen.net>
Fri, 20 Nov 2020 22:03:28 +0000 (17:03 -0500)
Enhance xfs_quota to detect and report grace period expirations past
2038.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
include/xqm.h
quota/edit.c
quota/quota.c
quota/quota.h
quota/report.c

index 8ab19072656e86bf196805bac82e5fa200225a69..573441db98601aab401853c2d6eb68baebda3c0c 100644 (file)
@@ -47,7 +47,10 @@ typedef struct fs_disk_quota {
        __s32           d_btimer;       /* similar to above; for disk blocks */
        __u16           d_iwarns;       /* # warnings issued wrt num inodes */
        __u16           d_bwarns;       /* # warnings issued wrt disk blocks */
-       __s32           d_padding2;     /* padding2 - for future use */
+       __s8            d_itimer_hi;    /* upper 8 bits of timer values */
+       __s8            d_btimer_hi;
+       __s8            d_rtbtimer_hi;
+       __s8            d_padding2;     /* padding2 - for future use */
        __u64           d_rtb_hardlimit;/* absolute limit on realtime blks */
        __u64           d_rtb_softlimit;/* preferred limit on RT disk blks */
        __u64           d_rtbcount;     /* # realtime blocks owned */
@@ -93,6 +96,21 @@ typedef struct fs_disk_quota {
 #define FS_DQ_RTBWARNS (1<<11)
 #define FS_DQ_WARNS_MASK       (FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS)
 
+/*
+ * Accounting values.  These can only be set for filesystem with
+ * non-transactional quotas that require quotacheck(8) in userspace.
+ */
+#define FS_DQ_BCOUNT           (1<<12)
+#define FS_DQ_ICOUNT           (1<<13)
+#define FS_DQ_RTBCOUNT         (1<<14)
+#define FS_DQ_ACCT_MASK                (FS_DQ_BCOUNT | FS_DQ_ICOUNT | FS_DQ_RTBCOUNT)
+
+/*
+ * Quota expiration timestamps are 40-bit signed integers, with the upper 8
+ * bits encoded in the _hi fields.
+ */
+#define FS_DQ_BIGTIME          (1<<15)
+
 /*
  * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
  */
index b3cad024b1f1fa9d1c495878ff968f9c4b38c8f0..1a3b2d9f959be835b6e0dd7e39d3c01db9f7d593 100644 (file)
@@ -417,6 +417,53 @@ restore_f(
        return 0;
 }
 
+time64_t
+decode_timer(
+       const struct fs_disk_quota *d,
+       __s32                   timer_lo,
+       __s8                    timer_hi)
+{
+       if (d->d_fieldmask & FS_DQ_BIGTIME)
+               return (uint32_t)timer_lo | (int64_t)timer_hi << 32;
+       return timer_lo;
+}
+
+static inline void
+encode_timer(
+       const struct fs_disk_quota *d,
+       __s32                   *timer_lo,
+       __s8                    *timer_hi,
+       time64_t                timer)
+{
+       *timer_lo = timer;
+       if (d->d_fieldmask & FS_DQ_BIGTIME)
+               *timer_hi = timer >> 32;
+       else
+               *timer_hi = 0;
+}
+
+static inline bool want_bigtime(time64_t timer)
+{
+       return timer > INT32_MAX || timer < INT32_MIN;
+}
+
+static void
+encode_timers(
+       struct fs_disk_quota    *d,
+       time64_t                btimer,
+       time64_t                itimer,
+       time64_t                rtbtimer)
+{
+       d->d_fieldmask &= ~FS_DQ_BIGTIME;
+       if (want_bigtime(btimer) || want_bigtime(itimer) ||
+           want_bigtime(rtbtimer))
+               d->d_fieldmask |= FS_DQ_BIGTIME;
+
+       encode_timer(d, &d->d_btimer, &d->d_btimer_hi, btimer);
+       encode_timer(d, &d->d_itimer, &d->d_itimer_hi, itimer);
+       encode_timer(d, &d->d_rtbtimer, &d->d_rtbtimer_hi, rtbtimer);
+}
+
 static void
 set_timer(
        uint32_t                id,
@@ -426,6 +473,7 @@ set_timer(
        time64_t                value)
 {
        struct fs_disk_quota    d;
+       time64_t                btimer, itimer, rtbtimer;
 
        memset(&d, 0, sizeof(d));
 
@@ -446,23 +494,28 @@ set_timer(
 
                time(&now);
 
+               btimer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
+               itimer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
+               rtbtimer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
+
                /* Only set grace time if user is already past soft limit */
                if (d.d_blk_softlimit && d.d_bcount > d.d_blk_softlimit)
-                       d.d_btimer = now + value;
+                       btimer = now + value;
                if (d.d_ino_softlimit && d.d_icount > d.d_ino_softlimit)
-                       d.d_itimer = now + value;
+                       itimer = now + value;
                if (d.d_rtb_softlimit && d.d_rtbcount > d.d_rtb_softlimit)
-                       d.d_rtbtimer = now + value;
+                       rtbtimer = now + value;
        } else {
-               d.d_btimer = value;
-               d.d_itimer = value;
-               d.d_rtbtimer = value;
+               btimer = value;
+               itimer = value;
+               rtbtimer = value;
        }
 
        d.d_version = FS_DQUOT_VERSION;
        d.d_flags = type;
        d.d_fieldmask = mask;
        d.d_id = id;
+       encode_timers(&d, btimer, itimer, rtbtimer);
 
        if (xfsquotactl(XFS_SETQLIM, dev, type, id, (void *)&d) < 0) {
                exitcode = 1;
index 8ba0995d9174697d6b2ad71a8563f13730d9a229..0747cedcb8c2930b651e40792d0b80effc27f33a 100644 (file)
@@ -101,7 +101,7 @@ quota_mount(
        }
 
        if (form & XFS_BLOCK_QUOTA) {
-               timer = d.d_btimer;
+               timer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
                qflags = (flags & HUMAN_FLAG);
                if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
                        qflags |= LIMIT_FLAG;
@@ -123,7 +123,7 @@ quota_mount(
                                time_to_string(timer, qflags));
        }
        if (form & XFS_INODE_QUOTA) {
-               timer = d.d_itimer;
+               timer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
                qflags = (flags & HUMAN_FLAG);
                if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
                        qflags |= LIMIT_FLAG;
@@ -145,7 +145,7 @@ quota_mount(
                                time_to_string(timer, qflags));
        }
        if (form & XFS_RTBLOCK_QUOTA) {
-               timer = d.d_rtbtimer;
+               timer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
                qflags = (flags & HUMAN_FLAG);
                if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
                        qflags |= LIMIT_FLAG;
index 11f62b208e6a99d9440f54126d836643f1e6f82d..78b0d66d2a4f8ff85cb16e0ae7850d1f3243d899 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (c) 2005 Silicon Graphics, Inc.
  * All Rights Reserved.
  */
+#ifndef XFS_QUOTA_QUOTA_H_
+#define XFS_QUOTA_QUOTA_H_
 
 #include "xqm.h"
 #include "libfrog/paths.h"
@@ -73,3 +75,8 @@ extern char *uid_to_name(uint32_t __uid);
 extern char *gid_to_name(uint32_t __gid);
 extern char *prid_to_name(uint32_t __prid);
 extern bool isdigits_only(const char *);
+
+time64_t decode_timer(const struct fs_disk_quota *d, __s32 timer_lo,
+               __s8 timer_hi);
+
+#endif /* XFS_QUOTA_QUOTA_H_ */
index 2d5024e95177e2e58b2eb047a8f9516f0c81fb21..6ac5549097b781d9351f35364fae97a0df964879 100644 (file)
@@ -398,7 +398,7 @@ report_mount(
        }
 
        if (form & XFS_BLOCK_QUOTA) {
-               timer = d.d_btimer;
+               timer = decode_timer(&d, d.d_btimer, d.d_btimer_hi);
                qflags = (flags & HUMAN_FLAG);
                if (d.d_blk_hardlimit && d.d_bcount > d.d_blk_hardlimit)
                        qflags |= LIMIT_FLAG;
@@ -420,7 +420,7 @@ report_mount(
                                time_to_string(timer, qflags));
        }
        if (form & XFS_INODE_QUOTA) {
-               timer = d.d_itimer;
+               timer = decode_timer(&d, d.d_itimer, d.d_itimer_hi);
                qflags = (flags & HUMAN_FLAG);
                if (d.d_ino_hardlimit && d.d_icount > d.d_ino_hardlimit)
                        qflags |= LIMIT_FLAG;
@@ -442,7 +442,7 @@ report_mount(
                                time_to_string(timer, qflags));
        }
        if (form & XFS_RTBLOCK_QUOTA) {
-               timer = d.d_rtbtimer;
+               timer = decode_timer(&d, d.d_rtbtimer, d.d_rtbtimer_hi);
                qflags = (flags & HUMAN_FLAG);
                if (d.d_rtb_hardlimit && d.d_rtbcount > d.d_rtb_hardlimit)
                        qflags |= LIMIT_FLAG;