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