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.5 (Berkeley) 08/29/90 11 */ 12 #include "param.h" 13 #include "time.h" 14 #include "kernel.h" 15 #include "systm.h" 16 #include "ucred.h" 17 #include "namei.h" 18 #include "errno.h" 19 #include "malloc.h" 20 #include "file.h" 21 #include "vnode.h" 22 #include "mount.h" 23 #include "../ufs/fs.h" 24 #include "../ufs/quota.h" 25 #include "../ufs/inode.h" 26 #include "../ufs/ufsmount.h" 27 28 /* 29 * Quota name to error message mapping. 30 */ 31 static char *quotatypes[] = INITQFNAMES; 32 33 /* 34 * Set up the quotas for an inode. 35 * 36 * This routine completely defines the semantics of quotas. 37 * If other criterion want to be used to establish quotas, the 38 * MAXQUOTAS value in quotas.h should be increased, and the 39 * additional dquots set up here. 40 */ 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 chkdq(ip, change, cred, flags) 74 register struct inode *ip; 75 long change; 76 struct ucred *cred; 77 int flags; 78 { 79 register struct dquot *dq; 80 register int i; 81 int ncurblocks, error; 82 83 #ifdef DIAGNOSTIC 84 if ((flags & CHOWN) == 0) 85 chkdquot(ip); 86 #endif 87 if (change == 0) 88 return (0); 89 if (change < 0) { 90 for (i = 0; i < MAXQUOTAS; i++) { 91 if ((dq = ip->i_dquot[i]) == NODQUOT) 92 continue; 93 while (dq->dq_flags & DQ_LOCK) { 94 dq->dq_flags |= DQ_WANT; 95 sleep((caddr_t)dq, PINOD+1); 96 } 97 ncurblocks = dq->dq_curblocks + change; 98 if (ncurblocks >= 0) 99 dq->dq_curblocks = ncurblocks; 100 else 101 dq->dq_curblocks = 0; 102 dq->dq_flags &= ~DQ_BLKS; 103 dq->dq_flags |= DQ_MOD; 104 } 105 return (0); 106 } 107 if ((flags & FORCE) == 0 && cred->cr_uid != 0) { 108 for (i = 0; i < MAXQUOTAS; i++) { 109 if ((dq = ip->i_dquot[i]) == NODQUOT) 110 continue; 111 if (error = chkdqchg(ip, change, cred, i)) 112 return (error); 113 } 114 } 115 for (i = 0; i < MAXQUOTAS; i++) { 116 if ((dq = ip->i_dquot[i]) == NODQUOT) 117 continue; 118 while (dq->dq_flags & DQ_LOCK) { 119 dq->dq_flags |= DQ_WANT; 120 sleep((caddr_t)dq, PINOD+1); 121 } 122 dq->dq_curblocks += change; 123 dq->dq_flags |= DQ_MOD; 124 } 125 return (0); 126 } 127 128 /* 129 * Check for a valid change to a users allocation. 130 * Issue an error message if appropriate. 131 */ 132 chkdqchg(ip, change, cred, type) 133 struct inode *ip; 134 long change; 135 struct ucred *cred; 136 int type; 137 { 138 register struct dquot *dq = ip->i_dquot[type]; 139 long ncurblocks = dq->dq_curblocks + change; 140 141 /* 142 * If user would exceed their hard limit, disallow space allocation. 143 */ 144 if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) { 145 if ((dq->dq_flags & DQ_BLKS) == 0 && 146 ip->i_uid == cred->cr_uid) { 147 uprintf("\n%s: write failed, %s disk limit reached\n", 148 ip->i_fs->fs_fsmnt, quotatypes[type]); 149 dq->dq_flags |= DQ_BLKS; 150 } 151 return (EDQUOT); 152 } 153 /* 154 * If user is over their soft limit for too long, disallow space 155 * allocation. Reset time limit as they cross their soft limit. 156 */ 157 if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) { 158 if (dq->dq_curblocks < dq->dq_bsoftlimit) { 159 dq->dq_btime = time.tv_sec + 160 VFSTOUFS(ITOV(ip)->v_mount)->um_btime[type]; 161 if (ip->i_uid == cred->cr_uid) 162 uprintf("\n%s: warning, %s %s\n", 163 ip->i_fs->fs_fsmnt, quotatypes[type], 164 "disk quota exceeded"); 165 return (0); 166 } 167 if (time.tv_sec > dq->dq_btime) { 168 if ((dq->dq_flags & DQ_BLKS) == 0 && 169 ip->i_uid == cred->cr_uid) { 170 uprintf("\n%s: write failed, %s %s\n", 171 ip->i_fs->fs_fsmnt, quotatypes[type], 172 "disk quota exceeded too long"); 173 dq->dq_flags |= DQ_BLKS; 174 } 175 return (EDQUOT); 176 } 177 } 178 return (0); 179 } 180 181 /* 182 * Check the inode limit, applying corrective action. 183 */ 184 chkiq(ip, change, cred, flags) 185 register struct inode *ip; 186 long change; 187 struct ucred *cred; 188 int flags; 189 { 190 register struct dquot *dq; 191 register int i; 192 int ncurinodes, error; 193 194 #ifdef DIAGNOSTIC 195 if ((flags & CHOWN) == 0) 196 chkdquot(ip); 197 #endif 198 if (change == 0) 199 return (0); 200 if (change < 0) { 201 for (i = 0; i < MAXQUOTAS; i++) { 202 if ((dq = ip->i_dquot[i]) == NODQUOT) 203 continue; 204 while (dq->dq_flags & DQ_LOCK) { 205 dq->dq_flags |= DQ_WANT; 206 sleep((caddr_t)dq, PINOD+1); 207 } 208 ncurinodes = dq->dq_curinodes + change; 209 if (ncurinodes >= 0) 210 dq->dq_curinodes = ncurinodes; 211 else 212 dq->dq_curinodes = 0; 213 dq->dq_flags &= ~DQ_INODS; 214 dq->dq_flags |= DQ_MOD; 215 } 216 return (0); 217 } 218 if ((flags & FORCE) == 0 && cred->cr_uid != 0) { 219 for (i = 0; i < MAXQUOTAS; i++) { 220 if ((dq = ip->i_dquot[i]) == NODQUOT) 221 continue; 222 if (error = chkiqchg(ip, change, cred, i)) 223 return (error); 224 } 225 } 226 for (i = 0; i < MAXQUOTAS; i++) { 227 if ((dq = ip->i_dquot[i]) == NODQUOT) 228 continue; 229 while (dq->dq_flags & DQ_LOCK) { 230 dq->dq_flags |= DQ_WANT; 231 sleep((caddr_t)dq, PINOD+1); 232 } 233 dq->dq_curinodes += change; 234 dq->dq_flags |= DQ_MOD; 235 } 236 return (0); 237 } 238 239 /* 240 * Check for a valid change to a users allocation. 241 * Issue an error message if appropriate. 242 */ 243 chkiqchg(ip, change, cred, type) 244 struct inode *ip; 245 long change; 246 struct ucred *cred; 247 int type; 248 { 249 register struct dquot *dq = ip->i_dquot[type]; 250 long ncurinodes = dq->dq_curinodes + change; 251 252 /* 253 * If user would exceed their hard limit, disallow inode allocation. 254 */ 255 if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) { 256 if ((dq->dq_flags & DQ_INODS) == 0 && 257 ip->i_uid == cred->cr_uid) { 258 uprintf("\n%s: write failed, %s inode limit reached\n", 259 ip->i_fs->fs_fsmnt, quotatypes[type]); 260 dq->dq_flags |= DQ_INODS; 261 } 262 return (EDQUOT); 263 } 264 /* 265 * If user is over their soft limit for too long, disallow inode 266 * allocation. Reset time limit as they cross their soft limit. 267 */ 268 if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) { 269 if (dq->dq_curinodes < dq->dq_isoftlimit) { 270 dq->dq_itime = time.tv_sec + 271 VFSTOUFS(ITOV(ip)->v_mount)->um_itime[type]; 272 if (ip->i_uid == cred->cr_uid) 273 uprintf("\n%s: warning, %s %s\n", 274 ip->i_fs->fs_fsmnt, quotatypes[type], 275 "inode quota exceeded"); 276 return (0); 277 } 278 if (time.tv_sec > dq->dq_itime) { 279 if ((dq->dq_flags & DQ_INODS) == 0 && 280 ip->i_uid == cred->cr_uid) { 281 uprintf("\n%s: write failed, %s %s\n", 282 ip->i_fs->fs_fsmnt, quotatypes[type], 283 "inode quota exceeded too long"); 284 dq->dq_flags |= DQ_INODS; 285 } 286 return (EDQUOT); 287 } 288 } 289 return (0); 290 } 291 292 #ifdef DIAGNOSTIC 293 /* 294 * On filesystems with quotas enabled, 295 * it is an error for a file to change size and not 296 * to have a dquot structure associated with it. 297 */ 298 chkdquot(ip) 299 register struct inode *ip; 300 { 301 struct ufsmount *ump = VFSTOUFS(ITOV(ip)->v_mount); 302 register int i; 303 304 for (i = 0; i < MAXQUOTAS; i++) { 305 if (ump->um_quotas[i] == NULLVP || 306 (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING))) 307 continue; 308 if (ip->i_dquot[i] == NODQUOT) { 309 vprint("chkdquot: missing dquot", ITOV(ip)); 310 panic("missing dquot"); 311 } 312 } 313 } 314 #endif /* DIAGNOSTIC */ 315 316 /* 317 * Code to process quotactl commands. 318 */ 319 320 /* 321 * Q_QUOTAON - set up a quota file for a particular file system. 322 */ 323 quotaon(ndp, mp, type, fname) 324 register struct nameidata *ndp; 325 struct mount *mp; 326 register int type; 327 caddr_t fname; 328 { 329 register struct ufsmount *ump = VFSTOUFS(mp); 330 register struct vnode *vp, **vpp; 331 struct vnode *nextvp; 332 struct dquot *dq; 333 int error; 334 335 vpp = &ump->um_quotas[type]; 336 ndp->ni_segflg = UIO_USERSPACE; 337 ndp->ni_dirp = fname; 338 if (error = vn_open(ndp, FREAD|FWRITE, 0)) 339 return (error); 340 vp = ndp->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(ndp->ni_cred); 360 ump->um_cred[type] = ndp->ni_cred; 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 return (0); 842 } 843 dq->dq_flags |= DQ_LOCK; 844 auio.uio_iov = &aiov; 845 auio.uio_iovcnt = 1; 846 aiov.iov_base = (caddr_t)&dq->dq_dqb; 847 aiov.iov_len = sizeof (struct dqblk); 848 auio.uio_resid = sizeof (struct dqblk); 849 auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk)); 850 auio.uio_segflg = UIO_SYSSPACE; 851 auio.uio_rw = UIO_WRITE; 852 error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); 853 if (auio.uio_resid && error == 0) 854 error = EIO; 855 if (dq->dq_flags & DQ_WANT) 856 wakeup((caddr_t)dq); 857 dq->dq_flags &= ~(DQ_MOD|DQ_LOCK|DQ_WANT); 858 if (vp != dqvp) 859 VOP_UNLOCK(dqvp); 860 return (error); 861 } 862 863 /* 864 * Flush all entries from the cache for a particular vnode. 865 */ 866 dqflush(vp) 867 register struct vnode *vp; 868 { 869 register union dqhead *dh; 870 register struct dquot *dq, *nextdq; 871 872 /* 873 * Move all dquot's that used to refer to this quota 874 * file off their hash chains (they will eventually 875 * fall off the head of the free list and be re-used). 876 */ 877 for (dh = &dqhashtbl[dqhash]; dh >= dqhashtbl; dh--) { 878 for (dq = dh->dqh_forw; dq != (struct dquot *)dh; dq = nextdq) { 879 nextdq = dq->dq_forw; 880 if (dq->dq_ump->um_quotas[dq->dq_type] != vp) 881 continue; 882 if (dq->dq_cnt) 883 panic("dqflush: stray dquot"); 884 remque(dq); 885 dq->dq_forw = dq; 886 dq->dq_back = dq; 887 dq->dq_ump = (struct ufsmount *)0; 888 } 889 } 890 } 891