ulfs_quota.c revision 1.7 1 /* $NetBSD: ulfs_quota.c,v 1.7 2013/07/28 01:10:49 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.7 2013/07/28 01:10:49 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 lfs_dqlock;
62 kcondvar_t lfs_dqcv;
63 const char *lfs_quotatypes[ULFS_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 ulfsquota_init(struct inode *ip)
109 {
110 int i;
111
112 for (i = 0; i < ULFS_MAXQUOTAS; i++)
113 ip->i_dquot[i] = NODQUOT;
114 }
115
116 /*
117 * Release the quota fields from an inode.
118 */
119 void
120 ulfsquota_free(struct inode *ip)
121 {
122 int i;
123
124 for (i = 0; i < ULFS_MAXQUOTAS; i++) {
125 lfs_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 lfs_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 LFS_QUOTA
141 if (ip->i_lfs->um_flags & ULFS_QUOTA)
142 return lfs_chkdq1(ip, change, cred, flags);
143 #endif
144 #ifdef LFS_QUOTA2
145 if (ip->i_lfs->um_flags & ULFS_QUOTA2)
146 return lfs_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 lfs_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 LFS_QUOTA
161 if (ip->i_lfs->um_flags & ULFS_QUOTA)
162 return lfs_chkiq1(ip, change, cred, flags);
163 #endif
164 #ifdef LFS_QUOTA2
165 if (ip->i_lfs->um_flags & ULFS_QUOTA2)
166 return lfs_chkiq2(ip, change, cred, flags);
167 #endif
168 return 0;
169 }
170
171 int
172 lfsquota_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 ulfsmount *ump = VFSTOULFS(mp);
232 struct lfs *fs = ump->um_lfs;
233 struct quotastat *info;
234
235 KASSERT(args->qc_op == QUOTACTL_STAT);
236 info = args->u.stat.qc_info;
237
238 if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
239 return EOPNOTSUPP;
240
241 #ifdef LFS_QUOTA
242 if (fs->um_flags & ULFS_QUOTA) {
243 strcpy(info->qs_implname, "lfs quota v1");
244 info->qs_numidtypes = ULFS_MAXQUOTAS;
245 /* XXX no define for this */
246 info->qs_numobjtypes = 2;
247 info->qs_restrictions = 0;
248 info->qs_restrictions |= QUOTA_RESTRICT_NEEDSQUOTACHECK;
249 info->qs_restrictions |= QUOTA_RESTRICT_UNIFORMGRACE;
250 info->qs_restrictions |= QUOTA_RESTRICT_32BIT;
251 } else
252 #endif
253 #ifdef LFS_QUOTA2
254 if (fs->um_flags & ULFS_QUOTA2) {
255 strcpy(info->qs_implname, "lfs quota v2");
256 info->qs_numidtypes = ULFS_MAXQUOTAS;
257 info->qs_numobjtypes = N_QL;
258 info->qs_restrictions = 0;
259 } else
260 #endif
261 return EOPNOTSUPP;
262
263 return 0;
264 }
265
266 static int
267 quota_handle_cmd_idtypestat(struct mount *mp, struct lwp *l,
268 struct quotactl_args *args)
269 {
270 struct ulfsmount *ump = VFSTOULFS(mp);
271 struct lfs *fs = ump->um_lfs;
272 int idtype;
273 struct quotaidtypestat *info;
274 const char *name;
275
276 KASSERT(args->qc_op == QUOTACTL_IDTYPESTAT);
277 idtype = args->u.idtypestat.qc_idtype;
278 info = args->u.idtypestat.qc_info;
279
280 if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
281 return EOPNOTSUPP;
282
283 /*
284 * These are the same for both QUOTA and QUOTA2.
285 */
286 switch (idtype) {
287 case QUOTA_IDTYPE_USER:
288 name = "user";
289 break;
290 case QUOTA_IDTYPE_GROUP:
291 name = "group";
292 break;
293 default:
294 return EINVAL;
295 }
296 strlcpy(info->qis_name, name, sizeof(info->qis_name));
297 return 0;
298 }
299
300 static int
301 quota_handle_cmd_objtypestat(struct mount *mp, struct lwp *l,
302 struct quotactl_args *args)
303 {
304 struct ulfsmount *ump = VFSTOULFS(mp);
305 struct lfs *fs = ump->um_lfs;
306 int objtype;
307 struct quotaobjtypestat *info;
308 const char *name;
309 int isbytes;
310
311 KASSERT(args->qc_op == QUOTACTL_OBJTYPESTAT);
312 objtype = args->u.objtypestat.qc_objtype;
313 info = args->u.objtypestat.qc_info;
314
315 if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
316 return EOPNOTSUPP;
317
318 /*
319 * These are the same for both QUOTA and QUOTA2.
320 */
321 switch (objtype) {
322 case QUOTA_OBJTYPE_BLOCKS:
323 name = "block";
324 isbytes = 1;
325 break;
326 case QUOTA_OBJTYPE_FILES:
327 name = "file";
328 isbytes = 0;
329 break;
330 default:
331 return EINVAL;
332 }
333 strlcpy(info->qos_name, name, sizeof(info->qos_name));
334 info->qos_isbytes = isbytes;
335 return 0;
336 }
337
338 /* XXX shouldn't all this be in kauth ? */
339 static int
340 quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {
341 /* The user can always query about his own quota. */
342 if (id == kauth_cred_geteuid(l->l_cred))
343 return 0;
344 return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
345 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL);
346 }
347
348 static int
349 quota_handle_cmd_get(struct mount *mp, struct lwp *l,
350 struct quotactl_args *args)
351 {
352 struct ulfsmount *ump = VFSTOULFS(mp);
353 struct lfs *fs = ump->um_lfs;
354 int error;
355 const struct quotakey *qk;
356 struct quotaval *qv;
357
358 KASSERT(args->qc_op == QUOTACTL_GET);
359 qk = args->u.get.qc_key;
360 qv = args->u.get.qc_val;
361
362 if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
363 return EOPNOTSUPP;
364
365 error = quota_get_auth(mp, l, qk->qk_id);
366 if (error != 0)
367 return error;
368 #ifdef LFS_QUOTA
369 if (fs->um_flags & ULFS_QUOTA) {
370 error = lfsquota1_handle_cmd_get(ump, qk, qv);
371 } else
372 #endif
373 #ifdef LFS_QUOTA2
374 if (fs->um_flags & ULFS_QUOTA2) {
375 error = lfsquota2_handle_cmd_get(ump, qk, qv);
376 } else
377 #endif
378 panic("quota_handle_cmd_get: no support ?");
379
380 if (error != 0)
381 return error;
382
383 return error;
384 }
385
386 static int
387 quota_handle_cmd_put(struct mount *mp, struct lwp *l,
388 struct quotactl_args *args)
389 {
390 struct ulfsmount *ump = VFSTOULFS(mp);
391 struct lfs *fs = ump->um_lfs;
392 const struct quotakey *qk;
393 const struct quotaval *qv;
394 id_t kauth_id;
395 int error;
396
397 KASSERT(args->qc_op == QUOTACTL_PUT);
398 qk = args->u.put.qc_key;
399 qv = args->u.put.qc_val;
400
401 if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
402 return EOPNOTSUPP;
403
404 kauth_id = qk->qk_id;
405 if (kauth_id == QUOTA_DEFAULTID) {
406 kauth_id = 0;
407 }
408
409 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
410 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
411 NULL);
412 if (error != 0) {
413 return error;
414 }
415
416 #ifdef LFS_QUOTA
417 if (fs->um_flags & ULFS_QUOTA)
418 error = lfsquota1_handle_cmd_put(ump, qk, qv);
419 else
420 #endif
421 #ifdef LFS_QUOTA2
422 if (fs->um_flags & ULFS_QUOTA2) {
423 error = lfsquota2_handle_cmd_put(ump, qk, qv);
424 } else
425 #endif
426 panic("quota_handle_cmd_get: no support ?");
427
428 if (error == ENOENT) {
429 error = 0;
430 }
431
432 return error;
433 }
434
435 static int
436 quota_handle_cmd_delete(struct mount *mp, struct lwp *l,
437 struct quotactl_args *args)
438 {
439 struct ulfsmount *ump = VFSTOULFS(mp);
440 struct lfs *fs = ump->um_lfs;
441 const struct quotakey *qk;
442 id_t kauth_id;
443 int error;
444
445 KASSERT(args->qc_op == QUOTACTL_DELETE);
446 qk = args->u.delete.qc_key;
447
448 kauth_id = qk->qk_id;
449 if (kauth_id == QUOTA_DEFAULTID) {
450 kauth_id = 0;
451 }
452
453 if ((fs->um_flags & ULFS_QUOTA2) == 0)
454 return EOPNOTSUPP;
455
456 /* avoid whitespace changes */
457 {
458 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
459 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
460 NULL);
461 if (error != 0)
462 goto err;
463 #ifdef LFS_QUOTA2
464 if (fs->um_flags & ULFS_QUOTA2) {
465 error = lfsquota2_handle_cmd_delete(ump, qk);
466 } else
467 #endif
468 panic("quota_handle_cmd_get: no support ?");
469
470 if (error && error != ENOENT)
471 goto err;
472 }
473
474 return 0;
475 err:
476 return error;
477 }
478
479 static int
480 quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l,
481 struct quotactl_args *args)
482 {
483 struct ulfsmount *ump = VFSTOULFS(mp);
484 struct lfs *fs = ump->um_lfs;
485 struct quotakcursor *cursor;
486 struct quotakey *keys;
487 struct quotaval *vals;
488 unsigned maxnum;
489 unsigned *ret;
490 int error;
491
492 KASSERT(args->qc_op == QUOTACTL_CURSORGET);
493 cursor = args->u.cursorget.qc_cursor;
494 keys = args->u.cursorget.qc_keys;
495 vals = args->u.cursorget.qc_vals;
496 maxnum = args->u.cursorget.qc_maxnum;
497 ret = args->u.cursorget.qc_ret;
498
499 if ((fs->um_flags & ULFS_QUOTA2) == 0)
500 return EOPNOTSUPP;
501
502 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
503 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
504 if (error)
505 return error;
506
507 #ifdef LFS_QUOTA2
508 if (fs->um_flags & ULFS_QUOTA2) {
509 error = lfsquota2_handle_cmd_cursorget(ump, cursor, keys, vals,
510 maxnum, ret);
511 } else
512 #endif
513 panic("quota_handle_cmd_cursorget: no support ?");
514
515 return error;
516 }
517
518 static int
519 quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l,
520 struct quotactl_args *args)
521 {
522 #ifdef LFS_QUOTA2
523 struct ulfsmount *ump = VFSTOULFS(mp);
524 struct lfs *fs = ump->um_lfs;
525 #endif
526 struct quotakcursor *cursor;
527 int error;
528
529 KASSERT(args->qc_op == QUOTACTL_CURSOROPEN);
530 cursor = args->u.cursoropen.qc_cursor;
531
532 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
533 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
534 if (error)
535 return error;
536
537 #ifdef LFS_QUOTA2
538 if (fs->um_flags & ULFS_QUOTA2) {
539 error = lfsquota2_handle_cmd_cursoropen(ump, cursor);
540 } else
541 #endif
542 error = EOPNOTSUPP;
543
544 return error;
545 }
546
547 static int
548 quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l,
549 struct quotactl_args *args)
550 {
551 #ifdef LFS_QUOTA2
552 struct ulfsmount *ump = VFSTOULFS(mp);
553 struct lfs *fs = ump->um_lfs;
554 #endif
555 struct quotakcursor *cursor;
556 int error;
557
558 KASSERT(args->qc_op == QUOTACTL_CURSORCLOSE);
559 cursor = args->u.cursorclose.qc_cursor;
560
561 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
562 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
563 if (error)
564 return error;
565
566 #ifdef LFS_QUOTA2
567 if (fs->um_flags & ULFS_QUOTA2) {
568 error = lfsquota2_handle_cmd_cursorclose(ump, cursor);
569 } else
570 #endif
571 error = EOPNOTSUPP;
572
573 return error;
574 }
575
576 static int
577 quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l,
578 struct quotactl_args *args)
579 {
580 #ifdef LFS_QUOTA2
581 struct ulfsmount *ump = VFSTOULFS(mp);
582 struct lfs *fs = ump->um_lfs;
583 #endif
584 struct quotakcursor *cursor;
585 int idtype;
586 int error;
587
588 KASSERT(args->qc_op == QUOTACTL_CURSORSKIPIDTYPE);
589 cursor = args->u.cursorskipidtype.qc_cursor;
590 idtype = args->u.cursorskipidtype.qc_idtype;
591
592 #ifdef LFS_QUOTA2
593 if (fs->um_flags & ULFS_QUOTA2) {
594 error = lfsquota2_handle_cmd_cursorskipidtype(ump, cursor, idtype);
595 } else
596 #endif
597 error = EOPNOTSUPP;
598
599 return error;
600 }
601
602 static int
603 quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l,
604 struct quotactl_args *args)
605 {
606 #ifdef LFS_QUOTA2
607 struct ulfsmount *ump = VFSTOULFS(mp);
608 struct lfs *fs = ump->um_lfs;
609 #endif
610 struct quotakcursor *cursor;
611 int *ret;
612 int error;
613
614 KASSERT(args->qc_op == QUOTACTL_CURSORATEND);
615 cursor = args->u.cursoratend.qc_cursor;
616 ret = args->u.cursoratend.qc_ret;
617
618 #ifdef LFS_QUOTA2
619 if (fs->um_flags & ULFS_QUOTA2) {
620 error = lfsquota2_handle_cmd_cursoratend(ump, cursor, ret);
621 } else
622 #endif
623 error = EOPNOTSUPP;
624
625 return error;
626 }
627
628 static int
629 quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l,
630 struct quotactl_args *args)
631 {
632 #ifdef LFS_QUOTA2
633 struct ulfsmount *ump = VFSTOULFS(mp);
634 struct lfs *fs = ump->um_lfs;
635 #endif
636 struct quotakcursor *cursor;
637 int error;
638
639 KASSERT(args->qc_op == QUOTACTL_CURSORREWIND);
640 cursor = args->u.cursorrewind.qc_cursor;
641
642 #ifdef LFS_QUOTA2
643 if (fs->um_flags & ULFS_QUOTA2) {
644 error = lfsquota2_handle_cmd_cursorrewind(ump, cursor);
645 } else
646 #endif
647 error = EOPNOTSUPP;
648
649 return error;
650 }
651
652 static int
653 quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
654 struct quotactl_args *args)
655 {
656 struct ulfsmount *ump = VFSTOULFS(mp);
657 struct lfs *fs = ump->um_lfs;
658 int idtype;
659 const char *qfile;
660 int error;
661
662 KASSERT(args->qc_op == QUOTACTL_QUOTAON);
663 idtype = args->u.quotaon.qc_idtype;
664 qfile = args->u.quotaon.qc_quotafile;
665
666 if ((fs->um_flags & ULFS_QUOTA2) != 0)
667 return EBUSY;
668
669 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
670 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
671 if (error != 0) {
672 return error;
673 }
674 #ifdef LFS_QUOTA
675 error = lfsquota1_handle_cmd_quotaon(l, ump, idtype, qfile);
676 #else
677 error = EOPNOTSUPP;
678 #endif
679
680 return error;
681 }
682
683 static int
684 quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
685 struct quotactl_args *args)
686 {
687 struct ulfsmount *ump = VFSTOULFS(mp);
688 struct lfs *fs = ump->um_lfs;
689 int idtype;
690 int error;
691
692 KASSERT(args->qc_op == QUOTACTL_QUOTAOFF);
693 idtype = args->u.quotaoff.qc_idtype;
694
695 if ((fs->um_flags & ULFS_QUOTA2) != 0)
696 return EOPNOTSUPP;
697
698 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
699 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
700 if (error != 0) {
701 return error;
702 }
703 #ifdef LFS_QUOTA
704 error = lfsquota1_handle_cmd_quotaoff(l, ump, idtype);
705 #else
706 error = EOPNOTSUPP;
707 #endif
708
709 return error;
710 }
711
712 /*
713 * Initialize the quota system.
714 */
715 void
716 lfs_dqinit(void)
717 {
718
719 mutex_init(&lfs_dqlock, MUTEX_DEFAULT, IPL_NONE);
720 cv_init(&lfs_dqcv, "quota");
721 dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
722 dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "lfsdq",
723 NULL, IPL_NONE, NULL, NULL, NULL);
724 }
725
726 void
727 lfs_dqreinit(void)
728 {
729 struct dquot *dq;
730 struct dqhashhead *oldhash, *hash;
731 struct vnode *dqvp;
732 u_long oldmask, mask, hashval;
733 int i;
734
735 hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
736 mutex_enter(&lfs_dqlock);
737 oldhash = dqhashtbl;
738 oldmask = dqhash;
739 dqhashtbl = hash;
740 dqhash = mask;
741 for (i = 0; i <= oldmask; i++) {
742 while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
743 dqvp = dq->dq_ump->um_quotas[dq->dq_type];
744 LIST_REMOVE(dq, dq_hash);
745 hashval = DQHASH(dqvp, dq->dq_id);
746 LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
747 }
748 }
749 mutex_exit(&lfs_dqlock);
750 hashdone(oldhash, HASH_LIST, oldmask);
751 }
752
753 /*
754 * Free resources held by quota system.
755 */
756 void
757 lfs_dqdone(void)
758 {
759
760 pool_cache_destroy(dquot_cache);
761 hashdone(dqhashtbl, HASH_LIST, dqhash);
762 cv_destroy(&lfs_dqcv);
763 mutex_destroy(&lfs_dqlock);
764 }
765
766 /*
767 * Set up the quotas for an inode.
768 *
769 * This routine completely defines the semantics of quotas.
770 * If other criteria want to be used to establish quotas, the
771 * ULFS_MAXQUOTAS value in quotas.h should be increased, and the
772 * additional dquots set up here.
773 */
774 int
775 lfs_getinoquota(struct inode *ip)
776 {
777 struct ulfsmount *ump = ip->i_ump;
778 //struct lfs *fs = ump->um_lfs; // notyet
779 struct vnode *vp = ITOV(ip);
780 int i, error;
781 u_int32_t ino_ids[ULFS_MAXQUOTAS];
782
783 /*
784 * To avoid deadlocks never update quotas for quota files
785 * on the same file system
786 */
787 for (i = 0; i < ULFS_MAXQUOTAS; i++)
788 if (vp == ump->um_quotas[i])
789 return 0;
790
791 ino_ids[ULFS_USRQUOTA] = ip->i_uid;
792 ino_ids[ULFS_GRPQUOTA] = ip->i_gid;
793 for (i = 0; i < ULFS_MAXQUOTAS; i++) {
794 /*
795 * If the file id changed the quota needs update.
796 */
797 if (ip->i_dquot[i] != NODQUOT &&
798 ip->i_dquot[i]->dq_id != ino_ids[i]) {
799 lfs_dqrele(ITOV(ip), ip->i_dquot[i]);
800 ip->i_dquot[i] = NODQUOT;
801 }
802 /*
803 * Set up the quota based on file id.
804 * ENODEV means that quotas are not enabled.
805 */
806 if (ip->i_dquot[i] == NODQUOT &&
807 (error = lfs_dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
808 error != ENODEV)
809 return (error);
810 }
811 return 0;
812 }
813
814 /*
815 * Obtain a dquot structure for the specified identifier and quota file
816 * reading the information from the file if necessary.
817 */
818 int
819 lfs_dqget(struct vnode *vp, u_long id, struct ulfsmount *ump, int type,
820 struct dquot **dqp)
821 {
822 struct lfs *fs = ump->um_lfs;
823 struct dquot *dq, *ndq;
824 struct dqhashhead *dqh;
825 struct vnode *dqvp;
826 int error = 0; /* XXX gcc */
827
828 /* Lock to see an up to date value for QTF_CLOSING. */
829 mutex_enter(&lfs_dqlock);
830 if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0) {
831 mutex_exit(&lfs_dqlock);
832 *dqp = NODQUOT;
833 return (ENODEV);
834 }
835 dqvp = ump->um_quotas[type];
836 #ifdef LFS_QUOTA
837 if (fs->um_flags & ULFS_QUOTA) {
838 if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
839 mutex_exit(&lfs_dqlock);
840 *dqp = NODQUOT;
841 return (ENODEV);
842 }
843 }
844 #endif
845 #ifdef LFS_QUOTA2
846 if (fs->um_flags & ULFS_QUOTA2) {
847 if (dqvp == NULLVP) {
848 mutex_exit(&lfs_dqlock);
849 *dqp = NODQUOT;
850 return (ENODEV);
851 }
852 }
853 #endif
854 KASSERT(dqvp != vp);
855 /*
856 * Check the cache first.
857 */
858 dqh = &dqhashtbl[DQHASH(dqvp, id)];
859 LIST_FOREACH(dq, dqh, dq_hash) {
860 if (dq->dq_id != id ||
861 dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
862 continue;
863 KASSERT(dq->dq_cnt > 0);
864 lfs_dqref(dq);
865 mutex_exit(&lfs_dqlock);
866 *dqp = dq;
867 return (0);
868 }
869 /*
870 * Not in cache, allocate a new one.
871 */
872 mutex_exit(&lfs_dqlock);
873 ndq = pool_cache_get(dquot_cache, PR_WAITOK);
874 /*
875 * Initialize the contents of the dquot structure.
876 */
877 memset((char *)ndq, 0, sizeof *ndq);
878 ndq->dq_flags = 0;
879 ndq->dq_id = id;
880 ndq->dq_ump = ump;
881 ndq->dq_type = type;
882 mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
883 mutex_enter(&lfs_dqlock);
884 dqh = &dqhashtbl[DQHASH(dqvp, id)];
885 LIST_FOREACH(dq, dqh, dq_hash) {
886 if (dq->dq_id != id ||
887 dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
888 continue;
889 /*
890 * Another thread beat us allocating this dquot.
891 */
892 KASSERT(dq->dq_cnt > 0);
893 lfs_dqref(dq);
894 mutex_exit(&lfs_dqlock);
895 mutex_destroy(&ndq->dq_interlock);
896 pool_cache_put(dquot_cache, ndq);
897 *dqp = dq;
898 return 0;
899 }
900 dq = ndq;
901 LIST_INSERT_HEAD(dqh, dq, dq_hash);
902 lfs_dqref(dq);
903 mutex_enter(&dq->dq_interlock);
904 mutex_exit(&lfs_dqlock);
905 #ifdef LFS_QUOTA
906 if (fs->um_flags & ULFS_QUOTA)
907 error = lfs_dq1get(dqvp, id, ump, type, dq);
908 #endif
909 #ifdef LFS_QUOTA2
910 if (fs->um_flags & ULFS_QUOTA2)
911 error = lfs_dq2get(dqvp, id, ump, type, dq);
912 #endif
913 /*
914 * I/O error in reading quota file, release
915 * quota structure and reflect problem to caller.
916 */
917 if (error) {
918 mutex_enter(&lfs_dqlock);
919 LIST_REMOVE(dq, dq_hash);
920 mutex_exit(&lfs_dqlock);
921 mutex_exit(&dq->dq_interlock);
922 lfs_dqrele(vp, dq);
923 *dqp = NODQUOT;
924 return (error);
925 }
926 mutex_exit(&dq->dq_interlock);
927 *dqp = dq;
928 return (0);
929 }
930
931 /*
932 * Obtain a reference to a dquot.
933 */
934 void
935 lfs_dqref(struct dquot *dq)
936 {
937
938 KASSERT(mutex_owned(&lfs_dqlock));
939 dq->dq_cnt++;
940 KASSERT(dq->dq_cnt > 0);
941 }
942
943 /*
944 * Release a reference to a dquot.
945 */
946 void
947 lfs_dqrele(struct vnode *vp, struct dquot *dq)
948 {
949
950 if (dq == NODQUOT)
951 return;
952 mutex_enter(&dq->dq_interlock);
953 for (;;) {
954 mutex_enter(&lfs_dqlock);
955 if (dq->dq_cnt > 1) {
956 dq->dq_cnt--;
957 mutex_exit(&lfs_dqlock);
958 mutex_exit(&dq->dq_interlock);
959 return;
960 }
961 if ((dq->dq_flags & DQ_MOD) == 0)
962 break;
963 mutex_exit(&lfs_dqlock);
964 #ifdef LFS_QUOTA
965 if (dq->dq_ump->um_lfs->um_flags & ULFS_QUOTA)
966 (void) lfs_dq1sync(vp, dq);
967 #endif
968 #ifdef LFS_QUOTA2
969 if (dq->dq_ump->um_lfs->um_flags & ULFS_QUOTA2)
970 (void) lfs_dq2sync(vp, dq);
971 #endif
972 }
973 KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
974 LIST_REMOVE(dq, dq_hash);
975 mutex_exit(&lfs_dqlock);
976 mutex_exit(&dq->dq_interlock);
977 mutex_destroy(&dq->dq_interlock);
978 pool_cache_put(dquot_cache, dq);
979 }
980
981 int
982 lfs_qsync(struct mount *mp)
983 {
984 struct ulfsmount *ump = VFSTOULFS(mp);
985 struct lfs *fs = ump->um_lfs;
986
987 /* avoid compiler warning when quotas aren't enabled */
988 (void)ump;
989 (void)fs;
990
991 #ifdef LFS_QUOTA
992 if (fs->um_flags & ULFS_QUOTA)
993 return lfs_q1sync(mp);
994 #endif
995 #ifdef LFS_QUOTA2
996 if (fs->um_flags & ULFS_QUOTA2)
997 return lfs_q2sync(mp);
998 #endif
999 return 0;
1000 }
1001
1002 #ifdef DIAGNOSTIC
1003 /*
1004 * Check the hash chains for stray dquot's.
1005 */
1006 void
1007 lfs_dqflush(struct vnode *vp)
1008 {
1009 struct dquot *dq;
1010 int i;
1011
1012 mutex_enter(&lfs_dqlock);
1013 for (i = 0; i <= dqhash; i++)
1014 LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
1015 KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
1016 mutex_exit(&lfs_dqlock);
1017 }
1018 #endif
1019