Subject: Re: Ufs quota update
To: None <tech-kern@netbsd.org>
From: Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
List: tech-kern
Date: 07/07/2007 12:58:01
--jRHKVT23PllUwdXP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Fri, Jul 06, 2007 at 10:51:32AM -0700, Bill Stouder-Studenmund wrote:
> On Fri, Jul 06, 2007 at 11:21:54AM +0200, Juergen Hannken-Illjes wrote:
> > On Thu, Jul 05, 2007 at 10:53:00AM -0700, Bill Stouder-Studenmund wrote:
> > > 
> > > In general, great!
> > > 
> > > My one concern is that you seem to have removed quota handling from 
> > > ufs_access. I'm not fully sure what it was doing, and thus I'm not fully 
> > > sure if it's safe to remove.
> > 
> > I removed all explicit calls to getinoquota().  These calls don't check any
> > quota, they just make the quota fields of an inode valid.
> > 
> > Instead I changed the functions checking/changing quotas (chkdq() and chkiq())
> > to validate the inode's quota fields.
> 
> We have verified that an inode's quota fields are correct when requesting 
> write access to a file since revision 1.1 of ufs_vnops.c. I believe we 
> need to retain that. If there is an issue with the quota fields in an 
> inode, ufs_access() is a better time to report it than in an operation. 
> All of the other users I saw of getinoquota() subsequently added to or 
> removed from the quota, so merging the routines makes sense. Here, 
> however, we just validate. I believe we need to continue doing so.

Ok, updated diff attached.

-- 
Juergen Hannken-Illjes - hannken@eis.cs.tu-bs.de - TU Braunschweig (Germany)

--jRHKVT23PllUwdXP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ufs_quota.diff"

Index: sys/ufs/ufs/quota.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/quota.h,v
retrieving revision 1.24
diff -p -u -4 -r1.24 quota.h
--- sys/ufs/ufs/quota.h	23 Jun 2007 14:56:09 -0000	1.24
+++ sys/ufs/ufs/quota.h	7 Jul 2007 10:42:26 -0000
@@ -105,97 +105,16 @@ struct dqblk {
 	int32_t	  dqb_itime;		/* time limit for excessive files */
 };
 
 #ifdef _KERNEL
-#include <sys/queue.h>
-
-/*
- * The following structure records disk usage for a user or group on a
- * filesystem. There is one allocated for each quota that exists on any
- * filesystem for the current user or group. A cache is kept of recently
- * used entries.
- */
-struct dquot {
-	LIST_ENTRY(dquot) dq_hash;	/* hash list */
-	TAILQ_ENTRY(dquot) dq_freelist;	/* free list */
-	u_int16_t dq_flags;		/* flags, see below */
-	u_int16_t dq_type;		/* quota type of this dquot */
-	u_int32_t dq_cnt;		/* count of active references */
-	u_int32_t dq_id;		/* identifier this applies to */
-	struct	ufsmount *dq_ump;	/* filesystem that this is taken from */
-	struct	dqblk dq_dqb;		/* actual usage & quotas */
-};
-/*
- * Flag values.
- */
-#define	DQ_LOCK		0x01		/* this quota locked (no MODS) */
-#define	DQ_WANT		0x02		/* wakeup on unlock */
-#define	DQ_MOD		0x04		/* this quota modified since read */
-#define	DQ_FAKE		0x08		/* no limits here, just usage */
-#define	DQ_BLKS		0x10		/* has been warned about blk limit */
-#define	DQ_INODS	0x20		/* has been warned about inode limit */
-/*
- * Shorthand notation.
- */
-#define	dq_bhardlimit	dq_dqb.dqb_bhardlimit
-#define	dq_bsoftlimit	dq_dqb.dqb_bsoftlimit
-#define	dq_curblocks	dq_dqb.dqb_curblocks
-#define	dq_ihardlimit	dq_dqb.dqb_ihardlimit
-#define	dq_isoftlimit	dq_dqb.dqb_isoftlimit
-#define	dq_curinodes	dq_dqb.dqb_curinodes
-#define	dq_btime	dq_dqb.dqb_btime
-#define	dq_itime	dq_dqb.dqb_itime
-
-/*
- * If the system has never checked for a quota for this file, then it is
- * set to NODQUOT.  Once a write attempt is made the inode pointer is set
- * to reference a dquot structure.
- */
-#define	NODQUOT		NULL
-
-/*
- * Flags to chkdq() and chkiq()
- */
-#define	FORCE	0x01	/* force usage changes independent of limits */
-#define	CHOWN	0x02	/* (advisory) change initiated by chown */
 
 #include <sys/cdefs.h>
 
