ufs_quota.c revision 260827
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 260827 2014-01-17 16:17:07Z mckusick $"); 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 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 561 vp->v_vflag |= VV_SYSTEM; 562 VOP_UNLOCK(vp, 0); 563 *vpp = vp; 564 /* 565 * Save the credential of the process that turned on quotas. 566 * Set up the time limits for this quota. 567 */ 568 ump->um_cred[type] = crhold(td->td_ucred); 569 ump->um_btime[type] = MAX_DQ_TIME; 570 ump->um_itime[type] = MAX_IQ_TIME; 571 if (dqget(NULLVP, 0, ump, type, &dq) == 0) { 572 if (dq->dq_btime > 0) 573 ump->um_btime[type] = dq->dq_btime; 574 if (dq->dq_itime > 0) 575 ump->um_itime[type] = dq->dq_itime; 576 dqrele(NULLVP, dq); 577 } 578 /* 579 * Allow the getdq from getinoquota below to read the quota 580 * from file. 581 */ 582 UFS_LOCK(ump); 583 ump->um_qflags[type] &= ~QTF_CLOSING; 584 UFS_UNLOCK(ump); 585 /* 586 * Search vnodes associated with this mount point, 587 * adding references to quota file being opened. 588 * NB: only need to add dquot's for inodes being modified. 589 */ 590again: 591 MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 592 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 593 MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 594 goto again; 595 } 596 if (vp->v_type == VNON || vp->v_writecount == 0) { 597 VOP_UNLOCK(vp, 0); 598 vrele(vp); 599 continue; 600 } 601 error = getinoquota(VTOI(vp)); 602 VOP_UNLOCK(vp, 0); 603 vrele(vp); 604 if (error) { 605 MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 606 break; 607 } 608 } 609 610 if (error) 611 quotaoff_inchange(td, mp, type); 612 UFS_LOCK(ump); 613 ump->um_qflags[type] &= ~QTF_OPENING; 614 KASSERT((ump->um_qflags[type] & QTF_CLOSING) == 0, 615 ("quotaon: leaking flags")); 616 UFS_UNLOCK(ump); 617 618 vfs_unbusy(mp); 619 return (error); 620} 621 622/* 623 * Main code to turn off disk quotas for a filesystem. Does not change 624 * flags. 625 */ 626static int 627quotaoff1(struct thread *td, struct mount *mp, int type) 628{ 629 struct vnode *vp; 630 struct vnode *qvp, *mvp; 631 struct ufsmount *ump; 632 struct dquot *dq; 633 struct inode *ip; 634 struct ucred *cr; 635 int error; 636 637 ump = VFSTOUFS(mp); 638 639 UFS_LOCK(ump); 640 KASSERT((ump->um_qflags[type] & QTF_CLOSING) != 0, 641 ("quotaoff1: flags are invalid")); 642 if ((qvp = ump->um_quotas[type]) == NULLVP) { 643 UFS_UNLOCK(ump); 644 return (0); 645 } 646 cr = ump->um_cred[type]; 647 UFS_UNLOCK(ump); 648 649 /* 650 * Search vnodes associated with this mount point, 651 * deleting any references to quota file being closed. 652 */ 653again: 654 MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 655 if (vp->v_type == VNON) { 656 VI_UNLOCK(vp); 657 continue; 658 } 659 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 660 MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 661 goto again; 662 } 663 ip = VTOI(vp); 664 dq = ip->i_dquot[type]; 665 ip->i_dquot[type] = NODQUOT; 666 dqrele(vp, dq); 667 VOP_UNLOCK(vp, 0); 668 vrele(vp); 669 } 670 671 error = dqflush(qvp); 672 if (error != 0) 673 return (error); 674 675 /* 676 * Clear um_quotas before closing the quota vnode to prevent 677 * access to the closed vnode from dqget/dqsync 678 */ 679 UFS_LOCK(ump); 680 ump->um_quotas[type] = NULLVP; 681 ump->um_cred[type] = NOCRED; 682 UFS_UNLOCK(ump); 683 684 vn_lock(qvp, LK_EXCLUSIVE | LK_RETRY); 685 qvp->v_vflag &= ~VV_SYSTEM; 686 VOP_UNLOCK(qvp, 0); 687 error = vn_close(qvp, FREAD|FWRITE, td->td_ucred, td); 688 crfree(cr); 689 690 return (error); 691} 692 693/* 694 * Turns off quotas, assumes that ump->um_qflags are already checked 695 * and QTF_CLOSING is set to indicate operation in progress. Fixes 696 * ump->um_qflags and mp->mnt_flag after. 697 */ 698int 699quotaoff_inchange(struct thread *td, struct mount *mp, int type) 700{ 701 struct ufsmount *ump; 702 int i; 703 int error; 704 705 error = quotaoff1(td, mp, type); 706 707 ump = VFSTOUFS(mp); 708 UFS_LOCK(ump); 709 ump->um_qflags[type] &= ~QTF_CLOSING; 710 for (i = 0; i < MAXQUOTAS; i++) 711 if (ump->um_quotas[i] != NULLVP) 712 break; 713 if (i == MAXQUOTAS) { 714 MNT_ILOCK(mp); 715 mp->mnt_flag &= ~MNT_QUOTA; 716 MNT_IUNLOCK(mp); 717 } 718 UFS_UNLOCK(ump); 719 return (error); 720} 721 722/* 723 * Q_QUOTAOFF - turn off disk quotas for a filesystem. 724 */ 725int 726quotaoff(struct thread *td, struct mount *mp, int type) 727{ 728 struct ufsmount *ump; 729 int error; 730 731 error = priv_check(td, PRIV_UFS_QUOTAOFF); 732 if (error) 733 return (error); 734 735 ump = VFSTOUFS(mp); 736 UFS_LOCK(ump); 737 if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) { 738 UFS_UNLOCK(ump); 739 return (EALREADY); 740 } 741 ump->um_qflags[type] |= QTF_CLOSING; 742 UFS_UNLOCK(ump); 743 744 return (quotaoff_inchange(td, mp, type)); 745} 746 747/* 748 * Q_GETQUOTA - return current values in a dqblk structure. 749 */ 750static int 751_getquota(struct thread *td, struct mount *mp, u_long id, int type, 752 struct dqblk64 *dqb) 753{ 754 struct dquot *dq; 755 int error; 756 757 switch (type) { 758 case USRQUOTA: 759 if ((td->td_ucred->cr_uid != id) && !unprivileged_get_quota) { 760 error = priv_check(td, PRIV_VFS_GETQUOTA); 761 if (error) 762 return (error); 763 } 764 break; 765 766 case GRPQUOTA: 767 if (!groupmember(id, td->td_ucred) && 768 !unprivileged_get_quota) { 769 error = priv_check(td, PRIV_VFS_GETQUOTA); 770 if (error) 771 return (error); 772 } 773 break; 774 775 default: 776 return (EINVAL); 777 } 778 779 dq = NODQUOT; 780 error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq); 781 if (error) 782 return (error); 783 *dqb = dq->dq_dqb; 784 dqrele(NULLVP, dq); 785 return (error); 786} 787 788/* 789 * Q_SETQUOTA - assign an entire dqblk structure. 790 */ 791static int 792_setquota(struct thread *td, struct mount *mp, u_long id, int type, 793 struct dqblk64 *dqb) 794{ 795 struct dquot *dq; 796 struct dquot *ndq; 797 struct ufsmount *ump; 798 struct dqblk64 newlim; 799 int error; 800 801 error = priv_check(td, PRIV_VFS_SETQUOTA); 802 if (error) 803 return (error); 804 805 newlim = *dqb; 806 807 ndq = NODQUOT; 808 ump = VFSTOUFS(mp); 809 810 error = dqget(NULLVP, id, ump, type, &ndq); 811 if (error) 812 return (error); 813 dq = ndq; 814 DQI_LOCK(dq); 815 DQI_WAIT(dq, PINOD+1, "setqta"); 816 /* 817 * Copy all but the current values. 818 * Reset time limit if previously had no soft limit or were 819 * under it, but now have a soft limit and are over it. 820 */ 821 newlim.dqb_curblocks = dq->dq_curblocks; 822 newlim.dqb_curinodes = dq->dq_curinodes; 823 if (dq->dq_id != 0) { 824 newlim.dqb_btime = dq->dq_btime; 825 newlim.dqb_itime = dq->dq_itime; 826 } 827 if (newlim.dqb_bsoftlimit && 828 dq->dq_curblocks >= newlim.dqb_bsoftlimit && 829 (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit)) 830 newlim.dqb_btime = time_second + ump->um_btime[type]; 831 if (newlim.dqb_isoftlimit && 832 dq->dq_curinodes >= newlim.dqb_isoftlimit && 833 (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit)) 834 newlim.dqb_itime = time_second + ump->um_itime[type]; 835 dq->dq_dqb = newlim; 836 if (dq->dq_curblocks < dq->dq_bsoftlimit) 837 dq->dq_flags &= ~DQ_BLKS; 838 if (dq->dq_curinodes < dq->dq_isoftlimit) 839 dq->dq_flags &= ~DQ_INODS; 840 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && 841 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) 842 dq->dq_flags |= DQ_FAKE; 843 else 844 dq->dq_flags &= ~DQ_FAKE; 845 dq->dq_flags |= DQ_MOD; 846 DQI_UNLOCK(dq); 847 dqrele(NULLVP, dq); 848 return (0); 849} 850 851/* 852 * Q_SETUSE - set current inode and block usage. 853 */ 854static int 855_setuse(struct thread *td, struct mount *mp, u_long id, int type, 856 struct dqblk64 *dqb) 857{ 858 struct dquot *dq; 859 struct ufsmount *ump; 860 struct dquot *ndq; 861 struct dqblk64 usage; 862 int error; 863 864 error = priv_check(td, PRIV_UFS_SETUSE); 865 if (error) 866 return (error); 867 868 usage = *dqb; 869 870 ump = VFSTOUFS(mp); 871 ndq = NODQUOT; 872 873 error = dqget(NULLVP, id, ump, type, &ndq); 874 if (error) 875 return (error); 876 dq = ndq; 877 DQI_LOCK(dq); 878 DQI_WAIT(dq, PINOD+1, "setuse"); 879 /* 880 * Reset time limit if have a soft limit and were 881 * previously under it, but are now over it. 882 */ 883 if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit && 884 usage.dqb_curblocks >= dq->dq_bsoftlimit) 885 dq->dq_btime = time_second + ump->um_btime[type]; 886 if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit && 887 usage.dqb_curinodes >= dq->dq_isoftlimit) 888 dq->dq_itime = time_second + ump->um_itime[type]; 889 dq->dq_curblocks = usage.dqb_curblocks; 890 dq->dq_curinodes = usage.dqb_curinodes; 891 if (dq->dq_curblocks < dq->dq_bsoftlimit) 892 dq->dq_flags &= ~DQ_BLKS; 893 if (dq->dq_curinodes < dq->dq_isoftlimit) 894 dq->dq_flags &= ~DQ_INODS; 895 dq->dq_flags |= DQ_MOD; 896 DQI_UNLOCK(dq); 897 dqrele(NULLVP, dq); 898 return (0); 899} 900 901int 902getquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 903{ 904 struct dqblk32 dqb32; 905 struct dqblk64 dqb64; 906 int error; 907 908 error = _getquota(td, mp, id, type, &dqb64); 909 if (error) 910 return (error); 911 dqb64_dqb32(&dqb64, &dqb32); 912 error = copyout(&dqb32, addr, sizeof(dqb32)); 913 return (error); 914} 915 916int 917setquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 918{ 919 struct dqblk32 dqb32; 920 struct dqblk64 dqb64; 921 int error; 922 923 error = copyin(addr, &dqb32, sizeof(dqb32)); 924 if (error) 925 return (error); 926 dqb32_dqb64(&dqb32, &dqb64); 927 error = _setquota(td, mp, id, type, &dqb64); 928 return (error); 929} 930 931int 932setuse32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 933{ 934 struct dqblk32 dqb32; 935 struct dqblk64 dqb64; 936 int error; 937 938 error = copyin(addr, &dqb32, sizeof(dqb32)); 939 if (error) 940 return (error); 941 dqb32_dqb64(&dqb32, &dqb64); 942 error = _setuse(td, mp, id, type, &dqb64); 943 return (error); 944} 945 946int 947getquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 948{ 949 struct dqblk64 dqb64; 950 int error; 951 952 error = _getquota(td, mp, id, type, &dqb64); 953 if (error) 954 return (error); 955 error = copyout(&dqb64, addr, sizeof(dqb64)); 956 return (error); 957} 958 959int 960setquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr) 961{ 962 struct dqblk64 dqb64; 963 int error; 964 965 error = copyin(addr, &dqb64, sizeof(dqb64)); 966 if (error) 967 return (error); 968 error = _setquota(td, mp, id, type, &dqb64); 969 return (error); 970} 971 972int 973setuse(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 = _setuse(td, mp, id, type, &dqb64); 982 return (error); 983} 984 985/* 986 * Q_GETQUOTASIZE - get bit-size of quota file fields 987 */ 988int 989getquotasize(struct thread *td, struct mount *mp, u_long id, int type, 990 void *sizep) 991{ 992 struct ufsmount *ump = VFSTOUFS(mp); 993 int bitsize; 994 995 UFS_LOCK(ump); 996 if (ump->um_quotas[type] == NULLVP || 997 (ump->um_qflags[type] & QTF_CLOSING)) { 998 UFS_UNLOCK(ump); 999 return (EINVAL); 1000 } 1001 if ((ump->um_qflags[type] & QTF_64BIT) != 0) 1002 bitsize = 64; 1003 else 1004 bitsize = 32; 1005 UFS_UNLOCK(ump); 1006 return (copyout(&bitsize, sizep, sizeof(int))); 1007} 1008 1009/* 1010 * Q_SYNC - sync quota files to disk. 1011 */ 1012int 1013qsync(struct mount *mp) 1014{ 1015 struct ufsmount *ump = VFSTOUFS(mp); 1016 struct thread *td = curthread; /* XXX */ 1017 struct vnode *vp, *mvp; 1018 struct dquot *dq; 1019 int i, error; 1020 1021 /* 1022 * Check if the mount point has any quotas. 1023 * If not, simply return. 1024 */ 1025 UFS_LOCK(ump); 1026 for (i = 0; i < MAXQUOTAS; i++) 1027 if (ump->um_quotas[i] != NULLVP) 1028 break; 1029 UFS_UNLOCK(ump); 1030 if (i == MAXQUOTAS) 1031 return (0); 1032 /* 1033 * Search vnodes associated with this mount point, 1034 * synchronizing any modified dquot structures. 1035 */ 1036again: 1037 MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { 1038 if (vp->v_type == VNON) { 1039 VI_UNLOCK(vp); 1040 continue; 1041 } 1042 error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td); 1043 if (error) { 1044 if (error == ENOENT) { 1045 MNT_VNODE_FOREACH_ACTIVE_ABORT(mp, mvp); 1046 goto again; 1047 } 1048 continue; 1049 } 1050 for (i = 0; i < MAXQUOTAS; i++) { 1051 dq = VTOI(vp)->i_dquot[i]; 1052 if (dq != NODQUOT) 1053 dqsync(vp, dq); 1054 } 1055 vput(vp); 1056 } 1057 return (0); 1058} 1059 1060/* 1061 * Sync quota file for given vnode to disk. 1062 */ 1063int 1064qsyncvp(struct vnode *vp) 1065{ 1066 struct ufsmount *ump = VFSTOUFS(vp->v_mount); 1067 struct dquot *dq; 1068 int i; 1069 1070 /* 1071 * Check if the mount point has any quotas. 1072 * If not, simply return. 1073 */ 1074 UFS_LOCK(ump); 1075 for (i = 0; i < MAXQUOTAS; i++) 1076 if (ump->um_quotas[i] != NULLVP) 1077 break; 1078 UFS_UNLOCK(ump); 1079 if (i == MAXQUOTAS) 1080 return (0); 1081 /* 1082 * Search quotas associated with this vnode 1083 * synchronizing any modified dquot structures. 1084 */ 1085 for (i = 0; i < MAXQUOTAS; i++) { 1086 dq = VTOI(vp)->i_dquot[i]; 1087 if (dq != NODQUOT) 1088 dqsync(vp, dq); 1089 } 1090 return (0); 1091} 1092 1093/* 1094 * Code pertaining to management of the in-core dquot data structures. 1095 */ 1096#define DQHASH(dqvp, id) \ 1097 (&dqhashtbl[((((intptr_t)(dqvp)) >> 8) + id) & dqhash]) 1098static LIST_HEAD(dqhash, dquot) *dqhashtbl; 1099static u_long dqhash; 1100 1101/* 1102 * Dquot free list. 1103 */ 1104#define DQUOTINC 5 /* minimum free dquots desired */ 1105static TAILQ_HEAD(dqfreelist, dquot) dqfreelist; 1106static long numdquot, desireddquot = DQUOTINC; 1107 1108/* 1109 * Lock to protect quota hash, dq free list and dq_cnt ref counters of 1110 * _all_ dqs. 1111 */ 1112struct mtx dqhlock; 1113 1114#define DQH_LOCK() mtx_lock(&dqhlock) 1115#define DQH_UNLOCK() mtx_unlock(&dqhlock) 1116 1117static struct dquot *dqhashfind(struct dqhash *dqh, u_long id, 1118 struct vnode *dqvp); 1119 1120/* 1121 * Initialize the quota system. 1122 */ 1123void 1124dqinit(void) 1125{ 1126 1127 mtx_init(&dqhlock, "dqhlock", NULL, MTX_DEF); 1128 dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash); 1129 TAILQ_INIT(&dqfreelist); 1130} 1131 1132/* 1133 * Shut down the quota system. 1134 */ 1135void 1136dquninit(void) 1137{ 1138 struct dquot *dq; 1139 1140 hashdestroy(dqhashtbl, M_DQUOT, dqhash); 1141 while ((dq = TAILQ_FIRST(&dqfreelist)) != NULL) { 1142 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); 1143 mtx_destroy(&dq->dq_lock); 1144 free(dq, M_DQUOT); 1145 } 1146 mtx_destroy(&dqhlock); 1147} 1148 1149static struct dquot * 1150dqhashfind(struct dqhash *dqh, u_long id, struct vnode *dqvp) 1151{ 1152 struct dquot *dq; 1153 1154 mtx_assert(&dqhlock, MA_OWNED); 1155 LIST_FOREACH(dq, dqh, dq_hash) { 1156 if (dq->dq_id != id || 1157 dq->dq_ump->um_quotas[dq->dq_type] != dqvp) 1158 continue; 1159 /* 1160 * Cache hit with no references. Take 1161 * the structure off the free list. 1162 */ 1163 if (dq->dq_cnt == 0) 1164 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); 1165 DQREF(dq); 1166 return (dq); 1167 } 1168 return (NODQUOT); 1169} 1170 1171/* 1172 * Determine the quota file type. 1173 * 1174 * A 32-bit quota file is simply an array of struct dqblk32. 1175 * 1176 * A 64-bit quota file is a struct dqhdr64 followed by an array of struct 1177 * dqblk64. The header contains various magic bits which allow us to be 1178 * reasonably confident that it is indeeda 64-bit quota file and not just 1179 * a 32-bit quota file that just happens to "look right". 1180 * 1181 */ 1182static int 1183dqopen(struct vnode *vp, struct ufsmount *ump, int type) 1184{ 1185 struct dqhdr64 dqh; 1186 struct iovec aiov; 1187 struct uio auio; 1188 int error; 1189 1190 ASSERT_VOP_LOCKED(vp, "dqopen"); 1191 auio.uio_iov = &aiov; 1192 auio.uio_iovcnt = 1; 1193 aiov.iov_base = &dqh; 1194 aiov.iov_len = sizeof(dqh); 1195 auio.uio_resid = sizeof(dqh); 1196 auio.uio_offset = 0; 1197 auio.uio_segflg = UIO_SYSSPACE; 1198 auio.uio_rw = UIO_READ; 1199 auio.uio_td = (struct thread *)0; 1200 error = VOP_READ(vp, &auio, 0, ump->um_cred[type]); 1201 1202 if (error != 0) 1203 return (error); 1204 if (auio.uio_resid > 0) { 1205 /* assume 32 bits */ 1206 return (0); 1207 } 1208 1209 UFS_LOCK(ump); 1210 if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) == 0 && 1211 be32toh(dqh.dqh_version) == Q_DQHDR64_VERSION && 1212 be32toh(dqh.dqh_hdrlen) == (uint32_t)sizeof(struct dqhdr64) && 1213 be32toh(dqh.dqh_reclen) == (uint32_t)sizeof(struct dqblk64)) { 1214 /* XXX: what if the magic matches, but the sizes are wrong? */ 1215 ump->um_qflags[type] |= QTF_64BIT; 1216 } else { 1217 ump->um_qflags[type] &= ~QTF_64BIT; 1218 } 1219 UFS_UNLOCK(ump); 1220 1221 return (0); 1222} 1223 1224/* 1225 * Obtain a dquot structure for the specified identifier and quota file 1226 * reading the information from the file if necessary. 1227 */ 1228static int 1229dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, 1230 struct dquot **dqp) 1231{ 1232 uint8_t buf[sizeof(struct dqblk64)]; 1233 off_t base, recsize; 1234 struct dquot *dq, *dq1; 1235 struct dqhash *dqh; 1236 struct vnode *dqvp; 1237 struct iovec aiov; 1238 struct uio auio; 1239 int dqvplocked, error; 1240 1241#ifdef DEBUG_VFS_LOCKS 1242 if (vp != NULLVP) 1243 ASSERT_VOP_ELOCKED(vp, "dqget"); 1244#endif 1245 1246 if (vp != NULLVP && *dqp != NODQUOT) { 1247 return (0); 1248 } 1249 1250 /* XXX: Disallow negative id values to prevent the 1251 * creation of 100GB+ quota data files. 1252 */ 1253 if ((int)id < 0) 1254 return (EINVAL); 1255 1256 UFS_LOCK(ump); 1257 dqvp = ump->um_quotas[type]; 1258 if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) { 1259 *dqp = NODQUOT; 1260 UFS_UNLOCK(ump); 1261 return (EINVAL); 1262 } 1263 vref(dqvp); 1264 UFS_UNLOCK(ump); 1265 error = 0; 1266 dqvplocked = 0; 1267 1268 /* 1269 * Check the cache first. 1270 */ 1271 dqh = DQHASH(dqvp, id); 1272 DQH_LOCK(); 1273 dq = dqhashfind(dqh, id, dqvp); 1274 if (dq != NULL) { 1275 DQH_UNLOCK(); 1276hfound: DQI_LOCK(dq); 1277 DQI_WAIT(dq, PINOD+1, "dqget"); 1278 DQI_UNLOCK(dq); 1279 if (dq->dq_ump == NULL) { 1280 dqrele(vp, dq); 1281 dq = NODQUOT; 1282 error = EIO; 1283 } 1284 *dqp = dq; 1285 if (dqvplocked) 1286 vput(dqvp); 1287 else 1288 vrele(dqvp); 1289 return (error); 1290 } 1291 1292 /* 1293 * Quota vnode lock is before DQ_LOCK. Acquire dqvp lock there 1294 * since new dq will appear on the hash chain DQ_LOCKed. 1295 */ 1296 if (vp != dqvp) { 1297 DQH_UNLOCK(); 1298 vn_lock(dqvp, LK_SHARED | LK_RETRY); 1299 dqvplocked = 1; 1300 DQH_LOCK(); 1301 /* 1302 * Recheck the cache after sleep for quota vnode lock. 1303 */ 1304 dq = dqhashfind(dqh, id, dqvp); 1305 if (dq != NULL) { 1306 DQH_UNLOCK(); 1307 goto hfound; 1308 } 1309 } 1310 1311 /* 1312 * Not in cache, allocate a new one or take it from the 1313 * free list. 1314 */ 1315 if (TAILQ_FIRST(&dqfreelist) == NODQUOT && 1316 numdquot < MAXQUOTAS * desiredvnodes) 1317 desireddquot += DQUOTINC; 1318 if (numdquot < desireddquot) { 1319 numdquot++; 1320 DQH_UNLOCK(); 1321 dq1 = malloc(sizeof *dq1, M_DQUOT, M_WAITOK | M_ZERO); 1322 mtx_init(&dq1->dq_lock, "dqlock", NULL, MTX_DEF); 1323 DQH_LOCK(); 1324 /* 1325 * Recheck the cache after sleep for memory. 1326 */ 1327 dq = dqhashfind(dqh, id, dqvp); 1328 if (dq != NULL) { 1329 numdquot--; 1330 DQH_UNLOCK(); 1331 mtx_destroy(&dq1->dq_lock); 1332 free(dq1, M_DQUOT); 1333 goto hfound; 1334 } 1335 dq = dq1; 1336 } else { 1337 if ((dq = TAILQ_FIRST(&dqfreelist)) == NULL) { 1338 DQH_UNLOCK(); 1339 tablefull("dquot"); 1340 *dqp = NODQUOT; 1341 if (dqvplocked) 1342 vput(dqvp); 1343 else 1344 vrele(dqvp); 1345 return (EUSERS); 1346 } 1347 if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) 1348 panic("dqget: free dquot isn't %p", dq); 1349 TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); 1350 if (dq->dq_ump != NULL) 1351 LIST_REMOVE(dq, dq_hash); 1352 } 1353 1354 /* 1355 * Dq is put into hash already locked to prevent parallel 1356 * usage while it is being read from file. 1357 */ 1358 dq->dq_flags = DQ_LOCK; 1359 dq->dq_id = id; 1360 dq->dq_type = type; 1361 dq->dq_ump = ump; 1362 LIST_INSERT_HEAD(dqh, dq, dq_hash); 1363 DQREF(dq); 1364 DQH_UNLOCK(); 1365 1366 /* 1367 * Read the requested quota record from the quota file, performing 1368 * any necessary conversions. 1369 */ 1370 if (ump->um_qflags[type] & QTF_64BIT) { 1371 recsize = sizeof(struct dqblk64); 1372 base = sizeof(struct dqhdr64); 1373 } else { 1374 recsize = sizeof(struct dqblk32); 1375 base = 0; 1376 } 1377 auio.uio_iov = &aiov; 1378 auio.uio_iovcnt = 1; 1379 aiov.iov_base = buf; 1380 aiov.iov_len = recsize; 1381 auio.uio_resid = recsize; 1382 auio.uio_offset = base + id * recsize; 1383 auio.uio_segflg = UIO_SYSSPACE; 1384 auio.uio_rw = UIO_READ; 1385 auio.uio_td = (struct thread *)0; 1386 1387 error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]); 1388 if (auio.uio_resid == recsize && error == 0) { 1389 bzero(&dq->dq_dqb, sizeof(dq->dq_dqb)); 1390 } else { 1391 if (ump->um_qflags[type] & QTF_64BIT) 1392 dqb64_dq((struct dqblk64 *)buf, dq); 1393 else 1394 dqb32_dq((struct dqblk32 *)buf, dq); 1395 } 1396 if (dqvplocked) 1397 vput(dqvp); 1398 else 1399 vrele(dqvp); 1400 /* 1401 * I/O error in reading quota file, release 1402 * quota structure and reflect problem to caller. 1403 */ 1404 if (error) { 1405 DQH_LOCK(); 1406 dq->dq_ump = NULL; 1407 LIST_REMOVE(dq, dq_hash); 1408 DQH_UNLOCK(); 1409 DQI_LOCK(dq); 1410 if (dq->dq_flags & DQ_WANT) 1411 wakeup(dq); 1412 dq->dq_flags = 0; 1413 DQI_UNLOCK(dq); 1414 dqrele(vp, dq); 1415 *dqp = NODQUOT; 1416 return (error); 1417 } 1418 DQI_LOCK(dq); 1419 /* 1420 * Check for no limit to enforce. 1421 * Initialize time values if necessary. 1422 */ 1423 if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && 1424 dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) 1425 dq->dq_flags |= DQ_FAKE; 1426 if (dq->dq_id != 0) { 1427 if (dq->dq_btime == 0) { 1428 dq->dq_btime = time_second + ump->um_btime[type]; 1429 if (dq->dq_bsoftlimit && 1430 dq->dq_curblocks >= dq->dq_bsoftlimit) 1431 dq->dq_flags |= DQ_MOD; 1432 } 1433 if (dq->dq_itime == 0) { 1434 dq->dq_itime = time_second + ump->um_itime[type]; 1435 if (dq->dq_isoftlimit && 1436 dq->dq_curinodes >= dq->dq_isoftlimit) 1437 dq->dq_flags |= DQ_MOD; 1438 } 1439 } 1440 DQI_WAKEUP(dq); 1441 DQI_UNLOCK(dq); 1442 *dqp = dq; 1443 return (0); 1444} 1445 1446#ifdef DIAGNOSTIC 1447/* 1448 * Obtain a reference to a dquot. 1449 */ 1450static void 1451dqref(struct dquot *dq) 1452{ 1453 1454 dq->dq_cnt++; 1455} 1456#endif 1457 1458/* 1459 * Release a reference to a dquot. 1460 */ 1461void 1462dqrele(struct vnode *vp, struct dquot *dq) 1463{ 1464 1465 if (dq == NODQUOT) 1466 return; 1467 DQH_LOCK(); 1468 KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 1", dq)); 1469 if (dq->dq_cnt > 1) { 1470 dq->dq_cnt--; 1471 DQH_UNLOCK(); 1472 return; 1473 } 1474 DQH_UNLOCK(); 1475sync: 1476 (void) dqsync(vp, dq); 1477 1478 DQH_LOCK(); 1479 KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 2", dq)); 1480 if (--dq->dq_cnt > 0) 1481 { 1482 DQH_UNLOCK(); 1483 return; 1484 } 1485 1486 /* 1487 * The dq may become dirty after it is synced but before it is 1488 * put to the free list. Checking the DQ_MOD there without 1489 * locking dq should be safe since no other references to the 1490 * dq exist. 1491 */ 1492 if ((dq->dq_flags & DQ_MOD) != 0) { 1493 dq->dq_cnt++; 1494 DQH_UNLOCK(); 1495 goto sync; 1496 } 1497 TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist); 1498 DQH_UNLOCK(); 1499} 1500 1501/* 1502 * Update the disk quota in the quota file. 1503 */ 1504static int 1505dqsync(struct vnode *vp, struct dquot *dq) 1506{ 1507 uint8_t buf[sizeof(struct dqblk64)]; 1508 off_t base, recsize; 1509 struct vnode *dqvp; 1510 struct iovec aiov; 1511 struct uio auio; 1512 int error; 1513 struct mount *mp; 1514 struct ufsmount *ump; 1515 1516#ifdef DEBUG_VFS_LOCKS 1517 if (vp != NULL) 1518 ASSERT_VOP_ELOCKED(vp, "dqsync"); 1519#endif 1520 1521 mp = NULL; 1522 error = 0; 1523 if (dq == NODQUOT) 1524 panic("dqsync: dquot"); 1525 if ((ump = dq->dq_ump) == NULL) 1526 return (0); 1527 UFS_LOCK(ump); 1528 if ((dqvp = ump->um_quotas[dq->dq_type]) == NULLVP) 1529 panic("dqsync: file"); 1530 vref(dqvp); 1531 UFS_UNLOCK(ump); 1532 1533 DQI_LOCK(dq); 1534 if ((dq->dq_flags & DQ_MOD) == 0) { 1535 DQI_UNLOCK(dq); 1536 vrele(dqvp); 1537 return (0); 1538 } 1539 DQI_UNLOCK(dq); 1540 1541 (void) vn_start_secondary_write(dqvp, &mp, V_WAIT); 1542 if (vp != dqvp) 1543 vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY); 1544 1545 DQI_LOCK(dq); 1546 DQI_WAIT(dq, PINOD+2, "dqsync"); 1547 if ((dq->dq_flags & DQ_MOD) == 0) 1548 goto out; 1549 dq->dq_flags |= DQ_LOCK; 1550 DQI_UNLOCK(dq); 1551 1552 /* 1553 * Write the quota record to the quota file, performing any 1554 * necessary conversions. See dqget() for additional details. 1555 */ 1556 if (ump->um_qflags[dq->dq_type] & QTF_64BIT) { 1557 dq_dqb64(dq, (struct dqblk64 *)buf); 1558 recsize = sizeof(struct dqblk64); 1559 base = sizeof(struct dqhdr64); 1560 } else { 1561 dq_dqb32(dq, (struct dqblk32 *)buf); 1562 recsize = sizeof(struct dqblk32); 1563 base = 0; 1564 } 1565 1566 auio.uio_iov = &aiov; 1567 auio.uio_iovcnt = 1; 1568 aiov.iov_base = buf; 1569 aiov.iov_len = recsize; 1570 auio.uio_resid = recsize; 1571 auio.uio_offset = base + dq->dq_id * recsize; 1572 auio.uio_segflg = UIO_SYSSPACE; 1573 auio.uio_rw = UIO_WRITE; 1574 auio.uio_td = (struct thread *)0; 1575 error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); 1576 if (auio.uio_resid && error == 0) 1577 error = EIO; 1578 1579 DQI_LOCK(dq); 1580 DQI_WAKEUP(dq); 1581 dq->dq_flags &= ~DQ_MOD; 1582out: 1583 DQI_UNLOCK(dq); 1584 if (vp != dqvp) 1585 vput(dqvp); 1586 else 1587 vrele(dqvp); 1588 vn_finished_secondary_write(mp); 1589 return (error); 1590} 1591 1592/* 1593 * Flush all entries from the cache for a particular vnode. 1594 */ 1595static int 1596dqflush(struct vnode *vp) 1597{ 1598 struct dquot *dq, *nextdq; 1599 struct dqhash *dqh; 1600 int error; 1601 1602 /* 1603 * Move all dquot's that used to refer to this quota 1604 * file off their hash chains (they will eventually 1605 * fall off the head of the free list and be re-used). 1606 */ 1607 error = 0; 1608 DQH_LOCK(); 1609 for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) { 1610 for (dq = LIST_FIRST(dqh); dq; dq = nextdq) { 1611 nextdq = LIST_NEXT(dq, dq_hash); 1612 if (dq->dq_ump->um_quotas[dq->dq_type] != vp) 1613 continue; 1614 if (dq->dq_cnt) 1615 error = EBUSY; 1616 else { 1617 LIST_REMOVE(dq, dq_hash); 1618 dq->dq_ump = NULL; 1619 } 1620 } 1621 } 1622 DQH_UNLOCK(); 1623 return (error); 1624} 1625 1626/* 1627 * The following three functions are provided for the adjustment of 1628 * quotas by the soft updates code. 1629 */ 1630#ifdef SOFTUPDATES 1631/* 1632 * Acquire a reference to the quota structures associated with a vnode. 1633 * Return count of number of quota structures found. 1634 */ 1635int 1636quotaref(vp, qrp) 1637 struct vnode *vp; 1638 struct dquot **qrp; 1639{ 1640 struct inode *ip; 1641 struct dquot *dq; 1642 int i, found; 1643 1644 for (i = 0; i < MAXQUOTAS; i++) 1645 qrp[i] = NODQUOT; 1646 /* 1647 * Disk quotas must be turned off for system files. Currently 1648 * snapshot and quota files. 1649 */ 1650 if ((vp->v_vflag & VV_SYSTEM) != 0) 1651 return (0); 1652 /* 1653 * Iterate through and copy active quotas. 1654 */ 1655 found = 0; 1656 ip = VTOI(vp); 1657 mtx_lock(&dqhlock); 1658 for (i = 0; i < MAXQUOTAS; i++) { 1659 if ((dq = ip->i_dquot[i]) == NODQUOT) 1660 continue; 1661 DQREF(dq); 1662 qrp[i] = dq; 1663 found++; 1664 } 1665 mtx_unlock(&dqhlock); 1666 return (found); 1667} 1668 1669/* 1670 * Release a set of quota structures obtained from a vnode. 1671 */ 1672void 1673quotarele(qrp) 1674 struct dquot **qrp; 1675{ 1676 struct dquot *dq; 1677 int i; 1678 1679 for (i = 0; i < MAXQUOTAS; i++) { 1680 if ((dq = qrp[i]) == NODQUOT) 1681 continue; 1682 dqrele(NULL, dq); 1683 } 1684} 1685 1686/* 1687 * Adjust the number of blocks associated with a quota. 1688 * Positive numbers when adding blocks; negative numbers when freeing blocks. 1689 */ 1690void 1691quotaadj(qrp, ump, blkcount) 1692 struct dquot **qrp; 1693 struct ufsmount *ump; 1694 int64_t blkcount; 1695{ 1696 struct dquot *dq; 1697 ufs2_daddr_t ncurblocks; 1698 int i; 1699 1700 if (blkcount == 0) 1701 return; 1702 for (i = 0; i < MAXQUOTAS; i++) { 1703 if ((dq = qrp[i]) == NODQUOT) 1704 continue; 1705 DQI_LOCK(dq); 1706 DQI_WAIT(dq, PINOD+1, "adjqta"); 1707 ncurblocks = dq->dq_curblocks + blkcount; 1708 if (ncurblocks >= 0) 1709 dq->dq_curblocks = ncurblocks; 1710 else 1711 dq->dq_curblocks = 0; 1712 if (blkcount < 0) 1713 dq->dq_flags &= ~DQ_BLKS; 1714 else if (dq->dq_curblocks + blkcount >= dq->dq_bsoftlimit && 1715 dq->dq_curblocks < dq->dq_bsoftlimit) 1716 dq->dq_btime = time_second + ump->um_btime[i]; 1717 dq->dq_flags |= DQ_MOD; 1718 DQI_UNLOCK(dq); 1719 } 1720} 1721#endif /* SOFTUPDATES */ 1722 1723/* 1724 * 32-bit / 64-bit conversion functions. 1725 * 1726 * 32-bit quota records are stored in native byte order. Attention must 1727 * be paid to overflow issues. 1728 * 1729 * 64-bit quota records are stored in network byte order. 1730 */ 1731 1732#define CLIP32(u64) (u64 > UINT32_MAX ? UINT32_MAX : (uint32_t)u64) 1733 1734/* 1735 * Convert 32-bit host-order structure to dquot. 1736 */ 1737static void 1738dqb32_dq(const struct dqblk32 *dqb32, struct dquot *dq) 1739{ 1740 1741 dq->dq_bhardlimit = dqb32->dqb_bhardlimit; 1742 dq->dq_bsoftlimit = dqb32->dqb_bsoftlimit; 1743 dq->dq_curblocks = dqb32->dqb_curblocks; 1744 dq->dq_ihardlimit = dqb32->dqb_ihardlimit; 1745 dq->dq_isoftlimit = dqb32->dqb_isoftlimit; 1746 dq->dq_curinodes = dqb32->dqb_curinodes; 1747 dq->dq_btime = dqb32->dqb_btime; 1748 dq->dq_itime = dqb32->dqb_itime; 1749} 1750 1751/* 1752 * Convert 64-bit network-order structure to dquot. 1753 */ 1754static void 1755dqb64_dq(const struct dqblk64 *dqb64, struct dquot *dq) 1756{ 1757 1758 dq->dq_bhardlimit = be64toh(dqb64->dqb_bhardlimit); 1759 dq->dq_bsoftlimit = be64toh(dqb64->dqb_bsoftlimit); 1760 dq->dq_curblocks = be64toh(dqb64->dqb_curblocks); 1761 dq->dq_ihardlimit = be64toh(dqb64->dqb_ihardlimit); 1762 dq->dq_isoftlimit = be64toh(dqb64->dqb_isoftlimit); 1763 dq->dq_curinodes = be64toh(dqb64->dqb_curinodes); 1764 dq->dq_btime = be64toh(dqb64->dqb_btime); 1765 dq->dq_itime = be64toh(dqb64->dqb_itime); 1766} 1767 1768/* 1769 * Convert dquot to 32-bit host-order structure. 1770 */ 1771static void 1772dq_dqb32(const struct dquot *dq, struct dqblk32 *dqb32) 1773{ 1774 1775 dqb32->dqb_bhardlimit = CLIP32(dq->dq_bhardlimit); 1776 dqb32->dqb_bsoftlimit = CLIP32(dq->dq_bsoftlimit); 1777 dqb32->dqb_curblocks = CLIP32(dq->dq_curblocks); 1778 dqb32->dqb_ihardlimit = CLIP32(dq->dq_ihardlimit); 1779 dqb32->dqb_isoftlimit = CLIP32(dq->dq_isoftlimit); 1780 dqb32->dqb_curinodes = CLIP32(dq->dq_curinodes); 1781 dqb32->dqb_btime = CLIP32(dq->dq_btime); 1782 dqb32->dqb_itime = CLIP32(dq->dq_itime); 1783} 1784 1785/* 1786 * Convert dquot to 64-bit network-order structure. 1787 */ 1788static void 1789dq_dqb64(const struct dquot *dq, struct dqblk64 *dqb64) 1790{ 1791 1792 dqb64->dqb_bhardlimit = htobe64(dq->dq_bhardlimit); 1793 dqb64->dqb_bsoftlimit = htobe64(dq->dq_bsoftlimit); 1794 dqb64->dqb_curblocks = htobe64(dq->dq_curblocks); 1795 dqb64->dqb_ihardlimit = htobe64(dq->dq_ihardlimit); 1796 dqb64->dqb_isoftlimit = htobe64(dq->dq_isoftlimit); 1797 dqb64->dqb_curinodes = htobe64(dq->dq_curinodes); 1798 dqb64->dqb_btime = htobe64(dq->dq_btime); 1799 dqb64->dqb_itime = htobe64(dq->dq_itime); 1800} 1801 1802/* 1803 * Convert 64-bit host-order structure to 32-bit host-order structure. 1804 */ 1805static void 1806dqb64_dqb32(const struct dqblk64 *dqb64, struct dqblk32 *dqb32) 1807{ 1808 1809 dqb32->dqb_bhardlimit = CLIP32(dqb64->dqb_bhardlimit); 1810 dqb32->dqb_bsoftlimit = CLIP32(dqb64->dqb_bsoftlimit); 1811 dqb32->dqb_curblocks = CLIP32(dqb64->dqb_curblocks); 1812 dqb32->dqb_ihardlimit = CLIP32(dqb64->dqb_ihardlimit); 1813 dqb32->dqb_isoftlimit = CLIP32(dqb64->dqb_isoftlimit); 1814 dqb32->dqb_curinodes = CLIP32(dqb64->dqb_curinodes); 1815 dqb32->dqb_btime = CLIP32(dqb64->dqb_btime); 1816 dqb32->dqb_itime = CLIP32(dqb64->dqb_itime); 1817} 1818 1819/* 1820 * Convert 32-bit host-order structure to 64-bit host-order structure. 1821 */ 1822static void 1823dqb32_dqb64(const struct dqblk32 *dqb32, struct dqblk64 *dqb64) 1824{ 1825 1826 dqb64->dqb_bhardlimit = dqb32->dqb_bhardlimit; 1827 dqb64->dqb_bsoftlimit = dqb32->dqb_bsoftlimit; 1828 dqb64->dqb_curblocks = dqb32->dqb_curblocks; 1829 dqb64->dqb_ihardlimit = dqb32->dqb_ihardlimit; 1830 dqb64->dqb_isoftlimit = dqb32->dqb_isoftlimit; 1831 dqb64->dqb_curinodes = dqb32->dqb_curinodes; 1832 dqb64->dqb_btime = dqb32->dqb_btime; 1833 dqb64->dqb_itime = dqb32->dqb_itime; 1834} 1835