]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_quota: wire up XFS_GETQSTATV
authorEric Sandeen <sandeen@sandeen.net>
Fri, 26 Aug 2016 01:20:28 +0000 (11:20 +1000)
committerDave Chinner <david@fromorbit.com>
Fri, 26 Aug 2016 01:20:28 +0000 (11:20 +1000)
The new XFS_GETQSTATV quotactl, available since kernel v3.12,
was never implemented in xfs_quota, and the "state" command
continues to use XFS_GETQSTAT, which cannot report both
group & project quota on newer formats.

The new call has room for all 3 quota types (user, group, and
quota), vs just two, where previously project and quota
overlapped.

So:

First, try XFS_GETQSTATV.
If it passes, we have all the information we need, and we print
it. state_qfilestat() is modified to take the newer structure.

If it fails, try XFS_GETQSTAT.  If that passes, we are on an
older kernel with neither XFS_GETQSTATV nor the on-disk project
quota inode.  We copy the available information into the newer
statv structure, carefully determining wither group or project
(or neither) is actually active, and print it with the same
state_qfilestat routine.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Zorro Lang <zlang@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
include/xqm.h
quota/linux.c
quota/state.c

index c084b2d333a0944c51b569cc882dd117f40dfc1c..5b6934a27523c9599ff7cc1305b964c87630bc5a 100644 (file)
@@ -32,6 +32,7 @@
 #define Q_XGETQSTAT    XQM_CMD(5)      /* get quota subsystem status */
 #define Q_XQUOTARM     XQM_CMD(6)      /* free disk space used by dquots */
 #define Q_XQUOTASYNC   XQM_CMD(7)      /* delalloc flush, updates dquots */
+#define Q_XGETQSTATV   XQM_CMD(8)      /* newer version of get quota */
 #define Q_XGETNEXTQUOTA        XQM_CMD(9)      /* get disk limits and usage */
 
 /*
@@ -149,4 +150,35 @@ typedef struct fs_quota_stat {
        __u16           qs_iwarnlimit;  /* limit for num warnings */
 } fs_quota_stat_t;
 
+
+#ifndef FS_QSTATV_VERSION1
+#define FS_QSTATV_VERSION1     1       /* fs_quota_statv.qs_version */
+#endif
+
+/*
+ * Some basic information about 'quota files' for Q_XGETQSTATV command
+ */
+struct fs_qfilestatv {
+       __u64           qfs_ino;        /* inode number */
+       __u64           qfs_nblks;      /* number of BBs 512-byte-blks */
+       __u32           qfs_nextents;   /* number of extents */
+       __u32           qfs_pad;        /* pad for 8-byte alignment */
+};
+
+struct fs_quota_statv {
+       __s8                    qs_version;     /* version for future changes */
+       __u8                    qs_pad1;        /* pad for 16bit alignment */
+       __u16                   qs_flags;       /* FS_QUOTA_.* flags */
+       __u32                   qs_incoredqs;   /* number of dquots incore */
+       struct fs_qfilestatv    qs_uquota;      /* user quota information */
+       struct fs_qfilestatv    qs_gquota;      /* group quota information */
+       struct fs_qfilestatv    qs_pquota;      /* project quota information */
+       __s32                   qs_btimelimit;  /* limit for blks timer */
+       __s32                   qs_itimelimit;  /* limit for inodes timer */
+       __s32                   qs_rtbtimelimit;/* limit for rt blks timer */
+       __u16                   qs_bwarnlimit;  /* limit for num warnings */
+       __u16                   qs_iwarnlimit;  /* limit for num warnings */
+       __u64                   qs_pad2[8];     /* for future proofing */
+};
+
 #endif /* __XQM_H__ */
index 74dba0178633c435d18aef8618e88141fb869eb8..4f1f3c4f3e8cd95a00425a0d6755dc19975d5b5c 100644 (file)
@@ -55,6 +55,8 @@ xcommand_to_qcommand(
                return Q_XSETQLIM;
        case XFS_GETQSTAT:
                return Q_XGETQSTAT;
+       case XFS_GETQSTATV:
+               return Q_XGETQSTATV;
        case XFS_QUOTARM:
                return Q_XQUOTARM;
        case XFS_QSYNC:
index 81867621cdda2335f723e2f70d5bca2a1fd54547..9f6616ea172658b2d9c7ad1df6a69b8f8b9d1341 100644 (file)
@@ -111,12 +111,12 @@ remove_help(void)
 
 static void
 state_qfilestat(
-       FILE            *fp,
-       fs_path_t       *mount,
-       uint            type,
-       fs_qfilestat_t  *qfs,
-       int             accounting,
-       int             enforcing)
+       FILE                    *fp,
+       struct fs_path          *mount,
+       uint                    type,
+       struct fs_qfilestatv    *qfs,
+       int                     accounting,
+       int                     enforcing)
 {
        fprintf(fp, _("%s quota state on %s (%s)\n"), type_to_string(type),
                mount->fs_dir, mount->fs_name);
@@ -142,39 +142,96 @@ state_timelimit(
                time_to_string(timelimit, VERBOSE_FLAG | ABSOLUTE_FLAG));
 }
 
+/*
+ * fs_quota_stat holds a subset of fs_quota_statv; this copies
+ * the smaller into the larger, leaving any not-present fields
+ * empty.  This is so the same reporting function can be used
+ * for both XFS_GETQSTAT and XFS_GETQSTATV results.
+ */
 static void
