1*0a6a1f1dSLionel Sambuc /* $NetBSD: ulfs_quota.c,v 1.12 2014/06/28 22:27:51 dholland Exp $ */
284d9c625SLionel Sambuc /* from NetBSD: ufs_quota.c,v 1.115 2013/11/16 17:04:53 dholland Exp */
384d9c625SLionel Sambuc
484d9c625SLionel Sambuc /*
584d9c625SLionel Sambuc * Copyright (c) 1982, 1986, 1990, 1993, 1995
684d9c625SLionel Sambuc * The Regents of the University of California. All rights reserved.
784d9c625SLionel Sambuc *
884d9c625SLionel Sambuc * This code is derived from software contributed to Berkeley by
984d9c625SLionel Sambuc * Robert Elz at The University of Melbourne.
1084d9c625SLionel Sambuc *
1184d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
1284d9c625SLionel Sambuc * modification, are permitted provided that the following conditions
1384d9c625SLionel Sambuc * are met:
1484d9c625SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
1584d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1684d9c625SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
1784d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
1884d9c625SLionel Sambuc * documentation and/or other materials provided with the distribution.
1984d9c625SLionel Sambuc * 3. Neither the name of the University nor the names of its contributors
2084d9c625SLionel Sambuc * may be used to endorse or promote products derived from this software
2184d9c625SLionel Sambuc * without specific prior written permission.
2284d9c625SLionel Sambuc *
2384d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2484d9c625SLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2584d9c625SLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2684d9c625SLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2784d9c625SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2884d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2984d9c625SLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3084d9c625SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3184d9c625SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3284d9c625SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3384d9c625SLionel Sambuc * SUCH DAMAGE.
3484d9c625SLionel Sambuc *
3584d9c625SLionel Sambuc * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
3684d9c625SLionel Sambuc */
3784d9c625SLionel Sambuc
3884d9c625SLionel Sambuc #include <sys/cdefs.h>
39*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: ulfs_quota.c,v 1.12 2014/06/28 22:27:51 dholland Exp $");
4084d9c625SLionel Sambuc
4184d9c625SLionel Sambuc #if defined(_KERNEL_OPT)
4284d9c625SLionel Sambuc #include "opt_quota.h"
4384d9c625SLionel Sambuc #endif
4484d9c625SLionel Sambuc #include <sys/param.h>
4584d9c625SLionel Sambuc #include <sys/kernel.h>
4684d9c625SLionel Sambuc #include <sys/systm.h>
4784d9c625SLionel Sambuc #include <sys/namei.h>
4884d9c625SLionel Sambuc #include <sys/file.h>
4984d9c625SLionel Sambuc #include <sys/proc.h>
5084d9c625SLionel Sambuc #include <sys/vnode.h>
5184d9c625SLionel Sambuc #include <sys/mount.h>
5284d9c625SLionel Sambuc #include <sys/kauth.h>
5384d9c625SLionel Sambuc
5484d9c625SLionel Sambuc #include <sys/quotactl.h>
5584d9c625SLionel Sambuc #include <ufs/lfs/ulfs_quotacommon.h>
5684d9c625SLionel Sambuc #include <ufs/lfs/ulfs_inode.h>
5784d9c625SLionel Sambuc #include <ufs/lfs/ulfsmount.h>
5884d9c625SLionel Sambuc #include <ufs/lfs/ulfs_extern.h>
5984d9c625SLionel Sambuc #include <ufs/lfs/ulfs_quota.h>
6084d9c625SLionel Sambuc
6184d9c625SLionel Sambuc kmutex_t lfs_dqlock;
6284d9c625SLionel Sambuc kcondvar_t lfs_dqcv;
6384d9c625SLionel Sambuc const char *lfs_quotatypes[ULFS_MAXQUOTAS] = INITQFNAMES;
6484d9c625SLionel Sambuc
6584d9c625SLionel Sambuc /*
6684d9c625SLionel Sambuc * Code pertaining to management of the in-core dquot data structures.
6784d9c625SLionel Sambuc */
6884d9c625SLionel Sambuc #define DQHASH(dqvp, id) \
6984d9c625SLionel Sambuc (((((long)(dqvp)) >> 8) + id) & dqhash)
7084d9c625SLionel Sambuc static LIST_HEAD(dqhashhead, dquot) *dqhashtbl;
7184d9c625SLionel Sambuc static u_long dqhash;
7284d9c625SLionel Sambuc static pool_cache_t dquot_cache;
7384d9c625SLionel Sambuc
7484d9c625SLionel Sambuc
7584d9c625SLionel Sambuc static int quota_handle_cmd_stat(struct mount *, struct lwp *,
7684d9c625SLionel Sambuc struct quotactl_args *args);
7784d9c625SLionel Sambuc static int quota_handle_cmd_idtypestat(struct mount *, struct lwp *,
7884d9c625SLionel Sambuc struct quotactl_args *args);
7984d9c625SLionel Sambuc static int quota_handle_cmd_objtypestat(struct mount *, struct lwp *,
8084d9c625SLionel Sambuc struct quotactl_args *args);
8184d9c625SLionel Sambuc static int quota_handle_cmd_get(struct mount *, struct lwp *,
8284d9c625SLionel Sambuc struct quotactl_args *args);
8384d9c625SLionel Sambuc static int quota_handle_cmd_put(struct mount *, struct lwp *,
8484d9c625SLionel Sambuc struct quotactl_args *args);
8584d9c625SLionel Sambuc static int quota_handle_cmd_cursorget(struct mount *, struct lwp *,
8684d9c625SLionel Sambuc struct quotactl_args *args);
87*0a6a1f1dSLionel Sambuc static int quota_handle_cmd_del(struct mount *, struct lwp *,
8884d9c625SLionel Sambuc struct quotactl_args *args);
8984d9c625SLionel Sambuc static int quota_handle_cmd_quotaon(struct mount *, struct lwp *,
9084d9c625SLionel Sambuc struct quotactl_args *args);
9184d9c625SLionel Sambuc static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *,
9284d9c625SLionel Sambuc struct quotactl_args *args);
9384d9c625SLionel Sambuc static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *,
9484d9c625SLionel Sambuc struct quotactl_args *args);
9584d9c625SLionel Sambuc static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *,
9684d9c625SLionel Sambuc struct quotactl_args *args);
9784d9c625SLionel Sambuc static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *,
9884d9c625SLionel Sambuc struct quotactl_args *args);
9984d9c625SLionel Sambuc static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *,
10084d9c625SLionel Sambuc struct quotactl_args *args);
10184d9c625SLionel Sambuc static int quota_handle_cmd_cursorrewind(struct mount *, struct lwp *,
10284d9c625SLionel Sambuc struct quotactl_args *args);
10384d9c625SLionel Sambuc
10484d9c625SLionel Sambuc /*
10584d9c625SLionel Sambuc * Initialize the quota fields of an inode.
10684d9c625SLionel Sambuc */
10784d9c625SLionel Sambuc void
ulfsquota_init(struct inode * ip)10884d9c625SLionel Sambuc ulfsquota_init(struct inode *ip)
10984d9c625SLionel Sambuc {
11084d9c625SLionel Sambuc int i;
11184d9c625SLionel Sambuc
11284d9c625SLionel Sambuc for (i = 0; i < ULFS_MAXQUOTAS; i++)
11384d9c625SLionel Sambuc ip->i_dquot[i] = NODQUOT;
11484d9c625SLionel Sambuc }
11584d9c625SLionel Sambuc
11684d9c625SLionel Sambuc /*
11784d9c625SLionel Sambuc * Release the quota fields from an inode.
11884d9c625SLionel Sambuc */
11984d9c625SLionel Sambuc void
ulfsquota_free(struct inode * ip)12084d9c625SLionel Sambuc ulfsquota_free(struct inode *ip)
12184d9c625SLionel Sambuc {
12284d9c625SLionel Sambuc int i;
12384d9c625SLionel Sambuc
12484d9c625SLionel Sambuc for (i = 0; i < ULFS_MAXQUOTAS; i++) {
12584d9c625SLionel Sambuc lfs_dqrele(ITOV(ip), ip->i_dquot[i]);
12684d9c625SLionel Sambuc ip->i_dquot[i] = NODQUOT;
12784d9c625SLionel Sambuc }
12884d9c625SLionel Sambuc }
12984d9c625SLionel Sambuc
13084d9c625SLionel Sambuc /*
13184d9c625SLionel Sambuc * Update disk usage, and take corrective action.
13284d9c625SLionel Sambuc */
13384d9c625SLionel Sambuc int
lfs_chkdq(struct inode * ip,int64_t change,kauth_cred_t cred,int flags)13484d9c625SLionel Sambuc lfs_chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
13584d9c625SLionel Sambuc {
13684d9c625SLionel Sambuc /* do not track snapshot usage, or we will deadlock */
13784d9c625SLionel Sambuc if ((ip->i_flags & SF_SNAPSHOT) != 0)
13884d9c625SLionel Sambuc return 0;
13984d9c625SLionel Sambuc
14084d9c625SLionel Sambuc #ifdef LFS_QUOTA
14184d9c625SLionel Sambuc if (ip->i_lfs->um_flags & ULFS_QUOTA)
14284d9c625SLionel Sambuc return lfs_chkdq1(ip, change, cred, flags);
14384d9c625SLionel Sambuc #endif
14484d9c625SLionel Sambuc #ifdef LFS_QUOTA2
14584d9c625SLionel Sambuc if (ip->i_lfs->um_flags & ULFS_QUOTA2)
14684d9c625SLionel Sambuc return lfs_chkdq2(ip, change, cred, flags);
14784d9c625SLionel Sambuc #endif
14884d9c625SLionel Sambuc return 0;
14984d9c625SLionel Sambuc }
15084d9c625SLionel Sambuc
15184d9c625SLionel Sambuc /*
15284d9c625SLionel Sambuc * Check the inode limit, applying corrective action.
15384d9c625SLionel Sambuc */
15484d9c625SLionel Sambuc int
lfs_chkiq(struct inode * ip,int32_t change,kauth_cred_t cred,int flags)15584d9c625SLionel Sambuc lfs_chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
15684d9c625SLionel Sambuc {
15784d9c625SLionel Sambuc /* do not track snapshot usage, or we will deadlock */
15884d9c625SLionel Sambuc if ((ip->i_flags & SF_SNAPSHOT) != 0)
15984d9c625SLionel Sambuc return 0;
16084d9c625SLionel Sambuc #ifdef LFS_QUOTA
16184d9c625SLionel Sambuc if (ip->i_lfs->um_flags & ULFS_QUOTA)
16284d9c625SLionel Sambuc return lfs_chkiq1(ip, change, cred, flags);
16384d9c625SLionel Sambuc #endif
16484d9c625SLionel Sambuc #ifdef LFS_QUOTA2
16584d9c625SLionel Sambuc if (ip->i_lfs->um_flags & ULFS_QUOTA2)
16684d9c625SLionel Sambuc return lfs_chkiq2(ip, change, cred, flags);
16784d9c625SLionel Sambuc #endif
16884d9c625SLionel Sambuc return 0;
16984d9c625SLionel Sambuc }
17084d9c625SLionel Sambuc
17184d9c625SLionel Sambuc int
lfsquota_handle_cmd(struct mount * mp,struct lwp * l,struct quotactl_args * args)17284d9c625SLionel Sambuc lfsquota_handle_cmd(struct mount *mp, struct lwp *l,
17384d9c625SLionel Sambuc struct quotactl_args *args)
17484d9c625SLionel Sambuc {
17584d9c625SLionel Sambuc int error = 0;
17684d9c625SLionel Sambuc
17784d9c625SLionel Sambuc switch (args->qc_op) {
17884d9c625SLionel Sambuc case QUOTACTL_STAT:
17984d9c625SLionel Sambuc error = quota_handle_cmd_stat(mp, l, args);
18084d9c625SLionel Sambuc break;
18184d9c625SLionel Sambuc case QUOTACTL_IDTYPESTAT:
18284d9c625SLionel Sambuc error = quota_handle_cmd_idtypestat(mp, l, args);
18384d9c625SLionel Sambuc break;
18484d9c625SLionel Sambuc case QUOTACTL_OBJTYPESTAT:
18584d9c625SLionel Sambuc error = quota_handle_cmd_objtypestat(mp, l, args);
18684d9c625SLionel Sambuc break;
18784d9c625SLionel Sambuc case QUOTACTL_QUOTAON:
18884d9c625SLionel Sambuc error = quota_handle_cmd_quotaon(mp, l, args);
18984d9c625SLionel Sambuc break;
19084d9c625SLionel Sambuc case QUOTACTL_QUOTAOFF:
19184d9c625SLionel Sambuc error = quota_handle_cmd_quotaoff(mp, l, args);
19284d9c625SLionel Sambuc break;
19384d9c625SLionel Sambuc case QUOTACTL_GET:
19484d9c625SLionel Sambuc error = quota_handle_cmd_get(mp, l, args);
19584d9c625SLionel Sambuc break;
19684d9c625SLionel Sambuc case QUOTACTL_PUT:
19784d9c625SLionel Sambuc error = quota_handle_cmd_put(mp, l, args);
19884d9c625SLionel Sambuc break;
19984d9c625SLionel Sambuc case QUOTACTL_CURSORGET:
20084d9c625SLionel Sambuc error = quota_handle_cmd_cursorget(mp, l, args);
20184d9c625SLionel Sambuc break;
202*0a6a1f1dSLionel Sambuc case QUOTACTL_DEL:
203*0a6a1f1dSLionel Sambuc error = quota_handle_cmd_del(mp, l, args);
20484d9c625SLionel Sambuc break;
20584d9c625SLionel Sambuc case QUOTACTL_CURSOROPEN:
20684d9c625SLionel Sambuc error = quota_handle_cmd_cursoropen(mp, l, args);
20784d9c625SLionel Sambuc break;
20884d9c625SLionel Sambuc case QUOTACTL_CURSORCLOSE:
20984d9c625SLionel Sambuc error = quota_handle_cmd_cursorclose(mp, l, args);
21084d9c625SLionel Sambuc break;
21184d9c625SLionel Sambuc case QUOTACTL_CURSORSKIPIDTYPE:
21284d9c625SLionel Sambuc error = quota_handle_cmd_cursorskipidtype(mp, l, args);
21384d9c625SLionel Sambuc break;
21484d9c625SLionel Sambuc case QUOTACTL_CURSORATEND:
21584d9c625SLionel Sambuc error = quota_handle_cmd_cursoratend(mp, l, args);
21684d9c625SLionel Sambuc break;
21784d9c625SLionel Sambuc case QUOTACTL_CURSORREWIND:
21884d9c625SLionel Sambuc error = quota_handle_cmd_cursorrewind(mp, l, args);
21984d9c625SLionel Sambuc break;
22084d9c625SLionel Sambuc default:
22184d9c625SLionel Sambuc panic("Invalid quotactl operation %d\n", args->qc_op);
22284d9c625SLionel Sambuc }
22384d9c625SLionel Sambuc
22484d9c625SLionel Sambuc return error;
22584d9c625SLionel Sambuc }
22684d9c625SLionel Sambuc
22784d9c625SLionel Sambuc static int
quota_handle_cmd_stat(struct mount * mp,struct lwp * l,struct quotactl_args * args)22884d9c625SLionel Sambuc quota_handle_cmd_stat(struct mount *mp, struct lwp *l,
22984d9c625SLionel Sambuc struct quotactl_args *args)
23084d9c625SLionel Sambuc {
23184d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
23284d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
23384d9c625SLionel Sambuc
23484d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_STAT);
23584d9c625SLionel Sambuc
23684d9c625SLionel Sambuc if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
23784d9c625SLionel Sambuc return EOPNOTSUPP;
23884d9c625SLionel Sambuc
23984d9c625SLionel Sambuc #ifdef LFS_QUOTA
24084d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA) {
24184d9c625SLionel Sambuc struct quotastat *info = args->u.stat.qc_info;
24284d9c625SLionel Sambuc strcpy(info->qs_implname, "lfs quota v1");
24384d9c625SLionel Sambuc info->qs_numidtypes = ULFS_MAXQUOTAS;
24484d9c625SLionel Sambuc /* XXX no define for this */
24584d9c625SLionel Sambuc info->qs_numobjtypes = 2;
24684d9c625SLionel Sambuc info->qs_restrictions = 0;
24784d9c625SLionel Sambuc info->qs_restrictions |= QUOTA_RESTRICT_NEEDSQUOTACHECK;
24884d9c625SLionel Sambuc info->qs_restrictions |= QUOTA_RESTRICT_UNIFORMGRACE;
24984d9c625SLionel Sambuc info->qs_restrictions |= QUOTA_RESTRICT_32BIT;
25084d9c625SLionel Sambuc } else
25184d9c625SLionel Sambuc #endif
25284d9c625SLionel Sambuc #ifdef LFS_QUOTA2
25384d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
25484d9c625SLionel Sambuc struct quotastat *info = args->u.stat.qc_info;
25584d9c625SLionel Sambuc strcpy(info->qs_implname, "lfs quota v2");
25684d9c625SLionel Sambuc info->qs_numidtypes = ULFS_MAXQUOTAS;
25784d9c625SLionel Sambuc info->qs_numobjtypes = N_QL;
25884d9c625SLionel Sambuc info->qs_restrictions = 0;
25984d9c625SLionel Sambuc } else
26084d9c625SLionel Sambuc #endif
26184d9c625SLionel Sambuc return EOPNOTSUPP;
26284d9c625SLionel Sambuc
26384d9c625SLionel Sambuc return 0;
26484d9c625SLionel Sambuc }
26584d9c625SLionel Sambuc
26684d9c625SLionel Sambuc static int
quota_handle_cmd_idtypestat(struct mount * mp,struct lwp * l,struct quotactl_args * args)26784d9c625SLionel Sambuc quota_handle_cmd_idtypestat(struct mount *mp, struct lwp *l,
26884d9c625SLionel Sambuc struct quotactl_args *args)
26984d9c625SLionel Sambuc {
27084d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
27184d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
27284d9c625SLionel Sambuc int idtype;
27384d9c625SLionel Sambuc struct quotaidtypestat *info;
27484d9c625SLionel Sambuc const char *name;
27584d9c625SLionel Sambuc
27684d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_IDTYPESTAT);
27784d9c625SLionel Sambuc idtype = args->u.idtypestat.qc_idtype;
27884d9c625SLionel Sambuc info = args->u.idtypestat.qc_info;
27984d9c625SLionel Sambuc
28084d9c625SLionel Sambuc if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
28184d9c625SLionel Sambuc return EOPNOTSUPP;
28284d9c625SLionel Sambuc
28384d9c625SLionel Sambuc /*
28484d9c625SLionel Sambuc * These are the same for both QUOTA and QUOTA2.
28584d9c625SLionel Sambuc */
28684d9c625SLionel Sambuc switch (idtype) {
28784d9c625SLionel Sambuc case QUOTA_IDTYPE_USER:
28884d9c625SLionel Sambuc name = "user";
28984d9c625SLionel Sambuc break;
29084d9c625SLionel Sambuc case QUOTA_IDTYPE_GROUP:
29184d9c625SLionel Sambuc name = "group";
29284d9c625SLionel Sambuc break;
29384d9c625SLionel Sambuc default:
29484d9c625SLionel Sambuc return EINVAL;
29584d9c625SLionel Sambuc }
29684d9c625SLionel Sambuc strlcpy(info->qis_name, name, sizeof(info->qis_name));
29784d9c625SLionel Sambuc return 0;
29884d9c625SLionel Sambuc }
29984d9c625SLionel Sambuc
30084d9c625SLionel Sambuc static int
quota_handle_cmd_objtypestat(struct mount * mp,struct lwp * l,struct quotactl_args * args)30184d9c625SLionel Sambuc quota_handle_cmd_objtypestat(struct mount *mp, struct lwp *l,
30284d9c625SLionel Sambuc struct quotactl_args *args)
30384d9c625SLionel Sambuc {
30484d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
30584d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
30684d9c625SLionel Sambuc int objtype;
30784d9c625SLionel Sambuc struct quotaobjtypestat *info;
30884d9c625SLionel Sambuc const char *name;
30984d9c625SLionel Sambuc int isbytes;
31084d9c625SLionel Sambuc
31184d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_OBJTYPESTAT);
31284d9c625SLionel Sambuc objtype = args->u.objtypestat.qc_objtype;
31384d9c625SLionel Sambuc info = args->u.objtypestat.qc_info;
31484d9c625SLionel Sambuc
31584d9c625SLionel Sambuc if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
31684d9c625SLionel Sambuc return EOPNOTSUPP;
31784d9c625SLionel Sambuc
31884d9c625SLionel Sambuc /*
31984d9c625SLionel Sambuc * These are the same for both QUOTA and QUOTA2.
32084d9c625SLionel Sambuc */
32184d9c625SLionel Sambuc switch (objtype) {
32284d9c625SLionel Sambuc case QUOTA_OBJTYPE_BLOCKS:
32384d9c625SLionel Sambuc name = "block";
32484d9c625SLionel Sambuc isbytes = 1;
32584d9c625SLionel Sambuc break;
32684d9c625SLionel Sambuc case QUOTA_OBJTYPE_FILES:
32784d9c625SLionel Sambuc name = "file";
32884d9c625SLionel Sambuc isbytes = 0;
32984d9c625SLionel Sambuc break;
33084d9c625SLionel Sambuc default:
33184d9c625SLionel Sambuc return EINVAL;
33284d9c625SLionel Sambuc }
33384d9c625SLionel Sambuc strlcpy(info->qos_name, name, sizeof(info->qos_name));
33484d9c625SLionel Sambuc info->qos_isbytes = isbytes;
33584d9c625SLionel Sambuc return 0;
33684d9c625SLionel Sambuc }
33784d9c625SLionel Sambuc
33884d9c625SLionel Sambuc /* XXX shouldn't all this be in kauth ? */
33984d9c625SLionel Sambuc static int
quota_get_auth(struct mount * mp,struct lwp * l,uid_t id)34084d9c625SLionel Sambuc quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {
34184d9c625SLionel Sambuc /* The user can always query about his own quota. */
34284d9c625SLionel Sambuc if (id == kauth_cred_geteuid(l->l_cred))
34384d9c625SLionel Sambuc return 0;
34484d9c625SLionel Sambuc return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
34584d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL);
34684d9c625SLionel Sambuc }
34784d9c625SLionel Sambuc
34884d9c625SLionel Sambuc static int
quota_handle_cmd_get(struct mount * mp,struct lwp * l,struct quotactl_args * args)34984d9c625SLionel Sambuc quota_handle_cmd_get(struct mount *mp, struct lwp *l,
35084d9c625SLionel Sambuc struct quotactl_args *args)
35184d9c625SLionel Sambuc {
35284d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
35384d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
35484d9c625SLionel Sambuc int error;
35584d9c625SLionel Sambuc const struct quotakey *qk;
35684d9c625SLionel Sambuc
35784d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_GET);
35884d9c625SLionel Sambuc qk = args->u.get.qc_key;
35984d9c625SLionel Sambuc
36084d9c625SLionel Sambuc if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
36184d9c625SLionel Sambuc return EOPNOTSUPP;
36284d9c625SLionel Sambuc
36384d9c625SLionel Sambuc error = quota_get_auth(mp, l, qk->qk_id);
36484d9c625SLionel Sambuc if (error != 0)
36584d9c625SLionel Sambuc return error;
36684d9c625SLionel Sambuc #ifdef LFS_QUOTA
36784d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA) {
36884d9c625SLionel Sambuc struct quotaval *qv = args->u.get.qc_val;
36984d9c625SLionel Sambuc error = lfsquota1_handle_cmd_get(ump, qk, qv);
37084d9c625SLionel Sambuc } else
37184d9c625SLionel Sambuc #endif
37284d9c625SLionel Sambuc #ifdef LFS_QUOTA2
37384d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
37484d9c625SLionel Sambuc struct quotaval *qv = args->u.get.qc_val;
37584d9c625SLionel Sambuc error = lfsquota2_handle_cmd_get(ump, qk, qv);
37684d9c625SLionel Sambuc } else
37784d9c625SLionel Sambuc #endif
37884d9c625SLionel Sambuc panic("quota_handle_cmd_get: no support ?");
37984d9c625SLionel Sambuc
38084d9c625SLionel Sambuc if (error != 0)
38184d9c625SLionel Sambuc return error;
38284d9c625SLionel Sambuc
38384d9c625SLionel Sambuc return error;
38484d9c625SLionel Sambuc }
38584d9c625SLionel Sambuc
38684d9c625SLionel Sambuc static int
quota_handle_cmd_put(struct mount * mp,struct lwp * l,struct quotactl_args * args)38784d9c625SLionel Sambuc quota_handle_cmd_put(struct mount *mp, struct lwp *l,
38884d9c625SLionel Sambuc struct quotactl_args *args)
38984d9c625SLionel Sambuc {
39084d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
39184d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
39284d9c625SLionel Sambuc const struct quotakey *qk;
39384d9c625SLionel Sambuc id_t kauth_id;
39484d9c625SLionel Sambuc int error;
39584d9c625SLionel Sambuc
39684d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_PUT);
39784d9c625SLionel Sambuc qk = args->u.put.qc_key;
39884d9c625SLionel Sambuc
39984d9c625SLionel Sambuc if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0)
40084d9c625SLionel Sambuc return EOPNOTSUPP;
40184d9c625SLionel Sambuc
40284d9c625SLionel Sambuc kauth_id = qk->qk_id;
40384d9c625SLionel Sambuc if (kauth_id == QUOTA_DEFAULTID) {
40484d9c625SLionel Sambuc kauth_id = 0;
40584d9c625SLionel Sambuc }
40684d9c625SLionel Sambuc
40784d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
40884d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
40984d9c625SLionel Sambuc NULL);
41084d9c625SLionel Sambuc if (error != 0) {
41184d9c625SLionel Sambuc return error;
41284d9c625SLionel Sambuc }
41384d9c625SLionel Sambuc
41484d9c625SLionel Sambuc #ifdef LFS_QUOTA
41584d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA) {
41684d9c625SLionel Sambuc const struct quotaval *qv = args->u.put.qc_val;
41784d9c625SLionel Sambuc error = lfsquota1_handle_cmd_put(ump, qk, qv);
41884d9c625SLionel Sambuc } else
41984d9c625SLionel Sambuc #endif
42084d9c625SLionel Sambuc #ifdef LFS_QUOTA2
42184d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
42284d9c625SLionel Sambuc const struct quotaval *qv = args->u.put.qc_val;
42384d9c625SLionel Sambuc error = lfsquota2_handle_cmd_put(ump, qk, qv);
42484d9c625SLionel Sambuc } else
42584d9c625SLionel Sambuc #endif
42684d9c625SLionel Sambuc panic("quota_handle_cmd_get: no support ?");
42784d9c625SLionel Sambuc
42884d9c625SLionel Sambuc if (error == ENOENT) {
42984d9c625SLionel Sambuc error = 0;
43084d9c625SLionel Sambuc }
43184d9c625SLionel Sambuc
43284d9c625SLionel Sambuc return error;
43384d9c625SLionel Sambuc }
43484d9c625SLionel Sambuc
43584d9c625SLionel Sambuc static int
quota_handle_cmd_del(struct mount * mp,struct lwp * l,struct quotactl_args * args)436*0a6a1f1dSLionel Sambuc quota_handle_cmd_del(struct mount *mp, struct lwp *l,
43784d9c625SLionel Sambuc struct quotactl_args *args)
43884d9c625SLionel Sambuc {
43984d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
44084d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
44184d9c625SLionel Sambuc const struct quotakey *qk;
44284d9c625SLionel Sambuc id_t kauth_id;
44384d9c625SLionel Sambuc int error;
44484d9c625SLionel Sambuc
445*0a6a1f1dSLionel Sambuc KASSERT(args->qc_op == QUOTACTL_DEL);
446*0a6a1f1dSLionel Sambuc qk = args->u.del.qc_key;
44784d9c625SLionel Sambuc
44884d9c625SLionel Sambuc kauth_id = qk->qk_id;
44984d9c625SLionel Sambuc if (kauth_id == QUOTA_DEFAULTID) {
45084d9c625SLionel Sambuc kauth_id = 0;
45184d9c625SLionel Sambuc }
45284d9c625SLionel Sambuc
45384d9c625SLionel Sambuc if ((fs->um_flags & ULFS_QUOTA2) == 0)
45484d9c625SLionel Sambuc return EOPNOTSUPP;
45584d9c625SLionel Sambuc
45684d9c625SLionel Sambuc /* avoid whitespace changes */
45784d9c625SLionel Sambuc {
45884d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
45984d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
46084d9c625SLionel Sambuc NULL);
46184d9c625SLionel Sambuc if (error != 0)
46284d9c625SLionel Sambuc goto err;
46384d9c625SLionel Sambuc #ifdef LFS_QUOTA2
46484d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
465*0a6a1f1dSLionel Sambuc error = lfsquota2_handle_cmd_del(ump, qk);
46684d9c625SLionel Sambuc } else
46784d9c625SLionel Sambuc #endif
46884d9c625SLionel Sambuc panic("quota_handle_cmd_get: no support ?");
46984d9c625SLionel Sambuc
47084d9c625SLionel Sambuc if (error && error != ENOENT)
47184d9c625SLionel Sambuc goto err;
47284d9c625SLionel Sambuc }
47384d9c625SLionel Sambuc
47484d9c625SLionel Sambuc return 0;
47584d9c625SLionel Sambuc err:
47684d9c625SLionel Sambuc return error;
47784d9c625SLionel Sambuc }
47884d9c625SLionel Sambuc
47984d9c625SLionel Sambuc static int
quota_handle_cmd_cursorget(struct mount * mp,struct lwp * l,struct quotactl_args * args)48084d9c625SLionel Sambuc quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l,
48184d9c625SLionel Sambuc struct quotactl_args *args)
48284d9c625SLionel Sambuc {
48384d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
48484d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
48584d9c625SLionel Sambuc int error;
48684d9c625SLionel Sambuc
48784d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_CURSORGET);
48884d9c625SLionel Sambuc
48984d9c625SLionel Sambuc if ((fs->um_flags & ULFS_QUOTA2) == 0)
49084d9c625SLionel Sambuc return EOPNOTSUPP;
49184d9c625SLionel Sambuc
49284d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
49384d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
49484d9c625SLionel Sambuc if (error)
49584d9c625SLionel Sambuc return error;
49684d9c625SLionel Sambuc
49784d9c625SLionel Sambuc #ifdef LFS_QUOTA2
49884d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
49984d9c625SLionel Sambuc struct quotakcursor *cursor = args->u.cursorget.qc_cursor;
50084d9c625SLionel Sambuc struct quotakey *keys = args->u.cursorget.qc_keys;
50184d9c625SLionel Sambuc struct quotaval *vals = args->u.cursorget.qc_vals;
50284d9c625SLionel Sambuc unsigned maxnum = args->u.cursorget.qc_maxnum;
50384d9c625SLionel Sambuc unsigned *ret = args->u.cursorget.qc_ret;
50484d9c625SLionel Sambuc
50584d9c625SLionel Sambuc error = lfsquota2_handle_cmd_cursorget(ump, cursor, keys, vals,
50684d9c625SLionel Sambuc maxnum, ret);
50784d9c625SLionel Sambuc } else
50884d9c625SLionel Sambuc #endif
50984d9c625SLionel Sambuc panic("quota_handle_cmd_cursorget: no support ?");
51084d9c625SLionel Sambuc
51184d9c625SLionel Sambuc return error;
51284d9c625SLionel Sambuc }
51384d9c625SLionel Sambuc
51484d9c625SLionel Sambuc static int
quota_handle_cmd_cursoropen(struct mount * mp,struct lwp * l,struct quotactl_args * args)51584d9c625SLionel Sambuc quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l,
51684d9c625SLionel Sambuc struct quotactl_args *args)
51784d9c625SLionel Sambuc {
51884d9c625SLionel Sambuc #ifdef LFS_QUOTA2
51984d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
52084d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
52184d9c625SLionel Sambuc struct quotakcursor *cursor;
52284d9c625SLionel Sambuc #endif
52384d9c625SLionel Sambuc int error;
52484d9c625SLionel Sambuc
52584d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_CURSOROPEN);
52684d9c625SLionel Sambuc
52784d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
52884d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
52984d9c625SLionel Sambuc if (error)
53084d9c625SLionel Sambuc return error;
53184d9c625SLionel Sambuc
53284d9c625SLionel Sambuc #ifdef LFS_QUOTA2
53384d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
53484d9c625SLionel Sambuc cursor = args->u.cursoropen.qc_cursor;
53584d9c625SLionel Sambuc error = lfsquota2_handle_cmd_cursoropen(ump, cursor);
53684d9c625SLionel Sambuc } else
53784d9c625SLionel Sambuc #endif
53884d9c625SLionel Sambuc error = EOPNOTSUPP;
53984d9c625SLionel Sambuc
54084d9c625SLionel Sambuc return error;
54184d9c625SLionel Sambuc }
54284d9c625SLionel Sambuc
54384d9c625SLionel Sambuc static int
quota_handle_cmd_cursorclose(struct mount * mp,struct lwp * l,struct quotactl_args * args)54484d9c625SLionel Sambuc quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l,
54584d9c625SLionel Sambuc struct quotactl_args *args)
54684d9c625SLionel Sambuc {
54784d9c625SLionel Sambuc #ifdef LFS_QUOTA2
54884d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
54984d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
55084d9c625SLionel Sambuc #endif
55184d9c625SLionel Sambuc int error;
55284d9c625SLionel Sambuc
55384d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_CURSORCLOSE);
55484d9c625SLionel Sambuc
55584d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
55684d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
55784d9c625SLionel Sambuc if (error)
55884d9c625SLionel Sambuc return error;
55984d9c625SLionel Sambuc
56084d9c625SLionel Sambuc #ifdef LFS_QUOTA2
56184d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
56284d9c625SLionel Sambuc struct quotakcursor *cursor = args->u.cursorclose.qc_cursor;
56384d9c625SLionel Sambuc error = lfsquota2_handle_cmd_cursorclose(ump, cursor);
56484d9c625SLionel Sambuc } else
56584d9c625SLionel Sambuc #endif
56684d9c625SLionel Sambuc error = EOPNOTSUPP;
56784d9c625SLionel Sambuc
56884d9c625SLionel Sambuc return error;
56984d9c625SLionel Sambuc }
57084d9c625SLionel Sambuc
57184d9c625SLionel Sambuc static int
quota_handle_cmd_cursorskipidtype(struct mount * mp,struct lwp * l,struct quotactl_args * args)57284d9c625SLionel Sambuc quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l,
57384d9c625SLionel Sambuc struct quotactl_args *args)
57484d9c625SLionel Sambuc {
57584d9c625SLionel Sambuc #ifdef LFS_QUOTA2
57684d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
57784d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
57884d9c625SLionel Sambuc #endif
57984d9c625SLionel Sambuc int error;
58084d9c625SLionel Sambuc
58184d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_CURSORSKIPIDTYPE);
58284d9c625SLionel Sambuc
58384d9c625SLionel Sambuc #ifdef LFS_QUOTA2
58484d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
58584d9c625SLionel Sambuc struct quotakcursor *cursor = args->u.cursorskipidtype.qc_cursor;
58684d9c625SLionel Sambuc int idtype = args->u.cursorskipidtype.qc_idtype;
58784d9c625SLionel Sambuc error = lfsquota2_handle_cmd_cursorskipidtype(ump, cursor, idtype);
58884d9c625SLionel Sambuc } else
58984d9c625SLionel Sambuc #endif
59084d9c625SLionel Sambuc error = EOPNOTSUPP;
59184d9c625SLionel Sambuc
59284d9c625SLionel Sambuc return error;
59384d9c625SLionel Sambuc }
59484d9c625SLionel Sambuc
59584d9c625SLionel Sambuc static int
quota_handle_cmd_cursoratend(struct mount * mp,struct lwp * l,struct quotactl_args * args)59684d9c625SLionel Sambuc quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l,
59784d9c625SLionel Sambuc struct quotactl_args *args)
59884d9c625SLionel Sambuc {
59984d9c625SLionel Sambuc #ifdef LFS_QUOTA2
60084d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
60184d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
60284d9c625SLionel Sambuc #endif
60384d9c625SLionel Sambuc int error;
60484d9c625SLionel Sambuc
60584d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_CURSORATEND);
60684d9c625SLionel Sambuc
60784d9c625SLionel Sambuc #ifdef LFS_QUOTA2
60884d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
60984d9c625SLionel Sambuc struct quotakcursor *cursor = args->u.cursoratend.qc_cursor;
61084d9c625SLionel Sambuc int *ret = args->u.cursoratend.qc_ret;
61184d9c625SLionel Sambuc error = lfsquota2_handle_cmd_cursoratend(ump, cursor, ret);
61284d9c625SLionel Sambuc } else
61384d9c625SLionel Sambuc #endif
61484d9c625SLionel Sambuc error = EOPNOTSUPP;
61584d9c625SLionel Sambuc
61684d9c625SLionel Sambuc return error;
61784d9c625SLionel Sambuc }
61884d9c625SLionel Sambuc
61984d9c625SLionel Sambuc static int
quota_handle_cmd_cursorrewind(struct mount * mp,struct lwp * l,struct quotactl_args * args)62084d9c625SLionel Sambuc quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l,
62184d9c625SLionel Sambuc struct quotactl_args *args)
62284d9c625SLionel Sambuc {
62384d9c625SLionel Sambuc #ifdef LFS_QUOTA2
62484d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
62584d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
62684d9c625SLionel Sambuc #endif
62784d9c625SLionel Sambuc int error;
62884d9c625SLionel Sambuc
62984d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_CURSORREWIND);
63084d9c625SLionel Sambuc
63184d9c625SLionel Sambuc #ifdef LFS_QUOTA2
63284d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
63384d9c625SLionel Sambuc struct quotakcursor *cursor = args->u.cursorrewind.qc_cursor;
63484d9c625SLionel Sambuc error = lfsquota2_handle_cmd_cursorrewind(ump, cursor);
63584d9c625SLionel Sambuc } else
63684d9c625SLionel Sambuc #endif
63784d9c625SLionel Sambuc error = EOPNOTSUPP;
63884d9c625SLionel Sambuc
63984d9c625SLionel Sambuc return error;
64084d9c625SLionel Sambuc }
64184d9c625SLionel Sambuc
64284d9c625SLionel Sambuc static int
quota_handle_cmd_quotaon(struct mount * mp,struct lwp * l,struct quotactl_args * args)64384d9c625SLionel Sambuc quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
64484d9c625SLionel Sambuc struct quotactl_args *args)
64584d9c625SLionel Sambuc {
64684d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
64784d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
64884d9c625SLionel Sambuc int error;
64984d9c625SLionel Sambuc
65084d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_QUOTAON);
65184d9c625SLionel Sambuc
65284d9c625SLionel Sambuc if ((fs->um_flags & ULFS_QUOTA2) != 0)
65384d9c625SLionel Sambuc return EBUSY;
65484d9c625SLionel Sambuc
65584d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
65684d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
65784d9c625SLionel Sambuc if (error != 0) {
65884d9c625SLionel Sambuc return error;
65984d9c625SLionel Sambuc }
66084d9c625SLionel Sambuc #ifdef LFS_QUOTA
66184d9c625SLionel Sambuc int idtype = args->u.quotaon.qc_idtype;
66284d9c625SLionel Sambuc const char *qfile = args->u.quotaon.qc_quotafile;
66384d9c625SLionel Sambuc error = lfsquota1_handle_cmd_quotaon(l, ump, idtype, qfile);
66484d9c625SLionel Sambuc #else
66584d9c625SLionel Sambuc error = EOPNOTSUPP;
66684d9c625SLionel Sambuc #endif
66784d9c625SLionel Sambuc
66884d9c625SLionel Sambuc return error;
66984d9c625SLionel Sambuc }
67084d9c625SLionel Sambuc
67184d9c625SLionel Sambuc static int
quota_handle_cmd_quotaoff(struct mount * mp,struct lwp * l,struct quotactl_args * args)67284d9c625SLionel Sambuc quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
67384d9c625SLionel Sambuc struct quotactl_args *args)
67484d9c625SLionel Sambuc {
67584d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
67684d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
67784d9c625SLionel Sambuc int error;
67884d9c625SLionel Sambuc
67984d9c625SLionel Sambuc KASSERT(args->qc_op == QUOTACTL_QUOTAOFF);
68084d9c625SLionel Sambuc
68184d9c625SLionel Sambuc if ((fs->um_flags & ULFS_QUOTA2) != 0)
68284d9c625SLionel Sambuc return EOPNOTSUPP;
68384d9c625SLionel Sambuc
68484d9c625SLionel Sambuc error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
68584d9c625SLionel Sambuc KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
68684d9c625SLionel Sambuc if (error != 0) {
68784d9c625SLionel Sambuc return error;
68884d9c625SLionel Sambuc }
68984d9c625SLionel Sambuc #ifdef LFS_QUOTA
69084d9c625SLionel Sambuc int idtype = args->u.quotaoff.qc_idtype;
69184d9c625SLionel Sambuc error = lfsquota1_handle_cmd_quotaoff(l, ump, idtype);
69284d9c625SLionel Sambuc #else
69384d9c625SLionel Sambuc error = EOPNOTSUPP;
69484d9c625SLionel Sambuc #endif
69584d9c625SLionel Sambuc
69684d9c625SLionel Sambuc return error;
69784d9c625SLionel Sambuc }
69884d9c625SLionel Sambuc
69984d9c625SLionel Sambuc /*
70084d9c625SLionel Sambuc * Initialize the quota system.
70184d9c625SLionel Sambuc */
70284d9c625SLionel Sambuc void
lfs_dqinit(void)70384d9c625SLionel Sambuc lfs_dqinit(void)
70484d9c625SLionel Sambuc {
70584d9c625SLionel Sambuc
70684d9c625SLionel Sambuc mutex_init(&lfs_dqlock, MUTEX_DEFAULT, IPL_NONE);
70784d9c625SLionel Sambuc cv_init(&lfs_dqcv, "quota");
70884d9c625SLionel Sambuc dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
70984d9c625SLionel Sambuc dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "lfsdq",
71084d9c625SLionel Sambuc NULL, IPL_NONE, NULL, NULL, NULL);
71184d9c625SLionel Sambuc }
71284d9c625SLionel Sambuc
71384d9c625SLionel Sambuc void
lfs_dqreinit(void)71484d9c625SLionel Sambuc lfs_dqreinit(void)
71584d9c625SLionel Sambuc {
71684d9c625SLionel Sambuc struct dquot *dq;
71784d9c625SLionel Sambuc struct dqhashhead *oldhash, *hash;
71884d9c625SLionel Sambuc struct vnode *dqvp;
71984d9c625SLionel Sambuc u_long oldmask, mask, hashval;
72084d9c625SLionel Sambuc int i;
72184d9c625SLionel Sambuc
72284d9c625SLionel Sambuc hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
72384d9c625SLionel Sambuc mutex_enter(&lfs_dqlock);
72484d9c625SLionel Sambuc oldhash = dqhashtbl;
72584d9c625SLionel Sambuc oldmask = dqhash;
72684d9c625SLionel Sambuc dqhashtbl = hash;
72784d9c625SLionel Sambuc dqhash = mask;
72884d9c625SLionel Sambuc for (i = 0; i <= oldmask; i++) {
72984d9c625SLionel Sambuc while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
73084d9c625SLionel Sambuc dqvp = dq->dq_ump->um_quotas[dq->dq_type];
73184d9c625SLionel Sambuc LIST_REMOVE(dq, dq_hash);
73284d9c625SLionel Sambuc hashval = DQHASH(dqvp, dq->dq_id);
73384d9c625SLionel Sambuc LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
73484d9c625SLionel Sambuc }
73584d9c625SLionel Sambuc }
73684d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
73784d9c625SLionel Sambuc hashdone(oldhash, HASH_LIST, oldmask);
73884d9c625SLionel Sambuc }
73984d9c625SLionel Sambuc
74084d9c625SLionel Sambuc /*
74184d9c625SLionel Sambuc * Free resources held by quota system.
74284d9c625SLionel Sambuc */
74384d9c625SLionel Sambuc void
lfs_dqdone(void)74484d9c625SLionel Sambuc lfs_dqdone(void)
74584d9c625SLionel Sambuc {
74684d9c625SLionel Sambuc
74784d9c625SLionel Sambuc pool_cache_destroy(dquot_cache);
74884d9c625SLionel Sambuc hashdone(dqhashtbl, HASH_LIST, dqhash);
74984d9c625SLionel Sambuc cv_destroy(&lfs_dqcv);
75084d9c625SLionel Sambuc mutex_destroy(&lfs_dqlock);
75184d9c625SLionel Sambuc }
75284d9c625SLionel Sambuc
75384d9c625SLionel Sambuc /*
75484d9c625SLionel Sambuc * Set up the quotas for an inode.
75584d9c625SLionel Sambuc *
75684d9c625SLionel Sambuc * This routine completely defines the semantics of quotas.
75784d9c625SLionel Sambuc * If other criteria want to be used to establish quotas, the
75884d9c625SLionel Sambuc * ULFS_MAXQUOTAS value in quotas.h should be increased, and the
75984d9c625SLionel Sambuc * additional dquots set up here.
76084d9c625SLionel Sambuc */
76184d9c625SLionel Sambuc int
lfs_getinoquota(struct inode * ip)76284d9c625SLionel Sambuc lfs_getinoquota(struct inode *ip)
76384d9c625SLionel Sambuc {
76484d9c625SLionel Sambuc struct ulfsmount *ump = ip->i_ump;
76584d9c625SLionel Sambuc //struct lfs *fs = ump->um_lfs; // notyet
76684d9c625SLionel Sambuc struct vnode *vp = ITOV(ip);
76784d9c625SLionel Sambuc int i, error;
76884d9c625SLionel Sambuc u_int32_t ino_ids[ULFS_MAXQUOTAS];
76984d9c625SLionel Sambuc
77084d9c625SLionel Sambuc /*
77184d9c625SLionel Sambuc * To avoid deadlocks never update quotas for quota files
77284d9c625SLionel Sambuc * on the same file system
77384d9c625SLionel Sambuc */
77484d9c625SLionel Sambuc for (i = 0; i < ULFS_MAXQUOTAS; i++)
77584d9c625SLionel Sambuc if (vp == ump->um_quotas[i])
77684d9c625SLionel Sambuc return 0;
77784d9c625SLionel Sambuc
77884d9c625SLionel Sambuc ino_ids[ULFS_USRQUOTA] = ip->i_uid;
77984d9c625SLionel Sambuc ino_ids[ULFS_GRPQUOTA] = ip->i_gid;
78084d9c625SLionel Sambuc for (i = 0; i < ULFS_MAXQUOTAS; i++) {
78184d9c625SLionel Sambuc /*
78284d9c625SLionel Sambuc * If the file id changed the quota needs update.
78384d9c625SLionel Sambuc */
78484d9c625SLionel Sambuc if (ip->i_dquot[i] != NODQUOT &&
78584d9c625SLionel Sambuc ip->i_dquot[i]->dq_id != ino_ids[i]) {
78684d9c625SLionel Sambuc lfs_dqrele(ITOV(ip), ip->i_dquot[i]);
78784d9c625SLionel Sambuc ip->i_dquot[i] = NODQUOT;
78884d9c625SLionel Sambuc }
78984d9c625SLionel Sambuc /*
79084d9c625SLionel Sambuc * Set up the quota based on file id.
79184d9c625SLionel Sambuc * ENODEV means that quotas are not enabled.
79284d9c625SLionel Sambuc */
79384d9c625SLionel Sambuc if (ip->i_dquot[i] == NODQUOT &&
79484d9c625SLionel Sambuc (error = lfs_dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
79584d9c625SLionel Sambuc error != ENODEV)
79684d9c625SLionel Sambuc return (error);
79784d9c625SLionel Sambuc }
79884d9c625SLionel Sambuc return 0;
79984d9c625SLionel Sambuc }
80084d9c625SLionel Sambuc
80184d9c625SLionel Sambuc /*
80284d9c625SLionel Sambuc * Obtain a dquot structure for the specified identifier and quota file
80384d9c625SLionel Sambuc * reading the information from the file if necessary.
80484d9c625SLionel Sambuc */
80584d9c625SLionel Sambuc int
lfs_dqget(struct vnode * vp,u_long id,struct ulfsmount * ump,int type,struct dquot ** dqp)80684d9c625SLionel Sambuc lfs_dqget(struct vnode *vp, u_long id, struct ulfsmount *ump, int type,
80784d9c625SLionel Sambuc struct dquot **dqp)
80884d9c625SLionel Sambuc {
80984d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
81084d9c625SLionel Sambuc struct dquot *dq, *ndq;
81184d9c625SLionel Sambuc struct dqhashhead *dqh;
81284d9c625SLionel Sambuc struct vnode *dqvp;
81384d9c625SLionel Sambuc int error = 0; /* XXX gcc */
81484d9c625SLionel Sambuc
81584d9c625SLionel Sambuc /* Lock to see an up to date value for QTF_CLOSING. */
81684d9c625SLionel Sambuc mutex_enter(&lfs_dqlock);
81784d9c625SLionel Sambuc if ((fs->um_flags & (ULFS_QUOTA|ULFS_QUOTA2)) == 0) {
81884d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
81984d9c625SLionel Sambuc *dqp = NODQUOT;
82084d9c625SLionel Sambuc return (ENODEV);
82184d9c625SLionel Sambuc }
82284d9c625SLionel Sambuc dqvp = ump->um_quotas[type];
82384d9c625SLionel Sambuc #ifdef LFS_QUOTA
82484d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA) {
82584d9c625SLionel Sambuc if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
82684d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
82784d9c625SLionel Sambuc *dqp = NODQUOT;
82884d9c625SLionel Sambuc return (ENODEV);
82984d9c625SLionel Sambuc }
83084d9c625SLionel Sambuc }
83184d9c625SLionel Sambuc #endif
83284d9c625SLionel Sambuc #ifdef LFS_QUOTA2
83384d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2) {
83484d9c625SLionel Sambuc if (dqvp == NULLVP) {
83584d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
83684d9c625SLionel Sambuc *dqp = NODQUOT;
83784d9c625SLionel Sambuc return (ENODEV);
83884d9c625SLionel Sambuc }
83984d9c625SLionel Sambuc }
84084d9c625SLionel Sambuc #endif
84184d9c625SLionel Sambuc KASSERT(dqvp != vp);
84284d9c625SLionel Sambuc /*
84384d9c625SLionel Sambuc * Check the cache first.
84484d9c625SLionel Sambuc */
84584d9c625SLionel Sambuc dqh = &dqhashtbl[DQHASH(dqvp, id)];
84684d9c625SLionel Sambuc LIST_FOREACH(dq, dqh, dq_hash) {
84784d9c625SLionel Sambuc if (dq->dq_id != id ||
84884d9c625SLionel Sambuc dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
84984d9c625SLionel Sambuc continue;
85084d9c625SLionel Sambuc KASSERT(dq->dq_cnt > 0);
85184d9c625SLionel Sambuc lfs_dqref(dq);
85284d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
85384d9c625SLionel Sambuc *dqp = dq;
85484d9c625SLionel Sambuc return (0);
85584d9c625SLionel Sambuc }
85684d9c625SLionel Sambuc /*
85784d9c625SLionel Sambuc * Not in cache, allocate a new one.
85884d9c625SLionel Sambuc */
85984d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
86084d9c625SLionel Sambuc ndq = pool_cache_get(dquot_cache, PR_WAITOK);
86184d9c625SLionel Sambuc /*
86284d9c625SLionel Sambuc * Initialize the contents of the dquot structure.
86384d9c625SLionel Sambuc */
86484d9c625SLionel Sambuc memset((char *)ndq, 0, sizeof *ndq);
86584d9c625SLionel Sambuc ndq->dq_flags = 0;
86684d9c625SLionel Sambuc ndq->dq_id = id;
86784d9c625SLionel Sambuc ndq->dq_ump = ump;
86884d9c625SLionel Sambuc ndq->dq_type = type;
86984d9c625SLionel Sambuc mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
87084d9c625SLionel Sambuc mutex_enter(&lfs_dqlock);
87184d9c625SLionel Sambuc dqh = &dqhashtbl[DQHASH(dqvp, id)];
87284d9c625SLionel Sambuc LIST_FOREACH(dq, dqh, dq_hash) {
87384d9c625SLionel Sambuc if (dq->dq_id != id ||
87484d9c625SLionel Sambuc dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
87584d9c625SLionel Sambuc continue;
87684d9c625SLionel Sambuc /*
87784d9c625SLionel Sambuc * Another thread beat us allocating this dquot.
87884d9c625SLionel Sambuc */
87984d9c625SLionel Sambuc KASSERT(dq->dq_cnt > 0);
88084d9c625SLionel Sambuc lfs_dqref(dq);
88184d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
88284d9c625SLionel Sambuc mutex_destroy(&ndq->dq_interlock);
88384d9c625SLionel Sambuc pool_cache_put(dquot_cache, ndq);
88484d9c625SLionel Sambuc *dqp = dq;
88584d9c625SLionel Sambuc return 0;
88684d9c625SLionel Sambuc }
88784d9c625SLionel Sambuc dq = ndq;
88884d9c625SLionel Sambuc LIST_INSERT_HEAD(dqh, dq, dq_hash);
88984d9c625SLionel Sambuc lfs_dqref(dq);
89084d9c625SLionel Sambuc mutex_enter(&dq->dq_interlock);
89184d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
89284d9c625SLionel Sambuc #ifdef LFS_QUOTA
89384d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA)
89484d9c625SLionel Sambuc error = lfs_dq1get(dqvp, id, ump, type, dq);
89584d9c625SLionel Sambuc #endif
89684d9c625SLionel Sambuc #ifdef LFS_QUOTA2
89784d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2)
89884d9c625SLionel Sambuc error = lfs_dq2get(dqvp, id, ump, type, dq);
89984d9c625SLionel Sambuc #endif
90084d9c625SLionel Sambuc /*
90184d9c625SLionel Sambuc * I/O error in reading quota file, release
90284d9c625SLionel Sambuc * quota structure and reflect problem to caller.
90384d9c625SLionel Sambuc */
90484d9c625SLionel Sambuc if (error) {
90584d9c625SLionel Sambuc mutex_enter(&lfs_dqlock);
90684d9c625SLionel Sambuc LIST_REMOVE(dq, dq_hash);
90784d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
90884d9c625SLionel Sambuc mutex_exit(&dq->dq_interlock);
90984d9c625SLionel Sambuc lfs_dqrele(vp, dq);
91084d9c625SLionel Sambuc *dqp = NODQUOT;
91184d9c625SLionel Sambuc return (error);
91284d9c625SLionel Sambuc }
91384d9c625SLionel Sambuc mutex_exit(&dq->dq_interlock);
91484d9c625SLionel Sambuc *dqp = dq;
91584d9c625SLionel Sambuc return (0);
91684d9c625SLionel Sambuc }
91784d9c625SLionel Sambuc
91884d9c625SLionel Sambuc /*
91984d9c625SLionel Sambuc * Obtain a reference to a dquot.
92084d9c625SLionel Sambuc */
92184d9c625SLionel Sambuc void
lfs_dqref(struct dquot * dq)92284d9c625SLionel Sambuc lfs_dqref(struct dquot *dq)
92384d9c625SLionel Sambuc {
92484d9c625SLionel Sambuc
92584d9c625SLionel Sambuc KASSERT(mutex_owned(&lfs_dqlock));
92684d9c625SLionel Sambuc dq->dq_cnt++;
92784d9c625SLionel Sambuc KASSERT(dq->dq_cnt > 0);
92884d9c625SLionel Sambuc }
92984d9c625SLionel Sambuc
93084d9c625SLionel Sambuc /*
93184d9c625SLionel Sambuc * Release a reference to a dquot.
93284d9c625SLionel Sambuc */
93384d9c625SLionel Sambuc void
lfs_dqrele(struct vnode * vp,struct dquot * dq)93484d9c625SLionel Sambuc lfs_dqrele(struct vnode *vp, struct dquot *dq)
93584d9c625SLionel Sambuc {
93684d9c625SLionel Sambuc
93784d9c625SLionel Sambuc if (dq == NODQUOT)
93884d9c625SLionel Sambuc return;
93984d9c625SLionel Sambuc mutex_enter(&dq->dq_interlock);
94084d9c625SLionel Sambuc for (;;) {
94184d9c625SLionel Sambuc mutex_enter(&lfs_dqlock);
94284d9c625SLionel Sambuc if (dq->dq_cnt > 1) {
94384d9c625SLionel Sambuc dq->dq_cnt--;
94484d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
94584d9c625SLionel Sambuc mutex_exit(&dq->dq_interlock);
94684d9c625SLionel Sambuc return;
94784d9c625SLionel Sambuc }
94884d9c625SLionel Sambuc if ((dq->dq_flags & DQ_MOD) == 0)
94984d9c625SLionel Sambuc break;
95084d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
95184d9c625SLionel Sambuc #ifdef LFS_QUOTA
95284d9c625SLionel Sambuc if (dq->dq_ump->um_lfs->um_flags & ULFS_QUOTA)
95384d9c625SLionel Sambuc (void) lfs_dq1sync(vp, dq);
95484d9c625SLionel Sambuc #endif
95584d9c625SLionel Sambuc #ifdef LFS_QUOTA2
95684d9c625SLionel Sambuc if (dq->dq_ump->um_lfs->um_flags & ULFS_QUOTA2)
95784d9c625SLionel Sambuc (void) lfs_dq2sync(vp, dq);
95884d9c625SLionel Sambuc #endif
95984d9c625SLionel Sambuc }
96084d9c625SLionel Sambuc KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
96184d9c625SLionel Sambuc LIST_REMOVE(dq, dq_hash);
96284d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
96384d9c625SLionel Sambuc mutex_exit(&dq->dq_interlock);
96484d9c625SLionel Sambuc mutex_destroy(&dq->dq_interlock);
96584d9c625SLionel Sambuc pool_cache_put(dquot_cache, dq);
96684d9c625SLionel Sambuc }
96784d9c625SLionel Sambuc
96884d9c625SLionel Sambuc int
lfs_qsync(struct mount * mp)96984d9c625SLionel Sambuc lfs_qsync(struct mount *mp)
97084d9c625SLionel Sambuc {
97184d9c625SLionel Sambuc struct ulfsmount *ump = VFSTOULFS(mp);
97284d9c625SLionel Sambuc struct lfs *fs = ump->um_lfs;
97384d9c625SLionel Sambuc
97484d9c625SLionel Sambuc /* avoid compiler warning when quotas aren't enabled */
97584d9c625SLionel Sambuc (void)ump;
97684d9c625SLionel Sambuc (void)fs;
97784d9c625SLionel Sambuc
97884d9c625SLionel Sambuc #ifdef LFS_QUOTA
97984d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA)
98084d9c625SLionel Sambuc return lfs_q1sync(mp);
98184d9c625SLionel Sambuc #endif
98284d9c625SLionel Sambuc #ifdef LFS_QUOTA2
98384d9c625SLionel Sambuc if (fs->um_flags & ULFS_QUOTA2)
98484d9c625SLionel Sambuc return lfs_q2sync(mp);
98584d9c625SLionel Sambuc #endif
98684d9c625SLionel Sambuc return 0;
98784d9c625SLionel Sambuc }
98884d9c625SLionel Sambuc
98984d9c625SLionel Sambuc #ifdef DIAGNOSTIC
99084d9c625SLionel Sambuc /*
99184d9c625SLionel Sambuc * Check the hash chains for stray dquot's.
99284d9c625SLionel Sambuc */
99384d9c625SLionel Sambuc void
lfs_dqflush(struct vnode * vp)99484d9c625SLionel Sambuc lfs_dqflush(struct vnode *vp)
99584d9c625SLionel Sambuc {
99684d9c625SLionel Sambuc struct dquot *dq;
99784d9c625SLionel Sambuc int i;
99884d9c625SLionel Sambuc
99984d9c625SLionel Sambuc mutex_enter(&lfs_dqlock);
100084d9c625SLionel Sambuc for (i = 0; i <= dqhash; i++)
100184d9c625SLionel Sambuc LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
100284d9c625SLionel Sambuc KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
100384d9c625SLionel Sambuc mutex_exit(&lfs_dqlock);
100484d9c625SLionel Sambuc }
100584d9c625SLionel Sambuc #endif
1006