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