-struct dquot;
-struct inode;
-struct mount;
-struct proc;
-struct ufsmount;
-struct vnode;
 __BEGIN_DECLS
-int	chkdq(struct inode *, int64_t, kauth_cred_t, int);
-int	chkdqchg(struct inode *, int64_t, kauth_cred_t, int);
-int	chkiq(struct inode *, int32_t, kauth_cred_t, int);
-int	chkiqchg(struct inode *, int32_t, kauth_cred_t, int);
-void	dqflush(struct vnode *);
-int	dqget(struct vnode *,
-	    u_long, struct ufsmount *, int, struct dquot **);
 void	dqinit(void);
 void	dqreinit(void);
 void	dqdone(void);
-void	dqref(struct dquot *);
-void	dqrele(struct vnode *, struct dquot *);
-int	dqsync(struct vnode *, struct dquot *);
-int	getinoquota(struct inode *);
-int	getquota(struct mount *, u_long, int, void *);
-int	qsync(struct mount *mp);
-int	quotaoff(struct lwp *, struct mount *, int);
-int	quotaon(struct lwp *, struct mount *, int, void *);
-int	setquota(struct mount *, u_long, int, void *);
-int	setuse(struct mount *, u_long, int, void *);
-int	ufs_quotactl(struct mount *, int, uid_t, void *, struct lwp *);
-__END_DECLS
-
-#ifdef DIAGNOSTIC
-__BEGIN_DECLS
-void	chkdquot(struct inode *);
 __END_DECLS
-#endif
 #else
 __BEGIN_DECLS
 int quotactl(const char *, int , int, void *);
 __END_DECLS
Index: sys/ufs/ufs/ufs_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_extern.h,v
retrieving revision 1.52
diff -p -u -4 -r1.52 ufs_extern.h
--- sys/ufs/ufs/ufs_extern.h	4 Mar 2007 06:03:47 -0000	1.52
+++ sys/ufs/ufs/ufs_extern.h	7 Jul 2007 10:42:27 -0000
@@ -131,25 +131,23 @@ int	ufs_dirempty(struct inode *, ino_t, 
 int	ufs_checkpath(struct inode *, struct inode *, kauth_cred_t);
 int	ufs_blkatoff(struct vnode *, off_t, char **, struct buf **);
 
 /* ufs_quota.c */
+/*
+ * Flags to chkdq() and chkiq()
+ */
+#define	FORCE	0x01	/* force usage changes independent of limits */
+void	ufsquota_init(struct inode *);
+void	ufsquota_free(struct inode *);
 int	getinoquota(struct inode *);
 int	chkdq(struct inode *, int64_t, kauth_cred_t, int);
-int	chkdqchg(struct inode *, int64_t, kauth_cred_t, int);
 int	chkiq(struct inode *, int32_t, kauth_cred_t, int);
-int	chkiqchg(struct inode *, int32_t, kauth_cred_t, int);
-void	chkdquot(struct inode *);
 int	quotaon(struct lwp *, struct mount *, int, void *);
 int	quotaoff(struct lwp *, struct mount *, int);
 int	getquota(struct mount *, u_long, int, void *);
 int	setquota(struct mount *, u_long, int, void *);
 int	setuse(struct mount *, u_long, int, void *);
 int	qsync(struct mount *);
-int	dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **);
-void	dqref(struct dquot *);
-void	dqrele(struct vnode *, struct dquot *);
-int	dqsync(struct vnode *, struct dquot *);
-void	dqflush(struct vnode *);
 
 /* ufs_vfsops.c */
 void	ufs_init(void);
 void	ufs_reinit(void);
