1 /* 2 * Copyright (c) 1982, 1986, 1990 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Robert Elz at The University of Melbourne. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)ufs_quota.c 7.16 (Berkeley) 07/03/92 11 */ 12 #include <sys/param.h> 13 #include <sys/kernel.h> 14 #include <sys/systm.h> 15 #include <sys/namei.h> 16 #include <sys/malloc.h> 17 #include <sys/file.h> 18 #include <sys/proc.h> 19 #include <sys/vnode.h> 20 #include <sys/mount.h> 21 22 #include <ufs/ufs/quota.h> 23 #include <ufs/ufs/inode.h> 24 #include <ufs/ufs/ufsmount.h> 25 #include <ufs/ufs/ufs_extern.h> 26 27 /* 28 * Quota name to error message mapping. 29 */ 30 static char *quotatypes[] = INITQFNAMES; 31 32 /* 33 * Set up the quotas for an inode. 34 * 35 * This routine completely defines the semantics of quotas. 36 * If other criterion want to be used to establish quotas, the 37 * MAXQUOTAS value in quotas.h should be increased, and the 38 * additional dquots set up here. 39 */ 40 int 41 getinoquota(ip) 42 register struct inode *ip; 43 { 44 struct ufsmount *ump; 45 struct vnode *vp = ITOV(ip); 46 int error; 47 48 ump = VFSTOUFS(vp->v_mount); 49 /* 50 * Set up the user quota based on file uid. 51 * EINVAL means that quotas are not enabled. 52 */ 53 if (ip->i_dquot[USRQUOTA] == NODQUOT && 54 (error = 55 dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) && 56 error != EINVAL) 57 return (error); 58 /* 59 * Set up the group quota based on file gid. 60 * EINVAL means that quotas are not enabled. 61 */ 62 if (ip->i_dquot[GRPQUOTA] == NODQUOT && 63 (error = 64 dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) && 65 error != EINVAL) 66 return (error); 67 return (0); 68 } 69 70 /* 71 * Update disk usage, and take corrective action. 72 */ 73 int 74 chkdq(ip, change, cred, flags) 75 register struct inode *ip; 76 long change; 77 struct ucred *cred; 78 int flags; 79 { 80 register struct dquot *dq; 81 register int i; 82 int ncurblocks, error; 83 84 #ifdef DIAGNOSTIC 85 if ((flags & CHOWN) == 0) 86 chkdquot(ip); 87 #endif 88 if (change == 0) 89 return (0); 90 if (change < 0) { 91 for (i = 0; i < MAXQUOTAS; i++) { 92 if ((dq = ip->i_dquot[i]) == NODQUOT) 93 continue; 94 while (dq->dq_flags & DQ_LOCK) { 95 dq->dq_flags |= DQ_WANT; 96 sleep((caddr_t)dq, PINOD+1); 97 } 98 ncurblocks = dq->dq_curblocks + change; 99 if (ncurblocks >= 0) 100 dq->dq_curblocks = ncurblocks; 101 else 102 dq->dq_curblocks = 0; 103 dq->dq_flags &= ~DQ_BLKS; 104 dq->dq_flags |= DQ_MOD; 105 } 106 return (0); 107 } 108 if ((flags & FORCE) == 0 && cred->cr_uid != 0) { 109 for (i = 0; i < MAXQUOTAS; i++) { 110 if ((dq = ip->i_dquot[i]) == NODQUOT) 111 continue; 112 if (error = chkdqchg(ip, change, cred, i)) 113 return (error); 114 } 115 } 116 for (i = 0; i < MAXQUOTAS; i++) { 117 if ((dq = ip->i_dquot[i]) == NODQUOT) 118 continue; 119 while (dq->dq_flags & DQ_LOCK) { 120 dq->dq_flags |= DQ_WANT; 121 sleep((caddr_t)dq, PINOD+1); 122 } 123 dq->dq_curblocks += change; 124 dq->dq_flags |= DQ_MOD; 125 } 126 return (0); 127 } 128 129 /* 130 * Check for a valid change to a users allocation. 131 * Issue an error message if appropriate. 132 */ 133 int 134 chkdqchg(ip, change, cred, type) 135 struct inode *ip; 136 long change; 137 struct ucred *cred; 138 int type; 139 { 140 register struct dquot *dq = ip->i_dquot[type]; 141 long ncurblocks = dq->dq_curblocks + change; 142 143 /* 144 * If user would exceed their hard limit, disallow space allocation. 145 */ 146 if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) { 147 if ((dq->dq_flags & DQ_BLKS) == 0 && 148 ip->i_uid == cred->cr_uid) { 149 uprintf("\n%s: write failed, %s disk limit reached\n", 150 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 151 quotatypes[type]); 152 dq->dq_flags |= DQ_BLKS; 153 } 154 return (EDQUOT); 155 } 156 /* 157 * If user is over their soft limit for too long, disallow space 158 * allocation. Reset time limit as they cross their soft limit. 159 */ 160 if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) { 161 if (dq->dq_curblocks < dq->dq_bsoftlimit) { 162 dq->dq_btime = time.tv_sec + 163 VFSTOUFS(ITOV(ip)->v_mount)->um_btime[type]; 164 if (ip->i_uid == cred->cr_uid) 165 uprintf("\n%s: warning, %s %s\n", 166 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 167 quotatypes[type], "disk quota exceeded"); 168 return (0); 169 } 170 if (time.tv_sec > dq->dq_btime) { 171 if ((dq->dq_flags & DQ_BLKS) == 0 && 172 ip->i_uid == cred->cr_uid) { 173 uprintf("\n%s: write failed, %s %s\n", 174 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 175 quotatypes[type], 176 "disk quota exceeded for too long"); 177 dq->dq_flags |= DQ_BLKS; 178 } 179 return (EDQUOT); 180 } 181 } 182 return (0); 183 } 184 185 /* 186 * Check the inode limit, applying corrective action. 187 */ 188 int 189 chkiq(ip, change, cred, flags) 190 register struct inode *ip; 191 long change; 192 struct ucred *cred; 193 int flags; 194 { 195 register struct dquot *dq; 196 register int i; 197 int ncurinodes, error; 198 199 #ifdef DIAGNOSTIC 200 if ((flags & CHOWN) == 0) 201 chkdquot(ip); 202 #endif 203 if (change == 0) 204 return (0); 205 if (change < 0) { 206 for (i = 0; i < MAXQUOTAS; i++) { 207 if ((dq = ip->i_dquot[i]) == NODQUOT) 208 continue; 209 while (dq->dq_flags & DQ_LOCK) { 210 dq->dq_flags |= DQ_WANT; 211 sleep((caddr_t)dq, PINOD+1); 212 } 213 ncurinodes = dq->dq_curinodes + change; 214 if (ncurinodes >= 0) 215 dq->dq_curinodes = ncurinodes; 216 else 217 dq->dq_curinodes = 0; 218 dq->dq_flags &= ~DQ_INODS; 219 dq->dq_flags |= DQ_MOD; 220 } 221 return (0); 222 } 223 if ((flags & FORCE) == 0 && cred->cr_uid != 0) { 224 for (i = 0; i < MAXQUOTAS; i++) { 225 if ((dq = ip->i_dquot[i]) == NODQUOT) 226 continue; 227 if (error = chkiqchg(ip, change, cred, i)) 228 return (error); 229 } 230 } 231 for (i = 0; i < MAXQUOTAS; i++) { 232 if ((dq = ip->i_dquot[i]) == NODQUOT) 233 continue; 234 while (dq->dq_flags & DQ_LOCK) { 235 dq->dq_flags |= DQ_WANT; 236 sleep((caddr_t)dq, PINOD+1); 237 } 238 dq->dq_curinodes += change; 239 dq->dq_flags |= DQ_MOD; 240 } 241 return (0); 242 } 243 244 /* 245 * Check for a valid change to a users allocation. 246 * Issue an error message if appropriate. 247 */ 248 int 249 chkiqchg(ip, change, cred, type) 250 struct inode *ip; 251 long change; 252 struct ucred *cred; 253 int type; 254 { 255 register struct dquot *dq = ip->i_dquot[type]; 256 long ncurinodes = dq->dq_curinodes + change; 257 258 /* 259 * If user would exceed their hard limit, disallow inode allocation. 260 */ 261 if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) { 262 if ((dq->dq_flags & DQ_INODS) == 0 && 263 ip->i_uid == cred->cr_uid) { 264 uprintf("\n%s: write failed, %s inode limit reached\n", 265 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 266 quotatypes[type]); 267 dq->dq_flags |= DQ_INODS; 268 } 269 return (EDQUOT); 270 } 271 /* 272 * If user is over their soft limit for too long, disallow inode 273 * allocation. Reset time limit as they cross their soft limit. 274 */ 275 if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) { 276 if (dq->dq_curinodes < dq->dq_isoftlimit) { 277 dq->dq_itime = time.tv_sec + 278 VFSTOUFS(ITOV(ip)->v_mount)->um_itime[type]; 279 if (ip->i_uid == cred->cr_uid) 280 uprintf("\n%s: warning, %s %s\n", 281 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 282 quotatypes[type], "inode quota exceeded"); 283 return (0); 284 } 285 if (time.tv_sec > dq->dq_itime) { 286 if ((dq->dq_flags & DQ_INODS) == 0 && 287 ip->i_uid == cred->cr_uid) { 288 uprintf("\n%s: write failed, %s %s\n", 289 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 290 quotatypes[type], 291 "inode quota exceeded for too long"); 292 dq->dq_flags |= DQ_INODS; 293 } 294 return (EDQUOT); 295 } 296 } 297 return (0); 298 } 299 300 #ifdef DIAGNOSTIC 301 /* 302 * On filesystems with quotas enabled, it is an error for a file to change 303 * size and not to have a dquot structure associated with it. 304 */ 305 void 306 chkdquot(ip) 307 register struct inode *ip; 308 { 309 struct ufsmount *ump = VFSTOUFS(ITOV(ip)->v_mount); 310 register int i; 311 312 for (i = 0; i < MAXQUOTAS; i++) { 313 if (ump->um_quotas[i] == NULLVP || 314 (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING))) 315 continue; 316 if (ip->i_dquot[i] == NODQUOT) { 317 vprint("chkdquot: missing dquot", ITOV(ip)); 318 panic("missing dquot"); 319 } 320 } 321 } 322 #endif 323 324 /* 325 * Code to process quotactl commands. 326 */ 327 328 /* 329 * Q_QUOTAON - set up a quota file for a particular file system. 330 */ 331 int 332 quotaon(p, mp, type, fname) 333 struct proc *p; 334 struct mount *mp; 335 register int type; 336 caddr_t fname; 337 { 338 register struct ufsmount *ump = VFSTOUFS(mp); 339 register struct vnode *vp, **vpp; 340 struct vnode *nextvp; 341 struct dquot *dq; 342 int error; 343 struct nameidata nd; 344 345 vpp = &ump->um_quotas[type]; 346 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname, p); 347 if (error = vn_open(&nd, FREAD|FWRITE, 0)) 348 return (error); 349 vp = nd.ni_vp; 350 VOP_UNLOCK(vp); 351 if (vp->v_type != VREG) { 352 (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 353 return (EACCES); 354 } 355 if (vfs_busy(mp)) { 356 (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 357 return (EBUSY); 358 } 359 if (*vpp != vp) 360 quotaoff(p, mp, type); 361 ump->um_qflags[type] |= QTF_OPENING; 362 mp->mnt_flag |= MNT_QUOTA; 363 vp->v_flag |= VSYSTEM; 364 *vpp = vp; 365 /* 366 * Save the credential of the process that turned on quotas. 367 * Set up the time limits for this quota. 368 */ 369 crhold(p->p_ucred); 370 ump->um_cred[type] = p->p_ucred; 371 ump->um_btime[type] = MAX_DQ_TIME; 372 ump->um_itime[type] = MAX_IQ_TIME; 373 if (dqget(NULLVP, 0, ump, type, &dq) == 0) { 374 if (dq->dq_btime > 0) 375 ump->um_btime[type] = dq->dq_btime; 376 if (dq->dq_itime > 0) 377 ump->um_itime[type] = dq->dq_itime; 378 dqrele(NULLVP, dq); 379 } 380 /* 381 * Search vnodes associated with this mount point, 382 * adding references to quota file being opened. 383 * NB: only need to add dquot's for inodes being modified. 384 */ 385 again: 386 for (vp = mp->mnt_mounth; vp; vp = nextvp) { 387 nextvp = vp->v_mountf; 388 if (vp->v_writecount == 0) 389 continue; 390 if (vget(vp)) 391 goto again; 392 if (error = getinoquota(VTOI(vp))) { 393 vput(vp); 394 break; 395 } 396 vput(vp); 397 if (vp->v_mountf != nextvp || vp->v_mount != mp) 398 goto again; 399 } 400 ump->um_qflags[type] &= ~QTF_OPENING; 401 if (error) 402 quotaoff(p, mp, type); 403 vfs_unbusy(mp); 404 return (error); 405 } 406 407 /* 408 * Q_QUOTAOFF - turn off disk quotas for a filesystem. 409 */ 410 int 411 quotaoff(p, mp, type) 412 struct proc *p; 413 struct mount *mp; 414 register int type; 415 { 416 register struct vnode *vp; 417 struct vnode *qvp, *nextvp; 418 struct ufsmount *ump = VFSTOUFS(mp); 419 register struct dquot *dq; 420 register struct inode *ip; 421 int error; 422 423 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 424 panic("quotaoff: not busy"); 425 if ((qvp = ump->um_quotas[type]) == NULLVP) 426 return (0); 427 ump->um_qflags[type] |= QTF_CLOSING; 428 /* 429 * Search vnodes associated with this mount point, 430 * deleting any references to quota file being closed. 431 */ 432 again: 433 for (vp = mp->mnt_mounth; vp; vp = nextvp) { 434 nextvp = vp->v_mountf; 435 if (vget(vp)) 436 goto again; 437 ip = VTOI(vp); 438 dq = ip->i_dquot[type]; 439 ip->i_dquot[type] = NODQUOT; 440 dqrele(vp, dq); 441 vput(vp); 442 if (vp->v_mountf != nextvp || vp->v_mount != mp) 443 goto again; 444 } 445 dqflush(qvp); 446 qvp->v_flag &= ~VSYSTEM; 447 error = vn_close(qvp, FREAD|FWRITE, p->p_ucred, p); 448 ump->um_quotas[type] = NULLVP; 449 crfree(ump->um_cred[type]); 450 ump->um_cred[type] = NOCRED; 451 ump->um_qflags[type] &= ~QTF_CLOSING; 452 for (type = 0; type < MAXQUOTAS; type++) 453 if (ump->um_quotas[type] != NULLVP) 454 break; 455 if (type == MAXQUOTAS) 456 mp->mnt_flag &= ~MNT_QUOTA; 457 return (error); 458 } 459 460 /* 461 * Q_GETQUOTA - return current values in a dqblk structure. 462 */ 463 int 464 getquota(mp, id, type, addr) 465 struct mount *mp; 466 u_long id; 467 int type; 468 caddr_t addr; 469 { 470 struct dquot *dq; 471 int error; 472 473 if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq)) 474 return (error); 475 error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk)); 476 dqrele(NULLVP, dq); 477 return (error); 478 } 479 480 /* 481 * Q_SETQUOTA - assign an entire dqblk structure. 482 */ 483 int 484 setquota(mp, id, type, addr) 485 struct mount *mp; 486 u_long id; 487 int type; 488 caddr_t addr; 489 { 490 register struct dquot *dq; 491 struct dquot *ndq; 492 struct ufsmount *ump = VFSTOUFS(mp); 493 struct dqblk newlim; 494 int error; 495 496 if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk))) 497 return (error); 498 if (error = dqget(NULLVP, id, ump, type, &ndq)) 499 return (error); 500 dq = ndq; 501 while (dq->dq_flags & DQ_LOCK) { 502 dq->dq_flags |= DQ_WANT; 503 sleep((caddr_t)dq, PINOD+1); 504 } 505 /* 506 * Copy all but the current values. 507 * Reset time limit if previously had no soft limit or were 508 * under it, but now have a soft limit and are over it. 509 */ 510 newlim.dqb_curblocks = dq->dq_curblocks; 511 newlim.dqb_curinodes = dq->dq_curinodes; 512 if (dq->dq_id != 0) { 513 newlim.dqb_btime = dq->dq_btime; 514 newlim.dqb_itime = dq->dq_itime; 515 } 516 if (newlim.dqb_bsoftlimit && 517 dq->dq_curblocks >= newlim.dqb_bsoftlimit && 518 (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit)) 519 newlim.dqb_btime = time.tv_sec + ump->um_btime[type]; 520 if (newlim.dqb_isoftlimit && 521 dq->dq_curinodes >= newlim.dqb_isoftlimit && 522 (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit)) 523 newlim.dqb_itime = time.tv_sec + ump->um_itime[type]; 524 dq->dq_dqb = newlim; 525 if (dq->dq_curblocks < dq->dq_bsoftlimit) 526 dq->dq_flags &= ~DQ_BLKS; 527 if (dq->dq_curinodes < dq->dq_isoftlimit) 528 dq->dq_flags &= ~DQ_INODS; 529 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && 530 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) 531 dq->dq_flags |= DQ_FAKE; 532 else 533 dq->dq_flags &= ~DQ_FAKE; 534 dq->dq_flags |= DQ_MOD; 535 dqrele(NULLVP, dq); 536 return (0); 537 } 538 539 /* 540 * Q_SETUSE - set current inode and block usage. 541 */ 542 int 543 setuse(mp, id, type, addr) 544 struct mount *mp; 545 u_long id; 546 int type; 547 caddr_t addr; 548 { 549 register struct dquot *dq; 550 struct ufsmount *ump = VFSTOUFS(mp); 551 struct dquot *ndq; 552 struct dqblk usage; 553 int error; 554 555 if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk))) 556 return (error); 557 if (error = dqget(NULLVP, id, ump, type, &ndq)) 558 return (error); 559 dq = ndq; 560 while (dq->dq_flags & DQ_LOCK) { 561 dq->dq_flags |= DQ_WANT; 562 sleep((caddr_t)dq, PINOD+1); 563 } 564 /* 565 * Reset time limit if have a soft limit and were 566 * previously under it, but are now over it. 567 */ 568 if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit && 569 usage.dqb_curblocks >= dq->dq_bsoftlimit) 570 dq->dq_btime = time.tv_sec + ump->um_btime[type]; 571 if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit && 572 usage.dqb_curinodes >= dq->dq_isoftlimit) 573 dq->dq_itime = time.tv_sec + ump->um_itime[type]; 574 dq->dq_curblocks = usage.dqb_curblocks; 575 dq->dq_curinodes = usage.dqb_curinodes; 576 if (dq->dq_curblocks < dq->dq_bsoftlimit) 577 dq->dq_flags &= ~DQ_BLKS; 578 if (dq->dq_curinodes < dq->dq_isoftlimit) 579 dq->dq_flags &= ~DQ_INODS; 580 dq->dq_flags |= DQ_MOD; 581 dqrele(NULLVP, dq); 582 return (0); 583 } 584 585 /* 586 * Q_SYNC - sync quota files to disk. 587 */ 588 int 589 qsync(mp) 590 struct mount *mp; 591 { 592 struct ufsmount *ump = VFSTOUFS(mp); 593 register struct vnode *vp, *nextvp; 594 register struct dquot *dq; 595 register int i; 596 597 /* 598 * Check if the mount point has any quotas. 599 * If not, simply return. 600 */ 601 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 602 panic("qsync: not busy"); 603 for (i = 0; i < MAXQUOTAS; i++) 604 if (ump->um_quotas[i] != NULLVP) 605 break; 606 if (i == MAXQUOTAS) 607 return (0); 608 /* 609 * Search vnodes associated with this mount point, 610 * synchronizing any modified dquot structures. 611 */ 612 again: 613 for (vp = mp->mnt_mounth; vp; vp = nextvp) { 614 nextvp = vp->v_mountf; 615 if (VOP_ISLOCKED(vp)) 616 continue; 617 if (vget(vp)) 618 goto again; 619 for (i = 0; i < MAXQUOTAS; i++) { 620 dq = VTOI(vp)->i_dquot[i]; 621 if (dq != NODQUOT && (dq->dq_flags & DQ_MOD)) 622 dqsync(vp, dq); 623 } 624 vput(vp); 625 if (vp->v_mountf != nextvp || vp->v_mount != mp) 626 goto again; 627 } 628 return (0); 629 } 630 631 /* 632 * Code pertaining to management of the in-core dquot data structures. 633 */ 634 635 /* 636 * Dquot cache - hash chain headers. 637 */ 638 union dqhead { 639 union dqhead *dqh_head[2]; 640 struct dquot *dqh_chain[2]; 641 }; 642 #define dqh_forw dqh_chain[0] 643 #define dqh_back dqh_chain[1] 644 645 union dqhead *dqhashtbl; 646 long dqhash; 647 648 /* 649 * Dquot free list. 650 */ 651 #define DQUOTINC 5 /* minimum free dquots desired */ 652 struct dquot *dqfreel, **dqback = &dqfreel; 653 long numdquot, desireddquot = DQUOTINC; 654 655 /* 656 * Initialize the quota system. 657 */ 658 void 659 dqinit() 660 { 661 register union dqhead *dhp; 662 register long dqhashsize; 663 664 dqhashsize = roundup((desiredvnodes + 1) * sizeof *dhp / 2, 665 NBPG * CLSIZE); 666 dqhashtbl = (union dqhead *)malloc(dqhashsize, M_DQUOT, M_WAITOK); 667 for (dqhash = 1; dqhash <= dqhashsize / sizeof *dhp; dqhash <<= 1) 668 continue; 669 dqhash = (dqhash >> 1) - 1; 670 for (dhp = &dqhashtbl[dqhash]; dhp >= dqhashtbl; dhp--) { 671 dhp->dqh_head[0] = dhp; 672 dhp->dqh_head[1] = dhp; 673 } 674 } 675 676 /* 677 * Obtain a dquot structure for the specified identifier and quota file 678 * reading the information from the file if necessary. 679 */ 680 int 681 dqget(vp, id, ump, type, dqp) 682 struct vnode *vp; 683 u_long id; 684 register struct ufsmount *ump; 685 register int type; 686 struct dquot **dqp; 687 { 688 register struct dquot *dq; 689 register union dqhead *dh; 690 register struct dquot *dp; 691 register struct vnode *dqvp; 692 struct iovec aiov; 693 struct uio auio; 694 int error; 695 696 dqvp = ump->um_quotas[type]; 697 if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) { 698 *dqp = NODQUOT; 699 return (EINVAL); 700 } 701 /* 702 * Check the cache first. 703 */ 704 dh = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash]; 705 for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = dq->dq_forw) { 706 if (dq->dq_id != id || 707 dq->dq_ump->um_quotas[dq->dq_type] != dqvp) 708 continue; 709 /* 710 * Cache hit with no references. Take 711 * the structure off the free list. 712 */ 713 if (dq->dq_cnt == 0) { 714 dp = dq->dq_freef; 715 if (dp != NODQUOT) 716 dp->dq_freeb = dq->dq_freeb; 717 else 718 dqback = dq->dq_freeb; 719 *dq->dq_freeb = dp; 720 } 721 DQREF(dq); 722 *dqp = dq; 723 return (0); 724 } 725 /* 726 * Not in cache, allocate a new one. 727 */ 728 if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes) 729 desireddquot += DQUOTINC; 730 if (numdquot < desireddquot) { 731 dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK); 732 bzero((char *)dq, sizeof *dq); 733 numdquot++; 734 } else { 735 if ((dq = dqfreel) == NULL) { 736 tablefull("dquot"); 737 *dqp = NODQUOT; 738 return (EUSERS); 739 } 740 if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) 741 panic("free dquot isn't"); 742 if ((dp = dq->dq_freef) != NODQUOT) 743 dp->dq_freeb = &dqfreel; 744 else 745 dqback = &dqfreel; 746 dqfreel = dp; 747 dq->dq_freef = NULL; 748 dq->dq_freeb = NULL; 749 remque(dq); 750 } 751 /* 752 * Initialize the contents of the dquot structure. 753 */ 754 if (vp != dqvp) 755 VOP_LOCK(dqvp); 756 insque(dq, dh); 757 DQREF(dq); 758 dq->dq_flags = DQ_LOCK; 759 dq->dq_id = id; 760 dq->dq_ump = ump; 761 dq->dq_type = type; 762 auio.uio_iov = &aiov; 763 auio.uio_iovcnt = 1; 764 aiov.iov_base = (caddr_t)&dq->dq_dqb; 765 aiov.iov_len = sizeof (struct dqblk); 766 auio.uio_resid = sizeof (struct dqblk); 767 auio.uio_offset = (off_t)(id * sizeof (struct dqblk)); 768 auio.uio_segflg = UIO_SYSSPACE; 769 auio.uio_rw = UIO_READ; 770 auio.uio_procp = (struct proc *)0; 771 error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]); 772 if (auio.uio_resid == sizeof(struct dqblk) && error == 0) 773 bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk)); 774 if (vp != dqvp) 775 VOP_UNLOCK(dqvp); 776 if (dq->dq_flags & DQ_WANT) 777 wakeup((caddr_t)dq); 778 dq->dq_flags = 0; 779 /* 780 * I/O error in reading quota file, release 781 * quota structure and reflect problem to caller. 782 */ 783 if (error) { 784 remque(dq); 785 dq->dq_forw = dq; /* on a private, unfindable hash list */ 786 dq->dq_back = dq; 787 dqrele(vp, dq); 788 *dqp = NODQUOT; 789 return (error); 790 } 791 /* 792 * Check for no limit to enforce. 793 * Initialize time values if necessary. 794 */ 795 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && 796 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) 797 dq->dq_flags |= DQ_FAKE; 798 if (dq->dq_id != 0) { 799 if (dq->dq_btime == 0) 800 dq->dq_btime = time.tv_sec + ump->um_btime[type]; 801 if (dq->dq_itime == 0) 802 dq->dq_itime = time.tv_sec + ump->um_itime[type]; 803 } 804 *dqp = dq; 805 return (0); 806 } 807 808 /* 809 * Obtain a reference to a dquot. 810 */ 811 void 812 dqref(dq) 813 struct dquot *dq; 814 { 815 816 dq->dq_cnt++; 817 } 818 819 /* 820 * Release a reference to a dquot. 821 */ 822 void 823 dqrele(vp, dq) 824 struct vnode *vp; 825 register struct dquot *dq; 826 { 827 828 if (dq == NODQUOT) 829 return; 830 if (dq->dq_cnt > 1) { 831 dq->dq_cnt--; 832 return; 833 } 834 if (dq->dq_flags & DQ_MOD) 835 (void) dqsync(vp, dq); 836 if (--dq->dq_cnt > 0) 837 return; 838 if (dqfreel != NODQUOT) { 839 *dqback = dq; 840 dq->dq_freeb = dqback; 841 } else { 842 dqfreel = dq; 843 dq->dq_freeb = &dqfreel; 844 } 845 dq->dq_freef = NODQUOT; 846 dqback = &dq->dq_freef; 847 } 848 849 /* 850 * Update the disk quota in the quota file. 851 */ 852 int 853 dqsync(vp, dq) 854 struct vnode *vp; 855 register struct dquot *dq; 856 { 857 struct vnode *dqvp; 858 struct iovec aiov; 859 struct uio auio; 860 int error; 861 862 if (dq == NODQUOT) 863 panic("dqsync: dquot"); 864 if ((dq->dq_flags & DQ_MOD) == 0) 865 return (0); 866 if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP) 867 panic("dqsync: file"); 868 if (vp != dqvp) 869 VOP_LOCK(dqvp); 870 while (dq->dq_flags & DQ_LOCK) { 871 dq->dq_flags |= DQ_WANT; 872 sleep((caddr_t)dq, PINOD+2); 873 if ((dq->dq_flags & DQ_MOD) == 0) { 874 if (vp != dqvp) 875 VOP_UNLOCK(dqvp); 876 return (0); 877 } 878 } 879 dq->dq_flags |= DQ_LOCK; 880 auio.uio_iov = &aiov; 881 auio.uio_iovcnt = 1; 882 aiov.iov_base = (caddr_t)&dq->dq_dqb; 883 aiov.iov_len = sizeof (struct dqblk); 884 auio.uio_resid = sizeof (struct dqblk); 885 auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk)); 886 auio.uio_segflg = UIO_SYSSPACE; 887 auio.uio_rw = UIO_WRITE; 888 auio.uio_procp = (struct proc *)0; 889 error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); 890 if (auio.uio_resid && error == 0) 891 error = EIO; 892 if (dq->dq_flags & DQ_WANT) 893 wakeup((caddr_t)dq); 894 dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT); 895 if (vp != dqvp) 896 VOP_UNLOCK(dqvp); 897 return (error); 898 } 899 900 /* 901 * Flush all entries from the cache for a particular vnode. 902 */ 903 void 904 dqflush(vp) 905 register struct vnode *vp; 906 { 907 register union dqhead *dh; 908 register struct dquot *dq, *nextdq; 909 910 /* 911 * Move all dquot's that used to refer to this quota 912 * file off their hash chains (they will eventually 913 * fall off the head of the free list and be re-used). 914 */ 915 for (dh = &dqhashtbl[dqhash]; dh >= dqhashtbl; dh--) { 916 for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = nextdq) { 917 nextdq = dq->dq_forw; 918 if (dq->dq_ump->um_quotas[dq->dq_type] != vp) 919 continue; 920 if (dq->dq_cnt) 921 panic("dqflush: stray dquot"); 922 remque(dq); 923 dq->dq_forw = dq; 924 dq->dq_back = dq; 925 dq->dq_ump = (struct ufsmount *)0; 926 } 927 } 928 } 929