From 85687833434d50e3f5fd4b849e543eb505bf5a20 Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Tue, 26 Jan 2016 13:10:59 +0100
Subject: [PATCH 1/2] Scan dquots using Q_GETNEXTQUOTA
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Check for new kernel quotactl Q_GETNEXTQUOTA and if available use it for
scanning all dquot structures.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Petr Písař <ppisar@redhat.com>
---
quota.h | 14 ++++++++++++++
quotaio_generic.c | 34 ++++++++++++++++++++++++++++++++++
quotaio_generic.h | 4 ++++
quotaio_meta.c | 14 +++++++++++++-
4 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/quota.h b/quota.h
index 0c38427..0607e04 100644
--- a/quota.h
+++ b/quota.h
@@ -63,6 +63,7 @@ typedef int64_t qsize_t; /* Type in which we store size limitations */
#define Q_SETINFO 0x800006 /* set information about quota files */
#define Q_GETQUOTA 0x800007 /* get user quota structure */
#define Q_SETQUOTA 0x800008 /* set user quota structure */
+#define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */
/*
* Quota structure used for communication with userspace via quotactl
@@ -91,6 +92,19 @@ struct if_dqblk {
u_int32_t dqb_valid;
};
+struct if_nextdqblk {
+ u_int64_t dqb_bhardlimit;
+ u_int64_t dqb_bsoftlimit;
+ u_int64_t dqb_curspace;
+ u_int64_t dqb_ihardlimit;
+ u_int64_t dqb_isoftlimit;
+ u_int64_t dqb_curinodes;
+ u_int64_t dqb_btime;
+ u_int64_t dqb_itime;
+ u_int32_t dqb_valid;
+ u_int32_t dqb_id;
+};
+
/*
* Structure used for setting quota information about file via quotactl
* Following flags are used to specify which fields are valid
diff --git a/quotaio_generic.c b/quotaio_generic.c
index 5001a56..4bdf380 100644
--- a/quotaio_generic.c
+++ b/quotaio_generic.c
@@ -161,3 +161,37 @@ int generic_scan_dquots(struct quota_handle *h,
free(dquot);
return ret;
}
+
+int vfs_scan_dquots(struct quota_handle *h,
+ int (*process_dquot)(struct dquot *dquot, char *dqname))
+{
+ struct dquot *dquot = get_empty_dquot();
+ qid_t id = 0;
+ struct if_nextdqblk kdqblk;
+ int ret;
+
+ dquot->dq_h = h;
+ while (1) {
+ ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type),
+ h->qh_quotadev, id, (void *)&kdqblk);
+ if (ret < 0)
+ break;
+
+ /*
+ * This is a slight hack but we know struct if_dqblk is a
+ * subset of struct if_nextdqblk
+ */
+ generic_kern2utildqblk(&dquot->dq_dqb,
+ (struct if_dqblk *)&kdqblk);
+ dquot->dq_id = kdqblk.dqb_id;
+ ret = process_dquot(dquot, NULL);
+ if (ret < 0)
+ break;
+ id = kdqblk.dqb_id + 1;
+ }
+ free(dquot);
+
+ if (errno == ENOENT)
+ return 0;
+ return ret;
+}
diff --git a/quotaio_generic.h b/quotaio_generic.h
index 5edc11c..a7930f0 100644
--- a/quotaio_generic.h
+++ b/quotaio_generic.h
@@ -27,4 +27,8 @@ int generic_scan_dquots(struct quota_handle *h,
int (*process_dquot)(struct dquot *dquot, char *dqname),
int (*get_dquot)(struct dquot *dquot));
+/* Scan all dquots using kernel quotactl to get existing ids */
+int vfs_scan_dquots(struct quota_handle *h,
+ int (*process_dquot)(struct dquot *dquot, char *dqname));
+
#endif
diff --git a/quotaio_meta.c b/quotaio_meta.c
index e52b4f4..ad6ff7a 100644
--- a/quotaio_meta.c
+++ b/quotaio_meta.c
@@ -8,6 +8,7 @@
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
#include <sys/types.h>
@@ -55,7 +56,18 @@ static int meta_commit_dquot(struct dquot *dquot, int flags)
static int meta_scan_dquots(struct quota_handle *h, int (*process_dquot)(struct dquot *dquot, char *dqname))
{
- return generic_scan_dquots(h, process_dquot, vfs_get_dquot);
+ struct if_nextdqblk kdqblk;
+ int ret;
+
+ ret = quotactl(QCMD(Q_GETNEXTQUOTA, h->qh_type), h->qh_quotadev, 0,
+ (void *)&kdqblk);
+ /*
+ * Fall back to scanning using passwd if Q_GETNEXTQUOTA is not
+ * supported
+ */
+ if (ret < 0 && (errno == ENOSYS || errno == EINVAL))
+ return generic_scan_dquots(h, process_dquot, vfs_get_dquot);
+ return vfs_scan_dquots(h, process_dquot);
}
struct quotafile_ops quotafile_ops_meta = {
--
2.5.0