Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Jan 2009 13:54:03 +0000 (UTC)
From:      Dag-Erling Smorgrav <des@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r187914 - in projects/quota64: lib/libutil libexec/rpc.rquotad sys/ufs/ufs usr.sbin/edquota
Message-ID:  <200901301354.n0UDs3Ag093570@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: des
Date: Fri Jan 30 13:54:03 2009
New Revision: 187914
URL: http://svn.freebsd.org/changeset/base/187914

Log:
  WIP

Added:
  projects/quota64/lib/libutil/quotafile.3   (contents, props changed)
  projects/quota64/lib/libutil/quotafile.c   (contents, props changed)
Modified:
  projects/quota64/lib/libutil/Makefile
  projects/quota64/lib/libutil/libutil.h
  projects/quota64/libexec/rpc.rquotad/Makefile
  projects/quota64/libexec/rpc.rquotad/rquotad.c
  projects/quota64/sys/ufs/ufs/quota.h
  projects/quota64/sys/ufs/ufs/ufs_quota.c
  projects/quota64/sys/ufs/ufs/ufs_vfsops.c
  projects/quota64/sys/ufs/ufs/ufsmount.h
  projects/quota64/usr.sbin/edquota/Makefile
  projects/quota64/usr.sbin/edquota/edquota.c

Modified: projects/quota64/lib/libutil/Makefile
==============================================================================
--- projects/quota64/lib/libutil/Makefile	Fri Jan 30 09:42:25 2009	(r187913)
+++ projects/quota64/lib/libutil/Makefile	Fri Jan 30 13:54:03 2009	(r187914)
@@ -12,8 +12,8 @@ SRCS=	_secure_path.c auth.c expand_numbe
 	hexdump.c humanize_number.c kinfo_getfile.c kinfo_getvmmap.c kld.c \
 	login.c login_auth.c login_cap.c \
 	login_class.c login_crypt.c login_ok.c login_times.c login_tty.c \
-	logout.c logwtmp.c pidfile.c property.c pty.c pw_util.c realhostname.c \
-	stub.c trimdomain.c uucplock.c
+	logout.c logwtmp.c pidfile.c property.c pty.c pw_util.c quotafile.c \
+	realhostname.c stub.c trimdomain.c uucplock.c
 INCS=	libutil.h login_cap.h
 
 WARNS?=	6
@@ -30,7 +30,7 @@ MAN+=	kld.3 login.3 login_auth.3 login_t
 	login_cap.3 login_class.3 login_times.3 login_ok.3 \
 	_secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
 	realhostname_sa.3 trimdomain.3 fparseln.3 humanize_number.3 \
-	pidfile.3 flopen.3 expand_number.3
+	pidfile.3 flopen.3 expand_number.3 quotafile.3
 MAN+=	login.conf.5 auth.conf.5
 MLINKS+= kld.3 kld_isloaded.3 kld.3 kld_load.3
 MLINKS+= property.3 properties_read.3  property.3 properties_free.3
@@ -58,5 +58,9 @@ MLINKS+=pidfile.3 pidfile_open.3 \
 	pidfile.3 pidfile_write.3 \
 	pidfile.3 pidfile_close.3 \
 	pidfile.3 pidfile_remove.3
+MLINKS+=quotafile.3 quota_open.3 \
+	quotafile.3 quota_read.3 \
+	quotafile.3 quota_write.3 \
+	quotafile.3 quota_close.3
 
 .include <bsd.lib.mk>

Modified: projects/quota64/lib/libutil/libutil.h
==============================================================================
--- projects/quota64/lib/libutil/libutil.h	Fri Jan 30 09:42:25 2009	(r187913)
+++ projects/quota64/lib/libutil/libutil.h	Fri Jan 30 13:54:03 2009	(r187914)
@@ -140,6 +140,15 @@ int pidfile_close(struct pidfh *pfh);
 int pidfile_remove(struct pidfh *pfh);
 #endif
 
+#ifdef _UFS_UFS_QUOTA_H_
+struct quotafile;
+struct quotafile *quota_open(const char *);
+struct quotafile *quota_create(const char *);
+void quota_close(struct quotafile *);
+int quota_read(struct quotafile *, struct dqblk *, int);
+int quota_write(struct quotafile *, const struct dqblk *, int);
+#endif
+
 __END_DECLS
 
 #define UU_LOCK_INUSE (1)

