Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 06 Jul 2018 09:43:26 +0300
From:      Toomas Soome <tsoome@me.com>
To:        Sean Eric Fagan <sef@FreeBSD.org>
Cc:        src-committers <src-committers@freebsd.org>, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   Re: svn commit: r336017 - in head: include/rpcsvc lib/libutil libexec/rpc.rquotad sys/cddl/contrib/opensolaris/uts/common/fs/zfs usr.bin/quota
Message-ID:  <44B06A1B-360C-4826-A1B6-44AF772D70F5@me.com>
In-Reply-To: <201807052256.w65MuETx038724@repo.freebsd.org>
References:  <201807052256.w65MuETx038724@repo.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Hi!

Unfortunately this patch is not quite correct regarding how you define =
the RPC interfaces.

The versioning in RPC is to specify the interface, much like versioning =
in shared library.=20

If you have RPC program version 1, exposing functions get_quota() and =
get_active_quota(), and you want to expose new function, you should =
introduce new version.

The best example about this logic is in mount.x - there you can see how =
they have done 2 versions of the interface, expanding the list of =
exported functions.

The problem is, to create connection with server, you specify =
<RPCROGNUM, VERSION> pair, and if supported, you will get the =
corresponding handle. Now you can have situation with mixed new and old =
interfaces (sharing the same version number) but the exported functions =
are not the same.

rgds,
toomas

