From owner-svn-src-head@freebsd.org Fri Jul 6 06:43:15 2018 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C50C61045B36; Fri, 6 Jul 2018 06:43:14 +0000 (UTC) (envelope-from tsoome@me.com) Received: from st13p35im-asmtp001.me.com (st13p35im-asmtp001.me.com [17.164.199.64]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 7143C8EA03; Fri, 6 Jul 2018 06:43:14 +0000 (UTC) (envelope-from tsoome@me.com) Received: from process-dkim-sign-daemon.st13p35im-asmtp001.me.com by st13p35im-asmtp001.me.com (Oracle Communications Messaging Server 8.0.1.2.20170607 64bit (built Jun 7 2017)) id <0PBF00800MGQZU00@st13p35im-asmtp001.me.com>; Fri, 06 Jul 2018 06:43:08 +0000 (GMT) Received: from icloud.com ([127.0.0.1]) by st13p35im-asmtp001.me.com (Oracle Communications Messaging Server 8.0.1.2.20170607 64bit (built Jun 7 2017)) with ESMTPSA id <0PBF00L9RMNSKD10@st13p35im-asmtp001.me.com>; Fri, 06 Jul 2018 06:43:07 +0000 (GMT) X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2018-07-06_02:,, signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 clxscore=1011 suspectscore=1 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000 definitions=main-1807060073 Content-type: text/plain; charset=us-ascii MIME-version: 1.0 (Mac OS X Mail 11.4 \(3445.8.2\)) 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 From: Toomas Soome In-reply-to: <201807052256.w65MuETx038724@repo.freebsd.org> Date: Fri, 06 Jul 2018 09:43:26 +0300 Cc: src-committers , svn-src-all@freebsd.org, svn-src-head@freebsd.org Content-transfer-encoding: quoted-printable Message-id: <44B06A1B-360C-4826-A1B6-44AF772D70F5@me.com> References: <201807052256.w65MuETx038724@repo.freebsd.org> To: Sean Eric Fagan X-Mailer: Apple Mail (2.3445.8.2) X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 06 Jul 2018 06:43:15 -0000 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 = 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 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 > %__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; /* 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; /* path to filesystem of = interest */ > + int sqa_id; /* Set quota for uid */ > + sq_dqblk sqa_dqblk; > +}; > + > +struct ext_getquota_args { > + string gqa_pathp; /* 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; /* 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 > #include > #include > +#include > #include > #include > #include >=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 > #include > #include > +#include > + > #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, "a)) !=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, "a) > + * > + * 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