1 /*        $NetBSD: ulfs_quota.c,v 1.13 2016/06/19 23:06:09 dholland Exp $       */
2 /*  from NetBSD: ufs_quota.c,v 1.117 2014/06/28 22:27:51 dholland 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.13 2016/06/19 23:06:09 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_del(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
ulfsquota_init(struct inode * ip)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
ulfsquota_free(struct inode * ip)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
lfs_chkdq(struct inode * ip,int64_t change,kauth_cred_t cred,int flags)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
lfs_chkiq(struct inode * ip,int32_t change,kauth_cred_t cred,int flags)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
lfsquota_handle_cmd(struct mount * mp,struct lwp * l,struct quotactl_args * args)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_DEL:
203                     error = quota_handle_cmd_del(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
quota_handle_cmd_stat(struct mount * mp,struct lwp * l,struct quotactl_args * args)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 
234           KASSERT(args->qc_op == QUOTACTL_STAT);
235 
236           if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
237                     return EOPNOTSUPP;
238 
239 #ifdef LFS_QUOTA
240           if (fs->um_flags & ULFS_QUOTA) {
241                     struct quotastat *info = args->u.stat.qc_info;
242                     strcpy(info->qs_implname, "lfs quota v1");
243                     info->qs_numidtypes = ULFS_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 LFS_QUOTA2
253           if (fs->um_flags & ULFS_QUOTA2) {
254                     struct quotastat *info = args->u.stat.qc_info;
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
quota_handle_cmd_idtypestat(struct mount * mp,struct lwp * l,struct quotactl_args * args)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
quota_handle_cmd_objtypestat(struct mount * mp,struct lwp * l,struct quotactl_args * args)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
quota_get_auth(struct mount * mp,struct lwp * l,uid_t id)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
quota_handle_cmd_get(struct mount * mp,struct lwp * l,struct quotactl_args * args)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 
357           KASSERT(args->qc_op == QUOTACTL_GET);
358           qk = args->u.get.qc_key;
359 
360           if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
361                     return EOPNOTSUPP;
362 
363           error = quota_get_auth(mp, l, qk->qk_id);
364           if (error != 0)
365                     return error;
366 #ifdef LFS_QUOTA
367           if (fs->um_flags & ULFS_QUOTA) {
368                     struct quotaval *qv = args->u.get.qc_val;
369                     error = lfsquota1_handle_cmd_get(ump, qk, qv);
370           } else
371 #endif
372 #ifdef LFS_QUOTA2
373           if (fs->um_flags & ULFS_QUOTA2) {
374                     struct quotaval *qv = args->u.get.qc_val;
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
quota_handle_cmd_put(struct mount * mp,struct lwp * l,struct quotactl_args * args)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           id_t kauth_id;
394           int error;
395 
396           KASSERT(args->qc_op == QUOTACTL_PUT);
397           qk = args->u.put.qc_key;
398 
399           if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
400                     return EOPNOTSUPP;
401 
402           kauth_id = qk->qk_id;
403           if (kauth_id == QUOTA_DEFAULTID) {
404                     kauth_id = 0;
405           }
406 
407           error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
408               KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
409               NULL);
410           if (error != 0) {
411                     return error;
412           }
413 
414 #ifdef LFS_QUOTA
415           if (fs->um_flags & ULFS_QUOTA) {
416                     const struct quotaval *qv = args->u.put.qc_val;
417                     error = lfsquota1_handle_cmd_put(ump, qk, qv);
418           } else
419 #endif
420 #ifdef LFS_QUOTA2
421           if (fs->um_flags & ULFS_QUOTA2) {
422                     const struct quotaval *qv = args->u.put.qc_val;
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
quota_handle_cmd_del(struct mount * mp,struct lwp * l,struct quotactl_args * args)436 quota_handle_cmd_del(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_DEL);
446           qk = args->u.del.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_del(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
quota_handle_cmd_cursorget(struct mount * mp,struct lwp * l,struct quotactl_args * args)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           int error;
486 
487           KASSERT(args->qc_op == QUOTACTL_CURSORGET);
488 
489           if ((fs->um_flags & ULFS_QUOTA2) == 0)
490                     return EOPNOTSUPP;
491 
492           error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
493               KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
494           if (error)
495                     return error;
496 
497 #ifdef LFS_QUOTA2
498           if (fs->um_flags & ULFS_QUOTA2) {
499                     struct quotakcursor *cursor = args->u.cursorget.qc_cursor;
500                     struct quotakey *keys = args->u.cursorget.qc_keys;
501                     struct quotaval *vals = args->u.cursorget.qc_vals;
502                     unsigned maxnum = args->u.cursorget.qc_maxnum;
503                     unsigned *ret = args->u.cursorget.qc_ret;
504 
505                     error = lfsquota2_handle_cmd_cursorget(ump, cursor, keys, vals,
506                         maxnum, ret);
507           } else
508 #endif
509                     panic("quota_handle_cmd_cursorget: no support ?");
510 
511           return error;
512 }
513 
514 static int
quota_handle_cmd_cursoropen(struct mount * mp,struct lwp * l,struct quotactl_args * args)515 quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l,
516     struct quotactl_args *args)
517 {
518 #ifdef LFS_QUOTA2
519           struct ulfsmount *ump = VFSTOULFS(mp);
520           struct lfs *fs = ump->um_lfs;
521           struct quotakcursor *cursor;
522 #endif
523           int error;
524 
525           KASSERT(args->qc_op == QUOTACTL_CURSOROPEN);
526 
527           error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
528               KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
529           if (error)
530                     return error;
531 
532 #ifdef LFS_QUOTA2
533           if (fs->um_flags & ULFS_QUOTA2) {
534                     cursor = args->u.cursoropen.qc_cursor;
535                     error = lfsquota2_handle_cmd_cursoropen(ump, cursor);
536           } else
537 #endif
538                     error = EOPNOTSUPP;
539 
540           return error;
541 }
542 
543 static int
quota_handle_cmd_cursorclose(struct mount * mp,struct lwp * l,struct quotactl_args * args)544 quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l,
545     struct quotactl_args *args)
546 {
547 #ifdef LFS_QUOTA2
548           struct ulfsmount *ump = VFSTOULFS(mp);
549           struct lfs *fs = ump->um_lfs;
550 #endif
551           int error;
552 
553           KASSERT(args->qc_op == QUOTACTL_CURSORCLOSE);
554 
555           error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
556               KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
557           if (error)
558                     return error;
559 
560 #ifdef LFS_QUOTA2
561           if (fs->um_flags & ULFS_QUOTA2) {
562                     struct quotakcursor *cursor = args->u.cursorclose.qc_cursor;
563                     error = lfsquota2_handle_cmd_cursorclose(ump, cursor);
564           } else
565 #endif
566                     error = EOPNOTSUPP;
567 
568           return error;
569 }
570 
571 static int
quota_handle_cmd_cursorskipidtype(struct mount * mp,struct lwp * l,struct quotactl_args * args)572 quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l,
573     struct quotactl_args *args)
574 {
575 #ifdef LFS_QUOTA2
576           struct ulfsmount *ump = VFSTOULFS(mp);
577           struct lfs *fs = ump->um_lfs;
578 #endif
579           int error;
580 
581           KASSERT(args->qc_op == QUOTACTL_CURSORSKIPIDTYPE);
582 
583 #ifdef LFS_QUOTA2
584           if (fs->um_flags & ULFS_QUOTA2) {
585                     struct quotakcursor *cursor = args->u.cursorskipidtype.qc_cursor;
586                     int idtype = args->u.cursorskipidtype.qc_idtype;
587                     error = lfsquota2_handle_cmd_cursorskipidtype(ump, cursor, idtype);
588           } else
589 #endif
590                     error = EOPNOTSUPP;
591 
592           return error;
593 }
594 
595 static int
quota_handle_cmd_cursoratend(struct mount * mp,struct lwp * l,struct quotactl_args * args)596 quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l,
597     struct quotactl_args *args)
598 {
599 #ifdef LFS_QUOTA2
600           struct ulfsmount *ump = VFSTOULFS(mp);
601           struct lfs *fs = ump->um_lfs;
602 #endif
603           int error;
604 
605           KASSERT(args->qc_op == QUOTACTL_CURSORATEND);
606 
607 #ifdef LFS_QUOTA2
608           if (fs->um_flags & ULFS_QUOTA2) {
609                     struct quotakcursor *cursor = args->u.cursoratend.qc_cursor;
610                     int *ret = args->u.cursoratend.qc_ret;
611                     error = lfsquota2_handle_cmd_cursoratend(ump, cursor, ret);
612           } else
613 #endif
614                     error = EOPNOTSUPP;
615 
616           return error;
617 }
618 
619 static int
quota_handle_cmd_cursorrewind(struct mount * mp,struct lwp * l,struct quotactl_args * args)620 quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l,
621     struct quotactl_args *args)
622 {
623 #ifdef LFS_QUOTA2
624           struct ulfsmount *ump = VFSTOULFS(mp);
625           struct lfs *fs = ump->um_lfs;
626 #endif
627           int error;
628 
629           KASSERT(args->qc_op == QUOTACTL_CURSORREWIND);
630 
631 #ifdef LFS_QUOTA2
632           if (fs->um_flags & ULFS_QUOTA2) {
633                     struct quotakcursor *cursor = args->u.cursorrewind.qc_cursor;
634                     error = lfsquota2_handle_cmd_cursorrewind(ump, cursor);
635           } else
636 #endif
637                     error = EOPNOTSUPP;
638 
639           return error;
640 }
641 
642 static int
quota_handle_cmd_quotaon(struct mount * mp,struct lwp * l,struct quotactl_args * args)643 quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
644     struct quotactl_args *args)
645 {
646           struct ulfsmount *ump = VFSTOULFS(mp);
647           struct lfs *fs = ump->um_lfs;
648           int error;
649 
650           KASSERT(args->qc_op == QUOTACTL_QUOTAON);
651 
652           if ((fs->um_flags & ULFS_QUOTA2) != 0)
653                     return EBUSY;
654 
655           error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
656               KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
657           if (error != 0) {
658                     return error;
659           }
660 #ifdef LFS_QUOTA
661           int idtype = args->u.quotaon.qc_idtype;
662           const char *qfile = args->u.quotaon.qc_quotafile;
663           error = lfsquota1_handle_cmd_quotaon(l, ump, idtype, qfile);
664 #else
665           error = EOPNOTSUPP;
666 #endif
667 
668           return error;
669 }
670 
671 static int
quota_handle_cmd_quotaoff(struct mount * mp,struct lwp * l,struct quotactl_args * args)672 quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
673     struct quotactl_args *args)
674 {
675           struct ulfsmount *ump = VFSTOULFS(mp);
676           struct lfs *fs = ump->um_lfs;
677           int error;
678 
679           KASSERT(args->qc_op == QUOTACTL_QUOTAOFF);
680 
681           if ((fs->um_flags & ULFS_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 LFS_QUOTA
690           int idtype = args->u.quotaoff.qc_idtype;
691           error = lfsquota1_handle_cmd_quotaoff(l, ump, idtype);
692 #else
693           error = EOPNOTSUPP;
694 #endif
695 
696           return error;
697 }
698 
699 /*
700  * Initialize the quota system.
701  */
702 void
lfs_dqinit(void)703 lfs_dqinit(void)
704 {
705 
706           mutex_init(&lfs_dqlock, MUTEX_DEFAULT, IPL_NONE);
707           cv_init(&lfs_dqcv, "quota");
708           dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
709           dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "lfsdq",
710               NULL, IPL_NONE, NULL, NULL, NULL);
711 }
712 
713 void
lfs_dqreinit(void)714 lfs_dqreinit(void)
715 {
716           struct dquot *dq;
717           struct dqhashhead *oldhash, *hash;
718           struct vnode *dqvp;
719           u_long oldmask, mask, hashval;
720           int i;
721 
722           hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
723           mutex_enter(&lfs_dqlock);
724           oldhash = dqhashtbl;
725           oldmask = dqhash;
726           dqhashtbl = hash;
727           dqhash = mask;
728           for (i = 0; i <= oldmask; i++) {
729                     while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
730                               dqvp = dq->dq_ump->um_quotas[dq->dq_type];
731                               LIST_REMOVE(dq, dq_hash);
732                               hashval = DQHASH(dqvp, dq->dq_id);
733                               LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
734                     }
735           }
736           mutex_exit(&lfs_dqlock);
737           hashdone(oldhash, HASH_LIST, oldmask);
738 }
739 
740 /*
741  * Free resources held by quota system.
742  */
743 void
lfs_dqdone(void)744 lfs_dqdone(void)
745 {
746 
747           pool_cache_destroy(dquot_cache);
748           hashdone(dqhashtbl, HASH_LIST, dqhash);
749           cv_destroy(&lfs_dqcv);
750           mutex_destroy(&lfs_dqlock);
751 }
752 
753 /*
754  * Set up the quotas for an inode.
755  *
756  * This routine completely defines the semantics of quotas.
757  * If other criteria want to be used to establish quotas, the
758  * ULFS_MAXQUOTAS value in quotas.h should be increased, and the
759  * additional dquots set up here.
760  */
761 int
lfs_getinoquota(struct inode * ip)762 lfs_getinoquota(struct inode *ip)
763 {
764           struct ulfsmount *ump = ip->i_ump;
765           //struct lfs *fs = ump->um_lfs; // notyet
766           struct vnode *vp = ITOV(ip);
767           int i, error;
768           u_int32_t ino_ids[ULFS_MAXQUOTAS];
769 
770           /*
771            * To avoid deadlocks never update quotas for quota files
772            * on the same file system
773            */
774           for (i = 0; i < ULFS_MAXQUOTAS; i++)
775                     if (vp == ump->um_quotas[i])
776                               return 0;
777 
778           ino_ids[ULFS_USRQUOTA] = ip->i_uid;
779           ino_ids[ULFS_GRPQUOTA] = ip->i_gid;
780           for (i = 0; i < ULFS_MAXQUOTAS; i++) {
781                     /*
782                      * If the file id changed the quota needs update.
783                      */
784                     if (ip->i_dquot[i] != NODQUOT &&
785                         ip->i_dquot[i]->dq_id != ino_ids[i]) {
786                               lfs_dqrele(ITOV(ip), ip->i_dquot[i]);
787                               ip->i_dquot[i] = NODQUOT;
788                     }
789                     /*
790                      * Set up the quota based on file id.
791                      * ENODEV means that quotas are not enabled.
792                      */
793                     if (ip->i_dquot[i] == NODQUOT &&
794                         (error = lfs_dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
795                         error != ENODEV)
796                               return (error);
797           }
798           return 0;
799 }
800 
801 /*
802  * Obtain a dquot structure for the specified identifier and quota file
803  * reading the information from the file if necessary.
804  */
805 int
lfs_dqget(struct vnode * vp,u_long id,struct ulfsmount * ump,int type,struct dquot ** dqp)806 lfs_dqget(struct vnode *vp, u_long id, struct ulfsmount *ump, int type,
807     struct dquot **dqp)
808 {
809           struct lfs *fs = ump->um_lfs;
810           struct dquot *dq, *ndq;
811           struct dqhashhead *dqh;
812           struct vnode *dqvp;
813           int error = 0; /* XXX gcc */
814 
815           /* Lock to see an up to date value for QTF_CLOSING. */
816           mutex_enter(&lfs_dqlock);
817           if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0) {
818                     mutex_exit(&lfs_dqlock);
819                     *dqp = NODQUOT;
820                     return (ENODEV);
821           }
822           dqvp = ump->um_quotas[type];
823 #ifdef LFS_QUOTA
824           if (fs->um_flags & ULFS_QUOTA) {
825                     if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
826                               mutex_exit(&lfs_dqlock);
827                               *dqp = NODQUOT;
828                               return (ENODEV);
829                     }
830           }
831 #endif
832 #ifdef LFS_QUOTA2
833           if (fs->um_flags & ULFS_QUOTA2) {
834                     if (dqvp == NULLVP) {
835                               mutex_exit(&lfs_dqlock);
836                               *dqp = NODQUOT;
837                               return (ENODEV);
838                     }
839           }
840 #endif
841           KASSERT(dqvp != vp);
842           /*
843            * Check the cache first.
844            */
845           dqh = &dqhashtbl[DQHASH(dqvp, id)];
846           LIST_FOREACH(dq, dqh, dq_hash) {
847                     if (dq->dq_id != id ||
848                         dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
849                               continue;
850                     KASSERT(dq->dq_cnt > 0);
851                     lfs_dqref(dq);
852                     mutex_exit(&lfs_dqlock);
853                     *dqp = dq;
854                     return (0);
855           }
856           /*
857            * Not in cache, allocate a new one.
858            */
859           mutex_exit(&lfs_dqlock);
860           ndq = pool_cache_get(dquot_cache, PR_WAITOK);
861           /*
862            * Initialize the contents of the dquot structure.
863            */
864           memset((char *)ndq, 0, sizeof *ndq);
865           ndq->dq_flags = 0;
866           ndq->dq_id = id;
867           ndq->dq_ump = ump;
868           ndq->dq_type = type;
869           mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
870           mutex_enter(&lfs_dqlock);
871           dqh = &dqhashtbl[DQHASH(dqvp, id)];
872           LIST_FOREACH(dq, dqh, dq_hash) {
873                     if (dq->dq_id != id ||
874                         dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
875                               continue;
876                     /*
877                      * Another thread beat us allocating this dquot.
878                      */
879                     KASSERT(dq->dq_cnt > 0);
880                     lfs_dqref(dq);
881                     mutex_exit(&lfs_dqlock);
882                     mutex_destroy(&ndq->dq_interlock);
883                     pool_cache_put(dquot_cache, ndq);
884                     *dqp = dq;
885                     return 0;
886           }
887           dq = ndq;
888           LIST_INSERT_HEAD(dqh, dq, dq_hash);
889           lfs_dqref(dq);
890           mutex_enter(&dq->dq_interlock);
891           mutex_exit(&lfs_dqlock);
892 #ifdef LFS_QUOTA
893           if (fs->um_flags & ULFS_QUOTA)
894                     error = lfs_dq1get(dqvp, id, ump, type, dq);
895 #endif
896 #ifdef LFS_QUOTA2
897           if (fs->um_flags & ULFS_QUOTA2)
898                     error = lfs_dq2get(dqvp, id, ump, type, dq);
899 #endif
900           /*
901            * I/O error in reading quota file, release
902            * quota structure and reflect problem to caller.
903            */
904           if (error) {
905                     mutex_enter(&lfs_dqlock);
906                     LIST_REMOVE(dq, dq_hash);
907                     mutex_exit(&lfs_dqlock);
908                     mutex_exit(&dq->dq_interlock);
909                     lfs_dqrele(vp, dq);
910                     *dqp = NODQUOT;
911                     return (error);
912           }
913           mutex_exit(&dq->dq_interlock);
914           *dqp = dq;
915           return (0);
916 }
917 
918 /*
919  * Obtain a reference to a dquot.
920  */
921 void
lfs_dqref(struct dquot * dq)922 lfs_dqref(struct dquot *dq)
923 {
924 
925           KASSERT(mutex_owned(&lfs_dqlock));
926           dq->dq_cnt++;
927           KASSERT(dq->dq_cnt > 0);
928 }
929 
930 /*
931  * Release a reference to a dquot.
932  */
933 void
lfs_dqrele(struct vnode * vp,struct dquot * dq)934 lfs_dqrele(struct vnode *vp, struct dquot *dq)
935 {
936 
937           if (dq == NODQUOT)
938                     return;
939           mutex_enter(&dq->dq_interlock);
940           for (;;) {
941                     mutex_enter(&lfs_dqlock);
942                     if (dq->dq_cnt > 1) {
943                               dq->dq_cnt--;
944                               mutex_exit(&lfs_dqlock);
945                               mutex_exit(&dq->dq_interlock);
946                               return;
947                     }
948                     if ((dq->dq_flags & DQ_MOD) == 0)
949                               break;
950                     mutex_exit(&lfs_dqlock);
951 #ifdef LFS_QUOTA
952                     if (dq->dq_ump->um_lfs->um_flags & ULFS_QUOTA)
953                               (void) lfs_dq1sync(vp, dq);
954 #endif
955 #ifdef LFS_QUOTA2
956                     if (dq->dq_ump->um_lfs->um_flags & ULFS_QUOTA2)
957                               (void) lfs_dq2sync(vp, dq);
958 #endif
959           }
960           KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
961           LIST_REMOVE(dq, dq_hash);
962           mutex_exit(&lfs_dqlock);
963           mutex_exit(&dq->dq_interlock);
964           mutex_destroy(&dq->dq_interlock);
965           pool_cache_put(dquot_cache, dq);
966 }
967 
968 int
lfs_qsync(struct mount * mp)969 lfs_qsync(struct mount *mp)
970 {
971           struct ulfsmount *ump = VFSTOULFS(mp);
972           struct lfs *fs = ump->um_lfs;
973 
974           /* avoid compiler warning when quotas aren't enabled */
975           (void)ump;
976           (void)fs;
977 
978 #ifdef LFS_QUOTA
979           if (fs->um_flags & ULFS_QUOTA)
980                     return lfs_q1sync(mp);
981 #endif
982 #ifdef LFS_QUOTA2
983           if (fs->um_flags & ULFS_QUOTA2)
984                     return lfs_q2sync(mp);
985 #endif
986           return 0;
987 }
988 
989 #ifdef DIAGNOSTIC
990 /*
991  * Check the hash chains for stray dquot's.
992  */
993 void
lfs_dqflush(struct vnode * vp)994 lfs_dqflush(struct vnode *vp)
995 {
996           struct dquot *dq;
997           int i;
998 
999           mutex_enter(&lfs_dqlock);
1000           for (i = 0; i <= dqhash; i++)
1001                     LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
1002                               KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
1003           mutex_exit(&lfs_dqlock);
1004 }
1005 #endif
1006