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