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
70static int opendq();
71static int setquota();
72static int getquota();
73static int quotasync();
74
75/*
76 * Quota sub-system init flag.
77 */
78int 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*/
87int
88quotactl(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
162static int
163opendq_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 */
194static int
195opendq(
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, NULL);
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
321static int
322closedq_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 */
370int
371closedq(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 */
423struct 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
432static int
433setquota_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 */
490static int
491setquota(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, NULL);
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 */
680static int
681getquota(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 */
720int
721qsync(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 */
735int
736quotasync(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