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