Index: ufs/inode.h =================================================================== RCS file: /shared/ncvs/src/sys/ufs/ufs/inode.h,v retrieving revision 1.51 diff -u -r1.51 inode.h --- ufs/inode.h 10 Oct 2006 09:20:54 -0000 1.51 +++ ufs/inode.h 7 Feb 2007 18:33:48 -0000 @@ -128,6 +128,8 @@ #define IN_SPACECOUNTED 0x0080 /* Blocks to be freed in free count. */ #define IN_LAZYACCESS 0x0100 /* Process IN_ACCESS after the suspension finished */ +#define IN_HADUSRQ 0x0200 /* Inode had a user quota in quotaoff */ +#define IN_HADGRPQ 0x0400 /* Inode had a group quota in quotaoff */ #define i_devvp i_ump->um_devvp #define i_umbufobj i_ump->um_bo Index: ufs/quota.h =================================================================== RCS file: /shared/ncvs/src/sys/ufs/ufs/quota.h,v retrieving revision 1.30 diff -u -r1.30 quota.h --- ufs/quota.h 14 Mar 2007 08:54:07 -0000 1.30 +++ ufs/quota.h 7 May 2007 02:28:39 -0000 @@ -44,6 +44,10 @@ * soft limits are treated as hard limits (usually resulting in an allocation * failure). The timer is started when the user crosses their soft limit, it * is reset when they go below their soft limit. + * + * These values can be overridden with the vfs.ufs.quota.grace_itime + * and vfs.ufs.quota.grace_btime sysctls or on a per-file system basis + * with edquota(8). */ #define MAX_IQ_TIME (7*24*60*60) /* seconds in 1 week */ #define MAX_DQ_TIME (7*24*60*60) /* seconds in 1 week */ @@ -60,6 +64,13 @@ #define GRPQUOTA 1 /* element used for group quotas */ /* + * The following constant defines the maximum id value that we will + * maintain quota data for. This value can be overridden with the + * vfs.ufs.quota.id_max sysctl. + */ +#define QUOTA_ID_MAX (1 << 24) /* maximum quota id */ + +/* * Definitions for the default names of the quotas files. */ #define INITQFNAMES { \ @@ -85,6 +96,7 @@ #define Q_SETQUOTA 0x0400 /* set limits and usage */ #define Q_SETUSE 0x0500 /* set usage */ #define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ +#define Q_GETDQUOTS 0x0700 /* read in-core dquots */ /* * The following structure defines the format of the disk quota file @@ -162,6 +174,11 @@ #define CHOWN 0x02 /* (advisory) change initiated by chown */ /* + * Flags to dqget() + */ +#define DQG_INMEM 0x01 /* only get dq from memory, do not read disk */ + +/* * Macros to avoid subroutine calls to trivial functions. */ #ifdef DIAGNOSTIC @@ -194,12 +211,16 @@ struct vnode; int chkdq(struct inode *, int64_t, struct ucred *, int); +#ifdef DIAGNOSTIC +void chkdquot(struct inode *); +#endif int chkiq(struct inode *, int, struct ucred *, int); 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 getdquots(struct thread *, u_long, void *); int qsync(struct mount *mp); int quotaoff(struct thread *td, struct mount *, int); int quotaon(struct thread *td, struct mount *, int, void *); Index: ufs/ufs_dirhash.c =================================================================== RCS file: /shared/ncvs/src/sys/ufs/ufs/ufs_dirhash.c,v retrieving revision 1.23 diff -u -r1.23 ufs_dirhash.c --- ufs/ufs_dirhash.c 31 Oct 2005 15:41:28 -0000 1.23 +++ ufs/ufs_dirhash.c 4 Feb 2007 10:57:49 -0000 @@ -64,7 +64,7 @@ static MALLOC_DEFINE(M_DIRHASH, "ufs_dirhash", "UFS directory hash tables"); -static SYSCTL_NODE(_vfs, OID_AUTO, ufs, CTLFLAG_RD, 0, "UFS filesystem"); +SYSCTL_NODE(_vfs, OID_AUTO, ufs, CTLFLAG_RD, 0, "UFS filesystem"); static int ufs_mindirhashsize = DIRBLKSIZ * 5; SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_minsize, CTLFLAG_RW, Index: ufs/ufs_quota.c =================================================================== RCS file: /shared/ncvs/src/sys/ufs/ufs/ufs_quota.c,v retrieving revision 1.95 diff -u -r1.95 ufs_quota.c --- ufs/ufs_quota.c 12 Jun 2007 00:12:01 -0000 1.95 +++ ufs/ufs_quota.c 20 Jul 2007 05:59:18 -0000 @@ -59,10 +59,29 @@ #include #include +static long grace_btime = MAX_DQ_TIME; /* block grace time. 0 = none */ +static long grace_itime = MAX_IQ_TIME; /* i-node grace time. 0 = none */ +static long quota_debug = 0; +static u_long quota_id_max = QUOTA_ID_MAX; static int unprivileged_get_quota = 0; + SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_get_quota, CTLFLAG_RW, &unprivileged_get_quota, 0, "Unprivileged processes may retrieve quotas for other uids and gids"); +SYSCTL_DECL(_vfs_ufs); +static SYSCTL_NODE(_vfs_ufs, OID_AUTO, quota, CTLFLAG_RD, + 0, "UFS quota system"); +SYSCTL_LONG(_vfs_ufs_quota, OID_AUTO, debug, CTLFLAG_RW, + "a_debug, 0, "Quota system debugging level"); +SYSCTL_LONG(_vfs_ufs_quota, OID_AUTO, grace_btime, CTLFLAG_RW, + &grace_btime, QUOTA_ID_MAX, + "Default quota block usage grace period in seconds"); +SYSCTL_LONG(_vfs_ufs_quota, OID_AUTO, grace_itime, CTLFLAG_RW, + &grace_itime, MAX_IQ_TIME, + "Default quota i-node usage grace period in seconds"); +SYSCTL_ULONG(_vfs_ufs_quota, OID_AUTO, id_max, CTLFLAG_RW, + "a_id_max, QUOTA_ID_MAX, + "Maximum id value allowed for quota accounting"); static MALLOC_DEFINE(M_DQUOT, "ufs_quota", "UFS quota entries"); @@ -77,12 +96,15 @@ u_long, struct ufsmount *, int, struct dquot **); static int dqsync(struct vnode *, struct dquot *); static void dqflush(struct vnode *); +static void dqprint(char *, struct dquot *); static int quotaoff1(struct thread *td, struct mount *mp, int type); static int quotaoff_inchange(struct thread *td, struct mount *mp, int type); #ifdef DIAGNOSTIC static void dqref(struct dquot *); -static void chkdquot(struct inode *); +#if 0 /* mpp */ +void chkdquot(struct inode *); +#endif #endif /* @@ -110,10 +132,10 @@ if ((vp->v_vflag & VV_SYSTEM) != 0) return (0); /* - * XXX: Turn off quotas for files with a negative UID or GID. - * This prevents the creation of 100GB+ quota files. + * Disallow quotas for files with ids that are too large. + * This prevents creation of extremely large quota files. */ - if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) + if (ip->i_uid > quota_id_max || ip->i_gid > quota_id_max) return (0); ump = VFSTOUFS(vp->v_mount); /* @@ -122,16 +144,34 @@ */ if ((error = dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) && - error != EINVAL) + error != EINVAL) { +#ifdef DIAGNOSTIC + printf("getinoquota: user dqget failed ino %lu on dev %s\n", + (u_long)ip->i_number, devtoname(ip->i_dev)); + vprint("getinoquota: user dqget failed", vp); +#endif return (error); + } /* * Set up the group quota based on file gid. * EINVAL means that quotas are not enabled. */ if ((error = dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) && - error != EINVAL) + error != EINVAL) { +#ifdef DIAGNOSTIC + printf("getinoquota: group dqget failed ino %lu on dev %s\n", + (u_long)ip->i_number, devtoname(ip->i_dev)); + vprint("getinoquota: group dqget failed", vp); +#endif return (error); + } +#ifdef DIAGNOSTIC + /* + * Make sure the dquot was actually set in the i-node. + */ + chkdquot(ip); +#endif return (0); } @@ -157,10 +197,10 @@ if ((vp->v_vflag & VV_SYSTEM) != 0) return (0); /* - * XXX: Turn off quotas for files with a negative UID or GID. - * This prevents the creation of 100GB+ quota files. + * Disallow quotas for files with ids that are too large. + * This prevents creation of extremely large quota files. */ - if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) + if (ip->i_uid > quota_id_max || ip->i_gid > quota_id_max) return (0); #ifdef DIAGNOSTIC if ((flags & CHOWN) == 0) @@ -458,7 +498,7 @@ * 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. */ -static void +void chkdquot(ip) struct inode *ip; { @@ -473,10 +513,10 @@ if ((vp->v_vflag & VV_SYSTEM) != 0) return; /* - * XXX: Turn off quotas for files with a negative UID or GID. - * This prevents the creation of 100GB+ quota files. + * Disallow quotas for files with ids that are too large. + * This prevents creation of extremely large quota files. */ - if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) + if (ip->i_uid > quota_id_max || ip->i_gid > quota_id_max) return; UFS_LOCK(ump); @@ -485,7 +525,14 @@ (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING))) continue; if (ip->i_dquot[i] == NODQUOT) { + if (ip->i_ump->um_qflags[i] & QTF_CLOSING) + printf("chkdquot: ip->i_ump->um_qflags & QTF_CLOSING"); + if (ump->um_qflags[i] & QTF_CLOSING) + printf("chkdquot: ump->um_qflags & QTF_CLOSING"); UFS_UNLOCK(ump); + printf("ip = %lx, ip->i_ump = %lx, ump = %lx\n", + (u_long)ip, (u_long)ip->i_ump, (u_long)ump); + vn_printf(vp, "chkdquot: missing dquot\n"); vprint("chkdquot: missing dquot", ITOV(ip)); panic("chkdquot: missing dquot"); } @@ -514,7 +561,11 @@ struct dquot *dq; int error, flags, vfslocked; struct nameidata nd; + struct inode *ip; + int got_dq = 0, skipped = 0, alloced_dq = 0, vnodecount = 0; + int hadgrp, hadusr; + printf("quotaon for type %d\n", type); error = priv_check(td, PRIV_UFS_QUOTAON); if (error) return (error); @@ -564,8 +615,8 @@ * Set up the time limits for this quota. */ ump->um_cred[type] = crhold(td->td_ucred); - ump->um_btime[type] = MAX_DQ_TIME; - ump->um_itime[type] = MAX_IQ_TIME; + ump->um_btime[type] = grace_btime; + ump->um_itime[type] = grace_itime; if (dqget(NULLVP, 0, ump, type, &dq) == 0) { if (dq->dq_btime > 0) ump->um_btime[type] = dq->dq_btime; @@ -587,6 +638,7 @@ */ MNT_ILOCK(mp); again: + vnodecount = 0; MNT_VNODE_FOREACH(vp, mp, mvp) { VI_LOCK(vp); MNT_IUNLOCK(mp); @@ -595,14 +647,81 @@ MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); goto again; } - if (vp->v_type == VNON || vp->v_writecount == 0) { + ip = VTOI(vp); + vnodecount++; + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (vp->v_writecount != 0) + goto getquota; + break; + default: + if (vp->v_writecount != 0) { + vprint("skipping getinoquota for ", vp); + skipped++; + } + VOP_UNLOCK(vp, 0, td); + vrele(vp); + MNT_ILOCK(mp); + continue; + } +#if 0 + if (vp->v_writecount == 0) { + if (type == USRQUOTA && (ip->i_flags & IN_HADUSRQ)) { + vprint("quotaon: no-write & had usr quota before ", vp); + goto getquota; + } + if (type == GRPQUOTA && (ip->i_flags & IN_HADGRPQ)) { + vprint("quotaon: no-write & had grp quota before ", vp); + goto getquota; + } VOP_UNLOCK(vp, 0, td); vrele(vp); MNT_ILOCK(mp); continue; } +#endif +getquota: + if (quota_debug > 1) { + if (vp->v_writecount == 0) { + VOP_UNLOCK(vp, 0, td); + vrele(vp); + MNT_ILOCK(mp); + continue; + } + } + hadusr = hadgrp = 0; + if (ip->i_dquot[USRQUOTA] == NODQUOT) + hadusr = 1; + if (ip->i_dquot[GRPQUOTA] == NODQUOT) + hadgrp = 1; error = getinoquota(VTOI(vp)); VOP_UNLOCK(vp, 0, td); +#if 0 + if (!hadusr && ip->i_dquot[USRQUOTA] != NODQUOT) { + if (ip->i_dquot[USRQUOTA]->dq_cnt == 1) + alloced_dq++; + else + got_dq++; + } + if (!hadgrp && ip->i_dquot[GRPQUOTA] != NODQUOT) { + if (ip->i_dquot[GRPQUOTA]->dq_cnt == 1) + alloced_dq++; + else + got_dq++; + } +#endif +#ifdef DIAGNOSTIC + if (error) { + printf("getinoquota error %d ino %lu on dev %s\n", + error, (u_long)VTOI(vp)->i_number, + devtoname(VTOI(vp)->i_dev)); + vprint("quotaon: getinoquota failed", vp); + } + else + chkdquot(VTOI(vp)); +#endif vrele(vp); MNT_ILOCK(mp); if (error) { @@ -619,6 +738,7 @@ KASSERT((ump->um_qflags[type] & QTF_CLOSING) == 0, ("quotaon: leaking flags")); UFS_UNLOCK(ump); + printf("quotaon set %d dq's, allocated %d, skipped = %d\n", got_dq, alloced_dq, skipped); return (error); } @@ -641,7 +761,9 @@ struct ucred *cr; int vfslocked; int error; + int dqrele_count = 0, dqfree_count = 0, vnodecount = 0; + printf("quotaoff: type = %d\n", type); ump = VFSTOUFS(mp); UFS_LOCK(ump); @@ -660,6 +782,7 @@ */ MNT_ILOCK(mp); again: + vnodecount = 0; MNT_VNODE_FOREACH(vp, mp, mvp) { VI_LOCK(vp); MNT_IUNLOCK(mp); @@ -668,6 +791,7 @@ MNT_ILOCK(mp); continue; } + vnodecount++; if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { MNT_ILOCK(mp); MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); @@ -676,11 +800,28 @@ ip = VTOI(vp); dq = ip->i_dquot[type]; ip->i_dquot[type] = NODQUOT; + if (vp->v_type == VNON || vp->v_writecount == 0) { + if (dq != NULL && quota_debug > 1) { + vprint("quotaoff: non-writer has dq", vp); + printf("v_flag: %#lx, quota type: %d\n", + vp->v_vflag, type); + } + } + if (dq != NULL) { + ip->i_flags |= type == USRQUOTA ? IN_HADUSRQ : + IN_HADGRPQ; + } + if (dq != NULL) { + if (dq->dq_cnt == 1) + dqfree_count++; + dqrele_count++; + } dqrele(vp, dq); VOP_UNLOCK(vp, 0, td); vrele(vp); MNT_ILOCK(mp); } + printf("quotaoff: vnode count = %d,released %d dq's, freed %d for type %d\n", vnodecount, dqrele_count, dqfree_count, type); MNT_IUNLOCK(mp); dqflush(qvp); @@ -984,6 +1125,11 @@ } for (i = 0; i < MAXQUOTAS; i++) { dq = VTOI(vp)->i_dquot[i]; + if (dq != NODQUOT && vp->v_writecount == 0 && + quota_debug > 4) { + dqprint("qsync: non-writer with a dq", dq); + vprint("vnode: ", vp); + } if (dq != NODQUOT) dqsync(vp, dq); } @@ -1046,6 +1192,7 @@ TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); mtx_destroy(&dq->dq_lock); free(dq, M_DQUOT); + numdquot--; } mtx_destroy(&dqhlock); } @@ -1094,6 +1241,7 @@ struct iovec aiov; struct uio auio; int vfslocked, dqvplocked, error; + int count; /* mpp */ #ifdef DEBUG_VFS_LOCKS if (vp != NULLVP) @@ -1104,11 +1252,14 @@ return (0); } - /* XXX: Disallow negative id values to prevent the - * creation of 100GB+ quota data files. - */ - if ((int)id < 0) + /* + * Disallow quotas for files with ids that are too large. + * This prevents creation of extremely large quota files. + */ + if (id > quota_id_max) { + *dqp = NODQUOT; return (EINVAL); + } UFS_LOCK(ump); dqvp = ump->um_quotas[type]; @@ -1171,7 +1322,14 @@ * Not in cache, allocate a new one or take it from the * free list. */ - if (TAILQ_FIRST(&dqfreelist) == NODQUOT && + dq = TAILQ_FIRST(&dqfreelist); + count = 0; + while (dq != NULL) { + count++; + dq = TAILQ_NEXT(dq, dq_freelist); + } + dq = TAILQ_FIRST(&dqfreelist); + if (dq == NULL && numdquot >= desireddquot && numdquot < MAXQUOTAS * desiredvnodes) desireddquot += DQUOTINC; if (numdquot < desireddquot) { @@ -1260,6 +1418,9 @@ DQI_UNLOCK(dq); dqrele(vp, dq); *dqp = NODQUOT; +#ifdef DIAGNOSTIC + printf("dqget: error reading quota file: %d\n", error); +#endif return (error); } DQI_LOCK(dq); @@ -1287,10 +1448,38 @@ DQI_WAKEUP(dq); DQI_UNLOCK(dq); *dqp = dq; + dqprint("dqget: read dq off disk\n", dq); return (0); } #ifdef DIAGNOSTIC + +/* + * Print dq information. + */ + +static void +dqprint(msg, dq) + char *msg; + struct dquot *dq; +{ + if (quota_debug < 2) + return; + printf(msg); + if (dq == NODQUOT) { + printf("dqprint: NULL dq\n"); + return; + } + printf(" dq: %p id: %lu type: %u flags: %#x ump: %p on %s\n", + dq, (u_long)dq->dq_id, dq->dq_type, + dq->dq_flags, dq->dq_ump, devtoname(dq->dq_ump->um_dev)); + printf(" cnt: %lu bslim: %lu bhlim: %lu usage: %lu islim: %lu ihlim: %lu inodes: %lu\n", + (u_long)dq->dq_cnt, (u_long)dq->dq_bsoftlimit, + (u_long)dq->dq_bhardlimit, (u_long)dq->dq_curblocks, + (u_long)dq->dq_isoftlimit, (u_long)dq->dq_ihardlimit, + (u_long)dq->dq_curinodes); +} + /* * Obtain a reference to a dquot. */ @@ -1311,7 +1500,6 @@ struct vnode *vp; struct dquot *dq; { - if (dq == NODQUOT) return; DQH_LOCK(); @@ -1447,3 +1635,66 @@ } DQH_UNLOCK(); } + + +/* + * Q_GETDQUOTS - return the dquot chain + */ +int +getdquots(td, type, addr) + struct thread *td; + u_long type; + void *addr; +{ + int count; + int error; + int locked = 0; + int want = 0; + int fake = 0; + int mod = 0; + int blks = 0; + int inos = 0; + struct dquot *dqaddr; + struct dquot *dq, *nextdq; + struct dqhash *dqh; + + error = priv_check(td, PRIV_VFS_SETQUOTA); + if (error) + return (error); + if (type) { + error = copyout(&numdquot, (caddr_t)addr, sizeof(numdquot)); + return (error); + } + count = 0; + dqaddr = (struct dquot *) addr; + for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) { + for (dq = LIST_FIRST(dqh); dq; dq = nextdq) { + nextdq = LIST_NEXT(dq, dq_hash); + error = copyout(dq, (caddr_t)dqaddr, + sizeof(struct dquot)); + if (error) { + printf("getdquots: copyout: count %d, dqaddr = %lx\n", + count, (u_long)dqaddr); + return (error); + } + if (dq->dq_flags & DQ_LOCK) + locked++; + if (dq->dq_flags & DQ_WANT) + want++; + if (dq->dq_flags & DQ_MOD) + mod++; + if (dq->dq_flags & DQ_FAKE) + fake++; + if (dq->dq_flags & DQ_BLKS) + blks++; + if (dq->dq_flags & DQ_INODS) + inos++; + dqaddr++; + count++; + } + } + printf("returned %d items with GET_DQUOTS\n", count); + printf("dqhash = %lu, locked=%d, want=%d, mod=%d, fake=%d, blks=%d, inos=%d\n", + dqhash, locked, want, mod, fake, blks, inos); + return (0); +} Index: ufs/ufs_vfsops.c =================================================================== RCS file: /shared/ncvs/src/sys/ufs/ufs/ufs_vfsops.c,v retrieving revision 1.48 diff -u -r1.48 ufs_vfsops.c --- ufs/ufs_vfsops.c 1 Feb 2007 02:13:53 -0000 1.48 +++ ufs/ufs_vfsops.c 6 Feb 2007 07:55:01 -0000 @@ -146,6 +146,10 @@ error = qsync(mp); break; + case Q_GETDQUOTS: + error = getdquots(td, type, arg); + break; + default: error = EINVAL; break; Index: ufs/ufs_vnops.c =================================================================== RCS file: /shared/ncvs/src/sys/ufs/ufs/ufs_vnops.c,v retrieving revision 1.291 diff -u -r1.291 ufs_vnops.c --- ufs/ufs_vnops.c 12 Jun 2007 00:12:01 -0000 1.291 +++ ufs/ufs_vnops.c 17 Jul 2007 23:47:39 -0000 @@ -327,6 +327,13 @@ case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); +#ifdef QUOTA + if ((error = getinoquota(ip)) != 0) + return (error); +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif +#endif break; default: break; @@ -719,6 +726,9 @@ #ifdef QUOTA if ((error = getinoquota(ip)) != 0) return (error); +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif if (ouid == uid) { dqrele(vp, ip->i_dquot[USRQUOTA]); ip->i_dquot[USRQUOTA] = NODQUOT; @@ -741,6 +751,9 @@ DIP_SET(ip, i_uid, uid); #ifdef QUOTA if ((error = getinoquota(ip)) == 0) { +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif if (ouid == uid) { dqrele(vp, ip->i_dquot[USRQUOTA]); ip->i_dquot[USRQUOTA] = NODQUOT; @@ -765,6 +778,9 @@ ip->i_uid = ouid; DIP_SET(ip, i_uid, ouid); if (getinoquota(ip) == 0) { +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif if (ouid == uid) { dqrele(vp, ip->i_dquot[USRQUOTA]); ip->i_dquot[USRQUOTA] = NODQUOT; @@ -775,12 +791,20 @@ } (void) chkdq(ip, change, cred, FORCE|CHOWN); (void) chkiq(ip, 1, cred, FORCE|CHOWN); - (void) getinoquota(ip); + if (getinoquota(ip) == 0) { +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif + ; + } } return (error); good: if (getinoquota(ip)) panic("ufs_chown: lost quota"); +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif #endif /* QUOTA */ ip->i_flag |= IN_CHANGE; if ((ip->i_mode & (ISUID | ISGID)) && (ouid != uid || ogid != gid)) { @@ -1450,6 +1474,9 @@ vput(tvp); return (error); } +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif #endif } #else /* !SUIDDIR */ @@ -1462,6 +1489,9 @@ vput(tvp); return (error); } +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif #endif #endif /* !SUIDDIR */ ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; @@ -2010,8 +2040,8 @@ struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); - printf("\tino %lu, on dev %s", (u_long)ip->i_number, - devtoname(ip->i_dev)); + printf("\tino %lu, on dev %s, flags: %#x", (u_long)ip->i_number, + devtoname(ip->i_dev), ip->i_flags); if (vp->v_type == VFIFO) fifo_printinfo(vp); printf("\n"); @@ -2286,6 +2316,9 @@ vput(tvp); return (error); } +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif #endif } #else /* !SUIDDIR */ @@ -2298,6 +2331,9 @@ vput(tvp); return (error); } +#ifdef DIAGNOSTIC + chkdquot(ip); +#endif #endif #endif /* !SUIDDIR */ ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;