#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 */
/*
__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__ */
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);
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