xref: /titanic_50/usr/src/uts/common/fs/ufs/quotacalls.c (revision 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd)
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, &quot, 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, &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;
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