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