Home | History | Annotate | Line # | Download | only in ufs
ufs_quota.c revision 1.74
      1 /*	$NetBSD: ufs_quota.c,v 1.74 2012/01/29 06:37:30 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.74 2012/01/29 06:37:30 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 	id_t id;
    236 	int q2type;
    237 	int defaultq;
    238 	prop_array_t replies;
    239 
    240 	KASSERT(args->qc_type == QCT_GET);
    241 	id = args->u.get.qc_id;
    242 	q2type = args->u.get.qc_q2type;
    243 	defaultq = args->u.get.qc_defaultq;
    244 	replies = args->u.get.qc_replies;
    245 
    246 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    247 		return EOPNOTSUPP;
    248 
    249 	/* avoid whitespace diffs */ {
    250 		error = quota_get_auth(mp, l, id);
    251 		if (error != 0)
    252 			return error;
    253 #ifdef QUOTA
    254 		if (ump->um_flags & UFS_QUOTA)
    255 			error = quota1_handle_cmd_get(ump, q2type, id, defaultq,
    256 			    replies);
    257 		else
    258 #endif
    259 #ifdef QUOTA2
    260 		if (ump->um_flags & UFS_QUOTA2) {
    261 			error = quota2_handle_cmd_get(ump, q2type, id, defaultq,
    262 			    replies);
    263 		} else
    264 #endif
    265 			panic("quota_handle_cmd_get: no support ?");
    266 
    267 		if (error != 0)
    268 			return error;
    269 	}
    270 
    271 	return error;
    272 }
    273 
    274 static int
    275 quota_handle_cmd_set(struct mount *mp, struct lwp *l,
    276     struct vfs_quotactl_args *args)
    277 {
    278 	prop_array_t replies;
    279 	prop_object_iterator_t iter;
    280 	prop_dictionary_t data;
    281 	uint32_t id;
    282 	struct ufsmount *ump = VFSTOUFS(mp);
    283 	int error, defaultq = 0;
    284 	const char *idstr;
    285 	prop_dictionary_t cmddict;
    286 	int q2type;
    287 	prop_array_t datas;
    288 
    289 	KASSERT(args->qc_type == QCT_PROPLIB);
    290 	cmddict = args->u.proplib.qc_cmddict;
    291 	q2type = args->u.proplib.qc_q2type;
    292 	datas = args->u.proplib.qc_datas;
    293 
    294 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    295 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    296 
    297 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    298 		return EOPNOTSUPP;
    299 
    300 	replies = prop_array_create();
    301 	if (replies == NULL)
    302 		return ENOMEM;
    303 
    304 	iter = prop_array_iterator(datas);
    305 	if (iter == NULL) {
    306 		prop_object_release(replies);
    307 		return ENOMEM;
    308 	}
    309 	while ((data = prop_object_iterator_next(iter)) != NULL) {
    310 		if (!prop_dictionary_get_uint32(data, "id", &id)) {
    311 			if (!prop_dictionary_get_cstring_nocopy(data, "id",
    312 			    &idstr))
    313 				continue;
    314 			if (strcmp(idstr, "default"))
    315 				continue;
    316 			id = 0;
    317 			defaultq = 1;
    318 		} else {
    319 			defaultq = 0;
    320 		}
    321 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    322 		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL);
    323 		if (error != 0)
    324 			goto err;
    325 #ifdef QUOTA
    326 		if (ump->um_flags & UFS_QUOTA)
    327 			error = quota1_handle_cmd_set(ump, q2type, id, defaultq,
    328 			    data);
    329 		else
    330 #endif
    331 #ifdef QUOTA2
    332 		if (ump->um_flags & UFS_QUOTA2) {
    333 			error = quota2_handle_cmd_set(ump, q2type, id, defaultq,
    334 			    data);
    335 		} else
    336 #endif
    337 			panic("quota_handle_cmd_get: no support ?");
    338 
    339 		if (error && error != ENOENT)
    340 			goto err;
    341 	}
    342 	prop_object_iterator_release(iter);
    343 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    344 		error = ENOMEM;
    345 	} else {
    346 		error = 0;
    347 	}
    348 	return error;
    349 err:
    350 	prop_object_iterator_release(iter);
    351 	prop_object_release(replies);
    352 	return error;
    353 }
    354 
    355 static int
    356 quota_handle_cmd_clear(struct mount *mp, struct lwp *l,
    357     struct vfs_quotactl_args *args)
    358 {
    359 	prop_array_t replies;
    360 	prop_object_iterator_t iter;
    361 	prop_dictionary_t data;
    362 	uint32_t id;
    363 	struct ufsmount *ump = VFSTOUFS(mp);
    364 	int error, defaultq = 0;
    365 	const char *idstr;
    366 	prop_dictionary_t cmddict;
    367 	int q2type;
    368 	prop_array_t datas;
    369 
    370 	KASSERT(args->qc_type == QCT_PROPLIB);
    371 	cmddict = args->u.proplib.qc_cmddict;
    372 	q2type = args->u.proplib.qc_q2type;
    373 	datas = args->u.proplib.qc_datas;
    374 
    375 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    376 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    377 
    378 	if ((ump->um_flags & UFS_QUOTA2) == 0)
    379 		return EOPNOTSUPP;
    380 
    381 	replies = prop_array_create();
    382 	if (replies == NULL)
    383 		return ENOMEM;
    384 
    385 	iter = prop_array_iterator(datas);
    386 	if (iter == NULL) {
    387 		prop_object_release(replies);
    388 		return ENOMEM;
    389 	}
    390 	while ((data = prop_object_iterator_next(iter)) != NULL) {
    391 		if (!prop_dictionary_get_uint32(data, "id", &id)) {
    392 			if (!prop_dictionary_get_cstring_nocopy(data, "id",
    393 			    &idstr))
    394 				continue;
    395 			if (strcmp(idstr, "default"))
    396 				continue;
    397 			id = 0;
    398 			defaultq = 1;
    399 		} else {
    400 			defaultq = 0;
    401 		}
    402 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    403 		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL);
    404 		if (error != 0)
    405 			goto err;
    406 #ifdef QUOTA2
    407 		if (ump->um_flags & UFS_QUOTA2) {
    408 			error = quota2_handle_cmd_clear(ump, q2type, id, defaultq,
    409 			    data);
    410 		} else
    411 #endif
    412 			panic("quota_handle_cmd_get: no support ?");
    413 
    414 		if (error && error != ENOENT)
    415 			goto err;
    416 	}
    417 	prop_object_iterator_release(iter);
    418 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    419 		error = ENOMEM;
    420 	} else {
    421 		error = 0;
    422 	}
    423 	return error;
    424 err:
    425 	prop_object_iterator_release(iter);
    426 	prop_object_release(replies);
    427 	return error;
    428 }
    429 
    430 static int
    431 quota_handle_cmd_getall(struct mount *mp, struct lwp *l,
    432     struct vfs_quotactl_args *args)
    433 {
    434 	prop_array_t replies;
    435 	struct ufsmount *ump = VFSTOUFS(mp);
    436 	int error;
    437 	prop_dictionary_t cmddict;
    438 	int q2type;
    439 	prop_array_t datas;
    440 
    441 	KASSERT(args->qc_type == QCT_PROPLIB);
    442 	cmddict = args->u.proplib.qc_cmddict;
    443 	q2type = args->u.proplib.qc_q2type;
    444 	datas = args->u.proplib.qc_datas;
    445 
    446 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    447 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    448 
    449 	if ((ump->um_flags & UFS_QUOTA2) == 0)
    450 		return EOPNOTSUPP;
    451 
    452 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    453 	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
    454 	if (error)
    455 		return error;
    456 
    457 	replies = prop_array_create();
    458 	if (replies == NULL)
    459 		return ENOMEM;
    460 
    461 #ifdef QUOTA2
    462 	if (ump->um_flags & UFS_QUOTA2) {
    463 		error = quota2_handle_cmd_getall(ump, q2type, replies);
    464 	} else
    465 #endif
    466 		panic("quota_handle_cmd_getall: no support ?");
    467 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
    468 		error = ENOMEM;
    469 	} else {
    470 		error = 0;
    471 	}
    472 	return error;
    473 }
    474 
    475 static int
    476 quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
    477     struct vfs_quotactl_args *args)
    478 {
    479 	prop_dictionary_t data;
    480 	struct ufsmount *ump = VFSTOUFS(mp);
    481 	int error;
    482 	const char *qfile;
    483 	prop_dictionary_t cmddict;
    484 	int q2type;
    485 	prop_array_t datas;
    486 
    487 	KASSERT(args->qc_type == QCT_PROPLIB);
    488 	cmddict = args->u.proplib.qc_cmddict;
    489 	q2type = args->u.proplib.qc_q2type;
    490 	datas = args->u.proplib.qc_datas;
    491 
    492 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    493 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    494 
    495 	if ((ump->um_flags & UFS_QUOTA2) != 0)
    496 		return EBUSY;
    497 
    498 	if (prop_array_count(datas) != 1)
    499 		return EINVAL;
    500 
    501 	data = prop_array_get(datas, 0);
    502 	if (data == NULL)
    503 		return ENOMEM;
    504 	if (!prop_dictionary_get_cstring_nocopy(data, "quotafile",
    505 	    &qfile))
    506 		return EINVAL;
    507 
    508 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    509 	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
    510 	if (error != 0) {
    511 		return error;
    512 	}
    513 #ifdef QUOTA
    514 	error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile);
    515 #else
    516 	error = EOPNOTSUPP;
    517 #endif
    518 
    519 	return error;
    520 }
    521 
    522 static int
    523 quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
    524     struct vfs_quotactl_args *args)
    525 {
    526 	struct ufsmount *ump = VFSTOUFS(mp);
    527 	int error;
    528 	prop_dictionary_t cmddict;
    529 	int q2type;
    530 	prop_array_t datas;
    531 
    532 	KASSERT(args->qc_type == QCT_PROPLIB);
    533 	cmddict = args->u.proplib.qc_cmddict;
    534 	q2type = args->u.proplib.qc_q2type;
    535 	datas = args->u.proplib.qc_datas;
    536 
    537 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
    538 	KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
    539 
    540 	if ((ump->um_flags & UFS_QUOTA2) != 0)
    541 		return EOPNOTSUPP;
    542 
    543 	if (prop_array_count(datas) != 0)
    544 		return EINVAL;
    545 
    546 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    547 	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
    548 	if (error != 0) {
    549 		return error;
    550 	}
    551 #ifdef QUOTA
    552 	error = quota1_handle_cmd_quotaoff(l, ump, q2type);
    553 #else
    554 	error = EOPNOTSUPP;
    555 #endif
    556 
    557 	return error;
    558 }
    559 
    560 /*
    561  * Initialize the quota system.
    562  */
    563 void
    564 dqinit(void)
    565 {
    566 
    567 	mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE);
    568 	cv_init(&dqcv, "quota");
    569 	dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
    570 	dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq",
    571 	    NULL, IPL_NONE, NULL, NULL, NULL);
    572 }
    573 
    574 void
    575 dqreinit(void)
    576 {
    577 	struct dquot *dq;
    578 	struct dqhashhead *oldhash, *hash;
    579 	struct vnode *dqvp;
    580 	u_long oldmask, mask, hashval;
    581 	int i;
    582 
    583 	hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
    584 	mutex_enter(&dqlock);
    585 	oldhash = dqhashtbl;
    586 	oldmask = dqhash;
    587 	dqhashtbl = hash;
    588 	dqhash = mask;
    589 	for (i = 0; i <= oldmask; i++) {
    590 		while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
    591 			dqvp = dq->dq_ump->um_quotas[dq->dq_type];
    592 			LIST_REMOVE(dq, dq_hash);
    593 			hashval = DQHASH(dqvp, dq->dq_id);
    594 			LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
    595 		}
    596 	}
    597 	mutex_exit(&dqlock);
    598 	hashdone(oldhash, HASH_LIST, oldmask);
    599 }
    600 
    601 /*
    602  * Free resources held by quota system.
    603  */
    604 void
    605 dqdone(void)
    606 {
    607 
    608 	pool_cache_destroy(dquot_cache);
    609 	hashdone(dqhashtbl, HASH_LIST, dqhash);
    610 	cv_destroy(&dqcv);
    611 	mutex_destroy(&dqlock);
    612 }
    613 
    614 /*
    615  * Set up the quotas for an inode.
    616  *
    617  * This routine completely defines the semantics of quotas.
    618  * If other criterion want to be used to establish quotas, the
    619  * MAXQUOTAS value in quotas.h should be increased, and the
    620  * additional dquots set up here.
    621  */
    622 int
    623 getinoquota(struct inode *ip)
    624 {
    625 	struct ufsmount *ump = ip->i_ump;
    626 	struct vnode *vp = ITOV(ip);
    627 	int i, error;
    628 	u_int32_t ino_ids[MAXQUOTAS];
    629 
    630 	/*
    631 	 * To avoid deadlocks never update quotas for quota files
    632 	 * on the same file system
    633 	 */
    634 	for (i = 0; i < MAXQUOTAS; i++)
    635 		if (vp == ump->um_quotas[i])
    636 			return 0;
    637 
    638 	ino_ids[USRQUOTA] = ip->i_uid;
    639 	ino_ids[GRPQUOTA] = ip->i_gid;
    640 	for (i = 0; i < MAXQUOTAS; i++) {
    641 		/*
    642 		 * If the file id changed the quota needs update.
    643 		 */
    644 		if (ip->i_dquot[i] != NODQUOT &&
    645 		    ip->i_dquot[i]->dq_id != ino_ids[i]) {
    646 			dqrele(ITOV(ip), ip->i_dquot[i]);
    647 			ip->i_dquot[i] = NODQUOT;
    648 		}
    649 		/*
    650 		 * Set up the quota based on file id.
    651 		 * ENODEV means that quotas are not enabled.
    652 		 */
    653 		if (ip->i_dquot[i] == NODQUOT &&
    654 		    (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
    655 		    error != ENODEV)
    656 			return (error);
    657 	}
    658 	return 0;
    659 }
    660 
    661 /*
    662  * Obtain a dquot structure for the specified identifier and quota file
    663  * reading the information from the file if necessary.
    664  */
    665 int
    666 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
    667     struct dquot **dqp)
    668 {
    669 	struct dquot *dq, *ndq;
    670 	struct dqhashhead *dqh;
    671 	struct vnode *dqvp;
    672 	int error = 0; /* XXX gcc */
    673 
    674 	/* Lock to see an up to date value for QTF_CLOSING. */
    675 	mutex_enter(&dqlock);
    676 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) {
    677 		mutex_exit(&dqlock);
    678 		*dqp = NODQUOT;
    679 		return (ENODEV);
    680 	}
    681 	dqvp = ump->um_quotas[type];
    682 #ifdef QUOTA
    683 	if (ump->um_flags & UFS_QUOTA) {
    684 		if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
    685 			mutex_exit(&dqlock);
    686 			*dqp = NODQUOT;
    687 			return (ENODEV);
    688 		}
    689 	}
    690 #endif
    691 #ifdef QUOTA2
    692 	if (ump->um_flags & UFS_QUOTA2) {
    693 		if (dqvp == NULLVP) {
    694 			mutex_exit(&dqlock);
    695 			*dqp = NODQUOT;
    696 			return (ENODEV);
    697 		}
    698 	}
    699 #endif
    700 	KASSERT(dqvp != vp);
    701 	/*
    702 	 * Check the cache first.
    703 	 */
    704 	dqh = &dqhashtbl[DQHASH(dqvp, id)];
    705 	LIST_FOREACH(dq, dqh, dq_hash) {
    706 		if (dq->dq_id != id ||
    707 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    708 			continue;
    709 		KASSERT(dq->dq_cnt > 0);
    710 		dqref(dq);
    711 		mutex_exit(&dqlock);
    712 		*dqp = dq;
    713 		return (0);
    714 	}
    715 	/*
    716 	 * Not in cache, allocate a new one.
    717 	 */
    718 	mutex_exit(&dqlock);
    719 	ndq = pool_cache_get(dquot_cache, PR_WAITOK);
    720 	/*
    721 	 * Initialize the contents of the dquot structure.
    722 	 */
    723 	memset((char *)ndq, 0, sizeof *ndq);
    724 	ndq->dq_flags = 0;
    725 	ndq->dq_id = id;
    726 	ndq->dq_ump = ump;
    727 	ndq->dq_type = type;
    728 	mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
    729 	mutex_enter(&dqlock);
    730 	dqh = &dqhashtbl[DQHASH(dqvp, id)];
    731 	LIST_FOREACH(dq, dqh, dq_hash) {
    732 		if (dq->dq_id != id ||
    733 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    734 			continue;
    735 		/*
    736 		 * Another thread beat us allocating this dquot.
    737 		 */
    738 		KASSERT(dq->dq_cnt > 0);
    739 		dqref(dq);
    740 		mutex_exit(&dqlock);
    741 		mutex_destroy(&ndq->dq_interlock);
    742 		pool_cache_put(dquot_cache, ndq);
    743 		*dqp = dq;
    744 		return 0;
    745 	}
    746 	dq = ndq;
    747 	LIST_INSERT_HEAD(dqh, dq, dq_hash);
    748 	dqref(dq);
    749 	mutex_enter(&dq->dq_interlock);
    750 	mutex_exit(&dqlock);
    751 #ifdef QUOTA
    752 	if (ump->um_flags & UFS_QUOTA)
    753 		error = dq1get(dqvp, id, ump, type, dq);
    754 #endif
    755 #ifdef QUOTA2
    756 	if (ump->um_flags & UFS_QUOTA2)
    757 		error = dq2get(dqvp, id, ump, type, dq);
    758 #endif
    759 	/*
    760 	 * I/O error in reading quota file, release
    761 	 * quota structure and reflect problem to caller.
    762 	 */
    763 	if (error) {
    764 		mutex_enter(&dqlock);
    765 		LIST_REMOVE(dq, dq_hash);
    766 		mutex_exit(&dqlock);
    767 		mutex_exit(&dq->dq_interlock);
    768 		dqrele(vp, dq);
    769 		*dqp = NODQUOT;
    770 		return (error);
    771 	}
    772 	mutex_exit(&dq->dq_interlock);
    773 	*dqp = dq;
    774 	return (0);
    775 }
    776 
    777 /*
    778  * Obtain a reference to a dquot.
    779  */
    780 void
    781 dqref(struct dquot *dq)
    782 {
    783 
    784 	KASSERT(mutex_owned(&dqlock));
    785 	dq->dq_cnt++;
    786 	KASSERT(dq->dq_cnt > 0);
    787 }
    788 
    789 /*
    790  * Release a reference to a dquot.
    791  */
    792 void
    793 dqrele(struct vnode *vp, struct dquot *dq)
    794 {
    795 
    796 	if (dq == NODQUOT)
    797 		return;
    798 	mutex_enter(&dq->dq_interlock);
    799 	for (;;) {
    800 		mutex_enter(&dqlock);
    801 		if (dq->dq_cnt > 1) {
    802 			dq->dq_cnt--;
    803 			mutex_exit(&dqlock);
    804 			mutex_exit(&dq->dq_interlock);
    805 			return;
    806 		}
    807 		if ((dq->dq_flags & DQ_MOD) == 0)
    808 			break;
    809 		mutex_exit(&dqlock);
    810 #ifdef QUOTA
    811 		if (dq->dq_ump->um_flags & UFS_QUOTA)
    812 			(void) dq1sync(vp, dq);
    813 #endif
    814 #ifdef QUOTA2
    815 		if (dq->dq_ump->um_flags & UFS_QUOTA2)
    816 			(void) dq2sync(vp, dq);
    817 #endif
    818 	}
    819 	KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
    820 	LIST_REMOVE(dq, dq_hash);
    821 	mutex_exit(&dqlock);
    822 	mutex_exit(&dq->dq_interlock);
    823 	mutex_destroy(&dq->dq_interlock);
    824 	pool_cache_put(dquot_cache, dq);
    825 }
    826 
    827 int
    828 qsync(struct mount *mp)
    829 {
    830 	struct ufsmount *ump = VFSTOUFS(mp);
    831 #ifdef QUOTA
    832 	if (ump->um_flags & UFS_QUOTA)
    833 		return q1sync(mp);
    834 #endif
    835 #ifdef QUOTA2
    836 	if (ump->um_flags & UFS_QUOTA2)
    837 		return q2sync(mp);
    838 #endif
    839 	return 0;
    840 }
    841 
    842 #ifdef DIAGNOSTIC
    843 /*
    844  * Check the hash chains for stray dquot's.
    845  */
    846 void
    847 dqflush(struct vnode *vp)
    848 {
    849 	struct dquot *dq;
    850 	int i;
    851 
    852 	mutex_enter(&dqlock);
    853 	for (i = 0; i <= dqhash; i++)
    854 		LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
    855 			KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
    856 	mutex_exit(&dqlock);
    857 }
    858 #endif
    859