Index: sys/ufs/ufs/ufs_dirhash.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_dirhash.c,v
retrieving revision 1.14
diff -p -u -4 -r1.14 ufs_dirhash.c
--- sys/ufs/ufs/ufs_dirhash.c	12 Mar 2007 18:18:38 -0000	1.14
+++ sys/ufs/ufs/ufs_dirhash.c	7 Jul 2007 10:42:26 -0000
@@ -43,9 +43,8 @@
 #include <sys/mount.h>
 #include <sys/pool.h>
 #include <sys/sysctl.h>
 
-#include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>
 #include <ufs/ufs/dirhash.h>
 #include <ufs/ufs/ufsmount.h>
Index: sys/ufs/ufs/ufs_extattr.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_extattr.c,v
retrieving revision 1.13
diff -p -u -4 -r1.13 ufs_extattr.c
--- sys/ufs/ufs/ufs_extattr.c	4 Mar 2007 06:03:47 -0000	1.13
+++ sys/ufs/ufs/ufs_extattr.c	7 Jul 2007 10:42:27 -0000
@@ -69,9 +69,8 @@ __RCSID("$NetBSD: ufs_extattr.c,v 1.13 2
 #include <sys/sysctl.h>
 
 #include <ufs/ufs/dir.h>
 #include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/ufs_bswap.h>
 #include <ufs/ufs/ufs_extern.h>
Index: sys/ufs/ufs/ufs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_inode.c,v
retrieving revision 1.66
diff -p -u -4 -r1.66 ufs_inode.c
--- sys/ufs/ufs/ufs_inode.c	17 May 2007 07:26:22 -0000	1.66
+++ sys/ufs/ufs/ufs_inode.c	7 Jul 2007 10:42:27 -0000
@@ -53,9 +53,8 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,
 #include <sys/namei.h>
 #include <sys/kauth.h>
 #include <sys/fstrans.h>
 
-#include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/ufs_extern.h>
 #ifdef UFS_DIRHASH
@@ -100,10 +99,9 @@ ufs_inactive(void *v)
 		softdep_releasefile(ip);
 
 	if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
 #ifdef QUOTA
-		if (!getinoquota(ip))
-			(void)chkiq(ip, -1, NOCRED, 0);
+		(void)chkiq(ip, -1, NOCRED, 0);
 #endif
 #ifdef UFS_EXTATTR
 		ufs_extattr_vnode_inactive(vp, l);
 #endif
@@ -170,17 +168,9 @@ ufs_reclaim(struct vnode *vp, struct lwp
 		vrele(ip->i_devvp);
 		ip->i_devvp = 0;
 	}
 #ifdef QUOTA
-	{
-		int i;
-		for (i = 0; i < MAXQUOTAS; i++) {
-			if (ip->i_dquot[i] != NODQUOT) {
-				dqrele(vp, ip->i_dquot[i]);
-				ip->i_dquot[i] = NODQUOT;
-			}
-		}
-	}
+	ufsquota_free(ip);
 #endif
 #ifdef UFS_DIRHASH
 	if (ip->i_dirhash != NULL)
 		ufsdirhash_free(ip);
Index: sys/ufs/ufs/ufs_quota.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_quota.c,v
retrieving revision 1.46
diff -p -u -4 -r1.46 ufs_quota.c
--- sys/ufs/ufs/ufs_quota.c	23 Jun 2007 14:56:10 -0000	1.46
+++ sys/ufs/ufs/ufs_quota.c	7 Jul 2007 10:42:27 -0000
@@ -53,8 +53,60 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/ufs_extern.h>
 
 /*
+ * The following structure records disk usage for a user or group on a
+ * filesystem. There is one allocated for each quota that exists on any
+ * filesystem for the current user or group. A cache is kept of recently
+ * used entries.
+ */
+struct dquot {
+	LIST_ENTRY(dquot) dq_hash;	/* hash list */
+	TAILQ_ENTRY(dquot) dq_freelist;	/* free list */
+	u_int16_t dq_flags;		/* flags, see below */
+	u_int16_t dq_type;		/* quota type of this dquot */
+	u_int32_t dq_cnt;		/* count of active references */
+	u_int32_t dq_id;		/* identifier this applies to */
+	struct	ufsmount *dq_ump;	/* filesystem that this is taken from */
+	struct	dqblk dq_dqb;		/* actual usage & quotas */
+};
+/*
+ * Flag values.
+ */
+#define	DQ_LOCK		0x01		/* this quota locked (no MODS) */
+#define	DQ_WANT		0x02		/* wakeup on unlock */
+#define	DQ_MOD		0x04		/* this quota modified since read */
+#define	DQ_FAKE		0x08		/* no limits here, just usage */
+#define	DQ_BLKS		0x10		/* has been warned about blk limit */
+#define	DQ_INODS	0x20		/* has been warned about inode limit */
+/*
+ * Shorthand notation.
+ */
+#define	dq_bhardlimit	dq_dqb.dqb_bhardlimit
+#define	dq_bsoftlimit	dq_dqb.dqb_bsoftlimit
+#define	dq_curblocks	dq_dqb.dqb_curblocks
+#define	dq_ihardlimit	dq_dqb.dqb_ihardlimit
+#define	dq_isoftlimit	dq_dqb.dqb_isoftlimit
+#define	dq_curinodes	dq_dqb.dqb_curinodes
+#define	dq_btime	dq_dqb.dqb_btime
+#define	dq_itime	dq_dqb.dqb_itime
+/*
+ * If the system has never checked for a quota for this file, then it is
+ * set to NODQUOT.  Once a write attempt is made the inode pointer is set
+ * to reference a dquot structure.
+ */
+#define	NODQUOT		NULL
+
+static int chkdqchg(struct inode *, int64_t, kauth_cred_t, int);
+static int chkiqchg(struct inode *, int32_t, kauth_cred_t, int);
+static void dqflush(struct vnode *);
+static int dqget(struct vnode *, u_long, struct ufsmount *, int,
+		 struct dquot **);
+static void dqref(struct dquot *);
+static void dqrele(struct vnode *, struct dquot *); 
+static int dqsync(struct vnode *, struct dquot *);
+
+/*
  * Quota name to error message mapping.
  */
 static const char *quotatypes[] = INITQFNAMES;
 
@@ -73,8 +125,16 @@ getinoquota(struct inode *ip)
 	struct vnode *vp = ITOV(ip);
 	int error;
 
 	/*
+	 * If the file uid changed the user quota needs update.
+	 */
+	if (ip->i_dquot[USRQUOTA] != NODQUOT &&
+	    ip->i_dquot[USRQUOTA]->dq_id != ip->i_uid) {
+		dqrele(ITOV(ip), ip->i_dquot[USRQUOTA]);
+		ip->i_dquot[USRQUOTA] = NODQUOT;
+	}
+	/*
 	 * Set up the user quota based on file uid.
 	 * EINVAL means that quotas are not enabled.
 	 */
 	if (ip->i_dquot[USRQUOTA] == NODQUOT &&
@@ -82,8 +142,16 @@ getinoquota(struct inode *ip)
 		dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) &&
 	    error != EINVAL)
 		return (error);
 	/*
+	 * If the file gid changed the group quota needs update.
+	 */
+	if (ip->i_dquot[GRPQUOTA] != NODQUOT &&
+	    ip->i_dquot[GRPQUOTA]->dq_id != ip->i_gid) {
+		dqrele(ITOV(ip), ip->i_dquot[GRPQUOTA]);
+		ip->i_dquot[GRPQUOTA] = NODQUOT;
+	}
+	/*
 	 * Set up the group quota based on file gid.
 	 * EINVAL means that quotas are not enabled.
 	 */
 	if (ip->i_dquot[GRPQUOTA] == NODQUOT &&
@@ -94,8 +162,34 @@ getinoquota(struct inode *ip)
 	return (0);
 }
 
 /*
+ * Initialize the quota fields of an inode.
+ */
+void
+ufsquota_init(struct inode *ip)
+{
+	int i;
+
+	for (i = 0; i < MAXQUOTAS; i++)
+		ip->i_dquot[i] = NODQUOT;
+}
+
+/*
+ * Release the quota fields from an inode.
+ */
+void
+ufsquota_free(struct inode *ip)
+{
+	int i;
+
+	for (i = 0; i < MAXQUOTAS; i++) {
+		dqrele(ITOV(ip), ip->i_dquot[i]);
+		ip->i_dquot[i] = NODQUOT;
+	}
+}
+
+/*
  * Update disk usage, and take corrective action.
  */
 int
 chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
