summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2011-05-05 16:14:07 +0200
committerJan Kara <jack@suse.cz>2011-05-05 16:14:07 +0200
commitc3a392437a2ec4793f2b1112058de0c3b459b6fe (patch)
tree0af9cc6eb7c7e9155716142d33cd937aefe89648
parente482f256411dba6a9d647e6df7f24eef8af3d59b (diff)
downloadlinuxquota-c3a392437a2ec4793f2b1112058de0c3b459b6fe.tar.gz
Implement repquota for filesystems without quota files
Some filesystem do not have quota files accessible from userspace. For these implementing ->scan_dquots() used by repquota is problematic. What we do is that we iterate over all users and ask for quota information for each of them. XFS already does this so make its code generic and use it for all filesystems using quotaio_meta.c - only OCFS2 these days. Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--convertquota.c2
-rw-r--r--quotaio.c24
-rw-r--r--quotaio_generic.c63
-rw-r--r--quotaio_generic.h6
-rw-r--r--quotaio_meta.c6
-rw-r--r--quotaio_xfs.c68
-rw-r--r--quotasys.h2
-rw-r--r--repquota.c4
-rw-r--r--warnquota.c4
9 files changed, 104 insertions, 75 deletions
diff --git a/convertquota.c b/convertquota.c
index ab16193..1e40804 100644
--- a/convertquota.c
+++ b/convertquota.c
@@ -312,7 +312,7 @@ static int convert_format(int type, struct mntent *mnt)
struct quota_handle *qo;
int ret = 0;
- if (!(qo = init_io(mnt, type, infmt, IOI_OPENFILE))) {
+ if (!(qo = init_io(mnt, type, infmt, IOI_INITSCAN))) {
errstr(_("Cannot open old format file for %ss on %s\n"),
type2name(type), mnt->mnt_dir);
return -1;
diff --git a/quotaio.c b/quotaio.c
index 21881fc..bf0de85 100644
--- a/quotaio.c
+++ b/quotaio.c
@@ -43,6 +43,7 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
int fd = -1, kernfmt;
struct quota_handle *h = smalloc(sizeof(struct quota_handle));
const char *mnt_fsname = NULL;
+ int nameflag;
if (!hasquota(mnt, type, 0))
goto out_handle;
@@ -110,44 +111,33 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
errstr(_("Quota not supported by the filesystem.\n"));
goto out_handle;
}
- if (flags & IOI_OPENFILE) {
- errstr(_("Operation not supported for filesystems with hidden quota files!\n"));
- goto out_handle;
- }
h->qh_fd = -1;
h->qh_fmt = fmt;
goto set_ops;
}
+ nameflag = (!QIO_ENABLED(h) || flags & IOI_INITSCAN) ? NF_FORMAT : 0;
if (fmt == -1) {
/* Let's try any VFSv0 quota format... */
- if (get_qf_name(mnt, type, QF_VFSV0,
- (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
- &qfname) >= 0)
+ if (get_qf_name(mnt, type, QF_VFSV0, nameflag, &qfname) >= 0)
fmt = QF_VFSV0;
/* And then VFSv1 quota format... */
- else if (get_qf_name(mnt, type, QF_VFSV1,
- (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
- &qfname) >= 0)
+ else if (get_qf_name(mnt, type, QF_VFSV1, nameflag, &qfname) >= 0)
fmt = QF_VFSV1;
/* And then old quota format... */
- else if (get_qf_name(mnt, type, QF_VFSOLD,
- (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
- &qfname) >= 0)
+ else if (get_qf_name(mnt, type, QF_VFSOLD, nameflag, &qfname) >= 0)
fmt = QF_VFSOLD;
else { /* Don't know... */
errstr(_("Cannot find any quota file to work on.\n"));
goto out_handle;
}
} else {
- if (get_qf_name(mnt, type, fmt,
- (!QIO_ENABLED(h) || flags & IOI_OPENFILE) ? NF_FORMAT : 0,
- &qfname) < 0) {
+ if (get_qf_name(mnt, type, fmt, nameflag, &qfname) < 0) {
errstr(_("Quota file not found or has wrong format.\n"));
goto out_handle;
}
}
- if (!QIO_ENABLED(h) || flags & IOI_OPENFILE) { /* Need to open file? */
+ if (!QIO_ENABLED(h) || flags & IOI_INITSCAN) { /* Need to open file? */
if (QIO_ENABLED(h)) { /* Kernel uses same file? */
unsigned int cmd =
(kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC;
diff --git a/quotaio_generic.c b/quotaio_generic.c
index e5df683..5001a56 100644
--- a/quotaio_generic.c
+++ b/quotaio_generic.c
@@ -8,6 +8,9 @@
#include <errno.h>
#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
#include <sys/types.h>
#include "pot.h"
@@ -98,3 +101,63 @@ int vfs_set_dquot(struct dquot *dquot, int flags)
}
return 0;
}
+
+static int scan_one_dquot(struct dquot *dquot, int (*get_dquot)(struct dquot *))
+{
+ int ret;
+ struct util_dqblk *dqb = &dquot->dq_dqb;
+
+ memset(dqb, 0, sizeof(struct util_dqblk));
+ ret = get_dquot(dquot);
+ if (ret < 0)
+ return ret;
+ if (!dqb->dqb_bhardlimit && !dqb->dqb_bsoftlimit && !dqb->dqb_ihardlimit && !dqb->dqb_isoftlimit && !dqb->dqb_curinodes && !dqb->dqb_curspace)
+ return 1;
+ return 0;
+}
+
+/* Generic quota scanning using passwd... */
+int generic_scan_dquots(struct quota_handle *h,
+ int (*process_dquot)(struct dquot *dquot, char *dqname),
+ int (*get_dquot)(struct dquot *dquot))
+{
+ struct dquot *dquot = get_empty_dquot();
+ int ret = 0;
+
+ dquot->dq_h = h;
+ if (h->qh_type == USRQUOTA) {
+ struct passwd *usr;
+
+ setpwent();
+ while ((usr = getpwent()) != NULL) {
+ dquot->dq_id = usr->pw_uid;
+ ret = scan_one_dquot(dquot, get_dquot);
+ if (ret < 0)
+ break;
+ if (ret > 0)
+ continue;
+ ret = process_dquot(dquot, usr->pw_name);
+ if (ret < 0)
+ break;
+ }
+ endpwent();
+ } else if (h->qh_type == GRPQUOTA) {
+ struct group *grp;
+
+ setgrent();
+ while ((grp = getgrent()) != NULL) {
+ dquot->dq_id = grp->gr_gid;
+ ret = scan_one_dquot(dquot, get_dquot);
+ if (ret < 0)
+ break;
+ if (ret > 0)
+ continue;
+ ret = process_dquot(dquot, grp->gr_name);
+ if (ret < 0)
+ break;
+ }
+ endgrent();
+ }
+ free(dquot);
+ return ret;
+}
diff --git a/quotaio_generic.h b/quotaio_generic.h
index 422fb52..5edc11c 100644
--- a/quotaio_generic.h
+++ b/quotaio_generic.h
@@ -21,4 +21,10 @@ int vfs_get_dquot(struct dquot *dquot);
/* Set dquot in kernel */
int vfs_set_dquot(struct dquot *dquot, int flags);
+/* Generic routine for scanning dquots when quota format does not have
+ * better way */
+int generic_scan_dquots(struct quota_handle *h,
+ int (*process_dquot)(struct dquot *dquot, char *dqname),
+ int (*get_dquot)(struct dquot *dquot));
+
#endif
diff --git a/quotaio_meta.c b/quotaio_meta.c
index f1f714f..e52b4f4 100644
--- a/quotaio_meta.c
+++ b/quotaio_meta.c
@@ -53,9 +53,15 @@ static int meta_commit_dquot(struct dquot *dquot, int flags)
return vfs_set_dquot(dquot, 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 quotafile_ops quotafile_ops_meta = {
init_io: meta_init_io,
write_info: meta_write_info,
read_dquot: meta_read_dquot,
commit_dquot: meta_commit_dquot,
+scan_dquots: meta_scan_dquots,
};
diff --git a/quotaio_xfs.c b/quotaio_xfs.c
index 62075b5..2e879e6 100644
--- a/quotaio_xfs.c
+++ b/quotaio_xfs.c
@@ -10,8 +10,6 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <pwd.h>
-#include <grp.h>
#include "pot.h"
#include "common.h"
@@ -19,6 +17,7 @@
#include "quotaio.h"
#include "quotasys.h"
#include "dqblk_xfs.h"
+#include "quotaio_generic.h"
#define XFS_USRQUOTA(h) ((h)->qh_type == USRQUOTA && \
(h)->qh_info.u.xfs_mdqi.qs_flags & XFS_QUOTA_UDQ_ACCT)
@@ -175,24 +174,21 @@ static int xfs_commit_dquot(struct dquot *dquot, int flags)
/*
* xfs_scan_dquots helper - processes a single dquot
*/
-static int xfs_scan_dquot(struct quota_handle *h,
- struct xfs_kern_dqblk *d,
- char *name, struct dquot *dq,
- int (*process_dquot) (struct dquot *dquot, char *dqname))
+static int xfs_get_dquot(struct dquot *dq)
{
- int qcmd = QCMD(Q_XFS_GETQUOTA, h->qh_type);
-
- memset(d, 0, sizeof(struct xfs_kern_dqblk));
-
- if (quotactl(qcmd, h->qh_quotadev, dq->dq_id, (void *)d) < 0) {
- return 0;
+ struct xfs_kern_dqblk d;
+ int qcmd = QCMD(Q_XFS_GETQUOTA, 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 (ret == -ENOENT)
+ return 0;
+ return ret;
}
- if (d->d_blk_hardlimit == 0 &&
- d->d_blk_softlimit == 0 &&
- d->d_ino_hardlimit == 0 &&
- d->d_ino_softlimit == 0 && d->d_bcount == 0 && d->d_icount == 0) return 0;
- xfs_kern2utildqblk(&dq->dq_dqb, d);
- return process_dquot(dq, name);
+ xfs_kern2utildqblk(&dq->dq_dqb, &d);
+ return 0;
}
/*
@@ -200,42 +196,10 @@ static int xfs_scan_dquot(struct quota_handle *h,
*/
static int xfs_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, char *dqname))
{
- struct dquot *dq;
- struct xfs_kern_dqblk d;
- int rd = 0;
-
if (!XFS_USRQUOTA(h) && !XFS_GRPQUOTA(h))
- return rd;
-
- dq = get_empty_dquot();
- dq->dq_h = h;
- if (h->qh_type == USRQUOTA) {
- struct passwd *usr;
-
- setpwent();
- while ((usr = getpwent()) != NULL) {
- dq->dq_id = usr->pw_uid;
- rd = xfs_scan_dquot(h, &d, usr->pw_name, dq, process_dquot);
- if (rd < 0)
- break;
- }
- endpwent();
- }
- else { /* GRPQUOTA */
- struct group *grp;
-
- setgrent();
- while ((grp = getgrent()) != NULL) {
- dq->dq_id = grp->gr_gid;
- rd = xfs_scan_dquot(h, &d, grp->gr_name, dq, process_dquot);
- if (rd < 0)
- break;
- }
- endgrent();
- }
+ return 0;
- free(dq);
- return rd;
+ return generic_scan_dquots(h, process_dquot, xfs_get_dquot);
}
/*
diff --git a/quotasys.h b/quotasys.h
index 90e5aae..005b275 100644
--- a/quotasys.h
+++ b/quotasys.h
@@ -20,7 +20,7 @@
/* Flags for IO initialization */
#define IOI_READONLY 0x1 /* Only readonly access */
-#define IOI_OPENFILE 0x2 /* Open file even if kernel has quotas turned on */
+#define IOI_INITSCAN 0x2 /* Prepare handle for scanning dquots */
#define IOI_NFS_MIXED_PATHS 0x4 /* Trim leading / from NFSv4 mountpoints */
#define KERN_KNOWN_QUOTA_VERSION (6*10000 + 5*100 + 1)
diff --git a/repquota.c b/repquota.c
index f781f0d..17dd9e4 100644
--- a/repquota.c
+++ b/repquota.c
@@ -317,9 +317,9 @@ static void report(int type)
int i;
if (flags & FL_ALL)
- handles = create_handle_list(0, NULL, type, fmt, IOI_READONLY | IOI_OPENFILE, MS_LOCALONLY | (flags & FL_NOAUTOFS ? MS_NO_AUTOFS : 0));
+ handles = create_handle_list(0, NULL, type, fmt, IOI_READONLY | IOI_INITSCAN, MS_LOCALONLY | (flags & FL_NOAUTOFS ? MS_NO_AUTOFS : 0));
else
- handles = create_handle_list(mntcnt, mnt, type, fmt, IOI_READONLY | IOI_OPENFILE, MS_LOCALONLY | (flags & FL_NOAUTOFS ? MS_NO_AUTOFS : 0));
+ handles = create_handle_list(mntcnt, mnt, type, fmt, IOI_READONLY | IOI_INITSCAN, MS_LOCALONLY | (flags & FL_NOAUTOFS ? MS_NO_AUTOFS : 0));
for (i = 0; handles[i]; i++)
report_it(handles[i], type);
dispose_handle_list(handles);
diff --git a/warnquota.c b/warnquota.c
index 9f09fcd..2ca286f 100644
--- a/warnquota.c
+++ b/warnquota.c
@@ -951,7 +951,7 @@ static void warn_quota(void)
wc_exit(1);
if (flags & FL_USER) {
- handles = create_handle_list(0, NULL, USRQUOTA, -1, IOI_READONLY | IOI_OPENFILE, MS_LOCALONLY | (flags & FL_NOAUTOFS ? MS_NO_AUTOFS : 0));
+ handles = create_handle_list(0, NULL, USRQUOTA, -1, IOI_READONLY | IOI_INITSCAN, MS_LOCALONLY | (flags & FL_NOAUTOFS ? MS_NO_AUTOFS : 0));
if (!maildev[0] || !strcasecmp(maildev, "any"))
maildev_handle = NULL;
else
@@ -963,7 +963,7 @@ static void warn_quota(void)
if (flags & FL_GROUP) {
if (get_groupadmins() < 0)
wc_exit(1);
- handles = create_handle_list(0, NULL, GRPQUOTA, -1, IOI_READONLY | IOI_OPENFILE, MS_LOCALONLY | (flags & FL_NOAUTOFS ? MS_NO_AUTOFS : 0));
+ handles = create_handle_list(0, NULL, GRPQUOTA, -1, IOI_READONLY | IOI_INITSCAN, MS_LOCALONLY | (flags & FL_NOAUTOFS ? MS_NO_AUTOFS : 0));
if (!maildev[0] || !strcasecmp(maildev, "any"))
maildev_handle = NULL;
else