-state_quotafile_mount(
-       FILE            *fp,
-       uint            type,
-       fs_path_t       *mount,
-       uint            flags)
+state_stat_to_statv(
+       struct fs_quota_stat    *s,
+       struct fs_quota_statv   *sv)
 {
-       fs_quota_stat_t s;
-       char            *dev = mount->fs_name;
+       memset(sv, 0, sizeof(struct fs_quota_statv));
+
+       /* shared information */
+       sv->qs_version = s->qs_version;
+       sv->qs_flags = s->qs_flags;
+       sv->qs_incoredqs = s->qs_incoredqs;
+       sv->qs_btimelimit = s->qs_btimelimit;
+       sv->qs_itimelimit = s->qs_itimelimit;
+       sv->qs_rtbtimelimit = s->qs_rtbtimelimit;
+       sv->qs_bwarnlimit = s->qs_bwarnlimit;
+       sv->qs_iwarnlimit = s->qs_iwarnlimit;
+
+       /* Always room for uquota */
+       sv->qs_uquota.qfs_ino = s->qs_uquota.qfs_ino;
+       sv->qs_uquota.qfs_nblks = s->qs_uquota.qfs_nblks;
+       sv->qs_uquota.qfs_nextents = s->qs_uquota.qfs_nextents;
+
+       /*
+        * If we are here, XFS_GETQSTATV failed and XFS_GETQSTAT passed;
+        * that is a very strong hint that we're on a kernel which predates
+        * the on-disk pquota inode; both were added in v3.12.  So, we do
+        * some tricksy determination here.
+        * gs_gquota may hold either group quota inode info, or project
+        * quota if that is used instead; which one it actually holds depends
+        * on the quota flags.  (If neither is set, neither is used)
+        */
+       if (s->qs_flags & XFS_QUOTA_GDQ_ACCT) {
+               /* gs_gquota holds group quota info */
+               sv->qs_gquota.qfs_ino = s->qs_gquota.qfs_ino;
+               sv->qs_gquota.qfs_nblks = s->qs_gquota.qfs_nblks;
+               sv->qs_gquota.qfs_nextents = s->qs_gquota.qfs_nextents;
+       } else if (s->qs_flags & XFS_QUOTA_PDQ_ACCT) {
+               /* gs_gquota actually holds project quota info */
+               sv->qs_pquota.qfs_ino = s->qs_gquota.qfs_ino;
+               sv->qs_pquota.qfs_nblks = s->qs_gquota.qfs_nblks;
+               sv->qs_pquota.qfs_nextents = s->qs_gquota.qfs_nextents;
+       }
+}
 
-       if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, (void *)&s) < 0) {
-               if (flags & VERBOSE_FLAG)
-                       fprintf(fp, _("%s quota are not enabled on %s\n"),
-                               type_to_string(type), dev);
-               return;
+static void
+state_quotafile_mount(
+       FILE                    *fp,
+       uint                    type,
+       struct fs_path          *mount,
+       uint                    flags)
+{
+       struct fs_quota_stat    s;
+       struct fs_quota_statv   sv;
+       char                    *dev = mount->fs_name;
+
+       sv.qs_version = FS_QSTATV_VERSION1;
+
+       if (xfsquotactl(XFS_GETQSTATV, dev, type, 0, (void *)&sv) < 0) {
+               if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, (void *)&s) < 0) {
+                       if (flags & VERBOSE_FLAG)
+                               fprintf(fp,
+                                       _("%s quota are not enabled on %s\n"),
+                                       type_to_string(type), dev);
+                       return;
+               }
+               state_stat_to_statv(&s, &sv);
        }
 
        if (type & XFS_USER_QUOTA)
-               state_qfilestat(fp, mount, XFS_USER_QUOTA, &s.qs_uquota,
-                               s.qs_flags & XFS_QUOTA_UDQ_ACCT,
-                               s.qs_flags & XFS_QUOTA_UDQ_ENFD);
+               state_qfilestat(fp, mount, XFS_USER_QUOTA, &sv.qs_uquota,
+                               sv.qs_flags & XFS_QUOTA_UDQ_ACCT,
+                               sv.qs_flags & XFS_QUOTA_UDQ_ENFD);
        if (type & XFS_GROUP_QUOTA)
-               state_qfilestat(fp, mount, XFS_GROUP_QUOTA, &s.qs_gquota,
-                               s.qs_flags & XFS_QUOTA_GDQ_ACCT,
-                               s.qs_flags & XFS_QUOTA_GDQ_ENFD);
+               state_qfilestat(fp, mount, XFS_GROUP_QUOTA, &sv.qs_gquota,
+                               sv.qs_flags & XFS_QUOTA_GDQ_ACCT,
+                               sv.qs_flags & XFS_QUOTA_GDQ_ENFD);
        if (type & XFS_PROJ_QUOTA)
-               state_qfilestat(fp, mount, XFS_PROJ_QUOTA, &s.qs_gquota,
-                               s.qs_flags & XFS_QUOTA_PDQ_ACCT,
-                               s.qs_flags & XFS_QUOTA_PDQ_ENFD);
+               state_qfilestat(fp, mount, XFS_PROJ_QUOTA, &sv.qs_pquota,
+                               sv.qs_flags & XFS_QUOTA_PDQ_ACCT,
+                               sv.qs_flags & XFS_QUOTA_PDQ_ENFD);
 
-       state_timelimit(fp, XFS_BLOCK_QUOTA, s.qs_btimelimit);
-       state_timelimit(fp, XFS_INODE_QUOTA, s.qs_itimelimit);
-       state_timelimit(fp, XFS_RTBLOCK_QUOTA, s.qs_rtbtimelimit);
+       state_timelimit(fp, XFS_BLOCK_QUOTA, sv.qs_btimelimit);
+       state_timelimit(fp, XFS_INODE_QUOTA, sv.qs_itimelimit);
+       state_timelimit(fp, XFS_RTBLOCK_QUOTA, sv.qs_rtbtimelimit);
 }
 
 static void