Home | History | Annotate | Line # | Download | only in ufs
ufs_quota.c revision 1.107
      1 /*	$NetBSD: ufs_quota.c,v 1.107 2012/02/01 05:34:43 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.107 2012/02/01 05:34:43 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 
     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_stat(struct mount *, struct lwp *,
     74     struct quotactl_args *args);
     75 static int quota_handle_cmd_idtypestat(struct mount *, struct lwp *,
     76     struct quotactl_args *args);
     77 static int quota_handle_cmd_objtypestat(struct mount *, struct lwp *,
     78     struct quotactl_args *args);
     79 static int quota_handle_cmd_get(struct mount *, struct lwp *,
     80     struct quotactl_args *args);
     81 static int quota_handle_cmd_put(struct mount *, struct lwp *,
     82     struct quotactl_args *args);
     83 static int quota_handle_cmd_cursorget(struct mount *, struct lwp *,
     84     struct quotactl_args *args);
     85 static int quota_handle_cmd_delete(struct mount *, struct lwp *,
     86     struct quotactl_args *args);
     87 static int quota_handle_cmd_quotaon(struct mount *, struct lwp *,
     88     struct quotactl_args *args);
     89 static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *,
     90     struct quotactl_args *args);
     91 static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *,
     92     struct quotactl_args *args);
     93 static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *,
     94     struct quotactl_args *args);
     95 static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *,
     96     struct quotactl_args *args);
     97 static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *,
     98     struct quotactl_args *args);
     99 static int quota_handle_cmd_cursorrewind(struct mount *, struct lwp *,
    100     struct quotactl_args *args);
    101 
    102 /*
    103  * Initialize the quota fields of an inode.
    104  */
    105 void
    106 ufsquota_init(struct inode *ip)
    107 {
    108 	int i;
    109 
    110 	for (i = 0; i < MAXQUOTAS; i++)
    111 		ip->i_dquot[i] = NODQUOT;
    112 }
    113 
    114 /*
    115  * Release the quota fields from an inode.
    116  */
    117 void
    118 ufsquota_free(struct inode *ip)
    119 {
    120 	int i;
    121 
    122 	for (i = 0; i < MAXQUOTAS; i++) {
    123 		dqrele(ITOV(ip), ip->i_dquot[i]);
    124 		ip->i_dquot[i] = NODQUOT;
    125 	}
    126 }
    127 
    128 /*
    129  * Update disk usage, and take corrective action.
    130  */
    131 int
    132 chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
    133 {
    134 	/* do not track snapshot usage, or we will deadlock */
    135 	if ((ip->i_flags & SF_SNAPSHOT) != 0)
    136 		return 0;
    137 
    138 #ifdef QUOTA
    139 	if (ip->i_ump->um_flags & UFS_QUOTA)
    140 		return chkdq1(ip, change, cred, flags);
    141 #endif
    142 #ifdef QUOTA2
    143 	if (ip->i_ump->um_flags & UFS_QUOTA2)
    144 		return chkdq2(ip, change, cred, flags);
    145 #endif
    146 	return 0;
    147 }
    148 
    149 /*
    150  * Check the inode limit, applying corrective action.
    151  */
    152 int
    153 chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
    154 {
    155 	/* do not track snapshot usage, or we will deadlock */
    156 	if ((ip->i_flags & SF_SNAPSHOT) != 0)
    157 		return 0;
    158 #ifdef QUOTA
    159 	if (ip->i_ump->um_flags & UFS_QUOTA)
    160 		return chkiq1(ip, change, cred, flags);
    161 #endif
    162 #ifdef QUOTA2
    163 	if (ip->i_ump->um_flags & UFS_QUOTA2)
    164 		return chkiq2(ip, change, cred, flags);
    165 #endif
    166 	return 0;
    167 }
    168 
    169 int
    170 quota_handle_cmd(struct mount *mp, struct lwp *l,
    171 		 struct quotactl_args *args)
    172 {
    173 	int error = 0;
    174 
    175 	switch (args->qc_op) {
    176 	    case QUOTACTL_STAT:
    177 		error = quota_handle_cmd_stat(mp, l, args);
    178 		break;
    179 	    case QUOTACTL_IDTYPESTAT:
    180 		error = quota_handle_cmd_idtypestat(mp, l, args);
    181 		break;
    182 	    case QUOTACTL_OBJTYPESTAT:
    183 		error = quota_handle_cmd_objtypestat(mp, l, args);
    184 		break;
    185 	    case QUOTACTL_QUOTAON:
    186 		error = quota_handle_cmd_quotaon(mp, l, args);
    187 		break;
    188 	    case QUOTACTL_QUOTAOFF:
    189 		error = quota_handle_cmd_quotaoff(mp, l, args);
    190 		break;
    191 	    case QUOTACTL_GET:
    192 		error = quota_handle_cmd_get(mp, l, args);
    193 		break;
    194 	    case QUOTACTL_PUT:
    195 		error = quota_handle_cmd_put(mp, l, args);
    196 		break;
    197 	    case QUOTACTL_CURSORGET:
    198 		error = quota_handle_cmd_cursorget(mp, l, args);
    199 		break;
    200 	    case QUOTACTL_DELETE:
    201 		error = quota_handle_cmd_delete(mp, l, args);
    202 		break;
    203 	    case QUOTACTL_CURSOROPEN:
    204 		error = quota_handle_cmd_cursoropen(mp, l, args);
    205 		break;
    206 	    case QUOTACTL_CURSORCLOSE:
    207 		error = quota_handle_cmd_cursorclose(mp, l, args);
    208 		break;
    209 	    case QUOTACTL_CURSORSKIPIDTYPE:
    210 		error = quota_handle_cmd_cursorskipidtype(mp, l, args);
    211 		break;
    212 	    case QUOTACTL_CURSORATEND:
    213 		error = quota_handle_cmd_cursoratend(mp, l, args);
    214 		break;
    215 	    case QUOTACTL_CURSORREWIND:
    216 		error = quota_handle_cmd_cursorrewind(mp, l, args);
    217 		break;
    218 	    default:
    219 		panic("Invalid quotactl operation %d\n", args->qc_op);
    220 	}
    221 
    222 	return error;
    223 }
    224 
    225 static int
    226 quota_handle_cmd_stat(struct mount *mp, struct lwp *l,
    227     struct quotactl_args *args)
    228 {
    229 	struct ufsmount *ump = VFSTOUFS(mp);
    230 	struct quotastat *ret;
    231 
    232 	KASSERT(args->qc_op == QUOTACTL_STAT);
    233 	ret = args->u.stat.qc_ret;
    234 
    235 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    236 		return EOPNOTSUPP;
    237 
    238 #ifdef QUOTA
    239 	if (ump->um_flags & UFS_QUOTA) {
    240 		strcpy(ret->qs_implname, "ufs/ffs quota v1");
    241 		ret->qs_numidtypes = MAXQUOTAS;
    242 		/* XXX no define for this */
    243 		ret->qs_numobjtypes = 2;
    244 		ret->qs_restrictions = 0;
    245 		ret->qs_restrictions |= QUOTA_RESTRICT_NEEDSQUOTACHECK;
    246 		ret->qs_restrictions |= QUOTA_RESTRICT_UNIFORMGRACE;
    247 		ret->qs_restrictions |= QUOTA_RESTRICT_32BIT;
    248 	} else
    249 #endif
    250 #ifdef QUOTA2
    251 	if (ump->um_flags & UFS_QUOTA2) {
    252 		strcpy(ret->qs_implname, "ufs/ffs quota v2");
    253 		ret->qs_numidtypes = MAXQUOTAS;
    254 		ret->qs_numobjtypes = N_QL;
    255 		ret->qs_restrictions = 0;
    256 	} else
    257 #endif
    258 		return EOPNOTSUPP;
    259 
    260 	return 0;
    261 }
    262 
    263 static int
    264 quota_handle_cmd_idtypestat(struct mount *mp, struct lwp *l,
    265     struct quotactl_args *args)
    266 {
    267 	struct ufsmount *ump = VFSTOUFS(mp);
    268 	int idtype;
    269 	struct quotaidtypestat *info;
    270 	const char *name;
    271 
    272 	KASSERT(args->qc_op == QUOTACTL_IDTYPESTAT);
    273 	idtype = args->u.idtypestat.qc_idtype;
    274 	info = args->u.idtypestat.qc_info;
    275 
    276 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    277 		return EOPNOTSUPP;
    278 
    279 	/*
    280 	 * These are the same for both QUOTA and QUOTA2.
    281 	 */
    282 	switch (idtype) {
    283 	    case QUOTA_IDTYPE_USER:
    284 		name = "user";
    285 		break;
    286 	    case QUOTA_IDTYPE_GROUP:
    287 		name = "group";
    288 		break;
    289 	    default:
    290 		return EINVAL;
    291 	}
    292 	strlcpy(info->qis_name, name, sizeof(info->qis_name));
    293 	return 0;
    294 }
    295 
    296 static int
    297 quota_handle_cmd_objtypestat(struct mount *mp, struct lwp *l,
    298     struct quotactl_args *args)
    299 {
    300 	struct ufsmount *ump = VFSTOUFS(mp);
    301 	int objtype;
    302 	struct quotaobjtypestat *info;
    303 	const char *name;
    304 	int isbytes;
    305 
    306 	KASSERT(args->qc_op == QUOTACTL_OBJTYPESTAT);
    307 	objtype = args->u.objtypestat.qc_objtype;
    308 	info = args->u.objtypestat.qc_info;
    309 
    310 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    311 		return EOPNOTSUPP;
    312 
    313 	/*
    314 	 * These are the same for both QUOTA and QUOTA2.
    315 	 */
    316 	switch (objtype) {
    317 	    case QUOTA_OBJTYPE_BLOCKS:
    318 		name = "block";
    319 		isbytes = 1;
    320 		break;
    321 	    case QUOTA_OBJTYPE_FILES:
    322 		name = "file";
    323 		isbytes = 0;
    324 		break;
    325 	    default:
    326 		return EINVAL;
    327 	}
    328 	strlcpy(info->qos_name, name, sizeof(info->qos_name));
    329 	info->qos_isbytes = isbytes;
    330 	return 0;
    331 }
    332 
    333 /* XXX shouldn't all this be in kauth ? */
    334 static int
    335 quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {
    336 	/* The user can always query about his own quota. */
    337 	if (id == kauth_cred_getuid(l->l_cred))
    338 		return 0;
    339 	return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    340 	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL);
    341 }
    342 
    343 static int
    344 quota_handle_cmd_get(struct mount *mp, struct lwp *l,
    345     struct quotactl_args *args)
    346 {
    347 	struct ufsmount *ump = VFSTOUFS(mp);
    348 	int error;
    349 	const struct quotakey *qk;
    350 	struct quotaval *ret;
    351 
    352 	KASSERT(args->qc_op == QUOTACTL_GET);
    353 	qk = args->u.get.qc_key;
    354 	ret = args->u.get.qc_ret;
    355 
    356 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    357 		return EOPNOTSUPP;
    358 
    359 	error = quota_get_auth(mp, l, qk->qk_id);
    360 	if (error != 0)
    361 		return error;
    362 #ifdef QUOTA
    363 	if (ump->um_flags & UFS_QUOTA) {
    364 		error = quota1_handle_cmd_get(ump, qk, ret);
    365 	} else
    366 #endif
    367 #ifdef QUOTA2
    368 	if (ump->um_flags & UFS_QUOTA2) {
    369 		error = quota2_handle_cmd_get(ump, qk, ret);
    370 	} else
    371 #endif
    372 		panic("quota_handle_cmd_get: no support ?");
    373 
    374 	if (error != 0)
    375 		return error;
    376 
    377 	return error;
    378 }
    379 
    380 static int
    381 quota_handle_cmd_put(struct mount *mp, struct lwp *l,
    382     struct quotactl_args *args)
    383 {
    384 	struct ufsmount *ump = VFSTOUFS(mp);
    385 	const struct quotakey *qk;
    386 	const struct quotaval *qv;
    387 	id_t kauth_id;
    388 	int error;
    389 
    390 	KASSERT(args->qc_op == QUOTACTL_PUT);
    391 	qk = args->u.put.qc_key;
    392 	qv = args->u.put.qc_val;
    393 
    394 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
    395 		return EOPNOTSUPP;
    396 
    397 	kauth_id = qk->qk_id;
    398 	if (kauth_id == QUOTA_DEFAULTID) {
    399 		kauth_id = 0;
    400 	}
    401 
    402 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    403 	    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
    404 	    NULL);
    405 	if (error != 0) {
    406 		return error;
    407 	}
    408 
    409 #ifdef QUOTA
    410 	if (ump->um_flags & UFS_QUOTA)
    411 		error = quota1_handle_cmd_put(ump, qk, qv);
    412 	else
    413 #endif
    414 #ifdef QUOTA2
    415 	if (ump->um_flags & UFS_QUOTA2) {
    416 		error = quota2_handle_cmd_put(ump, qk, qv);
    417 	} else
    418 #endif
    419 		panic("quota_handle_cmd_get: no support ?");
    420 
    421 	if (error == ENOENT) {
    422 		error = 0;
    423 	}
    424 
    425 	return error;
    426 }
    427 
    428 static int
    429 quota_handle_cmd_delete(struct mount *mp, struct lwp *l,
    430     struct quotactl_args *args)
    431 {
    432 	struct ufsmount *ump = VFSTOUFS(mp);
    433 	const struct quotakey *qk;
    434 	id_t kauth_id;
    435 	int error;
    436 
    437 	KASSERT(args->qc_op == QUOTACTL_DELETE);
    438 	qk = args->u.delete.qc_key;
    439 
    440 	kauth_id = qk->qk_id;
    441 	if (kauth_id == QUOTA_DEFAULTID) {
    442 		kauth_id = 0;
    443 	}
    444 
    445 	if ((ump->um_flags & UFS_QUOTA2) == 0)
    446 		return EOPNOTSUPP;
    447 
    448 	/* avoid whitespace changes */
    449 	{
    450 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    451 		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
    452 		    NULL);
    453 		if (error != 0)
    454 			goto err;
    455 #ifdef QUOTA2
    456 		if (ump->um_flags & UFS_QUOTA2) {
    457 			error = quota2_handle_cmd_delete(ump, qk);
    458 		} else
    459 #endif
    460 			panic("quota_handle_cmd_get: no support ?");
    461 
    462 		if (error && error != ENOENT)
    463 			goto err;
    464 	}
    465 
    466 	return 0;
    467  err:
    468 	return error;
    469 }
    470 
    471 static int
    472 quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l,
    473     struct quotactl_args *args)
    474 {
    475 	struct ufsmount *ump = VFSTOUFS(mp);
    476 	struct quotakcursor *cursor;
    477 	struct quotakey *keys;
    478 	struct quotaval *vals;
    479 	unsigned maxnum;
    480 	unsigned *ret;
    481 	int error;
    482 
    483 	KASSERT(args->qc_op == QUOTACTL_CURSORGET);
    484 	cursor = args->u.cursorget.qc_cursor;
    485 	keys = args->u.cursorget.qc_keys;
    486 	vals = args->u.cursorget.qc_vals;
    487 	maxnum = args->u.cursorget.qc_maxnum;
    488 	ret = args->u.cursorget.qc_ret;
    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 #ifdef QUOTA2
    499 	if (ump->um_flags & UFS_QUOTA2) {
    500 		error = quota2_handle_cmd_cursorget(ump, cursor, keys, vals,
    501 						    maxnum, ret);
    502 	} else
    503 #endif
    504 		panic("quota_handle_cmd_cursorget: no support ?");
    505 
    506 	return error;
    507 }
    508 
    509 static int
    510 quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l,
    511     struct quotactl_args *args)
    512 {
    513 #ifdef QUOTA2
    514 	struct ufsmount *ump = VFSTOUFS(mp);
    515 #endif
    516 	struct quotakcursor *cursor;
    517 	int error;
    518 
    519 	KASSERT(args->qc_op == QUOTACTL_CURSOROPEN);
    520 	cursor = args->u.cursoropen.qc_cursor;
    521 
    522 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    523 	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
    524 	if (error)
    525 		return error;
    526 
    527 #ifdef QUOTA2
    528 	if (ump->um_flags & UFS_QUOTA2) {
    529 		error = quota2_handle_cmd_cursoropen(ump, cursor);
    530 	} else
    531 #endif
    532 		error = EOPNOTSUPP;
    533 
    534 	return error;
    535 }
    536 
    537 static int
    538 quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l,
    539     struct quotactl_args *args)
    540 {
    541 #ifdef QUOTA2
    542 	struct ufsmount *ump = VFSTOUFS(mp);
    543 #endif
    544 	struct quotakcursor *cursor;
    545 	int error;
    546 
    547 	KASSERT(args->qc_op == QUOTACTL_CURSORCLOSE);
    548 	cursor = args->u.cursorclose.qc_cursor;
    549 
    550 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    551 	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
    552 	if (error)
    553 		return error;
    554 
    555 #ifdef QUOTA2
    556 	if (ump->um_flags & UFS_QUOTA2) {
    557 		error = quota2_handle_cmd_cursorclose(ump, cursor);
    558 	} else
    559 #endif
    560 		error = EOPNOTSUPP;
    561 
    562 	return error;
    563 }
    564 
    565 static int
    566 quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l,
    567     struct quotactl_args *args)
    568 {
    569 #ifdef QUOTA2
    570 	struct ufsmount *ump = VFSTOUFS(mp);
    571 #endif
    572 	struct quotakcursor *cursor;
    573 	int idtype;
    574 	int error;
    575 
    576 	KASSERT(args->qc_op == QUOTACTL_CURSORSKIPIDTYPE);
    577 	cursor = args->u.cursorskipidtype.qc_cursor;
    578 	idtype = args->u.cursorskipidtype.qc_idtype;
    579 
    580 #ifdef QUOTA2
    581 	if (ump->um_flags & UFS_QUOTA2) {
    582 		error = quota2_handle_cmd_cursorskipidtype(ump, cursor, idtype);
    583 	} else
    584 #endif
    585 		error = EOPNOTSUPP;
    586 
    587 	return error;
    588 }
    589 
    590 static int
    591 quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l,
    592     struct quotactl_args *args)
    593 {
    594 #ifdef QUOTA2
    595 	struct ufsmount *ump = VFSTOUFS(mp);
    596 #endif
    597 	struct quotakcursor *cursor;
    598 	int *ret;
    599 	int error;
    600 
    601 	KASSERT(args->qc_op == QUOTACTL_CURSORATEND);
    602 	cursor = args->u.cursoratend.qc_cursor;
    603 	ret = args->u.cursoratend.qc_ret;
    604 
    605 #ifdef QUOTA2
    606 	if (ump->um_flags & UFS_QUOTA2) {
    607 		error = quota2_handle_cmd_cursoratend(ump, cursor, ret);
    608 	} else
    609 #endif
    610 		error = EOPNOTSUPP;
    611 
    612 	return error;
    613 }
    614 
    615 static int
    616 quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l,
    617     struct quotactl_args *args)
    618 {
    619 #ifdef QUOTA2
    620 	struct ufsmount *ump = VFSTOUFS(mp);
    621 #endif
    622 	struct quotakcursor *cursor;
    623 	int error;
    624 
    625 	KASSERT(args->qc_op == QUOTACTL_CURSORREWIND);
    626 	cursor = args->u.cursorrewind.qc_cursor;
    627 
    628 #ifdef QUOTA2
    629 	if (ump->um_flags & UFS_QUOTA2) {
    630 		error = quota2_handle_cmd_cursorrewind(ump, cursor);
    631 	} else
    632 #endif
    633 		error = EOPNOTSUPP;
    634 
    635 	return error;
    636 }
    637 
    638 static int
    639 quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
    640     struct quotactl_args *args)
    641 {
    642 	struct ufsmount *ump = VFSTOUFS(mp);
    643 	int idtype;
    644 	const char *qfile;
    645 	int error;
    646 
    647 	KASSERT(args->qc_op == QUOTACTL_QUOTAON);
    648 	idtype = args->u.quotaon.qc_idtype;
    649 	qfile = args->u.quotaon.qc_quotafile;
    650 
    651 	if ((ump->um_flags & UFS_QUOTA2) != 0)
    652 		return EBUSY;
    653 
    654 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    655 	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
    656 	if (error != 0) {
    657 		return error;
    658 	}
    659 #ifdef QUOTA
    660 	error = quota1_handle_cmd_quotaon(l, ump, idtype, qfile);
    661 #else
    662 	error = EOPNOTSUPP;
    663 #endif
    664 
    665 	return error;
    666 }
    667 
    668 static int
    669 quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
    670     struct quotactl_args *args)
    671 {
    672 	struct ufsmount *ump = VFSTOUFS(mp);
    673 	int idtype;
    674 	int error;
    675 
    676 	KASSERT(args->qc_op == QUOTACTL_QUOTAOFF);
    677 	idtype = args->u.quotaoff.qc_idtype;
    678 
    679 	if ((ump->um_flags & UFS_QUOTA2) != 0)
    680 		return EOPNOTSUPP;
    681 
    682 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
    683 	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
    684 	if (error != 0) {
    685 		return error;
    686 	}
    687 #ifdef QUOTA
    688 	error = quota1_handle_cmd_quotaoff(l, ump, idtype);
    689 #else
    690 	error = EOPNOTSUPP;
    691 #endif
    692 
    693 	return error;
    694 }
    695 
    696 /*
    697  * Initialize the quota system.
    698  */
    699 void
    700 dqinit(void)
    701 {
    702 
    703 	mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE);
    704 	cv_init(&dqcv, "quota");
    705 	dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
    706 	dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq",
    707 	    NULL, IPL_NONE, NULL, NULL, NULL);
    708 }
    709 
    710 void
    711 dqreinit(void)
    712 {
    713 	struct dquot *dq;
    714 	struct dqhashhead *oldhash, *hash;
    715 	struct vnode *dqvp;
    716 	u_long oldmask, mask, hashval;
    717 	int i;
    718 
    719 	hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
    720 	mutex_enter(&dqlock);
    721 	oldhash = dqhashtbl;
    722 	oldmask = dqhash;
    723 	dqhashtbl = hash;
    724 	dqhash = mask;
    725 	for (i = 0; i <= oldmask; i++) {
    726 		while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
    727 			dqvp = dq->dq_ump->um_quotas[dq->dq_type];
    728 			LIST_REMOVE(dq, dq_hash);
    729 			hashval = DQHASH(dqvp, dq->dq_id);
    730 			LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
    731 		}
    732 	}
    733 	mutex_exit(&dqlock);
    734 	hashdone(oldhash, HASH_LIST, oldmask);
    735 }
    736 
    737 /*
    738  * Free resources held by quota system.
    739  */
    740 void
    741 dqdone(void)
    742 {
    743 
    744 	pool_cache_destroy(dquot_cache);
    745 	hashdone(dqhashtbl, HASH_LIST, dqhash);
    746 	cv_destroy(&dqcv);
    747 	mutex_destroy(&dqlock);
    748 }
    749 
    750 /*
    751  * Set up the quotas for an inode.
    752  *
    753  * This routine completely defines the semantics of quotas.
    754  * If other criterion want to be used to establish quotas, the
    755  * MAXQUOTAS value in quotas.h should be increased, and the
    756  * additional dquots set up here.
    757  */
    758 int
    759 getinoquota(struct inode *ip)
    760 {
    761 	struct ufsmount *ump = ip->i_ump;
    762 	struct vnode *vp = ITOV(ip);
    763 	int i, error;
    764 	u_int32_t ino_ids[MAXQUOTAS];
    765 
    766 	/*
    767 	 * To avoid deadlocks never update quotas for quota files
    768 	 * on the same file system
    769 	 */
    770 	for (i = 0; i < MAXQUOTAS; i++)
    771 		if (vp == ump->um_quotas[i])
    772 			return 0;
    773 
    774 	ino_ids[USRQUOTA] = ip->i_uid;
    775 	ino_ids[GRPQUOTA] = ip->i_gid;
    776 	for (i = 0; i < MAXQUOTAS; i++) {
    777 		/*
    778 		 * If the file id changed the quota needs update.
    779 		 */
    780 		if (ip->i_dquot[i] != NODQUOT &&
    781 		    ip->i_dquot[i]->dq_id != ino_ids[i]) {
    782 			dqrele(ITOV(ip), ip->i_dquot[i]);
    783 			ip->i_dquot[i] = NODQUOT;
    784 		}
    785 		/*
    786 		 * Set up the quota based on file id.
    787 		 * ENODEV means that quotas are not enabled.
    788 		 */
    789 		if (ip->i_dquot[i] == NODQUOT &&
    790 		    (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
    791 		    error != ENODEV)
    792 			return (error);
    793 	}
    794 	return 0;
    795 }
    796 
    797 /*
    798  * Obtain a dquot structure for the specified identifier and quota file
    799  * reading the information from the file if necessary.
    800  */
    801 int
    802 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
    803     struct dquot **dqp)
    804 {
    805 	struct dquot *dq, *ndq;
    806 	struct dqhashhead *dqh;
    807 	struct vnode *dqvp;
    808 	int error = 0; /* XXX gcc */
    809 
    810 	/* Lock to see an up to date value for QTF_CLOSING. */
    811 	mutex_enter(&dqlock);
    812 	if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) {
    813 		mutex_exit(&dqlock);
    814 		*dqp = NODQUOT;
    815 		return (ENODEV);
    816 	}
    817 	dqvp = ump->um_quotas[type];
    818 #ifdef QUOTA
    819 	if (ump->um_flags & UFS_QUOTA) {
    820 		if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
    821 			mutex_exit(&dqlock);
    822 			*dqp = NODQUOT;
    823 			return (ENODEV);
    824 		}
    825 	}
    826 #endif
    827 #ifdef QUOTA2
    828 	if (ump->um_flags & UFS_QUOTA2) {
    829 		if (dqvp == NULLVP) {
    830 			mutex_exit(&dqlock);
    831 			*dqp = NODQUOT;
    832 			return (ENODEV);
    833 		}
    834 	}
    835 #endif
    836 	KASSERT(dqvp != vp);
    837 	/*
    838 	 * Check the cache first.
    839 	 */
    840 	dqh = &dqhashtbl[DQHASH(dqvp, id)];
    841 	LIST_FOREACH(dq, dqh, dq_hash) {
    842 		if (dq->dq_id != id ||
    843 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    844 			continue;
    845 		KASSERT(dq->dq_cnt > 0);
    846 		dqref(dq);
    847 		mutex_exit(&dqlock);
    848 		*dqp = dq;
    849 		return (0);
    850 	}
    851 	/*
    852 	 * Not in cache, allocate a new one.
    853 	 */
    854 	mutex_exit(&dqlock);
    855 	ndq = pool_cache_get(dquot_cache, PR_WAITOK);
    856 	/*
    857 	 * Initialize the contents of the dquot structure.
    858 	 */
    859 	memset((char *)ndq, 0, sizeof *ndq);
    860 	ndq->dq_flags = 0;
    861 	ndq->dq_id = id;
    862 	ndq->dq_ump = ump;
    863 	ndq->dq_type = type;
    864 	mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
    865 	mutex_enter(&dqlock);
    866 	dqh = &dqhashtbl[DQHASH(dqvp, id)];
    867 	LIST_FOREACH(dq, dqh, dq_hash) {
    868 		if (dq->dq_id != id ||
    869 		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
    870 			continue;
    871 		/*
    872 		 * Another thread beat us allocating this dquot.
    873 		 */
    874 		KASSERT(dq->dq_cnt > 0);
    875 		dqref(dq);
    876 		mutex_exit(&dqlock);
    877 		mutex_destroy(&ndq->dq_interlock);
    878 		pool_cache_put(dquot_cache, ndq);
    879 		*dqp = dq;
    880 		return 0;
    881 	}
    882 	dq = ndq;
    883 	LIST_INSERT_HEAD(dqh, dq, dq_hash);
    884 	dqref(dq);
    885 	mutex_enter(&dq->dq_interlock);
    886 	mutex_exit(&dqlock);
    887 #ifdef QUOTA
    888 	if (ump->um_flags & UFS_QUOTA)
    889 		error = dq1get(dqvp, id, ump, type, dq);
    890 #endif
    891 #ifdef QUOTA2
    892 	if (ump->um_flags & UFS_QUOTA2)
    893 		error = dq2get(dqvp, id, ump, type, dq);
    894 #endif
    895 	/*
    896 	 * I/O error in reading quota file, release
    897 	 * quota structure and reflect problem to caller.
    898 	 */
    899 	if (error) {
    900 		mutex_enter(&dqlock);
    901 		LIST_REMOVE(dq, dq_hash);
    902 		mutex_exit(&dqlock);
    903 		mutex_exit(&dq->dq_interlock);
    904 		dqrele(vp, dq);
    905 		*dqp = NODQUOT;
    906 		return (error);
    907 	}
    908 	mutex_exit(&dq->dq_interlock);
    909 	*dqp = dq;
    910 	return (0);
    911 }
    912 
    913 /*
    914  * Obtain a reference to a dquot.
    915  */
    916 void
    917 dqref(struct dquot *dq)
    918 {
    919 
    920 	KASSERT(mutex_owned(&dqlock));
    921 	dq->dq_cnt++;
    922 	KASSERT(dq->dq_cnt > 0);
    923 }
    924 
    925 /*
    926  * Release a reference to a dquot.
    927  */
    928 void
    929 dqrele(struct vnode *vp, struct dquot *dq)
    930 {
    931 
    932 	if (dq == NODQUOT)
    933 		return;
    934 	mutex_enter(&dq->dq_interlock);
    935 	for (;;) {
    936 		mutex_enter(&dqlock);
    937 		if (dq->dq_cnt > 1) {
    938 			dq->dq_cnt--;
    939 			mutex_exit(&dqlock);
    940 			mutex_exit(&dq->dq_interlock);
    941 			return;
    942 		}
    943 		if ((dq->dq_flags & DQ_MOD) == 0)
    944 			break;
    945 		mutex_exit(&dqlock);
    946 #ifdef QUOTA
    947 		if (dq->dq_ump->um_flags & UFS_QUOTA)
    948 			(void) dq1sync(vp, dq);
    949 #endif
    950 #ifdef QUOTA2
    951 		if (dq->dq_ump->um_flags & UFS_QUOTA2)
    952 			(void) dq2sync(vp, dq);
    953 #endif
    954 	}
    955 	KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
    956 	LIST_REMOVE(dq, dq_hash);
    957 	mutex_exit(&dqlock);
    958 	mutex_exit(&dq->dq_interlock);
    959 	mutex_destroy(&dq->dq_interlock);
    960 	pool_cache_put(dquot_cache, dq);
    961 }
    962 
    963 int
    964 qsync(struct mount *mp)
    965 {
    966 	struct ufsmount *ump = VFSTOUFS(mp);
    967 #ifdef QUOTA
    968 	if (ump->um_flags & UFS_QUOTA)
    969 		return q1sync(mp);
    970 #endif
    971 #ifdef QUOTA2
    972 	if (ump->um_flags & UFS_QUOTA2)
    973 		return q2sync(mp);
    974 #endif
    975 	return 0;
    976 }
    977 
    978 #ifdef DIAGNOSTIC
    979 /*
    980  * Check the hash chains for stray dquot's.
    981  */
    982 void
    983 dqflush(struct vnode *vp)
    984 {
    985 	struct dquot *dq;
    986 	int i;
    987 
    988 	mutex_enter(&dqlock);
    989 	for (i = 0; i <= dqhash; i++)
    990 		LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
    991 			KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
    992 	mutex_exit(&dqlock);
    993 }
    994 #endif
    995