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