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