ufs_quota.c revision 1.112 1 /* $NetBSD: ufs_quota.c,v 1.112 2012/09/09 04:27:49 manu 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.112 2012/09/09 04:27:49 manu 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_delete(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
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
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
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
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
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_DELETE:
202 error = quota_handle_cmd_delete(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
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
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
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
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
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
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
430 quota_handle_cmd_delete(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_DELETE);
439 qk = args->u.delete.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_delete(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
473 quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l,
474 struct quotactl_args *args)
475 {
476 struct ufsmount *ump = VFSTOUFS(mp);
477 struct quotakcursor *cursor;
478 struct quotakey *keys;
479 struct quotaval *vals;
480 unsigned maxnum;
481 unsigned *ret;
482 int error;
483
484 KASSERT(args->qc_op == QUOTACTL_CURSORGET);
485 cursor = args->u.cursorget.qc_cursor;
486 keys = args->u.cursorget.qc_keys;
487 vals = args->u.cursorget.qc_vals;
488 maxnum = args->u.cursorget.qc_maxnum;
489 ret = args->u.cursorget.qc_ret;
490
491 if ((ump->um_flags & UFS_QUOTA2) == 0)
492 return EOPNOTSUPP;
493
494 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
495 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
496 if (error)
497 return error;
498
499 #ifdef QUOTA2
500 if (ump->um_flags & UFS_QUOTA2) {
501 error = quota2_handle_cmd_cursorget(ump, cursor, keys, vals,
502 maxnum, ret);
503 } else
504 #endif
505 panic("quota_handle_cmd_cursorget: no support ?");
506
507 return error;
508 }
509
510 static int
511 quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l,
512 struct quotactl_args *args)
513 {
514 #ifdef QUOTA2
515 struct ufsmount *ump = VFSTOUFS(mp);
516 #endif
517 struct quotakcursor *cursor;
518 int error;
519
520 KASSERT(args->qc_op == QUOTACTL_CURSOROPEN);
521 cursor = args->u.cursoropen.qc_cursor;
522
523 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
524 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
525 if (error)
526 return error;
527
528 #ifdef QUOTA2
529 if (ump->um_flags & UFS_QUOTA2) {
530 error = quota2_handle_cmd_cursoropen(ump, cursor);
531 } else
532 #endif
533 error = EOPNOTSUPP;
534
535 return error;
536 }
537
538 static int
539 quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l,
540 struct quotactl_args *args)
541 {
542 #ifdef QUOTA2
543 struct ufsmount *ump = VFSTOUFS(mp);
544 #endif
545 struct quotakcursor *cursor;
546 int error;
547
548 KASSERT(args->qc_op == QUOTACTL_CURSORCLOSE);
549 cursor = args->u.cursorclose.qc_cursor;
550
551 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
552 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
553 if (error)
554 return error;
555
556 #ifdef QUOTA2
557 if (ump->um_flags & UFS_QUOTA2) {
558 error = quota2_handle_cmd_cursorclose(ump, cursor);
559 } else
560 #endif
561 error = EOPNOTSUPP;
562
563 return error;
564 }
565
566 static int
567 quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l,
568 struct quotactl_args *args)
569 {
570 #ifdef QUOTA2
571 struct ufsmount *ump = VFSTOUFS(mp);
572 #endif
573 struct quotakcursor *cursor;
574 int idtype;
575 int error;
576
577 KASSERT(args->qc_op == QUOTACTL_CURSORSKIPIDTYPE);
578 cursor = args->u.cursorskipidtype.qc_cursor;
579 idtype = args->u.cursorskipidtype.qc_idtype;
580
581 #ifdef QUOTA2
582 if (ump->um_flags & UFS_QUOTA2) {
583 error = quota2_handle_cmd_cursorskipidtype(ump, cursor, idtype);
584 } else
585 #endif
586 error = EOPNOTSUPP;
587
588 return error;
589 }
590
591 static int
592 quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l,
593 struct quotactl_args *args)
594 {
595 #ifdef QUOTA2
596 struct ufsmount *ump = VFSTOUFS(mp);
597 #endif
598 struct quotakcursor *cursor;
599 int *ret;
600 int error;
601
602 KASSERT(args->qc_op == QUOTACTL_CURSORATEND);
603 cursor = args->u.cursoratend.qc_cursor;
604 ret = args->u.cursoratend.qc_ret;
605
606 #ifdef QUOTA2
607 if (ump->um_flags & UFS_QUOTA2) {
608 error = quota2_handle_cmd_cursoratend(ump, cursor, ret);
609 } else
610 #endif
611 error = EOPNOTSUPP;
612
613 return error;
614 }
615
616 static int
617 quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l,
618 struct quotactl_args *args)
619 {
620 #ifdef QUOTA2
621 struct ufsmount *ump = VFSTOUFS(mp);
622 #endif
623 struct quotakcursor *cursor;
624 int error;
625
626 KASSERT(args->qc_op == QUOTACTL_CURSORREWIND);
627 cursor = args->u.cursorrewind.qc_cursor;
628
629 #ifdef QUOTA2
630 if (ump->um_flags & UFS_QUOTA2) {
631 error = quota2_handle_cmd_cursorrewind(ump, cursor);
632 } else
633 #endif
634 error = EOPNOTSUPP;
635
636 return error;
637 }
638
639 static int
640 quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
641 struct quotactl_args *args)
642 {
643 struct ufsmount *ump = VFSTOUFS(mp);
644 int idtype;
645 const char *qfile;
646 int error;
647
648 KASSERT(args->qc_op == QUOTACTL_QUOTAON);
649 idtype = args->u.quotaon.qc_idtype;
650 qfile = args->u.quotaon.qc_quotafile;
651
652 if ((ump->um_flags & UFS_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 QUOTA
661 error = quota1_handle_cmd_quotaon(l, ump, idtype, qfile);
662 #else
663 error = EOPNOTSUPP;
664 #endif
665
666 return error;
667 }
668
669 static int
670 quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
671 struct quotactl_args *args)
672 {
673 struct ufsmount *ump = VFSTOUFS(mp);
674 int idtype;
675 int error;
676
677 KASSERT(args->qc_op == QUOTACTL_QUOTAOFF);
678 idtype = args->u.quotaoff.qc_idtype;
679
680 if ((ump->um_flags & UFS_QUOTA2) != 0)
681 return EOPNOTSUPP;
682
683 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
684 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
685 if (error != 0) {
686 return error;
687 }
688 #ifdef QUOTA
689 error = quota1_handle_cmd_quotaoff(l, ump, idtype);
690 #else
691 error = EOPNOTSUPP;
692 #endif
693
694 return error;
695 }
696
697 /*
698 * Initialize the quota system.
699 */
700 void
701 dqinit(void)
702 {
703
704 mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE);
705 cv_init(&dqcv, "quota");
706 dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
707 dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq",
708 NULL, IPL_NONE, NULL, NULL, NULL);
709 }
710
711 void
712 dqreinit(void)
713 {
714 struct dquot *dq;
715 struct dqhashhead *oldhash, *hash;
716 struct vnode *dqvp;
717 u_long oldmask, mask, hashval;
718 int i;
719
720 hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
721 mutex_enter(&dqlock);
722 oldhash = dqhashtbl;
723 oldmask = dqhash;
724 dqhashtbl = hash;
725 dqhash = mask;
726 for (i = 0; i <= oldmask; i++) {
727 while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
728 dqvp = dq->dq_ump->um_quotas[dq->dq_type];
729 LIST_REMOVE(dq, dq_hash);
730 hashval = DQHASH(dqvp, dq->dq_id);
731 LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
732 }
733 }
734 mutex_exit(&dqlock);
735 hashdone(oldhash, HASH_LIST, oldmask);
736 }
737
738 /*
739 * Free resources held by quota system.
740 */
741 void
742 dqdone(void)
743 {
744
745 pool_cache_destroy(dquot_cache);
746 hashdone(dqhashtbl, HASH_LIST, dqhash);
747 cv_destroy(&dqcv);
748 mutex_destroy(&dqlock);
749 }
750
751 /*
752 * Set up the quotas for an inode.
753 *
754 * This routine completely defines the semantics of quotas.
755 * If other criterion want to be used to establish quotas, the
756 * MAXQUOTAS value in quotas.h should be increased, and the
757 * additional dquots set up here.
758 */
759 int
760 getinoquota(struct inode *ip)
761 {
762 struct ufsmount *ump = ip->i_ump;
763 struct vnode *vp = ITOV(ip);
764 int i, error;
765 u_int32_t ino_ids[MAXQUOTAS];
766
767 /*
768 * To avoid deadlocks never update quotas for quota files
769 * on the same file system
770 */
771 for (i = 0; i < MAXQUOTAS; i++)
772 if (vp == ump->um_quotas[i])
773 return 0;
774
775 ino_ids[USRQUOTA] = ip->i_uid;
776 ino_ids[GRPQUOTA] = ip->i_gid;
777 for (i = 0; i < MAXQUOTAS; i++) {
778 /*
779 * If the file id changed the quota needs update.
780 */
781 if (ip->i_dquot[i] != NODQUOT &&
782 ip->i_dquot[i]->dq_id != ino_ids[i]) {
783 dqrele(ITOV(ip), ip->i_dquot[i]);
784 ip->i_dquot[i] = NODQUOT;
785 }
786 /*
787 * Set up the quota based on file id.
788 * ENODEV means that quotas are not enabled.
789 */
790 if (ip->i_dquot[i] == NODQUOT &&
791 (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
792 error != ENODEV)
793 return (error);
794 }
795 return 0;
796 }
797
798 /*
799 * Obtain a dquot structure for the specified identifier and quota file
800 * reading the information from the file if necessary.
801 */
802 int
803 dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
804 struct dquot **dqp)
805 {
806 struct dquot *dq, *ndq;
807 struct dqhashhead *dqh;
808 struct vnode *dqvp;
809 int error = 0; /* XXX gcc */
810
811 /* Lock to see an up to date value for QTF_CLOSING. */
812 mutex_enter(&dqlock);
813 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) {
814 mutex_exit(&dqlock);
815 *dqp = NODQUOT;
816 return (ENODEV);
817 }
818 dqvp = ump->um_quotas[type];
819 #ifdef QUOTA
820 if (ump->um_flags & UFS_QUOTA) {
821 if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
822 mutex_exit(&dqlock);
823 *dqp = NODQUOT;
824 return (ENODEV);
825 }
826 }
827 #endif
828 #ifdef QUOTA2
829 if (ump->um_flags & UFS_QUOTA2) {
830 if (dqvp == NULLVP) {
831 mutex_exit(&dqlock);
832 *dqp = NODQUOT;
833 return (ENODEV);
834 }
835 }
836 #endif
837 KASSERT(dqvp != vp);
838 /*
839 * Check the cache first.
840 */
841 dqh = &dqhashtbl[DQHASH(dqvp, id)];
842 LIST_FOREACH(dq, dqh, dq_hash) {
843 if (dq->dq_id != id ||
844 dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
845 continue;
846 KASSERT(dq->dq_cnt > 0);
847 dqref(dq);
848 mutex_exit(&dqlock);
849 *dqp = dq;
850 return (0);
851 }
852 /*
853 * Not in cache, allocate a new one.
854 */
855 mutex_exit(&dqlock);
856 ndq = pool_cache_get(dquot_cache, PR_WAITOK);
857 /*
858 * Initialize the contents of the dquot structure.
859 */
860 memset((char *)ndq, 0, sizeof *ndq);
861 ndq->dq_flags = 0;
862 ndq->dq_id = id;
863 ndq->dq_ump = ump;
864 ndq->dq_type = type;
865 mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
866 mutex_enter(&dqlock);
867 dqh = &dqhashtbl[DQHASH(dqvp, id)];
868 LIST_FOREACH(dq, dqh, dq_hash) {
869 if (dq->dq_id != id ||
870 dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
871 continue;
872 /*
873 * Another thread beat us allocating this dquot.
874 */
875 KASSERT(dq->dq_cnt > 0);
876 dqref(dq);
877 mutex_exit(&dqlock);
878 mutex_destroy(&ndq->dq_interlock);
879 pool_cache_put(dquot_cache, ndq);
880 *dqp = dq;
881 return 0;
882 }
883 dq = ndq;
884 LIST_INSERT_HEAD(dqh, dq, dq_hash);
885 dqref(dq);
886 mutex_enter(&dq->dq_interlock);
887 mutex_exit(&dqlock);
888 #ifdef QUOTA
889 if (ump->um_flags & UFS_QUOTA)
890 error = dq1get(dqvp, id, ump, type, dq);
891 #endif
892 #ifdef QUOTA2
893 if (ump->um_flags & UFS_QUOTA2)
894 error = dq2get(dqvp, id, ump, type, dq);
895 #endif
896 /*
897 * I/O error in reading quota file, release
898 * quota structure and reflect problem to caller.
899 */
900 if (error) {
901 mutex_enter(&dqlock);
902 LIST_REMOVE(dq, dq_hash);
903 mutex_exit(&dqlock);
904 mutex_exit(&dq->dq_interlock);
905 dqrele(vp, dq);
906 *dqp = NODQUOT;
907 return (error);
908 }
909 mutex_exit(&dq->dq_interlock);
910 *dqp = dq;
911 return (0);
912 }
913
914 /*
915 * Obtain a reference to a dquot.
916 */
917 void
918 dqref(struct dquot *dq)
919 {
920
921 KASSERT(mutex_owned(&dqlock));
922 dq->dq_cnt++;
923 KASSERT(dq->dq_cnt > 0);
924 }
925
926 /*
927 * Release a reference to a dquot.
928 */
929 void
930 dqrele(struct vnode *vp, struct dquot *dq)
931 {
932
933 if (dq == NODQUOT)
934 return;
935 mutex_enter(&dq->dq_interlock);
936 for (;;) {
937 mutex_enter(&dqlock);
938 if (dq->dq_cnt > 1) {
939 dq->dq_cnt--;
940 mutex_exit(&dqlock);
941 mutex_exit(&dq->dq_interlock);
942 return;
943 }
944 if ((dq->dq_flags & DQ_MOD) == 0)
945 break;
946 mutex_exit(&dqlock);
947 #ifdef QUOTA
948 if (dq->dq_ump->um_flags & UFS_QUOTA)
949 (void) dq1sync(vp, dq);
950 #endif
951 #ifdef QUOTA2
952 if (dq->dq_ump->um_flags & UFS_QUOTA2)
953 (void) dq2sync(vp, dq);
954 #endif
955 }
956 KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
957 LIST_REMOVE(dq, dq_hash);
958 mutex_exit(&dqlock);
959 mutex_exit(&dq->dq_interlock);
960 mutex_destroy(&dq->dq_interlock);
961 pool_cache_put(dquot_cache, dq);
962 }
963
964 int
965 qsync(struct mount *mp)
966 {
967 struct ufsmount *ump = VFSTOUFS(mp);
968 #ifdef QUOTA
969 if (ump->um_flags & UFS_QUOTA)
970 return q1sync(mp);
971 #endif
972 #ifdef QUOTA2
973 if (ump->um_flags & UFS_QUOTA2)
974 return q2sync(mp);
975 #endif
976 return 0;
977 }
978
979 #ifdef DIAGNOSTIC
980 /*
981 * Check the hash chains for stray dquot's.
982 */
983 void
984 dqflush(struct vnode *vp)
985 {
986 struct dquot *dq;
987 int i;
988
989 mutex_enter(&dqlock);
990 for (i = 0; i <= dqhash; i++)
991 LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
992 KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
993 mutex_exit(&dqlock);
994 }
995 #endif
996