NFS quota support for FreeBSD

Stefan (metze) Metzmacher metze at samba.org
Wed Jun 2 06:58:00 GMT 2004


Jeremy, Jerry,

any objectsions if I apply this?
I can't test it here and I don't want to break the next release:-)
But the patch looks good and it only takes effect when using --with-quotas

> I seem to have Samba 3.0.4 on FreeBSD properly fetching quota information
> for NFS filesystems. The code that does the work (nfs_quotas() and friends)
> was taken from the Sun implementation so I can't take much credit. :-)
> 
> Patch attached and suggestions welcome.
> 
> 
> 
> ------------------------------------------------------------------------
> 
> --- smbd/quotas.c.orig	Sun May 30 23:31:06 2004
> +++ smbd/quotas.c	Sun May 30 23:44:35 2004
> @@ -933,6 +933,176 @@
>  #include <devnm.h>
>  #endif
>  
> +#if defined(__FreeBSD__)
> +
> +#include <rpc/rpc.h>
> +#include <rpc/types.h>
> +#include <rpcsvc/rquota.h>
> +#include <rpc/nettype.h>
> +#include <rpc/xdr.h>
> +
> +static int quotastat;
> +
> +static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
> +{
> +	if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
> +		return(0);
> +	if (!xdr_int(xdrsp, &args->gqa_uid))
> +		return(0);
> +	return (1);
> +}
> +
> +static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
> +{
> +	if (!xdr_int(xdrsp, &quotastat)) {
> +		DEBUG(6,("nfs_quotas: Status bad or zero\n"));
> +		return 0;
> +	}
> +	if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
> +		DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
> +		return 0;
> +	}
> +	if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
> +		DEBUG(6,("nfs_quotas: Active bad or zero\n"));
> +		return 0;
> +	}
> +	if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
> +		DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
> +		return 0;
> +	}
> +	if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
> +		DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
> +		return 0;
> +	}
> +	if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
> +		DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
> +		return 0;
> +	}
> +	return (1);
> +}
> +
> +/* Works on FreeBSD, too. :-) */
> +static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
> +{
> +	uid_t uid = euser_id;
> +	struct dqblk D;
> +	char *mnttype = nfspath;
> +	CLIENT *clnt;
> +	struct getquota_rslt gqr;
> +	struct getquota_args args;
> +	char *cutstr, *pathname, *host, *testpath;
> +	int len;
> +	static struct timeval timeout = {2,0};
> +	enum clnt_stat clnt_stat;
> +	BOOL ret = True;
> +
> +	*bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
> +
> +	len=strcspn(mnttype, ":");
> +	pathname=strstr(mnttype, ":");
> +	cutstr = (char *) malloc(len+1);
> +	if (!cutstr)
> +		return False;
> +
> +	memset(cutstr, '\0', len+1);
> +	host = strncat(cutstr,mnttype, sizeof(char) * len );
> +	DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
> +	DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
> +	testpath=strchr_m(mnttype, ':');
> +	args.gqa_pathp = testpath+1;
> +	args.gqa_uid = uid;
> +
> +	DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
> +
> +	if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
> +		ret = False;
> +		goto out;
> +	}
> +
> +	clnt->cl_auth = authunix_create_default();
> +	DEBUG(9,("nfs_quotas: auth_success\n"));
> +
> +	clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
> +
> +	if (clnt_stat != RPC_SUCCESS) {
> +		DEBUG(9,("nfs_quotas: clnt_call fail\n"));
> +		ret = False;
> +		goto out;
> +	}
> +
> +	/* 
> +	 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
> +	 * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
> +	 * something sensible.
> +	 */   
> +
> +	switch ( quotastat ) {
> +	case 0:
> +		DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", quotastat ));
> +		ret = False;
> +		goto out;
> +
> +	case 1:
> +		DEBUG(9,("nfs_quotas: Good quota data\n"));
> +		D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
> +		D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
> +		D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
> +		break;
> +
> +	case 2:
> +	case 3:
> +		D.dqb_bsoftlimit = 1;
> +		D.dqb_curblocks = 1;
> +		DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
> +		break;
> +
> +	default:
> +		DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", quotastat ));
> +		break;
> +	}
> +
> +	DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
> +			quotastat,
> +			gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
> +			gqr.getquota_rslt_u.gqr_rquota.rq_active,
> +			gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
> +			gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
> +			gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
> +
> +	if (D.dqb_bsoftlimit == 0)
> +		D.dqb_bsoftlimit = D.dqb_bhardlimit;
> +	if (D.dqb_bsoftlimit == 0)
> +		return False;
> +
> +	*bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
> +	*dsize = D.dqb_bsoftlimit;
> +
> +	if (D.dqb_curblocks == D.dqb_curblocks == 1)
> +		*bsize = DEV_BSIZE;
> +
> +	if (D.dqb_curblocks > D.dqb_bsoftlimit) {
> +		*dfree = 0;
> +		*dsize = D.dqb_curblocks;
> +	} else
> +		*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
> +
> +  out:
> +
> +	if (clnt) {
> +		if (clnt->cl_auth)
> +			auth_destroy(clnt->cl_auth);
> +		clnt_destroy(clnt);
> +	}
> +
> +	DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
> +
> +	SAFE_FREE(cutstr);
> +	DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
> +	return ret;
> +}
> +
> +#endif
> +
>  /****************************************************************************
>  try to get the disk space from disk quotas - default version
>  ****************************************************************************/
> @@ -976,9 +1146,41 @@
>    {
>      /* FreeBSD patches from Marty Moll <martym at arbor.edu> */
>      gid_t egrp_id;
> - 
> +#if defined(__FreeBSD__)
> +    SMB_DEV_T devno;
> +    struct statfs *mnts;
> +    SMB_STRUCT_STAT st;
> +    int mntsize, i;
> +    
> +    if (sys_stat(path,&st) < 0)
> +        return False;
> +    devno = st.st_dev;
> +
> +    mntsize = getmntinfo(&mnts,MNT_NOWAIT);
> +    if (mntsize <= 0)
> +        return False;
> +
> +    for (i = 0; i < mntsize; i++) {
> +        if (sys_stat(mnts[i].f_mntonname,&st) < 0)
> +            return False;
> +        if (st.st_dev == devno)
> +            break;
> +    }
> +    if (i == mntsize)
> +        return False;
> +#endif
> +    
>      save_re_uid();
>      set_effective_uid(0);
> +
> +#if defined(__FreeBSD__)
> +    if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
> +        BOOL retval;
> +        retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
> +        restore_re_uid();
> +        return retval;
> +    }
> +#endif
>  
>      egrp_id = getegid();
>      r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);


-- 
metze

Stefan Metzmacher <metze at samba.org> www.samba.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 194 bytes
Desc: OpenPGP digital signature
Url : http://lists.samba.org/archive/samba-technical/attachments/20040602/de0b877a/signature.bin


More information about the samba-technical mailing list