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