Home | History | Annotate | Line # | Download | only in ufs
ufs_quota.c revision 1.70
      1 /*	$NetBSD: ufs_quota.c,v 1.70 2011/03/24 17:05:46 bouyer 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.70 2011/03/24 17:05:46 bouyer 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 <ufs/ufs/quota.h>
     54 #include <ufs/ufs/inode.h>
     55 #include <ufs/ufs/ufsmount.h>
     56 #include <ufs/ufs/ufs_extern.h>
     57 #include <ufs/ufs/ufs_quota.h>
     58 #include <quota/quotaprop.h>
     59 
     60 kmutex_t dqlock;
     61 kcondvar_t dqcv;
     62 
     63 /*
     64  * Code pertaining to management of the in-core dquot data structures.
     65  */
     66 #define DQHASH(dqvp, id) \
     67 	(((((long)(dqvp)) >> 8) + id) & dqhash)
     68 static LIST_HEAD(dqhashhead, dquot) *dqhashtbl;
     69 static u_long dqhash;
     70 static pool_cache_t dquot_cache;
     71 
     72 
     73 static int quota_handle_cmd_get_version(struct mount *, struct lwp *,
     74     prop_dictionary_t, prop_array_t);
     75 static int quota_handle_cmd_get(struct mount *, struct lwp *,
     76     prop_dictionary_t, int, prop_array_t);
     77 static int quota_handle_cmd_set(struct mount *, struct lwp *,
     78     prop_dictionary_t, int, prop_array_t);
     79 static int quota_handle_cmd_getall(struct mount *, struct lwp *,
     80     prop_dictionary_t, int, prop_array_t);
     81 static int quota_handle_cmd_clear(struct mount *, struct lwp *,
     82     prop_dictionary_t, int, prop_array_t);
     83 static int quota_handle_cmd_quotaon(struct mount *, struct lwp *,
     84     prop_dictionary_t, int, prop_array_t);
     85 static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *,
     86     prop_dictionary_t, int, prop_array_t);
     87 /*
     88  * Initialize the quota fields of an inode.
     89  */
     90 void
     91 ufsquota_init(struct inode *ip)
     92 {
     93 	int i;
     94 
     95 	for (i = 0; i < MAXQUOTAS; i++)
     96 		ip->i_dquot[i] = NODQUOT;
     97 }
     98 
     99 /*
    100  * Release the quota fields from an inode.
    101  */
    102 void
    103 ufsquota_free(struct inode *ip)
    104 {
    105 	int i;
    106 
    107 	for (i = 0; i < MAXQUOTAS; i++) {
    108 		dqrele(ITOV(ip), ip->i_dquot[i]);
    109 		ip->i_dquot[i] = NODQUOT;
    110 	}
    111 }
    112 
    113 /*
    114  * Update disk usage, and take corrective action.
    115  */
    116 int
    117 chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
    118 {
    119 	/* do not track snapshot usage, or we will deadlock */
    120 	if ((ip->i_flags & SF_SNAPSHOT) != 0)
    121 		return 0;
    122 
    123 #ifdef QUOTA
    124 	if (ip->i_ump->um_flags & UFS_QUOTA)
    125 		return chkdq1(ip, change, cred, flags);
    126 #endif
    127 #ifdef QUOTA2
    128 	if (ip->i_ump->um_flags & UFS_QUOTA2)
    129 		return chkdq2(ip, change, cred, flags);
    130 #endif
    131 	return 0;
    132 }
    133 
    134 /*
    135  * Check the inode limit, applying corrective action.
    136  */
    137 int
    138 chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
    139 {
    140 	/* do not track snapshot usage, or we will deadlock */
    141 	if ((ip->i_flags & SF_SNAPSHOT) != 0)
    142 		return 0;
    143 #ifdef QUOTA
    144 	if (ip->i_ump->um_flags & UFS_QUOTA)
    145 		return chkiq1(ip, change, cred, flags);
    146 #endif
    147 #ifdef QUOTA2
    148 	if (ip->i_ump->um_flags & UFS_QUOTA2)
    149 		return chkiq2(ip, change, cred, flags);
    150 #endif
    151 	return 0;
    152 }
    153 
    154 int
    155 quota_handle_cmd(struct mount *mp, struct lwp *l, prop_dictionary_t cmddict)
    156 {
    157 	int error = 0;
    158 	const char *cmd, *type;
    159 	prop_array_t datas;
    160 	int q2type;
    161 
    162 	if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd))
    163 		return EINVAL;
    164 	if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type))
    165 		return EINVAL;
    166 	if (!strcmp(type, QUOTADICT_CLASS_USER)) {
    167 		q2type = USRQUOTA;
    168 	} else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) {
    169 		q2type = GRPQUOTA;
    170 	} else
    171 		return EOPNOTSUPP;
    172 	datas = prop_dictionary_get(cmddict, "data");
    173 	if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY)
    174 		return EINVAL;
    175 
    176 	prop_object_retain(datas);
    177 	prop_dictionary_remove(cmddict, "data"); /* prepare for return */
    178 
    179 	if (strcmp(cmd, "get version") == 0) {
    180 		error = quota_handle_cmd_get_version(mp, l, cmddict, datas);
    181 		goto end;
    182 	}
    183 	if (strcmp(cmd, "quotaon") == 0) {
    184 		error = quota_handle_cmd_quotaon(mp, l, cmddict,
    185 		    q2type, datas);
    186 		goto end;
    187 	}
    188 	if (strcmp(cmd, "quotaoff") == 0) {
    189 		error = quota_handle_cmd_quotaoff(mp, l, cmddict,
    190 		    q2type, datas);
    191 		goto end;
    192 	}
    193 	if (strcmp(cmd, "get") == 0) {
    194 		error = quota_handle_cmd_get(mp, l, cmddict, q2type, datas);
    195 		goto end;
    196 	}
    197 	if (strcmp(cmd, "set") == 0) {
    198 		error = quota_handle_cmd_set(mp, l, cmddict, q2type, datas);
    199 		goto end;
    200 	}
    201 	if (strcmp(cmd, "getall") == 0) {
    202 		error = quota_handle_cmd_getall(mp, l, cmddict, q2type, datas);
    203 		goto end;
    204 	}
    205 	if (strcmp(cmd, "clear") == 0) {
    206 		error = quota_handle_cmd_clear(mp, l, cmddict, q2type, datas);
    207 		goto end;
    208 	}
    209 	error = EOPNOTSUPP;
    210 end:
    211 	error = (prop_dictionary_set_int8(cmddict, "return",
    212 	    error) ? 0 : ENOMEM);
    213 	prop_object_release(datas);
    214 	return error;
    215 }
    216 
    217 static int
    218 quota_handle_cmd_get_version(struct mount *mp, struct lwp *l,
    219     prop_dictionary_t cmddict, prop_array_t datas)
    220 {
    221 	struct ufsmount *ump = VFSTOUFS(mp);
    222 	prop_array_t replies;
    223 	prop_dictionary_t data;
    224 	int error = 0;
    225 
    226 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    227 		return EOPNOTSUPP;
    228 
    229 	replies = prop_array_create();
    230 	if (replies == NULL)
    231 		return ENOMEM;
    232 
    233 	data = prop_dictionary_create();
    234 	if (data == NULL) {
    235 		prop_object_release(replies);
    236 		return ENOMEM;
    237 	}
    238 
    239 #ifdef QUOTA
    240 	if (ump->um_flags & UFS_QUOTA) {
    241 		if (!prop_dictionary_set_int8(data, "version", 1))
    242 			error = ENOMEM;
    243 	} else
    244 #endif
    245 #ifdef QUOTA2
    246 	if (ump->um_flags & UFS_QUOTA2) {
    247 		if (!prop_dictionary_set_int8(data, "version", 2))
    248 			error = ENOMEM;
    249 	} else
    250 #endif
    251 		error = 0;
    252 	if (error)
    253 		prop_object_release(data);
    254 	else if (!prop_array_add_and_rel(replies, data))
    255 		error = ENOMEM;
    256 	if (error)
    257 		prop_object_release(replies);
    258 	else if (!prop_dictionary_set_and_rel(cmddict, "data", replies))
    259 		error = ENOMEM;
    260 	return error;
    261 }
    262 
    263 /* XXX shouldn't all this be in kauth ? */
    264 static int
    265 quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {
    266 	/* The user can always query about his own quota. */
    267 	if (id == kauth_cred_getuid(l->l_cred))
    268 		return 0;
    269 	return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    270 	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL);
    271 }
    272 
    273 static int
    274 quota_handle_cmd_get(struct mount *mp, struct lwp *l,
    275     prop_dictionary_t cmddict, int type, prop_array_t datas)
    276 {
    277 	prop_array_t replies;
    278 	prop_object_iterator_t iter;
    279 	prop_dictionary_t data;
    280 	uint32_t id;
    281 	struct ufsmount *ump = VFSTOUFS(mp);
    282 	int error, defaultq = 0;
    283 	const char *idstr;
    284 
    285 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    286 		return EOPNOTSUPP;
    287 
    288 	replies = prop_array_create();
    289 	if (replies == NULL)
    290 		return ENOMEM;
    291 
    292 	iter = prop_array_iterator(datas);
    293 	if (iter == NULL) {
    294 		prop_object_release(replies);
    295 		return ENOMEM;
    296 	}
    297 	while ((data = prop_object_iterator_next(iter)) != NULL) {
    298 		if (!prop_dictionary_get_uint32(data, "id", &id)) {
    299 			if (!prop_dictionary_get_cstring_nocopy(data, "id",
    300 			    &idstr))
    301 				continue;
    302 			if (strcmp(idstr, "default")) {
    303 				error = EINVAL;
    304 				goto err;
    305 			}
    306 			id = 0;
    307 			defaultq = 1;
    308 		} else {
    309 			defaultq = 0;
    310 		}
    311 		error = quota_get_auth(mp, l, id);
    312 		if (error == EPERM)
    313 			continue;
    314 		if (error != 0)
    315 			goto err;
    316 #ifdef QUOTA
    317 		if (ump->um_flags & UFS_QUOTA)
    318 			error = quota1_handle_cmd_get(ump, type, id, defaultq,
    319 			    replies);
    320 		else
    321 #endif
    322 #ifdef QUOTA2
    323 		if (ump->um_flags & UFS_QUOTA2) {
    324 			error = quota2_handle_cmd_get(ump, type, id, defaultq,
    325 			    replies);
    326 		} else
    327 #endif
    328 			panic("quota_handle_cmd_get: no support ?");
    329 
    330 		if (error == ENOENT)
    331 			continue;
    332 		if (error != 0)
    333 			goto err;
    334 	}
    335 	prop_object_iterator_release(iter);
    336 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    337 		error = ENOMEM;
    338 	} else {
    339 		error = 0;
    340 	}
    341 	return error;
    342 err:
    343 	prop_object_iterator_release(iter);
    344 	prop_object_release(replies);
    345 	return error;
    346 }
    347 
    348 static int
    349 quota_handle_cmd_set(struct mount *mp, struct lwp *l,
    350     prop_dictionary_t cmddict, int type, prop_array_t datas)
    351 {
    352 	prop_array_t replies;
    353 	prop_object_iterator_t iter;
    354 	prop_dictionary_t data;
    355 	uint32_t id;
    356 	struct ufsmount *ump = VFSTOUFS(mp);
    357 	int error, defaultq = 0;
    358 	const char *idstr;
    359 
    360 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    361 		return EOPNOTSUPP;
    362 
    363 	replies = prop_array_create();
    364 	if (replies == NULL)
    365 		return ENOMEM;
    366 
    367 	iter = prop_array_iterator(datas);
    368 	if (iter == NULL) {
    369 		prop_object_release(replies);
    370 		return ENOMEM;
    371 	}
    372 	while ((data = prop_object_iterator_next(iter)) != NULL) {
    373 		if (!prop_dictionary_get_uint32(data, "id", &id)) {
    374 			if (!prop_dictionary_get_cstring_nocopy(data, "id",
    375 			    &idstr))
    376 				continue;
    377 			if (strcmp(idstr, "default"))
    378 				continue;
    379 			id = 0;
    380 			defaultq = 1;
    381 		} else {
    382 			defaultq = 0;
    383 		}
    384 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    385 		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL);
    386 		if (error != 0)
    387 			goto err;
    388 #ifdef QUOTA
    389 		if (ump->um_flags & UFS_QUOTA)
    390 			error = quota1_handle_cmd_set(ump, type, id, defaultq,
    391 			    data);
    392 		else
    393 #endif
    394 #ifdef QUOTA2
    395 		if (ump->um_flags & UFS_QUOTA2) {
    396 			error = quota2_handle_cmd_set(ump, type, id, defaultq,
    397 			    data);
    398 		} else
    399 #endif
    400 			panic("quota_handle_cmd_get: no support ?");
    401 
    402 		if (error && error != ENOENT)
    403 			goto err;
    404 	}
    405 	prop_object_iterator_release(iter);
    406 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    407 		error = ENOMEM;
    408 	} else {
    409 		error = 0;
    410 	}
    411 	return error;
    412 err:
    413 	prop_object_iterator_release(iter);
    414 	prop_object_release(replies);
    415 	return error;
    416 }
    417 
    418 static int
    419 quota_handle_cmd_clear(struct mount *mp, struct lwp *l,
    420     prop_dictionary_t cmddict, int type, prop_array_t datas)
    421 {
    422 	prop_array_t replies;
    423 	prop_object_iterator_t iter;
    424 	prop_dictionary_t data;
    425 	uint32_t id;
    426 	struct ufsmount *ump = VFSTOUFS(mp);
    427 	int error, defaultq = 0;
    428 	const char *idstr;
    429 
    430 	if ((ump->um_flags & UFS_QUOTA2) == 0)
    431 		return EOPNOTSUPP;
    432 
    433 	replies = prop_array_create();
    434 	if (replies == NULL)
    435 		return ENOMEM;
    436 
    437 	iter = prop_array_iterator(datas);
    438 	if (iter == NULL) {
    439 		prop_object_release(replies);
    440 		return ENOMEM;
    441 	}
    442 	while ((data = prop_object_iterator_next(iter)) != NULL) {
    443 		if (!prop_dictionary_get_uint32(data, "id", &id)) {
    444 			if (!prop_dictionary_get_cstring_nocopy(data, "id",
    445 			    &idstr))
    446 				continue;
    447 			if (strcmp(idstr, "default"))
    448 				continue;
    449 			id = 0;
    450 			defaultq = 1;
    451 		} else {
    452 			defaultq = 0;
    453 		}
    454 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    455 		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL);
    456 		if (error != 0)
    457 			goto err;
    458 #ifdef QUOTA2
    459 		if (ump->um_flags & UFS_QUOTA2) {
    460 			error = quota2_handle_cmd_clear(ump, type, id, defaultq,
    461 			    data);
    462 		} else
    463 #endif
    464 			panic("quota_handle_cmd_get: no support ?");
    465 
    466 		if (error && error != ENOENT)
    467 			goto err;
    468 	}
    469 	prop_object_iterator_release(iter);
    470 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    471 		error = ENOMEM;
    472 	} else {
    473 		error = 0;
    474 	}
    475 	return error;
    476 err:
    477 	prop_object_iterator_release(iter);
    478 	prop_object_release(replies);
    479 	return error;
    480 }
    481 
    482 static int
    483 quota_handle_cmd_getall(struct mount *mp, struct lwp *l,
    484     prop_dictionary_t cmddict, int type, prop_array_t datas)
    485 {
    486 	prop_array_t replies;
    487 	struct ufsmount *ump = VFSTOUFS(mp);
    488 	int error;
    489 
    490 	if ((ump->um_flags & UFS_QUOTA2) == 0)
    491 		return EOPNOTSUPP;
    492 
    493 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    494 	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
    495 	if (error)
    496 		return error;
    497 
    498 	replies = prop_array_create();
    499 	if (replies == NULL)
    500 		return ENOMEM;
    501 
    502 #ifdef QUOTA2
    503 	if (ump->um_flags & UFS_QUOTA2) {
    504 		error = quota2_handle_cmd_getall(ump, type, replies);
    505 	} else
    506 #endif
    507 		panic("quota_handle_cmd_getall: no support ?");
    508 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    509 		error = ENOMEM;
    510 	} else {
    511 		error = 0;
    512 	}
    513 	return error;
    514 }
    515 
    516 static int
    517 quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
    518     prop_dictionary_t cmddict, int type, prop_array_t datas)
    519 {
    520 	prop_dictionary_t data;
    521 	struct ufsmount *ump = VFSTOUFS(mp);
    522 	int error;
    523 	const char *qfile;
    524 
    525 	if ((ump->um_flags & UFS_QUOTA2) != 0)
    526 		return EBUSY;
    527 
    528 	if (prop_array_count(datas) != 1)
    529 		return EINVAL;
    530 
    531 	data = prop_array_get(datas, 0);
    532 	if (data == NULL)
    533 		return ENOMEM;
    534 	if (!prop_dictionary_get_cstring_nocopy(data, "quotafile",
    535 	    &qfile))
    536 		return EINVAL;
    537 
    538 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    539 	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
    540 	if (error != 0) {
    541 		return error;
    542 	}
    543 #ifdef QUOTA
    544 	error = quota1_handle_cmd_quotaon(l, ump, type, qfile);
    545 #else
    546 	error = EOPNOTSUPP;
    547 #endif
    548 
    549 	return error;
    550 }
    551 
    552 static int
    553 quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
    554     prop_dictionary_t cmddict, int type, prop_array_t datas)
    555 {
    556 	struct ufsmount *ump = VFSTOUFS(mp);
    557 	int error;
    558 
    559 	if ((ump->um_flags & UFS_QUOTA2) != 0)
    560 		return EOPNOTSUPP;
    561 
    562 	if (prop_array_count(datas) != 0)
    563 		return EINVAL;
    564 
    565 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    566 	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
    567 	if (error != 0) {
    568 		return error;
    569 	}
    570 #ifdef QUOTA
    571 	error = quota1_handle_cmd_quotaoff(l, ump, type);
    572 #else
    573 	error = EOPNOTSUPP;
    574 #endif
    575 
    576 	return error;
    577 }
    578 
    579 /*
    580  * Initialize the quota system.
    581  */
    582 void
    583 dqinit(void)
    584 {
    585 
    586 	mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE);
    587 	cv_init(&dqcv, "quota");
    588 	dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
    589 	dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq",
    590 	    NULL, IPL_NONE, NULL, NULL, NULL);
    591 }
    592 
    593 void
    594 dqreinit(void)
    595 {
    596 	struct dquot *dq;
    597 	struct dqhashhead *oldhash, *hash;
    598 	struct vnode *dqvp;
    599 	u_long oldmask, mask, hashval;
    600 	int i;
    601 
    602 	hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
    603 	mutex_enter(&dqlock);
    604 	oldhash = dqhashtbl;
    605 	oldmask = dqhash;
    606 	dqhashtbl = hash;
    607 	dqhash = mask;
    608 	for (i = 0; i <= oldmask; i++) {
    609 		while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
    610 			dqvp = dq->dq_ump->um_quotas[dq->dq_type];
    611 			LIST_REMOVE(dq, dq_hash);
    612 			hashval = DQHASH(dqvp, dq->dq_id);
    613 			LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
    614 		}
    615 	}
    616 	mutex_exit(&dqlock);
    617 	hashdone(oldhash, HASH_LIST, oldmask);
    618 }
    619 
    620 /*
    621  * Free resources held by quota system.
    622  */
    623 void
    624 dqdone(void)
    625 {
    626 
    627 	pool_cache_destroy(dquot_cache);
    628 	hashdone(dqhashtbl, HASH_LIST, dqhash);
    629 	cv_destroy(&dqcv);
    630 	mutex_destroy(&dqlock);
    631 }
    632 
    633 /*
    634  * Set up the quotas for an inode.
    635  *
    636  * This routine completely defines the semantics of quotas.
    637  * If other criterion want to be used to establish quotas, the
    638  * MAXQUOTAS value in quotas.h should be increased, and the
    639  * additional dquots set up here.
    640  */
    641 int
    642 getinoquota(struct inode *ip)
    643 {
    644 	struct ufsmount *ump = ip->i_ump;
    645 	struct vnode *vp = ITOV(ip);
    646 	int i, error;
    647 	u_int32_t ino_ids[MAXQUOTAS];
    648 
    649 	/*
    650 	 * To avoid deadlocks never update quotas for quota files
    651 	 * on the same file system
    652 	 */
    653 	for (i = 0; i < MAXQUOTAS; i++)
    654 		if (vp == ump->um_quotas[i])
    655 			return 0;
    656 
    657 	ino_ids[USRQUOTA] = ip->i_uid;
    658 	ino_ids[GRPQUOTA] = ip->i_gid;
    659 	for (i = 0; i < MAXQUOTAS; i++) {
    660 		/*
    661 		 * If the file id changed the quota needs update.
    662 		 */
    663 		if (ip->i_dquot[i] != NODQUOT &&
    664 		    ip->i_dquot[i]->dq_id != ino_ids[i]) {
    665 			dqrele(ITOV(ip), ip->i_dquot[i]);
    666 			ip->i_dquot[i] = NODQUOT;
    667 		}
    668 		/*
    669 		 * Set up the quota based on file id.
    670 		 * ENODEV means that quotas are not enabled.
    671 		 */
    672 		if (ip->i_dquot[i] == NODQUOT &&
    673 		    (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
    674 		    error != ENODEV)
    675 			return (error);
    676 	}
    677 	return 0;
    678 }
    679 
    680 /*
    681  * Obtain a dquot structure for the specified identifier and quota file
    682  * reading the information from the file if necessary.
    683  */
    684 int
    685 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
    686     struct dquot **dqp)
    687 {
    688 	struct dquot *dq, *ndq;
    689 	struct dqhashhead *dqh;
    690 	struct vnode *dqvp;
    691 	int error = 0; /* XXX gcc */
    692 
    693 	/* Lock to see an up to date value for QTF_CLOSING. */
    694 	mutex_enter(&dqlock);
    695 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) {
    696 		mutex_exit(&dqlock);
    697 		*dqp = NODQUOT;
    698 		return (ENODEV);
    699 	}
    700 	dqvp = ump->um_quotas[type];
    701 #ifdef QUOTA
    702 	if (ump->um_flags & UFS_QUOTA) {
    703 		if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
    704 			mutex_exit(&dqlock);
    705 			*dqp = NODQUOT;
    706 			return (ENODEV);
    707 		}
    708 	}
    709 #endif
    710 #ifdef QUOTA2
    711 	if (ump->um_flags & UFS_QUOTA2) {
    712 		if (dqvp == NULLVP) {
    713 			mutex_exit(&dqlock);
    714 			*dqp = NODQUOT;
    715 			return (ENODEV);
    716 		}
    717 	}
    718 #endif
    719 	KASSERT(dqvp != vp);
    720 	/*
    721 	 * Check the cache first.
    722 	 */
    723 	dqh = &dqhashtbl[DQHASH(dqvp, id)];
    724 	LIST_FOREACH(dq, dqh, dq_hash) {
    725 		if (dq->dq_id != id ||
    726 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    727 			continue;
    728 		KASSERT(dq->dq_cnt > 0);
    729 		dqref(dq);
    730 		mutex_exit(&dqlock);
    731 		*dqp = dq;
    732 		return (0);
    733 	}
    734 	/*
    735 	 * Not in cache, allocate a new one.
    736 	 */
    737 	mutex_exit(&dqlock);
    738 	ndq = pool_cache_get(dquot_cache, PR_WAITOK);
    739 	/*
    740 	 * Initialize the contents of the dquot structure.
    741 	 */
    742 	memset((char *)ndq, 0, sizeof *ndq);
    743 	ndq->dq_flags = 0;
    744 	ndq->dq_id = id;
    745 	ndq->dq_ump = ump;
    746 	ndq->dq_type = type;
    747 	mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
    748 	mutex_enter(&dqlock);
    749 	dqh = &dqhashtbl[DQHASH(dqvp, id)];
    750 	LIST_FOREACH(dq, dqh, dq_hash) {
    751 		if (dq->dq_id != id ||
    752 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    753 			continue;
    754 		/*
    755 		 * Another thread beat us allocating this dquot.
    756 		 */
    757 		KASSERT(dq->dq_cnt > 0);
    758 		dqref(dq);
    759 		mutex_exit(&dqlock);
    760 		mutex_destroy(&ndq->dq_interlock);
    761 		pool_cache_put(dquot_cache, ndq);
    762 		*dqp = dq;
    763 		return 0;
    764 	}
    765 	dq = ndq;
    766 	LIST_INSERT_HEAD(dqh, dq, dq_hash);
    767 	dqref(dq);
    768 	mutex_enter(&dq->dq_interlock);
    769 	mutex_exit(&dqlock);
    770 #ifdef QUOTA
    771 	if (ump->um_flags & UFS_QUOTA)
    772 		error = dq1get(dqvp, id, ump, type, dq);
    773 #endif
    774 #ifdef QUOTA2
    775 	if (ump->um_flags & UFS_QUOTA2)
    776 		error = dq2get(dqvp, id, ump, type, dq);
    777 #endif
    778 	/*
    779 	 * I/O error in reading quota file, release
    780 	 * quota structure and reflect problem to caller.
    781 	 */
    782 	if (error) {
    783 		mutex_enter(&dqlock);
    784 		LIST_REMOVE(dq, dq_hash);
    785 		mutex_exit(&dqlock);
    786 		mutex_exit(&dq->dq_interlock);
    787 		dqrele(vp, dq);
    788 		*dqp = NODQUOT;
    789 		return (error);
    790 	}
    791 	mutex_exit(&dq->dq_interlock);
    792 	*dqp = dq;
    793 	return (0);
    794 }
    795 
    796 /*
    797  * Obtain a reference to a dquot.
    798  */
    799 void
    800 dqref(struct dquot *dq)
    801 {
    802 
    803 	KASSERT(mutex_owned(&dqlock));
    804 	dq->dq_cnt++;
    805 	KASSERT(dq->dq_cnt > 0);
    806 }
    807 
    808 /*
    809  * Release a reference to a dquot.
    810  */
    811 void
    812 dqrele(struct vnode *vp, struct dquot *dq)
    813 {
    814 
    815 	if (dq == NODQUOT)
    816 		return;
    817 	mutex_enter(&dq->dq_interlock);
    818 	for (;;) {
    819 		mutex_enter(&dqlock);
    820 		if (dq->dq_cnt > 1) {
    821 			dq->dq_cnt--;
    822 			mutex_exit(&dqlock);
    823 			mutex_exit(&dq->dq_interlock);
    824 			return;
    825 		}
    826 		if ((dq->dq_flags & DQ_MOD) == 0)
    827 			break;
    828 		mutex_exit(&dqlock);
    829 #ifdef QUOTA
    830 		if (dq->dq_ump->um_flags & UFS_QUOTA)
    831 			(void) dq1sync(vp, dq);
    832 #endif
    833 #ifdef QUOTA2
    834 		if (dq->dq_ump->um_flags & UFS_QUOTA2)
    835 			(void) dq2sync(vp, dq);
    836 #endif
    837 	}
    838 	KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
    839 	LIST_REMOVE(dq, dq_hash);
    840 	mutex_exit(&dqlock);
    841 	mutex_exit(&dq->dq_interlock);
    842 	mutex_destroy(&dq->dq_interlock);
    843 	pool_cache_put(dquot_cache, dq);
    844 }
    845 
    846 int
    847 qsync(struct mount *mp)
    848 {
    849 	struct ufsmount *ump = VFSTOUFS(mp);
    850 #ifdef QUOTA
    851 	if (ump->um_flags & UFS_QUOTA)
    852 		return q1sync(mp);
    853 #endif
    854 #ifdef QUOTA2
    855 	if (ump->um_flags & UFS_QUOTA2)
    856 		return q2sync(mp);
    857 #endif
    858 	return 0;
    859 }
    860 
    861 #ifdef DIAGNOSTIC
    862 /*
    863  * Check the hash chains for stray dquot's.
    864  */
    865 void
    866 dqflush(struct vnode *vp)
    867 {
    868 	struct dquot *dq;
    869 	int i;
    870 
    871 	mutex_enter(&dqlock);
    872 	for (i = 0; i <= dqhash; i++)
    873 		LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
    874 			KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
    875 	mutex_exit(&dqlock);
    876 }
    877 #endif
    878