Added: projects/quota64/lib/libutil/quotafile.3
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/quota64/lib/libutil/quotafile.3	Fri Jan 30 13:54:03 2009	(r187914)
@@ -0,0 +1,69 @@
+.\"-
+.\" Copyright (c) 2008 Dag-Erling Coïdan Smørgrav
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 4, 2008
+.Dt QUOTAFILE 3
+.Os
+.Sh NAME
+.Nm quota_open
+.Nm quota_create
+.Nm quota_read
+.Nm quota_write
+.Nm quota_close
+.Nd "Manipulate quota files"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In ufs/ufs/quota.h
+.In libutil.h
+.Ft "struct quotafile *"
+.Fn quota_open "const char *path"
+.Ft "struct quotafile *"
+.Fn quota_create "const char *path"
+.Ft int
+.Fn quota_read "struct quotafile *qf" "struct dqblk *dqb" "int type"
+.Ft int
+.Fn quota_write "struct quotafile *qf" "const struct dqblk *dqb" "int type"
+.Ft int
+.Fn quota_close "struct quotafile *qf"
+.Sh DESCRIPTION
+.Sh RETURN VALUES
+.Sh SEE ALSO
+.Xr quotactl 2 ,
+.Xr quota.user 5 ,
+.Xr quota.group 5
+.Sh HISTORY
+The
+.Nm
+functions first appeared in
+.Fx 8.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+functions and this manual page were written by
+.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org .

