Home | History | Annotate | Line # | Download | only in ufs
ufs_quota.c revision 1.1
      1 /*
      2  * Copyright (c) 1982, 1986, 1990, 1993
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * This code is derived from software contributed to Berkeley by
      6  * Robert Elz at The University of Melbourne.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  *	from: @(#)ufs_quota.c	8.2 (Berkeley) 12/30/93
     37  *	$Id: ufs_quota.c,v 1.1 1994/06/08 11:43:20 mycroft Exp $
     38  */
     39 #include <sys/param.h>
     40 #include <sys/kernel.h>
     41 #include <sys/systm.h>
     42 #include <sys/namei.h>
     43 #include <sys/malloc.h>
     44 #include <sys/file.h>
     45 #include <sys/proc.h>
     46 #include <sys/vnode.h>
     47 #include <sys/mount.h>
     48 
     49 #include <ufs/ufs/quota.h>
     50 #include <ufs/ufs/inode.h>
     51 #include <ufs/ufs/ufsmount.h>
     52 #include <ufs/ufs/ufs_extern.h>
     53 
     54 /*
     55  * Quota name to error message mapping.
     56  */
     57 static char *quotatypes[] = INITQFNAMES;
     58 
     59 /*
     60  * Set up the quotas for an inode.
     61  *
     62  * This routine completely defines the semantics of quotas.
     63  * If other criterion want to be used to establish quotas, the
     64  * MAXQUOTAS value in quotas.h should be increased, and the
     65  * additional dquots set up here.
     66  */
     67 int
     68 getinoquota(ip)
     69 	register struct inode *ip;
     70 {
     71 	struct ufsmount *ump;
     72 	struct vnode *vp = ITOV(ip);
     73 	int error;
     74 
     75 	ump = VFSTOUFS(vp->v_mount);
     76 	/*
     77 	 * Set up the user quota based on file uid.
     78 	 * EINVAL means that quotas are not enabled.
     79 	 */
     80 	if (ip->i_dquot[USRQUOTA] == NODQUOT &&
     81 	    (error =
     82 		dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) &&
     83 	    error != EINVAL)
     84 		return (error);
     85 	/*
     86 	 * Set up the group quota based on file gid.
     87 	 * EINVAL means that quotas are not enabled.
     88 	 */
     89 	if (ip->i_dquot[GRPQUOTA] == NODQUOT &&
     90 	    (error =
     91 		dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) &&
     92 	    error != EINVAL)
     93 		return (error);
     94 	return (0);
     95 }
     96 
     97 /*
     98  * Update disk usage, and take corrective action.
     99  */
    100 int
    101 chkdq(ip, change, cred, flags)
    102 	register struct inode *ip;
    103 	long change;
    104 	struct ucred *cred;
    105 	int flags;
    106 {
    107 	register struct dquot *dq;
    108 	register int i;
    109 	int ncurblocks, error;
    110 
    111 #ifdef DIAGNOSTIC
    112 	if ((flags & CHOWN) == 0)
    113 		chkdquot(ip);
    114 #endif
    115 	if (change == 0)
    116 		return (0);
    117 	if (change < 0) {
    118 		for (i = 0; i < MAXQUOTAS; i++) {
    119 			if ((dq = ip->i_dquot[i]) == NODQUOT)
    120 				continue;
    121 			while (dq->dq_flags & DQ_LOCK) {
    122 				dq->dq_flags |= DQ_WANT;
    123 				sleep((caddr_t)dq, PINOD+1);
    124 			}
    125 			ncurblocks = dq->dq_curblocks + change;
    126 			if (ncurblocks >= 0)
    127 				dq->dq_curblocks = ncurblocks;
    128 			else
    129 				dq->dq_curblocks = 0;
    130 			dq->dq_flags &= ~DQ_BLKS;
    131 			dq->dq_flags |= DQ_MOD;
    132 		}
    133 		return (0);
    134 	}
    135 	if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
    136 		for (i = 0; i < MAXQUOTAS; i++) {
    137 			if ((dq = ip->i_dquot[i]) == NODQUOT)
    138 				continue;
    139 			if (error = chkdqchg(ip, change, cred, i))
    140 				return (error);
    141 		}
    142 	}
    143 	for (i = 0; i < MAXQUOTAS; i++) {
    144 		if ((dq = ip->i_dquot[i]) == NODQUOT)
    145 			continue;
    146 		while (dq->dq_flags & DQ_LOCK) {
    147 			dq->dq_flags |= DQ_WANT;
    148 			sleep((caddr_t)dq, PINOD+1);
    149 		}
    150 		dq->dq_curblocks += change;
    151 		dq->dq_flags |= DQ_MOD;
    152 	}
    153 	return (0);
    154 }
    155 
    156 /*
    157  * Check for a valid change to a users allocation.
    158  * Issue an error message if appropriate.
    159  */
    160 int
    161 chkdqchg(ip, change, cred, type)
    162 	struct inode *ip;
    163 	long change;
    164 	struct ucred *cred;
    165 	int type;
    166 {
    167 	register struct dquot *dq = ip->i_dquot[type];
    168 	long ncurblocks = dq->dq_curblocks + change;
    169 
    170 	/*
    171 	 * If user would exceed their hard limit, disallow space allocation.
    172 	 */
    173 	if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
    174 		if ((dq->dq_flags & DQ_BLKS) == 0 &&
    175 		    ip->i_uid == cred->cr_uid) {
    176 			uprintf("\n%s: write failed, %s disk limit reached\n",
    177 			    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    178 			    quotatypes[type]);
    179 			dq->dq_flags |= DQ_BLKS;
    180 		}
    181 		return (EDQUOT);
    182 	}
    183 	/*
    184 	 * If user is over their soft limit for too long, disallow space
    185 	 * allocation. Reset time limit as they cross their soft limit.
    186 	 */
    187 	if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
    188 		if (dq->dq_curblocks < dq->dq_bsoftlimit) {
    189 			dq->dq_btime = time.tv_sec +
    190 			    VFSTOUFS(ITOV(ip)->v_mount)->um_btime[type];
    191 			if (ip->i_uid == cred->cr_uid)
    192 				uprintf("\n%s: warning, %s %s\n",
    193 				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    194 				    quotatypes[type], "disk quota exceeded");
    195 			return (0);
    196 		}
    197 		if (time.tv_sec > dq->dq_btime) {
    198 			if ((dq->dq_flags & DQ_BLKS) == 0 &&
    199 			    ip->i_uid == cred->cr_uid) {
    200 				uprintf("\n%s: write failed, %s %s\n",
    201 				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    202 				    quotatypes[type],
    203 				    "disk quota exceeded for too long");
    204 				dq->dq_flags |= DQ_BLKS;
    205 			}
    206 			return (EDQUOT);
    207 		}
    208 	}
    209 	return (0);
    210 }
    211 
    212 /*
    213  * Check the inode limit, applying corrective action.
    214  */
    215 int
    216 chkiq(ip, change, cred, flags)
    217 	register struct inode *ip;
    218 	long change;
    219 	struct ucred *cred;
    220 	int flags;
    221 {
    222 	register struct dquot *dq;
    223 	register int i;
    224 	int ncurinodes, error;
    225 
    226 #ifdef DIAGNOSTIC
    227 	if ((flags & CHOWN) == 0)
    228 		chkdquot(ip);
    229 #endif
    230 	if (change == 0)
    231 		return (0);
    232 	if (change < 0) {
    233 		for (i = 0; i < MAXQUOTAS; i++) {
    234 			if ((dq = ip->i_dquot[i]) == NODQUOT)
    235 				continue;
    236 			while (dq->dq_flags & DQ_LOCK) {
    237 				dq->dq_flags |= DQ_WANT;
    238 				sleep((caddr_t)dq, PINOD+1);
    239 			}
    240 			ncurinodes = dq->dq_curinodes + change;
    241 			if (ncurinodes >= 0)
    242 				dq->dq_curinodes = ncurinodes;
    243 			else
    244 				dq->dq_curinodes = 0;
    245 			dq->dq_flags &= ~DQ_INODS;
    246 			dq->dq_flags |= DQ_MOD;
    247 		}
    248 		return (0);
    249 	}
    250 	if ((flags & FORCE) == 0 && cred->cr_uid != 0) {
    251 		for (i = 0; i < MAXQUOTAS; i++) {
    252 			if ((dq = ip->i_dquot[i]) == NODQUOT)
    253 				continue;
    254 			if (error = chkiqchg(ip, change, cred, i))
    255 				return (error);
    256 		}
    257 	}
    258 	for (i = 0; i < MAXQUOTAS; i++) {
    259 		if ((dq = ip->i_dquot[i]) == NODQUOT)
    260 			continue;
    261 		while (dq->dq_flags & DQ_LOCK) {
    262 			dq->dq_flags |= DQ_WANT;
    263 			sleep((caddr_t)dq, PINOD+1);
    264 		}
    265 		dq->dq_curinodes += change;
    266 		dq->dq_flags |= DQ_MOD;
    267 	}
    268 	return (0);
    269 }
    270 
    271 /*
    272  * Check for a valid change to a users allocation.
    273  * Issue an error message if appropriate.
    274  */
    275 int
    276 chkiqchg(ip, change, cred, type)
    277 	struct inode *ip;
    278 	long change;
    279 	struct ucred *cred;
    280 	int type;
    281 {
    282 	register struct dquot *dq = ip->i_dquot[type];
    283 	long ncurinodes = dq->dq_curinodes + change;
    284 
    285 	/*
    286 	 * If user would exceed their hard limit, disallow inode allocation.
    287 	 */
    288 	if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
    289 		if ((dq->dq_flags & DQ_INODS) == 0 &&
    290 		    ip->i_uid == cred->cr_uid) {
    291 			uprintf("\n%s: write failed, %s inode limit reached\n",
    292 			    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    293 			    quotatypes[type]);
    294 			dq->dq_flags |= DQ_INODS;
    295 		}
    296 		return (EDQUOT);
    297 	}
    298 	/*
    299 	 * If user is over their soft limit for too long, disallow inode
    300 	 * allocation. Reset time limit as they cross their soft limit.
    301 	 */
    302 	if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
    303 		if (dq->dq_curinodes < dq->dq_isoftlimit) {
    304 			dq->dq_itime = time.tv_sec +
    305 			    VFSTOUFS(ITOV(ip)->v_mount)->um_itime[type];
    306 			if (ip->i_uid == cred->cr_uid)
    307 				uprintf("\n%s: warning, %s %s\n",
    308 				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    309 				    quotatypes[type], "inode quota exceeded");
    310 			return (0);
    311 		}
    312 		if (time.tv_sec > dq->dq_itime) {
    313 			if ((dq->dq_flags & DQ_INODS) == 0 &&
    314 			    ip->i_uid == cred->cr_uid) {
    315 				uprintf("\n%s: write failed, %s %s\n",
    316 				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    317 				    quotatypes[type],
    318 				    "inode quota exceeded for too long");
    319 				dq->dq_flags |= DQ_INODS;
    320 			}
    321 			return (EDQUOT);
    322 		}
    323 	}
    324 	return (0);
    325 }
    326 
    327 #ifdef DIAGNOSTIC
    328 /*
    329  * On filesystems with quotas enabled, it is an error for a file to change
    330  * size and not to have a dquot structure associated with it.
    331  */
    332 void
    333 chkdquot(ip)
    334 	register struct inode *ip;
    335 {
    336 	struct ufsmount *ump = VFSTOUFS(ITOV(ip)->v_mount);
    337 	register int i;
    338 
    339 	for (i = 0; i < MAXQUOTAS; i++) {
    340 		if (ump->um_quotas[i] == NULLVP ||
    341 		    (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
    342 			continue;
    343 		if (ip->i_dquot[i] == NODQUOT) {
    344 			vprint("chkdquot: missing dquot", ITOV(ip));
    345 			panic("missing dquot");
    346 		}
    347 	}
    348 }
    349 #endif
    350 
    351 /*
    352  * Code to process quotactl commands.
    353  */
    354 
    355 /*
    356  * Q_QUOTAON - set up a quota file for a particular file system.
    357  */
    358 int
    359 quotaon(p, mp, type, fname)
    360 	struct proc *p;
    361 	struct mount *mp;
    362 	register int type;
    363 	caddr_t fname;
    364 {
    365 	register struct ufsmount *ump = VFSTOUFS(mp);
    366 	register struct vnode *vp, **vpp;
    367 	struct vnode *nextvp;
    368 	struct dquot *dq;
    369 	int error;
    370 	struct nameidata nd;
    371 
    372 	vpp = &ump->um_quotas[type];
    373 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname, p);
    374 	if (error = vn_open(&nd, FREAD|FWRITE, 0))
    375 		return (error);
    376 	vp = nd.ni_vp;
    377 	VOP_UNLOCK(vp);
    378 	if (vp->v_type != VREG) {
    379 		(void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
    380 		return (EACCES);
    381 	}
    382 	if (vfs_busy(mp)) {
    383 		(void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
    384 		return (EBUSY);
    385 	}
    386 	if (*vpp != vp)
    387 		quotaoff(p, mp, type);
    388 	ump->um_qflags[type] |= QTF_OPENING;
    389 	mp->mnt_flag |= MNT_QUOTA;
    390 	vp->v_flag |= VSYSTEM;
    391 	*vpp = vp;
    392 	/*
    393 	 * Save the credential of the process that turned on quotas.
    394 	 * Set up the time limits for this quota.
    395 	 */
    396 	crhold(p->p_ucred);
    397 	ump->um_cred[type] = p->p_ucred;
    398 	ump->um_btime[type] = MAX_DQ_TIME;
    399 	ump->um_itime[type] = MAX_IQ_TIME;
    400 	if (dqget(NULLVP, 0, ump, type, &dq) == 0) {
    401 		if (dq->dq_btime > 0)
    402 			ump->um_btime[type] = dq->dq_btime;
    403 		if (dq->dq_itime > 0)
    404 			ump->um_itime[type] = dq->dq_itime;
    405 		dqrele(NULLVP, dq);
    406 	}
    407 	/*
    408 	 * Search vnodes associated with this mount point,
    409 	 * adding references to quota file being opened.
    410 	 * NB: only need to add dquot's for inodes being modified.
    411 	 */
    412 again:
    413 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) {
    414 		nextvp = vp->v_mntvnodes.le_next;
    415 		if (vp->v_writecount == 0)
    416 			continue;
    417 		if (vget(vp, 1))
    418 			goto again;
    419 		if (error = getinoquota(VTOI(vp))) {
    420 			vput(vp);
    421 			break;
    422 		}
    423 		vput(vp);
    424 		if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp)
    425 			goto again;
    426 	}
    427 	ump->um_qflags[type] &= ~QTF_OPENING;
    428 	if (error)
    429 		quotaoff(p, mp, type);
    430 	vfs_unbusy(mp);
    431 	return (error);
    432 }
    433 
    434 /*
    435  * Q_QUOTAOFF - turn off disk quotas for a filesystem.
    436  */
    437 int
    438 quotaoff(p, mp, type)
    439 	struct proc *p;
    440 	struct mount *mp;
    441 	register int type;
    442 {
    443 	register struct vnode *vp;
    444 	struct vnode *qvp, *nextvp;
    445 	struct ufsmount *ump = VFSTOUFS(mp);
    446 	register struct dquot *dq;
    447 	register struct inode *ip;
    448 	int error;
    449 
    450 	if ((mp->mnt_flag & MNT_MPBUSY) == 0)
    451 		panic("quotaoff: not busy");
    452 	if ((qvp = ump->um_quotas[type]) == NULLVP)
    453 		return (0);
    454 	ump->um_qflags[type] |= QTF_CLOSING;
    455 	/*
    456 	 * Search vnodes associated with this mount point,
    457 	 * deleting any references to quota file being closed.
    458 	 */
    459 again:
    460 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) {
    461 		nextvp = vp->v_mntvnodes.le_next;
    462 		if (vget(vp, 1))
    463 			goto again;
    464 		ip = VTOI(vp);
    465 		dq = ip->i_dquot[type];
    466 		ip->i_dquot[type] = NODQUOT;
    467 		dqrele(vp, dq);
    468 		vput(vp);
    469 		if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp)
    470 			goto again;
    471 	}
    472 	dqflush(qvp);
    473 	qvp->v_flag &= ~VSYSTEM;
    474 	error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p);
    475 	ump->um_quotas[type] = NULLVP;
    476 	crfree(ump->um_cred[type]);
    477 	ump->um_cred[type] = NOCRED;
    478 	ump->um_qflags[type] &= ~QTF_CLOSING;
    479 	for (type = 0; type < MAXQUOTAS; type++)
    480 		if (ump->um_quotas[type] != NULLVP)
    481 			break;
    482 	if (type == MAXQUOTAS)
    483 		mp->mnt_flag &= ~MNT_QUOTA;
    484 	return (error);
    485 }
    486 
    487 /*
    488  * Q_GETQUOTA - return current values in a dqblk structure.
    489  */
    490 int
    491 getquota(mp, id, type, addr)
    492 	struct mount *mp;
    493 	u_long id;
    494 	int type;
    495 	caddr_t addr;
    496 {
    497 	struct dquot *dq;
    498 	int error;
    499 
    500 	if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq))
    501 		return (error);
    502 	error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk));
    503 	dqrele(NULLVP, dq);
    504 	return (error);
    505 }
    506 
    507 /*
    508  * Q_SETQUOTA - assign an entire dqblk structure.
    509  */
    510 int
    511 setquota(mp, id, type, addr)
    512 	struct mount *mp;
    513 	u_long id;
    514 	int type;
    515 	caddr_t addr;
    516 {
    517 	register struct dquot *dq;
    518 	struct dquot *ndq;
    519 	struct ufsmount *ump = VFSTOUFS(mp);
    520 	struct dqblk newlim;
    521 	int error;
    522 
    523 	if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)))
    524 		return (error);
    525 	if (error = dqget(NULLVP, id, ump, type, &ndq))
    526 		return (error);
    527 	dq = ndq;
    528 	while (dq->dq_flags & DQ_LOCK) {
    529 		dq->dq_flags |= DQ_WANT;
    530 		sleep((caddr_t)dq, PINOD+1);
    531 	}
    532 	/*
    533 	 * Copy all but the current values.
    534 	 * Reset time limit if previously had no soft limit or were
    535 	 * under it, but now have a soft limit and are over it.
    536 	 */
    537 	newlim.dqb_curblocks = dq->dq_curblocks;
    538 	newlim.dqb_curinodes = dq->dq_curinodes;
    539 	if (dq->dq_id != 0) {
    540 		newlim.dqb_btime = dq->dq_btime;
    541 		newlim.dqb_itime = dq->dq_itime;
    542 	}
    543 	if (newlim.dqb_bsoftlimit &&
    544 	    dq->dq_curblocks >= newlim.dqb_bsoftlimit &&
    545 	    (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
    546 		newlim.dqb_btime = time.tv_sec + ump->um_btime[type];
    547 	if (newlim.dqb_isoftlimit &&
    548 	    dq->dq_curinodes >= newlim.dqb_isoftlimit &&
    549 	    (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
    550 		newlim.dqb_itime = time.tv_sec + ump->um_itime[type];
    551 	dq->dq_dqb = newlim;
    552 	if (dq->dq_curblocks < dq->dq_bsoftlimit)
    553 		dq->dq_flags &= ~DQ_BLKS;
    554 	if (dq->dq_curinodes < dq->dq_isoftlimit)
    555 		dq->dq_flags &= ~DQ_INODS;
    556 	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
    557 	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
    558 		dq->dq_flags |= DQ_FAKE;
    559 	else
    560 		dq->dq_flags &= ~DQ_FAKE;
    561 	dq->dq_flags |= DQ_MOD;
    562 	dqrele(NULLVP, dq);
    563 	return (0);
    564 }
    565 
    566 /*
    567  * Q_SETUSE - set current inode and block usage.
    568  */
    569 int
    570 setuse(mp, id, type, addr)
    571 	struct mount *mp;
    572 	u_long id;
    573 	int type;
    574 	caddr_t addr;
    575 {
    576 	register struct dquot *dq;
    577 	struct ufsmount *ump = VFSTOUFS(mp);
    578 	struct dquot *ndq;
    579 	struct dqblk usage;
    580 	int error;
    581 
    582 	if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk)))
    583 		return (error);
    584 	if (error = dqget(NULLVP, id, ump, type, &ndq))
    585 		return (error);
    586 	dq = ndq;
    587 	while (dq->dq_flags & DQ_LOCK) {
    588 		dq->dq_flags |= DQ_WANT;
    589 		sleep((caddr_t)dq, PINOD+1);
    590 	}
    591 	/*
    592 	 * Reset time limit if have a soft limit and were
    593 	 * previously under it, but are now over it.
    594 	 */
    595 	if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
    596 	    usage.dqb_curblocks >= dq->dq_bsoftlimit)
    597 		dq->dq_btime = time.tv_sec + ump->um_btime[type];
    598 	if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
    599 	    usage.dqb_curinodes >= dq->dq_isoftlimit)
    600 		dq->dq_itime = time.tv_sec + ump->um_itime[type];
    601 	dq->dq_curblocks = usage.dqb_curblocks;
    602 	dq->dq_curinodes = usage.dqb_curinodes;
    603 	if (dq->dq_curblocks < dq->dq_bsoftlimit)
    604 		dq->dq_flags &= ~DQ_BLKS;
    605 	if (dq->dq_curinodes < dq->dq_isoftlimit)
    606 		dq->dq_flags &= ~DQ_INODS;
    607 	dq->dq_flags |= DQ_MOD;
    608 	dqrele(NULLVP, dq);
    609 	return (0);
    610 }
    611 
    612 /*
    613  * Q_SYNC - sync quota files to disk.
    614  */
    615 int
    616 qsync(mp)
    617 	struct mount *mp;
    618 {
    619 	struct ufsmount *ump = VFSTOUFS(mp);
    620 	register struct vnode *vp, *nextvp;
    621 	register struct dquot *dq;
    622 	register int i;
    623 
    624 	/*
    625 	 * Check if the mount point has any quotas.
    626 	 * If not, simply return.
    627 	 */
    628 	if ((mp->mnt_flag & MNT_MPBUSY) == 0)
    629 		panic("qsync: not busy");
    630 	for (i = 0; i < MAXQUOTAS; i++)
    631 		if (ump->um_quotas[i] != NULLVP)
    632 			break;
    633 	if (i == MAXQUOTAS)
    634 		return (0);
    635 	/*
    636 	 * Search vnodes associated with this mount point,
    637 	 * synchronizing any modified dquot structures.
    638 	 */
    639 again:
    640 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) {
    641 		nextvp = vp->v_mntvnodes.le_next;
    642 		if (VOP_ISLOCKED(vp))
    643 			continue;
    644 		if (vget(vp, 1))
    645 			goto again;
    646 		for (i = 0; i < MAXQUOTAS; i++) {
    647 			dq = VTOI(vp)->i_dquot[i];
    648 			if (dq != NODQUOT && (dq->dq_flags & DQ_MOD))
    649 				dqsync(vp, dq);
    650 		}
    651 		vput(vp);
    652 		if (vp->v_mntvnodes.le_next != nextvp || vp->v_mount != mp)
    653 			goto again;
    654 	}
    655 	return (0);
    656 }
    657 
    658 /*
    659  * Code pertaining to management of the in-core dquot data structures.
    660  */
    661 struct dquot **dqhashtbl;
    662 u_long dqhash;
    663 
    664 /*
    665  * Dquot free list.
    666  */
    667 #define	DQUOTINC	5	/* minimum free dquots desired */
    668 struct dquot *dqfreel, **dqback = &dqfreel;
    669 long numdquot, desireddquot = DQUOTINC;
    670 
    671 /*
    672  * Initialize the quota system.
    673  */
    674 void
    675 dqinit()
    676 {
    677 
    678 	dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash);
    679 }
    680 
    681 /*
    682  * Obtain a dquot structure for the specified identifier and quota file
    683  * reading the information from the file if necessary.
    684  */
    685 int
    686 dqget(vp, id, ump, type, dqp)
    687 	struct vnode *vp;
    688 	u_long id;
    689 	register struct ufsmount *ump;
    690 	register int type;
    691 	struct dquot **dqp;
    692 {
    693 	register struct dquot *dq, *dp, **dpp;
    694 	register struct vnode *dqvp;
    695 	struct iovec aiov;
    696 	struct uio auio;
    697 	int error;
    698 
    699 	dqvp = ump->um_quotas[type];
    700 	if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
    701 		*dqp = NODQUOT;
    702 		return (EINVAL);
    703 	}
    704 	/*
    705 	 * Check the cache first.
    706 	 */
    707 	dpp = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash];
    708 	for (dq = *dpp; dq; dq = dq->dq_forw) {
    709 		if (dq->dq_id != id ||
    710 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    711 			continue;
    712 		/*
    713 		 * Cache hit with no references.  Take
    714 		 * the structure off the free list.
    715 		 */
    716 		if (dq->dq_cnt == 0) {
    717 			if ((dp = dq->dq_freef) != NODQUOT)
    718 				dp->dq_freeb = dq->dq_freeb;
    719 			else
    720 				dqback = dq->dq_freeb;
    721 			*dq->dq_freeb = dp;
    722 		}
    723 		DQREF(dq);
    724 		*dqp = dq;
    725 		return (0);
    726 	}
    727 	/*
    728 	 * Not in cache, allocate a new one.
    729 	 */
    730 	if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes)
    731 		desireddquot += DQUOTINC;
    732 	if (numdquot < desireddquot) {
    733 		dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK);
    734 		bzero((char *)dq, sizeof *dq);
    735 		numdquot++;
    736 	} else {
    737 		if ((dq = dqfreel) == NULL) {
    738 			tablefull("dquot");
    739 			*dqp = NODQUOT;
    740 			return (EUSERS);
    741 		}
    742 		if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
    743 			panic("free dquot isn't");
    744 		if ((dp = dq->dq_freef) != NODQUOT)
    745 			dp->dq_freeb = &dqfreel;
    746 		else
    747 			dqback = &dqfreel;
    748 		dqfreel = dp;
    749 		dq->dq_freef = NULL;
    750 		dq->dq_freeb = NULL;
    751 		if (dp = dq->dq_forw)
    752 			dp->dq_back = dq->dq_back;
    753 		*dq->dq_back = dp;
    754 	}
    755 	/*
    756 	 * Initialize the contents of the dquot structure.
    757 	 */
    758 	if (vp != dqvp)
    759 		VOP_LOCK(dqvp);
    760 	if (dp = *dpp)
    761 		dp->dq_back = &dq->dq_forw;
    762 	dq->dq_forw = dp;
    763 	dq->dq_back = dpp;
    764 	*dpp = dq;
    765 	DQREF(dq);
    766 	dq->dq_flags = DQ_LOCK;
    767 	dq->dq_id = id;
    768 	dq->dq_ump = ump;
    769 	dq->dq_type = type;
    770 	auio.uio_iov = &aiov;
    771 	auio.uio_iovcnt = 1;
    772 	aiov.iov_base = (caddr_t)&dq->dq_dqb;
    773 	aiov.iov_len = sizeof (struct dqblk);
    774 	auio.uio_resid = sizeof (struct dqblk);
    775 	auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
    776 	auio.uio_segflg = UIO_SYSSPACE;
    777 	auio.uio_rw = UIO_READ;
    778 	auio.uio_procp = (struct proc *)0;
    779 	error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
    780 	if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
    781 		bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk));
    782 	if (vp != dqvp)
    783 		VOP_UNLOCK(dqvp);
    784 	if (dq->dq_flags & DQ_WANT)
    785 		wakeup((caddr_t)dq);
    786 	dq->dq_flags = 0;
    787 	/*
    788 	 * I/O error in reading quota file, release
    789 	 * quota structure and reflect problem to caller.
    790 	 */
    791 	if (error) {
    792 		if (dp = dq->dq_forw)
    793 			dp->dq_back = dq->dq_back;
    794 		*dq->dq_back = dp;
    795 		dq->dq_forw = NULL;
    796 		dq->dq_back = NULL;
    797 		dqrele(vp, dq);
    798 		*dqp = NODQUOT;
    799 		return (error);
    800 	}
    801 	/*
    802 	 * Check for no limit to enforce.
    803 	 * Initialize time values if necessary.
    804 	 */
    805 	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
    806 	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
    807 		dq->dq_flags |= DQ_FAKE;
    808 	if (dq->dq_id != 0) {
    809 		if (dq->dq_btime == 0)
    810 			dq->dq_btime = time.tv_sec + ump->um_btime[type];
    811 		if (dq->dq_itime == 0)
    812 			dq->dq_itime = time.tv_sec + ump->um_itime[type];
    813 	}
    814 	*dqp = dq;
    815 	return (0);
    816 }
    817 
    818 /*
    819  * Obtain a reference to a dquot.
    820  */
    821 void
    822 dqref(dq)
    823 	struct dquot *dq;
    824 {
    825 
    826 	dq->dq_cnt++;
    827 }
    828 
    829 /*
    830  * Release a reference to a dquot.
    831  */
    832 void
    833 dqrele(vp, dq)
    834 	struct vnode *vp;
    835 	register struct dquot *dq;
    836 {
    837 
    838 	if (dq == NODQUOT)
    839 		return;
    840 	if (dq->dq_cnt > 1) {
    841 		dq->dq_cnt--;
    842 		return;
    843 	}
    844 	if (dq->dq_flags & DQ_MOD)
    845 		(void) dqsync(vp, dq);
    846 	if (--dq->dq_cnt > 0)
    847 		return;
    848 	if (dqfreel != NODQUOT) {
    849 		*dqback = dq;
    850 		dq->dq_freeb = dqback;
    851 	} else {
    852 		dqfreel = dq;
    853 		dq->dq_freeb = &dqfreel;
    854 	}
    855 	dq->dq_freef = NODQUOT;
    856 	dqback = &dq->dq_freef;
    857 }
    858 
    859 /*
    860  * Update the disk quota in the quota file.
    861  */
    862 int
    863 dqsync(vp, dq)
    864 	struct vnode *vp;
    865 	register struct dquot *dq;
    866 {
    867 	struct vnode *dqvp;
    868 	struct iovec aiov;
    869 	struct uio auio;
    870 	int error;
    871 
    872 	if (dq == NODQUOT)
    873 		panic("dqsync: dquot");
    874 	if ((dq->dq_flags & DQ_MOD) == 0)
    875 		return (0);
    876 	if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
    877 		panic("dqsync: file");
    878 	if (vp != dqvp)
    879 		VOP_LOCK(dqvp);
    880 	while (dq->dq_flags & DQ_LOCK) {
    881 		dq->dq_flags |= DQ_WANT;
    882 		sleep((caddr_t)dq, PINOD+2);
    883 		if ((dq->dq_flags & DQ_MOD) == 0) {
    884 			if (vp != dqvp)
    885 				VOP_UNLOCK(dqvp);
    886 			return (0);
    887 		}
    888 	}
    889 	dq->dq_flags |= DQ_LOCK;
    890 	auio.uio_iov = &aiov;
    891 	auio.uio_iovcnt = 1;
    892 	aiov.iov_base = (caddr_t)&dq->dq_dqb;
    893 	aiov.iov_len = sizeof (struct dqblk);
    894 	auio.uio_resid = sizeof (struct dqblk);
    895 	auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
    896 	auio.uio_segflg = UIO_SYSSPACE;
    897 	auio.uio_rw = UIO_WRITE;
    898 	auio.uio_procp = (struct proc *)0;
    899 	error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
    900 	if (auio.uio_resid && error == 0)
    901 		error = EIO;
    902 	if (dq->dq_flags & DQ_WANT)
    903 		wakeup((caddr_t)dq);
    904 	dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT);
    905 	if (vp != dqvp)
    906 		VOP_UNLOCK(dqvp);
    907 	return (error);
    908 }
    909 
    910 /*
    911  * Flush all entries from the cache for a particular vnode.
    912  */
    913 void
    914 dqflush(vp)
    915 	register struct vnode *vp;
    916 {
    917 	register struct dquot *dq, *dp, **dpp, *nextdq;
    918 
    919 	/*
    920 	 * Move all dquot's that used to refer to this quota
    921 	 * file off their hash chains (they will eventually
    922 	 * fall off the head of the free list and be re-used).
    923 	 */
    924 	for (dpp = &dqhashtbl[dqhash]; dpp >= dqhashtbl; dpp--) {
    925 		for (dq = *dpp; dq; dq = nextdq) {
    926 			nextdq = dq->dq_forw;
    927 			if (dq->dq_ump->um_quotas[dq->dq_type] != vp)
    928 				continue;
    929 			if (dq->dq_cnt)
    930 				panic("dqflush: stray dquot");
    931 			if (dp = dq->dq_forw)
    932 				dp->dq_back = dq->dq_back;
    933 			*dq->dq_back = dp;
    934 			dq->dq_forw = NULL;
    935 			dq->dq_back = NULL;
    936 			dq->dq_ump = (struct ufsmount *)0;
    937 		}
    938 	}
    939 }
    940