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