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.7 (Berkeley) 03/19/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 if (vp->v_type != VREG) { 342 vrele(vp); 343 return (EACCES); 344 } 345 if (vfs_busy(mp)) { 346 vrele(vp); 347 return (EBUSY); 348 } 349 if (*vpp != vp) 350 quotaoff(mp, type); 351 ump->um_qflags[type] |= QTF_OPENING; 352 mp->mnt_flag |= MNT_QUOTA; 353 vp->v_flag |= VSYSTEM; 354 *vpp = vp; 355 /* 356 * Save the credential of the process that turned on quotas. 357 * Set up the time limits for this quota. 358 */ 359 crhold(p->p_ucred); 360 ump->um_cred[type] = p->p_ucred; 361 ump->um_btime[type] = MAX_DQ_TIME; 362 ump->um_itime[type] = MAX_IQ_TIME; 363 if (dqget(NULLVP, 0, ump, type, &dq) == 0) { 364 if (dq->dq_btime > 0) 365 ump->um_btime[type] = dq->dq_btime; 366 if (dq->dq_itime > 0) 367 ump->um_itime[type] = dq->dq_itime; 368 dqrele(NULLVP, dq); 369 } 370 /* 371 * Search vnodes associated with this mount point, 372 * adding references to quota file being opened. 373 * NB: only need to add dquot's for inodes being modified; 374 * vp->v_usecount == 0 below should use vp->v_writecnt == 0. 375 */ 376 again: 377 for (vp = mp->mnt_mounth; vp; vp = nextvp) { 378 nextvp = vp->v_mountf; 379 if (vp->v_usecount == 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(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(mp, type) 402 struct mount *mp; 403 register int type; 404 { 405 register struct vnode *vp; 406 struct vnode *qvp, *nextvp; 407 struct ufsmount *ump = VFSTOUFS(mp); 408 register struct dquot *dq; 409 register struct inode *ip; 410 411 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 412 panic("quotaoff: not busy"); 413 if ((qvp = ump->um_quotas[type]) == NULLVP) 414 return (0); 415 ump->um_qflags[type] |= QTF_CLOSING; 416 /* 417 * Search vnodes associated with this mount point, 418 * deleting any references to quota file being closed. 419 */ 420 again: 421 for (vp = mp->mnt_mounth; vp; vp = nextvp) { 422 nextvp = vp->v_mountf; 423 if (vget(vp)) 424 goto again; 425 ip = VTOI(vp); 426 dq = ip->i_dquot[type]; 427 ip->i_dquot[type] = NODQUOT; 428 dqrele(vp, dq); 429 vput(vp); 430 if (vp->v_mountf != nextvp || vp->v_mount != mp) 431 goto again; 432 } 433 dqflush(qvp); 434 qvp->v_flag &= ~VSYSTEM; 435 vrele(qvp); 436 ump->um_quotas[type] = NULLVP; 437 crfree(ump->um_cred[type]); 438 ump->um_cred[type] = NOCRED; 439 ump->um_qflags[type] &= ~QTF_CLOSING; 440 for (type = 0; type < MAXQUOTAS; type++) 441 if (ump->um_quotas[type] != NULLVP) 442 break; 443 if (type == MAXQUOTAS) 444 mp->mnt_flag &= ~MNT_QUOTA; 445 return (0); 446 } 447 448 /* 449 * Q_GETQUOTA - return current values in a dqblk structure. 450 */ 451 getquota(mp, id, type, addr) 452 struct mount *mp; 453 u_long id; 454 int type; 455 caddr_t addr; 456 { 457 struct dquot *dq; 458 int error; 459 460 if (error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq)) 461 return (error); 462 error = copyout((caddr_t)&dq->dq_dqb, addr, sizeof (struct dqblk)); 463 dqrele(NULLVP, dq); 464 return (error); 465 } 466 467 /* 468 * Q_SETQUOTA - assign an entire dqblk structure. 469 */ 470 setquota(mp, id, type, addr) 471 struct mount *mp; 472 u_long id; 473 int type; 474 caddr_t addr; 475 { 476 register struct dquot *dq; 477 struct dquot *ndq; 478 struct ufsmount *ump = VFSTOUFS(mp); 479 struct dqblk newlim; 480 int error; 481 482 if (error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk))) 483 return (error); 484 if (error = dqget(NULLVP, id, ump, type, &ndq)) 485 return (error); 486 dq = ndq; 487 while (dq->dq_flags & DQ_LOCK) { 488 dq->dq_flags |= DQ_WANT; 489 sleep((caddr_t)dq, PINOD+1); 490 } 491 /* 492 * Copy all but the current values. 493 * Reset time limit if previously had no soft limit or were 494 * under it, but now have a soft limit and are over it. 495 */ 496 newlim.dqb_curblocks = dq->dq_curblocks; 497 newlim.dqb_curinodes = dq->dq_curinodes; 498 if (dq->dq_id != 0) { 499 newlim.dqb_btime = dq->dq_btime; 500 newlim.dqb_itime = dq->dq_itime; 501 } 502 if (newlim.dqb_bsoftlimit && 503 dq->dq_curblocks >= newlim.dqb_bsoftlimit && 504 (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit)) 505 newlim.dqb_btime = time.tv_sec + ump->um_btime[type]; 506 if (newlim.dqb_isoftlimit && 507 dq->dq_curinodes >= newlim.dqb_isoftlimit && 508 (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit)) 509 newlim.dqb_itime = time.tv_sec + ump->um_itime[type]; 510 dq->dq_dqb = newlim; 511 if (dq->dq_curblocks < dq->dq_bsoftlimit) 512 dq->dq_flags &= ~DQ_BLKS; 513 if (dq->dq_curinodes < dq->dq_isoftlimit) 514 dq->dq_flags &= ~DQ_INODS; 515 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && 516 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) 517 dq->dq_flags |= DQ_FAKE; 518 else 519 dq->dq_flags &= ~DQ_FAKE; 520 dq->dq_flags |= DQ_MOD; 521 dqrele(NULLVP, dq); 522 return (0); 523 } 524 525 /* 526 * Q_SETUSE - set current inode and block usage. 527 */ 528 setuse(mp, id, type, addr) 529 struct mount *mp; 530 u_long id; 531 int type; 532 caddr_t addr; 533 { 534 register struct dquot *dq; 535 struct ufsmount *ump = VFSTOUFS(mp); 536 struct dquot *ndq; 537 struct dqblk usage; 538 int error; 539 540 if (error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk))) 541 return (error); 542 if (error = dqget(NULLVP, id, ump, type, &ndq)) 543 return (error); 544 dq = ndq; 545 while (dq->dq_flags & DQ_LOCK) { 546 dq->dq_flags |= DQ_WANT; 547 sleep((caddr_t)dq, PINOD+1); 548 } 549 /* 550 * Reset time limit if have a soft limit and were 551 * previously under it, but are now over it. 552 */ 553 if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit && 554 usage.dqb_curblocks >= dq->dq_bsoftlimit) 555 dq->dq_btime = time.tv_sec + ump->um_btime[type]; 556 if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit && 557 usage.dqb_curinodes >= dq->dq_isoftlimit) 558 dq->dq_itime = time.tv_sec + ump->um_itime[type]; 559 dq->dq_curblocks = usage.dqb_curblocks; 560 dq->dq_curinodes = usage.dqb_curinodes; 561 if (dq->dq_curblocks < dq->dq_bsoftlimit) 562 dq->dq_flags &= ~DQ_BLKS; 563 if (dq->dq_curinodes < dq->dq_isoftlimit) 564 dq->dq_flags &= ~DQ_INODS; 565 dq->dq_flags |= DQ_MOD; 566 dqrele(NULLVP, dq); 567 return (0); 568 } 569 570 /* 571 * Q_SYNC - sync quota files to disk. 572 */ 573 qsync(mp) 574 struct mount *mp; 575 { 576 struct ufsmount *ump = VFSTOUFS(mp); 577 register struct vnode *vp, *nextvp; 578 register struct dquot *dq; 579 register int i; 580 581 /* 582 * Search vnodes associated with this mount point, 583 * synchronizing any modified dquot structures. 584 */ 585 if ((mp->mnt_flag & MNT_MPBUSY) == 0) 586 panic("qsync: not busy"); 587 again: 588 for (vp = mp->mnt_mounth; vp; vp = nextvp) { 589 nextvp = vp->v_mountf; 590 if (vget(vp)) 591 goto again; 592 for (i = 0; i < MAXQUOTAS; i++) { 593 dq = VTOI(vp)->i_dquot[i]; 594 if (dq != NODQUOT && (dq->dq_flags & DQ_MOD)) 595 dqsync(vp, dq); 596 } 597 vput(vp); 598 if (vp->v_mountf != nextvp || vp->v_mount != mp) 599 goto again; 600 } 601 return (0); 602 } 603 604 /* 605 * Code pertaining to management of the in-core dquot data structures. 606 */ 607 608 /* 609 * Dquot cache - hash chain headers. 610 */ 611 union dqhead { 612 union dqhead *dqh_head[2]; 613 struct dquot *dqh_chain[2]; 614 }; 615 #define dqh_forw dqh_chain[0] 616 #define dqh_back dqh_chain[1] 617 618 union dqhead *dqhashtbl; 619 long dqhash; 620 621 /* 622 * Dquot free list. 623 */ 624 #define DQUOTINC 5 /* minimum free dquots desired */ 625 struct dquot *dqfreel, **dqback = &dqfreel; 626 long numdquot, desireddquot = DQUOTINC; 627 628 /* 629 * Initialize the quota system. 630 */ 631 dqinit() 632 { 633 register union dqhead *dhp; 634 register long dqhashsize; 635 636 dqhashsize = roundup((desiredvnodes + 1) * sizeof *dhp / 2, 637 NBPG * CLSIZE); 638 dqhashtbl = (union dqhead *)malloc(dqhashsize, M_DQUOT, M_WAITOK); 639 for (dqhash = 1; dqhash <= dqhashsize / sizeof *dhp; dqhash <<= 1) 640 /* void */; 641 dqhash = (dqhash >> 1) - 1; 642 for (dhp = &dqhashtbl[dqhash]; dhp >= dqhashtbl; dhp--) { 643 dhp->dqh_head[0] = dhp; 644 dhp->dqh_head[1] = dhp; 645 } 646 } 647 648 /* 649 * Obtain a dquot structure for the specified identifier and quota file 650 * reading the information from the file if necessary. 651 */ 652 dqget(vp, id, ump, type, dqp) 653 struct vnode *vp; 654 u_long id; 655 register struct ufsmount *ump; 656 register int type; 657 struct dquot **dqp; 658 { 659 register struct dquot *dq; 660 register union dqhead *dh; 661 register struct dquot *dp; 662 register struct vnode *dqvp; 663 struct iovec aiov; 664 struct uio auio; 665 int error; 666 667 dqvp = ump->um_quotas[type]; 668 if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) { 669 *dqp = NODQUOT; 670 return (EINVAL); 671 } 672 /* 673 * Check the cache first. 674 */ 675 dh = &dqhashtbl[((((int)(dqvp)) >> 8) + id) & dqhash]; 676 for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = dq->dq_forw) { 677 if (dq->dq_id != id || 678 dq->dq_ump->um_quotas[dq->dq_type] != dqvp) 679 continue; 680 /* 681 * Cache hit with no references. Take 682 * the structure off the free list. 683 */ 684 if (dq->dq_cnt == 0) { 685 dp = dq->dq_freef; 686 if (dp != NODQUOT) 687 dp->dq_freeb = dq->dq_freeb; 688 else 689 dqback = dq->dq_freeb; 690 *dq->dq_freeb = dp; 691 } 692 DQREF(dq); 693 *dqp = dq; 694 return (0); 695 } 696 /* 697 * Not in cache, allocate a new one. 698 */ 699 if (dqfreel == NODQUOT && numdquot < MAXQUOTAS * desiredvnodes) 700 desireddquot += DQUOTINC; 701 if (numdquot < desireddquot) { 702 dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT, M_WAITOK); 703 bzero((char *)dq, sizeof *dq); 704 numdquot++; 705 } else { 706 if ((dq = dqfreel) == NULL) { 707 tablefull("dquot"); 708 *dqp = NODQUOT; 709 return (EUSERS); 710 } 711 if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) 712 panic("free dquot isn't"); 713 if ((dp = dq->dq_freef) != NODQUOT) 714 dp->dq_freeb = &dqfreel; 715 else 716 dqback = &dqfreel; 717 dqfreel = dp; 718 dq->dq_freef = NULL; 719 dq->dq_freeb = NULL; 720 remque(dq); 721 } 722 /* 723 * Initialize the contents of the dquot structure. 724 */ 725 if (vp != dqvp) 726 VOP_LOCK(dqvp); 727 insque(dq, dh); 728 DQREF(dq); 729 dq->dq_flags = DQ_LOCK; 730 dq->dq_id = id; 731 dq->dq_ump = ump; 732 dq->dq_type = type; 733 auio.uio_iov = &aiov; 734 auio.uio_iovcnt = 1; 735 aiov.iov_base = (caddr_t)&dq->dq_dqb; 736 aiov.iov_len = sizeof (struct dqblk); 737 auio.uio_resid = sizeof (struct dqblk); 738 auio.uio_offset = (off_t)(id * sizeof (struct dqblk)); 739 auio.uio_segflg = UIO_SYSSPACE; 740 auio.uio_rw = UIO_READ; 741 error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]); 742 if (auio.uio_resid == sizeof(struct dqblk) && error == 0) 743 bzero((caddr_t)&dq->dq_dqb, sizeof(struct dqblk)); 744 if (vp != dqvp) 745 VOP_UNLOCK(dqvp); 746 if (dq->dq_flags & DQ_WANT) 747 wakeup((caddr_t)dq); 748 dq->dq_flags = 0; 749 /* 750 * I/O error in reading quota file, release 751 * quota structure and reflect problem to caller. 752 */ 753 if (error) { 754 remque(dq); 755 dq->dq_forw = dq; /* on a private, unfindable hash list */ 756 dq->dq_back = dq; 757 dqrele(vp, dq); 758 *dqp = NODQUOT; 759 return (error); 760 } 761 /* 762 * Check for no limit to enforce. 763 * Initialize time values if necessary. 764 */ 765 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && 766 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) 767 dq->dq_flags |= DQ_FAKE; 768 if (dq->dq_id != 0) { 769 if (dq->dq_btime == 0) 770 dq->dq_btime = time.tv_sec + ump->um_btime[type]; 771 if (dq->dq_itime == 0) 772 dq->dq_itime = time.tv_sec + ump->um_itime[type]; 773 } 774 *dqp = dq; 775 return (0); 776 } 777 778 /* 779 * Obtain a reference to a dquot. 780 */ 781 dqref(dq) 782 struct dquot *dq; 783 { 784 785 dq->dq_cnt++; 786 } 787 788 /* 789 * Release a reference to a dquot. 790 */ 791 dqrele(vp, dq) 792 struct vnode *vp; 793 register struct dquot *dq; 794 { 795 796 if (dq == NODQUOT) 797 return; 798 if (dq->dq_cnt > 1) { 799 dq->dq_cnt--; 800 return; 801 } 802 if (dq->dq_flags & DQ_MOD) 803 (void) dqsync(vp, dq); 804 if (--dq->dq_cnt > 0) 805 return; 806 if (dqfreel != NODQUOT) { 807 *dqback = dq; 808 dq->dq_freeb = dqback; 809 } else { 810 dqfreel = dq; 811 dq->dq_freeb = &dqfreel; 812 } 813 dq->dq_freef = NODQUOT; 814 dqback = &dq->dq_freef; 815 } 816 817 /* 818 * Update the disk quota in the quota file. 819 */ 820 dqsync(vp, dq) 821 struct vnode *vp; 822 register struct dquot *dq; 823 { 824 struct vnode *dqvp; 825 struct iovec aiov; 826 struct uio auio; 827 int error; 828 829 if (dq == NODQUOT) 830 panic("dqsync: dquot"); 831 if ((dq->dq_flags & DQ_MOD) == 0) 832 return (0); 833 if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP) 834 panic("dqsync: file"); 835 if (vp != dqvp) 836 VOP_LOCK(dqvp); 837 while (dq->dq_flags & DQ_LOCK) { 838 dq->dq_flags |= DQ_WANT; 839 sleep((caddr_t)dq, PINOD+2); 840 if ((dq->dq_flags & DQ_MOD) == 0) { 841 if (vp != dqvp) 842 VOP_UNLOCK(dqvp); 843 return (0); 844 } 845 } 846 dq->dq_flags |= DQ_LOCK; 847 auio.uio_iov = &aiov; 848 auio.uio_iovcnt = 1; 849 aiov.iov_base = (caddr_t)&dq->dq_dqb; 850 aiov.iov_len = sizeof (struct dqblk); 851 auio.uio_resid = sizeof (struct dqblk); 852 auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk)); 853 auio.uio_segflg = UIO_SYSSPACE; 854 auio.uio_rw = UIO_WRITE; 855 error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); 856 if (auio.uio_resid && error == 0) 857 error = EIO; 858 if (dq->dq_flags & DQ_WANT) 859 wakeup((caddr_t)dq); 860 dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT); 861 if (vp != dqvp) 862 VOP_UNLOCK(dqvp); 863 return (error); 864 } 865 866 /* 867 * Flush all entries from the cache for a particular vnode. 868 */ 869 dqflush(vp) 870 register struct vnode *vp; 871 { 872 register union dqhead *dh; 873 register struct dquot *dq, *nextdq; 874 875 /* 876 * Move all dquot's that used to refer to this quota 877 * file off their hash chains (they will eventually 878 * fall off the head of the free list and be re-used). 879 */ 880 for (dh = &dqhashtbl[dqhash]; dh >= dqhashtbl; dh--) { 881 for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = nextdq) { 882 nextdq = dq->dq_forw; 883 if (dq->dq_ump->um_quotas[dq->dq_type] != vp) 884 continue; 885 if (dq->dq_cnt) 886 panic("dqflush: stray dquot"); 887 remque(dq); 888 dq->dq_forw = dq; 889 dq->dq_back = dq; 890 dq->dq_ump = (struct ufsmount *)0; 891 } 892 } 893 } 894