Home | History | Annotate | Line # | Download | only in lfs
ulfs_quota1.c revision 1.5.4.1
      1  1.5.4.1     rmind /*	$NetBSD: ulfs_quota1.c,v 1.5.4.1 2013/08/28 23:59:38 rmind Exp $	*/
      2      1.1  dholland /*  from NetBSD: ufs_quota1.c,v 1.18 2012/02/02 03:00:48 matt Exp  */
      3      1.1  dholland 
      4      1.1  dholland /*
      5      1.1  dholland  * Copyright (c) 1982, 1986, 1990, 1993, 1995
      6      1.1  dholland  *	The Regents of the University of California.  All rights reserved.
      7      1.1  dholland  *
      8      1.1  dholland  * This code is derived from software contributed to Berkeley by
      9      1.1  dholland  * Robert Elz at The University of Melbourne.
     10      1.1  dholland  *
     11      1.1  dholland  * Redistribution and use in source and binary forms, with or without
     12      1.1  dholland  * modification, are permitted provided that the following conditions
     13      1.1  dholland  * are met:
     14      1.1  dholland  * 1. Redistributions of source code must retain the above copyright
     15      1.1  dholland  *    notice, this list of conditions and the following disclaimer.
     16      1.1  dholland  * 2. Redistributions in binary form must reproduce the above copyright
     17      1.1  dholland  *    notice, this list of conditions and the following disclaimer in the
     18      1.1  dholland  *    documentation and/or other materials provided with the distribution.
     19      1.1  dholland  * 3. Neither the name of the University nor the names of its contributors
     20      1.1  dholland  *    may be used to endorse or promote products derived from this software
     21      1.1  dholland  *    without specific prior written permission.
     22      1.1  dholland  *
     23      1.1  dholland  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24      1.1  dholland  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25      1.1  dholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26      1.1  dholland  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27      1.1  dholland  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28      1.1  dholland  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29      1.1  dholland  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30      1.1  dholland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31      1.1  dholland  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32      1.1  dholland  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33      1.1  dholland  * SUCH DAMAGE.
     34      1.1  dholland  *
     35      1.1  dholland  *	@(#)ufs_quota.c	8.5 (Berkeley) 5/20/95
     36      1.1  dholland  */
     37      1.1  dholland 
     38      1.1  dholland #include <sys/cdefs.h>
     39  1.5.4.1     rmind __KERNEL_RCSID(0, "$NetBSD: ulfs_quota1.c,v 1.5.4.1 2013/08/28 23:59:38 rmind Exp $");
     40      1.1  dholland 
     41      1.1  dholland #include <sys/param.h>
     42      1.1  dholland #include <sys/kernel.h>
     43      1.1  dholland #include <sys/systm.h>
     44      1.1  dholland #include <sys/namei.h>
     45      1.1  dholland #include <sys/file.h>
     46      1.1  dholland #include <sys/proc.h>
     47      1.1  dholland #include <sys/vnode.h>
     48      1.1  dholland #include <sys/mount.h>
     49      1.1  dholland #include <sys/kauth.h>
     50      1.1  dholland 
     51      1.2  dholland #include <ufs/lfs/ulfs_quota1.h>
     52      1.2  dholland #include <ufs/lfs/ulfs_inode.h>
     53      1.2  dholland #include <ufs/lfs/ulfsmount.h>
     54      1.2  dholland #include <ufs/lfs/ulfs_extern.h>
     55      1.2  dholland #include <ufs/lfs/ulfs_quota.h>
     56      1.1  dholland 
     57      1.1  dholland static int chkdqchg(struct inode *, int64_t, kauth_cred_t, int);
     58      1.1  dholland static int chkiqchg(struct inode *, int32_t, kauth_cred_t, int);
     59      1.1  dholland 
     60      1.1  dholland /*
     61      1.1  dholland  * Update disk usage, and take corrective action.
     62      1.1  dholland  */
     63      1.1  dholland int
     64      1.4  dholland lfs_chkdq1(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
     65      1.1  dholland {
     66      1.1  dholland 	struct dquot *dq;
     67      1.1  dholland 	int i;
     68      1.1  dholland 	int ncurblocks, error;
     69      1.1  dholland 
     70      1.4  dholland 	if ((error = lfs_getinoquota(ip)) != 0)
     71      1.1  dholland 		return error;
     72      1.1  dholland 	if (change == 0)
     73      1.1  dholland 		return (0);
     74      1.1  dholland 	if (change < 0) {
     75      1.3  dholland 		for (i = 0; i < ULFS_MAXQUOTAS; i++) {
     76      1.1  dholland 			if ((dq = ip->i_dquot[i]) == NODQUOT)
     77      1.1  dholland 				continue;
     78      1.1  dholland 			mutex_enter(&dq->dq_interlock);
     79      1.1  dholland 			ncurblocks = dq->dq_curblocks + change;
     80      1.1  dholland 			if (ncurblocks >= 0)
     81      1.1  dholland 				dq->dq_curblocks = ncurblocks;
     82      1.1  dholland 			else
     83      1.1  dholland 				dq->dq_curblocks = 0;
     84      1.1  dholland 			dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
     85      1.1  dholland 			dq->dq_flags |= DQ_MOD;
     86      1.1  dholland 			mutex_exit(&dq->dq_interlock);
     87      1.1  dholland 		}
     88      1.1  dholland 		return (0);
     89      1.1  dholland 	}
     90      1.3  dholland 	for (i = 0; i < ULFS_MAXQUOTAS; i++) {
     91      1.1  dholland 		if ((dq = ip->i_dquot[i]) == NODQUOT)
     92      1.1  dholland 			continue;
     93      1.1  dholland 		if ((flags & FORCE) == 0 &&
     94      1.1  dholland 		    kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA,
     95      1.1  dholland 		    KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, KAUTH_ARG(i),
     96      1.1  dholland 		    KAUTH_ARG(QL_BLOCK), NULL) != 0) {
     97      1.1  dholland 			mutex_enter(&dq->dq_interlock);
     98      1.1  dholland 			error = chkdqchg(ip, change, cred, i);
     99      1.1  dholland 			mutex_exit(&dq->dq_interlock);
    100      1.1  dholland 			if (error != 0)
    101      1.1  dholland 				return (error);
    102      1.1  dholland 		}
    103      1.1  dholland 	}
    104      1.3  dholland 	for (i = 0; i < ULFS_MAXQUOTAS; i++) {
    105      1.1  dholland 		if ((dq = ip->i_dquot[i]) == NODQUOT)
    106      1.1  dholland 			continue;
    107      1.1  dholland 		mutex_enter(&dq->dq_interlock);
    108      1.1  dholland 		dq->dq_curblocks += change;
    109      1.1  dholland 		dq->dq_flags |= DQ_MOD;
    110      1.1  dholland 		mutex_exit(&dq->dq_interlock);
    111      1.1  dholland 	}
    112      1.1  dholland 	return (0);
    113      1.1  dholland }
    114      1.1  dholland 
    115      1.1  dholland /*
    116      1.1  dholland  * Check for a valid change to a users allocation.
    117      1.1  dholland  * Issue an error message if appropriate.
    118      1.1  dholland  */
    119      1.1  dholland static int
    120      1.1  dholland chkdqchg(struct inode *ip, int64_t change, kauth_cred_t cred, int type)
    121      1.1  dholland {
    122      1.1  dholland 	struct dquot *dq = ip->i_dquot[type];
    123      1.1  dholland 	long ncurblocks = dq->dq_curblocks + change;
    124      1.1  dholland 
    125      1.1  dholland 	KASSERT(mutex_owned(&dq->dq_interlock));
    126      1.1  dholland 	/*
    127      1.1  dholland 	 * If user would exceed their hard limit, disallow space allocation.
    128      1.1  dholland 	 */
    129      1.1  dholland 	if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) {
    130      1.1  dholland 		if ((dq->dq_flags & DQ_WARN(QL_BLOCK)) == 0 &&
    131      1.1  dholland 		    ip->i_uid == kauth_cred_geteuid(cred)) {
    132      1.1  dholland 			uprintf("\n%s: write failed, %s disk limit reached\n",
    133      1.1  dholland 			    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    134      1.4  dholland 			    lfs_quotatypes[type]);
    135      1.1  dholland 			dq->dq_flags |= DQ_WARN(QL_BLOCK);
    136      1.1  dholland 		}
    137      1.1  dholland 		return (EDQUOT);
    138      1.1  dholland 	}
    139      1.1  dholland 	/*
    140      1.1  dholland 	 * If user is over their soft limit for too long, disallow space
    141      1.1  dholland 	 * allocation. Reset time limit as they cross their soft limit.
    142      1.1  dholland 	 */
    143      1.1  dholland 	if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) {
    144      1.1  dholland 		if (dq->dq_curblocks < dq->dq_bsoftlimit) {
    145      1.1  dholland 			dq->dq_btime =
    146      1.1  dholland 			    time_second + ip->i_ump->umq1_btime[type];
    147      1.1  dholland 			if (ip->i_uid == kauth_cred_geteuid(cred))
    148      1.1  dholland 				uprintf("\n%s: warning, %s %s\n",
    149      1.1  dholland 				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    150      1.4  dholland 				    lfs_quotatypes[type], "disk quota exceeded");
    151      1.1  dholland 			return (0);
    152      1.1  dholland 		}
    153      1.1  dholland 		if (time_second > dq->dq_btime) {
    154      1.1  dholland 			if ((dq->dq_flags & DQ_WARN(QL_BLOCK)) == 0 &&
    155      1.1  dholland 			    ip->i_uid == kauth_cred_geteuid(cred)) {
    156      1.1  dholland 				uprintf("\n%s: write failed, %s %s\n",
    157      1.1  dholland 				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    158      1.4  dholland 				    lfs_quotatypes[type],
    159      1.1  dholland 				    "disk quota exceeded for too long");
    160      1.1  dholland 				dq->dq_flags |= DQ_WARN(QL_BLOCK);
    161      1.1  dholland 			}
    162      1.1  dholland 			return (EDQUOT);
    163      1.1  dholland 		}
    164      1.1  dholland 	}
    165      1.1  dholland 	return (0);
    166      1.1  dholland }
    167      1.1  dholland 
    168      1.1  dholland /*
    169      1.1  dholland  * Check the inode limit, applying corrective action.
    170      1.1  dholland  */
    171      1.1  dholland int
    172      1.4  dholland lfs_chkiq1(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
    173      1.1  dholland {
    174      1.1  dholland 	struct dquot *dq;
    175      1.1  dholland 	int i;
    176      1.1  dholland 	int ncurinodes, error;
    177      1.1  dholland 
    178      1.4  dholland 	if ((error = lfs_getinoquota(ip)) != 0)
    179      1.1  dholland 		return error;
    180      1.1  dholland 	if (change == 0)
    181      1.1  dholland 		return (0);
    182      1.1  dholland 	if (change < 0) {
    183      1.3  dholland 		for (i = 0; i < ULFS_MAXQUOTAS; i++) {
    184      1.1  dholland 			if ((dq = ip->i_dquot[i]) == NODQUOT)
    185      1.1  dholland 				continue;
    186      1.1  dholland 			mutex_enter(&dq->dq_interlock);
    187      1.1  dholland 			ncurinodes = dq->dq_curinodes + change;
    188      1.1  dholland 			if (ncurinodes >= 0)
    189      1.1  dholland 				dq->dq_curinodes = ncurinodes;
    190      1.1  dholland 			else
    191      1.1  dholland 				dq->dq_curinodes = 0;
    192      1.1  dholland 			dq->dq_flags &= ~DQ_WARN(QL_FILE);
    193      1.1  dholland 			dq->dq_flags |= DQ_MOD;
    194      1.1  dholland 			mutex_exit(&dq->dq_interlock);
    195      1.1  dholland 		}
    196      1.1  dholland 		return (0);
    197      1.1  dholland 	}
    198      1.3  dholland 	for (i = 0; i < ULFS_MAXQUOTAS; i++) {
    199      1.1  dholland 		if ((dq = ip->i_dquot[i]) == NODQUOT)
    200      1.1  dholland 			continue;
    201      1.1  dholland 		if ((flags & FORCE) == 0 && kauth_authorize_system(cred,
    202      1.1  dholland 		    KAUTH_SYSTEM_FS_QUOTA, KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT,
    203      1.1  dholland 		    KAUTH_ARG(i), KAUTH_ARG(QL_FILE), NULL) != 0) {
    204      1.1  dholland 			mutex_enter(&dq->dq_interlock);
    205      1.1  dholland 			error = chkiqchg(ip, change, cred, i);
    206      1.1  dholland 			mutex_exit(&dq->dq_interlock);
    207      1.1  dholland 			if (error != 0)
    208      1.1  dholland 				return (error);
    209      1.1  dholland 		}
    210      1.1  dholland 	}
    211      1.3  dholland 	for (i = 0; i < ULFS_MAXQUOTAS; i++) {
    212      1.1  dholland 		if ((dq = ip->i_dquot[i]) == NODQUOT)
    213      1.1  dholland 			continue;
    214      1.1  dholland 		mutex_enter(&dq->dq_interlock);
    215      1.1  dholland 		dq->dq_curinodes += change;
    216      1.1  dholland 		dq->dq_flags |= DQ_MOD;
    217      1.1  dholland 		mutex_exit(&dq->dq_interlock);
    218      1.1  dholland 	}
    219      1.1  dholland 	return (0);
    220      1.1  dholland }
    221      1.1  dholland 
    222      1.1  dholland /*
    223      1.1  dholland  * Check for a valid change to a users allocation.
    224      1.1  dholland  * Issue an error message if appropriate.
    225      1.1  dholland  */
    226      1.1  dholland static int
    227      1.1  dholland chkiqchg(struct inode *ip, int32_t change, kauth_cred_t cred, int type)
    228      1.1  dholland {
    229      1.1  dholland 	struct dquot *dq = ip->i_dquot[type];
    230      1.1  dholland 	long ncurinodes = dq->dq_curinodes + change;
    231      1.1  dholland 
    232      1.1  dholland 	KASSERT(mutex_owned(&dq->dq_interlock));
    233      1.1  dholland 	/*
    234      1.1  dholland 	 * If user would exceed their hard limit, disallow inode allocation.
    235      1.1  dholland 	 */
    236      1.1  dholland 	if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) {
    237      1.1  dholland 		if ((dq->dq_flags & DQ_WARN(QL_FILE)) == 0 &&
    238      1.1  dholland 		    ip->i_uid == kauth_cred_geteuid(cred)) {
    239      1.1  dholland 			uprintf("\n%s: write failed, %s inode limit reached\n",
    240      1.1  dholland 			    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    241      1.4  dholland 			    lfs_quotatypes[type]);
    242      1.1  dholland 			dq->dq_flags |= DQ_WARN(QL_FILE);
    243      1.1  dholland 		}
    244      1.1  dholland 		return (EDQUOT);
    245      1.1  dholland 	}
    246      1.1  dholland 	/*
    247      1.1  dholland 	 * If user is over their soft limit for too long, disallow inode
    248      1.1  dholland 	 * allocation. Reset time limit as they cross their soft limit.
    249      1.1  dholland 	 */
    250      1.1  dholland 	if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) {
    251      1.1  dholland 		if (dq->dq_curinodes < dq->dq_isoftlimit) {
    252      1.1  dholland 			dq->dq_itime =
    253      1.1  dholland 			    time_second + ip->i_ump->umq1_itime[type];
    254      1.1  dholland 			if (ip->i_uid == kauth_cred_geteuid(cred))
    255      1.1  dholland 				uprintf("\n%s: warning, %s %s\n",
    256      1.1  dholland 				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    257      1.4  dholland 				    lfs_quotatypes[type], "inode quota exceeded");
    258      1.1  dholland 			return (0);
    259      1.1  dholland 		}
    260      1.1  dholland 		if (time_second > dq->dq_itime) {
    261      1.1  dholland 			if ((dq->dq_flags & DQ_WARN(QL_FILE)) == 0 &&
    262      1.1  dholland 			    ip->i_uid == kauth_cred_geteuid(cred)) {
    263      1.1  dholland 				uprintf("\n%s: write failed, %s %s\n",
    264      1.1  dholland 				    ITOV(ip)->v_mount->mnt_stat.f_mntonname,
    265      1.4  dholland 				    lfs_quotatypes[type],
    266      1.1  dholland 				    "inode quota exceeded for too long");
    267      1.1  dholland 				dq->dq_flags |= DQ_WARN(QL_FILE);
    268      1.1  dholland 			}
    269      1.1  dholland 			return (EDQUOT);
    270      1.1  dholland 		}
    271      1.1  dholland 	}
    272      1.1  dholland 	return (0);
    273      1.1  dholland }
    274      1.1  dholland 
    275      1.1  dholland int
    276      1.4  dholland lfsquota1_umount(struct mount *mp, int flags)
    277      1.1  dholland {
    278      1.1  dholland 	int i, error;
    279      1.3  dholland 	struct ulfsmount *ump = VFSTOULFS(mp);
    280  1.5.4.1     rmind 	struct lfs *fs = ump->um_lfs;
    281      1.1  dholland 	struct lwp *l = curlwp;
    282      1.1  dholland 
    283  1.5.4.1     rmind 	if ((fs->um_flags & ULFS_QUOTA) == 0)
    284      1.1  dholland 		return 0;
    285      1.1  dholland 
    286      1.1  dholland 	if ((error = vflush(mp, NULLVP, SKIPSYSTEM | flags)) != 0)
    287      1.1  dholland 		return (error);
    288      1.1  dholland 
    289      1.3  dholland 	for (i = 0; i < ULFS_MAXQUOTAS; i++) {
    290      1.1  dholland 		if (ump->um_quotas[i] != NULLVP) {
    291      1.4  dholland 			lfsquota1_handle_cmd_quotaoff(l, ump, i);
    292      1.1  dholland 		}
    293      1.1  dholland 	}
    294      1.1  dholland 	return 0;
    295      1.1  dholland }
    296      1.1  dholland 
    297      1.1  dholland /*
    298      1.1  dholland  * Code to process quotactl commands.
    299      1.1  dholland  */
    300      1.1  dholland 
    301      1.1  dholland /*
    302      1.1  dholland  * set up a quota file for a particular file system.
    303      1.1  dholland  */
    304      1.1  dholland int
    305      1.4  dholland lfsquota1_handle_cmd_quotaon(struct lwp *l, struct ulfsmount *ump, int type,
    306      1.1  dholland     const char *fname)
    307      1.1  dholland {
    308      1.1  dholland 	struct mount *mp = ump->um_mountp;
    309  1.5.4.1     rmind 	struct lfs *fs = ump->um_lfs;
    310      1.1  dholland 	struct vnode *vp, **vpp, *mvp;
    311      1.1  dholland 	struct dquot *dq;
    312      1.1  dholland 	int error;
    313      1.1  dholland 	struct pathbuf *pb;
    314      1.1  dholland 	struct nameidata nd;
    315      1.1  dholland 
    316  1.5.4.1     rmind 	if (fs->um_flags & ULFS_QUOTA2) {
    317      1.1  dholland 		uprintf("%s: quotas v2 already enabled\n",
    318      1.1  dholland 		    mp->mnt_stat.f_mntonname);
    319      1.1  dholland 		return (EBUSY);
    320      1.1  dholland 	}
    321      1.1  dholland 
    322      1.1  dholland 	vpp = &ump->um_quotas[type];
    323      1.1  dholland 
    324      1.1  dholland 	pb = pathbuf_create(fname);
    325      1.1  dholland 	if (pb == NULL) {
    326      1.1  dholland 		return ENOMEM;
    327      1.1  dholland 	}
    328      1.1  dholland 	NDINIT(&nd, LOOKUP, FOLLOW, pb);
    329      1.1  dholland 	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
    330      1.1  dholland 		pathbuf_destroy(pb);
    331      1.1  dholland 		return error;
    332      1.1  dholland 	}
    333      1.1  dholland 	vp = nd.ni_vp;
    334      1.1  dholland 	pathbuf_destroy(pb);
    335      1.1  dholland 
    336      1.1  dholland 	VOP_UNLOCK(vp);
    337      1.1  dholland 	if (vp->v_type != VREG) {
    338      1.1  dholland 		(void) vn_close(vp, FREAD|FWRITE, l->l_cred);
    339      1.1  dholland 		return (EACCES);
    340      1.1  dholland 	}
    341      1.1  dholland 	if (*vpp != vp)
    342      1.4  dholland 		lfsquota1_handle_cmd_quotaoff(l, ump, type);
    343      1.4  dholland 	mutex_enter(&lfs_dqlock);
    344      1.1  dholland 	while ((ump->umq1_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0)
    345      1.4  dholland 		cv_wait(&lfs_dqcv, &lfs_dqlock);
    346      1.1  dholland 	ump->umq1_qflags[type] |= QTF_OPENING;
    347      1.4  dholland 	mutex_exit(&lfs_dqlock);
    348      1.1  dholland 	mp->mnt_flag |= MNT_QUOTA;
    349      1.1  dholland 	vp->v_vflag |= VV_SYSTEM;	/* XXXSMP */
    350      1.1  dholland 	*vpp = vp;
    351      1.1  dholland 	/*
    352      1.1  dholland 	 * Save the credential of the process that turned on quotas.
    353      1.1  dholland 	 * Set up the time limits for this quota.
    354      1.1  dholland 	 */
    355      1.1  dholland 	kauth_cred_hold(l->l_cred);
    356      1.1  dholland 	ump->um_cred[type] = l->l_cred;
    357      1.1  dholland 	ump->umq1_btime[type] = MAX_DQ_TIME;
    358      1.1  dholland 	ump->umq1_itime[type] = MAX_IQ_TIME;
    359      1.4  dholland 	if (lfs_dqget(NULLVP, 0, ump, type, &dq) == 0) {
    360      1.1  dholland 		if (dq->dq_btime > 0)
    361      1.1  dholland 			ump->umq1_btime[type] = dq->dq_btime;
    362      1.1  dholland 		if (dq->dq_itime > 0)
    363      1.1  dholland 			ump->umq1_itime[type] = dq->dq_itime;
    364      1.4  dholland 		lfs_dqrele(NULLVP, dq);
    365      1.1  dholland 	}
    366      1.1  dholland 	/* Allocate a marker vnode. */
    367      1.1  dholland 	mvp = vnalloc(mp);
    368      1.1  dholland 	/*
    369      1.1  dholland 	 * Search vnodes associated with this mount point,
    370      1.1  dholland 	 * adding references to quota file being opened.
    371      1.1  dholland 	 * NB: only need to add dquot's for inodes being modified.
    372      1.1  dholland 	 */
    373      1.1  dholland 	mutex_enter(&mntvnode_lock);
    374      1.1  dholland again:
    375      1.1  dholland 	for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
    376      1.1  dholland 		vmark(mvp, vp);
    377      1.1  dholland 		mutex_enter(vp->v_interlock);
    378      1.1  dholland 		if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
    379      1.1  dholland 		    vp->v_type == VNON || vp->v_writecount == 0 ||
    380      1.1  dholland 		    (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
    381      1.1  dholland 			mutex_exit(vp->v_interlock);
    382      1.1  dholland 			continue;
    383      1.1  dholland 		}
    384      1.1  dholland 		mutex_exit(&mntvnode_lock);
    385      1.1  dholland 		if (vget(vp, LK_EXCLUSIVE)) {
    386      1.1  dholland 			mutex_enter(&mntvnode_lock);
    387      1.1  dholland 			(void)vunmark(mvp);
    388      1.1  dholland 			goto again;
    389      1.1  dholland 		}
    390      1.4  dholland 		if ((error = lfs_getinoquota(VTOI(vp))) != 0) {
    391      1.1  dholland 			vput(vp);
    392      1.1  dholland 			mutex_enter(&mntvnode_lock);
    393      1.1  dholland 			(void)vunmark(mvp);
    394      1.1  dholland 			break;
    395      1.1  dholland 		}
    396      1.1  dholland 		vput(vp);
    397      1.1  dholland 		mutex_enter(&mntvnode_lock);
    398      1.1  dholland 	}
    399      1.1  dholland 	mutex_exit(&mntvnode_lock);
    400      1.1  dholland 	vnfree(mvp);
    401      1.1  dholland 
    402      1.4  dholland 	mutex_enter(&lfs_dqlock);
    403      1.1  dholland 	ump->umq1_qflags[type] &= ~QTF_OPENING;
    404      1.4  dholland 	cv_broadcast(&lfs_dqcv);
    405      1.1  dholland 	if (error == 0)
    406  1.5.4.1     rmind 		fs->um_flags |= ULFS_QUOTA;
    407      1.4  dholland 	mutex_exit(&lfs_dqlock);
    408      1.1  dholland 	if (error)
    409      1.4  dholland 		lfsquota1_handle_cmd_quotaoff(l, ump, type);
    410      1.1  dholland 	return (error);
    411      1.1  dholland }
    412      1.1  dholland 
    413      1.1  dholland /*
    414      1.1  dholland  * turn off disk quotas for a filesystem.
    415      1.1  dholland  */
    416      1.1  dholland int
    417      1.4  dholland lfsquota1_handle_cmd_quotaoff(struct lwp *l, struct ulfsmount *ump, int type)
    418      1.1  dholland {
    419      1.1  dholland 	struct mount *mp = ump->um_mountp;
    420  1.5.4.1     rmind 	struct lfs *fs = ump->um_lfs;
    421      1.1  dholland 	struct vnode *vp;
    422      1.1  dholland 	struct vnode *qvp, *mvp;
    423      1.1  dholland 	struct dquot *dq;
    424      1.1  dholland 	struct inode *ip;
    425      1.1  dholland 	kauth_cred_t cred;
    426      1.1  dholland 	int i, error;
    427      1.1  dholland 
    428      1.1  dholland 	/* Allocate a marker vnode. */
    429      1.1  dholland 	mvp = vnalloc(mp);
    430      1.1  dholland 
    431      1.4  dholland 	mutex_enter(&lfs_dqlock);
    432      1.1  dholland 	while ((ump->umq1_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0)
    433      1.4  dholland 		cv_wait(&lfs_dqcv, &lfs_dqlock);
    434      1.1  dholland 	if ((qvp = ump->um_quotas[type]) == NULLVP) {
    435      1.4  dholland 		mutex_exit(&lfs_dqlock);
    436      1.1  dholland 		vnfree(mvp);
    437      1.1  dholland 		return (0);
    438      1.1  dholland 	}
    439      1.1  dholland 	ump->umq1_qflags[type] |= QTF_CLOSING;
    440  1.5.4.1     rmind 	fs->um_flags &= ~ULFS_QUOTA;
    441      1.4  dholland 	mutex_exit(&lfs_dqlock);
    442      1.1  dholland 	/*
    443      1.1  dholland 	 * Search vnodes associated with this mount point,
    444      1.1  dholland 	 * deleting any references to quota file being closed.
    445      1.1  dholland 	 */
    446      1.1  dholland 	mutex_enter(&mntvnode_lock);
    447      1.1  dholland again:
    448      1.1  dholland 	for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
    449      1.1  dholland 		vmark(mvp, vp);
    450      1.1  dholland 		mutex_enter(vp->v_interlock);
    451      1.1  dholland 		if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
    452      1.1  dholland 		    vp->v_type == VNON ||
    453      1.1  dholland 		    (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
    454      1.1  dholland 			mutex_exit(vp->v_interlock);
    455      1.1  dholland 			continue;
    456      1.1  dholland 		}
    457      1.1  dholland 		mutex_exit(&mntvnode_lock);
    458      1.1  dholland 		if (vget(vp, LK_EXCLUSIVE)) {
    459      1.1  dholland 			mutex_enter(&mntvnode_lock);
    460      1.1  dholland 			(void)vunmark(mvp);
    461      1.1  dholland 			goto again;
    462      1.1  dholland 		}
    463      1.1  dholland 		ip = VTOI(vp);
    464      1.1  dholland 		dq = ip->i_dquot[type];
    465      1.1  dholland 		ip->i_dquot[type] = NODQUOT;
    466      1.4  dholland 		lfs_dqrele(vp, dq);
    467      1.1  dholland 		vput(vp);
    468      1.1  dholland 		mutex_enter(&mntvnode_lock);
    469      1.1  dholland 	}
    470      1.1  dholland 	mutex_exit(&mntvnode_lock);
    471      1.1  dholland #ifdef DIAGNOSTIC
    472      1.4  dholland 	lfs_dqflush(qvp);
    473      1.1  dholland #endif
    474      1.1  dholland 	qvp->v_vflag &= ~VV_SYSTEM;
    475      1.1  dholland 	error = vn_close(qvp, FREAD|FWRITE, l->l_cred);
    476      1.4  dholland 	mutex_enter(&lfs_dqlock);
    477      1.1  dholland 	ump->um_quotas[type] = NULLVP;
    478      1.1  dholland 	cred = ump->um_cred[type];
    479      1.1  dholland 	ump->um_cred[type] = NOCRED;
    480      1.3  dholland 	for (i = 0; i < ULFS_MAXQUOTAS; i++)
    481      1.1  dholland 		if (ump->um_quotas[i] != NULLVP)
    482      1.1  dholland 			break;
    483      1.1  dholland 	ump->umq1_qflags[type] &= ~QTF_CLOSING;
    484      1.4  dholland 	cv_broadcast(&lfs_dqcv);
    485      1.4  dholland 	mutex_exit(&lfs_dqlock);
    486      1.1  dholland 	kauth_cred_free(cred);
    487      1.3  dholland 	if (i == ULFS_MAXQUOTAS)
    488      1.1  dholland 		mp->mnt_flag &= ~MNT_QUOTA;
    489      1.1  dholland 	return (error);
    490      1.1  dholland }
    491      1.1  dholland 
    492      1.1  dholland int
    493      1.4  dholland lfsquota1_handle_cmd_get(struct ulfsmount *ump, const struct quotakey *qk,
    494      1.1  dholland     struct quotaval *qv)
    495      1.1  dholland {
    496      1.1  dholland 	struct dquot *dq;
    497      1.1  dholland 	int error;
    498      1.1  dholland 	struct quotaval blocks, files;
    499      1.1  dholland 	int idtype;
    500      1.1  dholland 	id_t id;
    501      1.1  dholland 
    502      1.1  dholland 	idtype = qk->qk_idtype;
    503      1.1  dholland 	id = qk->qk_id;
    504      1.1  dholland 
    505      1.1  dholland 	if (ump->um_quotas[idtype] == NULLVP)
    506      1.1  dholland 		return ENODEV;
    507      1.1  dholland 
    508      1.1  dholland 	if (id == QUOTA_DEFAULTID) { /* we want the grace period of id 0 */
    509      1.4  dholland 		if ((error = lfs_dqget(NULLVP, 0, ump, idtype, &dq)) != 0)
    510      1.1  dholland 			return error;
    511      1.1  dholland 
    512      1.1  dholland 	} else {
    513      1.4  dholland 		if ((error = lfs_dqget(NULLVP, id, ump, idtype, &dq)) != 0)
    514      1.1  dholland 			return error;
    515      1.1  dholland 	}
    516      1.4  dholland 	lfs_dqblk_to_quotavals(&dq->dq_un.dq1_dqb, &blocks, &files);
    517      1.4  dholland 	lfs_dqrele(NULLVP, dq);
    518      1.1  dholland 	if (id == QUOTA_DEFAULTID) {
    519      1.1  dholland 		if (blocks.qv_expiretime > 0)
    520      1.1  dholland 			blocks.qv_grace = blocks.qv_expiretime;
    521      1.1  dholland 		else
    522      1.1  dholland 			blocks.qv_grace = MAX_DQ_TIME;
    523      1.1  dholland 		if (files.qv_expiretime > 0)
    524      1.1  dholland 			files.qv_grace = files.qv_expiretime;
    525      1.1  dholland 		else
    526      1.1  dholland 			files.qv_grace = MAX_DQ_TIME;
    527      1.1  dholland 	}
    528      1.1  dholland 
    529      1.1  dholland 	switch (qk->qk_objtype) {
    530      1.1  dholland 	    case QUOTA_OBJTYPE_BLOCKS:
    531      1.1  dholland 		*qv = blocks;
    532      1.1  dholland 		break;
    533      1.1  dholland 	    case QUOTA_OBJTYPE_FILES:
    534      1.1  dholland 		*qv = files;
    535      1.1  dholland 		break;
    536      1.1  dholland 	    default:
    537      1.1  dholland 		return EINVAL;
    538      1.1  dholland 	}
    539      1.1  dholland 
    540      1.1  dholland 	return 0;
    541      1.1  dholland }
    542      1.1  dholland 
    543      1.1  dholland static uint32_t
    544      1.1  dholland quota1_encode_limit(uint64_t lim)
    545      1.1  dholland {
    546      1.1  dholland 	if (lim == QUOTA_NOLIMIT || lim >= 0xffffffff) {
    547      1.1  dholland 		return 0;
    548      1.1  dholland 	}
    549      1.1  dholland 	return lim;
    550      1.1  dholland }
    551      1.1  dholland 
    552      1.1  dholland int
    553      1.4  dholland lfsquota1_handle_cmd_put(struct ulfsmount *ump, const struct quotakey *key,
    554      1.1  dholland     const struct quotaval *val)
    555      1.1  dholland {
    556      1.1  dholland 	struct dquot *dq;
    557      1.1  dholland 	struct dqblk dqb;
    558      1.1  dholland 	int error;
    559      1.1  dholland 
    560      1.1  dholland 	switch (key->qk_idtype) {
    561      1.1  dholland 	    case QUOTA_IDTYPE_USER:
    562      1.1  dholland 	    case QUOTA_IDTYPE_GROUP:
    563      1.1  dholland 		break;
    564      1.1  dholland 	    default:
    565      1.1  dholland 		return EINVAL;
    566      1.1  dholland 	}
    567      1.1  dholland 
    568      1.1  dholland 	switch (key->qk_objtype) {
    569      1.1  dholland 	    case QUOTA_OBJTYPE_BLOCKS:
    570      1.1  dholland 	    case QUOTA_OBJTYPE_FILES:
    571      1.1  dholland 		break;
    572      1.1  dholland 	    default:
    573      1.1  dholland 		return EINVAL;
    574      1.1  dholland 	}
    575      1.1  dholland 
    576      1.1  dholland 	if (ump->um_quotas[key->qk_idtype] == NULLVP)
    577      1.1  dholland 		return ENODEV;
    578      1.1  dholland 
    579      1.1  dholland 	if (key->qk_id == QUOTA_DEFAULTID) {
    580      1.1  dholland 		/* just update grace times */
    581      1.1  dholland 		id_t id = 0;
    582      1.1  dholland 
    583      1.4  dholland 		if ((error = lfs_dqget(NULLVP, id, ump, key->qk_idtype, &dq)) != 0)
    584      1.1  dholland 			return error;
    585      1.1  dholland 		mutex_enter(&dq->dq_interlock);
    586      1.1  dholland 		if (val->qv_grace != QUOTA_NOTIME) {
    587      1.1  dholland 			if (key->qk_objtype == QUOTA_OBJTYPE_BLOCKS)
    588      1.1  dholland 				ump->umq1_btime[key->qk_idtype] = dq->dq_btime =
    589      1.1  dholland 					val->qv_grace;
    590      1.1  dholland 			if (key->qk_objtype == QUOTA_OBJTYPE_FILES)
    591      1.1  dholland 				ump->umq1_itime[key->qk_idtype] = dq->dq_itime =
    592      1.1  dholland 					val->qv_grace;
    593      1.1  dholland 		}
    594      1.1  dholland 		dq->dq_flags |= DQ_MOD;
    595      1.1  dholland 		mutex_exit(&dq->dq_interlock);
    596      1.4  dholland 		lfs_dqrele(NULLVP, dq);
    597      1.1  dholland 		return 0;
    598      1.1  dholland 	}
    599      1.1  dholland 
    600      1.4  dholland 	if ((error = lfs_dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq)) != 0)
    601      1.1  dholland 		return (error);
    602      1.1  dholland 	mutex_enter(&dq->dq_interlock);
    603      1.1  dholland 	/*
    604      1.1  dholland 	 * Copy all but the current values.
    605      1.1  dholland 	 * Reset time limit if previously had no soft limit or were
    606      1.1  dholland 	 * under it, but now have a soft limit and are over it.
    607      1.1  dholland 	 */
    608      1.1  dholland 	dqb.dqb_curblocks = dq->dq_curblocks;
    609      1.1  dholland 	dqb.dqb_curinodes = dq->dq_curinodes;
    610      1.1  dholland 	dqb.dqb_btime = dq->dq_btime;
    611      1.1  dholland 	dqb.dqb_itime = dq->dq_itime;
    612      1.1  dholland 	if (key->qk_objtype == QUOTA_OBJTYPE_BLOCKS) {
    613      1.1  dholland 		dqb.dqb_bsoftlimit = quota1_encode_limit(val->qv_softlimit);
    614      1.1  dholland 		dqb.dqb_bhardlimit = quota1_encode_limit(val->qv_hardlimit);
    615      1.1  dholland 		dqb.dqb_isoftlimit = dq->dq_isoftlimit;
    616      1.1  dholland 		dqb.dqb_ihardlimit = dq->dq_ihardlimit;
    617      1.1  dholland 	} else {
    618      1.1  dholland 		KASSERT(key->qk_objtype == QUOTA_OBJTYPE_FILES);
    619      1.1  dholland 		dqb.dqb_bsoftlimit = dq->dq_bsoftlimit;
    620      1.1  dholland 		dqb.dqb_bhardlimit = dq->dq_bhardlimit;
    621      1.1  dholland 		dqb.dqb_isoftlimit = quota1_encode_limit(val->qv_softlimit);
    622      1.1  dholland 		dqb.dqb_ihardlimit = quota1_encode_limit(val->qv_hardlimit);
    623      1.1  dholland 	}
    624      1.1  dholland 	if (dq->dq_id == 0 && val->qv_grace != QUOTA_NOTIME) {
    625      1.1  dholland 		/* also update grace time if available */
    626      1.1  dholland 		if (key->qk_objtype == QUOTA_OBJTYPE_BLOCKS) {
    627      1.1  dholland 			ump->umq1_btime[key->qk_idtype] = dqb.dqb_btime =
    628      1.1  dholland 				val->qv_grace;
    629      1.1  dholland 		}
    630      1.1  dholland 		if (key->qk_objtype == QUOTA_OBJTYPE_FILES) {
    631      1.1  dholland 			ump->umq1_itime[key->qk_idtype] = dqb.dqb_itime =
    632      1.1  dholland 				val->qv_grace;
    633      1.1  dholland 		}
    634      1.1  dholland 	}
    635      1.1  dholland 	if (dqb.dqb_bsoftlimit &&
    636      1.1  dholland 	    dq->dq_curblocks >= dqb.dqb_bsoftlimit &&
    637      1.1  dholland 	    (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
    638      1.1  dholland 		dqb.dqb_btime = time_second + ump->umq1_btime[key->qk_idtype];
    639      1.1  dholland 	if (dqb.dqb_isoftlimit &&
    640      1.1  dholland 	    dq->dq_curinodes >= dqb.dqb_isoftlimit &&
    641      1.1  dholland 	    (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
    642      1.1  dholland 		dqb.dqb_itime = time_second + ump->umq1_itime[key->qk_idtype];
    643      1.1  dholland 	dq->dq_un.dq1_dqb = dqb;
    644      1.1  dholland 	if (dq->dq_curblocks < dq->dq_bsoftlimit)
    645      1.1  dholland 		dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
    646      1.1  dholland 	if (dq->dq_curinodes < dq->dq_isoftlimit)
    647      1.1  dholland 		dq->dq_flags &= ~DQ_WARN(QL_FILE);
    648      1.1  dholland 	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
    649      1.1  dholland 	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
    650      1.1  dholland 		dq->dq_flags |= DQ_FAKE;
    651      1.1  dholland 	else
    652      1.1  dholland 		dq->dq_flags &= ~DQ_FAKE;
    653      1.1  dholland 	dq->dq_flags |= DQ_MOD;
    654      1.1  dholland 	mutex_exit(&dq->dq_interlock);
    655      1.4  dholland 	lfs_dqrele(NULLVP, dq);
    656      1.1  dholland 	return (0);
    657      1.1  dholland }
    658      1.1  dholland 
    659      1.1  dholland 
    660      1.1  dholland #if 0
    661      1.1  dholland /*
    662      1.1  dholland  * Q_SETQUOTA - assign an entire dqblk structure.
    663      1.1  dholland  */
    664      1.1  dholland int
    665      1.1  dholland setquota1(struct mount *mp, u_long id, int type, struct dqblk *dqb)
    666      1.1  dholland {
    667      1.1  dholland 	struct dquot *dq;
    668      1.1  dholland 	struct dquot *ndq;
    669      1.3  dholland 	struct ulfsmount *ump = VFSTOULFS(mp);
    670      1.1  dholland 
    671      1.1  dholland 
    672      1.4  dholland 	if ((error = lfs_dqget(NULLVP, id, ump, type, &ndq)) != 0)
    673      1.1  dholland 		return (error);
    674      1.1  dholland 	dq = ndq;
    675      1.1  dholland 	mutex_enter(&dq->dq_interlock);
    676      1.1  dholland 	/*
    677      1.1  dholland 	 * Copy all but the current values.
    678      1.1  dholland 	 * Reset time limit if previously had no soft limit or were
    679      1.1  dholland 	 * under it, but now have a soft limit and are over it.
    680      1.1  dholland 	 */
    681      1.1  dholland 	dqb->dqb_curblocks = dq->dq_curblocks;
    682      1.1  dholland 	dqb->dqb_curinodes = dq->dq_curinodes;
    683      1.1  dholland 	if (dq->dq_id != 0) {
    684      1.1  dholland 		dqb->dqb_btime = dq->dq_btime;
    685      1.1  dholland 		dqb->dqb_itime = dq->dq_itime;
    686      1.1  dholland 	}
    687      1.1  dholland 	if (dqb->dqb_bsoftlimit &&
    688      1.1  dholland 	    dq->dq_curblocks >= dqb->dqb_bsoftlimit &&
    689      1.1  dholland 	    (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit))
    690      1.1  dholland 		dqb->dqb_btime = time_second + ump->umq1_btime[type];
    691      1.1  dholland 	if (dqb->dqb_isoftlimit &&
    692      1.1  dholland 	    dq->dq_curinodes >= dqb->dqb_isoftlimit &&
    693      1.1  dholland 	    (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit))
    694      1.1  dholland 		dqb->dqb_itime = time_second + ump->umq1_itime[type];
    695      1.1  dholland 	dq->dq_un.dq1_dqb = *dqb;
    696      1.1  dholland 	if (dq->dq_curblocks < dq->dq_bsoftlimit)
    697      1.1  dholland 		dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
    698      1.1  dholland 	if (dq->dq_curinodes < dq->dq_isoftlimit)
    699      1.1  dholland 		dq->dq_flags &= ~DQ_WARN(QL_FILE);
    700      1.1  dholland 	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
    701      1.1  dholland 	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
    702      1.1  dholland 		dq->dq_flags |= DQ_FAKE;
    703      1.1  dholland 	else
    704      1.1  dholland 		dq->dq_flags &= ~DQ_FAKE;
    705      1.1  dholland 	dq->dq_flags |= DQ_MOD;
    706      1.1  dholland 	mutex_exit(&dq->dq_interlock);
    707      1.4  dholland 	lfs_dqrele(NULLVP, dq);
    708      1.1  dholland 	return (0);
    709      1.1  dholland }
    710      1.1  dholland 
    711      1.1  dholland /*
    712      1.1  dholland  * Q_SETUSE - set current inode and block usage.
    713      1.1  dholland  */
    714      1.1  dholland int
    715      1.1  dholland setuse(struct mount *mp, u_long id, int type, void *addr)
    716      1.1  dholland {
    717      1.1  dholland 	struct dquot *dq;
    718      1.3  dholland 	struct ulfsmount *ump = VFSTOULFS(mp);
    719      1.1  dholland 	struct dquot *ndq;
    720      1.1  dholland 	struct dqblk usage;
    721      1.1  dholland 	int error;
    722      1.1  dholland 
    723      1.1  dholland 	error = copyin(addr, (void *)&usage, sizeof (struct dqblk));
    724      1.1  dholland 	if (error)
    725      1.1  dholland 		return (error);
    726      1.4  dholland 	if ((error = lfs_dqget(NULLVP, id, ump, type, &ndq)) != 0)
    727      1.1  dholland 		return (error);
    728      1.1  dholland 	dq = ndq;
    729      1.1  dholland 	mutex_enter(&dq->dq_interlock);
    730      1.1  dholland 	/*
    731      1.1  dholland 	 * Reset time limit if have a soft limit and were
    732      1.1  dholland 	 * previously under it, but are now over it.
    733      1.1  dholland 	 */
    734      1.1  dholland 	if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit &&
    735      1.1  dholland 	    usage.dqb_curblocks >= dq->dq_bsoftlimit)
    736      1.1  dholland 		dq->dq_btime = time_second + ump->umq1_btime[type];
    737      1.1  dholland 	if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit &&
    738      1.1  dholland 	    usage.dqb_curinodes >= dq->dq_isoftlimit)
    739      1.1  dholland 		dq->dq_itime = time_second + ump->umq1_itime[type];
    740      1.1  dholland 	dq->dq_curblocks = usage.dqb_curblocks;
    741      1.1  dholland 	dq->dq_curinodes = usage.dqb_curinodes;
    742      1.1  dholland 	if (dq->dq_curblocks < dq->dq_bsoftlimit)
    743      1.1  dholland 		dq->dq_flags &= ~DQ_WARN(QL_BLOCK);
    744      1.1  dholland 	if (dq->dq_curinodes < dq->dq_isoftlimit)
    745      1.1  dholland 		dq->dq_flags &= ~DQ_WARN(QL_FILE);
    746      1.1  dholland 	dq->dq_flags |= DQ_MOD;
    747      1.1  dholland 	mutex_exit(&dq->dq_interlock);
    748      1.4  dholland 	lfs_dqrele(NULLVP, dq);
    749      1.1  dholland 	return (0);
    750      1.1  dholland }
    751      1.1  dholland #endif
    752      1.1  dholland 
    753      1.1  dholland /*
    754      1.1  dholland  * Q_SYNC - sync quota files to disk.
    755      1.1  dholland  */
    756      1.1  dholland int
    757      1.4  dholland lfs_q1sync(struct mount *mp)
    758      1.1  dholland {
    759      1.3  dholland 	struct ulfsmount *ump = VFSTOULFS(mp);
    760      1.1  dholland 	struct vnode *vp, *mvp;
    761      1.1  dholland 	struct dquot *dq;
    762      1.1  dholland 	int i, error;
    763      1.1  dholland 
    764      1.1  dholland 	/*
    765      1.1  dholland 	 * Check if the mount point has any quotas.
    766      1.1  dholland 	 * If not, simply return.
    767      1.1  dholland 	 */
    768      1.3  dholland 	for (i = 0; i < ULFS_MAXQUOTAS; i++)
    769      1.1  dholland 		if (ump->um_quotas[i] != NULLVP)
    770      1.1  dholland 			break;
    771      1.3  dholland 	if (i == ULFS_MAXQUOTAS)
    772      1.1  dholland 		return (0);
    773      1.1  dholland 
    774      1.1  dholland 	/* Allocate a marker vnode. */
    775      1.1  dholland 	mvp = vnalloc(mp);
    776      1.1  dholland 
    777      1.1  dholland 	/*
    778      1.1  dholland 	 * Search vnodes associated with this mount point,
    779      1.1  dholland 	 * synchronizing any modified dquot structures.
    780      1.1  dholland 	 */
    781      1.1  dholland 	mutex_enter(&mntvnode_lock);
    782      1.1  dholland  again:
    783      1.1  dholland 	for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) {
    784      1.1  dholland 		vmark(mvp, vp);
    785      1.1  dholland 		mutex_enter(vp->v_interlock);
    786      1.1  dholland 		if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) ||
    787      1.1  dholland 		    vp->v_type == VNON ||
    788      1.1  dholland 		    (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) {
    789      1.1  dholland 			mutex_exit(vp->v_interlock);
    790      1.1  dholland 			continue;
    791      1.1  dholland 		}
    792      1.1  dholland 		mutex_exit(&mntvnode_lock);
    793      1.1  dholland 		error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT);
    794      1.1  dholland 		if (error) {
    795      1.1  dholland 			mutex_enter(&mntvnode_lock);
    796      1.1  dholland 			if (error == ENOENT) {
    797      1.1  dholland 				(void)vunmark(mvp);
    798      1.1  dholland 				goto again;
    799      1.1  dholland 			}
    800      1.1  dholland 			continue;
    801      1.1  dholland 		}
    802      1.3  dholland 		for (i = 0; i < ULFS_MAXQUOTAS; i++) {
    803      1.1  dholland 			dq = VTOI(vp)->i_dquot[i];
    804      1.1  dholland 			if (dq == NODQUOT)
    805      1.1  dholland 				continue;
    806      1.1  dholland 			mutex_enter(&dq->dq_interlock);
    807      1.1  dholland 			if (dq->dq_flags & DQ_MOD)
    808      1.4  dholland 				lfs_dq1sync(vp, dq);
    809      1.1  dholland 			mutex_exit(&dq->dq_interlock);
    810      1.1  dholland 		}
    811      1.1  dholland 		vput(vp);
    812      1.1  dholland 		mutex_enter(&mntvnode_lock);
    813      1.1  dholland 	}
    814      1.1  dholland 	mutex_exit(&mntvnode_lock);
    815      1.1  dholland 	vnfree(mvp);
    816      1.1  dholland 	return (0);
    817      1.1  dholland }
    818      1.1  dholland 
    819      1.1  dholland /*
    820      1.1  dholland  * Obtain a dquot structure for the specified identifier and quota file
    821      1.1  dholland  * reading the information from the file if necessary.
    822      1.1  dholland  */
    823      1.1  dholland int
    824      1.4  dholland lfs_dq1get(struct vnode *dqvp, u_long id, struct ulfsmount *ump, int type,
    825      1.1  dholland     struct dquot *dq)
    826      1.1  dholland {
    827      1.1  dholland 	struct iovec aiov;
    828      1.1  dholland 	struct uio auio;
    829      1.1  dholland 	int error;
    830      1.1  dholland 
    831      1.1  dholland 	KASSERT(mutex_owned(&dq->dq_interlock));
    832      1.1  dholland 	vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
    833      1.1  dholland 	auio.uio_iov = &aiov;
    834      1.1  dholland 	auio.uio_iovcnt = 1;
    835      1.1  dholland 	aiov.iov_base = (void *)&dq->dq_un.dq1_dqb;
    836      1.1  dholland 	aiov.iov_len = sizeof (struct dqblk);
    837      1.1  dholland 	auio.uio_resid = sizeof (struct dqblk);
    838      1.1  dholland 	auio.uio_offset = (off_t)(id * sizeof (struct dqblk));
    839      1.1  dholland 	auio.uio_rw = UIO_READ;
    840      1.1  dholland 	UIO_SETUP_SYSSPACE(&auio);
    841      1.1  dholland 	error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]);
    842      1.1  dholland 	if (auio.uio_resid == sizeof(struct dqblk) && error == 0)
    843      1.1  dholland 		memset((void *)&dq->dq_un.dq1_dqb, 0, sizeof(struct dqblk));
    844      1.1  dholland 	VOP_UNLOCK(dqvp);
    845      1.1  dholland 	/*
    846      1.1  dholland 	 * I/O error in reading quota file, release
    847      1.1  dholland 	 * quota structure and reflect problem to caller.
    848      1.1  dholland 	 */
    849      1.1  dholland 	if (error)
    850      1.1  dholland 		return (error);
    851      1.1  dholland 	/*
    852      1.1  dholland 	 * Check for no limit to enforce.
    853      1.1  dholland 	 * Initialize time values if necessary.
    854      1.1  dholland 	 */
    855      1.1  dholland 	if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 &&
    856      1.1  dholland 	    dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0)
    857      1.1  dholland 		dq->dq_flags |= DQ_FAKE;
    858      1.1  dholland 	if (dq->dq_id != 0) {
    859      1.1  dholland 		if (dq->dq_btime == 0)
    860      1.1  dholland 			dq->dq_btime = time_second + ump->umq1_btime[type];
    861      1.1  dholland 		if (dq->dq_itime == 0)
    862      1.1  dholland 			dq->dq_itime = time_second + ump->umq1_itime[type];
    863      1.1  dholland 	}
    864      1.1  dholland 	return (0);
    865      1.1  dholland }
    866      1.1  dholland 
    867      1.1  dholland /*
    868      1.1  dholland  * Update the disk quota in the quota file.
    869      1.1  dholland  */
    870      1.1  dholland int
    871      1.4  dholland lfs_dq1sync(struct vnode *vp, struct dquot *dq)
    872      1.1  dholland {
    873      1.1  dholland 	struct vnode *dqvp;
    874      1.1  dholland 	struct iovec aiov;
    875      1.1  dholland 	struct uio auio;
    876      1.1  dholland 	int error;
    877      1.1  dholland 
    878      1.1  dholland 	if (dq == NODQUOT)
    879      1.1  dholland 		panic("dq1sync: dquot");
    880      1.1  dholland 	KASSERT(mutex_owned(&dq->dq_interlock));
    881      1.1  dholland 	if ((dq->dq_flags & DQ_MOD) == 0)
    882      1.1  dholland 		return (0);
    883      1.1  dholland 	if ((dqvp = dq->dq_ump->um_quotas[dq->dq_type]) == NULLVP)
    884      1.1  dholland 		panic("dq1sync: file");
    885      1.1  dholland 	KASSERT(dqvp != vp);
    886      1.1  dholland 	vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY);
    887      1.1  dholland 	auio.uio_iov = &aiov;
    888      1.1  dholland 	auio.uio_iovcnt = 1;
    889      1.1  dholland 	aiov.iov_base = (void *)&dq->dq_un.dq1_dqb;
    890      1.1  dholland 	aiov.iov_len = sizeof (struct dqblk);
    891      1.1  dholland 	auio.uio_resid = sizeof (struct dqblk);
    892      1.1  dholland 	auio.uio_offset = (off_t)(dq->dq_id * sizeof (struct dqblk));
    893      1.1  dholland 	auio.uio_rw = UIO_WRITE;
    894      1.1  dholland 	UIO_SETUP_SYSSPACE(&auio);
    895      1.1  dholland 	error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]);
    896      1.1  dholland 	if (auio.uio_resid && error == 0)
    897      1.1  dholland 		error = EIO;
    898      1.1  dholland 	dq->dq_flags &= ~DQ_MOD;
    899      1.1  dholland 	VOP_UNLOCK(dqvp);
    900      1.1  dholland 	return (error);
    901      1.1  dholland }
    902