Added: projects/quota64/lib/libutil/quotafile.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/quota64/lib/libutil/quotafile.c	Fri Jan 30 13:54:03 2009	(r187914)
@@ -0,0 +1,272 @@
+/*-
+ * Copyright (c) 2008 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/stat.h>
+
+#include <ufs/ufs/quota.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <libutil.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct quotafile {
+	int fd;
+	int type; /* 32 or 64 */
+};
+
+struct quotafile *
+quota_open(const char *fn)
+{
+	struct quotafile *qf;
+	struct dqhdr64 dqh;
+	int serrno;
+
+	if ((qf = calloc(1, sizeof(*qf))) == NULL)
+		return (NULL);
+	if ((qf->fd = open(fn, O_RDWR)) < 0) {
+		serrno = errno;
+		free(qf);
+		errno = serrno;
+		return (NULL);
+	}
+	qf->type = 32;
+	switch (read(qf->fd, &dqh, sizeof(dqh))) {
+	case -1:
+		serrno = errno;
+		close(qf->fd);
+		free(qf);
+		errno = serrno;
+		return (NULL);
+	case sizeof(dqh):
+		if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) != 0) {
+			/* no magic, assume 32 bits */
+			qf->type = 32;
+			return (qf);
+		}
+		if (be32toh(dqh.dqh_version) != Q_DQHDR64_VERSION ||
+		    be32toh(dqh.dqh_hdrlen) != sizeof(struct dqhdr64) ||
+		    be32toh(dqh.dqh_reclen) != sizeof(struct dqblk64)) {
+			/* correct magic, wrong version / lengths */
+			close(qf->fd);
+			free(qf);
+			errno = EINVAL;
+			return (NULL);
+		}
+		qf->type = 64;
+		return (qf);
+	default:
+		qf->type = 32;
+		return (qf);
+	}
+	/* not reached */
+}
+
+struct quotafile *
+quota_create(const char *fn)
+{
+	struct quotafile *qf;
+	struct dqhdr64 dqh;
+	struct group *grp;
+	int serrno;
+
+	if ((qf = calloc(1, sizeof(*qf))) == NULL)
+		return (NULL);
+	if ((qf->fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
+		serrno = errno;
+		free(qf);
+		errno = serrno;
+		return (NULL);
+	}
+	qf->type = 64;
+	memset(&dqh, 0, sizeof(dqh));
+	memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
+	dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
+	dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
+	dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
+	if (write(qf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
+		serrno = errno;
+		unlink(fn);
+		close(qf->fd);
+		free(qf);
+		errno = serrno;
+		return (NULL);
+	}
+	grp = getgrnam(QUOTAGROUP);
+	fchown(qf->fd, 0, grp ? grp->gr_gid : 0);
+	fchmod(qf->fd, 0640);
+	return (qf);
+}
+
+void
+quota_close(struct quotafile *qf)
+{
+
+	close(qf->fd);
+	free(qf);
+}
+
+static int
+quota_read32(struct quotafile *qf, struct dqblk *dqb, int id)
+{
+	struct dqblk32 dqb32;
+	off_t off;
+
+	off = id * sizeof(struct dqblk32);
+	if (lseek(qf->fd, off, SEEK_SET) == -1)
+		return (-1);
+	switch (read(qf->fd, &dqb32, sizeof(dqb32))) {
+	case 0:
+		memset(&dqb, 0, sizeof(*dqb));
+		return (0);
+	case sizeof(dqb32):
+		dqb->dqb_bhardlimit = dqb32.dqb_bhardlimit;
+		dqb->dqb_bsoftlimit = dqb32.dqb_bsoftlimit;
+		dqb->dqb_curblocks = dqb32.dqb_curblocks;
+		dqb->dqb_ihardlimit = dqb32.dqb_ihardlimit;
+		dqb->dqb_isoftlimit = dqb32.dqb_isoftlimit;
+		dqb->dqb_curinodes = dqb32.dqb_curinodes;
+		dqb->dqb_btime = dqb32.dqb_btime;
+		dqb->dqb_itime = dqb32.dqb_itime;
+		return (0);
+	default:
+		return (-1);
+	}
+}
+
+static int
+quota_read64(struct quotafile *qf, struct dqblk *dqb, int id)
+{
+	struct dqblk64 dqb64;
+	off_t off;
+
+	off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64);
+	if (lseek(qf->fd, off, SEEK_SET) == -1)
+		return (-1);
+	switch (read(qf->fd, &dqb64, sizeof(dqb64))) {
+	case 0:
+		memset(&dqb, 0, sizeof(*dqb));
+		return (0);
+	case sizeof(dqb64):
+		dqb->dqb_bhardlimit = be64toh(dqb64.dqb_bhardlimit);
+		dqb->dqb_bsoftlimit = be64toh(dqb64.dqb_bsoftlimit);
+		dqb->dqb_curblocks = be64toh(dqb64.dqb_curblocks);
+		dqb->dqb_ihardlimit = be64toh(dqb64.dqb_ihardlimit);
+		dqb->dqb_isoftlimit = be64toh(dqb64.dqb_isoftlimit);
+		dqb->dqb_curinodes = be64toh(dqb64.dqb_curinodes);
+		dqb->dqb_btime = be64toh(dqb64.dqb_btime);
+		dqb->dqb_itime = be64toh(dqb64.dqb_itime);
+		return (0);
+	default:
+		return (-1);
+	}
+}
+
+int
+quota_read(struct quotafile *qf, struct dqblk *dqb, int id)
+{
+
+	switch (qf->type) {
+	case 32:
+		return quota_read32(qf, dqb, id);
+	case 64:
+		return quota_read64(qf, dqb, id);
+	default:
+		errno = EINVAL;
+		return (-1);
+	}
+	/* not reached */
+}
+
+#define CLIP32(u64) ((u64) > UINT32_MAX ? UINT32_MAX : (uint32_t)(u64))
+
+static int
+quota_write32(struct quotafile *qf, const struct dqblk *dqb, int id)
+{
+	struct dqblk32 dqb32;
+	off_t off;
+
+	dqb32.dqb_bhardlimit = CLIP32(dqb->dqb_bhardlimit);
+	dqb32.dqb_bsoftlimit = CLIP32(dqb->dqb_bsoftlimit);
+	dqb32.dqb_curblocks = CLIP32(dqb->dqb_curblocks);
+	dqb32.dqb_ihardlimit = CLIP32(dqb->dqb_ihardlimit);
+	dqb32.dqb_isoftlimit = CLIP32(dqb->dqb_isoftlimit);
+	dqb32.dqb_curinodes = CLIP32(dqb->dqb_curinodes);
+	dqb32.dqb_btime = CLIP32(dqb->dqb_btime);
+	dqb32.dqb_itime = CLIP32(dqb->dqb_itime);
+
+	off = id * sizeof(struct dqblk32);
+	if (lseek(qf->fd, off, SEEK_SET) == -1)
+		return (-1);
+	return (write(qf->fd, &dqb32, sizeof(dqb32)));
+}
+
+static int
+quota_write64(struct quotafile *qf, const struct dqblk *dqb, int id)
+{
+	struct dqblk64 dqb64;
+	off_t off;
+
+	dqb64.dqb_bhardlimit = htobe64(dqb->dqb_bhardlimit);
+	dqb64.dqb_bsoftlimit = htobe64(dqb->dqb_bsoftlimit);
+	dqb64.dqb_curblocks = htobe64(dqb->dqb_curblocks);
+	dqb64.dqb_ihardlimit = htobe64(dqb->dqb_ihardlimit);
+	dqb64.dqb_isoftlimit = htobe64(dqb->dqb_isoftlimit);
+	dqb64.dqb_curinodes = htobe64(dqb->dqb_curinodes);
+	dqb64.dqb_btime = htobe64(dqb->dqb_btime);
+	dqb64.dqb_itime = htobe64(dqb->dqb_itime);
+
+	off = sizeof(struct dqhdr64) + id * sizeof(struct dqblk64);
+	if (lseek(qf->fd, off, SEEK_SET) == -1)
+		return (-1);
+	return (write(qf->fd, &dqb64, sizeof(dqb64)));
+}
+
+int
+quota_write(struct quotafile *qf, const struct dqblk *dqb, int id)
+{
+
+	switch (qf->type) {
+	case 32:
+		return quota_write32(qf, dqb, id);
+	case 64:
+		return quota_write64(qf, dqb, id);
+	default:
+		errno = EINVAL;
+		return (-1);
+	}
+	/* not reached */
+}

Modified: projects/quota64/libexec/rpc.rquotad/Makefile
==============================================================================
--- projects/quota64/libexec/rpc.rquotad/Makefile	Fri Jan 30 09:42:25 2009	(r187913)
+++ projects/quota64/libexec/rpc.rquotad/Makefile	Fri Jan 30 13:54:03 2009	(r187914)
@@ -6,7 +6,7 @@ MAN  =	rpc.rquotad.8
 
 WARNS ?= 6
 
-DPADD=	${LIBRPCSVC}
-LDADD=	-lrpcsvc
+DPADD=	${LIBRPCSVC} ${LIBUTIL}
+LDADD=	-lrpcsvc -lutil
 
 .include <bsd.prog.mk>

Modified: projects/quota64/libexec/rpc.rquotad/rquotad.c
==============================================================================
--- projects/quota64/libexec/rpc.rquotad/rquotad.c	Fri Jan 30 09:42:25 2009	(r187913)
+++ projects/quota64/libexec/rpc.rquotad/rquotad.c	Fri Jan 30 13:54:03 2009	(r187914)
@@ -23,6 +23,7 @@ __FBSDID("$FreeBSD$");
 #include <errno.h>
 #include <fstab.h>
 #include <grp.h>
+#include <libutil.h>
 #include <pwd.h>
 #include <signal.h>
 #include <stdio.h>
@@ -247,9 +248,10 @@ initfs(void)
 int
 getfsquota(long id, char *path, struct dqblk *dqblk)
 {
+	struct quotafile *qf;
 	struct stat st_path;
 	struct fs_stat *fs;
-	int	qcmd, fd, ret = 0;
+	int qcmd, ret = 0;
 
 	if (stat(path, &st_path) < 0)
 		return (0);
@@ -265,32 +267,16 @@ getfsquota(long id, char *path, struct d
 		if (quotactl(fs->fs_file, qcmd, id, dqblk) == 0)
 			return (1);
 
-		if ((fd = open(fs->qfpathname, O_RDONLY)) < 0) {
+		if ((qf = quota_open(fs->qfpathname)) == NULL) {
 			syslog(LOG_ERR, "open error: %s: %m", fs->qfpathname);
 			return (0);
 		}
-		if (lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET) == (off_t)-1) {
-			close(fd);
-			return (1);
-		}
-		switch (read(fd, dqblk, sizeof(struct dqblk))) {
-		case 0:
-			/*
-                         * Convert implicit 0 quota (EOF)
-                         * into an explicit one (zero'ed dqblk)
-                         */
-			bzero(dqblk, sizeof(struct dqblk));
-			ret = 1;
-			break;
-		case sizeof(struct dqblk):	/* OK */
-			ret = 1;
-			break;
-		default:	/* ERROR */
+		if (quota_read(qf, dqblk, id) != 0) {
 			syslog(LOG_ERR, "read error: %s: %m", fs->qfpathname);
-			close(fd);
+			quota_close(qf);
 			return (0);
 		}
-		close(fd);
+		quota_close(qf);
 	}
 	return (ret);
 }

Modified: projects/quota64/sys/ufs/ufs/quota.h
==============================================================================
--- projects/quota64/sys/ufs/ufs/quota.h	Fri Jan 30 09:42:25 2009	(r187913)
+++ projects/quota64/sys/ufs/ufs/quota.h	Fri Jan 30 13:54:03 2009	(r187914)
@@ -81,10 +81,13 @@
 
 #define	Q_QUOTAON	0x0100	/* enable quotas */
 #define	Q_QUOTAOFF	0x0200	/* disable quotas */
-#define	Q_GETQUOTA	0x0300	/* get limits and usage */
-#define	Q_SETQUOTA	0x0400	/* set limits and usage */
-#define	Q_SETUSE	0x0500	/* set usage */
+#define	Q_GETQUOTA32	0x0300	/* get limits and usage (32-bit version) */
+#define	Q_SETQUOTA32	0x0400	/* set limits and usage (32-bit version) */
+#define	Q_SETUSE32	0x0500	/* set usage (32-bit version) */
 #define	Q_SYNC		0x0600	/* sync disk copy of a filesystems quotas */
+#define	Q_GETQUOTA	0x0700	/* get limits and usage (64-bit version) */
+#define	Q_SETQUOTA	0x0800	/* set limits and usage (64-bit version) */
+#define	Q_SETUSE	0x0900	/* set usage (64-bit version) */
 
 /*
  * The following structure defines the format of the disk quota file
@@ -93,7 +96,7 @@
  * the vnode for each quota file (a pointer is retained in the ufsmount
  * structure).
  */
-struct dqblk {
+struct dqblk32 {
 	u_int32_t dqb_bhardlimit;	/* absolute limit on disk blks alloc */
 	u_int32_t dqb_bsoftlimit;	/* preferred limit on disk blks */
 	u_int32_t dqb_curblocks;	/* current block count */
@@ -104,6 +107,30 @@ struct dqblk {
 	int32_t   dqb_itime;		/* time limit for excessive files */
 };
 
+struct dqblk64 {
+	u_int64_t dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+	u_int64_t dqb_bsoftlimit;	/* preferred limit on disk blks */
+	u_int64_t dqb_curblocks;	/* current block count */
+	u_int64_t dqb_ihardlimit;	/* maximum # allocated inodes + 1 */
+	u_int64_t dqb_isoftlimit;	/* preferred inode limit */
+	u_int64_t dqb_curinodes;	/* current # allocated inodes */
+	int64_t   dqb_btime;		/* time limit for excessive disk use */
+	int64_t   dqb_itime;		/* time limit for excessive files */
+};
+
+#define dqblk dqblk64
+
+#define Q_DQHDR64_MAGIC "QUOTA64"
+#define Q_DQHDR64_VERSION 0x20081104
+
+struct dqhdr64 {
+	char	  dqh_magic[8];		/* Q_DQHDR64_MAGIC */
+	uint32_t  dqh_version;		/* Q_DQHDR64_VERSION */
+	uint32_t  dqh_hdrlen;		/* header length */
+	uint32_t  dqh_reclen;		/* record length */
+	char	  dqh_unused[44];	/* reserved for future extension */
+};
+
 #ifdef _KERNEL
 
 #include <sys/queue.h>
@@ -125,7 +152,7 @@ struct dquot {
 	u_int32_t dq_id;		/* identifier this applies to */
 	struct ufsmount *dq_ump;	/* (h) filesystem that this is
 					   taken from */
-	struct dqblk dq_dqb;		/* actual usage & quotas */
+	struct dqblk64 dq_dqb;		/* actual usage & quotas */
 };
 /*
  * Flag values.
@@ -199,10 +226,13 @@ void	dqinit(void);
 void	dqrele(struct vnode *, struct dquot *);
 void	dquninit(void);
 int	getinoquota(struct inode *);
-int	getquota(struct thread *, struct mount *, u_long, int, void *);
 int	qsync(struct mount *mp);
 int	quotaoff(struct thread *td, struct mount *, int);
 int	quotaon(struct thread *td, struct mount *, int, void *);
+int	getquota32(struct thread *, struct mount *, u_long, int, void *);
+int	setquota32(struct thread *, struct mount *, u_long, int, void *);
+int	setuse32(struct thread *, struct mount *, u_long, int, void *);
+int	getquota(struct thread *, struct mount *, u_long, int, void *);
 int	setquota(struct thread *, struct mount *, u_long, int, void *);
 int	setuse(struct thread *, struct mount *, u_long, int, void *);
 vfs_quotactl_t ufs_quotactl;

Modified: projects/quota64/sys/ufs/ufs/ufs_quota.c
==============================================================================
--- projects/quota64/sys/ufs/ufs/ufs_quota.c	Fri Jan 30 09:42:25 2009	(r187913)
+++ projects/quota64/sys/ufs/ufs/ufs_quota.c	Fri Jan 30 13:54:03 2009	(r187914)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/endian.h>
 #include <sys/fcntl.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
@@ -73,6 +74,7 @@ static char *quotatypes[] = INITQFNAMES;
 
 static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int, int *);
 static int chkiqchg(struct inode *, int, struct ucred *, int, int *);
+static int dqopen(struct vnode *, struct ufsmount *, int);
 static int dqget(struct vnode *,
 	u_long, struct ufsmount *, int, struct dquot **);
 static int dqsync(struct vnode *, struct dquot *);
@@ -80,6 +82,14 @@ static void dqflush(struct vnode *);
 static int quotaoff1(struct thread *td, struct mount *mp, int type);
 static int quotaoff_inchange(struct thread *td, struct mount *mp, int type);
 
+/* conversion functions - from_to() */
+static void dqb32_dq(const struct dqblk32 *, struct dquot *);
+static void dqb64_dq(const struct dqblk64 *, struct dquot *);
+static void dq_dqb32(const struct dquot *, struct dqblk32 *);
+static void dq_dqb64(const struct dquot *, struct dqblk64 *);
+static void dqb32_dqb64(const struct dqblk32 *, struct dqblk64 *);
+static void dqb64_dqb32(const struct dqblk64 *, struct dqblk32 *);
+
 #ifdef DIAGNOSTIC
 static void dqref(struct dquot *);
 static void chkdquot(struct inode *);
@@ -90,7 +100,7 @@ static void chkdquot(struct inode *);
  *
  * This routine completely defines the semantics of quotas.
  * If other criterion want to be used to establish quotas, the
- * MAXQUOTAS value in quotas.h should be increased, and the
+ * MAXQUOTAS value in quota.h should be increased, and the
  * additional dquots set up here.
  */
 int
@@ -522,6 +532,13 @@ quotaon(struct thread *td, struct mount 
 		return (EALREADY);
 	}
 	ump->um_qflags[type] |= QTF_OPENING|QTF_CLOSING;
+	if ((error = dqopen(vp, ump, type)) != 0) {
+		ump->um_qflags[type] &= ~(QTF_OPENING|QTF_CLOSING);
+		UFS_UNLOCK(ump);
+		(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
+		VFS_UNLOCK_GIANT(vfslocked);
+		return (error);
+	}
 	MNT_ILOCK(mp);
 	mp->mnt_flag |= MNT_QUOTA;
 	MNT_IUNLOCK(mp);
@@ -734,8 +751,9 @@ quotaoff(struct thread *td, struct mount
 /*
  * Q_GETQUOTA - return current values in a dqblk structure.
  */
-int
-getquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+static int
+_getquota(struct thread *td, struct mount *mp, u_long id, int type,
+    struct dqblk64 *dqb)
 {
 	struct dquot *dq;
 	int error;
@@ -766,7 +784,7 @@ getquota(struct thread *td, struct mount
 	error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq);
 	if (error)
 		return (error);
-	error = copyout(&dq->dq_dqb, addr, sizeof (struct dqblk));
+	*dqb = dq->dq_dqb;
 	dqrele(NULLVP, dq);
 	return (error);
 }
@@ -774,23 +792,21 @@ getquota(struct thread *td, struct mount
 /*
  * Q_SETQUOTA - assign an entire dqblk structure.
  */
-int
-setquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+static int
+_setquota(struct thread *td, struct mount *mp, u_long id, int type,
+    struct dqblk64 *dqb)
 {
 	struct dquot *dq;
 	struct dquot *ndq;
 	struct ufsmount *ump;
-	struct dqblk newlim;
+	struct dqblk64 newlim;
 	int error;
 
 	error = priv_check(td, PRIV_VFS_SETQUOTA);
 	if (error)
 		return (error);
 
-	ump = VFSTOUFS(mp);
-	error = copyin(addr, &newlim, sizeof (struct dqblk));
-	if (error)
-		return (error);
+	newlim = *dqb;
 
 	ndq = NODQUOT;
 	ump = VFSTOUFS(mp);
@@ -839,23 +855,21 @@ setquota(struct thread *td, struct mount
 /*
  * Q_SETUSE - set current inode and block usage.
  */
-int
-setuse(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+static int
+_setuse(struct thread *td, struct mount *mp, u_long id, int type,
+    struct dqblk64 *dqb)
 {
 	struct dquot *dq;
 	struct ufsmount *ump;
 	struct dquot *ndq;
-	struct dqblk usage;
+	struct dqblk64 usage;
 	int error;
 
 	error = priv_check(td, PRIV_UFS_SETUSE);
 	if (error)
 		return (error);
 
-	ump = VFSTOUFS(mp);
-	error = copyin(addr, &usage, sizeof (struct dqblk));
-	if (error)
-		return (error);
+	usage = *dqb;
 
 	ump = VFSTOUFS(mp);
 	ndq = NODQUOT;
@@ -888,6 +902,90 @@ setuse(struct thread *td, struct mount *
 	return (0);
 }
 
+int
+getquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+{
+	struct dqblk32 dqb32;
+	struct dqblk64 dqb64;
+	int error;
+
+	error = _getquota(td, mp, id, type, &dqb64);
+	if (error)
+		return (error);
+	dqb64_dqb32(&dqb64, &dqb32);
+	error = copyout(&dqb32, addr, sizeof(dqb32));
+	return (error);
+}
+
+int
+setquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+{
+	struct dqblk32 dqb32;
+	struct dqblk64 dqb64;
+	int error;
+
+	error = copyin(addr, &dqb32, sizeof(dqb32));
+	if (error)
+		return (error);
+	dqb32_dqb64(&dqb32, &dqb64);
+	error = _setquota(td, mp, id, type, &dqb64);
+	return (error);
+}
+
+int
+setuse32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+{
+	struct dqblk32 dqb32;
+	struct dqblk64 dqb64;
+	int error;
+
+	error = copyin(addr, &dqb32, sizeof(dqb32));
+	if (error)
+		return (error);
+	dqb32_dqb64(&dqb32, &dqb64);
+	error = _setuse(td, mp, id, type, &dqb64);
+	return (error);
+}
+
+int
+getquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+{
+	struct dqblk64 dqb64;
+	int error;
+
+	error = _getquota(td, mp, id, type, &dqb64);
+	if (error)
+		return (error);
+	error = copyout(&dqb64, addr, sizeof(dqb64));
+	return (error);
+}
+
+int
+setquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+{
+	struct dqblk64 dqb64;
+	int error;
+
+	error = copyin(addr, &dqb64, sizeof(dqb64));
+	if (error)
+		return (error);
+	error = _setquota(td, mp, id, type, &dqb64);
+	return (error);
+}
+
+int
+setuse(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
+{
+	struct dqblk64 dqb64;
+	int error;
+
+	error = copyin(addr, &dqb64, sizeof(dqb64));
+	if (error)
+		return (error);
+	error = _setuse(td, mp, id, type, &dqb64);
+	return (error);
+}
+
 /*
  * Q_SYNC - sync quota files to disk.
  */
@@ -1025,6 +1123,47 @@ dqhashfind(struct dqhash *dqh, u_long id
 }
 
 /*
+ * Determine the quota file type.
+ */
+static int
+dqopen(struct vnode *vp, struct ufsmount *ump, int type)
+{
+	struct dqhdr64 dqh;
+	struct iovec aiov;
+	struct uio auio;
+	int error, vfslocked;
+
+	auio.uio_iov = &aiov;
+	auio.uio_iovcnt = 1;
+	aiov.iov_base = &dqh;
+	aiov.iov_len = sizeof(dqh);
+	auio.uio_resid = sizeof(dqh);
+	auio.uio_offset = 0;
+	auio.uio_segflg = UIO_SYSSPACE;
+	auio.uio_rw = UIO_READ;
+	auio.uio_td = (struct thread *)0;
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+	error = VOP_READ(vp, &auio, 0, ump->um_cred[type]);
+	VFS_UNLOCK_GIANT(vfslocked);
+
+	if (error != 0)
+		return (error);
+	if (auio.uio_resid > 0) {
+		/* assume 32 bits */
+		return (0);
+	}
+
+	if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) == 0 &&
+	    be32toh(dqh.dqh_version) == Q_DQHDR64_VERSION &&
+	    be32toh(dqh.dqh_hdrlen) == (uint32_t)sizeof(struct dqhdr64) &&
+	    be32toh(dqh.dqh_reclen) == (uint32_t)sizeof(struct dqblk64))
+		ump->um_qflags[type] |= QTF_64BIT;
+	/* XXX: what if the magic matches, but the sizes are wrong? */
+
+	return (0);
+}
+
+/*
  * Obtain a dquot structure for the specified identifier and quota file
  * reading the information from the file if necessary.
  */
@@ -1032,6 +1171,8 @@ static int
 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
     struct dquot **dqp)
 {
+	uint8_t buf[sizeof(struct dqblk64)];
+	off_t base, recsize;
 	struct dquot *dq, *dq1;
 	struct dqhash *dqh;
 	struct vnode *dqvp;
@@ -1121,8 +1262,7 @@ hfound:		DQI_LOCK(dq);
 	if (numdquot < desireddquot) {
 		numdquot++;
 		DQH_UNLOCK();
-		dq1 = (struct dquot *)malloc(sizeof *dq, M_DQUOT,
-		    M_WAITOK | M_ZERO);
+		dq1 = malloc(sizeof *dq1, M_DQUOT, M_WAITOK | M_ZERO);
 		mtx_init(&dq1->dq_lock, "dqlock", NULL, MTX_DEF);
 		DQH_LOCK();
 		/*
@@ -1169,20 +1309,52 @@ hfound:		DQI_LOCK(dq);
 	DQREF(dq);
 	DQH_UNLOCK();
 
+	/*
+	 * Read the requested quota record from the quota file, performing
+	 * any necessary conversions.
+	 *
+	 * The record's offset within the file depends on the size of the
+	 * record, which means we need to know whether it's a 32-bit file
+	 * or a 64-bit file.
+	 *
+	 * Luckily, root's record is always at offset 0, and most of it is
+	 * unused, so we can use it to store a magic number indicating the
+	 * file format.  Due to an acute lack of imagination, this magic
+	 * number, stored in the first byte of root's record and hence the
+	 * first byte of the file, is 64.
+	 *
+	 * Another lucky break is that quotaon() always loads root's
+	 * record, to get the default values for dq_btime and dq_itime, so
+	 * we will always have a chance to check the file format before
+	 * being asked for a "real" record.
+	 */
+	if (id == 0 || (ump->um_qflags[type] & QTF_64BIT)) {
+		recsize = sizeof(struct dqblk64);
+		base = sizeof(struct dqhdr64);
+	} else {
+		recsize = sizeof(struct dqblk32);
+		base = 0;
+	}
 	auio.uio_iov = &aiov;
 	auio.uio_iovcnt = 1;
-	aiov.iov_base = &dq->dq_dqb;
-	aiov.iov_len = sizeof (struct dqblk);
-	auio.uio_resid = sizeof (struct dqblk);
-	auio.uio_offset = (off_t)id * sizeof (struct dqblk);
+	aiov.iov_base = buf;
+	aiov.iov_len = recsize;
+	auio.uio_resid = recsize;
+	auio.uio_offset = base + id * recsize;
 	auio.uio_segflg = UIO_SYSSPACE;
 	auio.uio_rw = UIO_READ;
 	auio.uio_td = (struct thread *)0;
 
 	vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
 	error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
-	if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
-		bzero(&dq->dq_dqb, sizeof(struct dqblk));
+	if (auio.uio_resid == recsize && error == 0) {
+		bzero(&dq->dq_dqb, sizeof(dq->dq_dqb));
+	} else {
+		if (ump->um_qflags[type] & QTF_64BIT)
+			dqb64_dq((struct dqblk64 *)buf, dq);
+		else
+			dqb32_dq((struct dqblk32 *)buf, dq);
+	}
 	if (dqvplocked)
 		vput(dqvp);
 	else
@@ -1281,6 +1453,8 @@ dqrele(struct vnode *vp, struct dquot *d
 static int
 dqsync(struct vnode *vp, struct dquot *dq)
 {
+	uint8_t buf[sizeof(struct dqblk64)];
+	off_t base, recsize;
 	struct vnode *dqvp;
 	struct iovec aiov;
 	struct uio auio;
@@ -1327,12 +1501,26 @@ dqsync(struct vnode *vp, struct dquot *d
 	dq->dq_flags |= DQ_LOCK;
 	DQI_UNLOCK(dq);
 
+	/*
+	 * Write the quota record to the quota file, performing any
+	 * necessary conversions.  See dqget() for additional details.
+	 */
+	if (ump->um_qflags[dq->dq_type] & QTF_64BIT) {
+		dq_dqb64(dq, (struct dqblk64 *)buf);
+		recsize = sizeof(struct dqblk64);
+		base = sizeof(struct dqhdr64);
+	} else {
+		dq_dqb32(dq, (struct dqblk32 *)buf);
+		recsize = sizeof(struct dqblk32);
+		base = 0;
+	}
+
 	auio.uio_iov = &aiov;
 	auio.uio_iovcnt = 1;
-	aiov.iov_base = &dq->dq_dqb;
-	aiov.iov_len = sizeof (struct dqblk);
-	auio.uio_resid = sizeof (struct dqblk);
-	auio.uio_offset = (off_t)dq->dq_id * sizeof (struct dqblk);
+	aiov.iov_base = buf;
+	aiov.iov_len = recsize;
+	auio.uio_resid = recsize;
+	auio.uio_offset = base + dq->dq_id * recsize;
 	auio.uio_segflg = UIO_SYSSPACE;
 	auio.uio_rw = UIO_WRITE;
 	auio.uio_td = (struct thread *)0;
@@ -1345,7 +1533,8 @@ dqsync(struct vnode *vp, struct dquot *d
 	DQI_LOCK(dq);
 	DQI_WAKEUP(dq);
 	dq->dq_flags &= ~DQ_MOD;
-out:	DQI_UNLOCK(dq);
+out:
+	DQI_UNLOCK(dq);
 	vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
 	if (vp != dqvp)
 		vput(dqvp);
@@ -1384,3 +1573,98 @@ dqflush(struct vnode *vp)
 	}
 	DQH_UNLOCK();
 }
+
+/*
+ * 32-bit / 64-bit conversion functions.
+ *
+ * 32-bit quota records are stored in native byte order.  Attention must
+ * be paid to overflow issues.
+ *
+ * 64-bit quota records are stored in network byte order.
+ */
+
+#define CLIP32(u64) (u64 > UINT32_MAX ? UINT32_MAX : (uint32_t)u64)
+
+static void
+dqb32_dq(const struct dqblk32 *dqb32, struct dquot *dq)
+{
+
+	dq->dq_bhardlimit = dqb32->dqb_bhardlimit;
+	dq->dq_bsoftlimit = dqb32->dqb_bsoftlimit;
+	dq->dq_curblocks = dqb32->dqb_curblocks;
+	dq->dq_ihardlimit = dqb32->dqb_ihardlimit;
+	dq->dq_isoftlimit = dqb32->dqb_isoftlimit;
+	dq->dq_curinodes = dqb32->dqb_curinodes;
+	dq->dq_btime = dqb32->dqb_btime;
+	dq->dq_itime = dqb32->dqb_itime;
+}
+
+static void
+dqb64_dq(const struct dqblk64 *dqb64, struct dquot *dq)
+{
+
+	dq->dq_bhardlimit = be64toh(dqb64->dqb_bhardlimit);
+	dq->dq_bsoftlimit = be64toh(dqb64->dqb_bsoftlimit);
+	dq->dq_curblocks = be64toh(dqb64->dqb_curblocks);
+	dq->dq_ihardlimit = be64toh(dqb64->dqb_ihardlimit);
+	dq->dq_isoftlimit = be64toh(dqb64->dqb_isoftlimit);
+	dq->dq_curinodes = be64toh(dqb64->dqb_curinodes);
+	dq->dq_btime = be64toh(dqb64->dqb_btime);
+	dq->dq_itime = be64toh(dqb64->dqb_itime);
+}
+
+static void
+dq_dqb32(const struct dquot *dq, struct dqblk32 *dqb32)
+{

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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