remove unnecessary offset_t casts of 0
[unleashed.git] / kernel / fs / ufs / quotacalls.c
blob6da4eb4846743c4fc3729e5f85f248cb55459526
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
40 #pragma ident "%Z%%M% %I% %E% SMI"
43 * Quota system calls.
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>
70 static int opendq();
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.
86 /*ARGSUSED*/
87 int
88 quotactl(struct vnode *vp, intptr_t arg, int flag, struct cred *cr)
90 struct quotctl quot;
91 struct ufsvfs *ufsvfsp;
92 int error = 0;
94 if ((flag & DATAMODEL_MASK) == DATAMODEL_NATIVE) {
95 if (copyin((caddr_t)arg, &quot, sizeof (struct quotctl)))
96 return (EFAULT);
98 #ifdef _SYSCALL32_IMPL
99 else {
100 /* quotctl struct from ILP32 callers */
101 struct quotctl32 quot32;
102 if (copyin((caddr_t)arg, &quot32, 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;
108 #endif /* _SYSCALL32_IMPL */
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);
117 switch (quot.op) {
119 case Q_QUOTAON:
120 rw_enter(&dq_rwlock, RW_WRITER);
121 if (quotas_initialized == 0) {
122 qtinit2();
123 quotas_initialized = 1;
125 rw_exit(&dq_rwlock);
126 error = opendq(ufsvfsp, vp, cr);
127 break;
129 case Q_QUOTAOFF:
130 error = closedq(ufsvfsp, cr);
131 if (!error) {
132 invalidatedq(ufsvfsp);
134 break;
136 case Q_SETQUOTA:
137 case Q_SETQLIM:
138 error = setquota(quot.op, (uid_t)quot.uid, ufsvfsp,
139 quot.addr, cr);
140 break;
142 case Q_GETQUOTA:
143 error = getquota((uid_t)quot.uid, ufsvfsp, (caddr_t)quot.addr,
144 cr);
145 break;
147 case Q_SYNC:
148 error = qsync(ufsvfsp);
149 break;
151 case Q_ALLSYNC:
152 (void) qsync(NULL);
153 break;
155 default:
156 error = EINVAL;
157 break;
159 return (error);
162 static int
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) {
171 return (0);
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);
187 return (0);
191 * Set the quota file up for a particular file system.
192 * Called as the result of a quotaon (Q_QUOTAON) ioctl.
194 static int
195 opendq(
196 struct ufsvfs *ufsvfsp,
197 struct vnode *vp, /* quota file */
198 struct cred *cr)
200 struct inode *qip;
201 struct dquot *dqp;
202 int error;
203 int quotaon = 0;
205 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0)
206 return (EPERM);
208 VN_HOLD(vp);
211 * Check to be sure its a regular file.
213 if (vp->v_type != VREG) {
214 VN_RELE(vp);
215 return (EACCES);
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
234 * return.
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);
242 VN_RELE(vp);
243 rw_exit(&ufsvfsp->vfs_dqrwlock);
244 return (0);
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;
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, (uoff_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) fop_putpage(vp, 0, (size_t)qip->i_size,
274 B_INVAL, kcred, NULL);
275 } else {
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);
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);
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) {
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;
306 VN_RELE(ITOV(qip));
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);
318 return (error);
321 static int
322 closedq_scan_inode(struct inode *ip, void *arg)
324 struct dquot *dqp;
325 struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
328 * wrong file system; keep looking
330 if (ufsvfsp != (struct ufsvfs *)arg)
331 return (0);
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);
343 ip->i_dquot = NULL;
344 mutex_enter(&dqp->dq_lock);
345 dqput(dqp);
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;
358 dqput(dqp);
360 mutex_exit(&dqp->dq_lock);
362 rw_exit(&ip->i_contents);
364 return (0);
368 * Close off disk quotas for a file system.
371 closedq(struct ufsvfs *ufsvfsp, struct cred *cr)
373 struct inode *qip;
375 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0)
376 return (EPERM);
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);
386 return (0);
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.
394 qip = ufsvfsp->vfs_qinod;
395 if (!qip)
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);
416 VN_RELE(ITOV(qip));
417 return (0);
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
427 int sqd_type;
428 struct ufsvfs *sqd_ufsvfsp;
429 uid_t sqd_uid;
432 static int
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)
442 return (0);
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) {
452 return (0);
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);
475 dqput(ip->i_dquot);
476 mutex_exit(&ip->i_dquot->dq_lock);
477 ip->i_dquot = NULL;
480 rw_exit(&ip->i_contents);
482 return (0);
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.
490 static int
491 setquota(int cmd, uid_t uid, struct ufsvfs *ufsvfsp,
492 caddr_t addr, struct cred *cr)
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;
503 if (secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0)
504 return (EPERM);
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);
514 return (ESRCH);
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);
525 return (EFAULT);
527 error = getdiskquota(uid, ufsvfsp, 0, &xdqp);
528 if (error) {
529 rw_exit(&ufsvfsp->vfs_dqrwlock);
530 return (error);
532 dqp = xdqp;
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;
541 if (uid == 0) {
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;
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;
572 } else {
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;
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;
598 } else {
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
635 * by ufs_startio.
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, NULL, kcred);
641 rw_exit(&qip->i_contents);
643 (void) fop_putpage(ITOV(qip), dqoff(dqp->dq_uid) & ~qip->i_fs->fs_bmask,
644 qip->i_fs->fs_bsize, B_INVAL, kcred, NULL);
647 * We must set the dq_mof even if not we are not logging in case
648 * we are later remount to logging.
650 contig = 0;
651 rw_enter(&qip->i_contents, RW_WRITER);
652 error = bmap_read(qip, dqoff(dqp->dq_uid), &bn, &contig);
653 rw_exit(&qip->i_contents);
654 if (error || (bn == UFS_HOLE)) {
655 dqp->dq_mof = UFS_HOLE;
656 } else {
657 dqp->dq_mof = ldbtob(bn) +
658 (offset_t)((dqoff(dqp->dq_uid)) & (DEV_BSIZE - 1));
661 dqp->dq_flags &= ~DQ_MOD;
662 dqput(dqp);
663 mutex_exit(&dqp->dq_lock);
664 if (scan_type) {
665 struct setquota_data sqd;
667 sqd.sqd_type = scan_type;
668 sqd.sqd_ufsvfsp = ufsvfsp;
669 sqd.sqd_uid = uid;
670 (void) ufs_scan_inodes(0, setquota_scan_inode, &sqd, ufsvfsp);
672 rw_exit(&ufsvfsp->vfs_dqrwlock);
673 return (0);
677 * Q_GETQUOTA - return current values in a dqblk structure.
679 static int
680 getquota(uid_t uid, struct ufsvfs *ufsvfsp, caddr_t addr, cred_t *cr)
682 struct dquot *dqp;
683 struct dquot *xdqp;
684 struct dqblk dqb;
685 int error = 0;
687 if (uid != crgetruid(cr) &&
688 secpolicy_fs_quota(cr, ufsvfsp->vfs_vfs) != 0)
689 return (EPERM);
690 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
691 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) {
692 rw_exit(&ufsvfsp->vfs_dqrwlock);
693 return (ESRCH);
695 error = getdiskquota(uid, ufsvfsp, 0, &xdqp);
696 if (error) {
697 rw_exit(&ufsvfsp->vfs_dqrwlock);
698 return (error);
700 dqp = xdqp;
701 mutex_enter(&dqp->dq_lock);
702 if (dqp->dq_fhardlimit == 0 && dqp->dq_fsoftlimit == 0 &&
703 dqp->dq_bhardlimit == 0 && dqp->dq_bsoftlimit == 0) {
704 error = ESRCH;
705 } else {
706 bcopy(&dqp->dq_dqb, &dqb, sizeof (struct dqblk));
708 dqput(dqp);
709 mutex_exit(&dqp->dq_lock);
710 rw_exit(&ufsvfsp->vfs_dqrwlock);
711 if (error == 0 && copyout(&dqb, addr, sizeof (struct dqblk)) != 0)
712 error = EFAULT;
713 return (error);
717 * Q_SYNC - sync quota files to disk.
720 qsync(struct ufsvfs *ufsvfsp)
722 return (quotasync(ufsvfsp, /* do_lock */ 1));
726 * Sync quota information records to disk for the specified file system
727 * or all file systems with quotas if ufsvfsp == NULL. Grabs a reader
728 * lock on vfs_dqrwlock if it is needed.
730 * Currently, if ufsvfsp is NULL, then do_lock is always true, but the
731 * routine is coded to account for either do_lock value. This seemed
732 * to be the safer thing to do.
735 quotasync(struct ufsvfs *ufsvfsp, int do_lock)
737 struct dquot *dqp;
739 rw_enter(&dq_rwlock, RW_READER);
740 if (!quotas_initialized) {
741 rw_exit(&dq_rwlock);
742 return (ESRCH);
744 rw_exit(&dq_rwlock);
747 * The operation applies to a specific file system only.
749 if (ufsvfsp) {
750 if (do_lock) {
751 rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
755 * Quotas are not enabled on this file system so bail.
757 if ((ufsvfsp->vfs_qflags & MQ_ENABLED) == 0) {
758 if (do_lock) {
759 rw_exit(&ufsvfsp->vfs_dqrwlock);
761 return (ESRCH);
765 * This operation is a no-op on a logging file system because
766 * quota information is treated as metadata and is in the log.
767 * This code path treats quota information as user data which
768 * is not necessary on a logging file system.
770 if (TRANS_ISTRANS(ufsvfsp)) {
771 if (do_lock) {
772 rw_exit(&ufsvfsp->vfs_dqrwlock);
774 return (0);
778 * Try to sync all the quota info records for this
779 * file system:
781 for (dqp = dquot; dqp < dquotNDQUOT; dqp++) {
783 * If someone else has it, then ignore it.
785 if (!mutex_tryenter(&dqp->dq_lock)) {
786 continue;
790 * The quota info record is for this file system
791 * and it has changes.
793 if (dqp->dq_ufsvfsp == ufsvfsp &&
794 (dqp->dq_flags & DQ_MOD)) {
795 ASSERT(ufsvfsp->vfs_qflags & MQ_ENABLED);
796 dqupdate(dqp);
799 mutex_exit(&dqp->dq_lock);
801 if (do_lock) {
802 rw_exit(&ufsvfsp->vfs_dqrwlock);
805 return (0);
809 * Try to sync all the quota info records for *all* file systems
810 * for which quotas are enabled.
812 for (dqp = dquot; dqp < dquotNDQUOT; dqp++) {
814 * If someone else has it, then ignore it.
816 if (!mutex_tryenter(&dqp->dq_lock)) {
817 continue;
820 ufsvfsp = dqp->dq_ufsvfsp; /* shorthand */
823 * This quota info record has no changes or is
824 * not a valid quota info record yet.
826 if ((dqp->dq_flags & DQ_MOD) == 0 || ufsvfsp == NULL) {
827 mutex_exit(&dqp->dq_lock);
828 continue;
832 * Now we have a potential lock order problem:
834 * vfs_dqrwlock > dq_lock
836 * so if we have to get vfs_dqrwlock, then go thru hoops
837 * to avoid deadlock. If we cannot get the order right,
838 * then we ignore this quota info record.
840 if (do_lock) {
842 * If we can't grab vfs_dqrwlock, then we don't
843 * want to wait to avoid deadlock.
845 if (rw_tryenter(&ufsvfsp->vfs_dqrwlock,
846 RW_READER) == 0) {
847 mutex_exit(&dqp->dq_lock);
848 continue;
851 * Okay, now we have both dq_lock and vfs_dqrwlock.
852 * We should not deadlock for the following reasons:
853 * - If another thread has a reader lock on
854 * vfs_dqrwlock and is waiting for dq_lock,
855 * there is no conflict because we can also have
856 * a reader lock on vfs_dqrwlock.
857 * - If another thread has a writer lock on
858 * vfs_dqrwlock and is waiting for dq_lock,
859 * we would have failed the rw_tryenter() above
860 * and given up dq_lock.
861 * - Since we have dq_lock another thread cannot
862 * have it and be waiting for vfs_dqrwlock.
867 * Since we got to this file system via a quota info
868 * record and we have vfs_dqrwlock this is paranoia
869 * to make sure that quotas are enabled.
871 ASSERT(ufsvfsp->vfs_qflags & MQ_ENABLED);
874 * We are not logging. See above logging file system
875 * comment.
877 if (!TRANS_ISTRANS(ufsvfsp)) {
878 dqupdate(dqp);
882 * Since we have a private copy of dqp->dq_ufsvfsp,
883 * we can drop dq_lock now.
885 mutex_exit(&dqp->dq_lock);
887 if (do_lock) {
888 rw_exit(&ufsvfsp->vfs_dqrwlock);
892 return (0);