1/*	$NetBSD: ulfs_quota.c,v 1.13 2016/06/19 23:06:09 dholland Exp $	*/
2/*  from NetBSD: ufs_quota.c,v 1.117 2014/06/28 22:27:51 dholland Exp  */
3
4/*
5 * Copyright (c) 1982, 1986, 1990, 1993, 1995
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Robert Elz at The University of Melbourne.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *	@(#)ufs_quota.c	8.5 (Berkeley) 5/20/95
36 */
37
38#include <sys/cdefs.h>
39__KERNEL_RCSID(0, "$NetBSD: ulfs_quota.c,v 1.13 2016/06/19 23:06:09 dholland Exp $");
40
41#if defined(_KERNEL_OPT)
42#include "opt_quota.h"
43#endif
44#include <sys/param.h>
45#include <sys/kernel.h>
46#include <sys/systm.h>
47#include <sys/namei.h>
48#include <sys/file.h>
49#include <sys/proc.h>
50#include <sys/vnode.h>
51#include <sys/mount.h>
52#include <sys/kauth.h>
53
54#include <sys/quotactl.h>
55#include <ufs/lfs/ulfs_quotacommon.h>
56#include <ufs/lfs/ulfs_inode.h>
57#include <ufs/lfs/ulfsmount.h>
58#include <ufs/lfs/ulfs_extern.h>
59#include <ufs/lfs/ulfs_quota.h>
60
61kmutex_t lfs_dqlock;
62kcondvar_t lfs_dqcv;
63const char *lfs_quotatypes[ULFS_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_del(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
108ulfsquota_init(struct inode *ip)
109{
110	int i;
111
112	for (i = 0; i < ULFS_MAXQUOTAS; i++)
113		ip->i_dquot[i] = NODQUOT;
114}
115
116/*
117 * Release the quota fields from an inode.
118 */
119void
120ulfsquota_free(struct inode *ip)
121{
122	int i;
123
124	for (i = 0; i < ULFS_MAXQUOTAS; i++) {
125		lfs_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
134lfs_chkdq(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 LFS_QUOTA
141	if (ip->i_lfs->um_flags & ULFS_QUOTA)
142		return lfs_chkdq1(ip, change, cred, flags);
143#endif
144#ifdef LFS_QUOTA2
145	if (ip->i_lfs->um_flags & ULFS_QUOTA2)
146		return lfs_chkdq2(ip, change, cred, flags);
147#endif
148	return 0;
149}
150
151/*
152 * Check the inode limit, applying corrective action.
153 */
154int
155lfs_chkiq(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 LFS_QUOTA
161	if (ip->i_lfs->um_flags & ULFS_QUOTA)
162		return lfs_chkiq1(ip, change, cred, flags);
163#endif
164#ifdef LFS_QUOTA2
165	if (ip->i_lfs->um_flags & ULFS_QUOTA2)
166		return lfs_chkiq2(ip, change, cred, flags);
167#endif
168	return 0;
169}
170
171int
172lfsquota_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_DEL:
203		error = quota_handle_cmd_del(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 ulfsmount *ump = VFSTOULFS(mp);
232	struct lfs *fs = ump->um_lfs;
233
234	KASSERT(args->qc_op == QUOTACTL_STAT);
235
236	if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
237		return EOPNOTSUPP;
238
239#ifdef LFS_QUOTA
240	if (fs->um_flags & ULFS_QUOTA) {
241		struct quotastat *info = args->u.stat.qc_info;
242		strcpy(info->qs_implname, "lfs quota v1");
243		info->qs_numidtypes = ULFS_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 LFS_QUOTA2
253	if (fs->um_flags & ULFS_QUOTA2) {
254		struct quotastat *info = args->u.stat.qc_info;
255		strcpy(info->qs_implname, "lfs quota v2");
256		info->qs_numidtypes = ULFS_MAXQUOTAS;
257		info->qs_numobjtypes = N_QL;
258		info->qs_restrictions = 0;
259	} else
260#endif
261		return EOPNOTSUPP;
262
263	return 0;
264}
265
266static int
267quota_handle_cmd_idtypestat(struct mount *mp, struct lwp *l,
268    struct quotactl_args *args)
269{
270	struct ulfsmount *ump = VFSTOULFS(mp);
271	struct lfs *fs = ump->um_lfs;
272	int idtype;
273	struct quotaidtypestat *info;
274	const char *name;
275
276	KASSERT(args->qc_op == QUOTACTL_IDTYPESTAT);
277	idtype = args->u.idtypestat.qc_idtype;
278	info = args->u.idtypestat.qc_info;
279
280	if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
281		return EOPNOTSUPP;
282
283	/*
284	 * These are the same for both QUOTA and QUOTA2.
285	 */
286	switch (idtype) {
287	    case QUOTA_IDTYPE_USER:
288		name = "user";
289		break;
290	    case QUOTA_IDTYPE_GROUP:
291		name = "group";
292		break;
293	    default:
294		return EINVAL;
295	}
296	strlcpy(info->qis_name, name, sizeof(info->qis_name));
297	return 0;
298}
299
300static int
301quota_handle_cmd_objtypestat(struct mount *mp, struct lwp *l,
302    struct quotactl_args *args)
303{
304	struct ulfsmount *ump = VFSTOULFS(mp);
305	struct lfs *fs = ump->um_lfs;
306	int objtype;
307	struct quotaobjtypestat *info;
308	const char *name;
309	int isbytes;
310
311	KASSERT(args->qc_op == QUOTACTL_OBJTYPESTAT);
312	objtype = args->u.objtypestat.qc_objtype;
313	info = args->u.objtypestat.qc_info;
314
315	if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
316		return EOPNOTSUPP;
317
318	/*
319	 * These are the same for both QUOTA and QUOTA2.
320	 */
321	switch (objtype) {
322	    case QUOTA_OBJTYPE_BLOCKS:
323		name = "block";
324		isbytes = 1;
325		break;
326	    case QUOTA_OBJTYPE_FILES:
327		name = "file";
328		isbytes = 0;
329		break;
330	    default:
331		return EINVAL;
332	}
333	strlcpy(info->qos_name, name, sizeof(info->qos_name));
334	info->qos_isbytes = isbytes;
335	return 0;
336}
337
338/* XXX shouldn't all this be in kauth ? */
339static int
340quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {
341	/* The user can always query about his own quota. */
342	if (id == kauth_cred_geteuid(l->l_cred))
343		return 0;
344	return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
345	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL);
346}
347
348static int
349quota_handle_cmd_get(struct mount *mp, struct lwp *l,
350    struct quotactl_args *args)
351{
352	struct ulfsmount *ump = VFSTOULFS(mp);
353	struct lfs *fs = ump->um_lfs;
354	int error;
355	const struct quotakey *qk;
356
357	KASSERT(args->qc_op == QUOTACTL_GET);
358	qk = args->u.get.qc_key;
359
360	if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
361		return EOPNOTSUPP;
362
363	error = quota_get_auth(mp, l, qk->qk_id);
364	if (error != 0)
365		return error;
366#ifdef LFS_QUOTA
367	if (fs->um_flags & ULFS_QUOTA) {
368		struct quotaval *qv = args->u.get.qc_val;
369		error = lfsquota1_handle_cmd_get(ump, qk, qv);
370	} else
371#endif
372#ifdef LFS_QUOTA2
373	if (fs->um_flags & ULFS_QUOTA2) {
374		struct quotaval *qv = args->u.get.qc_val;
375		error = lfsquota2_handle_cmd_get(ump, qk, qv);
376	} else
377#endif
378		panic("quota_handle_cmd_get: no support ?");
379
380	if (error != 0)
381		return error;
382
383	return error;
384}
385
386static int
387quota_handle_cmd_put(struct mount *mp, struct lwp *l,
388    struct quotactl_args *args)
389{
390	struct ulfsmount *ump = VFSTOULFS(mp);
391	struct lfs *fs = ump->um_lfs;
392	const struct quotakey *qk;
393	id_t kauth_id;
394	int error;
395
396	KASSERT(args->qc_op == QUOTACTL_PUT);
397	qk = args->u.put.qc_key;
398
399	if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
400		return EOPNOTSUPP;
401
402	kauth_id = qk->qk_id;
403	if (kauth_id == QUOTA_DEFAULTID) {
404		kauth_id = 0;
405	}
406
407	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
408	    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
409	    NULL);
410	if (error != 0) {
411		return error;
412	}
413
414#ifdef LFS_QUOTA
415	if (fs->um_flags & ULFS_QUOTA) {
416		const struct quotaval *qv = args->u.put.qc_val;
417		error = lfsquota1_handle_cmd_put(ump, qk, qv);
418	} else
419#endif
420#ifdef LFS_QUOTA2
421	if (fs->um_flags & ULFS_QUOTA2) {
422		const struct quotaval *qv = args->u.put.qc_val;
423		error = lfsquota2_handle_cmd_put(ump, qk, qv);
424	} else
425#endif
426		panic("quota_handle_cmd_get: no support ?");
427
428	if (error == ENOENT) {
429		error = 0;
430	}
431
432	return error;
433}
434
435static int
436quota_handle_cmd_del(struct mount *mp, struct lwp *l,
437    struct quotactl_args *args)
438{
439	struct ulfsmount *ump = VFSTOULFS(mp);
440	struct lfs *fs = ump->um_lfs;
441	const struct quotakey *qk;
442	id_t kauth_id;
443	int error;
444
445	KASSERT(args->qc_op == QUOTACTL_DEL);
446	qk = args->u.del.qc_key;
447
448	kauth_id = qk->qk_id;
449	if (kauth_id == QUOTA_DEFAULTID) {
450		kauth_id = 0;
451	}
452
453	if ((fs->um_flags & ULFS_QUOTA2) == 0)
454		return EOPNOTSUPP;
455
456	/* avoid whitespace changes */
457	{
458		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
459		    KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
460		    NULL);
461		if (error != 0)
462			goto err;
463#ifdef LFS_QUOTA2
464		if (fs->um_flags & ULFS_QUOTA2) {
465			error = lfsquota2_handle_cmd_del(ump, qk);
466		} else
467#endif
468			panic("quota_handle_cmd_get: no support ?");
469
470		if (error && error != ENOENT)
471			goto err;
472	}
473
474	return 0;
475 err:
476	return error;
477}
478
479static int
480quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l,
481    struct quotactl_args *args)
482{
483	struct ulfsmount *ump = VFSTOULFS(mp);
484	struct lfs *fs = ump->um_lfs;
485	int error;
486
487	KASSERT(args->qc_op == QUOTACTL_CURSORGET);
488
489	if ((fs->um_flags & ULFS_QUOTA2) == 0)
490		return EOPNOTSUPP;
491
492	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
493	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
494	if (error)
495		return error;
496
497#ifdef LFS_QUOTA2
498	if (fs->um_flags & ULFS_QUOTA2) {
499		struct quotakcursor *cursor = args->u.cursorget.qc_cursor;
500		struct quotakey *keys = args->u.cursorget.qc_keys;
501		struct quotaval *vals = args->u.cursorget.qc_vals;
502		unsigned maxnum = args->u.cursorget.qc_maxnum;
503		unsigned *ret = args->u.cursorget.qc_ret;
504
505		error = lfsquota2_handle_cmd_cursorget(ump, cursor, keys, vals,
506		    maxnum, ret);
507	} else
508#endif
509		panic("quota_handle_cmd_cursorget: no support ?");
510
511	return error;
512}
513
514static int
515quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l,
516    struct quotactl_args *args)
517{
518#ifdef LFS_QUOTA2
519	struct ulfsmount *ump = VFSTOULFS(mp);
520	struct lfs *fs = ump->um_lfs;
521	struct quotakcursor *cursor;
522#endif
523	int error;
524
525	KASSERT(args->qc_op == QUOTACTL_CURSOROPEN);
526
527	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
528	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
529	if (error)
530		return error;
531
532#ifdef LFS_QUOTA2
533	if (fs->um_flags & ULFS_QUOTA2) {
534		cursor = args->u.cursoropen.qc_cursor;
535		error = lfsquota2_handle_cmd_cursoropen(ump, cursor);
536	} else
537#endif
538		error = EOPNOTSUPP;
539
540	return error;
541}
542
543static int
544quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l,
545    struct quotactl_args *args)
546{
547#ifdef LFS_QUOTA2
548	struct ulfsmount *ump = VFSTOULFS(mp);
549	struct lfs *fs = ump->um_lfs;
550#endif
551	int error;
552
553	KASSERT(args->qc_op == QUOTACTL_CURSORCLOSE);
554
555	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
556	    KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
557	if (error)
558		return error;
559
560#ifdef LFS_QUOTA2
561	if (fs->um_flags & ULFS_QUOTA2) {
562		struct quotakcursor *cursor = args->u.cursorclose.qc_cursor;
563		error = lfsquota2_handle_cmd_cursorclose(ump, cursor);
564	} else
565#endif
566		error = EOPNOTSUPP;
567
568	return error;
569}
570
571static int
572quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l,
573    struct quotactl_args *args)
574{
575#ifdef LFS_QUOTA2
576	struct ulfsmount *ump = VFSTOULFS(mp);
577	struct lfs *fs = ump->um_lfs;
578#endif
579	int error;
580
581	KASSERT(args->qc_op == QUOTACTL_CURSORSKIPIDTYPE);
582
583#ifdef LFS_QUOTA2
584	if (fs->um_flags & ULFS_QUOTA2) {
585		struct quotakcursor *cursor = args->u.cursorskipidtype.qc_cursor;
586		int idtype = args->u.cursorskipidtype.qc_idtype;
587		error = lfsquota2_handle_cmd_cursorskipidtype(ump, cursor, idtype);
588	} else
589#endif
590		error = EOPNOTSUPP;
591
592	return error;
593}
594
595static int
596quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l,
597    struct quotactl_args *args)
598{
599#ifdef LFS_QUOTA2
600	struct ulfsmount *ump = VFSTOULFS(mp);
601	struct lfs *fs = ump->um_lfs;
602#endif
603	int error;
604
605	KASSERT(args->qc_op == QUOTACTL_CURSORATEND);
606
607#ifdef LFS_QUOTA2
608	if (fs->um_flags & ULFS_QUOTA2) {
609		struct quotakcursor *cursor = args->u.cursoratend.qc_cursor;
610		int *ret = args->u.cursoratend.qc_ret;
611		error = lfsquota2_handle_cmd_cursoratend(ump, cursor, ret);
612	} else
613#endif
614		error = EOPNOTSUPP;
615
616	return error;
617}
618
619static int
620quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l,
621    struct quotactl_args *args)
622{
623#ifdef LFS_QUOTA2
624	struct ulfsmount *ump = VFSTOULFS(mp);
625	struct lfs *fs = ump->um_lfs;
626#endif
627	int error;
628
629	KASSERT(args->qc_op == QUOTACTL_CURSORREWIND);
630
631#ifdef LFS_QUOTA2
632	if (fs->um_flags & ULFS_QUOTA2) {
633		struct quotakcursor *cursor = args->u.cursorrewind.qc_cursor;
634		error = lfsquota2_handle_cmd_cursorrewind(ump, cursor);
635	} else
636#endif
637		error = EOPNOTSUPP;
638
639	return error;
640}
641
642static int
643quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
644    struct quotactl_args *args)
645{
646	struct ulfsmount *ump = VFSTOULFS(mp);
647	struct lfs *fs = ump->um_lfs;
648	int error;
649
650	KASSERT(args->qc_op == QUOTACTL_QUOTAON);
651
652	if ((fs->um_flags & ULFS_QUOTA2) != 0)
653		return EBUSY;
654
655	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
656	    KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
657	if (error != 0) {
658		return error;
659	}
660#ifdef LFS_QUOTA
661	int idtype = args->u.quotaon.qc_idtype;
662	const char *qfile = args->u.quotaon.qc_quotafile;
663	error = lfsquota1_handle_cmd_quotaon(l, ump, idtype, qfile);
664#else
665	error = EOPNOTSUPP;
666#endif
667
668	return error;
669}
670
671static int
672quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
673    struct quotactl_args *args)
674{
675	struct ulfsmount *ump = VFSTOULFS(mp);
676	struct lfs *fs = ump->um_lfs;
677	int error;
678
679	KASSERT(args->qc_op == QUOTACTL_QUOTAOFF);
680
681	if ((fs->um_flags & ULFS_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 LFS_QUOTA
690	int idtype = args->u.quotaoff.qc_idtype;
691	error = lfsquota1_handle_cmd_quotaoff(l, ump, idtype);
692#else
693	error = EOPNOTSUPP;
694#endif
695
696	return error;
697}
698
699/*
700 * Initialize the quota system.
701 */
702void
703lfs_dqinit(void)
704{
705
706	mutex_init(&lfs_dqlock, MUTEX_DEFAULT, IPL_NONE);
707	cv_init(&lfs_dqcv, "quota");
708	dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
709	dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "lfsdq",
710	    NULL, IPL_NONE, NULL, NULL, NULL);
711}
712
713void
714lfs_dqreinit(void)
715{
716	struct dquot *dq;
717	struct dqhashhead *oldhash, *hash;
718	struct vnode *dqvp;
719	u_long oldmask, mask, hashval;
720	int i;
721
722	hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
723	mutex_enter(&lfs_dqlock);
724	oldhash = dqhashtbl;
725	oldmask = dqhash;
726	dqhashtbl = hash;
727	dqhash = mask;
728	for (i = 0; i <= oldmask; i++) {
729		while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
730			dqvp = dq->dq_ump->um_quotas[dq->dq_type];
731			LIST_REMOVE(dq, dq_hash);
732			hashval = DQHASH(dqvp, dq->dq_id);
733			LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
734		}
735	}
736	mutex_exit(&lfs_dqlock);
737	hashdone(oldhash, HASH_LIST, oldmask);
738}
739
740/*
741 * Free resources held by quota system.
742 */
743void
744lfs_dqdone(void)
745{
746
747	pool_cache_destroy(dquot_cache);
748	hashdone(dqhashtbl, HASH_LIST, dqhash);
749	cv_destroy(&lfs_dqcv);
750	mutex_destroy(&lfs_dqlock);
751}
752
753/*
754 * Set up the quotas for an inode.
755 *
756 * This routine completely defines the semantics of quotas.
757 * If other criteria want to be used to establish quotas, the
758 * ULFS_MAXQUOTAS value in quotas.h should be increased, and the
759 * additional dquots set up here.
760 */
761int
762lfs_getinoquota(struct inode *ip)
763{
764	struct ulfsmount *ump = ip->i_ump;
765	//struct lfs *fs = ump->um_lfs; // notyet
766	struct vnode *vp = ITOV(ip);
767	int i, error;
768	u_int32_t ino_ids[ULFS_MAXQUOTAS];
769
770	/*
771	 * To avoid deadlocks never update quotas for quota files
772	 * on the same file system
773	 */
774	for (i = 0; i < ULFS_MAXQUOTAS; i++)
775		if (vp == ump->um_quotas[i])
776			return 0;
777
778	ino_ids[ULFS_USRQUOTA] = ip->i_uid;
779	ino_ids[ULFS_GRPQUOTA] = ip->i_gid;
780	for (i = 0; i < ULFS_MAXQUOTAS; i++) {
781		/*
782		 * If the file id changed the quota needs update.
783		 */
784		if (ip->i_dquot[i] != NODQUOT &&
785		    ip->i_dquot[i]->dq_id != ino_ids[i]) {
786			lfs_dqrele(ITOV(ip), ip->i_dquot[i]);
787			ip->i_dquot[i] = NODQUOT;
788		}
789		/*
790		 * Set up the quota based on file id.
791		 * ENODEV means that quotas are not enabled.
792		 */
793		if (ip->i_dquot[i] == NODQUOT &&
794		    (error = lfs_dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
795		    error != ENODEV)
796			return (error);
797	}
798	return 0;
799}
800
801/*
802 * Obtain a dquot structure for the specified identifier and quota file
803 * reading the information from the file if necessary.
804 */
805int
806lfs_dqget(struct vnode *vp, u_long id, struct ulfsmount *ump, int type,
807    struct dquot **dqp)
808{
809	struct lfs *fs = ump->um_lfs;
810	struct dquot *dq, *ndq;
811	struct dqhashhead *dqh;
812	struct vnode *dqvp;
813	int error = 0; /* XXX gcc */
814
815	/* Lock to see an up to date value for QTF_CLOSING. */
816	mutex_enter(&lfs_dqlock);
817	if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0) {
818		mutex_exit(&lfs_dqlock);
819		*dqp = NODQUOT;
820		return (ENODEV);
821	}
822	dqvp = ump->um_quotas[type];
823#ifdef LFS_QUOTA
824	if (fs->um_flags & ULFS_QUOTA) {
825		if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
826			mutex_exit(&lfs_dqlock);
827			*dqp = NODQUOT;
828			return (ENODEV);
829		}
830	}
831#endif
832#ifdef LFS_QUOTA2
833	if (fs->um_flags & ULFS_QUOTA2) {
834		if (dqvp == NULLVP) {
835			mutex_exit(&lfs_dqlock);
836			*dqp = NODQUOT;
837			return (ENODEV);
838		}
839	}
840#endif
841	KASSERT(dqvp != vp);
842	/*
843	 * Check the cache first.
844	 */
845	dqh = &dqhashtbl[DQHASH(dqvp, id)];
846	LIST_FOREACH(dq, dqh, dq_hash) {
847		if (dq->dq_id != id ||
848		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
849			continue;
850		KASSERT(dq->dq_cnt > 0);
851		lfs_dqref(dq);
852		mutex_exit(&lfs_dqlock);
853		*dqp = dq;
854		return (0);
855	}
856	/*
857	 * Not in cache, allocate a new one.
858	 */
859	mutex_exit(&lfs_dqlock);
860	ndq = pool_cache_get(dquot_cache, PR_WAITOK);
861	/*
862	 * Initialize the contents of the dquot structure.
863	 */
864	memset((char *)ndq, 0, sizeof *ndq);
865	ndq->dq_flags = 0;
866	ndq->dq_id = id;
867	ndq->dq_ump = ump;
868	ndq->dq_type = type;
869	mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
870	mutex_enter(&lfs_dqlock);
871	dqh = &dqhashtbl[DQHASH(dqvp, id)];
872	LIST_FOREACH(dq, dqh, dq_hash) {
873		if (dq->dq_id != id ||
874		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
875			continue;
876		/*
877		 * Another thread beat us allocating this dquot.
878		 */
879		KASSERT(dq->dq_cnt > 0);
880		lfs_dqref(dq);
881		mutex_exit(&lfs_dqlock);
882		mutex_destroy(&ndq->dq_interlock);
883		pool_cache_put(dquot_cache, ndq);
884		*dqp = dq;
885		return 0;
886	}
887	dq = ndq;
888	LIST_INSERT_HEAD(dqh, dq, dq_hash);
889	lfs_dqref(dq);
890	mutex_enter(&dq->dq_interlock);
891	mutex_exit(&lfs_dqlock);
892#ifdef LFS_QUOTA
893	if (fs->um_flags & ULFS_QUOTA)
894		error = lfs_dq1get(dqvp, id, ump, type, dq);
895#endif
896#ifdef LFS_QUOTA2
897	if (fs->um_flags & ULFS_QUOTA2)
898		error = lfs_dq2get(dqvp, id, ump, type, dq);
899#endif
900	/*
901	 * I/O error in reading quota file, release
902	 * quota structure and reflect problem to caller.
903	 */
904	if (error) {
905		mutex_enter(&lfs_dqlock);
906		LIST_REMOVE(dq, dq_hash);
907		mutex_exit(&lfs_dqlock);
908		mutex_exit(&dq->dq_interlock);
909		lfs_dqrele(vp, dq);
910		*dqp = NODQUOT;
911		return (error);
912	}
913	mutex_exit(&dq->dq_interlock);
914	*dqp = dq;
915	return (0);
916}
917
918/*
919 * Obtain a reference to a dquot.
920 */
921void
922lfs_dqref(struct dquot *dq)
923{
924
925	KASSERT(mutex_owned(&lfs_dqlock));
926	dq->dq_cnt++;
927	KASSERT(dq->dq_cnt > 0);
928}
929
930/*
931 * Release a reference to a dquot.
932 */
933void
934lfs_dqrele(struct vnode *vp, struct dquot *dq)
935{
936
937	if (dq == NODQUOT)
938		return;
939	mutex_enter(&dq->dq_interlock);
940	for (;;) {
941		mutex_enter(&lfs_dqlock);
942		if (dq->dq_cnt > 1) {
943			dq->dq_cnt--;
944			mutex_exit(&lfs_dqlock);
945			mutex_exit(&dq->dq_interlock);
946			return;
947		}
948		if ((dq->dq_flags & DQ_MOD) == 0)
949			break;
950		mutex_exit(&lfs_dqlock);
951#ifdef LFS_QUOTA
952		if (dq->dq_ump->um_lfs->um_flags & ULFS_QUOTA)
953			(void) lfs_dq1sync(vp, dq);
954#endif
955#ifdef LFS_QUOTA2
956		if (dq->dq_ump->um_lfs->um_flags & ULFS_QUOTA2)
957			(void) lfs_dq2sync(vp, dq);
958#endif
959	}
960	KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
961	LIST_REMOVE(dq, dq_hash);
962	mutex_exit(&lfs_dqlock);
963	mutex_exit(&dq->dq_interlock);
964	mutex_destroy(&dq->dq_interlock);
965	pool_cache_put(dquot_cache, dq);
966}
967
968int
969lfs_qsync(struct mount *mp)
970{
971	struct ulfsmount *ump = VFSTOULFS(mp);
972	struct lfs *fs = ump->um_lfs;
973
974	/* avoid compiler warning when quotas aren't enabled */
975	(void)ump;
976	(void)fs;
977
978#ifdef LFS_QUOTA
979	if (fs->um_flags & ULFS_QUOTA)
980		return lfs_q1sync(mp);
981#endif
982#ifdef LFS_QUOTA2
983	if (fs->um_flags & ULFS_QUOTA2)
984		return lfs_q2sync(mp);
985#endif
986	return 0;
987}
988
989#ifdef DIAGNOSTIC
990/*
991 * Check the hash chains for stray dquot's.
992 */
993void
994lfs_dqflush(struct vnode *vp)
995{
996	struct dquot *dq;
997	int i;
998
999	mutex_enter(&lfs_dqlock);
1000	for (i = 0; i <= dqhash; i++)
1001		LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
1002			KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
1003	mutex_exit(&lfs_dqlock);
1004}
1005#endif
1006