1 /* $NetBSD: ufs_quota2.c,v 1.46 2023/02/22 21:49:45 riastradh Exp $ */
2 /*-
3   * Copyright (c) 2010 Manuel Bouyer
4   * All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions
8   * are met:
9   * 1. Redistributions of source code must retain the above copyright
10   *    notice, this list of conditions and the following disclaimer.
11   * 2. Redistributions in binary form must reproduce the above copyright
12   *    notice, this list of conditions and the following disclaimer in the
13   *    documentation and/or other materials provided with the distribution.
14   *
15   * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25   * POSSIBILITY OF SUCH DAMAGE.
26   */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.46 2023/02/22 21:49:45 riastradh Exp $");
30 
31 #include <sys/buf.h>
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/namei.h>
36 #include <sys/file.h>
37 #include <sys/proc.h>
38 #include <sys/vnode.h>
39 #include <sys/mount.h>
40 #include <sys/kauth.h>
41 #include <sys/wapbl.h>
42 #include <sys/quota.h>
43 #include <sys/quotactl.h>
44 
45 #include <ufs/ufs/quota2.h>
46 #include <ufs/ufs/inode.h>
47 #include <ufs/ufs/ufsmount.h>
48 #include <ufs/ufs/ufs_bswap.h>
49 #include <ufs/ufs/ufs_extern.h>
50 #include <ufs/ufs/ufs_quota.h>
51 #include <ufs/ufs/ufs_wapbl.h>
52 
53 /*
54  * LOCKING:
55  * Data in the entries are protected by the associated struct dquot's
56  * dq_interlock (this means we can't read or change a quota entry without
57  * grabbing a dquot for it).
58  * The header and lists (including pointers in the data entries, and q2e_uid)
59  * are protected by the global dqlock.
60  * the locking order is dq_interlock -> dqlock
61  */
62 
63 static int quota2_bwrite(struct mount *, struct buf *);
64 static int getinoquota2(struct inode *, bool, bool, struct buf **,
65     struct quota2_entry **);
66 static int getq2h(struct ufsmount *, int, struct buf **,
67     struct quota2_header **, int);
68 static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **,
69     struct quota2_entry **, int);
70 static int quota2_walk_list(struct ufsmount *, struct buf *, int,
71     uint64_t *, int, void *,
72     int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *,
73       uint64_t, void *));
74 
75 static const char *limnames[] = INITQLNAMES;
76 
77 static void
quota2_dict_update_q2e_limits(int objtype,const struct quotaval * val,struct quota2_entry * q2e)78 quota2_dict_update_q2e_limits(int objtype, const struct quotaval *val,
79     struct quota2_entry *q2e)
80 {
81           /* make sure we can index q2e_val[] by the fs-independent objtype */
82           CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK);
83           CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE);
84 
85           q2e->q2e_val[objtype].q2v_hardlimit = val->qv_hardlimit;
86           q2e->q2e_val[objtype].q2v_softlimit = val->qv_softlimit;
87           q2e->q2e_val[objtype].q2v_grace = val->qv_grace;
88 }
89 
90 /*
91  * Convert internal representation to FS-independent representation.
92  * (Note that while the two types are currently identical, the
93  * internal representation is an on-disk struct and the FS-independent
94  * representation is not, and they might diverge in the future.)
95  */
96 static void
q2val_to_quotaval(struct quota2_val * q2v,struct quotaval * qv)97 q2val_to_quotaval(struct quota2_val *q2v, struct quotaval *qv)
98 {
99           qv->qv_softlimit = q2v->q2v_softlimit;
100           qv->qv_hardlimit = q2v->q2v_hardlimit;
101           qv->qv_usage = q2v->q2v_cur;
102           qv->qv_expiretime = q2v->q2v_time;
103           qv->qv_grace = q2v->q2v_grace;
104 }
105 
106 /*
107  * Convert a quota2entry and default-flag to the FS-independent
108  * representation.
109  */
110 static void
q2e_to_quotaval(struct quota2_entry * q2e,int def,id_t * id,int objtype,struct quotaval * ret)111 q2e_to_quotaval(struct quota2_entry *q2e, int def,
112     id_t *id, int objtype, struct quotaval *ret)
113 {
114           if (def) {
115                     *id = QUOTA_DEFAULTID;
116           } else {
117                     *id = q2e->q2e_uid;
118           }
119 
120           KASSERT(objtype >= 0 && objtype < N_QL);
121           q2val_to_quotaval(&q2e->q2e_val[objtype], ret);
122 }
123 
124 
125 static int
quota2_bwrite(struct mount * mp,struct buf * bp)126 quota2_bwrite(struct mount *mp, struct buf *bp)
127 {
128           if (mp->mnt_flag & MNT_SYNCHRONOUS)
129                     return bwrite(bp);
130           else {
131                     bdwrite(bp);
132                     return 0;
133           }
134 }
135 
136 static int
getq2h(struct ufsmount * ump,int type,struct buf ** bpp,struct quota2_header ** q2hp,int flags)137 getq2h(struct ufsmount *ump, int type,
138     struct buf **bpp, struct quota2_header **q2hp, int flags)
139 {
140           const int needswap = UFS_MPNEEDSWAP(ump);
141           int error;
142           struct buf *bp;
143           struct quota2_header *q2h;
144 
145           KASSERT(mutex_owned(&dqlock));
146           error = bread(ump->um_quotas[type], 0, ump->umq2_bsize,
147               flags, &bp);
148           if (error)
149                     return error;
150           if (bp->b_resid != 0)
151                     panic("dq2get: %s quota file truncated", quotatypes[type]);
152 
153           q2h = (void *)bp->b_data;
154           if (ufs_rw32(q2h->q2h_magic_number, needswap) != Q2_HEAD_MAGIC ||
155               q2h->q2h_type != type)
156                     panic("dq2get: corrupted %s quota header", quotatypes[type]);
157           *bpp = bp;
158           *q2hp = q2h;
159           return 0;
160 }
161 
162 static int
getq2e(struct ufsmount * ump,int type,daddr_t lblkno,int blkoffset,struct buf ** bpp,struct quota2_entry ** q2ep,int flags)163 getq2e(struct ufsmount *ump, int type, daddr_t lblkno, int blkoffset,
164     struct buf **bpp, struct quota2_entry **q2ep, int flags)
165 {
166           int error;
167           struct buf *bp;
168 
169           if (blkoffset & (sizeof(uint64_t) - 1)) {
170                     panic("dq2get: %s quota file corrupted",
171                         quotatypes[type]);
172           }
173           error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize,
174               flags, &bp);
175           if (error)
176                     return error;
177           if (bp->b_resid != 0) {
178                     panic("dq2get: %s quota file corrupted",
179                         quotatypes[type]);
180           }
181           *q2ep = (void *)((char *)bp->b_data + blkoffset);
182           *bpp = bp;
183           return 0;
184 }
185 
186 /* walk a quota entry list, calling the callback for each entry */
187 #define Q2WL_ABORT 0x10000000
188 
189 static int
quota2_walk_list(struct ufsmount * ump,struct buf * hbp,int type,uint64_t * offp,int flags,void * a,int (* func)(struct ufsmount *,uint64_t *,struct quota2_entry *,uint64_t,void *))190 quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type,
191     uint64_t *offp, int flags, void *a,
192     int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t,
193           void *))
194 {
195           const int needswap = UFS_MPNEEDSWAP(ump);
196           daddr_t off = ufs_rw64(*offp, needswap);
197           struct buf *bp, *obp = hbp;
198           int ret = 0, ret2 = 0;
199           struct quota2_entry *q2e;
200           daddr_t lblkno, blkoff, olblkno = 0;
201 
202           KASSERT(mutex_owned(&dqlock));
203 
204           while (off != 0) {
205                     lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
206                     blkoff = (off & ump->umq2_bmask);
207                     if (lblkno == 0) {
208                               /* in the header block */
209                               bp = hbp;
210                     } else if (lblkno == olblkno) {
211                               /* still in the same buf */
212                               bp = obp;
213                     } else {
214                               ret = bread(ump->um_quotas[type], lblkno,
215                                   ump->umq2_bsize, flags, &bp);
216                               if (ret)
217                                         return ret;
218                               if (bp->b_resid != 0) {
219                                         panic("%s: %s quota file corrupted",
220                                             __func__, quotatypes[type]);
221                               }
222                     }
223                     q2e = (void *)((char *)(bp->b_data) + blkoff);
224                     ret = (*func)(ump, offp, q2e, off, a);
225                     if (off != ufs_rw64(*offp, needswap)) {
226                               /* callback changed parent's pointer, redo */
227                               off = ufs_rw64(*offp, needswap);
228                               if (bp != hbp && bp != obp)
229                                         ret2 = bwrite(bp);
230                     } else {
231                               /* parent if now current */
232                               if (obp != bp && obp != hbp) {
233                                         if (flags & B_MODIFY)
234                                                   ret2 = bwrite(obp);
235                                         else
236                                                   brelse(obp, 0);
237                               }
238                               obp = bp;
239                               olblkno = lblkno;
240                               offp = &(q2e->q2e_next);
241                               off = ufs_rw64(*offp, needswap);
242                     }
243                     if (ret)
244                               break;
245                     if (ret2) {
246                               ret = ret2;
247                               break;
248                     }
249           }
250           if (obp != hbp) {
251                     if (flags & B_MODIFY)
252                               ret2 = bwrite(obp);
253                     else
254                               brelse(obp, 0);
255           }
256           if (ret & Q2WL_ABORT)
257                     return 0;
258           if (ret == 0)
259                     return ret2;
260           return ret;
261 }
262 
263 int
quota2_umount(struct mount * mp,int flags)264 quota2_umount(struct mount *mp, int flags)
265 {
266           int i, error;
267           struct ufsmount *ump = VFSTOUFS(mp);
268 
269           if ((ump->um_flags & UFS_QUOTA2) == 0)
270                     return 0;
271 
272           for (i = 0; i < MAXQUOTAS; i++) {
273                     if (ump->um_quotas[i] != NULLVP) {
274                               error = vn_close(ump->um_quotas[i], FREAD|FWRITE,
275                                   ump->um_cred[i]);
276                               if (error) {
277                                         printf("quota2_umount failed: close(%p) %d\n",
278                                             ump->um_quotas[i], error);
279                                         return error;
280                               }
281                     }
282                     ump->um_quotas[i] = NULLVP;
283           }
284           return 0;
285 }
286 
287 static int
quota2_q2ealloc(struct ufsmount * ump,int type,uid_t uid,struct dquot * dq)288 quota2_q2ealloc(struct ufsmount *ump, int type, uid_t uid, struct dquot *dq)
289 {
290           int error, error2;
291           struct buf *hbp, *bp;
292           struct quota2_header *q2h;
293           struct quota2_entry *q2e;
294           daddr_t offset;
295           u_long hash_mask;
296           const int needswap = UFS_MPNEEDSWAP(ump);
297 
298           KASSERT(mutex_owned(&dq->dq_interlock));
299           KASSERT(mutex_owned(&dqlock));
300           error = getq2h(ump, type, &hbp, &q2h, B_MODIFY);
301           if (error)
302                     return error;
303           offset = ufs_rw64(q2h->q2h_free, needswap);
304           if (offset == 0) {
305                     struct vnode *vp = ump->um_quotas[type];
306                     struct inode *ip = VTOI(vp);
307                     uint64_t size = ip->i_size;
308                     /* need to allocate a new disk block */
309                     error = UFS_BALLOC(vp, size, ump->umq2_bsize,
310                         ump->um_cred[type], B_CLRBUF | B_SYNC, &bp);
311                     if (error) {
312                               brelse(hbp, 0);
313                               return error;
314                     }
315                     KASSERT((ip->i_size % ump->umq2_bsize) == 0);
316                     ip->i_size += ump->umq2_bsize;
317                     DIP_ASSIGN(ip, size, ip->i_size);
318                     ip->i_flag |= IN_CHANGE | IN_UPDATE;
319                     uvm_vnp_setsize(vp, ip->i_size);
320                     quota2_addfreeq2e(q2h, bp->b_data, size, ump->umq2_bsize,
321                         needswap);
322                     error = bwrite(bp);
323                     error2 = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
324                     if (error || error2) {
325                               brelse(hbp, 0);
326                               if (error)
327                                         return error;
328                               return error2;
329                     }
330                     offset = ufs_rw64(q2h->q2h_free, needswap);
331                     KASSERT(offset != 0);
332           }
333           dq->dq2_lblkno = (offset >> ump->um_mountp->mnt_fs_bshift);
334           dq->dq2_blkoff = (offset & ump->umq2_bmask);
335           if (dq->dq2_lblkno == 0) {
336                     bp = hbp;
337                     q2e = (void *)((char *)bp->b_data + dq->dq2_blkoff);
338           } else {
339                     error = getq2e(ump, type, dq->dq2_lblkno,
340                         dq->dq2_blkoff, &bp, &q2e, B_MODIFY);
341                     if (error) {
342                               brelse(hbp, 0);
343                               return error;
344                     }
345           }
346           hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
347           /* remove from free list */
348           q2h->q2h_free = q2e->q2e_next;
349 
350           memcpy(q2e, &q2h->q2h_defentry, sizeof(*q2e));
351           q2e->q2e_uid = ufs_rw32(uid, needswap);
352           /* insert in hash list */
353           q2e->q2e_next = q2h->q2h_entries[uid & hash_mask];
354           q2h->q2h_entries[uid & hash_mask] = ufs_rw64(offset, needswap);
355           if (hbp != bp) {
356                     bwrite(hbp);
357           }
358           bwrite(bp);
359           return 0;
360 }
361 
362 static int
getinoquota2(struct inode * ip,bool alloc,bool modify,struct buf ** bpp,struct quota2_entry ** q2ep)363 getinoquota2(struct inode *ip, bool alloc, bool modify, struct buf **bpp,
364     struct quota2_entry **q2ep)
365 {
366           int error;
367           int i;
368           struct dquot *dq;
369           struct ufsmount *ump = ip->i_ump;
370           u_int32_t ino_ids[MAXQUOTAS];
371 
372           error = getinoquota(ip);
373           if (error)
374                     return error;
375 
376           if (alloc) {
377                     UFS_WAPBL_JLOCK_ASSERT(ump->um_mountp);
378           }
379         ino_ids[USRQUOTA] = ip->i_uid;
380         ino_ids[GRPQUOTA] = ip->i_gid;
381           /* first get the interlock for all dquot */
382           for (i = 0; i < MAXQUOTAS; i++) {
383                     dq = ip->i_dquot[i];
384                     if (dq == NODQUOT)
385                               continue;
386                     mutex_enter(&dq->dq_interlock);
387           }
388           /* now get the corresponding quota entry */
389           for (i = 0; i < MAXQUOTAS; i++) {
390                     bpp[i] = NULL;
391                     q2ep[i] = NULL;
392                     dq = ip->i_dquot[i];
393                     if (dq == NODQUOT)
394                               continue;
395                     if (__predict_false(ump->um_quotas[i] == NULL)) {
396                               /*
397                                * quotas have been turned off. This can happen
398                                * at umount time.
399                                */
400                               mutex_exit(&dq->dq_interlock);
401                               dqrele(NULLVP, dq);
402                               ip->i_dquot[i] = NULL;
403                               continue;
404                     }
405 
406                     if ((dq->dq2_lblkno | dq->dq2_blkoff) == 0) {
407                               if (!alloc) {
408                                         continue;
409                               }
410                               /* need to alloc a new on-disk quot */
411                               mutex_enter(&dqlock);
412                               error = quota2_q2ealloc(ump, i, ino_ids[i], dq);
413                               mutex_exit(&dqlock);
414                               if (error)
415                                         return error;
416                     }
417                     KASSERT(dq->dq2_lblkno != 0 || dq->dq2_blkoff != 0);
418                     error = getq2e(ump, i, dq->dq2_lblkno,
419                         dq->dq2_blkoff, &bpp[i], &q2ep[i],
420                         modify ? B_MODIFY : 0);
421                     if (error)
422                               return error;
423           }
424           return 0;
425 }
426 
427 __inline static int __unused
quota2_check_limit(struct quota2_val * q2v,uint64_t change,time_t now)428 quota2_check_limit(struct quota2_val *q2v, uint64_t change, time_t now)
429 {
430           return quota_check_limit(q2v->q2v_cur, change, q2v->q2v_softlimit,
431               q2v->q2v_hardlimit, q2v->q2v_time, now);
432 }
433 
434 static int
quota2_check(struct inode * ip,int vtype,int64_t change,kauth_cred_t cred,int flags)435 quota2_check(struct inode *ip, int vtype, int64_t change, kauth_cred_t cred,
436     int flags)
437 {
438           int error;
439           struct buf *bp[MAXQUOTAS];
440           struct quota2_entry *q2e[MAXQUOTAS];
441           struct quota2_val *q2vp;
442           struct dquot *dq;
443           uint64_t ncurblks;
444           struct ufsmount *ump = ip->i_ump;
445           struct mount *mp = ump->um_mountp;
446           const int needswap = UFS_MPNEEDSWAP(ump);
447           int i;
448 
449           if ((error = getinoquota2(ip, change > 0, change != 0, bp, q2e)) != 0)
450                     return error;
451           if (change == 0) {
452                     for (i = 0; i < MAXQUOTAS; i++) {
453                               dq = ip->i_dquot[i];
454                               if (dq == NODQUOT)
455                                         continue;
456                               if (bp[i])
457                                         brelse(bp[i], 0);
458                               mutex_exit(&dq->dq_interlock);
459                     }
460                     return 0;
461           }
462           if (change < 0) {
463                     for (i = 0; i < MAXQUOTAS; i++) {
464                               dq = ip->i_dquot[i];
465                               if (dq == NODQUOT)
466                                         continue;
467                               if (q2e[i] == NULL) {
468                                         mutex_exit(&dq->dq_interlock);
469                                         continue;
470                               }
471                               q2vp = &q2e[i]->q2e_val[vtype];
472                               ncurblks = ufs_rw64(q2vp->q2v_cur, needswap);
473                               if (ncurblks < -change)
474                                         ncurblks = 0;
475                               else
476                                         ncurblks += change;
477                               q2vp->q2v_cur = ufs_rw64(ncurblks, needswap);
478                               quota2_bwrite(mp, bp[i]);
479                               mutex_exit(&dq->dq_interlock);
480                     }
481                     return 0;
482           }
483           /* see if the allocation is allowed */
484           for (i = 0; i < MAXQUOTAS; i++) {
485                     struct quota2_val q2v;
486                     int ql_stat;
487                     dq = ip->i_dquot[i];
488                     if (dq == NODQUOT)
489                               continue;
490                     KASSERT(q2e[i] != NULL);
491                     quota2_ufs_rwq2v(&q2e[i]->q2e_val[vtype], &q2v, needswap);
492                     ql_stat = quota2_check_limit(&q2v, change, time_second);
493 
494                     if ((flags & FORCE) == 0 &&
495                         kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA,
496                               KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT,
497                               KAUTH_ARG(i), KAUTH_ARG(vtype), NULL) != 0) {
498                               /* enforce this limit */
499                               switch(QL_STATUS(ql_stat)) {
500                               case QL_S_DENY_HARD:
501                                         if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
502                                                   uprintf("\n%s: write failed, %s %s "
503                                                       "limit reached\n",
504                                                       mp->mnt_stat.f_mntonname,
505                                                       quotatypes[i], limnames[vtype]);
506                                                   dq->dq_flags |= DQ_WARN(vtype);
507                                         }
508                                         error = EDQUOT;
509                                         break;
510                               case QL_S_DENY_GRACE:
511                                         if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
512                                                   uprintf("\n%s: write failed, %s %s "
513                                                       "limit reached\n",
514                                                       mp->mnt_stat.f_mntonname,
515                                                       quotatypes[i], limnames[vtype]);
516                                                   dq->dq_flags |= DQ_WARN(vtype);
517                                         }
518                                         error = EDQUOT;
519                                         break;
520                               case QL_S_ALLOW_SOFT:
521                                         if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
522                                                   uprintf("\n%s: warning, %s %s "
523                                                       "quota exceeded\n",
524                                                       mp->mnt_stat.f_mntonname,
525                                                       quotatypes[i], limnames[vtype]);
526                                                   dq->dq_flags |= DQ_WARN(vtype);
527                                         }
528                                         break;
529                               }
530                     }
531                     /*
532                      * always do this; we don't know if the allocation will
533                      * succed or not in the end. if we don't do the allocation
534                      * q2v_time will be ignored anyway
535                      */
536                     if (ql_stat & QL_F_CROSS) {
537                               q2v.q2v_time = time_second + q2v.q2v_grace;
538                               quota2_ufs_rwq2v(&q2v, &q2e[i]->q2e_val[vtype],
539                                   needswap);
540                     }
541           }
542 
543           /* now do the allocation if allowed */
544           for (i = 0; i < MAXQUOTAS; i++) {
545                     dq = ip->i_dquot[i];
546                     if (dq == NODQUOT)
547                               continue;
548                     KASSERT(q2e[i] != NULL);
549                     if (error == 0) {
550                               q2vp = &q2e[i]->q2e_val[vtype];
551                               ncurblks = ufs_rw64(q2vp->q2v_cur, needswap);
552                               q2vp->q2v_cur = ufs_rw64(ncurblks + change, needswap);
553                               quota2_bwrite(mp, bp[i]);
554                     } else
555                               brelse(bp[i], 0);
556                     mutex_exit(&dq->dq_interlock);
557           }
558           return error;
559 }
560 
561 int
chkdq2(struct inode * ip,int64_t change,kauth_cred_t cred,int flags)562 chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
563 {
564           return quota2_check(ip, QL_BLOCK, change, cred, flags);
565 }
566 
567 int
chkiq2(struct inode * ip,int32_t change,kauth_cred_t cred,int flags)568 chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
569 {
570           return quota2_check(ip, QL_FILE, change, cred, flags);
571 }
572 
573 int
quota2_handle_cmd_put(struct ufsmount * ump,const struct quotakey * key,const struct quotaval * val)574 quota2_handle_cmd_put(struct ufsmount *ump, const struct quotakey *key,
575     const struct quotaval *val)
576 {
577           int error;
578           struct dquot *dq;
579           struct quota2_header *q2h;
580           struct quota2_entry q2e, *q2ep;
581           struct buf *bp;
582           const int needswap = UFS_MPNEEDSWAP(ump);
583 
584           /* make sure we can index by the fs-independent idtype */
585           CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA);
586           CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA);
587 
588           if (ump->um_quotas[key->qk_idtype] == NULLVP)
589                     return ENODEV;
590           error = UFS_WAPBL_BEGIN(ump->um_mountp);
591           if (error)
592                     return error;
593 
594           if (key->qk_id == QUOTA_DEFAULTID) {
595                     mutex_enter(&dqlock);
596                     error = getq2h(ump, key->qk_idtype, &bp, &q2h, B_MODIFY);
597                     if (error) {
598                               mutex_exit(&dqlock);
599                               goto out_wapbl;
600                     }
601                     quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
602                     quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e);
603                     quota2_ufs_rwq2e(&q2e, &q2h->q2h_defentry, needswap);
604                     mutex_exit(&dqlock);
605                     quota2_bwrite(ump->um_mountp, bp);
606                     goto out_wapbl;
607           }
608 
609           error = dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq);
610           if (error)
611                     goto out_wapbl;
612 
613           mutex_enter(&dq->dq_interlock);
614           if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
615                     /* need to alloc a new on-disk quot */
616                     mutex_enter(&dqlock);
617                     error = quota2_q2ealloc(ump, key->qk_idtype, key->qk_id, dq);
618                     mutex_exit(&dqlock);
619                     if (error)
620                               goto out_il;
621           }
622           KASSERT(dq->dq2_lblkno != 0 || dq->dq2_blkoff != 0);
623           error = getq2e(ump, key->qk_idtype, dq->dq2_lblkno,
624               dq->dq2_blkoff, &bp, &q2ep, B_MODIFY);
625           if (error)
626                     goto out_il;
627 
628           quota2_ufs_rwq2e(q2ep, &q2e, needswap);
629           /*
630            * Reset time limit if previously had no soft limit or were
631            * under it, but now have a soft limit and are over it.
632            */
633           if (val->qv_softlimit &&
634               q2e.q2e_val[key->qk_objtype].q2v_cur >= val->qv_softlimit &&
635               (q2e.q2e_val[key->qk_objtype].q2v_softlimit == 0 ||
636                     (q2e.q2e_val[key->qk_objtype].q2v_cur <
637                         q2e.q2e_val[key->qk_objtype].q2v_softlimit))) {
638                     q2e.q2e_val[key->qk_objtype].q2v_time =
639                         time_second + val->qv_grace;
640           }
641           quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e);
642           quota2_ufs_rwq2e(&q2e, q2ep, needswap);
643           quota2_bwrite(ump->um_mountp, bp);
644 
645 out_il:
646           mutex_exit(&dq->dq_interlock);
647           dqrele(NULLVP, dq);
648 out_wapbl:
649           UFS_WAPBL_END(ump->um_mountp);
650           return error;
651 }
652 
653 struct dq2clear_callback {
654           uid_t id;
655           struct dquot *dq;
656           struct quota2_header *q2h;
657 };
658 
659 static int
dq2clear_callback(struct ufsmount * ump,uint64_t * offp,struct quota2_entry * q2e,uint64_t off,void * v)660 dq2clear_callback(struct ufsmount *ump, uint64_t *offp,
661     struct quota2_entry *q2e,
662     uint64_t off, void *v)
663 {
664           struct dq2clear_callback *c = v;
665           const int needswap = UFS_MPNEEDSWAP(ump);
666           uint64_t myoff;
667 
668           if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
669                     KASSERT(mutex_owned(&c->dq->dq_interlock));
670                     c->dq->dq2_lblkno = 0;
671                     c->dq->dq2_blkoff = 0;
672                     myoff = *offp;
673                     /* remove from hash list */
674                     *offp = q2e->q2e_next;
675                     /* add to free list */
676                     q2e->q2e_next = c->q2h->q2h_free;
677                     c->q2h->q2h_free = myoff;
678                     return Q2WL_ABORT;
679           }
680           return 0;
681 }
682 int
quota2_handle_cmd_del(struct ufsmount * ump,const struct quotakey * qk)683 quota2_handle_cmd_del(struct ufsmount *ump, const struct quotakey *qk)
684 {
685           int idtype;
686           id_t id;
687           int objtype;
688           int error, i, canfree;
689           struct dquot *dq;
690           struct quota2_header *q2h;
691           struct quota2_entry q2e, *q2ep;
692           struct buf *hbp, *bp;
693           u_long hash_mask;
694           struct dq2clear_callback c;
695 
696           idtype = qk->qk_idtype;
697           id = qk->qk_id;
698           objtype = qk->qk_objtype;
699 
700           if (ump->um_quotas[idtype] == NULLVP)
701                     return ENODEV;
702           if (id == QUOTA_DEFAULTID)
703                     return EOPNOTSUPP;
704 
705           /* get the default entry before locking the entry's buffer */
706           mutex_enter(&dqlock);
707           error = getq2h(ump, idtype, &hbp, &q2h, 0);
708           if (error) {
709                     mutex_exit(&dqlock);
710                     return error;
711           }
712           /* we'll copy to another disk entry, so no need to swap */
713           memcpy(&q2e, &q2h->q2h_defentry, sizeof(q2e));
714           mutex_exit(&dqlock);
715           brelse(hbp, 0);
716 
717           error = dqget(NULLVP, id, ump, idtype, &dq);
718           if (error)
719                     return error;
720 
721           mutex_enter(&dq->dq_interlock);
722           if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
723                     /* already clear, nothing to do */
724                     error = ENOENT;
725                     goto out_il;
726           }
727           error = UFS_WAPBL_BEGIN(ump->um_mountp);
728           if (error)
729                     goto out_dq;
730 
731           error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff,
732               &bp, &q2ep, B_MODIFY);
733           if (error)
734                     goto out_wapbl;
735 
736           /* make sure we can index by the objtype passed in */
737           CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK);
738           CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE);
739 
740           /* clear the requested objtype by copying from the default entry */
741           q2ep->q2e_val[objtype].q2v_softlimit =
742                     q2e.q2e_val[objtype].q2v_softlimit;
743           q2ep->q2e_val[objtype].q2v_hardlimit =
744                     q2e.q2e_val[objtype].q2v_hardlimit;
745           q2ep->q2e_val[objtype].q2v_grace =
746                     q2e.q2e_val[objtype].q2v_grace;
747           q2ep->q2e_val[objtype].q2v_time = 0;
748 
749           /* if this entry now contains no information, we can free it */
750           canfree = 1;
751           for (i = 0; i < N_QL; i++) {
752                     if (q2ep->q2e_val[i].q2v_cur != 0 ||
753                         (q2ep->q2e_val[i].q2v_softlimit !=
754                          q2e.q2e_val[i].q2v_softlimit) ||
755                         (q2ep->q2e_val[i].q2v_hardlimit !=
756                          q2e.q2e_val[i].q2v_hardlimit) ||
757                         (q2ep->q2e_val[i].q2v_grace !=
758                          q2e.q2e_val[i].q2v_grace)) {
759                               canfree = 0;
760                               break;
761                     }
762                     /* note: do not need to check q2v_time */
763           }
764 
765           if (canfree == 0) {
766                     quota2_bwrite(ump->um_mountp, bp);
767                     goto out_wapbl;
768           }
769           /* we can free it. release bp so we can walk the list */
770           brelse(bp, 0);
771           mutex_enter(&dqlock);
772           error = getq2h(ump, idtype, &hbp, &q2h, 0);
773           if (error)
774                     goto out_dqlock;
775 
776           hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
777           c.dq = dq;
778           c.id = id;
779           c.q2h = q2h;
780           error = quota2_walk_list(ump, hbp, idtype,
781               &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c,
782               dq2clear_callback);
783 
784           bwrite(hbp);
785 
786 out_dqlock:
787           mutex_exit(&dqlock);
788 out_wapbl:
789           UFS_WAPBL_END(ump->um_mountp);
790 out_il:
791           mutex_exit(&dq->dq_interlock);
792 out_dq:
793           dqrele(NULLVP, dq);
794           return error;
795 }
796 
797 static int
quota2_fetch_q2e(struct ufsmount * ump,const struct quotakey * qk,struct quota2_entry * ret)798 quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
799     struct quota2_entry *ret)
800 {
801           struct dquot *dq;
802           int error;
803           struct quota2_entry *q2ep;
804           struct buf *bp;
805           const int needswap = UFS_MPNEEDSWAP(ump);
806 
807           error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
808           if (error)
809                     return error;
810 
811           mutex_enter(&dq->dq_interlock);
812           if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
813                     mutex_exit(&dq->dq_interlock);
814                     dqrele(NULLVP, dq);
815                     return ENOENT;
816           }
817           error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff,
818               &bp, &q2ep, 0);
819           if (error) {
820                     mutex_exit(&dq->dq_interlock);
821                     dqrele(NULLVP, dq);
822                     return error;
823           }
824           quota2_ufs_rwq2e(q2ep, ret, needswap);
825           brelse(bp, 0);
826           mutex_exit(&dq->dq_interlock);
827           dqrele(NULLVP, dq);
828 
829           return 0;
830 }
831 
832 static int
quota2_fetch_quotaval(struct ufsmount * ump,const struct quotakey * qk,struct quotaval * ret)833 quota2_fetch_quotaval(struct ufsmount *ump, const struct quotakey *qk,
834     struct quotaval *ret)
835 {
836           struct dquot *dq;
837           int error;
838           struct quota2_entry *q2ep, q2e;
839           struct buf  *bp;
840           const int needswap = UFS_MPNEEDSWAP(ump);
841           id_t id2;
842 
843           error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
844           if (error)
845                     return error;
846 
847           mutex_enter(&dq->dq_interlock);
848           if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
849                     mutex_exit(&dq->dq_interlock);
850                     dqrele(NULLVP, dq);
851                     return ENOENT;
852           }
853           error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff,
854               &bp, &q2ep, 0);
855           if (error) {
856                     mutex_exit(&dq->dq_interlock);
857                     dqrele(NULLVP, dq);
858                     return error;
859           }
860           quota2_ufs_rwq2e(q2ep, &q2e, needswap);
861           brelse(bp, 0);
862           mutex_exit(&dq->dq_interlock);
863           dqrele(NULLVP, dq);
864 
865           q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret);
866           KASSERT(id2 == qk->qk_id);
867           return 0;
868 }
869 
870 int
quota2_handle_cmd_get(struct ufsmount * ump,const struct quotakey * qk,struct quotaval * qv)871 quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk,
872     struct quotaval *qv)
873 {
874           int error;
875           struct quota2_header *q2h;
876           struct quota2_entry q2e;
877           struct buf *bp;
878           const int needswap = UFS_MPNEEDSWAP(ump);
879           id_t id2;
880 
881           /*
882            * Make sure the FS-independent codes match the internal ones,
883            * so we can use the passed-in objtype without having to
884            * convert it explicitly to QL_BLOCK/QL_FILE.
885            */
886           CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS);
887           CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES);
888           CTASSERT(N_QL == 2);
889 
890           if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) {
891                     return EINVAL;
892           }
893 
894           if (ump->um_quotas[qk->qk_idtype] == NULLVP)
895                     return ENODEV;
896           if (qk->qk_id == QUOTA_DEFAULTID) {
897                     mutex_enter(&dqlock);
898                     error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0);
899                     if (error) {
900                               mutex_exit(&dqlock);
901                               return error;
902                     }
903                     quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
904                     mutex_exit(&dqlock);
905                     brelse(bp, 0);
906                     q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2,
907                         qk->qk_objtype, qv);
908                     (void)id2;
909           } else
910                     error = quota2_fetch_quotaval(ump, qk, qv);
911 
912           return error;
913 }
914 
915 /*
916  * Cursor structure we used.
917  *
918  * This will get stored in userland between calls so we must not assume
919  * it isn't arbitrarily corrupted.
920  */
921 struct ufsq2_cursor {
922           uint32_t q2c_magic; /* magic number */
923           int q2c_hashsize;   /* size of hash table at last go */
924 
925           int q2c_users_done; /* true if we've returned all user data */
926           int q2c_groups_done;          /* true if we've returned all group data */
927           int q2c_defaults_done;        /* true if we've returned the default values */
928           int q2c_hashpos;    /* slot to start at in hash table */
929           int q2c_uidpos;               /* number of ids we've handled */
930           int q2c_blocks_done;          /* true if we've returned the blocks value */
931 };
932 
933 /*
934  * State of a single cursorget call, or at least the part of it that
935  * needs to be passed around.
936  */
937 struct q2cursor_state {
938           /* data return pointers */
939           struct quotakey *keys;
940           struct quotaval *vals;
941 
942           /* key/value counters */
943           unsigned maxkeyvals;
944           unsigned numkeys;   /* number of keys assigned */
945 
946           /* ID to key/value conversion state */
947           int skipfirst;                /* if true skip first key/value */
948           int skiplast;                 /* if true skip last key/value */
949 
950           /* ID counters */
951           unsigned maxids;    /* maximum number of IDs to handle */
952           unsigned numids;    /* number of IDs handled */
953 };
954 
955 /*
956  * Additional structure for getids callback.
957  */
958 struct q2cursor_getids {
959           struct q2cursor_state *state;
960           int idtype;
961           unsigned skip;                /* number of ids to skip over */
962           unsigned new_skip;  /* number of ids to skip over next time */
963           unsigned skipped;   /* number skipped so far */
964           int stopped;                  /* true if we stopped quota_walk_list early */
965 };
966 
967 /*
968  * Cursor-related functions
969  */
970 
971 /* magic number */
972 #define Q2C_MAGIC (0xbeebe111)
973 
974 /* extract cursor from caller form */
975 #define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0])
976 
977 /*
978  * Check that a cursor we're handed is something like valid. If
979  * someone munges it and it still passes these checks, they'll get
980  * partial or odd results back but won't break anything.
981  */
982 static int
q2cursor_check(struct ufsq2_cursor * cursor)983 q2cursor_check(struct ufsq2_cursor *cursor)
984 {
985           if (cursor->q2c_magic != Q2C_MAGIC) {
986                     return EINVAL;
987           }
988           if (cursor->q2c_hashsize < 0) {
989                     return EINVAL;
990           }
991 
992           if (cursor->q2c_users_done != 0 && cursor->q2c_users_done != 1) {
993                     return EINVAL;
994           }
995           if (cursor->q2c_groups_done != 0 && cursor->q2c_groups_done != 1) {
996                     return EINVAL;
997           }
998           if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) {
999                     return EINVAL;
1000           }
1001           if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) {
1002                     return EINVAL;
1003           }
1004           if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) {
1005                     return EINVAL;
1006           }
1007           return 0;
1008 }
1009 
1010 /*
1011  * Set up the q2cursor state.
1012  */
1013 static void
q2cursor_initstate(struct q2cursor_state * state,struct quotakey * keys,struct quotaval * vals,unsigned maxkeyvals,int blocks_done)1014 q2cursor_initstate(struct q2cursor_state *state, struct quotakey *keys,
1015     struct quotaval *vals, unsigned maxkeyvals, int blocks_done)
1016 {
1017           state->keys = keys;
1018           state->vals = vals;
1019 
1020           state->maxkeyvals = maxkeyvals;
1021           state->numkeys = 0;
1022 
1023           /*
1024            * For each ID there are two quotavals to return. If the
1025            * maximum number of entries to return is odd, we might want
1026            * to skip the first quotaval of the first ID, or the last
1027            * quotaval of the last ID, but not both. So the number of IDs
1028            * we want is (up to) half the number of return slots we have,
1029            * rounded up.
1030            */
1031 
1032           state->maxids = (state->maxkeyvals + 1) / 2;
1033           state->numids = 0;
1034           if (state->maxkeyvals % 2) {
1035                     if (blocks_done) {
1036                               state->skipfirst = 1;
1037                               state->skiplast = 0;
1038                     } else {
1039                               state->skipfirst = 0;
1040                               state->skiplast = 1;
1041                     }
1042           } else {
1043                     state->skipfirst = 0;
1044                     state->skiplast = 0;
1045           }
1046 }
1047 
1048 /*
1049  * Choose which idtype we're going to work on. If doing a full
1050  * iteration, we do users first, then groups, but either might be
1051  * disabled or marked to skip via cursorsetidtype(), so don't make
1052  * silly assumptions.
1053  */
1054 static int
q2cursor_pickidtype(struct ufsq2_cursor * cursor,int * idtype_ret)1055 q2cursor_pickidtype(struct ufsq2_cursor *cursor, int *idtype_ret)
1056 {
1057           if (cursor->q2c_users_done == 0) {
1058                     *idtype_ret = QUOTA_IDTYPE_USER;
1059           } else if (cursor->q2c_groups_done == 0) {
1060                     *idtype_ret = QUOTA_IDTYPE_GROUP;
1061           } else {
1062                     return EAGAIN;
1063           }
1064           return 0;
1065 }
1066 
1067 /*
1068  * Add an ID to the current state. Sets up either one or two keys to
1069  * refer to it, depending on whether it's first/last and the setting
1070  * of skipfirst. (skiplast does not need to be explicitly tested)
1071  */
1072 static void
q2cursor_addid(struct q2cursor_state * state,int idtype,id_t id)1073 q2cursor_addid(struct q2cursor_state *state, int idtype, id_t id)
1074 {
1075           KASSERT(state->numids < state->maxids);
1076           KASSERT(state->numkeys < state->maxkeyvals);
1077 
1078           if (!state->skipfirst || state->numkeys > 0) {
1079                     state->keys[state->numkeys].qk_idtype = idtype;
1080                     state->keys[state->numkeys].qk_id = id;
1081                     state->keys[state->numkeys].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
1082                     state->numkeys++;
1083           }
1084           if (state->numkeys < state->maxkeyvals) {
1085                     state->keys[state->numkeys].qk_idtype = idtype;
1086                     state->keys[state->numkeys].qk_id = id;
1087                     state->keys[state->numkeys].qk_objtype = QUOTA_OBJTYPE_FILES;
1088                     state->numkeys++;
1089           } else {
1090                     KASSERT(state->skiplast);
1091           }
1092           state->numids++;
1093 }
1094 
1095 /*
1096  * Callback function for getting IDs. Update counting and call addid.
1097  */
1098 static int
q2cursor_getids_callback(struct ufsmount * ump,uint64_t * offp,struct quota2_entry * q2ep,uint64_t off,void * v)1099 q2cursor_getids_callback(struct ufsmount *ump, uint64_t *offp,
1100     struct quota2_entry *q2ep, uint64_t off, void *v)
1101 {
1102           struct q2cursor_getids *gi = v;
1103           id_t id;
1104           const int needswap = UFS_MPNEEDSWAP(ump);
1105 
1106           if (gi->skipped < gi->skip) {
1107                     gi->skipped++;
1108                     return 0;
1109           }
1110           id = ufs_rw32(q2ep->q2e_uid, needswap);
1111           q2cursor_addid(gi->state, gi->idtype, id);
1112           gi->new_skip++;
1113           if (gi->state->numids >= gi->state->maxids) {
1114                     /* got enough ids, stop now */
1115                     gi->stopped = 1;
1116                     return Q2WL_ABORT;
1117           }
1118           return 0;
1119 }
1120 
1121 /*
1122  * Fill in a batch of quotakeys by scanning one or more hash chains.
1123  */
1124 static int
q2cursor_getkeys(struct ufsmount * ump,int idtype,struct ufsq2_cursor * cursor,struct q2cursor_state * state,int * hashsize_ret,struct quota2_entry * default_q2e_ret)1125 q2cursor_getkeys(struct ufsmount *ump, int idtype, struct ufsq2_cursor *cursor,
1126     struct q2cursor_state *state,
1127     int *hashsize_ret, struct quota2_entry *default_q2e_ret)
1128 {
1129           const int needswap = UFS_MPNEEDSWAP(ump);
1130           struct buf *hbp;
1131           struct quota2_header *q2h;
1132           int quota2_hash_size;
1133           struct q2cursor_getids gi;
1134           uint64_t offset;
1135           int error;
1136 
1137           /*
1138            * Read the header block.
1139            */
1140 
1141           mutex_enter(&dqlock);
1142           error = getq2h(ump, idtype, &hbp, &q2h, 0);
1143           if (error) {
1144                     mutex_exit(&dqlock);
1145                     return error;
1146           }
1147 
1148           /* if the table size has changed, make the caller start over */
1149           quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
1150           if (cursor->q2c_hashsize == 0) {
1151                     cursor->q2c_hashsize = quota2_hash_size;
1152           } else if (cursor->q2c_hashsize != quota2_hash_size) {
1153                     error = EDEADLK;
1154                     goto scanfail;
1155           }
1156 
1157           /* grab the entry with the default values out of the header */
1158           quota2_ufs_rwq2e(&q2h->q2h_defentry, default_q2e_ret, needswap);
1159 
1160           /* If we haven't done the defaults yet, that goes first. */
1161           if (cursor->q2c_defaults_done == 0) {
1162                     q2cursor_addid(state, idtype, QUOTA_DEFAULTID);
1163                     /* if we read both halves, mark it done */
1164                     if (state->numids < state->maxids || !state->skiplast) {
1165                               cursor->q2c_defaults_done = 1;
1166                     }
1167           }
1168 
1169           gi.state = state;
1170           gi.idtype = idtype;
1171 
1172           while (state->numids < state->maxids) {
1173                     if (cursor->q2c_hashpos >= quota2_hash_size) {
1174                               /* nothing more left */
1175                               break;
1176                     }
1177 
1178                     /* scan this hash chain */
1179                     gi.skip = cursor->q2c_uidpos;
1180                     gi.new_skip = gi.skip;
1181                     gi.skipped = 0;
1182                     gi.stopped = 0;
1183                     offset = q2h->q2h_entries[cursor->q2c_hashpos];
1184 
1185                     error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gi,
1186                         q2cursor_getids_callback);
1187                     KASSERT(error != Q2WL_ABORT);
1188                     if (error) {
1189                               break;
1190                     }
1191                     if (gi.stopped) {
1192                               /* callback stopped before reading whole chain */
1193                               cursor->q2c_uidpos = gi.new_skip;
1194                               /* if we didn't get both halves, back up */
1195                               if (state->numids == state->maxids && state->skiplast){
1196                                         KASSERT(cursor->q2c_uidpos > 0);
1197                                         cursor->q2c_uidpos--;
1198                               }
1199                     } else {
1200                               /* read whole chain */
1201                               /* if we got both halves of the last id, advance */
1202                               if (state->numids < state->maxids || !state->skiplast){
1203                                         cursor->q2c_uidpos = 0;
1204                                         cursor->q2c_hashpos++;
1205                               }
1206                     }
1207           }
1208 
1209 scanfail:
1210           mutex_exit(&dqlock);
1211           brelse(hbp, 0);
1212           if (error)
1213                     return error;
1214 
1215           *hashsize_ret = quota2_hash_size;
1216           return 0;
1217 }
1218 
1219 /*
1220  * Fetch the quotavals for the quotakeys.
1221  */
1222 static int
q2cursor_getvals(struct ufsmount * ump,struct q2cursor_state * state,const struct quota2_entry * default_q2e)1223 q2cursor_getvals(struct ufsmount *ump, struct q2cursor_state *state,
1224     const struct quota2_entry *default_q2e)
1225 {
1226           int hasid;
1227           id_t loadedid, id;
1228           unsigned pos;
1229           struct quota2_entry q2e;
1230           int objtype;
1231           int error;
1232 
1233           hasid = 0;
1234           loadedid = 0;
1235           for (pos = 0; pos < state->numkeys; pos++) {
1236                     id = state->keys[pos].qk_id;
1237                     if (!hasid || id != loadedid) {
1238                               hasid = 1;
1239                               loadedid = id;
1240                               if (id == QUOTA_DEFAULTID) {
1241                                         q2e = *default_q2e;
1242                               } else {
1243                                         error = quota2_fetch_q2e(ump,
1244                                             &state->keys[pos],
1245                                             &q2e);
1246                                         if (error == ENOENT) {
1247                                                   /* something changed - start over */
1248                                                   error = EDEADLK;
1249                                         }
1250                                         if (error) {
1251                                                   return error;
1252                                         }
1253                               }
1254                     }
1255 
1256 
1257                     objtype = state->keys[pos].qk_objtype;
1258                     KASSERT(objtype >= 0 && objtype < N_QL);
1259                     q2val_to_quotaval(&q2e.q2e_val[objtype], &state->vals[pos]);
1260           }
1261 
1262           return 0;
1263 }
1264 
1265 /*
1266  * Handle cursorget.
1267  *
1268  * We can't just read keys and values directly, because we can't walk
1269  * the list with qdlock and grab dq_interlock to read the entries at
1270  * the same time. So we're going to do two passes: one to figure out
1271  * which IDs we want and fill in the keys, and then a second to use
1272  * the keys to fetch the values.
1273  */
1274 int
quota2_handle_cmd_cursorget(struct ufsmount * ump,struct quotakcursor * qkc,struct quotakey * keys,struct quotaval * vals,unsigned maxreturn,unsigned * ret)1275 quota2_handle_cmd_cursorget(struct ufsmount *ump, struct quotakcursor *qkc,
1276     struct quotakey *keys, struct quotaval *vals, unsigned maxreturn,
1277     unsigned *ret)
1278 {
1279           int error;
1280           struct ufsq2_cursor *cursor;
1281           struct ufsq2_cursor newcursor;
1282           struct q2cursor_state state;
1283           struct quota2_entry default_q2e;
1284           int idtype;
1285           int quota2_hash_size = 0; /* XXX: sh3 gcc 4.8 -Wuninitialized */
1286 
1287           /*
1288            * Convert and validate the cursor.
1289            */
1290           cursor = Q2CURSOR(qkc);
1291           error = q2cursor_check(cursor);
1292           if (error) {
1293                     return error;
1294           }
1295 
1296           /*
1297            * Make sure our on-disk codes match the values of the
1298            * FS-independent ones. This avoids the need for explicit
1299            * conversion (which would be a NOP anyway and thus easily
1300            * left out or called in the wrong places...)
1301            */
1302           CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA);
1303           CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA);
1304           CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK);
1305           CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE);
1306 
1307           /*
1308            * If some of the idtypes aren't configured/enabled, arrange
1309            * to skip over them.
1310            */
1311           if (cursor->q2c_users_done == 0 &&
1312               ump->um_quotas[USRQUOTA] == NULLVP) {
1313                     cursor->q2c_users_done = 1;
1314           }
1315           if (cursor->q2c_groups_done == 0 &&
1316               ump->um_quotas[GRPQUOTA] == NULLVP) {
1317                     cursor->q2c_groups_done = 1;
1318           }
1319 
1320           /* Loop over, potentially, both idtypes */
1321           while (1) {
1322 
1323                     /* Choose id type */
1324                     error = q2cursor_pickidtype(cursor, &idtype);
1325                     if (error == EAGAIN) {
1326                               /* nothing more to do, return 0 */
1327                               *ret = 0;
1328                               return 0;
1329                     }
1330                     KASSERT(ump->um_quotas[idtype] != NULLVP);
1331 
1332                     /*
1333                      * Initialize the per-call iteration state. Copy the
1334                      * cursor state so we can update it in place but back
1335                      * out on error.
1336                      */
1337                     q2cursor_initstate(&state, keys, vals, maxreturn,
1338                         cursor->q2c_blocks_done);
1339                     newcursor = *cursor;
1340 
1341                     /* Assign keys */
1342                     error = q2cursor_getkeys(ump, idtype, &newcursor, &state,
1343                         &quota2_hash_size, &default_q2e);
1344                     if (error) {
1345                               return error;
1346                     }
1347 
1348                     /* Now fill in the values. */
1349                     error = q2cursor_getvals(ump, &state, &default_q2e);
1350                     if (error) {
1351                               return error;
1352                     }
1353 
1354                     /*
1355                      * Now that we aren't going to fail and lose what we
1356                      * did so far, we can update the cursor state.
1357                      */
1358 
1359                     if (newcursor.q2c_hashpos >= quota2_hash_size) {
1360                               if (idtype == QUOTA_IDTYPE_USER)
1361                                         cursor->q2c_users_done = 1;
1362                               else
1363                                         cursor->q2c_groups_done = 1;
1364 
1365                               /* start over on another id type */
1366                               cursor->q2c_hashsize = 0;
1367                               cursor->q2c_defaults_done = 0;
1368                               cursor->q2c_hashpos = 0;
1369                               cursor->q2c_uidpos = 0;
1370                               cursor->q2c_blocks_done = 0;
1371                     } else {
1372                               *cursor = newcursor;
1373                               cursor->q2c_blocks_done = state.skiplast;
1374                     }
1375 
1376                     /*
1377                      * If we have something to return, return it.
1378                      * Otherwise, continue to the other idtype, if any,
1379                      * and only return zero at end of iteration.
1380                      */
1381                     if (state.numkeys > 0) {
1382                               break;
1383                     }
1384           }
1385 
1386           *ret = state.numkeys;
1387           return 0;
1388 }
1389 
1390 int
quota2_handle_cmd_cursoropen(struct ufsmount * ump,struct quotakcursor * qkc)1391 quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc)
1392 {
1393           struct ufsq2_cursor *cursor;
1394 
1395           CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space));
1396           cursor = Q2CURSOR(qkc);
1397 
1398           cursor->q2c_magic = Q2C_MAGIC;
1399           cursor->q2c_hashsize = 0;
1400 
1401           cursor->q2c_users_done = 0;
1402           cursor->q2c_groups_done = 0;
1403           cursor->q2c_defaults_done = 0;
1404           cursor->q2c_hashpos = 0;
1405           cursor->q2c_uidpos = 0;
1406           cursor->q2c_blocks_done = 0;
1407           return 0;
1408 }
1409 
1410 int
quota2_handle_cmd_cursorclose(struct ufsmount * ump,struct quotakcursor * qkc)1411 quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc)
1412 {
1413           struct ufsq2_cursor *cursor;
1414           int error;
1415 
1416           cursor = Q2CURSOR(qkc);
1417           error = q2cursor_check(cursor);
1418           if (error) {
1419                     return error;
1420           }
1421 
1422           /* nothing to do */
1423 
1424           return 0;
1425 }
1426 
1427 int
quota2_handle_cmd_cursorskipidtype(struct ufsmount * ump,struct quotakcursor * qkc,int idtype)1428 quota2_handle_cmd_cursorskipidtype(struct ufsmount *ump,
1429     struct quotakcursor *qkc, int idtype)
1430 {
1431           struct ufsq2_cursor *cursor;
1432           int error;
1433 
1434           cursor = Q2CURSOR(qkc);
1435           error = q2cursor_check(cursor);
1436           if (error) {
1437                     return error;
1438           }
1439 
1440           switch (idtype) {
1441           case QUOTA_IDTYPE_USER:
1442                     cursor->q2c_users_done = 1;
1443                     break;
1444           case QUOTA_IDTYPE_GROUP:
1445                     cursor->q2c_groups_done = 1;
1446                     break;
1447           default:
1448                     return EINVAL;
1449           }
1450 
1451           return 0;
1452 }
1453 
1454 int
quota2_handle_cmd_cursoratend(struct ufsmount * ump,struct quotakcursor * qkc,int * ret)1455 quota2_handle_cmd_cursoratend(struct ufsmount *ump, struct quotakcursor *qkc,
1456     int *ret)
1457 {
1458           struct ufsq2_cursor *cursor;
1459           int error;
1460 
1461           cursor = Q2CURSOR(qkc);
1462           error = q2cursor_check(cursor);
1463           if (error) {
1464                     return error;
1465           }
1466 
1467           *ret = (cursor->q2c_users_done && cursor->q2c_groups_done);
1468           return 0;
1469 }
1470 
1471 int
quota2_handle_cmd_cursorrewind(struct ufsmount * ump,struct quotakcursor * qkc)1472 quota2_handle_cmd_cursorrewind(struct ufsmount *ump, struct quotakcursor *qkc)
1473 {
1474           struct ufsq2_cursor *cursor;
1475           int error;
1476 
1477           cursor = Q2CURSOR(qkc);
1478           error = q2cursor_check(cursor);
1479           if (error) {
1480                     return error;
1481           }
1482 
1483           cursor->q2c_hashsize = 0;
1484 
1485           cursor->q2c_users_done = 0;
1486           cursor->q2c_groups_done = 0;
1487           cursor->q2c_defaults_done = 0;
1488           cursor->q2c_hashpos = 0;
1489           cursor->q2c_uidpos = 0;
1490           cursor->q2c_blocks_done = 0;
1491 
1492           return 0;
1493 }
1494 
1495 int
q2sync(struct mount * mp)1496 q2sync(struct mount *mp)
1497 {
1498           return 0;
1499 }
1500 
1501 struct dq2get_callback {
1502           uid_t id;
1503           struct dquot *dq;
1504 };
1505 
1506 static int
dq2get_callback(struct ufsmount * ump,uint64_t * offp,struct quota2_entry * q2e,uint64_t off,void * v)1507 dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e,
1508     uint64_t off, void *v)
1509 {
1510           struct dq2get_callback *c = v;
1511           daddr_t lblkno;
1512           int blkoff;
1513           const int needswap = UFS_MPNEEDSWAP(ump);
1514 
1515           if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
1516                     KASSERT(mutex_owned(&c->dq->dq_interlock));
1517                     lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
1518                     blkoff = (off & ump->umq2_bmask);
1519                     c->dq->dq2_lblkno = lblkno;
1520                     c->dq->dq2_blkoff = blkoff;
1521                     return Q2WL_ABORT;
1522           }
1523           return 0;
1524 }
1525 
1526 int
dq2get(struct vnode * dqvp,u_long id,struct ufsmount * ump,int type,struct dquot * dq)1527 dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type,
1528     struct dquot *dq)
1529 {
1530           struct buf *bp;
1531           struct quota2_header *q2h;
1532           int error;
1533           daddr_t offset;
1534           u_long hash_mask;
1535           struct dq2get_callback c = {
1536                     .id = id,
1537                     .dq = dq
1538           };
1539 
1540           KASSERT(mutex_owned(&dq->dq_interlock));
1541           mutex_enter(&dqlock);
1542           error = getq2h(ump, type, &bp, &q2h, 0);
1543           if (error)
1544                     goto out_mutex;
1545           /* look for our entry */
1546           hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
1547           offset = q2h->q2h_entries[id & hash_mask];
1548           error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c,
1549               dq2get_callback);
1550           brelse(bp, 0);
1551 out_mutex:
1552           mutex_exit(&dqlock);
1553           return error;
1554 }
1555 
1556 int
dq2sync(struct vnode * vp,struct dquot * dq)1557 dq2sync(struct vnode *vp, struct dquot *dq)
1558 {
1559           return 0;
1560 }
1561