ufs_quota.c revision 271162
1/*- 2 * Copyright (c) 1982, 1986, 1990, 1993, 1995 3 * The Regents of the University of California. 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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: stable/10/sys/ufs/ufs/ufs_quota.c 271162 2014-09-05 13:25:27Z kib $"); 37 38#include "opt_ffs.h" 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/endian.h> 43#include <sys/fcntl.h> 44#include <sys/kernel.h> 45#include <sys/lock.h> 46#include <sys/malloc.h> 47#include <sys/mount.h> 48#include <sys/mutex.h> 49#include <sys/namei.h> 50#include <sys/priv.h> 51#include <sys/proc.h> 52#include <sys/socket.h> 53#include <sys/stat.h> 54#include <sys/sysctl.h> 55#include <sys/vnode.h> 56 57#include <ufs/ufs/extattr.h> 58#include <ufs/ufs/quota.h> 59#include <ufs/ufs/inode.h> 60#include <ufs/ufs/ufsmount.h> 61#include <ufs/ufs/ufs_extern.h> 62 63CTASSERT(sizeof(struct dqblk64) == sizeof(struct dqhdr64)); 64 65static int unprivileged_get_quota = 0; 66SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_get_quota, CTLFLAG_RW, 67 &unprivileged_get_quota, 0, 68 "Unprivileged processes may retrieve quotas for other uids and gids"); 69 70static MALLOC_DEFINE(M_DQUOT, "ufs_quota", "UFS quota entries"); 71 72/* 73 * Quota name to error message mapping. 74 */ 75static char *quotatypes[] = INITQFNAMES; 76 77static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int, int *); 78static int chkiqchg(struct inode *, int, struct ucred *, int, int *); 79static int dqopen(struct vnode *, struct ufsmount *, int); 80static int dqget(struct vnode *, 81 u_long, struct ufsmount *, int, struct dquot **); 82static int dqsync(struct vnode *, struct dquot *); 83static int dqflush(struct vnode *); 84static int quotaoff1(struct thread *td, struct mount *mp, int type); 85static int quotaoff_inchange(struct thread *td, struct mount *mp, int type); 86 87/* conversion functions - from_to() */ 88static void dqb32_dq(const struct dqblk32 *, struct dquot *); 89static void dqb64_dq(const struct dqblk64 *, struct dquot *); 90static void dq_dqb32(const struct dquot *, struct dqblk32 *); 91static void dq_dqb64(const struct dquot *, struct dqblk64 *); 92static void dqb32_dqb64(const struct dqblk32 *, struct dqblk64 *); 93static void dqb64_dqb32(const struct dqblk64 *, struct dqblk32 *); 94 95#ifdef DIAGNOSTIC 96static void dqref(struct dquot *); 97static void chkdquot(struct inode *); 98#endif 99 100/* 101 * Set up the quotas for an inode. 102 * 103 * This routine completely defines the semantics of quotas. 104 * If other criterion want to be used to establish quotas, the 105 * MAXQUOTAS value in quota.h should be increased, and the 106 * additional dquots set up here. 107 */ 108int 109getinoquota(struct inode *ip) 110{ 111 struct ufsmount *ump; 112 struct vnode *vp; 113 int error; 114 115 vp = ITOV(ip); 116 117 /* 118 * Disk quotas must be turned off for system files. Currently 119 * snapshot and quota files. 120 */ 121 if ((vp->v_vflag & VV_SYSTEM) != 0) 122 return (0); 123 /* 124 * XXX: Turn off quotas for files with a negative UID or GID. 125 * This prevents the creation of 100GB+ quota files. 126 */ 127 if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) 128 return (0); 129 ump = VFSTOUFS(vp->v_mount); 130 /* 131 * Set up the user quota based on file uid. 132 * EINVAL means that quotas are not enabled. 133 */ 134 if ((error = 135 dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) && 136 error != EINVAL) 137 return (error); 138 /* 139 * Set up the group quota based on file gid. 140 * EINVAL means that quotas are not enabled. 141 */ 142 if ((error = 143 dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) && 144 error != EINVAL) 145 return (error); 146 return (0); 147} 148 149/* 150 * Update disk usage, and take corrective action. 151 */ 152int 153chkdq(struct inode *ip, ufs2_daddr_t change, struct ucred *cred, int flags) 154{ 155 struct dquot *dq; 156 ufs2_daddr_t ncurblocks; 157 struct vnode *vp = ITOV(ip); 158 int i, error, warn, do_check; 159 160 /* 161 * Disk quotas must be turned off for system files. Currently 162 * snapshot and quota files. 163 */ 164 if ((vp->v_vflag & VV_SYSTEM) != 0) 165 return (0); 166 /* 167 * XXX: Turn off quotas for files with a negative UID or GID. 168 * This prevents the creation of 100GB+ quota files. 169 */ 170 if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) 171 return (0); 172#ifdef DIAGNOSTIC 173 if ((flags & CHOWN) == 0) 174 chkdquot(ip); 175#endif 176 if (change == 0) 177 return (0); 178 if (change < 0) { 179 for (i = 0; i < MAXQUOTAS; i++) { 180 if ((dq = ip->i_dquot[i]) == NODQUOT) 181 continue; 182 DQI_LOCK(dq); 183 DQI_WAIT(dq, PINOD+1, "chkdq1"); 184 ncurblocks = dq->dq_curblocks + change; 185 if (ncurblocks >= 0) 186 dq->dq_curblocks = ncurblocks; 187 else 188 dq->dq_curblocks = 0; 189 dq->dq_flags &= ~DQ_BLKS; 190 dq->dq_flags |= DQ_MOD; 191 DQI_UNLOCK(dq); 192 } 193 return (0); 194 } 195 if ((flags & FORCE) == 0 && 196 priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 197 do_check = 1; 198 else 199 do_check = 0; 200 for (i = 0; i < MAXQUOTAS; i++) { 201 if ((dq = ip->i_dquot[i]) == NODQUOT) 202 continue; 203 warn = 0; 204 DQI_LOCK(dq); 205 DQI_WAIT(dq, PINOD+1, "chkdq2"); 206 if (do_check) { 207 error = chkdqchg(ip, change, cred, i, &warn); 208 if (error) { 209 /* 210 * Roll back user quota changes when 211 * group quota failed. 212 */ 213 while (i > 0) { 214 --i; 215 dq = ip->i_dquot[i]; 216 if (dq == NODQUOT) 217 continue; 218 DQI_LOCK(dq); 219 DQI_WAIT(dq, PINOD+1, "chkdq3"); 220 ncurblocks = dq->dq_curblocks - change; 221 if (ncurblocks >= 0) 222 dq->dq_curblocks = ncurblocks; 223 else 224 dq->dq_curblocks = 0; 225 dq->dq_flags &= ~DQ_BLKS; 226 dq->dq_flags |= DQ_MOD; 227 DQI_UNLOCK(dq); 228 } 229 return (error); 230 } 231 } 232 /* Reset timer when crossing soft limit */ 233 if (dq->dq_curblocks + change >= dq->dq_bsoftlimit && 234 dq->dq_curblocks < dq->dq_bsoftlimit) 235 dq->dq_btime = time_second + ip->i_ump->um_btime[i]; 236 dq->dq_curblocks += change; 237 dq->dq_flags |= DQ_MOD; 238 DQI_UNLOCK(dq); 239 if (warn) 240 uprintf("\n%s: warning, %s disk quota exceeded\n", 241 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 242 quotatypes[i]); 243 } 244 return (0); 245} 246 247/* 248 * Check for a valid change to a users allocation. 249 * Issue an error message if appropriate. 250 */ 251static int 252chkdqchg(struct inode *ip, ufs2_daddr_t change, struct ucred *cred, 253 int type, int *warn) 254{ 255 struct dquot *dq = ip->i_dquot[type]; 256 ufs2_daddr_t ncurblocks = dq->dq_curblocks + change; 257 258 /* 259 * If user would exceed their hard limit, disallow space allocation. 260 */ 261 if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) { 262 if ((dq->dq_flags & DQ_BLKS) == 0 && 263 ip->i_uid == cred->cr_uid) { 264 dq->dq_flags |= DQ_BLKS; 265 DQI_UNLOCK(dq); 266 uprintf("\n%s: write failed, %s disk limit reached\n", 267 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 268 quotatypes[type]); 269 return (EDQUOT); 270 } 271 DQI_UNLOCK(dq); 272 return (EDQUOT); 273 } 274 /* 275 * If user is over their soft limit for too long, disallow space 276 * allocation. Reset time limit as they cross their soft limit. 277 */ 278 if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) { 279 if (dq->dq_curblocks < dq->dq_bsoftlimit) { 280 dq->dq_btime = time_second + ip->i_ump->um_btime[type]; 281 if (ip->i_uid == cred->cr_uid) 282 *warn = 1; 283 return (0); 284 } 285 if (time_second > dq->dq_btime) { 286 if ((dq->dq_flags & DQ_BLKS) == 0 && 287 ip->i_uid == cred->cr_uid) { 288 dq->dq_flags |= DQ_BLKS; 289 DQI_UNLOCK(dq); 290 uprintf("\n%s: write failed, %s " 291 "disk quota exceeded for too long\n", 292 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 293 quotatypes[type]); 294 return (EDQUOT); 295 } 296 DQI_UNLOCK(dq); 297 return (EDQUOT); 298 } 299 } 300 return (0); 301} 302 303/* 304 * Check the inode limit, applying corrective action. 305 */ 306int 307chkiq(struct inode *ip, int change, struct ucred *cred, int flags) 308{ 309 struct dquot *dq; 310 int i, error, warn, do_check; 311 312#ifdef DIAGNOSTIC 313 if ((flags & CHOWN) == 0) 314 chkdquot(ip); 315#endif 316 if (change == 0) 317 return (0); 318 if (change < 0) { 319 for (i = 0; i < MAXQUOTAS; i++) { 320 if ((dq = ip->i_dquot[i]) == NODQUOT) 321 continue; 322 DQI_LOCK(dq); 323 DQI_WAIT(dq, PINOD+1, "chkiq1"); 324 if (dq->dq_curinodes >= -change) 325 dq->dq_curinodes += change; 326 else 327 dq->dq_curinodes = 0; 328 dq->dq_flags &= ~DQ_INODS; 329 dq->dq_flags |= DQ_MOD; 330 DQI_UNLOCK(dq); 331 } 332 return (0); 333 } 334 if ((flags & FORCE) == 0 && 335 priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 336 do_check = 1; 337 else 338 do_check = 0; 339 for (i = 0; i < MAXQUOTAS; i++) { 340 if ((dq = ip->i_dquot[i]) == NODQUOT) 341 continue; 342 warn = 0; 343 DQI_LOCK(dq); 344 DQI_WAIT(dq, PINOD+1, "chkiq2"); 345 if (do_check) { 346 error = chkiqchg(ip, change, cred, i, &warn); 347 if (error) { 348 /* 349 * Roll back user quota changes when 350 * group quota failed. 351 */ 352 while (i > 0) { 353 --i; 354 dq = ip->i_dquot[i]; 355 if (dq == NODQUOT) 356 continue; 357 DQI_LOCK(dq); 358 DQI_WAIT(dq, PINOD+1, "chkiq3"); 359 if (dq->dq_curinodes >= change) 360 dq->dq_curinodes -= change; 361 else 362 dq->dq_curinodes = 0; 363 dq->dq_flags &= ~DQ_INODS; 364 dq->dq_flags |= DQ_MOD; 365 DQI_UNLOCK(dq); 366 } 367 return (error); 368 } 369 } 370 /* Reset timer when crossing soft limit */ 371 if (dq->dq_curinodes + change >= dq->dq_isoftlimit && 372 dq->dq_curinodes < dq->dq_isoftlimit) 373 dq->dq_itime = time_second + ip->i_ump->um_itime[i]; 374 dq->dq_curinodes += change; 375 dq->dq_flags |= DQ_MOD; 376 DQI_UNLOCK(dq); 377 if (warn) 378 uprintf("\n%s: warning, %s inode quota exceeded\n", 379 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 380 quotatypes[i]); 381 } 382 return (0); 383} 384 385/* 386 * Check for a valid change to a users allocation. 387 * Issue an error message if appropriate. 388 */ 389static int 390chkiqchg(struct inode *ip, int change, struct ucred *cred, int type, int *warn) 391{ 392 struct dquot *dq = ip->i_dquot[type]; 393 ino_t ncurinodes = dq->dq_curinodes + change; 394 395 /* 396 * If user would exceed their hard limit, disallow inode allocation. 397 */ 398 if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) { 399 if ((dq->dq_flags & DQ_INODS) == 0 && 400 ip->i_uid == cred->cr_uid) { 401 dq->dq_flags |= DQ_INODS; 402 DQI_UNLOCK(dq); 403 uprintf("\n%s: write failed, %s inode limit reached\n", 404 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 405 quotatypes[type]); 406 return (EDQUOT); 407 } 408 DQI_UNLOCK(dq); 409 return (EDQUOT); 410 } 411 /* 412 * If user is over their soft limit for too long, disallow inode 413 * allocation. Reset time limit as they cross their soft limit. 414 */ 415 if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) { 416 if (dq->dq_curinodes < dq->dq_isoftlimit) { 417 dq->dq_itime = time_second + ip->i_ump->um_itime[type]; 418 if (ip->i_uid == cred->cr_uid) 419 *warn = 1; 420 return (0); 421 } 422 if (time_second > dq->dq_itime) { 423 if ((dq->dq_flags & DQ_INODS) == 0 && 424 ip->i_uid == cred->cr_uid) { 425 dq->dq_flags |= DQ_INODS; 426 DQI_UNLOCK(dq); 427 uprintf("\n%s: write failed, %s " 428 "inode quota exceeded for too long\n", 429 ITOV(ip)->v_mount->mnt_stat.f_mntonname, 430 quotatypes[type]); 431 return (EDQUOT); 432 } 433 DQI_UNLOCK(dq); 434 return (EDQUOT); 435 } 436 } 437 return (0); 438} 439 440#ifdef DIAGNOSTIC 441/* 442 * On filesystems with quotas enabled, it is an error for a file to change 443 * size and not to have a dquot structure associated with it. 444 */ 445static void 446chkdquot(struct inode *ip) 447{ 448 struct ufsmount *ump = ip->i_ump; 449 struct vnode *vp = ITOV(ip); 450 int i; 451 452 /* 453 * Disk quotas must be turned off for system files. Currently 454 * these are snapshots and quota files. 455 */ 456 if ((vp->v_vflag & VV_SYSTEM) != 0) 457 return; 458 /* 459 * XXX: Turn off quotas for files with a negative UID or GID. 460 * This prevents the creation of 100GB+ quota files. 461 */ 462 if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) 463 return; 464 465 UFS_LOCK(ump); 466 for (i = 0; i < MAXQUOTAS; i++) { 467 if (ump->um_quotas[i] == NULLVP || 468 (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING))) 469 continue; 470 if (ip->i_dquot[i] == NODQUOT) { 471 UFS_UNLOCK(ump); 472 vprint("chkdquot: missing dquot", ITOV(ip)); 473 panic("chkdquot: missing dquot"); 474 } 475 } 476 UFS_UNLOCK(ump); 477} 478#endif 479 480/* 481 * Code to process quotactl commands. 482 */ 483 484/* 485 * Q_QUOTAON - set up a quota file for a particular filesystem. 486 */ 487int 488quotaon(struct thread *td, struct mount *mp, int type, void *fname) 489{ 490 struct ufsmount *ump; 491 struct vnode *vp, **vpp; 492 struct vnode *mvp; 493 struct dquot *dq; 494 int error, flags; 495 struct nameidata nd; 496 497 error = priv_check(td, PRIV_UFS_QUOTAON); 498 if (error) 499 return (error); 500 501 if (mp->mnt_flag & MNT_RDONLY) 502 return (EROFS); 503 504 ump = VFSTOUFS(mp); 505 dq = NODQUOT; 506 507 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname, td); 508 flags = FREAD | FWRITE; 509 vfs_ref(mp); 510 vfs_unbusy(mp); 511 error = vn_open(&nd, &flags, 0, NULL); 512 if (error != 0) { 513 vfs_rel(mp); 514 return (error); 515 } 516 NDFREE(&nd, NDF_ONLY_PNBUF); 517 vp = nd.ni_vp; 518 error = vfs_busy(mp, MBF_NOWAIT); 519 vfs_rel(mp); 520 if (error == 0) { 521 if (vp->v_type != VREG) { 522 error = EACCES; 523 vfs_unbusy(mp); 524 } 525 } 526 if (error != 0) { 527 VOP_UNLOCK(vp, 0); 528 (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); 529 return (error); 530 } 531 532 UFS_LOCK(ump); 533 if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) { 534 UFS_UNLOCK(ump); 535 VOP_UNLOCK(vp, 0); 536 (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); 537 vfs_unbusy(mp); 538 return (EALREADY); 539 } 540 ump->um_qflags[type] |= QTF_OPENING|QTF_CLOSING; 541 UFS_UNLOCK(ump); 542 if ((error = dqopen(vp, ump, type)) != 0) { 543 VOP_UNLOCK(vp, 0); 544 UFS_LOCK(ump); 545 ump->um_qflags[type] &= ~(QTF_OPENING|QTF_CLOSING); 546 UFS_UNLOCK(ump); 547 (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); 548 vfs_unbusy(mp); 549 return (error); 550 } 551 VOP_UNLOCK(vp, 0); 552 MNT_ILOCK(mp); 553 mp->mnt_flag |= MNT_QUOTA; 554 MNT_IUNLOCK(mp); 555 556 vpp = &ump->um_quotas[type]; 557 if (*vpp != vp) 558 quotaoff1(td, mp, type); 559 560 /* 561 * When the directory vnode containing the quota file is 562 * inactivated, due to the shared lookup of the quota file 563 * vput()ing the dvp, the qsyncvp() call for the containing 564 * directory would try to acquire the quota lock exclusive. 565 * At the same time, lookup already locked the quota vnode 566 * shared. Mark the quota vnode lock as allowing recursion 567 * and automatically converting shared locks to exclusive. 568 * 569 * Also mark quota vnode as system. 570 */ 571 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 572 vp->v_vflag |= VV_SYSTEM; 573 VN_LOCK_AREC(vp); 574 VN_LOCK_DSHARE(vp); 575 VOP_UNLOCK(vp, 0); 576 *vpp = vp; 577 /* 578 * Save the credential of the process that turned on quotas. 579 * Set up the time limits for this quota. 580 */ 581 ump->um_cred[type] = crhold(td->td_ucred); 582 ump->um_btime[type] = MAX_DQ_TIME; 583 ump->um_itime[type] = MAX_IQ_TIME; 584 if (dqget(NULLVP, 0, ump, type, &dq) == 0) { 585 if (dq->dq_btime > 0) 586 ump->um_btime[type] = dq->dq_btime; 587 if (dq->dq_itime > 0) 588 ump->um_itime[type] = dq->dq_itime; 589 dqrele(NULLVP, dq); 590 } 591 /* 592 * Allow the getdq from getinoquota below to read the quota 593 * from file. 594 */ 595 UFS_LOCK(ump); 596 ump->um_qflags[type] &= ~QTF_CLOSING; 597 UFS_UNLOCK(ump); 598 /* 599 * Search vnodes associated with this mount point, 600 * adding references to quota file being opened. 601 * NB: only need to add dquot's for inodes being modified. 602 */ 603again: 604 MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 605 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 606 MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 607 goto again; 608 } 609 if (vp->v_type == VNON || vp->v_writecount == 0) { 610 VOP_UNLOCK(vp, 0); 611 vrele(vp); 612 continue; 613 } 614 error = getinoquota(VTOI(vp)); 615 VOP_UNLOCK(vp, 0); 616 vrele(vp); 617 if (error) { 618 MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 619 break; 620 } 621 } 622 623 if (error) 624 quotaoff_inchange(td, mp, type); 625 UFS_LOCK(ump); 626 ump->um_qflags[type] &= ~QTF_OPENING; 627 KASSERT((ump->um_qflags[type] & QTF_CLOSING) == 0, 628 ("quotaon: leaking flags")); 629 UFS_UNLOCK(ump); 630 631 vfs_unbusy(mp); 632 return (error); 633} 634 635/* 636 * Main code to turn off disk quotas for a filesystem. Does not change 637 * flags. 638 */ 639static int 640quotaoff1(struct thread *td, struct mount *mp, int type) 641{ 642 struct vnode *vp; 643 struct vnode *qvp, *mvp; 644 struct ufsmount *ump; 645 struct dquot *dq; 646 struct inode *ip; 647 struct ucred *cr; 648 int error; 649 650 ump = VFSTOUFS(mp); 651 652 UFS_LOCK(ump); 653 KASSERT((ump->um_qflags[type] & QTF_CLOSING) != 0, 654 ("quotaoff1: flags are invalid")); 655 if ((qvp = ump->um_quotas[type]) == NULLVP) { 656 UFS_UNLOCK(ump); 657 return (0); 658 } 659 cr = ump->um_cred[type]; 660 UFS_UNLOCK(ump); 661 662 /* 663 * Search vnodes associated with this mount point, 664 * deleting any references to quota file being closed. 665 */ 666again: 667 MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 668 if (vp->v_type == VNON) { 669 VI_UNLOCK(vp); 670 continue; 671 } 672 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 673 MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 674 goto again; 675 } 676 ip = VTOI(vp); 677 dq = ip->i_dquot[type]; 678 ip->i_dquot[type] = NODQUOT; 679 dqrele(vp, dq); 680 VOP_UNLOCK(vp, 0); 681 vrele(vp); 682 } 683 684 error = dqflush(qvp); 685 if (error != 0) 686 return (error); 687 688 /* 689 * Clear um_quotas before closing the quota vnode to prevent 690 * access to the closed vnode from dqget/dqsync 691 */ 692 UFS_LOCK(ump); 693 ump->um_quotas[type] = NULLVP; 694 ump->um_cred[type] = NOCRED; 695 UFS_UNLOCK(ump); 696 697 vn_lock(qvp, LK_EXCLUSIVE | LK_RETRY); 698 qvp->v_vflag &= ~VV_SYSTEM; 699 VOP_UNLOCK(qvp, 0); 700 error = vn_close(qvp, FREAD|FWRITE, td->td_ucred, td); 701 crfree(cr); 702 703 return (error); 704} 705 706/* 707 * Turns off quotas, assumes that ump->um_qflags are already checked 708 * and QTF_CLOSING is set to indicate operation in progress. Fixes 709 * ump->um_qflags and mp->mnt_flag after. 710 */ 711int 712quotaoff_inchange(struct thread *td, struct mount *mp, int type) 713{ 714 struct ufsmount *ump; 715 int i; 716 int error; 717 718 error = quotaoff1(td, mp, type); 719 720 ump = VFSTOUFS(mp); 721 UFS_LOCK(ump); 722 ump->um_qflags[type] &= ~QTF_CLOSING; 723 for (i = 0; i < MAXQUOTAS; i++) 724 if (ump->um_quotas[i] != NULLVP) 725 break; 726 if (i == MAXQUOTAS) { 727 MNT_ILOCK(mp); 728 mp->mnt_flag &= ~MNT_QUOTA; 729 MNT_IUNLOCK(mp); 730 } 731 UFS_UNLOCK(ump); 732 return (error); 733} 734 735/* 736 * Q_QUOTAOFF - turn off disk quotas for a filesystem. 737 */ 738int 739quotaoff(struct thread *td, struct mount *mp, int type) 740{ 741 struct ufsmount *ump; 742 int error; 743 744 error = priv_check(td, PRIV_UFS_QUOTAOFF); 745 if (error) 746 return (error); 747 748 ump = VFSTOUFS(mp); 749 UFS_LOCK(ump); 750 if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) { 751 UFS_UNLOCK(ump); 752 return (EALREADY); 753 } 754 ump->um_qflags[type] |= QTF_CLOSING; 755 UFS_UNLOCK(ump); 756 757 return (quotaoff_inchange(td, mp, type)); 758} 759 760/* 761 * Q_GETQUOTA - return current values in a dqblk structure. 762 */ 763static int 764_getquota(struct thread *td, struct mount *mp, u_long id, int type, 765 struct dqblk64 *dqb) 766{ 767 struct dquot *dq; 768 int error; 769 770 switch (type) { 771 case USRQUOTA: 772 if ((td->td_ucred->cr_uid != id) && !unprivileged_get_quota) { 773 error = priv_check(td, PRIV_VFS_GETQUOTA); 774 if (error) 775 return (error); 776 } 777 break; 778 779 case GRPQUOTA: 780 if (!groupmember(id, td->td_ucred) && 781 !unprivileged_get_quota) { 782 error = priv_check(td, PRIV_VFS_GETQUOTA); 783 if (error) 784 return (error); 785 } 786 break; 787 788 default: 789 return (EINVAL); 790 } 791 792 dq = NODQUOT; 793 error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq); 794 if (error) 795 return (error); 796 *dqb = dq->dq_dqb; 797 dqrele(NULLVP, dq); 798 return (error); 799} 800 801/* 802 * Q_SETQUOTA - assign an entire dqblk structure. 803 */ 804static int 805_setquota(struct thread *td, struct mount *mp, u_long id, int type, 806 struct dqblk64 *dqb) 807{ 808 struct dquot *dq; 809 struct dquot *ndq; 810 struct ufsmount *ump; 811 struct dqblk64 newlim; 812 int error; 813 814 error = priv_check(td, PRIV_VFS_SETQUOTA); 815 if (error) 816 return (error); 817 818 newlim = *dqb; 819 820 ndq = NODQUOT; 821 ump = VFSTOUFS(mp); 822 823 error = dqget(NULLVP, id, ump, type, &ndq); 824 if (error) 825 return (error); 826 dq = ndq; 827 DQI_LOCK(dq); 828 DQI_WAIT(dq, PINOD+1, "setqta"); 829 /* 830 * Copy all but the current values. 831 * Reset time limit if previously had no soft limit or were 832 * under it, but now have a soft limit and are over it. 833 */ 834 newlim.dqb_curblocks = dq->dq_curblocks; 835 newlim.dqb_curinodes = dq->dq_curinodes; 836 if (dq->dq_id != 0) { 837 newlim.dqb_btime = dq->dq_btime; 838 newlim.dqb_itime = dq->dq_itime; 839 } 840 if (newlim.dqb_bsoftlimit && 841 dq->dq_curblocks >= newlim.dqb_bsoftlimit && 842 (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit)) 843 newlim.dqb_btime = time_second + ump->um_btime[type]; 844 if (newlim.dqb_isoftlimit && 845 dq->dq_curinodes >= newlim.dqb_isoftlimit && 846 (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit)) 847 newlim.dqb_itime = time_second + ump->um_itime[type]; 848 dq->dq_dqb = newlim; 849 if (dq->dq_curblocks < dq->dq_bsoftlimit) 850 dq->dq_flags &= ~DQ_BLKS; 851 if (dq->dq_curinodes < dq->dq_isoftlimit) 852 dq->dq_flags &= ~DQ_INODS; 853 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && 854 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) 855 dq->dq_flags |= DQ_FAKE; 856 else 857 dq->dq_flags &= ~DQ_FAKE; 858 dq->dq_flags |= DQ_MOD; 859 DQI_UNLOCK(dq); 860 dqrele(NULLVP, dq); 861 return (0); 862} 863 864/* 865 * Q_SETUSE - set current inode and block usage. 866 */ 867static int 868_setuse(struct thread *td, struct mount *mp, u_long id, int type, 869 struct dqblk64 *dqb) 870{ 871 struct dquot *dq; 872 struct ufsmount *ump; 873 struct dquot *ndq; 874 struct dqblk64 usage; 875 int error; 876 877 error = priv_check(td, PRIV_UFS_SETUSE); 878 if (error) 879 return (error); 880 881 usage = *dqb; 882 883 ump = VFSTOUFS(mp); 884 ndq = NODQUOT; 885 886 error = dqget(NULLVP, id, ump, type, &ndq); 887 if (error) 888 return (error); 889 dq = ndq; 890 DQI_LOCK(dq); 891 DQI_WAIT(dq, PINOD+1, "setuse"); 892 /* 893 * Reset time limit if have a soft limit and were 894 * previously under it, but are now over it. 895 */ 896 if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit && 897 usage.dqb_curblocks >= dq->dq_bsoftlimit) 898 dq->dq_btime = time_second + ump->um_btime[type]; 899 if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit && 900 usage.dqb_curinodes >= dq->dq_isoftlimit) 901 dq->dq_itime = time_second + ump->um_itime[type]; 902 dq->dq_curblocks = usage.dqb_curblocks; 903 dq->dq_curinodes = usage.dqb_curinodes; 904 if (dq->dq_curblocks < dq->dq_bsoftlimit) 905 dq->dq_flags &= ~DQ_BLKS; 906 if (dq->dq_curinodes < dq->dq_isoftlimit) 907 dq->dq_flags &= ~DQ_INODS; 908 dq->dq_flags |= DQ_MOD; 909 DQI_UNLOCK(dq); 910 dqrele(NULLVP, dq); 911 return (0); 912} 913 914int 915getquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 916{ 917 struct dqblk32 dqb32; 918 struct dqblk64 dqb64; 919 int error; 920 921 error = _getquota(td, mp, id, type, &dqb64); 922 if (error) 923 return (error); 924 dqb64_dqb32(&dqb64, &dqb32); 925 error = copyout(&dqb32, addr, sizeof(dqb32)); 926 return (error); 927} 928 929int 930setquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 931{ 932 struct dqblk32 dqb32; 933 struct dqblk64 dqb64; 934 int error; 935 936 error = copyin(addr, &dqb32, sizeof(dqb32)); 937 if (error) 938 return (error); 939 dqb32_dqb64(&dqb32, &dqb64); 940 error = _setquota(td, mp, id, type, &dqb64); 941 return (error); 942} 943 944int 945setuse32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 946{ 947 struct dqblk32 dqb32; 948 struct dqblk64 dqb64; 949 int error; 950 951 error = copyin(addr, &dqb32, sizeof(dqb32)); 952 if (error) 953 return (error); 954 dqb32_dqb64(&dqb32, &dqb64); 955 error = _setuse(td, mp, id, type, &dqb64); 956 return (error); 957} 958 959int 960getquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 961{ 962 struct dqblk64 dqb64; 963 int error; 964 965 error = _getquota(td, mp, id, type, &dqb64); 966 if (error) 967 return (error); 968 error = copyout(&dqb64, addr, sizeof(dqb64)); 969 return (error); 970} 971 972int 973setquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 974{ 975 struct dqblk64 dqb64; 976 int error; 977 978 error = copyin(addr, &dqb64, sizeof(dqb64)); 979 if (error) 980 return (error); 981 error = _setquota(td, mp, id, type, &dqb64); 982 return (error); 983} 984 985int 986setuse(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 987{ 988 struct dqblk64 dqb64; 989 int error; 990 991 error = copyin(addr, &dqb64, sizeof(dqb64)); 992 if (error) 993 return (error); 994 error = _setuse(td, mp, id, type, &dqb64); 995 return (error); 996} 997 998/* 999 * Q_GETQUOTASIZE - get bit-size of quota file fields 1000 */ 1001int 1002getquotasize(struct thread *td, struct mount *mp, u_long id, int type, 1003 void *sizep) 1004{ 1005 struct ufsmount *ump = VFSTOUFS(mp); 1006 int bitsize; 1007 1008 UFS_LOCK(ump); 1009 if (ump->um_quotas[type] == NULLVP || 1010 (ump->um_qflags[type] & QTF_CLOSING)) { 1011 UFS_UNLOCK(ump); 1012 return (EINVAL); 1013 } 1014 if ((ump->um_qflags[type] & QTF_64BIT) != 0) 1015 bitsize = 64; 1016 else 1017 bitsize = 32; 1018 UFS_UNLOCK(ump); 1019 return (copyout(&bitsize, sizep, sizeof(int))); 1020} 1021 1022/* 1023 * Q_SYNC - sync quota files to disk. 1024 */ 1025int 1026qsync(struct mount *mp) 1027{ 1028 struct ufsmount *ump = VFSTOUFS(mp); 1029 struct thread *td = curthread; /* XXX */ 1030 struct vnode *vp, *mvp; 1031 struct dquot *dq; 1032 int i, error; 1033 1034 /* 1035 * Check if the mount point has any quotas. 1036 * If not, simply return. 1037 */ 1038 UFS_LOCK(ump); 1039 for (i = 0; i < MAXQUOTAS; i++) 1040 if (ump->um_quotas[i] != NULLVP) 1041 break; 1042 UFS_UNLOCK(ump); 1043 if (i == MAXQUOTAS) 1044 return (0); 1045 /* 1046 * Search vnodes associated with this mount point, 1047 * synchronizing any modified dquot structures. 1048 */ 1049again: 1050 MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { 1051 if (vp->v_type == VNON) { 1052 VI_UNLOCK(vp); 1053 continue; 1054 } 1055 error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td); 1056 if (error) { 1057 if (error == ENOENT) { 1058 MNT_VNODE_FOREACH_ACTIVE_ABORT(mp, mvp); 1059 goto again; 1060 } 1061 continue; 1062 } 1063 for (i = 0; i < MAXQUOTAS; i++) { 1064 dq = VTOI(vp)->i_dquot[i]; 1065 if (dq != NODQUOT) 1066 dqsync(vp, dq); 1067 } 1068 vput(vp); 1069 } 1070 return (0); 1071} 1072 1073/* 1074 * Sync quota file for given vnode to disk. 1075 */ 1076int 1077qsyncvp(struct vnode *vp) 1078{ 1079 struct ufsmount *ump = VFSTOUFS(vp->v_mount); 1080 struct dquot *dq; 1081 int i; 1082 1083 /* 1084 * Check if the mount point has any quotas. 1085 * If not, simply return. 1086 */ 1087 UFS_LOCK(ump); 1088 for (i = 0; i < MAXQUOTAS; i++) 1089 if (ump->um_quotas[i] != NULLVP) 1090 break; 1091 UFS_UNLOCK(ump); 1092 if (i == MAXQUOTAS) 1093 return (0); 1094 /* 1095 * Search quotas associated with this vnode 1096 * synchronizing any modified dquot structures. 1097 */ 1098 for (i = 0; i < MAXQUOTAS; i++) { 1099 dq = VTOI(vp)->i_dquot[i]; 1100 if (dq != NODQUOT) 1101 dqsync(vp, dq); 1102 } 1103 return (0); 1104} 1105 1106/* 1107 * Code pertaining to management of the in-core dquot data structures. 1108 */ 1109#define DQHASH(dqvp, id) \ 1110 (&dqhashtbl[((((intptr_t)(dqvp)) >> 8) + id) & dqhash]) 1111static LIST_HEAD(dqhash, dquot) *dqhashtbl; 1112static u_long dqhash; 1113 1114/* 1115 * Dquot free list. 1116 */ 1117#define DQUOTINC 5 /* minimum free dquots desired */ 1118static TAILQ_HEAD(dqfreelist, dquot) dqfreelist; 1119static long numdquot, desireddquot = DQUOTINC; 1120 1121/* 1122 * Lock to protect quota hash, dq free list and dq_cnt ref counters of 1123 * _all_ dqs. 1124 */ 1125struct mtx dqhlock; 1126 1127#define DQH_LOCK() mtx_lock(&dqhlock) 1128#define DQH_UNLOCK() mtx_unlock(&dqhlock) 1129 1130static struct dquot *dqhashfind(struct dqhash *dqh, u_long id, 1131 struct vnode *dqvp); 1132 1133/* 1134 * Initialize the quota system. 1135 */ 1136void 1137dqinit(void) 1138{ 1139 1140 mtx_init(&dqhlock, "dqhlock", NULL, MTX_DEF); 1141 dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash); 1142 TAILQ_INIT(&dqfreelist); 1143} 1144 1145/* 1146 * Shut down the quota system. 1147 */ 1148void 1149dquninit(void) 1150{ 1151 struct dquot *dq; 1152 1153 hashdestroy(dqhashtbl, M_DQUOT, dqhash); 1154 while ((dq = TAILQ_FIRST(&dqfreelist)) != NULL) { 1155 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); 1156 mtx_destroy(&dq->dq_lock); 1157 free(dq, M_DQUOT); 1158 } 1159 mtx_destroy(&dqhlock); 1160} 1161 1162static struct dquot * 1163dqhashfind(struct dqhash *dqh, u_long id, struct vnode *dqvp) 1164{ 1165 struct dquot *dq; 1166 1167 mtx_assert(&dqhlock, MA_OWNED); 1168 LIST_FOREACH(dq, dqh, dq_hash) { 1169 if (dq->dq_id != id || 1170 dq->dq_ump->um_quotas[dq->dq_type] != dqvp) 1171 continue; 1172 /* 1173 * Cache hit with no references. Take 1174 * the structure off the free list. 1175 */ 1176 if (dq->dq_cnt == 0) 1177 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); 1178 DQREF(dq); 1179 return (dq); 1180 } 1181 return (NODQUOT); 1182} 1183 1184/* 1185 * Determine the quota file type. 1186 * 1187 * A 32-bit quota file is simply an array of struct dqblk32. 1188 * 1189 * A 64-bit quota file is a struct dqhdr64 followed by an array of struct 1190 * dqblk64. The header contains various magic bits which allow us to be 1191 * reasonably confident that it is indeeda 64-bit quota file and not just 1192 * a 32-bit quota file that just happens to "look right". 1193 * 1194 */ 1195static int 1196dqopen(struct vnode *vp, struct ufsmount *ump, int type) 1197{ 1198 struct dqhdr64 dqh; 1199 struct iovec aiov; 1200 struct uio auio; 1201 int error; 1202 1203 ASSERT_VOP_LOCKED(vp, "dqopen"); 1204 auio.uio_iov = &aiov; 1205 auio.uio_iovcnt = 1; 1206 aiov.iov_base = &dqh; 1207 aiov.iov_len = sizeof(dqh); 1208 auio.uio_resid = sizeof(dqh); 1209 auio.uio_offset = 0; 1210 auio.uio_segflg = UIO_SYSSPACE; 1211 auio.uio_rw = UIO_READ; 1212 auio.uio_td = (struct thread *)0; 1213 error = VOP_READ(vp, &auio, 0, ump->um_cred[type]); 1214 1215 if (error != 0) 1216 return (error); 1217 if (auio.uio_resid > 0) { 1218 /* assume 32 bits */ 1219 return (0); 1220 } 1221 1222 UFS_LOCK(ump); 1223 if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) == 0 && 1224 be32toh(dqh.dqh_version) == Q_DQHDR64_VERSION && 1225 be32toh(dqh.dqh_hdrlen) == (uint32_t)sizeof(struct dqhdr64) && 1226 be32toh(dqh.dqh_reclen) == (uint32_t)sizeof(struct dqblk64)) { 1227 /* XXX: what if the magic matches, but the sizes are wrong? */ 1228 ump->um_qflags[type] |= QTF_64BIT; 1229 } else { 1230 ump->um_qflags[type] &= ~QTF_64BIT; 1231 } 1232 UFS_UNLOCK(ump); 1233 1234 return (0); 1235} 1236 1237/* 1238 * Obtain a dquot structure for the specified identifier and quota file 1239 * reading the information from the file if necessary. 1240 */ 1241static int 1242dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, 1243 struct dquot **dqp) 1244{ 1245 uint8_t buf[sizeof(struct dqblk64)]; 1246 off_t base, recsize; 1247 struct dquot *dq, *dq1; 1248 struct dqhash *dqh; 1249 struct vnode *dqvp; 1250 struct iovec aiov; 1251 struct uio auio; 1252 int dqvplocked, error; 1253 1254#ifdef DEBUG_VFS_LOCKS 1255 if (vp != NULLVP) 1256 ASSERT_VOP_ELOCKED(vp, "dqget"); 1257#endif 1258 1259 if (vp != NULLVP && *dqp != NODQUOT) { 1260 return (0); 1261 } 1262 1263 /* XXX: Disallow negative id values to prevent the 1264 * creation of 100GB+ quota data files. 1265 */ 1266 if ((int)id < 0) 1267 return (EINVAL); 1268 1269 UFS_LOCK(ump); 1270 dqvp = ump->um_quotas[type]; 1271 if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) { 1272 *dqp = NODQUOT; 1273 UFS_UNLOCK(ump); 1274 return (EINVAL); 1275 } 1276 vref(dqvp); 1277 UFS_UNLOCK(ump); 1278 error = 0; 1279 dqvplocked = 0; 1280 1281 /* 1282 * Check the cache first. 1283 */ 1284 dqh = DQHASH(dqvp, id); 1285 DQH_LOCK(); 1286 dq = dqhashfind(dqh, id, dqvp); 1287 if (dq != NULL) { 1288 DQH_UNLOCK(); 1289hfound: DQI_LOCK(dq); 1290 DQI_WAIT(dq, PINOD+1, "dqget"); 1291 DQI_UNLOCK(dq); 1292 if (dq->dq_ump == NULL) { 1293 dqrele(vp, dq); 1294 dq = NODQUOT; 1295 error = EIO; 1296 } 1297 *dqp = dq; 1298 if (dqvplocked) 1299 vput(dqvp); 1300 else 1301 vrele(dqvp); 1302 return (error); 1303 } 1304 1305 /* 1306 * Quota vnode lock is before DQ_LOCK. Acquire dqvp lock there 1307 * since new dq will appear on the hash chain DQ_LOCKed. 1308 */ 1309 if (vp != dqvp) { 1310 DQH_UNLOCK(); 1311 vn_lock(dqvp, LK_SHARED | LK_RETRY); 1312 dqvplocked = 1; 1313 DQH_LOCK(); 1314 /* 1315 * Recheck the cache after sleep for quota vnode lock. 1316 */ 1317 dq = dqhashfind(dqh, id, dqvp); 1318 if (dq != NULL) { 1319 DQH_UNLOCK(); 1320 goto hfound; 1321 } 1322 } 1323 1324 /* 1325 * Not in cache, allocate a new one or take it from the 1326 * free list. 1327 */ 1328 if (TAILQ_FIRST(&dqfreelist) == NODQUOT && 1329 numdquot < MAXQUOTAS * desiredvnodes) 1330 desireddquot += DQUOTINC; 1331 if (numdquot < desireddquot) { 1332 numdquot++; 1333 DQH_UNLOCK(); 1334 dq1 = malloc(sizeof *dq1, M_DQUOT, M_WAITOK | M_ZERO); 1335 mtx_init(&dq1->dq_lock, "dqlock", NULL, MTX_DEF); 1336 DQH_LOCK(); 1337 /* 1338 * Recheck the cache after sleep for memory. 1339 */ 1340 dq = dqhashfind(dqh, id, dqvp); 1341 if (dq != NULL) { 1342 numdquot--; 1343 DQH_UNLOCK(); 1344 mtx_destroy(&dq1->dq_lock); 1345 free(dq1, M_DQUOT); 1346 goto hfound; 1347 } 1348 dq = dq1; 1349 } else { 1350 if ((dq = TAILQ_FIRST(&dqfreelist)) == NULL) { 1351 DQH_UNLOCK(); 1352 tablefull("dquot"); 1353 *dqp = NODQUOT; 1354 if (dqvplocked) 1355 vput(dqvp); 1356 else 1357 vrele(dqvp); 1358 return (EUSERS); 1359 } 1360 if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) 1361 panic("dqget: free dquot isn't %p", dq); 1362 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); 1363 if (dq->dq_ump != NULL) 1364 LIST_REMOVE(dq, dq_hash); 1365 } 1366 1367 /* 1368 * Dq is put into hash already locked to prevent parallel 1369 * usage while it is being read from file. 1370 */ 1371 dq->dq_flags = DQ_LOCK; 1372 dq->dq_id = id; 1373 dq->dq_type = type; 1374 dq->dq_ump = ump; 1375 LIST_INSERT_HEAD(dqh, dq, dq_hash); 1376 DQREF(dq); 1377 DQH_UNLOCK(); 1378 1379 /* 1380 * Read the requested quota record from the quota file, performing 1381 * any necessary conversions. 1382 */ 1383 if (ump->um_qflags[type] & QTF_64BIT) { 1384 recsize = sizeof(struct dqblk64); 1385 base = sizeof(struct dqhdr64); 1386 } else { 1387 recsize = sizeof(struct dqblk32); 1388 base = 0; 1389 } 1390 auio.uio_iov = &aiov; 1391 auio.uio_iovcnt = 1; 1392 aiov.iov_base = buf; 1393 aiov.iov_len = recsize; 1394 auio.uio_resid = recsize; 1395 auio.uio_offset = base + id * recsize; 1396 auio.uio_segflg = UIO_SYSSPACE; 1397 auio.uio_rw = UIO_READ; 1398 auio.uio_td = (struct thread *)0; 1399 1400 error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]); 1401 if (auio.uio_resid == recsize && error == 0) { 1402 bzero(&dq->dq_dqb, sizeof(dq->dq_dqb)); 1403 } else { 1404 if (ump->um_qflags[type] & QTF_64BIT) 1405 dqb64_dq((struct dqblk64 *)buf, dq); 1406 else 1407 dqb32_dq((struct dqblk32 *)buf, dq); 1408 } 1409 if (dqvplocked) 1410 vput(dqvp); 1411 else 1412 vrele(dqvp); 1413 /* 1414 * I/O error in reading quota file, release 1415 * quota structure and reflect problem to caller. 1416 */ 1417 if (error) { 1418 DQH_LOCK(); 1419 dq->dq_ump = NULL; 1420 LIST_REMOVE(dq, dq_hash); 1421 DQH_UNLOCK(); 1422 DQI_LOCK(dq); 1423 if (dq->dq_flags & DQ_WANT) 1424 wakeup(dq); 1425 dq->dq_flags = 0; 1426 DQI_UNLOCK(dq); 1427 dqrele(vp, dq); 1428 *dqp = NODQUOT; 1429 return (error); 1430 } 1431 DQI_LOCK(dq); 1432 /* 1433 * Check for no limit to enforce. 1434 * Initialize time values if necessary. 1435 */ 1436 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && 1437 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) 1438 dq->dq_flags |= DQ_FAKE; 1439 if (dq->dq_id != 0) { 1440 if (dq->dq_btime == 0) { 1441 dq->dq_btime = time_second + ump->um_btime[type]; 1442 if (dq->dq_bsoftlimit && 1443 dq->dq_curblocks >= dq->dq_bsoftlimit) 1444 dq->dq_flags |= DQ_MOD; 1445 } 1446 if (dq->dq_itime == 0) { 1447 dq->dq_itime = time_second + ump->um_itime[type]; 1448 if (dq->dq_isoftlimit && 1449 dq->dq_curinodes >= dq->dq_isoftlimit) 1450 dq->dq_flags |= DQ_MOD; 1451 } 1452 } 1453 DQI_WAKEUP(dq); 1454 DQI_UNLOCK(dq); 1455 *dqp = dq; 1456 return (0); 1457} 1458 1459#ifdef DIAGNOSTIC 1460/* 1461 * Obtain a reference to a dquot. 1462 */ 1463static void 1464dqref(struct dquot *dq) 1465{ 1466 1467 dq->dq_cnt++; 1468} 1469#endif 1470 1471/* 1472 * Release a reference to a dquot. 1473 */ 1474void 1475dqrele(struct vnode *vp, struct dquot *dq) 1476{ 1477 1478 if (dq == NODQUOT) 1479 return; 1480 DQH_LOCK(); 1481 KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 1", dq)); 1482 if (dq->dq_cnt > 1) { 1483 dq->dq_cnt--; 1484 DQH_UNLOCK(); 1485 return; 1486 } 1487 DQH_UNLOCK(); 1488sync: 1489 (void) dqsync(vp, dq); 1490 1491 DQH_LOCK(); 1492 KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 2", dq)); 1493 if (--dq->dq_cnt > 0) 1494 { 1495 DQH_UNLOCK(); 1496 return; 1497 } 1498 1499 /* 1500 * The dq may become dirty after it is synced but before it is 1501 * put to the free list. Checking the DQ_MOD there without 1502 * locking dq should be safe since no other references to the 1503 * dq exist. 1504 */ 1505 if ((dq->dq_flags & DQ_MOD) != 0) { 1506 dq->dq_cnt++; 1507 DQH_UNLOCK(); 1508 goto sync; 1509 } 1510 TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist); 1511 DQH_UNLOCK(); 1512} 1513 1514/* 1515 * Update the disk quota in the quota file. 1516 */ 1517static int 1518dqsync(struct vnode *vp, struct dquot *dq) 1519{ 1520 uint8_t buf[sizeof(struct dqblk64)]; 1521 off_t base, recsize; 1522 struct vnode *dqvp; 1523 struct iovec aiov; 1524 struct uio auio; 1525 int error; 1526 struct mount *mp; 1527 struct ufsmount *ump; 1528 1529#ifdef DEBUG_VFS_LOCKS 1530 if (vp != NULL) 1531 ASSERT_VOP_ELOCKED(vp, "dqsync"); 1532#endif 1533 1534 mp = NULL; 1535 error = 0; 1536 if (dq == NODQUOT) 1537 panic("dqsync: dquot"); 1538 if ((ump = dq->dq_ump) == NULL) 1539 return (0); 1540 UFS_LOCK(ump); 1541 if ((dqvp = ump->um_quotas[dq->dq_type]) == NULLVP) 1542 panic("dqsync: file"); 1543 vref(dqvp); 1544 UFS_UNLOCK(ump); 1545 1546 DQI_LOCK(dq); 1547 if ((dq->dq_flags & DQ_MOD) == 0) { 1548 DQI_UNLOCK(dq); 1549 vrele(dqvp); 1550 return (0); 1551 } 1552 DQI_UNLOCK(dq); 1553 1554 (void) vn_start_secondary_write(dqvp, &mp, V_WAIT); 1555 if (vp != dqvp) 1556 vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY); 1557 1558 DQI_LOCK(dq); 1559 DQI_WAIT(dq, PINOD+2, "dqsync"); 1560 if ((dq->dq_flags & DQ_MOD) == 0) 1561 goto out; 1562 dq->dq_flags |= DQ_LOCK; 1563 DQI_UNLOCK(dq); 1564 1565 /* 1566 * Write the quota record to the quota file, performing any 1567 * necessary conversions. See dqget() for additional details. 1568 */ 1569 if (ump->um_qflags[dq->dq_type] & QTF_64BIT) { 1570 dq_dqb64(dq, (struct dqblk64 *)buf); 1571 recsize = sizeof(struct dqblk64); 1572 base = sizeof(struct dqhdr64); 1573 } else { 1574 dq_dqb32(dq, (struct dqblk32 *)buf); 1575 recsize = sizeof(struct dqblk32); 1576 base = 0; 1577 } 1578 1579 auio.uio_iov = &aiov; 1580 auio.uio_iovcnt = 1; 1581 aiov.iov_base = buf; 1582 aiov.iov_len = recsize; 1583 auio.uio_resid = recsize; 1584 auio.uio_offset = base + dq->dq_id * recsize; 1585 auio.uio_segflg = UIO_SYSSPACE; 1586 auio.uio_rw = UIO_WRITE; 1587 auio.uio_td = (struct thread *)0; 1588 error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); 1589 if (auio.uio_resid && error == 0) 1590 error = EIO; 1591 1592 DQI_LOCK(dq); 1593 DQI_WAKEUP(dq); 1594 dq->dq_flags &= ~DQ_MOD; 1595out: 1596 DQI_UNLOCK(dq); 1597 if (vp != dqvp) 1598 vput(dqvp); 1599 else 1600 vrele(dqvp); 1601 vn_finished_secondary_write(mp); 1602 return (error); 1603} 1604 1605/* 1606 * Flush all entries from the cache for a particular vnode. 1607 */ 1608static int 1609dqflush(struct vnode *vp) 1610{ 1611 struct dquot *dq, *nextdq; 1612 struct dqhash *dqh; 1613 int error; 1614 1615 /* 1616 * Move all dquot's that used to refer to this quota 1617 * file off their hash chains (they will eventually 1618 * fall off the head of the free list and be re-used). 1619 */ 1620 error = 0; 1621 DQH_LOCK(); 1622 for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) { 1623 for (dq = LIST_FIRST(dqh); dq; dq = nextdq) { 1624 nextdq = LIST_NEXT(dq, dq_hash); 1625 if (dq->dq_ump->um_quotas[dq->dq_type] != vp) 1626 continue; 1627 if (dq->dq_cnt) 1628 error = EBUSY; 1629 else { 1630 LIST_REMOVE(dq, dq_hash); 1631 dq->dq_ump = NULL; 1632 } 1633 } 1634 } 1635 DQH_UNLOCK(); 1636 return (error); 1637} 1638 1639/* 1640 * The following three functions are provided for the adjustment of 1641 * quotas by the soft updates code. 1642 */ 1643#ifdef SOFTUPDATES 1644/* 1645 * Acquire a reference to the quota structures associated with a vnode. 1646 * Return count of number of quota structures found. 1647 */ 1648int 1649quotaref(vp, qrp) 1650 struct vnode *vp; 1651 struct dquot **qrp; 1652{ 1653 struct inode *ip; 1654 struct dquot *dq; 1655 int i, found; 1656 1657 for (i = 0; i < MAXQUOTAS; i++) 1658 qrp[i] = NODQUOT; 1659 /* 1660 * Disk quotas must be turned off for system files. Currently 1661 * snapshot and quota files. 1662 */ 1663 if ((vp->v_vflag & VV_SYSTEM) != 0) 1664 return (0); 1665 /* 1666 * Iterate through and copy active quotas. 1667 */ 1668 found = 0; 1669 ip = VTOI(vp); 1670 mtx_lock(&dqhlock); 1671 for (i = 0; i < MAXQUOTAS; i++) { 1672 if ((dq = ip->i_dquot[i]) == NODQUOT) 1673 continue; 1674 DQREF(dq); 1675 qrp[i] = dq; 1676 found++; 1677 } 1678 mtx_unlock(&dqhlock); 1679 return (found); 1680} 1681 1682/* 1683 * Release a set of quota structures obtained from a vnode. 1684 */ 1685void 1686quotarele(qrp) 1687 struct dquot **qrp; 1688{ 1689 struct dquot *dq; 1690 int i; 1691 1692 for (i = 0; i < MAXQUOTAS; i++) { 1693 if ((dq = qrp[i]) == NODQUOT) 1694 continue; 1695 dqrele(NULL, dq); 1696 } 1697} 1698 1699/* 1700 * Adjust the number of blocks associated with a quota. 1701 * Positive numbers when adding blocks; negative numbers when freeing blocks. 1702 */ 1703void 1704quotaadj(qrp, ump, blkcount) 1705 struct dquot **qrp; 1706 struct ufsmount *ump; 1707 int64_t blkcount; 1708{ 1709 struct dquot *dq; 1710 ufs2_daddr_t ncurblocks; 1711 int i; 1712 1713 if (blkcount == 0) 1714 return; 1715 for (i = 0; i < MAXQUOTAS; i++) { 1716 if ((dq = qrp[i]) == NODQUOT) 1717 continue; 1718 DQI_LOCK(dq); 1719 DQI_WAIT(dq, PINOD+1, "adjqta"); 1720 ncurblocks = dq->dq_curblocks + blkcount; 1721 if (ncurblocks >= 0) 1722 dq->dq_curblocks = ncurblocks; 1723 else 1724 dq->dq_curblocks = 0; 1725 if (blkcount < 0) 1726 dq->dq_flags &= ~DQ_BLKS; 1727 else if (dq->dq_curblocks + blkcount >= dq->dq_bsoftlimit && 1728 dq->dq_curblocks < dq->dq_bsoftlimit) 1729 dq->dq_btime = time_second + ump->um_btime[i]; 1730 dq->dq_flags |= DQ_MOD; 1731 DQI_UNLOCK(dq); 1732 } 1733} 1734#endif /* SOFTUPDATES */ 1735 1736/* 1737 * 32-bit / 64-bit conversion functions. 1738 * 1739 * 32-bit quota records are stored in native byte order. Attention must 1740 * be paid to overflow issues. 1741 * 1742 * 64-bit quota records are stored in network byte order. 1743 */ 1744 1745#define CLIP32(u64) (u64 > UINT32_MAX ? UINT32_MAX : (uint32_t)u64) 1746 1747/* 1748 * Convert 32-bit host-order structure to dquot. 1749 */ 1750static void 1751dqb32_dq(const struct dqblk32 *dqb32, struct dquot *dq) 1752{ 1753 1754 dq->dq_bhardlimit = dqb32->dqb_bhardlimit; 1755 dq->dq_bsoftlimit = dqb32->dqb_bsoftlimit; 1756 dq->dq_curblocks = dqb32->dqb_curblocks; 1757 dq->dq_ihardlimit = dqb32->dqb_ihardlimit; 1758 dq->dq_isoftlimit = dqb32->dqb_isoftlimit; 1759 dq->dq_curinodes = dqb32->dqb_curinodes; 1760 dq->dq_btime = dqb32->dqb_btime; 1761 dq->dq_itime = dqb32->dqb_itime; 1762} 1763 1764/* 1765 * Convert 64-bit network-order structure to dquot. 1766 */ 1767static void 1768dqb64_dq(const struct dqblk64 *dqb64, struct dquot *dq) 1769{ 1770 1771 dq->dq_bhardlimit = be64toh(dqb64->dqb_bhardlimit); 1772 dq->dq_bsoftlimit = be64toh(dqb64->dqb_bsoftlimit); 1773 dq->dq_curblocks = be64toh(dqb64->dqb_curblocks); 1774 dq->dq_ihardlimit = be64toh(dqb64->dqb_ihardlimit); 1775 dq->dq_isoftlimit = be64toh(dqb64->dqb_isoftlimit); 1776 dq->dq_curinodes = be64toh(dqb64->dqb_curinodes); 1777 dq->dq_btime = be64toh(dqb64->dqb_btime); 1778 dq->dq_itime = be64toh(dqb64->dqb_itime); 1779} 1780 1781/* 1782 * Convert dquot to 32-bit host-order structure. 1783 */ 1784static void 1785dq_dqb32(const struct dquot *dq, struct dqblk32 *dqb32) 1786{ 1787 1788 dqb32->dqb_bhardlimit = CLIP32(dq->dq_bhardlimit); 1789 dqb32->dqb_bsoftlimit = CLIP32(dq->dq_bsoftlimit); 1790 dqb32->dqb_curblocks = CLIP32(dq->dq_curblocks); 1791 dqb32->dqb_ihardlimit = CLIP32(dq->dq_ihardlimit); 1792 dqb32->dqb_isoftlimit = CLIP32(dq->dq_isoftlimit); 1793 dqb32->dqb_curinodes = CLIP32(dq->dq_curinodes); 1794 dqb32->dqb_btime = CLIP32(dq->dq_btime); 1795 dqb32->dqb_itime = CLIP32(dq->dq_itime); 1796} 1797 1798/* 1799 * Convert dquot to 64-bit network-order structure. 1800 */ 1801static void 1802dq_dqb64(const struct dquot *dq, struct dqblk64 *dqb64) 1803{ 1804 1805 dqb64->dqb_bhardlimit = htobe64(dq->dq_bhardlimit); 1806 dqb64->dqb_bsoftlimit = htobe64(dq->dq_bsoftlimit); 1807 dqb64->dqb_curblocks = htobe64(dq->dq_curblocks); 1808 dqb64->dqb_ihardlimit = htobe64(dq->dq_ihardlimit); 1809 dqb64->dqb_isoftlimit = htobe64(dq->dq_isoftlimit); 1810 dqb64->dqb_curinodes = htobe64(dq->dq_curinodes); 1811 dqb64->dqb_btime = htobe64(dq->dq_btime); 1812 dqb64->dqb_itime = htobe64(dq->dq_itime); 1813} 1814 1815/* 1816 * Convert 64-bit host-order structure to 32-bit host-order structure. 1817 */ 1818static void 1819dqb64_dqb32(const struct dqblk64 *dqb64, struct dqblk32 *dqb32) 1820{ 1821 1822 dqb32->dqb_bhardlimit = CLIP32(dqb64->dqb_bhardlimit); 1823 dqb32->dqb_bsoftlimit = CLIP32(dqb64->dqb_bsoftlimit); 1824 dqb32->dqb_curblocks = CLIP32(dqb64->dqb_curblocks); 1825 dqb32->dqb_ihardlimit = CLIP32(dqb64->dqb_ihardlimit); 1826 dqb32->dqb_isoftlimit = CLIP32(dqb64->dqb_isoftlimit); 1827 dqb32->dqb_curinodes = CLIP32(dqb64->dqb_curinodes); 1828 dqb32->dqb_btime = CLIP32(dqb64->dqb_btime); 1829 dqb32->dqb_itime = CLIP32(dqb64->dqb_itime); 1830} 1831 1832/* 1833 * Convert 32-bit host-order structure to 64-bit host-order structure. 1834 */ 1835static void 1836dqb32_dqb64(const struct dqblk32 *dqb32, struct dqblk64 *dqb64) 1837{ 1838 1839 dqb64->dqb_bhardlimit = dqb32->dqb_bhardlimit; 1840 dqb64->dqb_bsoftlimit = dqb32->dqb_bsoftlimit; 1841 dqb64->dqb_curblocks = dqb32->dqb_curblocks; 1842 dqb64->dqb_ihardlimit = dqb32->dqb_ihardlimit; 1843 dqb64->dqb_isoftlimit = dqb32->dqb_isoftlimit; 1844 dqb64->dqb_curinodes = dqb32->dqb_curinodes; 1845 dqb64->dqb_btime = dqb32->dqb_btime; 1846 dqb64->dqb_itime = dqb32->dqb_itime; 1847} 1848