1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 /* 40 * Quota system calls. 41 */ 42 #include <sys/types.h> 43 #include <sys/t_lock.h> 44 #include <sys/param.h> 45 #include <sys/time.h> 46 #include <sys/systm.h> 47 #include <sys/signal.h> 48 #include <sys/cred.h> 49 #include <sys/proc.h> 50 #include <sys/user.h> 51 #include <sys/proc.h> 52 #include <sys/vfs.h> 53 #include <sys/vnode.h> 54 #include <sys/uio.h> 55 #include <sys/buf.h> 56 #include <sys/file.h> 57 #include <sys/fs/ufs_inode.h> 58 #include <sys/fs/ufs_fs.h> 59 #include <sys/fs/ufs_quota.h> 60 #include <sys/errno.h> 61 #include <sys/debug.h> 62 #include <sys/cmn_err.h> 63 #include <sys/pathname.h> 64 #include <sys/mntent.h> 65 #include <sys/policy.h> 66 67 static int opendq(); 68 static int setquota(); 69 static int getquota(); 70 static int quotasync(); 71 72 /* 73 * Quota sub-system init flag. 74 */ 75 int quotas_initialized = 0; 76 77 /* 78 * Sys call to allow users to find out 79 * their current position wrt quota's 80 * and to allow privileged users to alter it. 81 */ 82 83 /*ARGSUSED*/ 84 int 85 quotactl(struct vnode *vp, intptr_t arg, int flag, struct cred *cr) 86 { 87 struct quotctl quot; 88 struct ufsvfs *ufsvfsp; 89 int error = 0; 90 91 if ((flag & DATAMODEL_MASK) == DATAMODEL_NATIVE) { 92 if (copyin((caddr_t)arg, ", sizeof (struct quotctl))) 93 return (EFAULT); 94 } 95 #ifdef _SYSCALL32_IMPL 96 else { 97 /* quotctl struct from ILP32 callers */ 98 struct quotctl32 quot32; 99 if (copyin((caddr_t)arg, "32, sizeof (struct quotctl32))) 100 return (EFAULT); 101 quot.op = quot32.op; 102 quot.uid = quot32.uid; 103 quot.addr = (caddr_t)(uintptr_t)quot32.addr; 104 } 105 #endif /* _SYSCALL32_IMPL */ 106 107 if (quot.uid < 0) 108 quot.uid = crgetruid(cr); 109 if (quot.op == Q_SYNC && vp == NULL) { 110 ufsvfsp = NULL; 111 } else if (quot.op != Q_ALLSYNC) { 112 ufsvfsp = (struct ufsvfs *)(vp->v_vfsp->vfs_data); 113 } 114 switch (quot.op) { 115 116 case Q_QUOTAON: 117 rw_enter(&dq_rwlock, RW_WRITER); 118 if (quotas_initialized == 0) { 119 qtinit2(); 120 quotas_initialized = 1; 121 } 122 rw_exit(&dq_rwlock); 123 error = opendq(ufsvfsp, vp, cr); 124 break; 125 126 case Q_QUOTAOFF: 127 error = closedq(ufsvfsp, cr); 128 if (!error) { 129 invalidatedq(ufsvfsp); 130 } 131 break; 132 133 case Q_SETQUOTA: 134 case Q_SETQLIM: 135 error = setquota(quot.op, (uid_t)quot.uid, ufsvfsp, 136 quot.addr, cr); 137 break; 138 139 case Q_GETQUOTA: 140 error = getquota((uid_t)quot.uid, ufsvfsp, (caddr_t)quot.addr, 141 cr); 142 break; 143 144 case Q_SYNC: 145 error = qsync(ufsvfsp); 146 break; 147 148 case Q_ALLSYNC: 149 (void) qsync(NULL); 150 break; 151 152 default: 153 error = EINVAL; 154 break; 155 } 156 return (error); 157 } 158 159 static int 160 opendq_scan_inode(struct inode *ip, void *arg) 161 { 162 struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 163 164 /* 165 * wrong file system or this is the quota inode; keep looking 166 */ 167 if (ufsvfsp != (struct ufsvfs *)arg || ip == ip->i_ufsvfs->vfs_qinod) { 168 return (0); 169 } 170 171 ASSERT(RW_WRITE_HELD(&ufsvfsp->vfs_dqrwlock)); 172 rw_enter(&ip->i_contents, RW_WRITER); 173 /* 174 * This inode is in the cache (by definition), is still valid, 175 * and is not a shadow inode or extended attribute directory inode, 176 * but does not have a quota so get the quota information. 177 */ 178 if (ip->i_mode && (ip->i_mode & IFMT) != IFSHAD && 179 (ip->i_mode & IFMT) != IFATTRDIR && ip->i_dquot == NULL) { 180 ip->i_dquot = getinoquota(ip); 181 } 182 rw_exit(&ip->i_contents); 183 184 return (0); 185 } 186 187 /* 188 * Set the quota file up for a particular file system. 189 * Called as the result of a quotaon (Q_QUOTAON) ioctl. 190 */ 191 static int 192 opendq( 193 struct ufsvfs *ufsvfsp, 194 struct vnode *vp, /* quota file */ 195 struct cred *cr) 196 { 197 struct inode *qip; 198 struct dquot *dqp; 199 int error; 200 int quotaon = 0; 201 202 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0) 203 return (EPERM); 204 205 VN_HOLD(vp); 206 207 /* 208 * Check to be sure its a regular file. 209 */ 210 if (vp->v_type != VREG) { 211 VN_RELE(vp); 212 return (EACCES); 213 } 214 215 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_WRITER); 216 217 /* 218 * We have vfs_dqrwlock as writer, so if quotas are disabled, 219 * then vfs_qinod should be NULL or we have a race somewhere. 220 */ 221 ASSERT((ufsvfsp->vfs_qflags & MQ_ENABLED) || (ufsvfsp->vfs_qinod == 0)); 222 223 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) != 0) { 224 /* 225 * Quotas are already enabled on this file system. 226 * 227 * If the "quotas" file was replaced (different inode) 228 * while quotas were enabled we don't want to re-enable 229 * them with a new "quotas" file. Simply print a warning 230 * message to the console, release the new vnode, and 231 * return. 232 * XXX - The right way to fix this is to return EBUSY 233 * for the ioctl() issued by 'quotaon'. 234 */ 235 if (VTOI(vp) != ufsvfsp->vfs_qinod) { 236 cmn_err(CE_WARN, "Previous quota file still in use." 237 " Disable quotas on %s before enabling.\n", 238 VTOI(vp)->i_fs->fs_fsmnt); 239 VN_RELE(vp); 240 rw_exit(&ufsvfsp->vfs_dqrwlock); 241 return (0); 242 } 243 (void) quotasync(ufsvfsp, /* do_lock */ 0); 244 /* remove extra hold on quota file */ 245 VN_RELE(vp); 246 quotaon++; 247 qip = ufsvfsp->vfs_qinod; 248 } else { 249 int qlen; 250 251 ufsvfsp->vfs_qinod = VTOI(vp); 252 qip = ufsvfsp->vfs_qinod; 253 /* 254 * Force the file to have no partially allocated blocks 255 * to prevent a realloc from changing the location of 256 * the data. We must do this even if not logging in 257 * case we later remount to logging. 258 */ 259 qlen = qip->i_fs->fs_bsize * NDADDR; 260 261 /* 262 * Largefiles: i_size needs to be atomically accessed now. 263 */ 264 rw_enter(&qip->i_contents, RW_WRITER); 265 if (qip->i_size < qlen) { 266 if (ufs_itrunc(qip, (u_offset_t)qlen, (int)0, cr) != 0) 267 cmn_err(CE_WARN, "opendq failed to remove frags" 268 " from quota file\n"); 269 rw_exit(&qip->i_contents); 270 (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)qip->i_size, 271 B_INVAL, kcred, NULL); 272 } else { 273 rw_exit(&qip->i_contents); 274 } 275 TRANS_MATA_IGET(ufsvfsp, qip); 276 } 277 278 /* 279 * The file system time limits are in the dquot for uid 0. 280 * The time limits set the relative time the other users 281 * can be over quota for this file system. 282 * If it is zero a default is used (see quota.h). 283 */ 284 error = getdiskquota((uid_t)0, ufsvfsp, 1, &dqp); 285 if (error == 0) { 286 mutex_enter(&dqp->dq_lock); 287 ufsvfsp->vfs_btimelimit = 288 (dqp->dq_btimelimit? dqp->dq_btimelimit: DQ_BTIMELIMIT); 289 ufsvfsp->vfs_ftimelimit = 290 (dqp->dq_ftimelimit? dqp->dq_ftimelimit: DQ_FTIMELIMIT); 291 292 ufsvfsp->vfs_qflags = MQ_ENABLED; /* enable quotas */ 293 vfs_setmntopt(ufsvfsp->vfs_vfs, MNTOPT_QUOTA, NULL, 0); 294 dqput(dqp); 295 mutex_exit(&dqp->dq_lock); 296 } else if (!quotaon) { 297 /* 298 * Some sort of I/O error on the quota file, and quotas were 299 * not already on when we got here so clean up. 300 */ 301 ufsvfsp->vfs_qflags = 0; 302 ufsvfsp->vfs_qinod = NULL; 303 VN_RELE(ITOV(qip)); 304 } 305 306 /* 307 * If quotas are enabled update all valid inodes in the 308 * cache with quota information. 309 */ 310 if (ufsvfsp->vfs_qflags & MQ_ENABLED) { 311 (void) ufs_scan_inodes(0, opendq_scan_inode, ufsvfsp, ufsvfsp); 312 } 313 314 rw_exit(&ufsvfsp->vfs_dqrwlock); 315 return (error); 316 } 317 318 static int 319 closedq_scan_inode(struct inode *ip, void *arg) 320 { 321 struct dquot *dqp; 322 struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 323 324 /* 325 * wrong file system; keep looking 326 */ 327 if (ufsvfsp != (struct ufsvfs *)arg) 328 return (0); 329 330 ASSERT(RW_WRITE_HELD(&ufsvfsp->vfs_dqrwlock)); 331 rw_enter(&ip->i_contents, RW_WRITER); 332 333 /* 334 * Shadow inodes and extended attribute directories 335 * do not have quota info records. 336 */ 337 if ((dqp = ip->i_dquot) != NULL) { 338 ASSERT((ip->i_mode & IFMT) != IFSHAD); 339 ASSERT((ip->i_mode & IFMT) != IFATTRDIR); 340 ip->i_dquot = NULL; 341 mutex_enter(&dqp->dq_lock); 342 dqput(dqp); 343 344 /* 345 * If we have a pending logging file system quota 346 * transaction, then cancel it. Clear the flag to 347 * prevent ufs_trans_push_quota() from trying to 348 * deal with this transaction just in case it is 349 * waiting for the mutex. We decrement the counter 350 * since the transaction won't be needing the quota 351 * info record anymore. 352 */ 353 if (dqp->dq_flags & DQ_TRANS) { 354 dqp->dq_flags &= ~DQ_TRANS; 355 dqput(dqp); 356 } 357 mutex_exit(&dqp->dq_lock); 358 } 359 rw_exit(&ip->i_contents); 360 361 return (0); 362 } 363 364 /* 365 * Close off disk quotas for a file system. 366 */ 367 int 368 closedq(struct ufsvfs *ufsvfsp, struct cred *cr) 369 { 370 struct inode *qip; 371 372 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0) 373 return (EPERM); 374 375 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_WRITER); 376 377 /* 378 * Quotas are not enabled on this file system so there is 379 * nothing more to do. 380 */ 381 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) { 382 rw_exit(&ufsvfsp->vfs_dqrwlock); 383 return (0); 384 } 385 386 /* 387 * At this point, the quota subsystem is quiescent on this file 388 * system so we can do all the work necessary to dismantle the 389 * quota stuff. 390 */ 391 qip = ufsvfsp->vfs_qinod; 392 if (!qip) 393 return (ufs_fault(ufsvfsp->vfs_root, "closedq: NULL qip")); 394 395 ufsvfsp->vfs_qflags = 0; /* disable quotas */ 396 vfs_setmntopt(ufsvfsp->vfs_vfs, MNTOPT_NOQUOTA, NULL, 0); 397 398 /* 399 * ufs_scan_inodes() depends on vfs_qinod, so we can't 400 * clear it until afterwards. 401 */ 402 (void) ufs_scan_inodes(0, closedq_scan_inode, ufsvfsp, ufsvfsp); 403 404 ufsvfsp->vfs_qinod = NULL; 405 rw_exit(&ufsvfsp->vfs_dqrwlock); 406 407 /* 408 * Sync and release the quota file inode. Since we have a private 409 * pointer to the quota inode and vfs_qinod is now clear we do not 410 * need to hold vfs_dqrwlock. 411 */ 412 (void) TRANS_SYNCIP(qip, 0, I_SYNC, TOP_SYNCIP_CLOSEDQ); 413 VN_RELE(ITOV(qip)); 414 return (0); 415 } 416 417 /* 418 * Private data between setquota() and setquota_scan_inode(). 419 */ 420 struct setquota_data { 421 #define SQD_TYPE_NONE 0 422 #define SQD_TYPE_LIMIT 1 423 #define SQD_TYPE_NO_LIMIT 2 424 int sqd_type; 425 struct ufsvfs *sqd_ufsvfsp; 426 uid_t sqd_uid; 427 }; 428 429 static int 430 setquota_scan_inode(struct inode *ip, void *arg) 431 { 432 struct setquota_data *sqdp = (struct setquota_data *)arg; 433 struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 434 435 /* 436 * wrong file system; keep looking 437 */ 438 if (ufsvfsp != sqdp->sqd_ufsvfsp) 439 return (0); 440 441 ASSERT(RW_WRITE_HELD(&ufsvfsp->vfs_dqrwlock)); 442 443 /* 444 * The file system does not have quotas enabled or this is the 445 * file system's quota inode; keep looking. 446 */ 447 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0 || 448 ip == ufsvfsp->vfs_qinod) { 449 return (0); 450 } 451 452 rw_enter(&ip->i_contents, RW_WRITER); 453 /* 454 * This inode is in the cache (by definition), is still valid, 455 * is not a shadow inode or extended attribute directory inode 456 * and has the right uid. 457 */ 458 if (ip->i_mode && (ip->i_mode & IFMT) != IFSHAD && 459 (ip->i_mode & IFMT) != IFATTRDIR && ip->i_uid == sqdp->sqd_uid) { 460 /* 461 * Transition is "no limit" to "at least one limit": 462 */ 463 if (sqdp->sqd_type == SQD_TYPE_LIMIT && 464 ip->i_dquot == NULL) { 465 ip->i_dquot = getinoquota(ip); 466 } 467 /* 468 * Transition is "at least one limit" to "no limit": 469 */ 470 else if (sqdp->sqd_type == SQD_TYPE_NO_LIMIT && ip->i_dquot) { 471 mutex_enter(&ip->i_dquot->dq_lock); 472 dqput(ip->i_dquot); 473 mutex_exit(&ip->i_dquot->dq_lock); 474 ip->i_dquot = NULL; 475 } 476 } 477 rw_exit(&ip->i_contents); 478 479 return (0); 480 } 481 482 /* 483 * Set various fields of the dqblk according to the command. 484 * Q_SETQUOTA - assign an entire dqblk structure. 485 * Q_SETQLIM - assign a dqblk structure except for the usage. 486 */ 487 static int 488 setquota(int cmd, uid_t uid, struct ufsvfs *ufsvfsp, 489 caddr_t addr, struct cred *cr) 490 { 491 struct dquot *dqp; 492 struct inode *qip; 493 struct dquot *xdqp; 494 struct dqblk newlim; 495 int error; 496 int scan_type = SQD_TYPE_NONE; 497 daddr_t bn; 498 int contig; 499 500 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0) 501 return (EPERM); 502 503 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_WRITER); 504 505 /* 506 * Quotas are not enabled on this file system so there is 507 * nothing more to do. 508 */ 509 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) { 510 rw_exit(&ufsvfsp->vfs_dqrwlock); 511 return (ESRCH); 512 } 513 514 /* 515 * At this point, the quota subsystem is quiescent on this file 516 * system so we can do all the work necessary to modify the quota 517 * information for this user. 518 */ 519 520 if (copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)) != 0) { 521 rw_exit(&ufsvfsp->vfs_dqrwlock); 522 return (EFAULT); 523 } 524 error = getdiskquota(uid, ufsvfsp, 0, &xdqp); 525 if (error) { 526 rw_exit(&ufsvfsp->vfs_dqrwlock); 527 return (error); 528 } 529 dqp = xdqp; 530 /* 531 * Don't change disk usage on Q_SETQLIM 532 */ 533 mutex_enter(&dqp->dq_lock); 534 if (cmd == Q_SETQLIM) { 535 newlim.dqb_curblocks = dqp->dq_curblocks; 536 newlim.dqb_curfiles = dqp->dq_curfiles; 537 } 538 if (uid == 0) { 539 /* 540 * Timelimits for uid 0 set the relative time 541 * the other users can be over quota for this file system. 542 * If it is zero a default is used (see quota.h). 543 */ 544 ufsvfsp->vfs_btimelimit = 545 newlim.dqb_btimelimit? newlim.dqb_btimelimit: DQ_BTIMELIMIT; 546 ufsvfsp->vfs_ftimelimit = 547 newlim.dqb_ftimelimit? newlim.dqb_ftimelimit: DQ_FTIMELIMIT; 548 } else { 549 if (newlim.dqb_bsoftlimit && 550 newlim.dqb_curblocks >= newlim.dqb_bsoftlimit) { 551 if (dqp->dq_bsoftlimit == 0 || 552 dqp->dq_curblocks < dqp->dq_bsoftlimit) { 553 /* If we're suddenly over the limit(s), */ 554 /* start the timer(s) */ 555 newlim.dqb_btimelimit = 556 (uint32_t)gethrestime_sec() + 557 ufsvfsp->vfs_btimelimit; 558 dqp->dq_flags &= ~DQ_BLKS; 559 } else { 560 /* If we're currently over the soft */ 561 /* limit and were previously over the */ 562 /* soft limit then preserve the old */ 563 /* time limit but make sure the DQ_BLKS */ 564 /* flag is set since we must have been */ 565 /* previously warned. */ 566 newlim.dqb_btimelimit = dqp->dq_btimelimit; 567 dqp->dq_flags |= DQ_BLKS; 568 } 569 } else { 570 /* Either no quota or under quota, clear time limit */ 571 newlim.dqb_btimelimit = 0; 572 dqp->dq_flags &= ~DQ_BLKS; 573 } 574 575 if (newlim.dqb_fsoftlimit && 576 newlim.dqb_curfiles >= newlim.dqb_fsoftlimit) { 577 if (dqp->dq_fsoftlimit == 0 || 578 dqp->dq_curfiles < dqp->dq_fsoftlimit) { 579 /* If we're suddenly over the limit(s), */ 580 /* start the timer(s) */ 581 newlim.dqb_ftimelimit = 582 (uint32_t)gethrestime_sec() + 583 ufsvfsp->vfs_ftimelimit; 584 dqp->dq_flags &= ~DQ_FILES; 585 } else { 586 /* If we're currently over the soft */ 587 /* limit and were previously over the */ 588 /* soft limit then preserve the old */ 589 /* time limit but make sure the */ 590 /* DQ_FILES flag is set since we must */ 591 /* have been previously warned. */ 592 newlim.dqb_ftimelimit = dqp->dq_ftimelimit; 593 dqp->dq_flags |= DQ_FILES; 594 } 595 } else { 596 /* Either no quota or under quota, clear time limit */ 597 newlim.dqb_ftimelimit = 0; 598 dqp->dq_flags &= ~DQ_FILES; 599 } 600 } 601 602 /* 603 * If there was previously no limit and there is now at least 604 * one limit, then any inodes in the cache have NULL d_iquot 605 * fields (getinoquota() returns NULL when there are no limits). 606 */ 607 if ((dqp->dq_fhardlimit == 0 && dqp->dq_fsoftlimit == 0 && 608 dqp->dq_bhardlimit == 0 && dqp->dq_bsoftlimit == 0) && 609 (newlim.dqb_fhardlimit || newlim.dqb_fsoftlimit || 610 newlim.dqb_bhardlimit || newlim.dqb_bsoftlimit)) { 611 scan_type = SQD_TYPE_LIMIT; 612 } 613 614 /* 615 * If there was previously at least one limit and there is now 616 * no limit, then any inodes in the cache have non-NULL d_iquot 617 * fields need to be reset to NULL. 618 */ 619 else if ((dqp->dq_fhardlimit || dqp->dq_fsoftlimit || 620 dqp->dq_bhardlimit || dqp->dq_bsoftlimit) && 621 (newlim.dqb_fhardlimit == 0 && newlim.dqb_fsoftlimit == 0 && 622 newlim.dqb_bhardlimit == 0 && newlim.dqb_bsoftlimit == 0)) { 623 scan_type = SQD_TYPE_NO_LIMIT; 624 } 625 626 dqp->dq_dqb = newlim; 627 dqp->dq_flags |= DQ_MOD; 628 629 /* 630 * push the new quota to disk now. If this is a trans device 631 * then force the page out with ufs_putpage so it will be deltaed 632 * by ufs_startio. 633 */ 634 qip = ufsvfsp->vfs_qinod; 635 rw_enter(&qip->i_contents, RW_WRITER); 636 (void) ufs_rdwri(UIO_WRITE, FWRITE | FSYNC, qip, (caddr_t)&dqp->dq_dqb, 637 sizeof (struct dqblk), dqoff(uid), UIO_SYSSPACE, 638 (int *)NULL, kcred); 639 rw_exit(&qip->i_contents); 640 641 (void) VOP_PUTPAGE(ITOV(qip), dqoff(dqp->dq_uid) & ~qip->i_fs->fs_bmask, 642 qip->i_fs->fs_bsize, B_INVAL, kcred, NULL); 643 644 /* 645 * We must set the dq_mof even if not we are not logging in case 646 * we are later remount to logging. 647 */ 648 contig = 0; 649 rw_enter(&qip->i_contents, RW_WRITER); 650 error = bmap_read(qip, dqoff(dqp->dq_uid), &bn, &contig); 651 rw_exit(&qip->i_contents); 652 if (error || (bn == UFS_HOLE)) { 653 dqp->dq_mof = UFS_HOLE; 654 } else { 655 dqp->dq_mof = ldbtob(bn) + 656 (offset_t)((dqoff(dqp->dq_uid)) & (DEV_BSIZE - 1)); 657 } 658 659 dqp->dq_flags &= ~DQ_MOD; 660 dqput(dqp); 661 mutex_exit(&dqp->dq_lock); 662 if (scan_type) { 663 struct setquota_data sqd; 664 665 sqd.sqd_type = scan_type; 666 sqd.sqd_ufsvfsp = ufsvfsp; 667 sqd.sqd_uid = uid; 668 (void) ufs_scan_inodes(0, setquota_scan_inode, &sqd, ufsvfsp); 669 } 670 rw_exit(&ufsvfsp->vfs_dqrwlock); 671 return (0); 672 } 673 674 /* 675 * Q_GETQUOTA - return current values in a dqblk structure. 676 */ 677 static int 678 getquota(uid_t uid, struct ufsvfs *ufsvfsp, caddr_t addr, cred_t *cr) 679 { 680 struct dquot *dqp; 681 struct dquot *xdqp; 682 struct dqblk dqb; 683 int error = 0; 684 685 if (uid != crgetruid(cr) && 686 secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0) 687 return (EPERM); 688 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 689 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) { 690 rw_exit(&ufsvfsp->vfs_dqrwlock); 691 return (ESRCH); 692 } 693 error = getdiskquota(uid, ufsvfsp, 0, &xdqp); 694 if (error) { 695 rw_exit(&ufsvfsp->vfs_dqrwlock); 696 return (error); 697 } 698 dqp = xdqp; 699 mutex_enter(&dqp->dq_lock); 700 if (dqp->dq_fhardlimit == 0 && dqp->dq_fsoftlimit == 0 && 701 dqp->dq_bhardlimit == 0 && dqp->dq_bsoftlimit == 0) { 702 error = ESRCH; 703 } else { 704 bcopy(&dqp->dq_dqb, &dqb, sizeof (struct dqblk)); 705 } 706 dqput(dqp); 707 mutex_exit(&dqp->dq_lock); 708 rw_exit(&ufsvfsp->vfs_dqrwlock); 709 if (error == 0 && copyout(&dqb, addr, sizeof (struct dqblk)) != 0) 710 error = EFAULT; 711 return (error); 712 } 713 714 /* 715 * Q_SYNC - sync quota files to disk. 716 */ 717 int 718 qsync(struct ufsvfs *ufsvfsp) 719 { 720 return (quotasync(ufsvfsp, /* do_lock */ 1)); 721 } 722 723 /* 724 * Sync quota information records to disk for the specified file system 725 * or all file systems with quotas if ufsvfsp == NULL. Grabs a reader 726 * lock on vfs_dqrwlock if it is needed. 727 * 728 * Currently, if ufsvfsp is NULL, then do_lock is always true, but the 729 * routine is coded to account for either do_lock value. This seemed 730 * to be the safer thing to do. 731 */ 732 int 733 quotasync(struct ufsvfs *ufsvfsp, int do_lock) 734 { 735 struct dquot *dqp; 736 737 rw_enter(&dq_rwlock, RW_READER); 738 if (!quotas_initialized) { 739 rw_exit(&dq_rwlock); 740 return (ESRCH); 741 } 742 rw_exit(&dq_rwlock); 743 744 /* 745 * The operation applies to a specific file system only. 746 */ 747 if (ufsvfsp) { 748 if (do_lock) { 749 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 750 } 751 752 /* 753 * Quotas are not enabled on this file system so bail. 754 */ 755 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) { 756 if (do_lock) { 757 rw_exit(&ufsvfsp->vfs_dqrwlock); 758 } 759 return (ESRCH); 760 } 761 762 /* 763 * This operation is a no-op on a logging file system because 764 * quota information is treated as metadata and is in the log. 765 * This code path treats quota information as user data which 766 * is not necessary on a logging file system. 767 */ 768 if (TRANS_ISTRANS(ufsvfsp)) { 769 if (do_lock) { 770 rw_exit(&ufsvfsp->vfs_dqrwlock); 771 } 772 return (0); 773 } 774 775 /* 776 * Try to sync all the quota info records for this 777 * file system: 778 */ 779 for (dqp = dquot; dqp < dquotNDQUOT; dqp++) { 780 /* 781 * If someone else has it, then ignore it. 782 */ 783 if (!mutex_tryenter(&dqp->dq_lock)) { 784 continue; 785 } 786 787 /* 788 * The quota info record is for this file system 789 * and it has changes. 790 */ 791 if (dqp->dq_ufsvfsp == ufsvfsp && 792 (dqp->dq_flags & DQ_MOD)) { 793 ASSERT(ufsvfsp->vfs_qflags & MQ_ENABLED); 794 dqupdate(dqp); 795 } 796 797 mutex_exit(&dqp->dq_lock); 798 } 799 if (do_lock) { 800 rw_exit(&ufsvfsp->vfs_dqrwlock); 801 } 802 803 return (0); 804 } 805 806 /* 807 * Try to sync all the quota info records for *all* file systems 808 * for which quotas are enabled. 809 */ 810 for (dqp = dquot; dqp < dquotNDQUOT; dqp++) { 811 /* 812 * If someone else has it, then ignore it. 813 */ 814 if (!mutex_tryenter(&dqp->dq_lock)) { 815 continue; 816 } 817 818 ufsvfsp = dqp->dq_ufsvfsp; /* shorthand */ 819 820 /* 821 * This quota info record has no changes or is 822 * not a valid quota info record yet. 823 */ 824 if ((dqp->dq_flags & DQ_MOD) == 0 || ufsvfsp == NULL) { 825 mutex_exit(&dqp->dq_lock); 826 continue; 827 } 828 829 /* 830 * Now we have a potential lock order problem: 831 * 832 * vfs_dqrwlock > dq_lock 833 * 834 * so if we have to get vfs_dqrwlock, then go thru hoops 835 * to avoid deadlock. If we cannot get the order right, 836 * then we ignore this quota info record. 837 */ 838 if (do_lock) { 839 /* 840 * If we can't grab vfs_dqrwlock, then we don't 841 * want to wait to avoid deadlock. 842 */ 843 if (rw_tryenter(&ufsvfsp->vfs_dqrwlock, 844 RW_READER) == 0) { 845 mutex_exit(&dqp->dq_lock); 846 continue; 847 } 848 /* 849 * Okay, now we have both dq_lock and vfs_dqrwlock. 850 * We should not deadlock for the following reasons: 851 * - If another thread has a reader lock on 852 * vfs_dqrwlock and is waiting for dq_lock, 853 * there is no conflict because we can also have 854 * a reader lock on vfs_dqrwlock. 855 * - If another thread has a writer lock on 856 * vfs_dqrwlock and is waiting for dq_lock, 857 * we would have failed the rw_tryenter() above 858 * and given up dq_lock. 859 * - Since we have dq_lock another thread cannot 860 * have it and be waiting for vfs_dqrwlock. 861 */ 862 } 863 864 /* 865 * Since we got to this file system via a quota info 866 * record and we have vfs_dqrwlock this is paranoia 867 * to make sure that quotas are enabled. 868 */ 869 ASSERT(ufsvfsp->vfs_qflags & MQ_ENABLED); 870 871 /* 872 * We are not logging. See above logging file system 873 * comment. 874 */ 875 if (!TRANS_ISTRANS(ufsvfsp)) { 876 dqupdate(dqp); 877 } 878 879 /* 880 * Since we have a private copy of dqp->dq_ufsvfsp, 881 * we can drop dq_lock now. 882 */ 883 mutex_exit(&dqp->dq_lock); 884 885 if (do_lock) { 886 rw_exit(&ufsvfsp->vfs_dqrwlock); 887 } 888 } 889 890 return (0); 891 } 892