@@ -103,12 +197,10 @@ chkdq(struct inode *ip, int64_t change, 
 	struct dquot *dq;
 	int i;
 	int ncurblocks, error;
 
-#ifdef DIAGNOSTIC
-	if ((flags & CHOWN) == 0)
-		chkdquot(ip);
-#endif
+	if ((error = getinoquota(ip)) != 0)
+		return error;
 	if (change == 0)
 		return (0);
 	if (change < 0) {
 		for (i = 0; i < MAXQUOTAS; i++) {
@@ -153,9 +245,9 @@ chkdq(struct inode *ip, int64_t change, 
 /*
  * Check for a valid change to a users allocation.
  * Issue an error message if appropriate.
  */
-int
+static int
 chkdqchg(struct inode *ip, int64_t change, kauth_cred_t cred, int type)
 {
 	struct dquot *dq = ip->i_dquot[type];
 	long ncurblocks = dq->dq_curblocks + change;
@@ -210,12 +302,10 @@ chkiq(struct inode *ip, int32_t change, 
 	struct dquot *dq;
 	int i;
 	int ncurinodes, error;
 
-#ifdef DIAGNOSTIC
-	if ((flags & CHOWN) == 0)
-		chkdquot(ip);
-#endif
+	if ((error = getinoquota(ip)) != 0)
+		return error;
 	if (change == 0)
 		return (0);
 	if (change < 0) {
 		for (i = 0; i < MAXQUOTAS; i++) {
@@ -260,9 +350,9 @@ chkiq(struct inode *ip, int32_t change, 
 /*
  * Check for a valid change to a users allocation.
  * Issue an error message if appropriate.
  */
-int
+static int
 chkiqchg(struct inode *ip, int32_t change, kauth_cred_t cred, int type)
 {
 	struct dquot *dq = ip->i_dquot[type];
 	long ncurinodes = dq->dq_curinodes + change;
@@ -307,31 +397,8 @@ chkiqchg(struct inode *ip, int32_t chang
 	}
 	return (0);
 }
 
-#ifdef DIAGNOSTIC
-/*
- * On filesystems with quotas enabled, it is an error for a file to change
- * size and not to have a dquot structure associated with it.
- */
-void
-chkdquot(struct inode *ip)
-{
-	struct ufsmount *ump = ip->i_ump;
-	int i;
-
-	for (i = 0; i < MAXQUOTAS; i++) {
-		if (ump->um_quotas[i] == NULLVP ||
-		    (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
-			continue;
-		if (ip->i_dquot[i] == NODQUOT) {
-			vprint("chkdquot: missing dquot", ITOV(ip));
-			panic("missing dquot");
-		}
-	}
-}
-#endif
-
 /*
  * Code to process quotactl commands.
  */
 
@@ -697,9 +764,9 @@ dqdone(void)
 /*
  * Obtain a dquot structure for the specified identifier and quota file
  * reading the information from the file if necessary.
  */
-int
+static int
 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
     struct dquot **dqp)
 {
 	struct dquot *dq;
@@ -810,9 +877,9 @@ dqget(struct vnode *vp, u_long id, struc
 
 /*
  * Obtain a reference to a dquot.
  */
-void
+static void
 dqref(struct dquot *dq)
 {
 
 	dq->dq_cnt++;
@@ -821,9 +888,9 @@ dqref(struct dquot *dq)
 
 /*
  * Release a reference to a dquot.
  */
-void
+static void
 dqrele(struct vnode *vp, struct dquot *dq)
 {
 
 	if (dq == NODQUOT)
@@ -841,9 +908,9 @@ dqrele(struct vnode *vp, struct dquot *d
 
 /*
  * Update the disk quota in the quota file.
  */
-int
+static int
 dqsync(struct vnode *vp, struct dquot *dq)
 {
 	struct vnode *dqvp;
 	struct iovec aiov;
@@ -889,9 +956,9 @@ dqsync(struct vnode *vp, struct dquot *d
 
 /*
  * Flush all entries from the cache for a particular vnode.
  */
-void
+static void
 dqflush(struct vnode *vp)
 {
 	struct dquot *dq, *nextdq;
 	struct dqhashhead *dqh;
Index: sys/ufs/ufs/ufs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.153
diff -p -u -4 -r1.153 ufs_vnops.c
--- sys/ufs/ufs/ufs_vnops.c	17 May 2007 07:26:23 -0000	1.153
+++ sys/ufs/ufs/ufs_vnops.c	7 Jul 2007 10:42:27 -0000
@@ -64,9 +64,8 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,
 
 #include <miscfs/specfs/specdev.h>
 #include <miscfs/fifofs/fifo.h>
 
-#include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/ufs_bswap.h>
@@ -581,9 +580,8 @@ ufs_chown(struct vnode *vp, uid_t uid, g
 	int		error, ismember = 0;
 #ifdef QUOTA
 	uid_t		ouid;
 	gid_t		ogid;
-	int		i;
 	int64_t		change;
 #endif
 	ip = VTOI(vp);
 	error = 0;
@@ -609,72 +607,31 @@ ufs_chown(struct vnode *vp, uid_t uid, g
 
 #ifdef QUOTA
 	ogid = ip->i_gid;
 	ouid = ip->i_uid;
-	if ((error = getinoquota(ip)) != 0)
-		return (error);
-	if (ouid == uid) {
-		dqrele(vp, ip->i_dquot[USRQUOTA]);
-		ip->i_dquot[USRQUOTA] = NODQUOT;
-	}
-	if (ogid == gid) {
-		dqrele(vp, ip->i_dquot[GRPQUOTA]);
-		ip->i_dquot[GRPQUOTA] = NODQUOT;
-	}
 	change = DIP(ip, blocks);
-	(void) chkdq(ip, -change, cred, CHOWN);
-	(void) chkiq(ip, -1, cred, CHOWN);
-	for (i = 0; i < MAXQUOTAS; i++) {
-		dqrele(vp, ip->i_dquot[i]);
-		ip->i_dquot[i] = NODQUOT;
-	}
+	(void) chkdq(ip, -change, cred, 0);
+	(void) chkiq(ip, -1, cred, 0);
 #endif
 	ip->i_gid = gid;
 	DIP_ASSIGN(ip, gid, gid);
 	ip->i_uid = uid;
 	DIP_ASSIGN(ip, uid, uid);
 #ifdef QUOTA
-	if ((error = getinoquota(ip)) == 0) {
-		if (ouid == uid) {
-			dqrele(vp, ip->i_dquot[USRQUOTA]);
-			ip->i_dquot[USRQUOTA] = NODQUOT;
-		}
-		if (ogid == gid) {
-			dqrele(vp, ip->i_dquot[GRPQUOTA]);
-			ip->i_dquot[GRPQUOTA] = NODQUOT;
-		}
-		if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
-			if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
-				goto good;
-			else
-				(void) chkdq(ip, -change, cred, CHOWN|FORCE);
-		}
-		for (i = 0; i < MAXQUOTAS; i++) {
-			dqrele(vp, ip->i_dquot[i]);
-			ip->i_dquot[i] = NODQUOT;
-		}
+	if ((error = chkdq(ip, change, cred, 0)) == 0) {
+		if ((error = chkiq(ip, 1, cred, 0)) == 0)
+			goto good;
+		else
+			(void) chkdq(ip, -change, cred, FORCE);
 	}
 	ip->i_gid = ogid;
 	DIP_ASSIGN(ip, gid, ogid);
 	ip->i_uid = ouid;
 	DIP_ASSIGN(ip, uid, ouid);
-	if (getinoquota(ip) == 0) {
-		if (ouid == uid) {
-			dqrele(vp, ip->i_dquot[USRQUOTA]);
-			ip->i_dquot[USRQUOTA] = NODQUOT;
-		}
-		if (ogid == gid) {
-			dqrele(vp, ip->i_dquot[GRPQUOTA]);
-			ip->i_dquot[GRPQUOTA] = NODQUOT;
-		}
-		(void) chkdq(ip, change, cred, FORCE|CHOWN);
-		(void) chkiq(ip, 1, cred, FORCE|CHOWN);
-		(void) getinoquota(ip);
-	}
+	(void) chkdq(ip, change, cred, FORCE);
+	(void) chkiq(ip, 1, cred, FORCE);
 	return (error);
  good:
-	if (getinoquota(ip))
-		panic("chown: lost quota");
 #endif /* QUOTA */
 	ip->i_flag |= IN_CHANGE;
 	return (0);
 }
@@ -1347,10 +1304,9 @@ ufs_mkdir(void *v)
 	DIP_ASSIGN(ip, uid, ip->i_uid);
 	ip->i_gid = dp->i_gid;
 	DIP_ASSIGN(ip, gid, ip->i_gid);
 #ifdef QUOTA
-	if ((error = getinoquota(ip)) ||
-	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
+	if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) {
 		PNBUF_PUT(cnp->cn_pnbuf);
 		UFS_VFREE(tvp, ip->i_number, dmode);
 		fstrans_done(dvp->v_mount);
 		vput(tvp);
@@ -2181,10 +2137,9 @@ ufs_makeinode(int mode, struct vnode *dv
 	DIP_ASSIGN(ip, gid, ip->i_gid);
 	ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
 	DIP_ASSIGN(ip, uid, ip->i_uid);
 #ifdef QUOTA
-	if ((error = getinoquota(ip)) ||
-	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
+	if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) {
 		UFS_VFREE(tvp, ip->i_number, mode);
 		vput(tvp);
 		PNBUF_PUT(cnp->cn_pnbuf);
 		vput(dvp);
Index: sys/ufs/ffs/ffs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_inode.c,v
retrieving revision 1.87
diff -p -u -4 -r1.87 ffs_inode.c
--- sys/ufs/ffs/ffs_inode.c	5 Jun 2007 12:31:34 -0000	1.87
+++ sys/ufs/ffs/ffs_inode.c	7 Jul 2007 10:42:25 -0000
@@ -202,12 +202,8 @@ ffs_truncate(struct vnode *ovp, off_t le
 	if (oip->i_size == length) {
 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
 		return (ffs_update(ovp, NULL, NULL, 0));
 	}
-#ifdef QUOTA
-	if ((error = getinoquota(oip)) != 0)
-		return (error);
-#endif
 	fs = oip->i_fs;
 	if (length > ump->um_maxfilesize)
 		return (EFBIG);
 
Index: sys/ufs/ffs/ffs_snapshot.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_snapshot.c,v
retrieving revision 1.43
diff -p -u -4 -r1.43 ffs_snapshot.c
--- sys/ufs/ffs/ffs_snapshot.c	4 Mar 2007 06:03:43 -0000	1.43
+++ sys/ufs/ffs/ffs_snapshot.c	7 Jul 2007 10:42:26 -0000
@@ -41,9 +41,8 @@
 __KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.43 2007/03/04 06:03:43 christos Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
-#include "opt_quota.h"
 #endif
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -187,12 +186,8 @@ ffs_snapshot(struct mount *mp, struct vn
 	    NULL) != 0 &&
 	    VTOI(vp)->i_uid != kauth_cred_geteuid(l->l_cred))
 		return EACCES;
 
-#ifdef QUOTA
-	if ((error = getinoquota(VTOI(vp))) != 0)
-		return error;
-#endif
 	if (vp->v_size != 0) {
 		error = ffs_truncate(vp, 0, 0, NOCRED, l);
 		if (error)
 			return error;
Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.201
diff -p -u -4 -r1.201 ffs_vfsops.c
--- sys/ufs/ffs/ffs_vfsops.c	29 May 2007 11:30:17 -0000	1.201
+++ sys/ufs/ffs/ffs_vfsops.c	7 Jul 2007 10:42:26 -0000
@@ -1463,14 +1463,9 @@ ffs_vget(struct mount *mp, ino_t ino, st
 	ip->i_dev = dev;
 	ip->i_number = ino;
 	LIST_INIT(&ip->i_pcbufhd);
 #ifdef QUOTA
-	{
-		int i;
-
-		for (i = 0; i < MAXQUOTAS; i++)
-			ip->i_dquot[i] = NODQUOT;
-	}
+	ufsquota_init(ip);
 #endif
 
 	/*
 	 * Put it onto its hash chain and lock it so that other requests for
Index: sys/ufs/lfs/lfs_alloc.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_alloc.c,v
retrieving revision 1.100
diff -p -u -4 -r1.100 lfs_alloc.c
--- sys/ufs/lfs/lfs_alloc.c	15 Feb 2007 15:40:54 -0000	1.100
+++ sys/ufs/lfs/lfs_alloc.c	7 Jul 2007 10:42:26 -0000
@@ -321,11 +321,8 @@ lfs_vcreate(struct mount *mp, ino_t ino,
 {
 	struct inode *ip;
 	struct ufs1_dinode *dp;
 	struct ufsmount *ump;
-#ifdef QUOTA
-	int i;
-#endif
 
 	/* Get a pointer to the private mount structure. */
 	ump = VFSTOUFS(mp);
 
@@ -350,10 +347,9 @@ lfs_vcreate(struct mount *mp, ino_t ino,
 	SPLAY_INIT(&ip->i_lfs_lbtree);
 	ip->i_lfs_nbtree = 0;
 	LIST_INIT(&ip->i_lfs_segdhd);
 #ifdef QUOTA
-	for (i = 0; i < MAXQUOTAS; i++)
-		ip->i_dquot[i] = NODQUOT;
+	ufsquota_init(ip);
 #endif
 #ifdef DEBUG
 	if (ino == LFS_IFILE_INUM)
 		vp->v_vnlock->lk_wmesg = "inlock";
Index: sys/ufs/lfs/lfs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_inode.c,v
retrieving revision 1.110
diff -p -u -4 -r1.110 lfs_inode.c
--- sys/ufs/lfs/lfs_inode.c	5 Jun 2007 12:31:34 -0000	1.110
+++ sys/ufs/lfs/lfs_inode.c	7 Jul 2007 10:42:26 -0000
@@ -255,12 +255,8 @@ lfs_truncate(struct vnode *ovp, off_t le
 	if (oip->i_size == length) {
 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
 		return (lfs_update(ovp, NULL, NULL, 0));
 	}
-#ifdef QUOTA
-	if ((error = getinoquota(oip)) != 0)
-		return (error);
-#endif
 	fs = oip->i_lfs;
 	lfs_imtime(fs);
 	osize = oip->i_size;
 	usepc = (ovp->v_type == VREG && ovp != fs->lfs_ivnode);

--jRHKVT23PllUwdXP--