Home | History | Annotate | Line # | Download | only in ufs
ufs_quota.c revision 1.84
      1 /*	$NetBSD: ufs_quota.c,v 1.84 2012/01/29 06:48:50 dholland Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1990, 1993, 1995
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Robert Elz at The University of Melbourne.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  *
     34  *	@(#)ufs_quota.c	8.5 (Berkeley) 5/20/95
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.84 2012/01/29 06:48:50 dholland Exp $");
     39 
     40 #if defined(_KERNEL_OPT)
     41 #include "opt_quota.h"
     42 #endif
     43 #include <sys/param.h>
     44 #include <sys/kernel.h>
     45 #include <sys/systm.h>
     46 #include <sys/namei.h>
     47 #include <sys/file.h>
     48 #include <sys/proc.h>
     49 #include <sys/vnode.h>
     50 #include <sys/mount.h>
     51 #include <sys/kauth.h>
     52 
     53 #include <sys/quotactl.h>
     54 #include <ufs/ufs/quota.h>
     55 #include <ufs/ufs/inode.h>
     56 #include <ufs/ufs/ufsmount.h>
     57 #include <ufs/ufs/ufs_extern.h>
     58 #include <ufs/ufs/ufs_quota.h>
     59 #include <quota/quotaprop.h>
     60 
     61 kmutex_t dqlock;
     62 kcondvar_t dqcv;
     63 
     64 /*
     65  * Code pertaining to management of the in-core dquot data structures.
     66  */
     67 #define DQHASH(dqvp, id) \
     68 	(((((long)(dqvp)) >> 8) + id) & dqhash)
     69 static LIST_HEAD(dqhashhead, dquot) *dqhashtbl;
     70 static u_long dqhash;
     71 static pool_cache_t dquot_cache;
     72 
     73 
     74 static int quota_handle_cmd_get_version(struct mount *, struct lwp *,
     75     struct vfs_quotactl_args *args);
     76 static int quota_handle_cmd_get(struct mount *, struct lwp *,
     77     struct vfs_quotactl_args *args);
     78 static int quota_handle_cmd_set(struct mount *, struct lwp *,
     79     struct vfs_quotactl_args *args);
     80 static int quota_handle_cmd_getall(struct mount *, struct lwp *,
     81     struct vfs_quotactl_args *args);
     82 static int quota_handle_cmd_clear(struct mount *, struct lwp *,
     83     struct vfs_quotactl_args *args);
     84 static int quota_handle_cmd_quotaon(struct mount *, struct lwp *,
     85     struct vfs_quotactl_args *args);
     86 static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *,
     87     struct vfs_quotactl_args *args);
     88 
     89 /*
     90  * Initialize the quota fields of an inode.
     91  */
     92 void
     93 ufsquota_init(struct inode *ip)
     94 {
     95 	int i;
     96 
     97 	for (i = 0; i < MAXQUOTAS; i++)
     98 		ip->i_dquot[i] = NODQUOT;
     99 }
    100 
    101 /*
    102  * Release the quota fields from an inode.
    103  */
    104 void
    105 ufsquota_free(struct inode *ip)
    106 {
    107 	int i;
    108 
    109 	for (i = 0; i < MAXQUOTAS; i++) {
    110 		dqrele(ITOV(ip), ip->i_dquot[i]);
    111 		ip->i_dquot[i] = NODQUOT;
    112 	}
    113 }
    114 
    115 /*
    116  * Update disk usage, and take corrective action.
    117  */
    118 int
    119 chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
    120 {
    121 	/* do not track snapshot usage, or we will deadlock */
    122 	if ((ip->i_flags & SF_SNAPSHOT) != 0)
    123 		return 0;
    124 
    125 #ifdef QUOTA
    126 	if (ip->i_ump->um_flags & UFS_QUOTA)
    127 		return chkdq1(ip, change, cred, flags);
    128 #endif
    129 #ifdef QUOTA2
    130 	if (ip->i_ump->um_flags & UFS_QUOTA2)
    131 		return chkdq2(ip, change, cred, flags);
    132 #endif
    133 	return 0;
    134 }
    135 
    136 /*
    137  * Check the inode limit, applying corrective action.
    138  */
    139 int
    140 chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
    141 {
    142 	/* do not track snapshot usage, or we will deadlock */
    143 	if ((ip->i_flags & SF_SNAPSHOT) != 0)
    144 		return 0;
    145 #ifdef QUOTA
    146 	if (ip->i_ump->um_flags & UFS_QUOTA)
    147 		return chkiq1(ip, change, cred, flags);
    148 #endif
    149 #ifdef QUOTA2
    150 	if (ip->i_ump->um_flags & UFS_QUOTA2)
    151 		return chkiq2(ip, change, cred, flags);
    152 #endif
    153 	return 0;
    154 }
    155 
    156 int
    157 quota_handle_cmd(struct mount *mp, struct lwp *l, int op,
    158 		 struct vfs_quotactl_args *args)
    159 {
    160 	int error = 0;
    161 
    162 	switch (op) {
    163 	    case QUOTACTL_GETVERSION:
    164 		error = quota_handle_cmd_get_version(mp, l, args);
    165 		break;
    166 	    case QUOTACTL_QUOTAON:
    167 		error = quota_handle_cmd_quotaon(mp, l, args);
    168 		break;
    169 	    case QUOTACTL_QUOTAOFF:
    170 		error = quota_handle_cmd_quotaoff(mp, l, args);
    171 		break;
    172 	    case QUOTACTL_GET:
    173 		error = quota_handle_cmd_get(mp, l, args);
    174 		break;
    175 	    case QUOTACTL_SET:
    176 		error = quota_handle_cmd_set(mp, l, args);
    177 		break;
    178 	    case QUOTACTL_GETALL:
    179 		error = quota_handle_cmd_getall(mp, l, args);
    180 		break;
    181 	    case QUOTACTL_CLEAR:
    182 		error = quota_handle_cmd_clear(mp, l, args);
    183 		break;
    184 	    default:
    185 		panic("Invalid quotactl operation %d\n", op);
    186 	}
    187 
    188 	return error;
    189 }
    190 
    191 static int
    192 quota_handle_cmd_get_version(struct mount *mp, struct lwp *l,
    193     struct vfs_quotactl_args *args)
    194 {
    195 	struct ufsmount *ump = VFSTOUFS(mp);
    196 	int *version_ret;
    197 
    198 	KASSERT(args->qc_type == QCT_GETVERSION);
    199 	version_ret = args->u.getversion.qc_version_ret;
    200 
    201 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    202 		return EOPNOTSUPP;
    203 
    204 #ifdef QUOTA
    205 	if (ump->um_flags & UFS_QUOTA) {
    206 		*version_ret = 1;
    207 	} else
    208 #endif
    209 #ifdef QUOTA2
    210 	if (ump->um_flags & UFS_QUOTA2) {
    211 		*version_ret = 2;
    212 	} else
    213 #endif
    214 		return EOPNOTSUPP;
    215 
    216 	return 0;
    217 }
    218 
    219 /* XXX shouldn't all this be in kauth ? */
    220 static int
    221 quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {
    222 	/* The user can always query about his own quota. */
    223 	if (id == kauth_cred_getuid(l->l_cred))
    224 		return 0;
    225 	return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    226 	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL);
    227 }
    228 
    229 static int
    230 quota_handle_cmd_get(struct mount *mp, struct lwp *l,
    231     struct vfs_quotactl_args *args)
    232 {
    233 	struct ufsmount *ump = VFSTOUFS(mp);
    234 	int error;
    235 	const struct quotakey *qk;
    236 	struct quotaval *ret;
    237 
    238 	KASSERT(args->qc_type == QCT_GET);
    239 	qk = args->u.get.qc_key;
    240 	ret = args->u.get.qc_ret;
    241 
    242 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    243 		return EOPNOTSUPP;
    244 
    245 	error = quota_get_auth(mp, l, qk->qk_id);
    246 	if (error != 0)
    247 		return error;
    248 #ifdef QUOTA
    249 	if (ump->um_flags & UFS_QUOTA) {
    250 		error = quota1_handle_cmd_get(ump, qk, ret);
    251 	} else
    252 #endif
    253 #ifdef QUOTA2
    254 	if (ump->um_flags & UFS_QUOTA2) {
    255 		error = quota2_handle_cmd_get(ump, qk, ret);
    256 	} else
    257 #endif
    258 		panic("quota_handle_cmd_get: no support ?");
    259 
    260 	if (error != 0)
    261 		return error;
    262 
    263 	return error;
    264 }
    265 
    266 static int
    267 quota_handle_cmd_set(struct mount *mp, struct lwp *l,
    268     struct vfs_quotactl_args *args)
    269 {
    270 	struct ufsmount *ump = VFSTOUFS(mp);
    271 	const struct quotakey *qk;
    272 	const struct quotaval *qv;
    273 	id_t kauth_id;
    274 	int error;
    275 
    276 	KASSERT(args->qc_type == QCT_SET);
    277 	qk = args->u.set.qc_key;
    278 	qv = args->u.set.qc_val;
    279 
    280 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    281 		return EOPNOTSUPP;
    282 
    283 	kauth_id = qk->qk_id;
    284 	if (kauth_id == QUOTA_DEFAULTID) {
    285 		kauth_id = 0;
    286 	}
    287 
    288 	/* avoid whitespace changes */
    289 	{
    290 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    291 		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
    292 		    NULL);
    293 		if (error != 0)
    294 			goto err;
    295 #ifdef QUOTA
    296 		if (ump->um_flags & UFS_QUOTA)
    297 			error = quota1_handle_cmd_set(ump, qk, qv);
    298 		else
    299 #endif
    300 #ifdef QUOTA2
    301 		if (ump->um_flags & UFS_QUOTA2) {
    302 			error = quota2_handle_cmd_set(ump, qk, qv);
    303 		} else
    304 #endif
    305 			panic("quota_handle_cmd_get: no support ?");
    306 
    307 		if (error && error != ENOENT)
    308 			goto err;
    309 	}
    310 
    311 	return 0;
    312  err:
    313 	return error;
    314 }
    315 
    316 static int
    317 quota_handle_cmd_clear(struct mount *mp, struct lwp *l,
    318     struct vfs_quotactl_args *args)
    319 {
    320 	prop_array_t replies;
    321 	prop_object_iterator_t iter;
    322 	prop_dictionary_t data;
    323 	uint32_t id;
    324 	struct ufsmount *ump = VFSTOUFS(mp);
    325 	int error, defaultq = 0;
    326 	const char *idstr;
    327 	prop_dictionary_t cmddict;
    328 	int q2type;
    329 	prop_array_t datas;
    330 
    331 	KASSERT(args->qc_type == QCT_PROPLIB);
    332 	cmddict = args->u.proplib.qc_cmddict;
    333 	q2type = args->u.proplib.qc_q2type;
    334 	datas = args->u.proplib.qc_datas;
    335 
    336 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    337 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    338 
    339 	if ((ump->um_flags & UFS_QUOTA2) == 0)
    340 		return EOPNOTSUPP;
    341 
    342 	replies = prop_array_create();
    343 	if (replies == NULL)
    344 		return ENOMEM;
    345 
    346 	iter = prop_array_iterator(datas);
    347 	if (iter == NULL) {
    348 		prop_object_release(replies);
    349 		return ENOMEM;
    350 	}
    351 	while ((data = prop_object_iterator_next(iter)) != NULL) {
    352 		if (!prop_dictionary_get_uint32(data, "id", &id)) {
    353 			if (!prop_dictionary_get_cstring_nocopy(data, "id",
    354 			    &idstr))
    355 				continue;
    356 			if (strcmp(idstr, "default"))
    357 				continue;
    358 			id = 0;
    359 			defaultq = 1;
    360 		} else {
    361 			defaultq = 0;
    362 		}
    363 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    364 		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL);
    365 		if (error != 0)
    366 			goto err;
    367 #ifdef QUOTA2
    368 		if (ump->um_flags & UFS_QUOTA2) {
    369 			error = quota2_handle_cmd_clear(ump, q2type, id, defaultq,
    370 			    data);
    371 		} else
    372 #endif
    373 			panic("quota_handle_cmd_get: no support ?");
    374 
    375 		if (error && error != ENOENT)
    376 			goto err;
    377 	}
    378 	prop_object_iterator_release(iter);
    379 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    380 		error = ENOMEM;
    381 	} else {
    382 		error = 0;
    383 	}
    384 	return error;
    385 err:
    386 	prop_object_iterator_release(iter);
    387 	prop_object_release(replies);
    388 	return error;
    389 }
    390 
    391 static int
    392 quota_handle_cmd_getall(struct mount *mp, struct lwp *l,
    393     struct vfs_quotactl_args *args)
    394 {
    395 	prop_array_t replies;
    396 	struct ufsmount *ump = VFSTOUFS(mp);
    397 	int error;
    398 	prop_dictionary_t cmddict;
    399 	int q2type;
    400 	prop_array_t datas;
    401 
    402 	KASSERT(args->qc_type == QCT_PROPLIB);
    403 	cmddict = args->u.proplib.qc_cmddict;
    404 	q2type = args->u.proplib.qc_q2type;
    405 	datas = args->u.proplib.qc_datas;
    406 
    407 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    408 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    409 
    410 	if ((ump->um_flags & UFS_QUOTA2) == 0)
    411 		return EOPNOTSUPP;
    412 
    413 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    414 	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
    415 	if (error)
    416 		return error;
    417 
    418 	replies = prop_array_create();
    419 	if (replies == NULL)
    420 		return ENOMEM;
    421 
    422 #ifdef QUOTA2
    423 	if (ump->um_flags & UFS_QUOTA2) {
    424 		error = quota2_handle_cmd_getall(ump, q2type, replies);
    425 	} else
    426 #endif
    427 		panic("quota_handle_cmd_getall: no support ?");
    428 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    429 		error = ENOMEM;
    430 	} else {
    431 		error = 0;
    432 	}
    433 	return error;
    434 }
    435 
    436 static int
    437 quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
    438     struct vfs_quotactl_args *args)
    439 {
    440 	prop_dictionary_t data;
    441 	struct ufsmount *ump = VFSTOUFS(mp);
    442 	int error;
    443 	const char *qfile;
    444 	prop_dictionary_t cmddict;
    445 	int q2type;
    446 	prop_array_t datas;
    447 
    448 	KASSERT(args->qc_type == QCT_PROPLIB);
    449 	cmddict = args->u.proplib.qc_cmddict;
    450 	q2type = args->u.proplib.qc_q2type;
    451 	datas = args->u.proplib.qc_datas;
    452 
    453 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    454 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    455 
    456 	if ((ump->um_flags & UFS_QUOTA2) != 0)
    457 		return EBUSY;
    458 
    459 	if (prop_array_count(datas) != 1)
    460 		return EINVAL;
    461 
    462 	data = prop_array_get(datas, 0);
    463 	if (data == NULL)
    464 		return ENOMEM;
    465 	if (!prop_dictionary_get_cstring_nocopy(data, "quotafile",
    466 	    &qfile))
    467 		return EINVAL;
    468 
    469 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    470 	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
    471 	if (error != 0) {
    472 		return error;
    473 	}
    474 #ifdef QUOTA
    475 	error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile);
    476 #else
    477 	error = EOPNOTSUPP;
    478 #endif
    479 
    480 	return error;
    481 }
    482 
    483 static int
    484 quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
    485     struct vfs_quotactl_args *args)
    486 {
    487 	struct ufsmount *ump = VFSTOUFS(mp);
    488 	int error;
    489 	prop_dictionary_t cmddict;
    490 	int q2type;
    491 	prop_array_t datas;
    492 
    493 	KASSERT(args->qc_type == QCT_PROPLIB);
    494 	cmddict = args->u.proplib.qc_cmddict;
    495 	q2type = args->u.proplib.qc_q2type;
    496 	datas = args->u.proplib.qc_datas;
    497 
    498 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    499 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    500 
    501 	if ((ump->um_flags & UFS_QUOTA2) != 0)
    502 		return EOPNOTSUPP;
    503 
    504 	if (prop_array_count(datas) != 0)
    505 		return EINVAL;
    506 
    507 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    508 	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
    509 	if (error != 0) {
    510 		return error;
    511 	}
    512 #ifdef QUOTA
    513 	error = quota1_handle_cmd_quotaoff(l, ump, q2type);
    514 #else
    515 	error = EOPNOTSUPP;
    516 #endif
    517 
    518 	return error;
    519 }
    520 
    521 /*
    522  * Initialize the quota system.
    523  */
    524 void
    525 dqinit(void)
    526 {
    527 
    528 	mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE);
    529 	cv_init(&dqcv, "quota");
    530 	dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
    531 	dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq",
    532 	    NULL, IPL_NONE, NULL, NULL, NULL);
    533 }
    534 
    535 void
    536 dqreinit(void)
    537 {
    538 	struct dquot *dq;
    539 	struct dqhashhead *oldhash, *hash;
    540 	struct vnode *dqvp;
    541 	u_long oldmask, mask, hashval;
    542 	int i;
    543 
    544 	hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
    545 	mutex_enter(&dqlock);
    546 	oldhash = dqhashtbl;
    547 	oldmask = dqhash;
    548 	dqhashtbl = hash;
    549 	dqhash = mask;
    550 	for (i = 0; i <= oldmask; i++) {
    551 		while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
    552 			dqvp = dq->dq_ump->um_quotas[dq->dq_type];
    553 			LIST_REMOVE(dq, dq_hash);
    554 			hashval = DQHASH(dqvp, dq->dq_id);
    555 			LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
    556 		}
    557 	}
    558 	mutex_exit(&dqlock);
    559 	hashdone(oldhash, HASH_LIST, oldmask);
    560 }
    561 
    562 /*
    563  * Free resources held by quota system.
    564  */
    565 void
    566 dqdone(void)
    567 {
    568 
    569 	pool_cache_destroy(dquot_cache);
    570 	hashdone(dqhashtbl, HASH_LIST, dqhash);
    571 	cv_destroy(&dqcv);
    572 	mutex_destroy(&dqlock);
    573 }
    574 
    575 /*
    576  * Set up the quotas for an inode.
    577  *
    578  * This routine completely defines the semantics of quotas.
    579  * If other criterion want to be used to establish quotas, the
    580  * MAXQUOTAS value in quotas.h should be increased, and the
    581  * additional dquots set up here.
    582  */
    583 int
    584 getinoquota(struct inode *ip)
    585 {
    586 	struct ufsmount *ump = ip->i_ump;
    587 	struct vnode *vp = ITOV(ip);
    588 	int i, error;
    589 	u_int32_t ino_ids[MAXQUOTAS];
    590 
    591 	/*
    592 	 * To avoid deadlocks never update quotas for quota files
    593 	 * on the same file system
    594 	 */
    595 	for (i = 0; i < MAXQUOTAS; i++)
    596 		if (vp == ump->um_quotas[i])
    597 			return 0;
    598 
    599 	ino_ids[USRQUOTA] = ip->i_uid;
    600 	ino_ids[GRPQUOTA] = ip->i_gid;
    601 	for (i = 0; i < MAXQUOTAS; i++) {
    602 		/*
    603 		 * If the file id changed the quota needs update.
    604 		 */
    605 		if (ip->i_dquot[i] != NODQUOT &&
    606 		    ip->i_dquot[i]->dq_id != ino_ids[i]) {
    607 			dqrele(ITOV(ip), ip->i_dquot[i]);
    608 			ip->i_dquot[i] = NODQUOT;
    609 		}
    610 		/*
    611 		 * Set up the quota based on file id.
    612 		 * ENODEV means that quotas are not enabled.
    613 		 */
    614 		if (ip->i_dquot[i] == NODQUOT &&
    615 		    (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
    616 		    error != ENODEV)
    617 			return (error);
    618 	}
    619 	return 0;
    620 }
    621 
    622 /*
    623  * Obtain a dquot structure for the specified identifier and quota file
    624  * reading the information from the file if necessary.
    625  */
    626 int
    627 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
    628     struct dquot **dqp)
    629 {
    630 	struct dquot *dq, *ndq;
    631 	struct dqhashhead *dqh;
    632 	struct vnode *dqvp;
    633 	int error = 0; /* XXX gcc */
    634 
    635 	/* Lock to see an up to date value for QTF_CLOSING. */
    636 	mutex_enter(&dqlock);
    637 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) {
    638 		mutex_exit(&dqlock);
    639 		*dqp = NODQUOT;
    640 		return (ENODEV);
    641 	}
    642 	dqvp = ump->um_quotas[type];
    643 #ifdef QUOTA
    644 	if (ump->um_flags & UFS_QUOTA) {
    645 		if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
    646 			mutex_exit(&dqlock);
    647 			*dqp = NODQUOT;
    648 			return (ENODEV);
    649 		}
    650 	}
    651 #endif
    652 #ifdef QUOTA2
    653 	if (ump->um_flags & UFS_QUOTA2) {
    654 		if (dqvp == NULLVP) {
    655 			mutex_exit(&dqlock);
    656 			*dqp = NODQUOT;
    657 			return (ENODEV);
    658 		}
    659 	}
    660 #endif
    661 	KASSERT(dqvp != vp);
    662 	/*
    663 	 * Check the cache first.
    664 	 */
    665 	dqh = &dqhashtbl[DQHASH(dqvp, id)];
    666 	LIST_FOREACH(dq, dqh, dq_hash) {
    667 		if (dq->dq_id != id ||
    668 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    669 			continue;
    670 		KASSERT(dq->dq_cnt > 0);
    671 		dqref(dq);
    672 		mutex_exit(&dqlock);
    673 		*dqp = dq;
    674 		return (0);
    675 	}
    676 	/*
    677 	 * Not in cache, allocate a new one.
    678 	 */
    679 	mutex_exit(&dqlock);
    680 	ndq = pool_cache_get(dquot_cache, PR_WAITOK);
    681 	/*
    682 	 * Initialize the contents of the dquot structure.
    683 	 */
    684 	memset((char *)ndq, 0, sizeof *ndq);
    685 	ndq->dq_flags = 0;
    686 	ndq->dq_id = id;
    687 	ndq->dq_ump = ump;
    688 	ndq->dq_type = type;
    689 	mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
    690 	mutex_enter(&dqlock);
    691 	dqh = &dqhashtbl[DQHASH(dqvp, id)];
    692 	LIST_FOREACH(dq, dqh, dq_hash) {
    693 		if (dq->dq_id != id ||
    694 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    695 			continue;
    696 		/*
    697 		 * Another thread beat us allocating this dquot.
    698 		 */
    699 		KASSERT(dq->dq_cnt > 0);
    700 		dqref(dq);
    701 		mutex_exit(&dqlock);
    702 		mutex_destroy(&ndq->dq_interlock);
    703 		pool_cache_put(dquot_cache, ndq);
    704 		*dqp = dq;
    705 		return 0;
    706 	}
    707 	dq = ndq;
    708 	LIST_INSERT_HEAD(dqh, dq, dq_hash);
    709 	dqref(dq);
    710 	mutex_enter(&dq->dq_interlock);
    711 	mutex_exit(&dqlock);
    712 #ifdef QUOTA
    713 	if (ump->um_flags & UFS_QUOTA)
    714 		error = dq1get(dqvp, id, ump, type, dq);
    715 #endif
    716 #ifdef QUOTA2
    717 	if (ump->um_flags & UFS_QUOTA2)
    718 		error = dq2get(dqvp, id, ump, type, dq);
    719 #endif
    720 	/*
    721 	 * I/O error in reading quota file, release
    722 	 * quota structure and reflect problem to caller.
    723 	 */
    724 	if (error) {
    725 		mutex_enter(&dqlock);
    726 		LIST_REMOVE(dq, dq_hash);
    727 		mutex_exit(&dqlock);
    728 		mutex_exit(&dq->dq_interlock);
    729 		dqrele(vp, dq);
    730 		*dqp = NODQUOT;
    731 		return (error);
    732 	}
    733 	mutex_exit(&dq->dq_interlock);
    734 	*dqp = dq;
    735 	return (0);
    736 }
    737 
    738 /*
    739  * Obtain a reference to a dquot.
    740  */
    741 void
    742 dqref(struct dquot *dq)
    743 {
    744 
    745 	KASSERT(mutex_owned(&dqlock));
    746 	dq->dq_cnt++;
    747 	KASSERT(dq->dq_cnt > 0);
    748 }
    749 
    750 /*
    751  * Release a reference to a dquot.
    752  */
    753 void
    754 dqrele(struct vnode *vp, struct dquot *dq)
    755 {
    756 
    757 	if (dq == NODQUOT)
    758 		return;
    759 	mutex_enter(&dq->dq_interlock);
    760 	for (;;) {
    761 		mutex_enter(&dqlock);
    762 		if (dq->dq_cnt > 1) {
    763 			dq->dq_cnt--;
    764 			mutex_exit(&dqlock);
    765 			mutex_exit(&dq->dq_interlock);
    766 			return;
    767 		}
    768 		if ((dq->dq_flags & DQ_MOD) == 0)
    769 			break;
    770 		mutex_exit(&dqlock);
    771 #ifdef QUOTA
    772 		if (dq->dq_ump->um_flags & UFS_QUOTA)
    773 			(void) dq1sync(vp, dq);
    774 #endif
    775 #ifdef QUOTA2
    776 		if (dq->dq_ump->um_flags & UFS_QUOTA2)
    777 			(void) dq2sync(vp, dq);
    778 #endif
    779 	}
    780 	KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
    781 	LIST_REMOVE(dq, dq_hash);
    782 	mutex_exit(&dqlock);
    783 	mutex_exit(&dq->dq_interlock);
    784 	mutex_destroy(&dq->dq_interlock);
    785 	pool_cache_put(dquot_cache, dq);
    786 }
    787 
    788 int
    789 qsync(struct mount *mp)
    790 {
    791 	struct ufsmount *ump = VFSTOUFS(mp);
    792 #ifdef QUOTA
    793 	if (ump->um_flags & UFS_QUOTA)
    794 		return q1sync(mp);
    795 #endif
    796 #ifdef QUOTA2
    797 	if (ump->um_flags & UFS_QUOTA2)
    798 		return q2sync(mp);
    799 #endif
    800 	return 0;
    801 }
    802 
    803 #ifdef DIAGNOSTIC
    804 /*
    805  * Check the hash chains for stray dquot's.
    806  */
    807 void
    808 dqflush(struct vnode *vp)
    809 {
    810 	struct dquot *dq;
    811 	int i;
    812 
    813 	mutex_enter(&dqlock);
    814 	for (i = 0; i <= dqhash; i++)
    815 		LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
    816 			KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
    817 	mutex_exit(&dqlock);
    818 }
    819 #endif
    820