Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 May 2012 17:17:09 -0500
From:      Dan Nelson <dnelson@allantgroup.com>
To:        Tom <freebsdlists@bsdunix.ch>
Cc:        freebsd-fs@FreeBSD.org
Subject:   Re: zfs userquota support for rquotad (nfs)?
Message-ID:  <20120516221709.GA1933@dan.emsphone.com>
In-Reply-To: <4FB2D099.8040103@bsdunix.ch>
References:  <4FB2D099.8040103@bsdunix.ch>

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

--FCuugMFkClbJLl1L
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

In the last episode (May 15), Tom said:
> Hello
> 
> Has someone tried or is working on an implementation to add ZFS
> userquota support to rquotad?
> 
> https://hg.openindiana.org/upstream/illumos/illumos-gate/rev/4f68f041ddcd

Here's a simple implementation I coded up a year ago.  Instead of trying to
link in libzfs on the fly, it simply popens a "zfs get" command to fetch the
user's quota info.

-- 
	Dan Nelson
	dnelson@allantgroup.com

--FCuugMFkClbJLl1L
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="userquota.diff"

Index: rquotad.c
===================================================================
--- rquotad.c	(revision 234445)
+++ rquotad.c	(working copy)
@@ -36,7 +36,8 @@
 void printerr_reply(SVCXPRT *transp);
 void initfs(void);
 int getfsquota(long id, char *path, struct dqblk *dqblk);
-int hasquota(struct fstab *fs, char **qfnamep);
+int hasquota(struct fstab *fs, const char **qfnamep);
+static int getzfsquota(uid_t user, char *dataset, struct dqblk *zq);
 
 /*
  * structure containing informations about ufs filesystems
@@ -45,6 +46,8 @@
 struct fs_stat {
 	struct fs_stat *fs_next;	/* next element */
 	char   *fs_file;		/* mount point of the filesystem */
+	char   *fs_spec;		/* device name of the filesystem */
+	char   *fs_type;		/* type of the filesystem */
 	char   *qfpathname;		/* pathname of the quota file */
 	dev_t   st_dev;			/* device of the filesystem */
 } fs_stat;
@@ -209,17 +212,22 @@
 {
 	struct fs_stat *fs_current = NULL;
 	struct fs_stat *fs_next = NULL;
-	char *qfpathname;
+	const char *qfpathname;
 	struct fstab *fs;
 	struct stat st;
 
 	setfsent();
 	while ((fs = getfsent())) {
-		if (strcmp(fs->fs_vfstype, "ufs"))
+		/* Only process UFS or ZFS filesystems */
+		if (strcmp(fs->fs_vfstype, "ufs") && strcmp(fs->fs_vfstype, "zfs"))
 			continue;
-		if (!hasquota(fs, &qfpathname))
+		/* Skip UFS filesystems with quotas disabled */
+		if ((strcmp(fs->fs_vfstype, "ufs") == 0) && !hasquota(fs, &qfpathname))
 			continue;
 
+		if (strcmp(fs->fs_vfstype, "zfs") == 0) 
+			qfpathname = "";
+
 		fs_current = (struct fs_stat *) malloc(sizeof(struct fs_stat));
 		fs_current->fs_next = fs_next;	/* next element */
 
@@ -227,6 +235,14 @@
 		    malloc(sizeof(char) * (strlen(fs->fs_file) + 1));
 		strcpy(fs_current->fs_file, fs->fs_file);
 
+		fs_current->fs_spec =
+		    malloc(sizeof(char) * (strlen(fs->fs_spec) + 1));
+		strcpy(fs_current->fs_spec, fs->fs_spec);
+
+		fs_current->fs_type =
+		    malloc(sizeof(char) * (strlen(fs->fs_vfstype) + 1));
+		strcpy(fs_current->fs_type, fs->fs_vfstype);
+
 		fs_current->qfpathname =
 		    malloc(sizeof(char) * (strlen(qfpathname) + 1));
 		strcpy(fs_current->qfpathname, qfpathname);
@@ -257,10 +273,13 @@
 	qcmd = QCMD(Q_GETQUOTA, USRQUOTA);
 
 	for (fs = fs_begin; fs != NULL; fs = fs->fs_next) {
-		/* where the devise is the same as path */
+		/* where the device is the same as path */
 		if (fs->st_dev != st_path.st_dev)
 			continue;
 
+		if (strcmp(fs->fs_type, "zfs") == 0)
+			return (getzfsquota(id, fs->fs_spec, dqblk));
+
 		/* find the specified filesystem. get and return quota */
 		if (quotactl(fs->fs_file, qcmd, id, dqblk) == 0)
 			return (1);
@@ -300,7 +319,7 @@
  * Comes from quota.c, NetBSD 0.9
  */
 int
-hasquota(struct fstab *fs, char  **qfnamep)
+hasquota(struct fstab *fs, const char **qfnamep)
 {
 	static char initname, usrname[100];
 	static char buf[BUFSIZ];
@@ -329,3 +348,43 @@
 	*qfnamep = buf;
 	return (1);
 }
+
+static int
+getzfsquota(uid_t user, char *dataset, struct dqblk *zq)
+{
+	uint64_t userquota, userused;
+	FILE *zfp;
+	char buf[64];
+	char *cmd;
+	int failed = 0;
+
+	asprintf(&cmd, "zfs get -Hp -o value userquota@%d,userused@%d %s", user, user, dataset);
+	if (cmd == NULL)
+		return (0);
+
+	zfp = popen(cmd, "r");
+	free(cmd);
+	if (zfp == NULL)
+		return (0);
+
+	if (fgets(buf, sizeof(buf), zfp) == NULL)
+		failed = 1;
+	if (!failed && (sscanf(buf, "%lld", &userquota) != 1))
+		failed = 1;
+	if (!failed && (fgets(buf, sizeof(buf), zfp) == NULL))
+		failed = 1;
+	if (!failed && (sscanf(buf, "%lld", &userused) != 1))
+		failed = 1;
+	failed += pclose(zfp);
+
+	if (failed)
+		return(0);
+
+	bzero(zq, sizeof(struct dqblk));
+
+	zq->dqb_bhardlimit = userquota / DEV_BSIZE;
+	zq->dqb_bsoftlimit = userquota / DEV_BSIZE;
+	zq->dqb_curblocks = userused / DEV_BSIZE;
+
+	return (1);
+}

--FCuugMFkClbJLl1L--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120516221709.GA1933>