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