support for ZFS user quotas in rquotad
Sean Eric Fagan
sef at Kithrup.COM
Tue Jun 5 19:11:54 UTC 2018
>I will try your patches.
They're about a year old, I think, there hasn't seemed to be much call for the
feature. But enjoy!
diff --git a/include/rpcsvc/rquota.x b/include/rpcsvc/rquota.x
index 0f3ecfc54d2..83e3533d0cc 100644
--- a/include/rpcsvc/rquota.x
+++ b/include/rpcsvc/rquota.x
@@ -1,3 +1,6 @@
+/* @(#)rquota.x 2.1 88/08/01 4.0 RPCSRC */
+/* @(#)rquota.x 1.2 87/09/20 Copyr 1987 Sun Micro */
+
/*
* Remote quota protocol
* Requires unix authentication
@@ -14,9 +17,41 @@
const RQ_PATHLEN = 1024;
+struct sq_dqblk {
+ unsigned int rq_bhardlimit; /* absolute limit on disk blks alloc */
+ unsigned int rq_bsoftlimit; /* preferred limit on disk blks */
+ unsigned int rq_curblocks; /* current block count */
+ unsigned int rq_fhardlimit; /* absolute limit on allocated files */
+ unsigned int rq_fsoftlimit; /* preferred file limit */
+ unsigned int rq_curfiles; /* current # allocated files */
+ unsigned int rq_btimeleft; /* time left for excessive disk use */
+ unsigned int rq_ftimeleft; /* time left for excessive files */
+};
+
struct getquota_args {
string gqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */
- int gqa_uid; /* inquire about quota for uid */
+ int gqa_uid; /* Inquire about quota for uid */
+};
+
+struct setquota_args {
+ int sqa_qcmd;
+ string sqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */
+ int sqa_id; /* Set quota for uid */
+ sq_dqblk sqa_dqblk;
+};
+
+struct ext_getquota_args {
+ string gqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */
+ int gqa_type; /* Type of quota info is needed about */
+ int gqa_id; /* Inquire about quota for id */
+};
+
+struct ext_setquota_args {
+ int sqa_qcmd;
+ string sqa_pathp<RQ_PATHLEN>; /* path to filesystem of interest */
+ int sqa_id; /* Set quota for id */
+ int sqa_type; /* Type of quota to set */
+ sq_dqblk sqa_dqblk;
};
/*
@@ -37,7 +72,7 @@ struct rquota {
enum gqr_status {
Q_OK = 1, /* quota returned */
- Q_NOQUOTA = 2, /* noquota for uid */
+ Q_NOQUOTA = 2, /* noquota for uid */
Q_EPERM = 3 /* no permission to access quota */
};
@@ -50,6 +85,15 @@ case Q_EPERM:
void;
};
+union setquota_rslt switch (gqr_status status) {
+case Q_OK:
+ rquota sqr_rquota; /* valid if status == Q_OK */
+case Q_NOQUOTA:
+ void;
+case Q_EPERM:
+ void;
+};
+
program RQUOTAPROG {
version RQUOTAVERS {
/*
@@ -63,5 +107,42 @@ program RQUOTAPROG {
*/
getquota_rslt
RQUOTAPROC_GETACTIVEQUOTA(getquota_args) = 2;
+
+ /*
+ * Set all quotas
+ */
+ setquota_rslt
+ RQUOTAPROC_SETQUOTA(setquota_args) = 3;
+
+ /*
+ * Get active quotas only
+ */
+ setquota_rslt
+ RQUOTAPROC_SETACTIVEQUOTA(setquota_args) = 4;
} = 1;
+ version EXT_RQUOTAVERS {
+ /*
+ * Get all quotas
+ */
+ getquota_rslt
+ RQUOTAPROC_GETQUOTA(ext_getquota_args) = 1;
+
+ /*
+ * Get active quotas only
+ */
+ getquota_rslt
+ RQUOTAPROC_GETACTIVEQUOTA(ext_getquota_args) = 2;
+
+ /*
+ * Set all quotas
+ */
+ setquota_rslt
+ RQUOTAPROC_SETQUOTA(ext_setquota_args) = 3;
+
+ /*
+ * Set active quotas only
+ */
+ setquota_rslt
+ RQUOTAPROC_SETACTIVEQUOTA(ext_setquota_args) = 4;
+ } = 2;
} = 100011;
diff --git a/lib/libutil/quotafile.c b/lib/libutil/quotafile.c
index 27444c2e31a..1ea16c58a2f 100644
--- a/lib/libutil/quotafile.c
+++ b/lib/libutil/quotafile.c
@@ -118,8 +118,6 @@ quota_open(struct fstab *fs, int quotatype, int openflags)
struct stat st;
int qcmd, serrno;
- if (strcmp(fs->fs_vfstype, "ufs"))
- return (NULL);
if ((qf = calloc(1, sizeof(*qf))) == NULL)
return (NULL);
qf->fd = -1;
@@ -128,10 +126,13 @@ quota_open(struct fstab *fs, int quotatype, int openflags)
if (stat(qf->fsname, &st) != 0)
goto error;
qf->dev = st.st_dev;
- serrno = hasquota(fs, quotatype, qf->qfname, sizeof(qf->qfname));
qcmd = QCMD(Q_GETQUOTASIZE, quotatype);
if (quotactl(qf->fsname, qcmd, 0, &qf->wordsize) == 0)
return (qf);
+ /* We only check the quota file for ufs */
+ if (strcmp(fs->fs_vfstype, "ufs"))
+ return (NULL);
+ serrno = hasquota(fs, quotatype, qf->qfname, sizeof(qf->qfname));
if (serrno == 0) {
errno = EOPNOTSUPP;
goto error;
diff --git a/libexec/rpc.rquotad/rquotad.c b/libexec/rpc.rquotad/rquotad.c
index d9ce06aac82..61bc7466687 100644
--- a/libexec/rpc.rquotad/rquotad.c
+++ b/libexec/rpc.rquotad/rquotad.c
@@ -28,18 +28,19 @@ __FBSDID("$FreeBSD$");
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <err.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
-static void rquota_service(struct svc_req *request, SVCXPRT *transp);
+static void rquota_service_1(struct svc_req *request, SVCXPRT *transp);
+static void rquota_service_2(struct svc_req *request, SVCXPRT *transp);
static void sendquota(struct svc_req *request, SVCXPRT *transp);
-static void initfs(void);
-static int getfsquota(long id, char *path, struct dqblk *dqblk);
+static void sendquota_extended(struct svc_req *request, SVCXPRT *transp);
+static int getfsquota(int type, long id, char *path, struct dqblk *dqblk);
-static struct quotafile **qfa; /* array of qfs */
-static int nqf, szqf; /* number of qfs and size of array */
static int from_inetd = 1;
+static int debug = 0;
static void
cleanup(int sig)
@@ -51,19 +52,32 @@ cleanup(int sig)
}
int
-main(void)
+main(int argc, char **argv)
{
SVCXPRT *transp;
int ok;
struct sockaddr_storage from;
socklen_t fromlen;
+ int vers;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "d")) != -1) {
+ switch (ch) {
+ case 'd':
+ debug++;
+ break;
+ default:
+ break;
+ }
+ }
fromlen = sizeof(from);
if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
from_inetd = 0;
if (!from_inetd) {
- daemon(0, 0);
+ if (!debug)
+ daemon(0, 0);
(void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
(void)signal(SIGINT, cleanup);
(void)signal(SIGTERM, cleanup);
@@ -79,27 +93,60 @@ main(void)
syslog(LOG_ERR, "couldn't create udp service.");
exit(1);
}
+ vers = RQUOTAVERS;
ok = svc_reg(transp, RQUOTAPROG, RQUOTAVERS,
- rquota_service, NULL);
+ rquota_service_1, NULL);
+ if (ok) {
+ vers = EXT_RQUOTAVERS;
+ ok = svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS,
+ rquota_service_2, NULL);
+ }
} else {
- ok = svc_create(rquota_service,
+ vers = RQUOTAVERS;
+ ok = svc_create(rquota_service_1,
RQUOTAPROG, RQUOTAVERS, "udp");
+ if (ok) {
+ vers = EXT_RQUOTAVERS;
+ ok = svc_create(rquota_service_2,
+ RQUOTAPROG, EXT_RQUOTAVERS, "udp");
+
+ }
}
if (!ok) {
syslog(LOG_ERR,
- "unable to register (RQUOTAPROG, RQUOTAVERS, %s)",
- from_inetd ? "(inetd)" : "udp");
+ "unable to register (RQUOTAPROG, %s, %s)",
+ vers == RQUOTAVERS ? "RQUOTAVERS" : "EXT_RQUOTAVERS",
+ from_inetd ? "(inetd)" : "udp");
exit(1);
}
- initfs();
svc_run();
syslog(LOG_ERR, "svc_run returned");
exit(1);
}
static void
-rquota_service(struct svc_req *request, SVCXPRT *transp)
+rquota_service_2(struct svc_req *request, SVCXPRT *transp)
+{
+
+ switch (request->rq_proc) {
+ case NULLPROC:
+ (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
+ break;
+ case RQUOTAPROC_GETQUOTA:
+ case RQUOTAPROC_GETACTIVEQUOTA:
+ sendquota_extended(request, transp);
+ break;
+ default:
+ svcerr_noproc(transp);
+ break;
+ }
+ if (from_inetd)
+ exit(0);
+}
+
+static void
+rquota_service_1(struct svc_req *request, SVCXPRT *transp)
{
switch (request->rq_proc) {
@@ -136,7 +183,7 @@ sendquota(struct svc_req *request, SVCXPRT *transp)
if (request->rq_cred.oa_flavor != AUTH_UNIX) {
/* bad auth */
getq_rslt.status = Q_EPERM;
- } else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
+ } else if (!getfsquota(USRQUOTA, getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) {
/* failed, return noquota */
getq_rslt.status = Q_NOQUOTA;
} else {
@@ -172,38 +219,55 @@ sendquota(struct svc_req *request, SVCXPRT *transp)
}
static void
-initfs(void)
+sendquota_extended(struct svc_req *request, SVCXPRT *transp)
{
- struct fstab *fs;
-
- setfsent();
- szqf = 8;
- if ((qfa = malloc(szqf * sizeof *qfa)) == NULL)
- goto enomem;
- while ((fs = getfsent())) {
- if (strcmp(fs->fs_vfstype, "ufs"))
- continue;
- if (nqf >= szqf) {
- szqf *= 2;
- if ((qfa = reallocf(qfa, szqf * sizeof *qfa)) == NULL)
- goto enomem;
- }
- if ((qfa[nqf] = quota_open(fs, USRQUOTA, O_RDONLY)) == NULL) {
- if (errno != EOPNOTSUPP)
- goto fserr;
- continue;
- }
- ++nqf;
- /* XXX */
+ struct ext_getquota_args getq_args;
+ struct getquota_rslt getq_rslt;
+ struct dqblk dqblk;
+ struct timeval timev;
+ int scale;
+
+ bzero(&getq_args, sizeof(getq_args));
+ if (!svc_getargs(transp, (xdrproc_t)xdr_ext_getquota_args, &getq_args)) {
+ svcerr_decode(transp);
+ return;
+ }
+ if (request->rq_cred.oa_flavor != AUTH_UNIX) {
+ /* bad auth */
+ getq_rslt.status = Q_EPERM;
+ } else if (!getfsquota(getq_args.gqa_type, getq_args.gqa_id, getq_args.gqa_pathp, &dqblk)) {
+ /* failed, return noquota */
+ getq_rslt.status = Q_NOQUOTA;
+ } else {
+ gettimeofday(&timev, NULL);
+ getq_rslt.status = Q_OK;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
+ scale = 1 << flsll(dqblk.dqb_bhardlimit >> 32);
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize =
+ DEV_BSIZE * scale;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
+ dqblk.dqb_bhardlimit / scale;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
+ dqblk.dqb_bsoftlimit / scale;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
+ dqblk.dqb_curblocks / scale;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
+ dqblk.dqb_ihardlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
+ dqblk.dqb_isoftlimit;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
+ dqblk.dqb_curinodes;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
+ dqblk.dqb_btime - timev.tv_sec;
+ getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
+ dqblk.dqb_itime - timev.tv_sec;
+ }
+ if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, &getq_rslt))
+ svcerr_systemerr(transp);
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) {
+ syslog(LOG_ERR, "unable to free arguments");
+ exit(1);
}
- endfsent();
- return;
-enomem:
- syslog(LOG_ERR, "out of memory");
- exit(1);
-fserr:
- syslog(LOG_ERR, "%s: %s", fs->fs_file, strerror(errno));
- exit(1);
}
/*
@@ -211,12 +275,43 @@ initfs(void)
* Return 0 if fail, 1 otherwise
*/
static int
-getfsquota(long id, char *path, struct dqblk *dqblk)
+getfsquota(int type, long id, char *path, struct dqblk *dqblk)
{
- int i;
+ struct quotafile *qf;
+ /*
+ * Remote quota checking is limited to mounted filesystems.
+ * Since UFS and ZFS support the quota system calls, we
+ * only need to make an fstab object that has the path, and
+ * a blank name for the filesystem type.
+ * This allows the quota_open() call to work the way we
+ * expect it to.
+ *
+ * The static char declaration is because compiler warnings
+ * don't allow passing a const char * to a char *.
+ */
+ int rv;
+ static char blank[] = "";
+ struct fstab fst;
+
+ fst.fs_file = path;
+ fst.fs_mntops = blank;
+ fst.fs_vfstype = blank;
+
+ if (type != USRQUOTA && type != GRPQUOTA)
+ return (0);
+
+ qf = quota_open(&fst, type, O_RDONLY);
+ if (debug)
+ warnx("quota_opoen(<%s, %s>, %d) returned %p",
+ fst.fs_file, fst.fs_mntops, type,
+ qf);
+ if (qf == NULL)
+ return (0);
- for (i = 0; i < nqf; ++i)
- if (quota_check_path(qfa[i], path) == 1)
- return (quota_read(qfa[i], dqblk, id) == 0);
- return (0);
+ rv = quota_read(qf, dqblk, id) == 0;
+ quota_close(qf);
+ if (debug)
+ warnx("getfsquota(%d, %ld, %s, %p) -> %d",
+ type, id, path, dqblk, rv);
+ return (rv);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
index 430ee528cdd..aabc04827c1 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
@@ -63,6 +63,8 @@
#include <sys/dmu_objset.h>
#include <sys/spa_boot.h>
#include <sys/jail.h>
+#include <ufs/ufs/quota.h>
+
#include "zfs_comutil.h"
struct mtx zfs_debug_mtx;
@@ -89,6 +91,7 @@ static int zfs_version_zpl = ZPL_VERSION;
SYSCTL_INT(_vfs_zfs_version, OID_AUTO, zpl, CTLFLAG_RD, &zfs_version_zpl, 0,
"ZPL_VERSION");
+static int zfs_quotactl(vfs_t *vfsp, int cmds, uid_t id, void *arg);
static int zfs_mount(vfs_t *vfsp);
static int zfs_umount(vfs_t *vfsp, int fflag);
static int zfs_root(vfs_t *vfsp, int flags, vnode_t **vpp);
@@ -110,6 +113,7 @@ struct vfsops zfs_vfsops = {
.vfs_sync = zfs_sync,
.vfs_checkexp = zfs_checkexp,
.vfs_fhtovp = zfs_fhtovp,
+ .vfs_quotactl = zfs_quotactl,
};
VFS_SET(zfs_vfsops, zfs, VFCF_JAIL | VFCF_DELEGADMIN);
@@ -121,6 +125,159 @@ VFS_SET(zfs_vfsops, zfs, VFCF_JAIL | VFCF_DELEGADMIN);
*/
static uint32_t zfs_active_fs_count = 0;
+static int
+zfs_getquota(zfsvfs_t *zfsvfs, uid_t id, int isgroup, struct dqblk64 *dqp)
+{
+ int error = 0;
+ char buf[32];
+ int err;
+ uint64_t usedobj, quotaobj;
+ uint64_t quota, used = 0;
+ timespec_t now;
+
+ usedobj = isgroup ? DMU_GROUPUSED_OBJECT : DMU_USERUSED_OBJECT;
+ quotaobj = isgroup ? zfsvfs->z_groupquota_obj : zfsvfs->z_userquota_obj;
+
+ if (quotaobj == 0 || zfsvfs->z_replay) {
+ error = ENOENT;
+ goto done;
+ }
+ (void)sprintf(buf, "%llx", (longlong_t)id);
+ if ((error = zap_lookup(zfsvfs->z_os, quotaobj,
+ buf, sizeof(quota), 1, "a)) != 0) {
+ dprintf("%s(%d): quotaobj lookup failed\n", __FUNCTION__, __LINE__);
+ goto done;
+ }
+ /*
+ * quota(8) uses bsoftlimit as "quoota", and hardlimit as "limit".
+ * So we set them to be the same.
+ */
+ dqp->dqb_bsoftlimit = dqp->dqb_bhardlimit = btodb(quota);
+ error = zap_lookup(zfsvfs->z_os, usedobj, buf, sizeof(used), 1, &used);
+ if (error && error != ENOENT) {
+ dprintf("%s(%d): usedobj failed; %d\n", __FUNCTION__, __LINE__, error);
+ goto done;
+ }
+ dqp->dqb_curblocks = btodb(used);
+ dqp->dqb_ihardlimit = dqp->dqb_isoftlimit = 0;
+ vfs_timestamp(&now);
+ /*
+ * Setting this to 0 causes FreeBSD quota(8) to print
+ * the number of days since the epoch, which isn't
+ * particularly useful.
+ */
+ dqp->dqb_btime = dqp->dqb_itime = now.tv_sec;
+done:
+ return (error);
+}
+
+static int
+zfs_quotactl(vfs_t *vfsp, int cmds, uid_t id, void *arg)
+{
+ zfsvfs_t *zfsvfs = vfsp->vfs_data;
+ struct thread *td;
+ int cmd, type, error = 0;
+ int bitsize;
+ uint64_t fuid;
+ zfs_userquota_prop_t quota_type;
+ struct dqblk64 dqblk = { 0 };
+
+ td = curthread;
+ cmd = cmds >> SUBCMDSHIFT;
+ type = cmds & SUBCMDMASK;
+
+ ZFS_ENTER(zfsvfs);
+ if (id == -1) {
+ switch (type) {
+ case USRQUOTA:
+ id = td->td_ucred->cr_ruid;
+ break;
+ case GRPQUOTA:
+ id = td->td_ucred->cr_rgid;
+ break;
+ default:
+ error = EINVAL;
+ goto done;
+ }
+ }
+ /*
+ * Map BSD type to:
+ * ZFS_PROP_USERUSED,
+ * ZFS_PROP_USERQUOTA,
+ * ZFS_PROP_GROUPUSED,
+ * ZFS_PROP_GROUPQUOTA
+ */
+ switch (cmd) {
+ case Q_SETQUOTA:
+ case Q_SETQUOTA32:
+ if (type == USRQUOTA)
+ quota_type = ZFS_PROP_USERQUOTA;
+ else if (type == GRPQUOTA)
+ quota_type = ZFS_PROP_GROUPQUOTA;
+ else
+ error = EINVAL;
+ break;
+ case Q_GETQUOTA:
+ case Q_GETQUOTA32:
+ if (type == USRQUOTA)
+ quota_type = ZFS_PROP_USERUSED;
+ else if (type == GRPQUOTA)
+ quota_type = ZFS_PROP_GROUPUSED;
+ else
+ error = EINVAL;
+ break;
+ }
+
+ /*
+ * Depending on the cmd, we may need to get
+ * the ruid and domain (see fuidstr_to_sid?),
+ * the fuid (how?), or other information.
+ * Create fuid using zfs_fuid_create(zfsvfs, id,
+ * ZFS_OWNER or ZFS_GROUP, cr, &fuidp)?
+ * I think I can use just the id?
+ *
+ * Look at zfs_fuid_overquota() to look up a quota.
+ * zap_lookup(something, quotaobj, fuidstring, sizeof(long long), 1, "a)
+ *
+ * See zfs_set_userquota() to set a quota.
+ */
+ if ((u_int)type >= MAXQUOTAS) {
+ error = EINVAL;
+ goto done;
+ }
+
+ switch (cmd) {
+ case Q_GETQUOTASIZE:
+ bitsize = 64;
+ error = copyout(&bitsize, arg, sizeof(int));
+ break;
+ case Q_QUOTAON:
+ // As far as I can tell, you can't turn quotas on or off on zfs
+ error = 0;
+ break;
+ case Q_QUOTAOFF:
+ error = ENOTSUP;
+ break;
+ case Q_SETQUOTA:
+ error = copyin(&dqblk, arg, sizeof(dqblk));
+ if (error == 0)
+ error = zfs_set_userquota(zfsvfs, quota_type,
+ "", id, dbtob(dqblk.dqb_bhardlimit));
+ break;
+ case Q_GETQUOTA:
+ error = zfs_getquota(zfsvfs, id, type == GRPQUOTA, &dqblk);
+ if (error == 0)
+ error = copyout(&dqblk, arg, sizeof(dqblk));
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+done:
+ ZFS_EXIT(zfsvfs);
+ return (error);
+}
+
/*ARGSUSED*/
static int
zfs_sync(vfs_t *vfsp, int waitfor)
diff --git a/usr.bin/quota/quota.c b/usr.bin/quota/quota.c
index c88f2aaefd8..32bdeabdadf 100644
--- a/usr.bin/quota/quota.c
+++ b/usr.bin/quota/quota.c
@@ -96,7 +96,7 @@ static int getufsquota(struct fstab *fs, struct quotause *qup, long id,
int quotatype);
static int getnfsquota(struct statfs *fst, struct quotause *qup, long id,
int quotatype);
-static int callaurpc(char *host, int prognum, int versnum, int procnum,
+static enum clnt_stat callaurpc(char *host, int prognum, int versnum, int procnum,
xdrproc_t inproc, char *in, xdrproc_t outproc, char *out);
static int alldigits(char *s);
@@ -566,21 +566,17 @@ getufsquota(struct fstab *fs, struct quotause *qup, long id, int quotatype)
static int
getnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype)
{
- struct getquota_args gq_args;
+ struct ext_getquota_args gq_args;
+ struct getquota_args old_gq_args;
struct getquota_rslt gq_rslt;
struct dqblk *dqp = &qup->dqblk;
struct timeval tv;
char *cp, host[NI_MAXHOST];
+ enum clnt_stat call_stat;
if (fst->f_flags & MNT_LOCAL)
return (0);
- /*
- * rpc.rquotad does not support group quotas
- */
- if (quotatype != USRQUOTA)
- return (0);
-
/*
* must be some form of "hostname:/path"
*/
@@ -602,11 +598,26 @@ getnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype)
return (0);
gq_args.gqa_pathp = cp + 1;
- gq_args.gqa_uid = id;
- if (callaurpc(host, RQUOTAPROG, RQUOTAVERS,
- RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&gq_args,
- (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt) != 0)
- return (0);
+ gq_args.gqa_id = id;
+ gq_args.gqa_type = quotatype;
+
+ call_stat = callaurpc(host, RQUOTAPROG, EXT_RQUOTAVERS,
+ RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_ext_getquota_args, (char *)&gq_args,
+ (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt);
+ if (call_stat == RPC_PROGVERSMISMATCH) {
+ if (quotatype == USRQUOTA) {
+ old_gq_args.gqa_pathp = cp + 1;
+ old_gq_args.gqa_uid = id;
+ call_stat = callaurpc(host, RQUOTAPROG, RQUOTAVERS,
+ RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char *)&old_gq_args,
+ (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt);
+ } else {
+ /* Old rpc quota does not support group type */
+ return (0);
+ }
+ }
+ if (call_stat != 0)
+ return (call_stat);
switch (gq_rslt.status) {
case Q_NOQUOTA:
@@ -648,7 +659,7 @@ getnfsquota(struct statfs *fst, struct quotause *qup, long id, int quotatype)
return (0);
}
-static int
+static enum clnt_stat
callaurpc(char *host, int prognum, int versnum, int procnum,
xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
{
@@ -669,8 +680,7 @@ callaurpc(char *host, int prognum, int versnum, int procnum,
tottimeout.tv_usec = 0;
clnt_stat = clnt_call(client, procnum, inproc, in,
outproc, out, tottimeout);
-
- return ((int) clnt_stat);
+ return (clnt_stat);
}
static int
More information about the freebsd-fs
mailing list