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>