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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
40 #pragma ident "%Z%%M% %I% %E% SMI"
45 #include <sys/types.h>
46 #include <sys/t_lock.h>
47 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/signal.h>
56 #include <sys/vnode.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>
71 static int setquota();
72 static int getquota();
73 static int quotasync();
76 * Quota sub-system init flag.
78 int quotas_initialized
= 0;
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.
88 quotactl(struct vnode
*vp
, intptr_t arg
, int flag
, struct cred
*cr
)
91 struct ufsvfs
*ufsvfsp
;
94 if ((flag
& DATAMODEL_MASK
) == DATAMODEL_NATIVE
) {
95 if (copyin((caddr_t
)arg
, "
, sizeof (struct quotctl
)))
98 #ifdef _SYSCALL32_IMPL
100 /* quotctl struct from ILP32 callers */
101 struct quotctl32 quot32
;
102 if (copyin((caddr_t
)arg
, "32
, sizeof (struct quotctl32
)))
105 quot
.uid
= quot32
.uid
;
106 quot
.addr
= (caddr_t
)(uintptr_t)quot32
.addr
;
108 #endif /* _SYSCALL32_IMPL */
111 quot
.uid
= crgetruid(cr
);
112 if (quot
.op
== Q_SYNC
&& vp
== NULL
) {
114 } else if (quot
.op
!= Q_ALLSYNC
) {
115 ufsvfsp
= (struct ufsvfs
*)(vp
->v_vfsp
->vfs_data
);
120 rw_enter(&dq_rwlock
, RW_WRITER
);
121 if (quotas_initialized
== 0) {
123 quotas_initialized
= 1;
126 error
= opendq(ufsvfsp
, vp
, cr
);
130 error
= closedq(ufsvfsp
, cr
);
132 invalidatedq(ufsvfsp
);
138 error
= setquota(quot
.op
, (uid_t
)quot
.uid
, ufsvfsp
,
143 error
= getquota((uid_t
)quot
.uid
, ufsvfsp
, (caddr_t
)quot
.addr
,
148 error
= qsync(ufsvfsp
);
163 opendq_scan_inode(struct inode
*ip
, void *arg
)
165 struct ufsvfs
*ufsvfsp
= ip
->i_ufsvfs
;
168 * wrong file system or this is the quota inode; keep looking
170 if (ufsvfsp
!= (struct ufsvfs
*)arg
|| ip
== ip
->i_ufsvfs
->vfs_qinod
) {
174 ASSERT(RW_WRITE_HELD(&ufsvfsp
->vfs_dqrwlock
));
175 rw_enter(&ip
->i_contents
, RW_WRITER
);
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.
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
);
185 rw_exit(&ip
->i_contents
);
191 * Set the quota file up for a particular file system.
192 * Called as the result of a quotaon (Q_QUOTAON) ioctl.
196 struct ufsvfs
*ufsvfsp
,
197 struct vnode
*vp
, /* quota file */
205 if (secpolicy_fs_quota(cr
, ufsvfsp
->vfs_vfs
) != 0)
211 * Check to be sure its a regular file.
213 if (vp
->v_type
!= VREG
) {
218 rw_enter(&ufsvfsp
->vfs_dqrwlock
, RW_WRITER
);
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.
224 ASSERT((ufsvfsp
->vfs_qflags
& MQ_ENABLED
) || (ufsvfsp
->vfs_qinod
== 0));
226 if ((ufsvfsp
->vfs_qflags
& MQ_ENABLED
) != 0) {
228 * Quotas are already enabled on this file system.
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
235 * XXX - The right way to fix this is to return EBUSY
236 * for the ioctl() issued by 'quotaon'.
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
);
243 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
246 (void) quotasync(ufsvfsp
, /* do_lock */ 0);
247 /* remove extra hold on quota file */
250 qip
= ufsvfsp
->vfs_qinod
;
254 ufsvfsp
->vfs_qinod
= VTOI(vp
);
255 qip
= ufsvfsp
->vfs_qinod
;
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.
262 qlen
= qip
->i_fs
->fs_bsize
* NDADDR
;
265 * Largefiles: i_size needs to be atomically accessed now.
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
, NULL
);
276 rw_exit(&qip
->i_contents
);
278 TRANS_MATA_IGET(ufsvfsp
, qip
);
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).
287 error
= getdiskquota((uid_t
)0, ufsvfsp
, 1, &dqp
);
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
);
295 ufsvfsp
->vfs_qflags
= MQ_ENABLED
; /* enable quotas */
296 vfs_setmntopt(ufsvfsp
->vfs_vfs
, MNTOPT_QUOTA
, NULL
, 0);
298 mutex_exit(&dqp
->dq_lock
);
299 } else if (!quotaon
) {
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.
304 ufsvfsp
->vfs_qflags
= 0;
305 ufsvfsp
->vfs_qinod
= NULL
;
310 * If quotas are enabled update all valid inodes in the
311 * cache with quota information.
313 if (ufsvfsp
->vfs_qflags
& MQ_ENABLED
) {
314 (void) ufs_scan_inodes(0, opendq_scan_inode
, ufsvfsp
, ufsvfsp
);
317 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
322 closedq_scan_inode(struct inode
*ip
, void *arg
)
325 struct ufsvfs
*ufsvfsp
= ip
->i_ufsvfs
;
328 * wrong file system; keep looking
330 if (ufsvfsp
!= (struct ufsvfs
*)arg
)
333 ASSERT(RW_WRITE_HELD(&ufsvfsp
->vfs_dqrwlock
));
334 rw_enter(&ip
->i_contents
, RW_WRITER
);
337 * Shadow inodes and extended attribute directories
338 * do not have quota info records.
340 if ((dqp
= ip
->i_dquot
) != NULL
) {
341 ASSERT((ip
->i_mode
& IFMT
) != IFSHAD
);
342 ASSERT((ip
->i_mode
& IFMT
) != IFATTRDIR
);
344 mutex_enter(&dqp
->dq_lock
);
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.
356 if (dqp
->dq_flags
& DQ_TRANS
) {
357 dqp
->dq_flags
&= ~DQ_TRANS
;
360 mutex_exit(&dqp
->dq_lock
);
362 rw_exit(&ip
->i_contents
);
368 * Close off disk quotas for a file system.
371 closedq(struct ufsvfs
*ufsvfsp
, struct cred
*cr
)
375 if (secpolicy_fs_quota(cr
, ufsvfsp
->vfs_vfs
) != 0)
378 rw_enter(&ufsvfsp
->vfs_dqrwlock
, RW_WRITER
);
381 * Quotas are not enabled on this file system so there is
382 * nothing more to do.
384 if ((ufsvfsp
->vfs_qflags
& MQ_ENABLED
) == 0) {
385 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
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
394 qip
= ufsvfsp
->vfs_qinod
;
396 return (ufs_fault(ufsvfsp
->vfs_root
, "closedq: NULL qip"));
398 ufsvfsp
->vfs_qflags
= 0; /* disable quotas */
399 vfs_setmntopt(ufsvfsp
->vfs_vfs
, MNTOPT_NOQUOTA
, NULL
, 0);
402 * ufs_scan_inodes() depends on vfs_qinod, so we can't
403 * clear it until afterwards.
405 (void) ufs_scan_inodes(0, closedq_scan_inode
, ufsvfsp
, ufsvfsp
);
407 ufsvfsp
->vfs_qinod
= NULL
;
408 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
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.
415 (void) TRANS_SYNCIP(qip
, 0, I_SYNC
, TOP_SYNCIP_CLOSEDQ
);
421 * Private data between setquota() and setquota_scan_inode().
423 struct setquota_data
{
424 #define SQD_TYPE_NONE 0
425 #define SQD_TYPE_LIMIT 1
426 #define SQD_TYPE_NO_LIMIT 2
428 struct ufsvfs
*sqd_ufsvfsp
;
433 setquota_scan_inode(struct inode
*ip
, void *arg
)
435 struct setquota_data
*sqdp
= (struct setquota_data
*)arg
;
436 struct ufsvfs
*ufsvfsp
= ip
->i_ufsvfs
;
439 * wrong file system; keep looking
441 if (ufsvfsp
!= sqdp
->sqd_ufsvfsp
)
444 ASSERT(RW_WRITE_HELD(&ufsvfsp
->vfs_dqrwlock
));
447 * The file system does not have quotas enabled or this is the
448 * file system's quota inode; keep looking.
450 if ((ufsvfsp
->vfs_qflags
& MQ_ENABLED
) == 0 ||
451 ip
== ufsvfsp
->vfs_qinod
) {
455 rw_enter(&ip
->i_contents
, RW_WRITER
);
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.
461 if (ip
->i_mode
&& (ip
->i_mode
& IFMT
) != IFSHAD
&&
462 (ip
->i_mode
& IFMT
) != IFATTRDIR
&& ip
->i_uid
== sqdp
->sqd_uid
) {
464 * Transition is "no limit" to "at least one limit":
466 if (sqdp
->sqd_type
== SQD_TYPE_LIMIT
&&
467 ip
->i_dquot
== NULL
) {
468 ip
->i_dquot
= getinoquota(ip
);
471 * Transition is "at least one limit" to "no limit":
473 else if (sqdp
->sqd_type
== SQD_TYPE_NO_LIMIT
&& ip
->i_dquot
) {
474 mutex_enter(&ip
->i_dquot
->dq_lock
);
476 mutex_exit(&ip
->i_dquot
->dq_lock
);
480 rw_exit(&ip
->i_contents
);
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.
491 setquota(int cmd
, uid_t uid
, struct ufsvfs
*ufsvfsp
,
492 caddr_t addr
, struct cred
*cr
)
499 int scan_type
= SQD_TYPE_NONE
;
503 if (secpolicy_fs_quota(cr
, ufsvfsp
->vfs_vfs
) != 0)
506 rw_enter(&ufsvfsp
->vfs_dqrwlock
, RW_WRITER
);
509 * Quotas are not enabled on this file system so there is
510 * nothing more to do.
512 if ((ufsvfsp
->vfs_qflags
& MQ_ENABLED
) == 0) {
513 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
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.
523 if (copyin(addr
, (caddr_t
)&newlim
, sizeof (struct dqblk
)) != 0) {
524 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
527 error
= getdiskquota(uid
, ufsvfsp
, 0, &xdqp
);
529 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
534 * Don't change disk usage on Q_SETQLIM
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
;
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).
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
;
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
;
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
;
573 /* Either no quota or under quota, clear time limit */
574 newlim
.dqb_btimelimit
= 0;
575 dqp
->dq_flags
&= ~DQ_BLKS
;
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
;
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
;
599 /* Either no quota or under quota, clear time limit */
600 newlim
.dqb_ftimelimit
= 0;
601 dqp
->dq_flags
&= ~DQ_FILES
;
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).
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
;
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.
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
;
629 dqp
->dq_dqb
= newlim
;
630 dqp
->dq_flags
|= DQ_MOD
;
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
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
,
642 rw_exit(&qip
->i_contents
);
644 (void) VOP_PUTPAGE(ITOV(qip
), dqoff(dqp
->dq_uid
) & ~qip
->i_fs
->fs_bmask
,
645 qip
->i_fs
->fs_bsize
, B_INVAL
, kcred
, NULL
);
648 * We must set the dq_mof even if not we are not logging in case
649 * we are later remount to logging.
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
;
658 dqp
->dq_mof
= ldbtob(bn
) +
659 (offset_t
)((dqoff(dqp
->dq_uid
)) & (DEV_BSIZE
- 1));
662 dqp
->dq_flags
&= ~DQ_MOD
;
664 mutex_exit(&dqp
->dq_lock
);
666 struct setquota_data sqd
;
668 sqd
.sqd_type
= scan_type
;
669 sqd
.sqd_ufsvfsp
= ufsvfsp
;
671 (void) ufs_scan_inodes(0, setquota_scan_inode
, &sqd
, ufsvfsp
);
673 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
678 * Q_GETQUOTA - return current values in a dqblk structure.
681 getquota(uid_t uid
, struct ufsvfs
*ufsvfsp
, caddr_t addr
, cred_t
*cr
)
688 if (uid
!= crgetruid(cr
) &&
689 secpolicy_fs_quota(cr
, ufsvfsp
->vfs_vfs
) != 0)
691 rw_enter(&ufsvfsp
->vfs_dqrwlock
, RW_READER
);
692 if ((ufsvfsp
->vfs_qflags
& MQ_ENABLED
) == 0) {
693 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
696 error
= getdiskquota(uid
, ufsvfsp
, 0, &xdqp
);
698 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
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) {
707 bcopy(&dqp
->dq_dqb
, &dqb
, sizeof (struct dqblk
));
710 mutex_exit(&dqp
->dq_lock
);
711 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
712 if (error
== 0 && copyout(&dqb
, addr
, sizeof (struct dqblk
)) != 0)
718 * Q_SYNC - sync quota files to disk.
721 qsync(struct ufsvfs
*ufsvfsp
)
723 return (quotasync(ufsvfsp
, /* do_lock */ 1));
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.
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.
736 quotasync(struct ufsvfs
*ufsvfsp
, int do_lock
)
740 rw_enter(&dq_rwlock
, RW_READER
);
741 if (!quotas_initialized
) {
748 * The operation applies to a specific file system only.
752 rw_enter(&ufsvfsp
->vfs_dqrwlock
, RW_READER
);
756 * Quotas are not enabled on this file system so bail.
758 if ((ufsvfsp
->vfs_qflags
& MQ_ENABLED
) == 0) {
760 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
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.
771 if (TRANS_ISTRANS(ufsvfsp
)) {
773 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
779 * Try to sync all the quota info records for this
782 for (dqp
= dquot
; dqp
< dquotNDQUOT
; dqp
++) {
784 * If someone else has it, then ignore it.
786 if (!mutex_tryenter(&dqp
->dq_lock
)) {
791 * The quota info record is for this file system
792 * and it has changes.
794 if (dqp
->dq_ufsvfsp
== ufsvfsp
&&
795 (dqp
->dq_flags
& DQ_MOD
)) {
796 ASSERT(ufsvfsp
->vfs_qflags
& MQ_ENABLED
);
800 mutex_exit(&dqp
->dq_lock
);
803 rw_exit(&ufsvfsp
->vfs_dqrwlock
);
810 * Try to sync all the quota info records for *all* file systems
811 * for which quotas are enabled.
813 for (dqp
= dquot
; dqp
< dquotNDQUOT
; dqp
++) {
815 * If someone else has it, then ignore it.
817 if (!mutex_tryenter(&dqp
->dq_lock
)) {
821 ufsvfsp
= dqp
->dq_ufsvfsp
; /* shorthand */
824 * This quota info record has no changes or is
825 * not a valid quota info record yet.
827 if ((dqp
->dq_flags
& DQ_MOD
) == 0 || ufsvfsp
== NULL
) {
828 mutex_exit(&dqp
->dq_lock
);
833 * Now we have a potential lock order problem:
835 * vfs_dqrwlock > dq_lock
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.
843 * If we can't grab vfs_dqrwlock, then we don't
844 * want to wait to avoid deadlock.
846 if (rw_tryenter(&ufsvfsp
->vfs_dqrwlock
,
848 mutex_exit(&dqp
->dq_lock
);
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.
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.
872 ASSERT(ufsvfsp
->vfs_qflags
& MQ_ENABLED
);
875 * We are not logging. See above logging file system
878 if (!TRANS_ISTRANS(ufsvfsp
)) {
883 * Since we have a private copy of dqp->dq_ufsvfsp,
884 * we can drop dq_lock now.
886 mutex_exit(&dqp
->dq_lock
);
889 rw_exit(&ufsvfsp
->vfs_dqrwlock
);