ufs_quota.c revision 271162
1/*-
2 * Copyright (c) 1982, 1986, 1990, 1993, 1995
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Robert Elz at The University of Melbourne.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	@(#)ufs_quota.c	8.5 (Berkeley) 5/20/95
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: stable/10/sys/ufs/ufs/ufs_quota.c 271162 2014-09-05 13:25:27Z kib $");
37
38#include "opt_ffs.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/endian.h>
43#include <sys/fcntl.h>
44#include <sys/kernel.h>
45#include <sys/lock.h>
46#include <sys/malloc.h>
47#include <sys/mount.h>
48#include <sys/mutex.h>
49#include <sys/namei.h>
50#include <sys/priv.h>
51#include <sys/proc.h>
52#include <sys/socket.h>
53#include <sys/stat.h>
54#include <sys/sysctl.h>
55#include <sys/vnode.h>
56
57#include <ufs/ufs/extattr.h>
58#include <ufs/ufs/quota.h>
59#include <ufs/ufs/inode.h>
60#include <ufs/ufs/ufsmount.h>
61#include <ufs/ufs/ufs_extern.h>
62
63CTASSERT(sizeof(struct dqblk64) == sizeof(struct dqhdr64));
64
65static int unprivileged_get_quota = 0;
66SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_get_quota, CTLFLAG_RW,
67    &unprivileged_get_quota, 0,
68    "Unprivileged processes may retrieve quotas for other uids and gids");
69
70static MALLOC_DEFINE(M_DQUOT, "ufs_quota", "UFS quota entries");
71
72/*
73 * Quota name to error message mapping.
74 */
75static char *quotatypes[] = INITQFNAMES;
76
77static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int, int *);
78static int chkiqchg(struct inode *, int, struct ucred *, int, int *);
79static int dqopen(struct vnode *, struct ufsmount *, int);
80static int dqget(struct vnode *,
81	u_long, struct ufsmount *, int, struct dquot **);
82static int dqsync(struct vnode *, struct dquot *);
83static int dqflush(struct vnode *);
84static int quotaoff1(struct thread *td, struct mount *mp, int type);
85static int quotaoff_inchange(struct thread *td, struct mount *mp, int type);
86
87/* conversion functions - from_to() */
88static void dqb32_dq(const struct dqblk32 *, struct dquot *);
89static void dqb64_dq(const struct dqblk64 *, struct dquot *);
90static void dq_dqb32(const struct dquot *, struct dqblk32 *);
91static void dq_dqb64(const struct dquot *, struct dqblk64 *);
92static void dqb32_dqb64(const struct dqblk32 *, struct dqblk64 *);
93static void dqb64_dqb32(const struct dqblk64 *, struct dqblk32 *);
94
95#ifdef DIAGNOSTIC
96static void dqref(struct dquot *);
97static void chkdquot(struct inode *);
98#endif
99
100/*
101 * Set up the quotas for an inode.
102 *
103 * This routine completely defines the semantics of quotas.
104 * If other criterion want to be used to establish quotas, the
105 * MAXQUOTAS value in quota.h should be increased, and the
106 * additional dquots set up here.
107 */
108int
109getinoquota(struct inode *ip)
110{
111	struct ufsmount *ump;
112	struct vnode *vp;
113	int error;
114
115	vp = ITOV(ip);
116
117	/*
118	 * Disk quotas must be turned off for system files.  Currently
119	 * snapshot and quota files.
120	 */
121	if ((vp->v_vflag & VV_SYSTEM) != 0)
122		return (0);
123	/*
124	 * XXX: Turn off quotas for files with a negative UID or GID.
125	 * This prevents the creation of 100GB+ quota files.
126	 */
127	if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
128		return (0);
129	ump = VFSTOUFS(vp->v_mount);
130	/*
131	 * Set up the user quota based on file uid.
132	 * EINVAL means that quotas are not enabled.
133	 */
134	if ((error =
135		dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) &&
136	    error != EINVAL)
137		return (error);
138	/*
139	 * Set up the group quota based on file gid.
140	 * EINVAL means that quotas are not enabled.
141	 */
142	if ((error =
143		dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) &&
144	    error != EINVAL)
145		return (error);
146	return (0);
147}
148
149/*
150 * Update disk usage, and take corrective action.
151 */
152int
153chkdq(struct inode *ip, ufs2_daddr_t change, struct ucred *cred, int flags)
154{
155	struct dquot *dq;
156	ufs2_daddr_t ncurblocks;
157	struct vnode *vp = ITOV(ip);
158	int i, error, warn, do_check;
159
160	/*
161	 * Disk quotas must be turned off for system files.  Currently
162	 * snapshot and quota files.
163	 */
164	if ((vp->v_vflag & VV_SYSTEM) != 0)
165		return (0);
166	/*
167	 * XXX: Turn off quotas for files with a negative UID or GID.
168	 * This prevents the creation of 100GB+ quota files.
169	 */
170	if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
171		return (0);
172#ifdef DIAGNOSTIC
173	if ((flags & CHOWN) == 0)
174		chkdquot(ip);
175#endif
176	if (change == 0)
177		return (0);
178	if (change < 0) {
179		for (i = 0; i < MAXQUOTAS; i++) {
180			if ((dq = ip->i_dquot[i]) == NODQUOT)
181				continue;
182			DQI_LOCK(dq);
183			DQI_WAIT(dq, PINOD+1, "chkdq1");
184			ncurblocks = dq->dq_curblocks + change;
185			if (ncurblocks >= 0)
186				dq->dq_curblocks = ncurblocks;
187			else
188				dq->dq_curblocks = 0;
189			dq->dq_flags &= ~DQ_BLKS;
190			dq->dq_flags |= DQ_MOD;
191			DQI_UNLOCK(dq);
192		}
193		return (0);
194	}
195	if ((flags & FORCE) == 0 &&
196	    priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
197		do_check = 1;
198	else
199		do_check = 0;
200	for (i = 0; i < MAXQUOTAS; i++) {
201		if ((dq = ip->i_dquot[i]) == NODQUOT)
202			continue;
203		warn = 0;
204		DQI_LOCK(dq);
205		DQI_WAIT(dq, PINOD+1, "chkdq2");
206		if (do_check) {
207			error = chkdqchg(ip, change, cred, i, &warn);
208			if (error) {
209				/*
210				 * Roll back user quota changes when
211				 * group quota failed.
212				 */
213				while (i > 0) {
214					--i;
215					dq = ip->i_dquot[i];
216					if (dq == NODQUOT)
217						continue;
218					DQI_LOCK(dq);
219					DQI_WAIT(dq, PINOD+1, "chkdq3");
220					ncurblocks = dq->dq_curblocks - change;
221					if (ncurblocks >= 0)
222						dq->dq_curblocks = ncurblocks;
223					else
224						dq->dq_curblocks = 0;
225					dq->dq_flags &= ~DQ_BLKS;
226					dq->dq_flags |= DQ_MOD;
227					DQI_UNLOCK(dq);
228				}
229				return (error);
230			}
231		}
232		/* Reset timer when crossing soft limit */
233		if (dq->dq_curblocks + change >= dq->dq_bsoftlimit &&
234		    dq->dq_curblocks < dq->dq_bsoftlimit)
235			dq->dq_btime = time_second + ip->i_ump->um_btime[i];
236		dq->dq_curblocks += change;
237		dq->dq_flags |= DQ_MOD;
238		DQI_UNLOCK(dq);
239		if (warn)
240			uprintf("\n%s: warning, %s disk quota exceeded\n",
241			    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
242			    quotatypes[i]);
243	}
244	return (0);
245}
246
247/*
248 * Check for a valid change to a users allocation.
249 * Issue an error message if appropriate.
250 */
251static int
252chkdqchg(struct inode *ip, ufs2_daddr_t change, struct ucred *cred,
253    int type, int *warn)
254{
255	struct dquot *dq = ip->i_dquot[type];
256	ufs2_daddr_t ncurblocks = dq->dq_curblocks + change;
257
258	/*
259	 * If user would exceed their hard limit, disallow space allocation.
260	 */
261	if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
262		if ((dq->dq_flags & DQ_BLKS) == 0 &&
263		    ip->i_uid == cred->cr_uid) {
264			dq->dq_flags |= DQ_BLKS;
265			DQI_UNLOCK(dq);
266			uprintf("\n%s: write failed, %s disk limit reached\n",
267			    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
268			    quotatypes[type]);
269			return (EDQUOT);
270		}
271		DQI_UNLOCK(dq);
272		return (EDQUOT);
273	}
274	/*
275	 * If user is over their soft limit for too long, disallow space
276	 * allocation. Reset time limit as they cross their soft limit.
277	 */
278	if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
279		if (dq->dq_curblocks < dq->dq_bsoftlimit) {
280			dq->dq_btime = time_second + ip->i_ump->um_btime[type];
281			if (ip->i_uid == cred->cr_uid)
282				*warn = 1;
283			return (0);
284		}
285		if (time_second > dq->dq_btime) {
286			if ((dq->dq_flags & DQ_BLKS) == 0 &&
287			    ip->i_uid == cred->cr_uid) {
288				dq->dq_flags |= DQ_BLKS;
289				DQI_UNLOCK(dq);
290				uprintf("\n%s: write failed, %s "
291				    "disk quota exceeded for too long\n",
292				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
293				    quotatypes[type]);
294				return (EDQUOT);
295			}
296			DQI_UNLOCK(dq);
297			return (EDQUOT);
298		}
299	}
300	return (0);
301}
302
303/*
304 * Check the inode limit, applying corrective action.
305 */
306int
307chkiq(struct inode *ip, int change, struct ucred *cred, int flags)
308{
309	struct dquot *dq;
310	int i, error, warn, do_check;
311
312#ifdef DIAGNOSTIC
313	if ((flags & CHOWN) == 0)
314		chkdquot(ip);
315#endif
316	if (change == 0)
317		return (0);
318	if (change < 0) {
319		for (i = 0; i < MAXQUOTAS; i++) {
320			if ((dq = ip->i_dquot[i]) == NODQUOT)
321				continue;
322			DQI_LOCK(dq);
323			DQI_WAIT(dq, PINOD+1, "chkiq1");
324			if (dq->dq_curinodes >= -change)
325				dq->dq_curinodes += change;
326			else
327				dq->dq_curinodes = 0;
328			dq->dq_flags &= ~DQ_INODS;
329			dq->dq_flags |= DQ_MOD;
330			DQI_UNLOCK(dq);
331		}
332		return (0);
333	}
334	if ((flags & FORCE) == 0 &&
335	    priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
336		do_check = 1;
337	else
338		do_check = 0;
339	for (i = 0; i < MAXQUOTAS; i++) {
340		if ((dq = ip->i_dquot[i]) == NODQUOT)
341			continue;
342		warn = 0;
343		DQI_LOCK(dq);
344		DQI_WAIT(dq, PINOD+1, "chkiq2");
345		if (do_check) {
346			error = chkiqchg(ip, change, cred, i, &warn);
347			if (error) {
348				/*
349				 * Roll back user quota changes when
350				 * group quota failed.
351				 */
352				while (i > 0) {
353					--i;
354					dq = ip->i_dquot[i];
355					if (dq == NODQUOT)
356						continue;
357					DQI_LOCK(dq);
358					DQI_WAIT(dq, PINOD+1, "chkiq3");
359					if (dq->dq_curinodes >= change)
360						dq->dq_curinodes -= change;
361					else
362						dq->dq_curinodes = 0;
363					dq->dq_flags &= ~DQ_INODS;
364					dq->dq_flags |= DQ_MOD;
365					DQI_UNLOCK(dq);
366				}
367				return (error);
368			}
369		}
370		/* Reset timer when crossing soft limit */
371		if (dq->dq_curinodes + change >= dq->dq_isoftlimit &&
372		    dq->dq_curinodes < dq->dq_isoftlimit)
373			dq->dq_itime = time_second + ip->i_ump->um_itime[i];
374		dq->dq_curinodes += change;
375		dq->dq_flags |= DQ_MOD;
376		DQI_UNLOCK(dq);
377		if (warn)
378			uprintf("\n%s: warning, %s inode quota exceeded\n",
379			    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
380			    quotatypes[i]);
381	}
382	return (0);
383}
384
385/*
386 * Check for a valid change to a users allocation.
387 * Issue an error message if appropriate.
388 */
389static int
390chkiqchg(struct inode *ip, int change, struct ucred *cred, int type, int *warn)
391{
392	struct dquot *dq = ip->i_dquot[type];
393	ino_t ncurinodes = dq->dq_curinodes + change;
394
395	/*
396	 * If user would exceed their hard limit, disallow inode allocation.
397	 */
398	if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
399		if ((dq->dq_flags & DQ_INODS) == 0 &&
400		    ip->i_uid == cred->cr_uid) {
401			dq->dq_flags |= DQ_INODS;
402			DQI_UNLOCK(dq);
403			uprintf("\n%s: write failed, %s inode limit reached\n",
404			    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
405			    quotatypes[type]);
406			return (EDQUOT);
407		}
408		DQI_UNLOCK(dq);
409		return (EDQUOT);
410	}
411	/*
412	 * If user is over their soft limit for too long, disallow inode
413	 * allocation. Reset time limit as they cross their soft limit.
414	 */
415	if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
416		if (dq->dq_curinodes < dq->dq_isoftlimit) {
417			dq->dq_itime = time_second + ip->i_ump->um_itime[type];
418			if (ip->i_uid == cred->cr_uid)
419				*warn = 1;
420			return (0);
421		}
422		if (time_second > dq->dq_itime) {
423			if ((dq->dq_flags & DQ_INODS) == 0 &&
424			    ip->i_uid == cred->cr_uid) {
425				dq->dq_flags |= DQ_INODS;
426				DQI_UNLOCK(dq);
427				uprintf("\n%s: write failed, %s "
428				    "inode quota exceeded for too long\n",
429				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
430				    quotatypes[type]);
431				return (EDQUOT);
432			}
433			DQI_UNLOCK(dq);
434			return (EDQUOT);
435		}
436	}
437	return (0);
438}
439
440#ifdef DIAGNOSTIC
441/*
442 * On filesystems with quotas enabled, it is an error for a file to change
443 * size and not to have a dquot structure associated with it.
444 */
445static void
446chkdquot(struct inode *ip)
447{
448	struct ufsmount *ump = ip->i_ump;
449	struct vnode *vp = ITOV(ip);
450	int i;
451
452	/*
453	 * Disk quotas must be turned off for system files.  Currently
454	 * these are snapshots and quota files.
455	 */
456	if ((vp->v_vflag & VV_SYSTEM) != 0)
457		return;
458	/*
459	 * XXX: Turn off quotas for files with a negative UID or GID.
460	 * This prevents the creation of 100GB+ quota files.
461	 */
462	if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
463		return;
464
465	UFS_LOCK(ump);
466	for (i = 0; i < MAXQUOTAS; i++) {
467		if (ump->um_quotas[i] == NULLVP ||
468		    (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
469			continue;
470		if (ip->i_dquot[i] == NODQUOT) {
471			UFS_UNLOCK(ump);
472			vprint("chkdquot: missing dquot", ITOV(ip));
473			panic("chkdquot: missing dquot");
474		}
475	}
476	UFS_UNLOCK(ump);
477}
478#endif
479
480/*
481 * Code to process quotactl commands.
482 */
483
484/*
485 * Q_QUOTAON - set up a quota file for a particular filesystem.
486 */
487int
488quotaon(struct thread *td, struct mount *mp, int type, void *fname)
489{
490	struct ufsmount *ump;
491	struct vnode *vp, **vpp;
492	struct vnode *mvp;
493	struct dquot *dq;
494	int error, flags;
495	struct nameidata nd;
496
497	error = priv_check(td, PRIV_UFS_QUOTAON);
498	if (error)
499		return (error);
500
501	if (mp->mnt_flag & MNT_RDONLY)
502		return (EROFS);
503
504	ump = VFSTOUFS(mp);
505	dq = NODQUOT;
506
507	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname, td);
508	flags = FREAD | FWRITE;
509	vfs_ref(mp);
510	vfs_unbusy(mp);
511	error = vn_open(&nd, &flags, 0, NULL);
512	if (error != 0) {
513		vfs_rel(mp);
514		return (error);
515	}
516	NDFREE(&nd, NDF_ONLY_PNBUF);
517	vp = nd.ni_vp;
518	error = vfs_busy(mp, MBF_NOWAIT);
519	vfs_rel(mp);
520	if (error == 0) {
521		if (vp->v_type != VREG) {
522			error = EACCES;
523			vfs_unbusy(mp);
524		}
525	}
526	if (error != 0) {
527		VOP_UNLOCK(vp, 0);
528		(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
529		return (error);
530	}
531
532	UFS_LOCK(ump);
533	if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) {
534		UFS_UNLOCK(ump);
535		VOP_UNLOCK(vp, 0);
536		(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
537		vfs_unbusy(mp);
538		return (EALREADY);
539	}
540	ump->um_qflags[type] |= QTF_OPENING|QTF_CLOSING;
541	UFS_UNLOCK(ump);
542	if ((error = dqopen(vp, ump, type)) != 0) {
543		VOP_UNLOCK(vp, 0);
544		UFS_LOCK(ump);
545		ump->um_qflags[type] &= ~(QTF_OPENING|QTF_CLOSING);
546		UFS_UNLOCK(ump);
547		(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
548		vfs_unbusy(mp);
549		return (error);
550	}
551	VOP_UNLOCK(vp, 0);
552	MNT_ILOCK(mp);
553	mp->mnt_flag |= MNT_QUOTA;
554	MNT_IUNLOCK(mp);
555
556	vpp = &ump->um_quotas[type];
557	if (*vpp != vp)
558		quotaoff1(td, mp, type);
559
560	/*
561	 * When the directory vnode containing the quota file is
562	 * inactivated, due to the shared lookup of the quota file
563	 * vput()ing the dvp, the qsyncvp() call for the containing
564	 * directory would try to acquire the quota lock exclusive.
565	 * At the same time, lookup already locked the quota vnode
566	 * shared.  Mark the quota vnode lock as allowing recursion
567	 * and automatically converting shared locks to exclusive.
568	 *
569	 * Also mark quota vnode as system.
570	 */
571	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
572	vp->v_vflag |= VV_SYSTEM;
573	VN_LOCK_AREC(vp);
574	VN_LOCK_DSHARE(vp);
575	VOP_UNLOCK(vp, 0);
576	*vpp = vp;
577	/*
578	 * Save the credential of the process that turned on quotas.
579	 * Set up the time limits for this quota.
580	 */
581	ump->um_cred[type] = crhold(td->td_ucred);
582	ump->um_btime[type] = MAX_DQ_TIME;
583	ump->um_itime[type] = MAX_IQ_TIME;
584	if (dqget(NULLVP, 0, ump, type, &dq) == 0) {
585		if (dq->dq_btime > 0)
586			ump->um_btime[type] = dq->dq_btime;
587		if (dq->dq_itime > 0)
588			ump->um_itime[type] = dq->dq_itime;
589		dqrele(NULLVP, dq);
590	}
591	/*
592	 * Allow the getdq from getinoquota below to read the quota
593	 * from file.
594	 */
595	UFS_LOCK(ump);
596	ump->um_qflags[type] &= ~QTF_CLOSING;
597	UFS_UNLOCK(ump);
598	/*
599	 * Search vnodes associated with this mount point,
600	 * adding references to quota file being opened.
601	 * NB: only need to add dquot's for inodes being modified.
602	 */
603again:
604	MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
605		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
606			MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
607			goto again;
608		}
609		if (vp->v_type == VNON || vp->v_writecount == 0) {
610			VOP_UNLOCK(vp, 0);
611			vrele(vp);
612			continue;
613		}
614		error = getinoquota(VTOI(vp));
615		VOP_UNLOCK(vp, 0);
616		vrele(vp);
617		if (error) {
618			MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
619			break;
620		}
621	}
622
623        if (error)
624		quotaoff_inchange(td, mp, type);
625	UFS_LOCK(ump);
626	ump->um_qflags[type] &= ~QTF_OPENING;
627	KASSERT((ump->um_qflags[type] & QTF_CLOSING) == 0,
628		("quotaon: leaking flags"));
629	UFS_UNLOCK(ump);
630
631	vfs_unbusy(mp);
632	return (error);
633}
634
635/*
636 * Main code to turn off disk quotas for a filesystem. Does not change
637 * flags.
638 */
639static int
640quotaoff1(struct thread *td, struct mount *mp, int type)
641{
642	struct vnode *vp;
643	struct vnode *qvp, *mvp;
644	struct ufsmount *ump;
645	struct dquot *dq;
646	struct inode *ip;
647	struct ucred *cr;
648	int error;
649
650	ump = VFSTOUFS(mp);
651
652	UFS_LOCK(ump);
653	KASSERT((ump->um_qflags[type] & QTF_CLOSING) != 0,
654		("quotaoff1: flags are invalid"));
655	if ((qvp = ump->um_quotas[type]) == NULLVP) {
656		UFS_UNLOCK(ump);
657		return (0);
658	}
659	cr = ump->um_cred[type];
660	UFS_UNLOCK(ump);
661
662	/*
663	 * Search vnodes associated with this mount point,
664	 * deleting any references to quota file being closed.
665	 */
666again:
667	MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
668		if (vp->v_type == VNON) {
669			VI_UNLOCK(vp);
670			continue;
671		}
672		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
673			MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
674			goto again;
675		}
676		ip = VTOI(vp);
677		dq = ip->i_dquot[type];
678		ip->i_dquot[type] = NODQUOT;
679		dqrele(vp, dq);
680		VOP_UNLOCK(vp, 0);
681		vrele(vp);
682	}
683
684	error = dqflush(qvp);
685	if (error != 0)
686		return (error);
687
688	/*
689	 * Clear um_quotas before closing the quota vnode to prevent
690	 * access to the closed vnode from dqget/dqsync
691	 */
692	UFS_LOCK(ump);
693	ump->um_quotas[type] = NULLVP;
694	ump->um_cred[type] = NOCRED;
695	UFS_UNLOCK(ump);
696
697	vn_lock(qvp, LK_EXCLUSIVE | LK_RETRY);
698	qvp->v_vflag &= ~VV_SYSTEM;
699	VOP_UNLOCK(qvp, 0);
700	error = vn_close(qvp, FREAD|FWRITE, td->td_ucred, td);
701	crfree(cr);
702
703	return (error);
704}
705
706/*
707 * Turns off quotas, assumes that ump->um_qflags are already checked
708 * and QTF_CLOSING is set to indicate operation in progress. Fixes
709 * ump->um_qflags and mp->mnt_flag after.
710 */
711int
712quotaoff_inchange(struct thread *td, struct mount *mp, int type)
713{
714	struct ufsmount *ump;
715	int i;
716	int error;
717
718	error = quotaoff1(td, mp, type);
719
720	ump = VFSTOUFS(mp);
721	UFS_LOCK(ump);
722	ump->um_qflags[type] &= ~QTF_CLOSING;
723	for (i = 0; i < MAXQUOTAS; i++)
724		if (ump->um_quotas[i] != NULLVP)
725			break;
726	if (i == MAXQUOTAS) {
727		MNT_ILOCK(mp);
728		mp->mnt_flag &= ~MNT_QUOTA;
729		MNT_IUNLOCK(mp);
730	}
731	UFS_UNLOCK(ump);
732	return (error);
733}
734
735/*
736 * Q_QUOTAOFF - turn off disk quotas for a filesystem.
737 */
738int
739quotaoff(struct thread *td, struct mount *mp, int type)
740{
741	struct ufsmount *ump;
742	int error;
743
744	error = priv_check(td, PRIV_UFS_QUOTAOFF);
745	if (error)
746		return (error);
747
748	ump = VFSTOUFS(mp);
749	UFS_LOCK(ump);
750	if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) {
751		UFS_UNLOCK(ump);
752		return (EALREADY);
753	}
754	ump->um_qflags[type] |= QTF_CLOSING;
755	UFS_UNLOCK(ump);
756
757	return (quotaoff_inchange(td, mp, type));
758}
759
760/*
761 * Q_GETQUOTA - return current values in a dqblk structure.
762 */
763static int
764_getquota(struct thread *td, struct mount *mp, u_long id, int type,
765    struct dqblk64 *dqb)
766{
767	struct dquot *dq;
768	int error;
769
770	switch (type) {
771	case USRQUOTA:
772		if ((td->td_ucred->cr_uid != id) && !unprivileged_get_quota) {
773			error = priv_check(td, PRIV_VFS_GETQUOTA);
774			if (error)
775				return (error);
776		}
777		break;
778
779	case GRPQUOTA:
780		if (!groupmember(id, td->td_ucred) &&
781		    !unprivileged_get_quota) {
782			error = priv_check(td, PRIV_VFS_GETQUOTA);
783			if (error)
784				return (error);
785		}
786		break;
787
788	default:
789		return (EINVAL);
790	}
791
792	dq = NODQUOT;
793	error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq);
794	if (error)
795		return (error);
796	*dqb = dq->dq_dqb;
797	dqrele(NULLVP, dq);
798	return (error);
799}
800
801/*
802 * Q_SETQUOTA - assign an entire dqblk structure.
803 */
804static int
805_setquota(struct thread *td, struct mount *mp, u_long id, int type,
806    struct dqblk64 *dqb)
807{
808	struct dquot *dq;
809	struct dquot *ndq;
810	struct ufsmount *ump;
811	struct dqblk64 newlim;
812	int error;
813
814	error = priv_check(td, PRIV_VFS_SETQUOTA);
815	if (error)
816		return (error);
817
818	newlim = *dqb;
819
820	ndq = NODQUOT;
821	ump = VFSTOUFS(mp);
822
823	error = dqget(NULLVP, id, ump, type, &ndq);
824	if (error)
825		return (error);
826	dq = ndq;
827	DQI_LOCK(dq);
828	DQI_WAIT(dq, PINOD+1, "setqta");
829	/*
830	 * Copy all but the current values.
831	 * Reset time limit if previously had no soft limit or were
832	 * under it, but now have a soft limit and are over it.
833	 */
834	newlim.dqb_curblocks = dq->dq_curblocks;
835	newlim.dqb_curinodes = dq->dq_curinodes;
836	if (dq->dq_id != 0) {
837		newlim.dqb_btime = dq->dq_btime;
838		newlim.dqb_itime = dq->dq_itime;
839	}
840	if (newlim.dqb_bsoftlimit &&
841	    dq->dq_curblocks >= newlim.dqb_bsoftlimit &&
842	    (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
843		newlim.dqb_btime = time_second + ump->um_btime[type];
844	if (newlim.dqb_isoftlimit &&
845	    dq->dq_curinodes >= newlim.dqb_isoftlimit &&
846	    (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
847		newlim.dqb_itime = time_second + ump->um_itime[type];
848	dq->dq_dqb = newlim;
849	if (dq->dq_curblocks < dq->dq_bsoftlimit)
850		dq->dq_flags &= ~DQ_BLKS;
851	if (dq->dq_curinodes < dq->dq_isoftlimit)
852		dq->dq_flags &= ~DQ_INODS;
853	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
854	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
855		dq->dq_flags |= DQ_FAKE;
856	else
857		dq->dq_flags &= ~DQ_FAKE;
858	dq->dq_flags |= DQ_MOD;
859	DQI_UNLOCK(dq);
860	dqrele(NULLVP, dq);
861	return (0);
862}
863
864/*
865 * Q_SETUSE - set current inode and block usage.
866 */
867static int
868_setuse(struct thread *td, struct mount *mp, u_long id, int type,
869    struct dqblk64 *dqb)
870{
871	struct dquot *dq;
872	struct ufsmount *ump;
873	struct dquot *ndq;
874	struct dqblk64 usage;
875	int error;
876
877	error = priv_check(td, PRIV_UFS_SETUSE);
878	if (error)
879		return (error);
880
881	usage = *dqb;
882
883	ump = VFSTOUFS(mp);
884	ndq = NODQUOT;
885
886	error = dqget(NULLVP, id, ump, type, &ndq);
887	if (error)
888		return (error);
889	dq = ndq;
890	DQI_LOCK(dq);
891	DQI_WAIT(dq, PINOD+1, "setuse");
892	/*
893	 * Reset time limit if have a soft limit and were
894	 * previously under it, but are now over it.
895	 */
896	if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
897	    usage.dqb_curblocks >= dq->dq_bsoftlimit)
898		dq->dq_btime = time_second + ump->um_btime[type];
899	if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
900	    usage.dqb_curinodes >= dq->dq_isoftlimit)
901		dq->dq_itime = time_second + ump->um_itime[type];
902	dq->dq_curblocks = usage.dqb_curblocks;
903	dq->dq_curinodes = usage.dqb_curinodes;
904	if (dq->dq_curblocks < dq->dq_bsoftlimit)
905		dq->dq_flags &= ~DQ_BLKS;
906	if (dq->dq_curinodes < dq->dq_isoftlimit)
907		dq->dq_flags &= ~DQ_INODS;
908	dq->dq_flags |= DQ_MOD;
909	DQI_UNLOCK(dq);
910	dqrele(NULLVP, dq);
911	return (0);
912}
913
914int
915getquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
916{
917	struct dqblk32 dqb32;
918	struct dqblk64 dqb64;
919	int error;
920
921	error = _getquota(td, mp, id, type, &dqb64);
922	if (error)
923		return (error);
924	dqb64_dqb32(&dqb64, &dqb32);
925	error = copyout(&dqb32, addr, sizeof(dqb32));
926	return (error);
927}
928
929int
930setquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
931{
932	struct dqblk32 dqb32;
933	struct dqblk64 dqb64;
934	int error;
935
936	error = copyin(addr, &dqb32, sizeof(dqb32));
937	if (error)
938		return (error);
939	dqb32_dqb64(&dqb32, &dqb64);
940	error = _setquota(td, mp, id, type, &dqb64);
941	return (error);
942}
943
944int
945setuse32(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
946{
947	struct dqblk32 dqb32;
948	struct dqblk64 dqb64;
949	int error;
950
951	error = copyin(addr, &dqb32, sizeof(dqb32));
952	if (error)
953		return (error);
954	dqb32_dqb64(&dqb32, &dqb64);
955	error = _setuse(td, mp, id, type, &dqb64);
956	return (error);
957}
958
959int
960getquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
961{
962	struct dqblk64 dqb64;
963	int error;
964
965	error = _getquota(td, mp, id, type, &dqb64);
966	if (error)
967		return (error);
968	error = copyout(&dqb64, addr, sizeof(dqb64));
969	return (error);
970}
971
972int
973setquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
974{
975	struct dqblk64 dqb64;
976	int error;
977
978	error = copyin(addr, &dqb64, sizeof(dqb64));
979	if (error)
980		return (error);
981	error = _setquota(td, mp, id, type, &dqb64);
982	return (error);
983}
984
985int
986setuse(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
987{
988	struct dqblk64 dqb64;
989	int error;
990
991	error = copyin(addr, &dqb64, sizeof(dqb64));
992	if (error)
993		return (error);
994	error = _setuse(td, mp, id, type, &dqb64);
995	return (error);
996}
997
998/*
999 * Q_GETQUOTASIZE - get bit-size of quota file fields
1000 */
1001int
1002getquotasize(struct thread *td, struct mount *mp, u_long id, int type,
1003    void *sizep)
1004{
1005	struct ufsmount *ump = VFSTOUFS(mp);
1006	int bitsize;
1007
1008	UFS_LOCK(ump);
1009	if (ump->um_quotas[type] == NULLVP ||
1010	    (ump->um_qflags[type] & QTF_CLOSING)) {
1011		UFS_UNLOCK(ump);
1012		return (EINVAL);
1013	}
1014	if ((ump->um_qflags[type] & QTF_64BIT) != 0)
1015		bitsize = 64;
1016	else
1017		bitsize = 32;
1018	UFS_UNLOCK(ump);
1019	return (copyout(&bitsize, sizep, sizeof(int)));
1020}
1021
1022/*
1023 * Q_SYNC - sync quota files to disk.
1024 */
1025int
1026qsync(struct mount *mp)
1027{
1028	struct ufsmount *ump = VFSTOUFS(mp);
1029	struct thread *td = curthread;		/* XXX */
1030	struct vnode *vp, *mvp;
1031	struct dquot *dq;
1032	int i, error;
1033
1034	/*
1035	 * Check if the mount point has any quotas.
1036	 * If not, simply return.
1037	 */
1038	UFS_LOCK(ump);
1039	for (i = 0; i < MAXQUOTAS; i++)
1040		if (ump->um_quotas[i] != NULLVP)
1041			break;
1042	UFS_UNLOCK(ump);
1043	if (i == MAXQUOTAS)
1044		return (0);
1045	/*
1046	 * Search vnodes associated with this mount point,
1047	 * synchronizing any modified dquot structures.
1048	 */
1049again:
1050	MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
1051		if (vp->v_type == VNON) {
1052			VI_UNLOCK(vp);
1053			continue;
1054		}
1055		error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td);
1056		if (error) {
1057			if (error == ENOENT) {
1058				MNT_VNODE_FOREACH_ACTIVE_ABORT(mp, mvp);
1059				goto again;
1060			}
1061			continue;
1062		}
1063		for (i = 0; i < MAXQUOTAS; i++) {
1064			dq = VTOI(vp)->i_dquot[i];
1065			if (dq != NODQUOT)
1066				dqsync(vp, dq);
1067		}
1068		vput(vp);
1069	}
1070	return (0);
1071}
1072
1073/*
1074 * Sync quota file for given vnode to disk.
1075 */
1076int
1077qsyncvp(struct vnode *vp)
1078{
1079	struct ufsmount *ump = VFSTOUFS(vp->v_mount);
1080	struct dquot *dq;
1081	int i;
1082
1083	/*
1084	 * Check if the mount point has any quotas.
1085	 * If not, simply return.
1086	 */
1087	UFS_LOCK(ump);
1088	for (i = 0; i < MAXQUOTAS; i++)
1089		if (ump->um_quotas[i] != NULLVP)
1090			break;
1091	UFS_UNLOCK(ump);
1092	if (i == MAXQUOTAS)
1093		return (0);
1094	/*
1095	 * Search quotas associated with this vnode
1096	 * synchronizing any modified dquot structures.
1097	 */
1098	for (i = 0; i < MAXQUOTAS; i++) {
1099		dq = VTOI(vp)->i_dquot[i];
1100		if (dq != NODQUOT)
1101			dqsync(vp, dq);
1102	}
1103	return (0);
1104}
1105
1106/*
1107 * Code pertaining to management of the in-core dquot data structures.
1108 */
1109#define DQHASH(dqvp, id) \
1110	(&dqhashtbl[((((intptr_t)(dqvp)) >> 8) + id) & dqhash])
1111static LIST_HEAD(dqhash, dquot) *dqhashtbl;
1112static u_long dqhash;
1113
1114/*
1115 * Dquot free list.
1116 */
1117#define	DQUOTINC	5	/* minimum free dquots desired */
1118static TAILQ_HEAD(dqfreelist, dquot) dqfreelist;
1119static long numdquot, desireddquot = DQUOTINC;
1120
1121/*
1122 * Lock to protect quota hash, dq free list and dq_cnt ref counters of
1123 * _all_ dqs.
1124 */
1125struct mtx dqhlock;
1126
1127#define	DQH_LOCK()	mtx_lock(&dqhlock)
1128#define	DQH_UNLOCK()	mtx_unlock(&dqhlock)
1129
1130static struct dquot *dqhashfind(struct dqhash *dqh, u_long id,
1131	struct vnode *dqvp);
1132
1133/*
1134 * Initialize the quota system.
1135 */
1136void
1137dqinit(void)
1138{
1139
1140	mtx_init(&dqhlock, "dqhlock", NULL, MTX_DEF);
1141	dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash);
1142	TAILQ_INIT(&dqfreelist);
1143}
1144
1145/*
1146 * Shut down the quota system.
1147 */
1148void
1149dquninit(void)
1150{
1151	struct dquot *dq;
1152
1153	hashdestroy(dqhashtbl, M_DQUOT, dqhash);
1154	while ((dq = TAILQ_FIRST(&dqfreelist)) != NULL) {
1155		TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
1156		mtx_destroy(&dq->dq_lock);
1157		free(dq, M_DQUOT);
1158	}
1159	mtx_destroy(&dqhlock);
1160}
1161
1162static struct dquot *
1163dqhashfind(struct dqhash *dqh, u_long id, struct vnode *dqvp)
1164{
1165	struct dquot *dq;
1166
1167	mtx_assert(&dqhlock, MA_OWNED);
1168	LIST_FOREACH(dq, dqh, dq_hash) {
1169		if (dq->dq_id != id ||
1170		    dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
1171			continue;
1172		/*
1173		 * Cache hit with no references.  Take
1174		 * the structure off the free list.
1175		 */
1176		if (dq->dq_cnt == 0)
1177			TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
1178		DQREF(dq);
1179		return (dq);
1180	}
1181	return (NODQUOT);
1182}
1183
1184/*
1185 * Determine the quota file type.
1186 *
1187 * A 32-bit quota file is simply an array of struct dqblk32.
1188 *
1189 * A 64-bit quota file is a struct dqhdr64 followed by an array of struct
1190 * dqblk64.  The header contains various magic bits which allow us to be
1191 * reasonably confident that it is indeeda 64-bit quota file and not just
1192 * a 32-bit quota file that just happens to "look right".
1193 *
1194 */
1195static int
1196dqopen(struct vnode *vp, struct ufsmount *ump, int type)
1197{
1198	struct dqhdr64 dqh;
1199	struct iovec aiov;
1200	struct uio auio;
1201	int error;
1202
1203	ASSERT_VOP_LOCKED(vp, "dqopen");
1204	auio.uio_iov = &aiov;
1205	auio.uio_iovcnt = 1;
1206	aiov.iov_base = &dqh;
1207	aiov.iov_len = sizeof(dqh);
1208	auio.uio_resid = sizeof(dqh);
1209	auio.uio_offset = 0;
1210	auio.uio_segflg = UIO_SYSSPACE;
1211	auio.uio_rw = UIO_READ;
1212	auio.uio_td = (struct thread *)0;
1213	error = VOP_READ(vp, &auio, 0, ump->um_cred[type]);
1214
1215	if (error != 0)
1216		return (error);
1217	if (auio.uio_resid > 0) {
1218		/* assume 32 bits */
1219		return (0);
1220	}
1221
1222	UFS_LOCK(ump);
1223	if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) == 0 &&
1224	    be32toh(dqh.dqh_version) == Q_DQHDR64_VERSION &&
1225	    be32toh(dqh.dqh_hdrlen) == (uint32_t)sizeof(struct dqhdr64) &&
1226	    be32toh(dqh.dqh_reclen) == (uint32_t)sizeof(struct dqblk64)) {
1227		/* XXX: what if the magic matches, but the sizes are wrong? */
1228		ump->um_qflags[type] |= QTF_64BIT;
1229	} else {
1230		ump->um_qflags[type] &= ~QTF_64BIT;
1231	}
1232	UFS_UNLOCK(ump);
1233
1234	return (0);
1235}
1236
1237/*
1238 * Obtain a dquot structure for the specified identifier and quota file
1239 * reading the information from the file if necessary.
1240 */
1241static int
1242dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
1243    struct dquot **dqp)
1244{
1245	uint8_t buf[sizeof(struct dqblk64)];
1246	off_t base, recsize;
1247	struct dquot *dq, *dq1;
1248	struct dqhash *dqh;
1249	struct vnode *dqvp;
1250	struct iovec aiov;
1251	struct uio auio;
1252	int dqvplocked, error;
1253
1254#ifdef DEBUG_VFS_LOCKS
1255	if (vp != NULLVP)
1256		ASSERT_VOP_ELOCKED(vp, "dqget");
1257#endif
1258
1259	if (vp != NULLVP && *dqp != NODQUOT) {
1260		return (0);
1261	}
1262
1263	/* XXX: Disallow negative id values to prevent the
1264	* creation of 100GB+ quota data files.
1265	*/
1266	if ((int)id < 0)
1267		return (EINVAL);
1268
1269	UFS_LOCK(ump);
1270	dqvp = ump->um_quotas[type];
1271	if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
1272		*dqp = NODQUOT;
1273		UFS_UNLOCK(ump);
1274		return (EINVAL);
1275	}
1276	vref(dqvp);
1277	UFS_UNLOCK(ump);
1278	error = 0;
1279	dqvplocked = 0;
1280
1281	/*
1282	 * Check the cache first.
1283	 */
1284	dqh = DQHASH(dqvp, id);
1285	DQH_LOCK();
1286	dq = dqhashfind(dqh, id, dqvp);
1287	if (dq != NULL) {
1288		DQH_UNLOCK();
1289hfound:		DQI_LOCK(dq);
1290		DQI_WAIT(dq, PINOD+1, "dqget");
1291		DQI_UNLOCK(dq);
1292		if (dq->dq_ump == NULL) {
1293			dqrele(vp, dq);
1294			dq = NODQUOT;
1295			error = EIO;
1296		}
1297		*dqp = dq;
1298		if (dqvplocked)
1299			vput(dqvp);
1300		else
1301			vrele(dqvp);
1302		return (error);
1303	}
1304
1305	/*
1306	 * Quota vnode lock is before DQ_LOCK. Acquire dqvp lock there
1307	 * since new dq will appear on the hash chain DQ_LOCKed.
1308	 */
1309	if (vp != dqvp) {
1310		DQH_UNLOCK();
1311		vn_lock(dqvp, LK_SHARED | LK_RETRY);
1312		dqvplocked = 1;
1313		DQH_LOCK();
1314		/*
1315		 * Recheck the cache after sleep for quota vnode lock.
1316		 */
1317		dq = dqhashfind(dqh, id, dqvp);
1318		if (dq != NULL) {
1319			DQH_UNLOCK();
1320			goto hfound;
1321		}
1322	}
1323
1324	/*
1325	 * Not in cache, allocate a new one or take it from the
1326	 * free list.
1327	 */
1328	if (TAILQ_FIRST(&dqfreelist) == NODQUOT &&
1329	    numdquot < MAXQUOTAS * desiredvnodes)
1330		desireddquot += DQUOTINC;
1331	if (numdquot < desireddquot) {
1332		numdquot++;
1333		DQH_UNLOCK();
1334		dq1 = malloc(sizeof *dq1, M_DQUOT, M_WAITOK | M_ZERO);
1335		mtx_init(&dq1->dq_lock, "dqlock", NULL, MTX_DEF);
1336		DQH_LOCK();
1337		/*
1338		 * Recheck the cache after sleep for memory.
1339		 */
1340		dq = dqhashfind(dqh, id, dqvp);
1341		if (dq != NULL) {
1342			numdquot--;
1343			DQH_UNLOCK();
1344			mtx_destroy(&dq1->dq_lock);
1345			free(dq1, M_DQUOT);
1346			goto hfound;
1347		}
1348		dq = dq1;
1349	} else {
1350		if ((dq = TAILQ_FIRST(&dqfreelist)) == NULL) {
1351			DQH_UNLOCK();
1352			tablefull("dquot");
1353			*dqp = NODQUOT;
1354			if (dqvplocked)
1355				vput(dqvp);
1356			else
1357				vrele(dqvp);
1358			return (EUSERS);
1359		}
1360		if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
1361			panic("dqget: free dquot isn't %p", dq);
1362		TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
1363		if (dq->dq_ump != NULL)
1364			LIST_REMOVE(dq, dq_hash);
1365	}
1366
1367	/*
1368	 * Dq is put into hash already locked to prevent parallel
1369	 * usage while it is being read from file.
1370	 */
1371	dq->dq_flags = DQ_LOCK;
1372	dq->dq_id = id;
1373	dq->dq_type = type;
1374	dq->dq_ump = ump;
1375	LIST_INSERT_HEAD(dqh, dq, dq_hash);
1376	DQREF(dq);
1377	DQH_UNLOCK();
1378
1379	/*
1380	 * Read the requested quota record from the quota file, performing
1381	 * any necessary conversions.
1382	 */
1383	if (ump->um_qflags[type] & QTF_64BIT) {
1384		recsize = sizeof(struct dqblk64);
1385		base = sizeof(struct dqhdr64);
1386	} else {
1387		recsize = sizeof(struct dqblk32);
1388		base = 0;
1389	}
1390	auio.uio_iov = &aiov;
1391	auio.uio_iovcnt = 1;
1392	aiov.iov_base = buf;
1393	aiov.iov_len = recsize;
1394	auio.uio_resid = recsize;
1395	auio.uio_offset = base + id * recsize;
1396	auio.uio_segflg = UIO_SYSSPACE;
1397	auio.uio_rw = UIO_READ;
1398	auio.uio_td = (struct thread *)0;
1399
1400	error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
1401	if (auio.uio_resid == recsize && error == 0) {
1402		bzero(&dq->dq_dqb, sizeof(dq->dq_dqb));
1403	} else {
1404		if (ump->um_qflags[type] & QTF_64BIT)
1405			dqb64_dq((struct dqblk64 *)buf, dq);
1406		else
1407			dqb32_dq((struct dqblk32 *)buf, dq);
1408	}
1409	if (dqvplocked)
1410		vput(dqvp);
1411	else
1412		vrele(dqvp);
1413	/*
1414	 * I/O error in reading quota file, release
1415	 * quota structure and reflect problem to caller.
1416	 */
1417	if (error) {
1418		DQH_LOCK();
1419		dq->dq_ump = NULL;
1420		LIST_REMOVE(dq, dq_hash);
1421		DQH_UNLOCK();
1422		DQI_LOCK(dq);
1423		if (dq->dq_flags & DQ_WANT)
1424			wakeup(dq);
1425		dq->dq_flags = 0;
1426		DQI_UNLOCK(dq);
1427		dqrele(vp, dq);
1428		*dqp = NODQUOT;
1429		return (error);
1430	}
1431	DQI_LOCK(dq);
1432	/*
1433	 * Check for no limit to enforce.
1434	 * Initialize time values if necessary.
1435	 */
1436	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
1437	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
1438		dq->dq_flags |= DQ_FAKE;
1439	if (dq->dq_id != 0) {
1440		if (dq->dq_btime == 0) {
1441			dq->dq_btime = time_second + ump->um_btime[type];
1442			if (dq->dq_bsoftlimit &&
1443			    dq->dq_curblocks >= dq->dq_bsoftlimit)
1444				dq->dq_flags |= DQ_MOD;
1445		}
1446		if (dq->dq_itime == 0) {
1447			dq->dq_itime = time_second + ump->um_itime[type];
1448			if (dq->dq_isoftlimit &&
1449			    dq->dq_curinodes >= dq->dq_isoftlimit)
1450				dq->dq_flags |= DQ_MOD;
1451		}
1452	}
1453	DQI_WAKEUP(dq);
1454	DQI_UNLOCK(dq);
1455	*dqp = dq;
1456	return (0);
1457}
1458
1459#ifdef DIAGNOSTIC
1460/*
1461 * Obtain a reference to a dquot.
1462 */
1463static void
1464dqref(struct dquot *dq)
1465{
1466
1467	dq->dq_cnt++;
1468}
1469#endif
1470
1471/*
1472 * Release a reference to a dquot.
1473 */
1474void
1475dqrele(struct vnode *vp, struct dquot *dq)
1476{
1477
1478	if (dq == NODQUOT)
1479		return;
1480	DQH_LOCK();
1481	KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 1", dq));
1482	if (dq->dq_cnt > 1) {
1483		dq->dq_cnt--;
1484		DQH_UNLOCK();
1485		return;
1486	}
1487	DQH_UNLOCK();
1488sync:
1489	(void) dqsync(vp, dq);
1490
1491	DQH_LOCK();
1492	KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 2", dq));
1493	if (--dq->dq_cnt > 0)
1494	{
1495		DQH_UNLOCK();
1496		return;
1497	}
1498
1499	/*
1500	 * The dq may become dirty after it is synced but before it is
1501	 * put to the free list. Checking the DQ_MOD there without
1502	 * locking dq should be safe since no other references to the
1503	 * dq exist.
1504	 */
1505	if ((dq->dq_flags & DQ_MOD) != 0) {
1506		dq->dq_cnt++;
1507		DQH_UNLOCK();
1508		goto sync;
1509	}
1510	TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist);
1511	DQH_UNLOCK();
1512}
1513
1514/*
1515 * Update the disk quota in the quota file.
1516 */
1517static int
1518dqsync(struct vnode *vp, struct dquot *dq)
1519{
1520	uint8_t buf[sizeof(struct dqblk64)];
1521	off_t base, recsize;
1522	struct vnode *dqvp;
1523	struct iovec aiov;
1524	struct uio auio;
1525	int error;
1526	struct mount *mp;
1527	struct ufsmount *ump;
1528
1529#ifdef DEBUG_VFS_LOCKS
1530	if (vp != NULL)
1531		ASSERT_VOP_ELOCKED(vp, "dqsync");
1532#endif
1533
1534	mp = NULL;
1535	error = 0;
1536	if (dq == NODQUOT)
1537		panic("dqsync: dquot");
1538	if ((ump = dq->dq_ump) == NULL)
1539		return (0);
1540	UFS_LOCK(ump);
1541	if ((dqvp = ump->um_quotas[dq->dq_type]) == NULLVP)
1542		panic("dqsync: file");
1543	vref(dqvp);
1544	UFS_UNLOCK(ump);
1545
1546	DQI_LOCK(dq);
1547	if ((dq->dq_flags & DQ_MOD) == 0) {
1548		DQI_UNLOCK(dq);
1549		vrele(dqvp);
1550		return (0);
1551	}
1552	DQI_UNLOCK(dq);
1553
1554	(void) vn_start_secondary_write(dqvp, &mp, V_WAIT);
1555	if (vp != dqvp)
1556		vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
1557
1558	DQI_LOCK(dq);
1559	DQI_WAIT(dq, PINOD+2, "dqsync");
1560	if ((dq->dq_flags & DQ_MOD) == 0)
1561		goto out;
1562	dq->dq_flags |= DQ_LOCK;
1563	DQI_UNLOCK(dq);
1564
1565	/*
1566	 * Write the quota record to the quota file, performing any
1567	 * necessary conversions.  See dqget() for additional details.
1568	 */
1569	if (ump->um_qflags[dq->dq_type] & QTF_64BIT) {
1570		dq_dqb64(dq, (struct dqblk64 *)buf);
1571		recsize = sizeof(struct dqblk64);
1572		base = sizeof(struct dqhdr64);
1573	} else {
1574		dq_dqb32(dq, (struct dqblk32 *)buf);
1575		recsize = sizeof(struct dqblk32);
1576		base = 0;
1577	}
1578
1579	auio.uio_iov = &aiov;
1580	auio.uio_iovcnt = 1;
1581	aiov.iov_base = buf;
1582	aiov.iov_len = recsize;
1583	auio.uio_resid = recsize;
1584	auio.uio_offset = base + dq->dq_id * recsize;
1585	auio.uio_segflg = UIO_SYSSPACE;
1586	auio.uio_rw = UIO_WRITE;
1587	auio.uio_td = (struct thread *)0;
1588	error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
1589	if (auio.uio_resid && error == 0)
1590		error = EIO;
1591
1592	DQI_LOCK(dq);
1593	DQI_WAKEUP(dq);
1594	dq->dq_flags &= ~DQ_MOD;
1595out:
1596	DQI_UNLOCK(dq);
1597	if (vp != dqvp)
1598		vput(dqvp);
1599	else
1600		vrele(dqvp);
1601	vn_finished_secondary_write(mp);
1602	return (error);
1603}
1604
1605/*
1606 * Flush all entries from the cache for a particular vnode.
1607 */
1608static int
1609dqflush(struct vnode *vp)
1610{
1611	struct dquot *dq, *nextdq;
1612	struct dqhash *dqh;
1613	int error;
1614
1615	/*
1616	 * Move all dquot's that used to refer to this quota
1617	 * file off their hash chains (they will eventually
1618	 * fall off the head of the free list and be re-used).
1619	 */
1620	error = 0;
1621	DQH_LOCK();
1622	for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) {
1623		for (dq = LIST_FIRST(dqh); dq; dq = nextdq) {
1624			nextdq = LIST_NEXT(dq, dq_hash);
1625			if (dq->dq_ump->um_quotas[dq->dq_type] != vp)
1626				continue;
1627			if (dq->dq_cnt)
1628				error = EBUSY;
1629			else {
1630				LIST_REMOVE(dq, dq_hash);
1631				dq->dq_ump = NULL;
1632			}
1633		}
1634	}
1635	DQH_UNLOCK();
1636	return (error);
1637}
1638
1639/*
1640 * The following three functions are provided for the adjustment of
1641 * quotas by the soft updates code.
1642 */
1643#ifdef SOFTUPDATES
1644/*
1645 * Acquire a reference to the quota structures associated with a vnode.
1646 * Return count of number of quota structures found.
1647 */
1648int
1649quotaref(vp, qrp)
1650	struct vnode *vp;
1651	struct dquot **qrp;
1652{
1653	struct inode *ip;
1654	struct dquot *dq;
1655	int i, found;
1656
1657	for (i = 0; i < MAXQUOTAS; i++)
1658		qrp[i] = NODQUOT;
1659	/*
1660	 * Disk quotas must be turned off for system files.  Currently
1661	 * snapshot and quota files.
1662	 */
1663	if ((vp->v_vflag & VV_SYSTEM) != 0)
1664		return (0);
1665	/*
1666	 * Iterate through and copy active quotas.
1667	 */
1668	found = 0;
1669	ip = VTOI(vp);
1670	mtx_lock(&dqhlock);
1671	for (i = 0; i < MAXQUOTAS; i++) {
1672		if ((dq = ip->i_dquot[i]) == NODQUOT)
1673			continue;
1674		DQREF(dq);
1675		qrp[i] = dq;
1676		found++;
1677	}
1678	mtx_unlock(&dqhlock);
1679	return (found);
1680}
1681
1682/*
1683 * Release a set of quota structures obtained from a vnode.
1684 */
1685void
1686quotarele(qrp)
1687	struct dquot **qrp;
1688{
1689	struct dquot *dq;
1690	int i;
1691
1692	for (i = 0; i < MAXQUOTAS; i++) {
1693		if ((dq = qrp[i]) == NODQUOT)
1694			continue;
1695		dqrele(NULL, dq);
1696	}
1697}
1698
1699/*
1700 * Adjust the number of blocks associated with a quota.
1701 * Positive numbers when adding blocks; negative numbers when freeing blocks.
1702 */
1703void
1704quotaadj(qrp, ump, blkcount)
1705	struct dquot **qrp;
1706	struct ufsmount *ump;
1707	int64_t blkcount;
1708{
1709	struct dquot *dq;
1710	ufs2_daddr_t ncurblocks;
1711	int i;
1712
1713	if (blkcount == 0)
1714		return;
1715	for (i = 0; i < MAXQUOTAS; i++) {
1716		if ((dq = qrp[i]) == NODQUOT)
1717			continue;
1718		DQI_LOCK(dq);
1719		DQI_WAIT(dq, PINOD+1, "adjqta");
1720		ncurblocks = dq->dq_curblocks + blkcount;
1721		if (ncurblocks >= 0)
1722			dq->dq_curblocks = ncurblocks;
1723		else
1724			dq->dq_curblocks = 0;
1725		if (blkcount < 0)
1726			dq->dq_flags &= ~DQ_BLKS;
1727		else if (dq->dq_curblocks + blkcount >= dq->dq_bsoftlimit &&
1728			 dq->dq_curblocks < dq->dq_bsoftlimit)
1729			dq->dq_btime = time_second + ump->um_btime[i];
1730		dq->dq_flags |= DQ_MOD;
1731		DQI_UNLOCK(dq);
1732	}
1733}
1734#endif /* SOFTUPDATES */
1735
1736/*
1737 * 32-bit / 64-bit conversion functions.
1738 *
1739 * 32-bit quota records are stored in native byte order.  Attention must
1740 * be paid to overflow issues.
1741 *
1742 * 64-bit quota records are stored in network byte order.
1743 */
1744
1745#define CLIP32(u64) (u64 > UINT32_MAX ? UINT32_MAX : (uint32_t)u64)
1746
1747/*
1748 * Convert 32-bit host-order structure to dquot.
1749 */
1750static void
1751dqb32_dq(const struct dqblk32 *dqb32, struct dquot *dq)
1752{
1753
1754	dq->dq_bhardlimit = dqb32->dqb_bhardlimit;
1755	dq->dq_bsoftlimit = dqb32->dqb_bsoftlimit;
1756	dq->dq_curblocks = dqb32->dqb_curblocks;
1757	dq->dq_ihardlimit = dqb32->dqb_ihardlimit;
1758	dq->dq_isoftlimit = dqb32->dqb_isoftlimit;
1759	dq->dq_curinodes = dqb32->dqb_curinodes;
1760	dq->dq_btime = dqb32->dqb_btime;
1761	dq->dq_itime = dqb32->dqb_itime;
1762}
1763
1764/*
1765 * Convert 64-bit network-order structure to dquot.
1766 */
1767static void
1768dqb64_dq(const struct dqblk64 *dqb64, struct dquot *dq)
1769{
1770
1771	dq->dq_bhardlimit = be64toh(dqb64->dqb_bhardlimit);
1772	dq->dq_bsoftlimit = be64toh(dqb64->dqb_bsoftlimit);
1773	dq->dq_curblocks = be64toh(dqb64->dqb_curblocks);
1774	dq->dq_ihardlimit = be64toh(dqb64->dqb_ihardlimit);
1775	dq->dq_isoftlimit = be64toh(dqb64->dqb_isoftlimit);
1776	dq->dq_curinodes = be64toh(dqb64->dqb_curinodes);
1777	dq->dq_btime = be64toh(dqb64->dqb_btime);
1778	dq->dq_itime = be64toh(dqb64->dqb_itime);
1779}
1780
1781/*
1782 * Convert dquot to 32-bit host-order structure.
1783 */
1784static void
1785dq_dqb32(const struct dquot *dq, struct dqblk32 *dqb32)
1786{
1787
1788	dqb32->dqb_bhardlimit = CLIP32(dq->dq_bhardlimit);
1789	dqb32->dqb_bsoftlimit = CLIP32(dq->dq_bsoftlimit);
1790	dqb32->dqb_curblocks = CLIP32(dq->dq_curblocks);
1791	dqb32->dqb_ihardlimit = CLIP32(dq->dq_ihardlimit);
1792	dqb32->dqb_isoftlimit = CLIP32(dq->dq_isoftlimit);
1793	dqb32->dqb_curinodes = CLIP32(dq->dq_curinodes);
1794	dqb32->dqb_btime = CLIP32(dq->dq_btime);
1795	dqb32->dqb_itime = CLIP32(dq->dq_itime);
1796}
1797
1798/*
1799 * Convert dquot to 64-bit network-order structure.
1800 */
1801static void
1802dq_dqb64(const struct dquot *dq, struct dqblk64 *dqb64)
1803{
1804
1805	dqb64->dqb_bhardlimit = htobe64(dq->dq_bhardlimit);
1806	dqb64->dqb_bsoftlimit = htobe64(dq->dq_bsoftlimit);
1807	dqb64->dqb_curblocks = htobe64(dq->dq_curblocks);
1808	dqb64->dqb_ihardlimit = htobe64(dq->dq_ihardlimit);
1809	dqb64->dqb_isoftlimit = htobe64(dq->dq_isoftlimit);
1810	dqb64->dqb_curinodes = htobe64(dq->dq_curinodes);
1811	dqb64->dqb_btime = htobe64(dq->dq_btime);
1812	dqb64->dqb_itime = htobe64(dq->dq_itime);
1813}
1814
1815/*
1816 * Convert 64-bit host-order structure to 32-bit host-order structure.
1817 */
1818static void
1819dqb64_dqb32(const struct dqblk64 *dqb64, struct dqblk32 *dqb32)
1820{
1821
1822	dqb32->dqb_bhardlimit = CLIP32(dqb64->dqb_bhardlimit);
1823	dqb32->dqb_bsoftlimit = CLIP32(dqb64->dqb_bsoftlimit);
1824	dqb32->dqb_curblocks = CLIP32(dqb64->dqb_curblocks);
1825	dqb32->dqb_ihardlimit = CLIP32(dqb64->dqb_ihardlimit);
1826	dqb32->dqb_isoftlimit = CLIP32(dqb64->dqb_isoftlimit);
1827	dqb32->dqb_curinodes = CLIP32(dqb64->dqb_curinodes);
1828	dqb32->dqb_btime = CLIP32(dqb64->dqb_btime);
1829	dqb32->dqb_itime = CLIP32(dqb64->dqb_itime);
1830}
1831
1832/*
1833 * Convert 32-bit host-order structure to 64-bit host-order structure.
1834 */
1835static void
1836dqb32_dqb64(const struct dqblk32 *dqb32, struct dqblk64 *dqb64)
1837{
1838
1839	dqb64->dqb_bhardlimit = dqb32->dqb_bhardlimit;
1840	dqb64->dqb_bsoftlimit = dqb32->dqb_bsoftlimit;
1841	dqb64->dqb_curblocks = dqb32->dqb_curblocks;
1842	dqb64->dqb_ihardlimit = dqb32->dqb_ihardlimit;
1843	dqb64->dqb_isoftlimit = dqb32->dqb_isoftlimit;
1844	dqb64->dqb_curinodes = dqb32->dqb_curinodes;
1845	dqb64->dqb_btime = dqb32->dqb_btime;
1846	dqb64->dqb_itime = dqb32->dqb_itime;
1847}
1848