1/* $NetBSD: ufs_quota.c,v 1.117 2014/06/28 22:27:51 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.117 2014/06/28 22:27:51 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
60kmutex_t dqlock;
61kcondvar_t dqcv;
62const 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)
69static LIST_HEAD(dqhashhead, dquot) *dqhashtbl;
70static u_long dqhash;
71static pool_cache_t dquot_cache;
72
73
74static int quota_handle_cmd_stat(struct mount *, struct lwp *,
75 struct quotactl_args *args);
76static int quota_handle_cmd_idtypestat(struct mount *, struct lwp *,
77 struct quotactl_args *args);
78static int quota_handle_cmd_objtypestat(struct mount *, struct lwp *,
79 struct quotactl_args *args);
80static int quota_handle_cmd_get(struct mount *, struct lwp *,
81 struct quotactl_args *args);
82static int quota_handle_cmd_put(struct mount *, struct lwp *,
83 struct quotactl_args *args);
84static int quota_handle_cmd_cursorget(struct mount *, struct lwp *,
85 struct quotactl_args *args);
86static int quota_handle_cmd_del(struct mount *, struct lwp *,
87 struct quotactl_args *args);
88static int quota_handle_cmd_quotaon(struct mount *, struct lwp *,
89 struct quotactl_args *args);
90static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *,
91 struct quotactl_args *args);
92static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *,
93 struct quotactl_args *args);
94static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *,
95 struct quotactl_args *args);
96static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *,
97 struct quotactl_args *args);
98static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *,
99 struct quotactl_args *args);
100static 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 */
106void
107ufsquota_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 */
118void
119ufsquota_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 */
132int
133chkdq(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 */
153int
154chkiq(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
170int
171quota_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
226static int
227quota_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
264static int
265quota_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
297static int
298quota_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 ? */
335static int
336quota_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
344static int
345quota_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
381static int
382quota_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
429static int
430quota_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
472static int
473quota_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
506static int
507quota_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
533static int
534quota_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
560static int
561quota_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
583static int
584quota_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
606static int
607quota_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
628static int
629quota_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
656static int
657quota_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 */
686void
687dqinit(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
697void
698dqreinit(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 */
727void
728dqdone(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 */
745int
746getinoquota(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 */
788int
789dqget(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 */
903void
904dqref(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 */
915void
916dqrele(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
950int
951qsync(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 */
969void
970dqflush(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