Bug 9371 - ZFS quotas support not complete
ZFS quotas support not complete
Status: NEW
Product: Samba 4.1 and newer
Classification: Unclassified
Component: File services
unspecified
x86 Solaris
: P5 normal
: ---
Assigned To: Samba QA Contact
Samba QA Contact
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-11-08 15:11 UTC by Mike Moya
Modified: 2016-01-05 07:32 UTC (History)
4 users (show)

See Also:


Attachments
zfs_dfree vfs module for 3.6 on Solaris (3.88 KB, patch)
2016-01-04 11:52 UTC, Björn Baumbach
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mike Moya 2012-11-08 15:11:18 UTC
This bug is years old. Just now sending it in. We created the following patch to mainly fix ZFS quotas in the case the quota is set to NONE (which is the default). What started the issue is 0 quota normally means unlimited. In the case of ZFS the quota is set to NONE. The following patch fixes this problem:

*** ./smbd/quotas.c.orig	Thu Oct  7 12:41:16 2010
--- ./smbd/quotas.c	Tue Nov 30 17:29:16 2010
***************
*** 392,397 ****
--- 392,398 ----
 #include <sys/param.h>
 #if defined(SUNOS5)
 #include <sys/fs/ufs_quota.h>
+ #include <libzfs.h>
 #include <sys/mnttab.h>
 #include <sys/mntent.h>
 #else /* defined(SUNOS4) */
***************
*** 432,457 ****
 	}
 	gqr->status = quotastat;

! 	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);
 }

--- 433,461 ----
 	}
 	gqr->status = quotastat;

!         if (quotastat == Q_OK) {
!                 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);
 }

***************
*** 511,518 ****
 	 */

 	switch (gqr.status) {
! 	case 0:
! 		DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", gqr.status));
 		ret = False;
 		goto out;

--- 515,522 ----
 	 */

 	switch (gqr.status) {
! 	default:
!                 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status ));
 		ret = False;
 		goto out;

***************
*** 521,538 ****
 		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", gqr.status));
- 		break;
- 
- 	default:
- 		DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", gqr.status ));
- 		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",
--- 525,536 ----
 		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;
+                 if (D.dqb_bsoftlimit == 0) {
+                         DEBUG(9,("nfs_quotas: soft quota is zero - change to no quota \n", gqr.status ));
+                         ret = False;
+                         goto out;
+                 }
 		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",
***************
*** 569,574 ****
--- 567,639 ----
 	DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
 	return ret;
 }
+ 
+ /* Get ZFS quota for user */
+ static bool zfs_quotas(char *zfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
+ {
+ 	libzfs_handle_t * zfs;
+ 	zfs_handle_t * zhp;
+ 	uint64_t userquota;
+ 	uint64_t userused;
+ 	char property[ /* "userquota@" + 12 + 1 */ 24 ];
+ 
+ 	*bsize = *dfree = *dsize = (uint64_t)0;
+ 
+ 	zfs = libzfs_init();
+ 	if (zfs == NULL) {
+ 		DEBUG(10,("zfs_quotas: Cannot initialize libzfs\n"));
+ 		return False;
+ 	}
+ 
+ 	zhp = zfs_open(zfs, zfspath, ZFS_TYPE_DATASET);
+ 	if (zhp == NULL) {
+ 		DEBUG(10,("zfs_quotas: Cannot open zfs \"%s\" handle\n", zfspath));
+ 		libzfs_fini(zfs);
+ 		return False;
+ 	}
+ 
+ 	/* Format request */
+ 	snprintf(property, sizeof(property), "userquota@%u", euser_id);
+ 
+ 	/* Get quota */
+ 	if (zfs_prop_get_userquota_int(zhp, property, &userquota)) {
+ 		DEBUG(10,("zfs_quotas: Cannot open zfs property \"%s\"\n", property));
+ 		zfs_close(zhp);
+ 		libzfs_fini(zfs);
+ 		return False;
+ 	}
+ 
+ 	/* Format request */
+ 	snprintf(property, sizeof(property), "userused@%u", euser_id);
+ 
+ 	/* Get used */
+ 	if (zfs_prop_get_userquota_int(zhp, property, &userused)) {
+ 		DEBUG(10,("zfs_quotas: Cannot open zfs property \"%s\"\n", property));
+ 		zfs_close(zhp);
+ 		libzfs_fini(zfs);
+ 		return False;
+ 	}
+ 
+ 	/* Close handles */
+ 	zfs_close(zhp);
+ 	libzfs_fini(zfs);
+ 
+ 	/* No quota? */
+ 	if (userquota == 0)
+ 		return False;
+ 
+ 	/* Update results */
+ 	*bsize = DEV_BSIZE;
+ 	*dsize = userquota / DEV_BSIZE;
+ 	if (userused > userquota) {
+ 		*dfree = 0;
+ 		*dsize = userused / DEV_BSIZE;
+ 	} else
+ 		*dfree = (userquota - userused) / DEV_BSIZE;
+ 	DEBUG(5,("zfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",zfspath,(double)*bsize,(double)*dfree,(double)*dsize));
+ 	DEBUG(10,("zfs_quotas: End of zfs_quotas\n"));
+ 	return True;
+ }
 #endif

 /****************************************************************************
***************
*** 619,627 ****
 		DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
 			mnt.mnt_mountp, (unsigned int)devno));

! 		/* quotas are only on vxfs, UFS or NFS */
 		if ((sbuf.st_ex_dev == devno) && (
 			strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
 			strcmp( mnt.mnt_fstype, "nfs" ) == 0    ||
 			strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
 				found = true;
--- 684,693 ----
 		DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
 			mnt.mnt_mountp, (unsigned int)devno));

! 		/* quotas are only on vxfs, UFS, ZFS or NFS */
 		if ((sbuf.st_ex_dev == devno) && (
 			strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
+ 			strcmp( mnt.mnt_fstype, MNTTYPE_ZFS ) == 0 ||
 			strcmp( mnt.mnt_fstype, "nfs" ) == 0    ||
 			strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
 				found = true;
***************
*** 672,677 ****
--- 738,753 ----
 		retval = nfs_quotas(mnt.mnt_special,
 				euser_id, bsize, dfree, dsize);
 		unbecome_root();
+ 		return retval;
+ 	}
+ 
+ 	if (strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) == 0) {
+ 		bool retval;
+ 		DEBUG(5,("disk_quotas: looking for mountpath (ZFS) \"%s\"\n",
+ 					mnt.mnt_special));
+ 		retval = zfs_quotas(mnt.mnt_special,
+ 				euser_id, bsize, dfree, dsize);
+ 		unbecome_root();
 		return retval;
 	}
Comment 1 Volker Lendecke 2012-11-09 07:24:35 UTC
Would it be possible that you re-do the patch as "diff -u" and upload it as an attachment? This makes it easier to apply, the Linux patch program seems to have problems applying this patch cleanly.

Thanks,

Volker
Comment 2 Mike Moya 2012-11-09 12:27:38 UTC
(In reply to comment #1)

Will do ...
--mike
Comment 3 Björn Baumbach 2016-01-04 11:52:25 UTC
Created attachment 11755 [details]
zfs_dfree vfs module for 3.6 on Solaris

Hi!

A few years ago I've produced a vfs module based on the work of Mike Moya (in the bug description).
As far as I remember the attached module works fine on Solaris with Samba 3.6.

Best regards
Björn