@@ -10,6 +10,7 @@
#define Q_XFS_QUOTAON Q_XQUOTAON
#define Q_XFS_QUOTAOFF Q_XQUOTAOFF
#define Q_XFS_GETQUOTA Q_XGETQUOTA
+#define Q_XFS_GETQUOTA2 Q_XGETQUOTA2
#define Q_XFS_SETQLIM Q_XSETQLIM
#define Q_XFS_GETQSTAT Q_XGETQSTAT
#define Q_XFS_QUOTARM Q_XQUOTARM
@@ -161,3 +161,52 @@ int generic_scan_dquots(struct quota_handle *h,
free(dquot);
return ret;
}
+
+/* Generic quota scanning using Q_XGETQUOTA2... */
+int generic_scan_dquots2(struct quota_handle *h,
+ int (*process_dquot)(struct dquot *dquot, char *dqname),
+ int (*get_dquot)(struct dquot *dquot))
+{
+ struct dquot *dquot = get_empty_dquot();
+ char namebuf[MAXNAMELEN];
+ int ret = 0;
+
+ dquot->dq_id = 0;
+ dquot->dq_h = h;
+ if (h->qh_type == USRQUOTA) {
+ while (1) {
+ ret = scan_one_dquot(dquot, get_dquot);
+ if (ret < 0) {
+ if (errno == ESRCH)
+ ret =0;
+ break;
+ }
+ if (ret > 0)
+ continue;
+ id2name(dquot->dq_id, dquot->dq_h->qh_type, namebuf);
+ ret = process_dquot(dquot, namebuf);
+ if (ret < 0)
+ break;
+ dquot->dq_id++;
+ }
+ } else if (h->qh_type == GRPQUOTA) {
+ while (1) {
+ ret = scan_one_dquot(dquot, get_dquot);
+ if (ret < 0) {
+ if (errno == ESRCH)
+ ret =0;
+ break;
+ }
+ if (ret > 0)
+ continue;
+ id2name(dquot->dq_id, dquot->dq_h->qh_type, namebuf);
+ ret = process_dquot(dquot, namebuf);
+ if (ret < 0)
+ break;
+ dquot->dq_id++;
+ }
+ }
+ free(dquot);
+ return ret;
+}
+
@@ -26,5 +26,9 @@ int vfs_set_dquot(struct dquot *dquot, int flags);
int generic_scan_dquots(struct quota_handle *h,
int (*process_dquot)(struct dquot *dquot, char *dqname),
int (*get_dquot)(struct dquot *dquot));
+/* Generic routine for scanning dquots when kernel can do the scanning */
+int generic_scan_dquots2(struct quota_handle *h,
+ int (*process_dquot)(struct dquot *dquot, char *dqname),
+ int (*get_dquot)(struct dquot *dquot));
#endif
@@ -192,14 +192,42 @@ static int xfs_get_dquot(struct dquot *dq)
}
/*
+ * xfs_scan_dquots helper - processes a single dquot with Q_XGETQUOTA2
+ */
+static int xfs_get_dquot2(struct dquot *dq)
+{
+ struct xfs_kern_dqblk d;
+ int qcmd = QCMD(Q_XFS_GETQUOTA2, dq->dq_h->qh_type);
+ int ret;
+
+ memset(&d, 0, sizeof(d));
+ ret = quotactl(qcmd, dq->dq_h->qh_quotadev, dq->dq_id, (void *)&d);
+ if (ret < 0) {
+ if (errno == ENOENT)
+ return 0;
+ return -1;
+ }
+ dq->dq_id = d.d_id;
+ xfs_kern2utildqblk(&dq->dq_dqb, &d);
+ return 0;
+}
+
+/*
* Scan all known dquots and call callback on each
*/
static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, char *dqname))
{
+ int ret;
+
if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
return 0;
- return generic_scan_dquots(h, process_dquot, xfs_get_dquot);
+ ret = generic_scan_dquots2(h, process_dquot, xfs_get_dquot2);
+
+ if (ret)
+ ret = generic_scan_dquots(h, process_dquot, xfs_get_dquot);
+
+ return ret;
}
/*
@@ -46,6 +46,7 @@
#define Q_XSETQLIM XQM_CMD(0x4) /* set disk limits only */
#define Q_XGETQSTAT XQM_CMD(0x5) /* returns fs_quota_stat_t struct */
#define Q_XQUOTARM XQM_CMD(0x6) /* free quota files' space */
+#define Q_XGETQUOTA2 XQM_CMD(0x9) /* get disk limits and usage >= ID */
/*
* fs_disk_quota structure:
Here's a patch to hook Q_XGETQUOTA2 into the generic quota tools repquota command. Rather than looping over getpwent(), it increments the id sent into the quotactl until it gets back ESRCH. If Q_XGETQUOTA2 doesn't exist it falls back to the old method. Signed-off-by: Eric Sandeen <sandeen@redhat.com> --- -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html