> On 6 Jul 2018, at 01:56, Sean Eric Fagan <sef@FreeBSD.org> wrote:
>=20
> Author: sef
> Date: Thu Jul  5 22:56:13 2018
> New Revision: 336017
> URL: https://svnweb.freebsd.org/changeset/base/336017
>=20
> Log:
>  This exposes ZFS user and group quotas via the normal
>  quatactl(2) mechanism.  (Read-only at this point, however.)
>  In particular, this is to allow rpc.rquotad query quotas
>  for NFS mounts, allowing users to see their quotas on the
>  hosts using the datasets.
>=20
>  The changes specifically:
>=20
>  * Add new RPC entry points for querying quotas.
>  * Changes the library routines to allow non-UFS quotas.
>  * Changes rquotad to check for quotas on mounted filesystems,
>  rather than being limited to entries in /etc/fstab
>  * Lastly, adds a VFS entry-point for ZFS to query quotas.
>=20
>  Note that this makes one unavoidable behavioural change: if quotas
>  are enabled, then they can be queried, as opposed to the current
>  method of checking for quotas being specified in fstab.  (With
>  ZFS, if there are user or group quotas, they're used, always.)
>=20
>  Reviewed by:	delphij, mav
>  Approved by:	mav
>  Sponsored by:	iXsystems Inc
>  Differential Revision:	https://reviews.freebsd.org/D15886
>=20
> Modified:
>  head/include/rpcsvc/rquota.x
>  head/lib/libutil/quotafile.c
>  head/libexec/rpc.rquotad/rquotad.c
>  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
>  head/usr.bin/quota/quota.c
>=20
> Modified: head/include/rpcsvc/rquota.x
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/include/rpcsvc/rquota.x	Thu Jul  5 21:38:54 2018	=
(r336016)
> +++ head/include/rpcsvc/rquota.x	Thu Jul  5 22:56:13 2018	=
(r336017)
> @@ -1,24 +1,55 @@
> +/* @(#)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
>  */
>=20
> #ifndef RPC_HDR
> -%#ifndef lint
> -%/*static char sccsid[] =3D "from: @(#)rquota.x 1.2 87/09/20 Copyr =
1987 Sun Micro";*/
> -%/*static char sccsid[] =3D "from: @(#)rquota.x	2.1 88/08/01 4.0 =
RPCSRC";*/
> -%#endif /* not lint */
> %#include <sys/cdefs.h>
> %__FBSDID("$FreeBSD$");
> #endif
>=20
> const RQ_PATHLEN =3D 1024;
>=20
> +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 =
*/
> };
>=20
> +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;
> +};
> +
> /*
>  * remote quota structure
>  */
> @@ -37,7 +68,7 @@ struct rquota {
>=20
> enum gqr_status {
> 	Q_OK =3D 1,		/* quota returned */
> -	Q_NOQUOTA =3D 2,  	/* noquota for uid */
> +	Q_NOQUOTA =3D 2,		/* noquota for uid */
> 	Q_EPERM =3D 3		/* no permission to access quota */
> };
>=20
> @@ -50,6 +81,15 @@ case Q_EPERM:
> 	void;
> };
>=20
> +union setquota_rslt switch (gqr_status status) {
> +case Q_OK:
> +	rquota sqr_rquota;	/* valid if status =3D=3D Q_OK */
> +case Q_NOQUOTA:
> +	void;
> +case Q_EPERM:
> +	void;
> +};
> +
> program RQUOTAPROG {
> 	version RQUOTAVERS {
> 		/*
> @@ -63,5 +103,42 @@ program RQUOTAPROG {
> 		 */
> 		getquota_rslt
> 		RQUOTAPROC_GETACTIVEQUOTA(getquota_args) =3D 2;
> +
> +		/*
> +		 * Set all quotas
> +		 */
> +		setquota_rslt
> +		RQUOTAPROC_SETQUOTA(setquota_args) =3D 3;
> +
> +		/*
> +	 	 * Get active quotas only
> +		 */
> +		setquota_rslt
> +		RQUOTAPROC_SETACTIVEQUOTA(setquota_args) =3D 4;
> 	} =3D 1;
> +	version EXT_RQUOTAVERS {
> +		/*
> +		 * Get all quotas
> +		 */
> +		getquota_rslt
> +		RQUOTAPROC_GETQUOTA(ext_getquota_args) =3D 1;
> +
> +		/*
> +	 	 * Get active quotas only
> +		 */
> +		getquota_rslt
> +		RQUOTAPROC_GETACTIVEQUOTA(ext_getquota_args) =3D 2;
> +
> +		/*
> +		 * Set all quotas
> +		 */
> +		setquota_rslt
> +		RQUOTAPROC_SETQUOTA(ext_setquota_args) =3D 3;
> +
> +		/*
> +	 	 * Set active quotas only
> +		 */
> +		setquota_rslt
> +		RQUOTAPROC_SETACTIVEQUOTA(ext_setquota_args) =3D 4;
> +	} =3D 2;
> } =3D 100011;
>=20
> Modified: head/lib/libutil/quotafile.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/lib/libutil/quotafile.c	Thu Jul  5 21:38:54 2018	=
(r336016)
> +++ head/lib/libutil/quotafile.c	Thu Jul  5 22:56:13 2018	=
(r336017)
> @@ -120,8 +120,6 @@ quota_open(struct fstab *fs, int quotatype, int =
openfl
> 	struct stat st;
> 	int qcmd, serrno;
>=20
> -	if (strcmp(fs->fs_vfstype, "ufs"))
> -		return (NULL);
> 	if ((qf =3D calloc(1, sizeof(*qf))) =3D=3D NULL)
> 		return (NULL);
> 	qf->fd =3D -1;
> @@ -130,10 +128,15 @@ quota_open(struct fstab *fs, int quotatype, int =
openfl
> 	if (stat(qf->fsname, &st) !=3D 0)
> 		goto error;
> 	qf->dev =3D st.st_dev;
> -	serrno =3D hasquota(fs, quotatype, qf->qfname, =
sizeof(qf->qfname));
> 	qcmd =3D QCMD(Q_GETQUOTASIZE, quotatype);
> 	if (quotactl(qf->fsname, qcmd, 0, &qf->wordsize) =3D=3D 0)
> 		return (qf);
> +	/* We only check the quota file for ufs */
> +	if (strcmp(fs->fs_vfstype, "ufs")) {
> +		errno =3D 0;
> +		goto error;
> +	}
> +	serrno =3D hasquota(fs, quotatype, qf->qfname, =
sizeof(qf->qfname));
> 	if (serrno =3D=3D 0) {
> 		errno =3D EOPNOTSUPP;
> 		goto error;
>=20
> Modified: head/libexec/rpc.rquotad/rquotad.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/libexec/rpc.rquotad/rquotad.c	Thu Jul  5 21:38:54 2018	=
(r336016)
> +++ head/libexec/rpc.rquotad/rquotad.c	Thu Jul  5 22:56:13 2018	=
(r336017)
> @@ -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>
>=20
> -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);
>=20
> -static struct quotafile **qfa;	/* array of qfs */
> -static int nqf, szqf;		/* number of qfs and size of =
array */
> static int from_inetd =3D 1;
> +static int debug =3D 0;
>=20
> static void
> cleanup(int sig)
> @@ -51,19 +52,32 @@ cleanup(int sig)
> }
>=20
> int
> -main(void)
> +main(int argc, char **argv)
> {
> 	SVCXPRT *transp;
> 	int ok;
> 	struct sockaddr_storage from;
> 	socklen_t fromlen;
> +	int vers;
> +	int ch;
>=20
> +	while ((ch =3D getopt(argc, argv, "d")) !=3D -1) {
> +		switch (ch) {
> +		case 'd':
> +			debug++;
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> 	fromlen =3D sizeof(from);
> 	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
> 		from_inetd =3D 0;
>=20
> 	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,40 @@ main(void)
> 			syslog(LOG_ERR, "couldn't create udp service.");
> 			exit(1);
> 		}
> +		vers =3D RQUOTAVERS;
> 		ok =3D svc_reg(transp, RQUOTAPROG, RQUOTAVERS,
> -		    rquota_service, NULL);
> +		    rquota_service_1, NULL);
> +		if (ok) {
> +			vers =3D EXT_RQUOTAVERS;
> +			ok =3D svc_reg(transp, RQUOTAPROG, =
EXT_RQUOTAVERS,
> +				     rquota_service_2, NULL);
> +		}
> 	} else {
> -		ok =3D svc_create(rquota_service,
> +		vers =3D RQUOTAVERS;
> +		ok =3D svc_create(rquota_service_1,
> 		    RQUOTAPROG, RQUOTAVERS, "udp");
> +		if (ok) {
> +			vers =3D EXT_RQUOTAVERS;
> +			ok =3D 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 =3D=3D RQUOTAVERS ? "RQUOTAVERS" : =
"EXT_RQUOTAVERS",
> +		       from_inetd ? "(inetd)" : "udp");
> 		exit(1);
> 	}
>=20
> -	initfs();
> 	svc_run();
> 	syslog(LOG_ERR, "svc_run returned");
> 	exit(1);
> }
>=20
> static void
> -rquota_service(struct svc_req *request, SVCXPRT *transp)
> +rquota_service_2(struct svc_req *request, SVCXPRT *transp)
> {
>=20
> 	switch (request->rq_proc) {
> @@ -108,6 +135,26 @@ rquota_service(struct svc_req *request, SVCXPRT =
*trans
> 		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) {
> +	case NULLPROC:
> +		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char =
*)NULL);
> +		break;
> +	case RQUOTAPROC_GETQUOTA:
> +	case RQUOTAPROC_GETACTIVEQUOTA:
> 		sendquota(request, transp);
> 		break;
> 	default:
> @@ -136,7 +183,7 @@ sendquota(struct svc_req *request, SVCXPRT =
*transp)
> 	if (request->rq_cred.oa_flavor !=3D AUTH_UNIX) {
> 		/* bad auth */
> 		getq_rslt.status =3D 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 =3D Q_NOQUOTA;
> 	} else {
> @@ -172,38 +219,55 @@ sendquota(struct svc_req *request, SVCXPRT =
*transp)
> }
>=20
> static void
> -initfs(void)
> +sendquota_extended(struct svc_req *request, SVCXPRT *transp)
> {
> -	struct fstab *fs;
> +	struct ext_getquota_args getq_args;
> +	struct getquota_rslt getq_rslt;
> +	struct dqblk dqblk;
> +	struct timeval timev;
> +	int scale;
>=20
> -	setfsent();
> -	szqf =3D 8;
> -	if ((qfa =3D malloc(szqf * sizeof *qfa)) =3D=3D NULL)
> -		goto enomem;
> -	while ((fs =3D getfsent())) {
> -		if (strcmp(fs->fs_vfstype, "ufs"))
> -			continue;
> -		if (nqf >=3D szqf) {
> -			szqf *=3D 2;
> -			if ((qfa =3D reallocf(qfa, szqf * sizeof *qfa)) =
=3D=3D NULL)
> -				goto enomem;
> -		}
> -		if ((qfa[nqf] =3D quota_open(fs, USRQUOTA, O_RDONLY)) =3D=3D=
 NULL) {
> -			if (errno !=3D EOPNOTSUPP)
> -				goto fserr;
> -			continue;
> -		}
> -		++nqf;
> -		/* XXX */
> +	bzero(&getq_args, sizeof(getq_args));
> +	if (!svc_getargs(transp, (xdrproc_t)xdr_ext_getquota_args, =
&getq_args)) {
> +		svcerr_decode(transp);
> +		return;
> 	}
> -	endfsent();
> -	return;
> -enomem:
> -	syslog(LOG_ERR, "out of memory");
> -	exit(1);
> -fserr:
> -	syslog(LOG_ERR, "%s: %s", fs->fs_file, strerror(errno));
> -	exit(1);
> +	if (request->rq_cred.oa_flavor !=3D AUTH_UNIX) {
> +		/* bad auth */
> +		getq_rslt.status =3D Q_EPERM;
> +	} else if (!getfsquota(getq_args.gqa_type, getq_args.gqa_id, =
getq_args.gqa_pathp, &dqblk)) {
> +		/* failed, return noquota */
> +		getq_rslt.status =3D Q_NOQUOTA;
> +	} else {
> +		gettimeofday(&timev, NULL);
> +		getq_rslt.status =3D Q_OK;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_active =3D TRUE;
> +		scale =3D 1 << flsll(dqblk.dqb_bhardlimit >> 32);
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize =3D
> +		    DEV_BSIZE * scale;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =3D
> +		    dqblk.dqb_bhardlimit / scale;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =3D
> +		    dqblk.dqb_bsoftlimit / scale;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =3D
> +		    dqblk.dqb_curblocks / scale;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =3D
> +		    dqblk.dqb_ihardlimit;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =3D
> +		    dqblk.dqb_isoftlimit;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =3D
> +		    dqblk.dqb_curinodes;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =3D
> +		    dqblk.dqb_btime - timev.tv_sec;
> +		getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =3D
> +		    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);
> +	}
> }
>=20
> /*
> @@ -211,12 +275,43 @@ fserr:
>  * 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[] =3D "";
> +	struct fstab fst;
>=20
> -	for (i =3D 0; i < nqf; ++i)
> -		if (quota_check_path(qfa[i], path) =3D=3D 1)
> -			return (quota_read(qfa[i], dqblk, id) =3D=3D 0);
> -	return (0);
> +	fst.fs_file =3D path;
> +	fst.fs_mntops =3D blank;
> +	fst.fs_vfstype =3D blank;
> +=09
> +	if (type !=3D USRQUOTA && type !=3D GRPQUOTA)
> +		return (0);
> +=09
> +	qf =3D quota_open(&fst, type, O_RDONLY);
> +	if (debug)
> +		warnx("quota_open(<%s, %s>, %d) returned %p",
> +		      fst.fs_file, fst.fs_mntops, type,
> +		      qf);
> +	if (qf =3D=3D NULL)
> +		return (0);
> +
> +	rv =3D quota_read(qf, dqblk, id) =3D=3D 0;
> +	quota_close(qf);
> +	if (debug)
> +		warnx("getfsquota(%d, %ld, %s, %p) -> %d",
> +		      type, id, path, dqblk, rv);
> +	return (rv);
> }
>=20
> Modified: =
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c	=
Thu Jul  5 21:38:54 2018	(r336016)
> +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c	=
Thu Jul  5 22:56:13 2018	(r336017)
> @@ -64,6 +64,8 @@
> #include <sys/dmu_objset.h>
> #include <sys/spa_boot.h>
> #include <sys/jail.h>
> +#include <ufs/ufs/quota.h>
> +
> #include "zfs_comutil.h"
>=20
> struct mtx zfs_debug_mtx;
> @@ -90,6 +92,7 @@ static int zfs_version_zpl =3D ZPL_VERSION;
> SYSCTL_INT(_vfs_zfs_version, OID_AUTO, zpl, CTLFLAG_RD, =
&zfs_version_zpl, 0,
>     "ZPL_VERSION");
>=20
> +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);
> @@ -111,6 +114,7 @@ struct vfsops zfs_vfsops =3D {
> 	.vfs_sync =3D		zfs_sync,
> 	.vfs_checkexp =3D		zfs_checkexp,
> 	.vfs_fhtovp =3D		zfs_fhtovp,
> +	.vfs_quotactl =3D		zfs_quotactl,
> };
>=20
> VFS_SET(zfs_vfsops, zfs, VFCF_JAIL | VFCF_DELEGADMIN);
> @@ -121,6 +125,159 @@ VFS_SET(zfs_vfsops, zfs, VFCF_JAIL | =
VFCF_DELEGADMIN);
>  * from being unloaded after a umount -f
>  */
> static uint32_t	zfs_active_fs_count =3D 0;
> +
> +static int
> +zfs_getquota(zfsvfs_t *zfsvfs, uid_t id, int isgroup, struct dqblk64 =
*dqp)
> +{
> +	int error =3D 0;
> +	char buf[32];
> +	int err;
> +	uint64_t usedobj, quotaobj;
> +	uint64_t quota, used =3D 0;
> +	timespec_t now;
> +=09
> +	usedobj =3D isgroup ? DMU_GROUPUSED_OBJECT : =
DMU_USERUSED_OBJECT;
> +	quotaobj =3D isgroup ? zfsvfs->z_groupquota_obj : =
zfsvfs->z_userquota_obj;
> +
> +	if (quotaobj =3D=3D 0 || zfsvfs->z_replay) {
> +		error =3D ENOENT;
> +		goto done;
> +	}
> +	(void)sprintf(buf, "%llx", (longlong_t)id);
> +	if ((error =3D zap_lookup(zfsvfs->z_os, quotaobj,
> +				buf, sizeof(quota), 1, &quota)) !=3D 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 =3D dqp->dqb_bhardlimit =3D btodb(quota);
> +	error =3D zap_lookup(zfsvfs->z_os, usedobj, buf, sizeof(used), =
1, &used);
> +	if (error && error !=3D ENOENT) {
> +		dprintf("%s(%d):  usedobj failed; %d\n", __FUNCTION__, =
__LINE__, error);
> +		goto done;
> +	}
> +	dqp->dqb_curblocks =3D btodb(used);
> +	dqp->dqb_ihardlimit =3D dqp->dqb_isoftlimit =3D 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 =3D dqp->dqb_itime =3D now.tv_sec;
> +done:
> +	return (error);
> +}
> +
> +static int
> +zfs_quotactl(vfs_t *vfsp, int cmds, uid_t id, void *arg)
> +{
> +	zfsvfs_t *zfsvfs =3D vfsp->vfs_data;
> +	struct thread *td;
> +	int cmd, type, error =3D 0;
> +	int bitsize;
> +	uint64_t fuid;
> +	zfs_userquota_prop_t quota_type;
> +	struct dqblk64 dqblk =3D { 0 };
> +=09
> +	td =3D curthread;
> +	cmd =3D cmds >> SUBCMDSHIFT;
> +	type =3D cmds & SUBCMDMASK;
> +
> +	ZFS_ENTER(zfsvfs);
> +	if (id =3D=3D -1) {
> +		switch (type) {
> +		case USRQUOTA:
> +			id =3D td->td_ucred->cr_ruid;
> +			break;
> +		case GRPQUOTA:
> +			id =3D td->td_ucred->cr_rgid;
> +			break;
> +		default:
> +			error =3D 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 =3D=3D USRQUOTA)
> +			quota_type =3D ZFS_PROP_USERQUOTA;
> +		else if (type =3D=3D GRPQUOTA)
> +			quota_type =3D ZFS_PROP_GROUPQUOTA;
> +		else
> +			error =3D EINVAL;
> +		break;
> +	case Q_GETQUOTA:
> +	case Q_GETQUOTA32:
> +		if (type =3D=3D USRQUOTA)
> +			quota_type =3D ZFS_PROP_USERUSED;
> +		else if (type =3D=3D GRPQUOTA)
> +			quota_type =3D ZFS_PROP_GROUPUSED;
> +		else
> +			error =3D 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, &quota)
> +	 *
> +	 * See zfs_set_userquota() to set a quota.
> +	 */
> +	if ((u_int)type >=3D MAXQUOTAS) {
> +		error =3D EINVAL;
> +		goto done;
> +	}
> +
> +	switch (cmd) {
> +	case Q_GETQUOTASIZE:
> +		bitsize =3D 64;
> +		error =3D 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 =3D 0;
> +		break;
> +	case Q_QUOTAOFF:
> +		error =3D ENOTSUP;
> +		break;
> +	case Q_SETQUOTA:
> +		error =3D copyin(&dqblk, arg, sizeof(dqblk));
> +		if (error =3D=3D 0)
> +			error =3D zfs_set_userquota(zfsvfs, quota_type,
> +						  "", id, =
dbtob(dqblk.dqb_bhardlimit));
> +		break;
> +	case Q_GETQUOTA:
> +		error =3D zfs_getquota(zfsvfs, id, type =3D=3D GRPQUOTA, =
&dqblk);
> +		if (error =3D=3D 0)
> +			error =3D copyout(&dqblk, arg, sizeof(dqblk));
> +		break;
> +	default:
> +		error =3D EINVAL;
> +		break;
> +	}
> +done:
> +	ZFS_EXIT(zfsvfs);
> +	return (error);
> +}
>=20
> /*ARGSUSED*/
> static int
>=20
> Modified: head/usr.bin/quota/quota.c
> =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
> --- head/usr.bin/quota/quota.c	Thu Jul  5 21:38:54 2018	=
(r336016)
> +++ head/usr.bin/quota/quota.c	Thu Jul  5 22:56:13 2018	=
(r336017)
> @@ -98,7 +98,7 @@ static int getufsquota(struct fstab *fs, struct =
quotau
> 	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,=20
> +static enum clnt_stat callaurpc(char *host, int prognum, int versnum, =
int procnum,=20
> 	xdrproc_t inproc, char *in, xdrproc_t outproc, char *out);
> static int alldigits(char *s);
>=20
> @@ -568,22 +568,18 @@ getufsquota(struct fstab *fs, struct quotause =
*qup, lo
> 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 =3D &qup->dqblk;
> 	struct timeval tv;
> 	char *cp, host[NI_MAXHOST];
> +	enum clnt_stat call_stat;
>=20
> 	if (fst->f_flags & MNT_LOCAL)
> 		return (0);
>=20
> 	/*
> -	 * rpc.rquotad does not support group quotas
> -	 */
> -	if (quotatype !=3D USRQUOTA)
> -		return (0);
> -
> -	/*
> 	 * must be some form of "hostname:/path"
> 	 */
> 	cp =3D fst->f_mntfromname;
> @@ -604,12 +600,27 @@ getnfsquota(struct statfs *fst, struct quotause =
*qup,=20
> 		return (0);
>=20
> 	gq_args.gqa_pathp =3D cp + 1;
> -	gq_args.gqa_uid =3D id;
> -	if (callaurpc(host, RQUOTAPROG, RQUOTAVERS,
> -	    RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, (char =
*)&gq_args,
> -	    (xdrproc_t)xdr_getquota_rslt, (char *)&gq_rslt) !=3D 0)
> -		return (0);
> +	gq_args.gqa_id =3D id;
> +	gq_args.gqa_type =3D quotatype;
>=20
> +	call_stat =3D 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 =3D=3D RPC_PROGVERSMISMATCH) {
> +		if (quotatype =3D=3D USRQUOTA) {
> +			old_gq_args.gqa_pathp =3D cp + 1;
> +			old_gq_args.gqa_uid =3D id;
> +			call_stat =3D 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 !=3D 0)
> +		return (call_stat);
> +
> 	switch (gq_rslt.status) {
> 	case Q_NOQUOTA:
> 		break;
> @@ -650,7 +661,7 @@ getnfsquota(struct statfs *fst, struct quotause =
*qup,=20
> 	return (0);
> }
>=20
> -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)
> {
> @@ -671,8 +682,7 @@ callaurpc(char *host, int prognum, int versnum, =
int pr
> 	tottimeout.tv_usec =3D 0;
> 	clnt_stat =3D clnt_call(client, procnum, inproc, in,
> 	    outproc, out, tottimeout);
> -=20
> -	return ((int) clnt_stat);
> +	return (clnt_stat);
> }
>=20
> static int
>=20




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?44B06A1B-360C-4826-A1B6-44AF772D70F5>