| @@ -1,927 +1,899 @@ | | | @@ -1,927 +1,899 @@ |
1 | /* $NetBSD: ufs_quota.c,v 1.72 2012/01/29 06:36:07 dholland Exp $ */ | | 1 | /* $NetBSD: ufs_quota.c,v 1.73 2012/01/29 06:36:51 dholland Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | | 4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Robert Elz at The University of Melbourne. | | 8 | * Robert Elz at The University of Melbourne. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors | | 18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software | | 19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | | 20 | * without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | * | | 33 | * |
34 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | | 34 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.72 2012/01/29 06:36:07 dholland Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.73 2012/01/29 06:36:51 dholland Exp $"); |
39 | | | 39 | |
40 | #if defined(_KERNEL_OPT) | | 40 | #if defined(_KERNEL_OPT) |
41 | #include "opt_quota.h" | | 41 | #include "opt_quota.h" |
42 | #endif | | 42 | #endif |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <sys/kernel.h> | | 44 | #include <sys/kernel.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | #include <sys/namei.h> | | 46 | #include <sys/namei.h> |
47 | #include <sys/file.h> | | 47 | #include <sys/file.h> |
48 | #include <sys/proc.h> | | 48 | #include <sys/proc.h> |
49 | #include <sys/vnode.h> | | 49 | #include <sys/vnode.h> |
50 | #include <sys/mount.h> | | 50 | #include <sys/mount.h> |
51 | #include <sys/kauth.h> | | 51 | #include <sys/kauth.h> |
52 | | | 52 | |
53 | #include <sys/quotactl.h> | | 53 | #include <sys/quotactl.h> |
54 | #include <ufs/ufs/quota.h> | | 54 | #include <ufs/ufs/quota.h> |
55 | #include <ufs/ufs/inode.h> | | 55 | #include <ufs/ufs/inode.h> |
56 | #include <ufs/ufs/ufsmount.h> | | 56 | #include <ufs/ufs/ufsmount.h> |
57 | #include <ufs/ufs/ufs_extern.h> | | 57 | #include <ufs/ufs/ufs_extern.h> |
58 | #include <ufs/ufs/ufs_quota.h> | | 58 | #include <ufs/ufs/ufs_quota.h> |
59 | #include <quota/quotaprop.h> | | 59 | #include <quota/quotaprop.h> |
60 | | | 60 | |
61 | kmutex_t dqlock; | | 61 | kmutex_t dqlock; |
62 | kcondvar_t dqcv; | | 62 | kcondvar_t dqcv; |
63 | | | 63 | |
64 | /* | | 64 | /* |
65 | * Code pertaining to management of the in-core dquot data structures. | | 65 | * Code pertaining to management of the in-core dquot data structures. |
66 | */ | | 66 | */ |
67 | #define DQHASH(dqvp, id) \ | | 67 | #define DQHASH(dqvp, id) \ |
68 | (((((long)(dqvp)) >> 8) + id) & dqhash) | | 68 | (((((long)(dqvp)) >> 8) + id) & dqhash) |
69 | static LIST_HEAD(dqhashhead, dquot) *dqhashtbl; | | 69 | static LIST_HEAD(dqhashhead, dquot) *dqhashtbl; |
70 | static u_long dqhash; | | 70 | static u_long dqhash; |
71 | static pool_cache_t dquot_cache; | | 71 | static pool_cache_t dquot_cache; |
72 | | | 72 | |
73 | | | 73 | |
74 | static int quota_handle_cmd_get_version(struct mount *, struct lwp *, | | 74 | static int quota_handle_cmd_get_version(struct mount *, struct lwp *, |
75 | struct vfs_quotactl_args *args); | | 75 | struct vfs_quotactl_args *args); |
76 | static int quota_handle_cmd_get(struct mount *, struct lwp *, | | 76 | static int quota_handle_cmd_get(struct mount *, struct lwp *, |
77 | struct vfs_quotactl_args *args); | | 77 | struct vfs_quotactl_args *args); |
78 | static int quota_handle_cmd_set(struct mount *, struct lwp *, | | 78 | static int quota_handle_cmd_set(struct mount *, struct lwp *, |
79 | struct vfs_quotactl_args *args); | | 79 | struct vfs_quotactl_args *args); |
80 | static int quota_handle_cmd_getall(struct mount *, struct lwp *, | | 80 | static int quota_handle_cmd_getall(struct mount *, struct lwp *, |
81 | struct vfs_quotactl_args *args); | | 81 | struct vfs_quotactl_args *args); |
82 | static int quota_handle_cmd_clear(struct mount *, struct lwp *, | | 82 | static int quota_handle_cmd_clear(struct mount *, struct lwp *, |
83 | struct vfs_quotactl_args *args); | | 83 | struct vfs_quotactl_args *args); |
84 | static int quota_handle_cmd_quotaon(struct mount *, struct lwp *, | | 84 | static int quota_handle_cmd_quotaon(struct mount *, struct lwp *, |
85 | struct vfs_quotactl_args *args); | | 85 | struct vfs_quotactl_args *args); |
86 | static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *, | | 86 | static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *, |
87 | struct vfs_quotactl_args *args); | | 87 | struct vfs_quotactl_args *args); |
88 | | | 88 | |
89 | /* | | 89 | /* |
90 | * Initialize the quota fields of an inode. | | 90 | * Initialize the quota fields of an inode. |
91 | */ | | 91 | */ |
92 | void | | 92 | void |
93 | ufsquota_init(struct inode *ip) | | 93 | ufsquota_init(struct inode *ip) |
94 | { | | 94 | { |
95 | int i; | | 95 | int i; |
96 | | | 96 | |
97 | for (i = 0; i < MAXQUOTAS; i++) | | 97 | for (i = 0; i < MAXQUOTAS; i++) |
98 | ip->i_dquot[i] = NODQUOT; | | 98 | ip->i_dquot[i] = NODQUOT; |
99 | } | | 99 | } |
100 | | | 100 | |
101 | /* | | 101 | /* |
102 | * Release the quota fields from an inode. | | 102 | * Release the quota fields from an inode. |
103 | */ | | 103 | */ |
104 | void | | 104 | void |
105 | ufsquota_free(struct inode *ip) | | 105 | ufsquota_free(struct inode *ip) |
106 | { | | 106 | { |
107 | int i; | | 107 | int i; |
108 | | | 108 | |
109 | for (i = 0; i < MAXQUOTAS; i++) { | | 109 | for (i = 0; i < MAXQUOTAS; i++) { |
110 | dqrele(ITOV(ip), ip->i_dquot[i]); | | 110 | dqrele(ITOV(ip), ip->i_dquot[i]); |
111 | ip->i_dquot[i] = NODQUOT; | | 111 | ip->i_dquot[i] = NODQUOT; |
112 | } | | 112 | } |
113 | } | | 113 | } |
114 | | | 114 | |
115 | /* | | 115 | /* |
116 | * Update disk usage, and take corrective action. | | 116 | * Update disk usage, and take corrective action. |
117 | */ | | 117 | */ |
118 | int | | 118 | int |
119 | chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | | 119 | chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) |
120 | { | | 120 | { |
121 | /* do not track snapshot usage, or we will deadlock */ | | 121 | /* do not track snapshot usage, or we will deadlock */ |
122 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | | 122 | if ((ip->i_flags & SF_SNAPSHOT) != 0) |
123 | return 0; | | 123 | return 0; |
124 | | | 124 | |
125 | #ifdef QUOTA | | 125 | #ifdef QUOTA |
126 | if (ip->i_ump->um_flags & UFS_QUOTA) | | 126 | if (ip->i_ump->um_flags & UFS_QUOTA) |
127 | return chkdq1(ip, change, cred, flags); | | 127 | return chkdq1(ip, change, cred, flags); |
128 | #endif | | 128 | #endif |
129 | #ifdef QUOTA2 | | 129 | #ifdef QUOTA2 |
130 | if (ip->i_ump->um_flags & UFS_QUOTA2) | | 130 | if (ip->i_ump->um_flags & UFS_QUOTA2) |
131 | return chkdq2(ip, change, cred, flags); | | 131 | return chkdq2(ip, change, cred, flags); |
132 | #endif | | 132 | #endif |
133 | return 0; | | 133 | return 0; |
134 | } | | 134 | } |
135 | | | 135 | |
136 | /* | | 136 | /* |
137 | * Check the inode limit, applying corrective action. | | 137 | * Check the inode limit, applying corrective action. |
138 | */ | | 138 | */ |
139 | int | | 139 | int |
140 | chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | | 140 | chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) |
141 | { | | 141 | { |
142 | /* do not track snapshot usage, or we will deadlock */ | | 142 | /* do not track snapshot usage, or we will deadlock */ |
143 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | | 143 | if ((ip->i_flags & SF_SNAPSHOT) != 0) |
144 | return 0; | | 144 | return 0; |
145 | #ifdef QUOTA | | 145 | #ifdef QUOTA |
146 | if (ip->i_ump->um_flags & UFS_QUOTA) | | 146 | if (ip->i_ump->um_flags & UFS_QUOTA) |
147 | return chkiq1(ip, change, cred, flags); | | 147 | return chkiq1(ip, change, cred, flags); |
148 | #endif | | 148 | #endif |
149 | #ifdef QUOTA2 | | 149 | #ifdef QUOTA2 |
150 | if (ip->i_ump->um_flags & UFS_QUOTA2) | | 150 | if (ip->i_ump->um_flags & UFS_QUOTA2) |
151 | return chkiq2(ip, change, cred, flags); | | 151 | return chkiq2(ip, change, cred, flags); |
152 | #endif | | 152 | #endif |
153 | return 0; | | 153 | return 0; |
154 | } | | 154 | } |
155 | | | 155 | |
156 | int | | 156 | int |
157 | quota_handle_cmd(struct mount *mp, struct lwp *l, int op, | | 157 | quota_handle_cmd(struct mount *mp, struct lwp *l, int op, |
158 | struct vfs_quotactl_args *args) | | 158 | struct vfs_quotactl_args *args) |
159 | { | | 159 | { |
160 | int error = 0; | | 160 | int error = 0; |
161 | | | 161 | |
162 | switch (op) { | | 162 | switch (op) { |
163 | case QUOTACTL_GETVERSION: | | 163 | case QUOTACTL_GETVERSION: |
164 | error = quota_handle_cmd_get_version(mp, l, args); | | 164 | error = quota_handle_cmd_get_version(mp, l, args); |
165 | break; | | 165 | break; |
166 | case QUOTACTL_QUOTAON: | | 166 | case QUOTACTL_QUOTAON: |
167 | error = quota_handle_cmd_quotaon(mp, l, args); | | 167 | error = quota_handle_cmd_quotaon(mp, l, args); |
168 | break; | | 168 | break; |
169 | case QUOTACTL_QUOTAOFF: | | 169 | case QUOTACTL_QUOTAOFF: |
170 | error = quota_handle_cmd_quotaoff(mp, l, args); | | 170 | error = quota_handle_cmd_quotaoff(mp, l, args); |
171 | break; | | 171 | break; |
172 | case QUOTACTL_GET: | | 172 | case QUOTACTL_GET: |
173 | error = quota_handle_cmd_get(mp, l, args); | | 173 | error = quota_handle_cmd_get(mp, l, args); |
174 | break; | | 174 | break; |
175 | case QUOTACTL_SET: | | 175 | case QUOTACTL_SET: |
176 | error = quota_handle_cmd_set(mp, l, args); | | 176 | error = quota_handle_cmd_set(mp, l, args); |
177 | break; | | 177 | break; |
178 | case QUOTACTL_GETALL: | | 178 | case QUOTACTL_GETALL: |
179 | error = quota_handle_cmd_getall(mp, l, args); | | 179 | error = quota_handle_cmd_getall(mp, l, args); |
180 | break; | | 180 | break; |
181 | case QUOTACTL_CLEAR: | | 181 | case QUOTACTL_CLEAR: |
182 | error = quota_handle_cmd_clear(mp, l, args); | | 182 | error = quota_handle_cmd_clear(mp, l, args); |
183 | break; | | 183 | break; |
184 | default: | | 184 | default: |
185 | panic("Invalid quotactl operation %d\n", op); | | 185 | panic("Invalid quotactl operation %d\n", op); |
186 | } | | 186 | } |
187 | | | 187 | |
188 | return error; | | 188 | return error; |
189 | } | | 189 | } |
190 | | | 190 | |
191 | static int | | 191 | static int |
192 | quota_handle_cmd_get_version(struct mount *mp, struct lwp *l, | | 192 | quota_handle_cmd_get_version(struct mount *mp, struct lwp *l, |
193 | struct vfs_quotactl_args *args) | | 193 | struct vfs_quotactl_args *args) |
194 | { | | 194 | { |
195 | struct ufsmount *ump = VFSTOUFS(mp); | | 195 | struct ufsmount *ump = VFSTOUFS(mp); |
196 | prop_array_t replies; | | 196 | int *version_ret; |
197 | prop_dictionary_t data; | | | |
198 | int error = 0; | | | |
199 | prop_dictionary_t cmddict; | | | |
200 | prop_array_t datas; | | | |
201 | | | 197 | |
202 | KASSERT(args->qc_type == QCT_PROPLIB); | | 198 | KASSERT(args->qc_type == QCT_GETVERSION); |
203 | cmddict = args->u.proplib.qc_cmddict; | | 199 | version_ret = args->u.getversion.qc_version_ret; |
204 | /* qc_q2type not used */ | | | |
205 | datas = args->u.proplib.qc_datas; | | | |
206 | | | | |
207 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | | |
208 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | | |
209 | | | 200 | |
210 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | | 201 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) |
211 | return EOPNOTSUPP; | | 202 | return EOPNOTSUPP; |
212 | | | 203 | |
213 | replies = prop_array_create(); | | | |
214 | if (replies == NULL) | | | |
215 | return ENOMEM; | | | |
216 | | | | |
217 | data = prop_dictionary_create(); | | | |
218 | if (data == NULL) { | | | |
219 | prop_object_release(replies); | | | |
220 | return ENOMEM; | | | |
221 | } | | | |
222 | | | | |
223 | #ifdef QUOTA | | 204 | #ifdef QUOTA |
224 | if (ump->um_flags & UFS_QUOTA) { | | 205 | if (ump->um_flags & UFS_QUOTA) { |
225 | if (!prop_dictionary_set_int8(data, "version", 1)) | | 206 | *version_ret = 1; |
226 | error = ENOMEM; | | | |
227 | } else | | 207 | } else |
228 | #endif | | 208 | #endif |
229 | #ifdef QUOTA2 | | 209 | #ifdef QUOTA2 |
230 | if (ump->um_flags & UFS_QUOTA2) { | | 210 | if (ump->um_flags & UFS_QUOTA2) { |
231 | if (!prop_dictionary_set_int8(data, "version", 2)) | | 211 | *version_ret = 2; |
232 | error = ENOMEM; | | | |
233 | } else | | 212 | } else |
234 | #endif | | 213 | #endif |
235 | error = 0; | | 214 | return EOPNOTSUPP; |
236 | if (error) | | 215 | |
237 | prop_object_release(data); | | 216 | return 0; |
238 | else if (!prop_array_add_and_rel(replies, data)) | | | |
239 | error = ENOMEM; | | | |
240 | if (error) | | | |
241 | prop_object_release(replies); | | | |
242 | else if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) | | | |
243 | error = ENOMEM; | | | |
244 | return error; | | | |
245 | } | | 217 | } |
246 | | | 218 | |
247 | /* XXX shouldn't all this be in kauth ? */ | | 219 | /* XXX shouldn't all this be in kauth ? */ |
248 | static int | | 220 | static int |
249 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { | | 221 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { |
250 | /* The user can always query about his own quota. */ | | 222 | /* The user can always query about his own quota. */ |
251 | if (id == kauth_cred_getuid(l->l_cred)) | | 223 | if (id == kauth_cred_getuid(l->l_cred)) |
252 | return 0; | | 224 | return 0; |
253 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 225 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
254 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); | | 226 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); |
255 | } | | 227 | } |
256 | | | 228 | |
257 | static int | | 229 | static int |
258 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | | 230 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, |
259 | struct vfs_quotactl_args *args) | | 231 | struct vfs_quotactl_args *args) |
260 | { | | 232 | { |
261 | prop_array_t replies; | | 233 | prop_array_t replies; |
262 | prop_object_iterator_t iter; | | 234 | prop_object_iterator_t iter; |
263 | prop_dictionary_t data; | | 235 | prop_dictionary_t data; |
264 | uint32_t id; | | 236 | uint32_t id; |
265 | struct ufsmount *ump = VFSTOUFS(mp); | | 237 | struct ufsmount *ump = VFSTOUFS(mp); |
266 | int error, defaultq = 0; | | 238 | int error, defaultq = 0; |
267 | const char *idstr; | | 239 | const char *idstr; |
268 | prop_dictionary_t cmddict; | | 240 | prop_dictionary_t cmddict; |
269 | int q2type; | | 241 | int q2type; |
270 | prop_array_t datas; | | 242 | prop_array_t datas; |
271 | | | 243 | |
272 | KASSERT(args->qc_type == QCT_PROPLIB); | | 244 | KASSERT(args->qc_type == QCT_PROPLIB); |
273 | cmddict = args->u.proplib.qc_cmddict; | | 245 | cmddict = args->u.proplib.qc_cmddict; |
274 | q2type = args->u.proplib.qc_q2type; | | 246 | q2type = args->u.proplib.qc_q2type; |
275 | datas = args->u.proplib.qc_datas; | | 247 | datas = args->u.proplib.qc_datas; |
276 | | | 248 | |
277 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 249 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
278 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 250 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
279 | | | 251 | |
280 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | | 252 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) |
281 | return EOPNOTSUPP; | | 253 | return EOPNOTSUPP; |
282 | | | 254 | |
283 | replies = prop_array_create(); | | 255 | replies = prop_array_create(); |
284 | if (replies == NULL) | | 256 | if (replies == NULL) |
285 | return ENOMEM; | | 257 | return ENOMEM; |
286 | | | 258 | |
287 | iter = prop_array_iterator(datas); | | 259 | iter = prop_array_iterator(datas); |
288 | if (iter == NULL) { | | 260 | if (iter == NULL) { |
289 | prop_object_release(replies); | | 261 | prop_object_release(replies); |
290 | return ENOMEM; | | 262 | return ENOMEM; |
291 | } | | 263 | } |
292 | while ((data = prop_object_iterator_next(iter)) != NULL) { | | 264 | while ((data = prop_object_iterator_next(iter)) != NULL) { |
293 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | | 265 | if (!prop_dictionary_get_uint32(data, "id", &id)) { |
294 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | | 266 | if (!prop_dictionary_get_cstring_nocopy(data, "id", |
295 | &idstr)) | | 267 | &idstr)) |
296 | continue; | | 268 | continue; |
297 | if (strcmp(idstr, "default")) { | | 269 | if (strcmp(idstr, "default")) { |
298 | error = EINVAL; | | 270 | error = EINVAL; |
299 | goto err; | | 271 | goto err; |
300 | } | | 272 | } |
301 | id = 0; | | 273 | id = 0; |
302 | defaultq = 1; | | 274 | defaultq = 1; |
303 | } else { | | 275 | } else { |
304 | defaultq = 0; | | 276 | defaultq = 0; |
305 | } | | 277 | } |
306 | error = quota_get_auth(mp, l, id); | | 278 | error = quota_get_auth(mp, l, id); |
307 | if (error == EPERM) | | 279 | if (error == EPERM) |
308 | continue; | | 280 | continue; |
309 | if (error != 0) | | 281 | if (error != 0) |
310 | goto err; | | 282 | goto err; |
311 | #ifdef QUOTA | | 283 | #ifdef QUOTA |
312 | if (ump->um_flags & UFS_QUOTA) | | 284 | if (ump->um_flags & UFS_QUOTA) |
313 | error = quota1_handle_cmd_get(ump, q2type, id, defaultq, | | 285 | error = quota1_handle_cmd_get(ump, q2type, id, defaultq, |
314 | replies); | | 286 | replies); |
315 | else | | 287 | else |
316 | #endif | | 288 | #endif |
317 | #ifdef QUOTA2 | | 289 | #ifdef QUOTA2 |
318 | if (ump->um_flags & UFS_QUOTA2) { | | 290 | if (ump->um_flags & UFS_QUOTA2) { |
319 | error = quota2_handle_cmd_get(ump, q2type, id, defaultq, | | 291 | error = quota2_handle_cmd_get(ump, q2type, id, defaultq, |
320 | replies); | | 292 | replies); |
321 | } else | | 293 | } else |
322 | #endif | | 294 | #endif |
323 | panic("quota_handle_cmd_get: no support ?"); | | 295 | panic("quota_handle_cmd_get: no support ?"); |
324 | | | 296 | |
325 | if (error == ENOENT) | | 297 | if (error == ENOENT) |
326 | continue; | | 298 | continue; |
327 | if (error != 0) | | 299 | if (error != 0) |
328 | goto err; | | 300 | goto err; |
329 | } | | 301 | } |
330 | prop_object_iterator_release(iter); | | 302 | prop_object_iterator_release(iter); |
331 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | | 303 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { |
332 | error = ENOMEM; | | 304 | error = ENOMEM; |
333 | } else { | | 305 | } else { |
334 | error = 0; | | 306 | error = 0; |
335 | } | | 307 | } |
336 | return error; | | 308 | return error; |
337 | err: | | 309 | err: |
338 | prop_object_iterator_release(iter); | | 310 | prop_object_iterator_release(iter); |
339 | prop_object_release(replies); | | 311 | prop_object_release(replies); |
340 | return error; | | 312 | return error; |
341 | } | | 313 | } |
342 | | | 314 | |
343 | static int | | 315 | static int |
344 | quota_handle_cmd_set(struct mount *mp, struct lwp *l, | | 316 | quota_handle_cmd_set(struct mount *mp, struct lwp *l, |
345 | struct vfs_quotactl_args *args) | | 317 | struct vfs_quotactl_args *args) |
346 | { | | 318 | { |
347 | prop_array_t replies; | | 319 | prop_array_t replies; |
348 | prop_object_iterator_t iter; | | 320 | prop_object_iterator_t iter; |
349 | prop_dictionary_t data; | | 321 | prop_dictionary_t data; |
350 | uint32_t id; | | 322 | uint32_t id; |
351 | struct ufsmount *ump = VFSTOUFS(mp); | | 323 | struct ufsmount *ump = VFSTOUFS(mp); |
352 | int error, defaultq = 0; | | 324 | int error, defaultq = 0; |
353 | const char *idstr; | | 325 | const char *idstr; |
354 | prop_dictionary_t cmddict; | | 326 | prop_dictionary_t cmddict; |
355 | int q2type; | | 327 | int q2type; |
356 | prop_array_t datas; | | 328 | prop_array_t datas; |
357 | | | 329 | |
358 | KASSERT(args->qc_type == QCT_PROPLIB); | | 330 | KASSERT(args->qc_type == QCT_PROPLIB); |
359 | cmddict = args->u.proplib.qc_cmddict; | | 331 | cmddict = args->u.proplib.qc_cmddict; |
360 | q2type = args->u.proplib.qc_q2type; | | 332 | q2type = args->u.proplib.qc_q2type; |
361 | datas = args->u.proplib.qc_datas; | | 333 | datas = args->u.proplib.qc_datas; |
362 | | | 334 | |
363 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 335 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
364 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 336 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
365 | | | 337 | |
366 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | | 338 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) |
367 | return EOPNOTSUPP; | | 339 | return EOPNOTSUPP; |
368 | | | 340 | |
369 | replies = prop_array_create(); | | 341 | replies = prop_array_create(); |
370 | if (replies == NULL) | | 342 | if (replies == NULL) |
371 | return ENOMEM; | | 343 | return ENOMEM; |
372 | | | 344 | |
373 | iter = prop_array_iterator(datas); | | 345 | iter = prop_array_iterator(datas); |
374 | if (iter == NULL) { | | 346 | if (iter == NULL) { |
375 | prop_object_release(replies); | | 347 | prop_object_release(replies); |
376 | return ENOMEM; | | 348 | return ENOMEM; |
377 | } | | 349 | } |
378 | while ((data = prop_object_iterator_next(iter)) != NULL) { | | 350 | while ((data = prop_object_iterator_next(iter)) != NULL) { |
379 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | | 351 | if (!prop_dictionary_get_uint32(data, "id", &id)) { |
380 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | | 352 | if (!prop_dictionary_get_cstring_nocopy(data, "id", |
381 | &idstr)) | | 353 | &idstr)) |
382 | continue; | | 354 | continue; |
383 | if (strcmp(idstr, "default")) | | 355 | if (strcmp(idstr, "default")) |
384 | continue; | | 356 | continue; |
385 | id = 0; | | 357 | id = 0; |
386 | defaultq = 1; | | 358 | defaultq = 1; |
387 | } else { | | 359 | } else { |
388 | defaultq = 0; | | 360 | defaultq = 0; |
389 | } | | 361 | } |
390 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 362 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
391 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); | | 363 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); |
392 | if (error != 0) | | 364 | if (error != 0) |
393 | goto err; | | 365 | goto err; |
394 | #ifdef QUOTA | | 366 | #ifdef QUOTA |
395 | if (ump->um_flags & UFS_QUOTA) | | 367 | if (ump->um_flags & UFS_QUOTA) |
396 | error = quota1_handle_cmd_set(ump, q2type, id, defaultq, | | 368 | error = quota1_handle_cmd_set(ump, q2type, id, defaultq, |
397 | data); | | 369 | data); |
398 | else | | 370 | else |
399 | #endif | | 371 | #endif |
400 | #ifdef QUOTA2 | | 372 | #ifdef QUOTA2 |
401 | if (ump->um_flags & UFS_QUOTA2) { | | 373 | if (ump->um_flags & UFS_QUOTA2) { |
402 | error = quota2_handle_cmd_set(ump, q2type, id, defaultq, | | 374 | error = quota2_handle_cmd_set(ump, q2type, id, defaultq, |
403 | data); | | 375 | data); |
404 | } else | | 376 | } else |
405 | #endif | | 377 | #endif |
406 | panic("quota_handle_cmd_get: no support ?"); | | 378 | panic("quota_handle_cmd_get: no support ?"); |
407 | | | 379 | |
408 | if (error && error != ENOENT) | | 380 | if (error && error != ENOENT) |
409 | goto err; | | 381 | goto err; |
410 | } | | 382 | } |
411 | prop_object_iterator_release(iter); | | 383 | prop_object_iterator_release(iter); |
412 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | | 384 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { |
413 | error = ENOMEM; | | 385 | error = ENOMEM; |
414 | } else { | | 386 | } else { |
415 | error = 0; | | 387 | error = 0; |
416 | } | | 388 | } |
417 | return error; | | 389 | return error; |
418 | err: | | 390 | err: |
419 | prop_object_iterator_release(iter); | | 391 | prop_object_iterator_release(iter); |
420 | prop_object_release(replies); | | 392 | prop_object_release(replies); |
421 | return error; | | 393 | return error; |
422 | } | | 394 | } |
423 | | | 395 | |
424 | static int | | 396 | static int |
425 | quota_handle_cmd_clear(struct mount *mp, struct lwp *l, | | 397 | quota_handle_cmd_clear(struct mount *mp, struct lwp *l, |
426 | struct vfs_quotactl_args *args) | | 398 | struct vfs_quotactl_args *args) |
427 | { | | 399 | { |
428 | prop_array_t replies; | | 400 | prop_array_t replies; |
429 | prop_object_iterator_t iter; | | 401 | prop_object_iterator_t iter; |
430 | prop_dictionary_t data; | | 402 | prop_dictionary_t data; |
431 | uint32_t id; | | 403 | uint32_t id; |
432 | struct ufsmount *ump = VFSTOUFS(mp); | | 404 | struct ufsmount *ump = VFSTOUFS(mp); |
433 | int error, defaultq = 0; | | 405 | int error, defaultq = 0; |
434 | const char *idstr; | | 406 | const char *idstr; |
435 | prop_dictionary_t cmddict; | | 407 | prop_dictionary_t cmddict; |
436 | int q2type; | | 408 | int q2type; |
437 | prop_array_t datas; | | 409 | prop_array_t datas; |
438 | | | 410 | |
439 | KASSERT(args->qc_type == QCT_PROPLIB); | | 411 | KASSERT(args->qc_type == QCT_PROPLIB); |
440 | cmddict = args->u.proplib.qc_cmddict; | | 412 | cmddict = args->u.proplib.qc_cmddict; |
441 | q2type = args->u.proplib.qc_q2type; | | 413 | q2type = args->u.proplib.qc_q2type; |
442 | datas = args->u.proplib.qc_datas; | | 414 | datas = args->u.proplib.qc_datas; |
443 | | | 415 | |
444 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 416 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
445 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 417 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
446 | | | 418 | |
447 | if ((ump->um_flags & UFS_QUOTA2) == 0) | | 419 | if ((ump->um_flags & UFS_QUOTA2) == 0) |
448 | return EOPNOTSUPP; | | 420 | return EOPNOTSUPP; |
449 | | | 421 | |
450 | replies = prop_array_create(); | | 422 | replies = prop_array_create(); |
451 | if (replies == NULL) | | 423 | if (replies == NULL) |
452 | return ENOMEM; | | 424 | return ENOMEM; |
453 | | | 425 | |
454 | iter = prop_array_iterator(datas); | | 426 | iter = prop_array_iterator(datas); |
455 | if (iter == NULL) { | | 427 | if (iter == NULL) { |
456 | prop_object_release(replies); | | 428 | prop_object_release(replies); |
457 | return ENOMEM; | | 429 | return ENOMEM; |
458 | } | | 430 | } |
459 | while ((data = prop_object_iterator_next(iter)) != NULL) { | | 431 | while ((data = prop_object_iterator_next(iter)) != NULL) { |
460 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | | 432 | if (!prop_dictionary_get_uint32(data, "id", &id)) { |
461 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | | 433 | if (!prop_dictionary_get_cstring_nocopy(data, "id", |
462 | &idstr)) | | 434 | &idstr)) |
463 | continue; | | 435 | continue; |
464 | if (strcmp(idstr, "default")) | | 436 | if (strcmp(idstr, "default")) |
465 | continue; | | 437 | continue; |
466 | id = 0; | | 438 | id = 0; |
467 | defaultq = 1; | | 439 | defaultq = 1; |
468 | } else { | | 440 | } else { |
469 | defaultq = 0; | | 441 | defaultq = 0; |
470 | } | | 442 | } |
471 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 443 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
472 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); | | 444 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); |
473 | if (error != 0) | | 445 | if (error != 0) |
474 | goto err; | | 446 | goto err; |
475 | #ifdef QUOTA2 | | 447 | #ifdef QUOTA2 |
476 | if (ump->um_flags & UFS_QUOTA2) { | | 448 | if (ump->um_flags & UFS_QUOTA2) { |
477 | error = quota2_handle_cmd_clear(ump, q2type, id, defaultq, | | 449 | error = quota2_handle_cmd_clear(ump, q2type, id, defaultq, |
478 | data); | | 450 | data); |
479 | } else | | 451 | } else |
480 | #endif | | 452 | #endif |
481 | panic("quota_handle_cmd_get: no support ?"); | | 453 | panic("quota_handle_cmd_get: no support ?"); |
482 | | | 454 | |
483 | if (error && error != ENOENT) | | 455 | if (error && error != ENOENT) |
484 | goto err; | | 456 | goto err; |
485 | } | | 457 | } |
486 | prop_object_iterator_release(iter); | | 458 | prop_object_iterator_release(iter); |
487 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | | 459 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { |
488 | error = ENOMEM; | | 460 | error = ENOMEM; |
489 | } else { | | 461 | } else { |
490 | error = 0; | | 462 | error = 0; |
491 | } | | 463 | } |
492 | return error; | | 464 | return error; |
493 | err: | | 465 | err: |
494 | prop_object_iterator_release(iter); | | 466 | prop_object_iterator_release(iter); |
495 | prop_object_release(replies); | | 467 | prop_object_release(replies); |
496 | return error; | | 468 | return error; |
497 | } | | 469 | } |
498 | | | 470 | |
499 | static int | | 471 | static int |
500 | quota_handle_cmd_getall(struct mount *mp, struct lwp *l, | | 472 | quota_handle_cmd_getall(struct mount *mp, struct lwp *l, |
501 | struct vfs_quotactl_args *args) | | 473 | struct vfs_quotactl_args *args) |
502 | { | | 474 | { |
503 | prop_array_t replies; | | 475 | prop_array_t replies; |
504 | struct ufsmount *ump = VFSTOUFS(mp); | | 476 | struct ufsmount *ump = VFSTOUFS(mp); |
505 | int error; | | 477 | int error; |
506 | prop_dictionary_t cmddict; | | 478 | prop_dictionary_t cmddict; |
507 | int q2type; | | 479 | int q2type; |
508 | prop_array_t datas; | | 480 | prop_array_t datas; |
509 | | | 481 | |
510 | KASSERT(args->qc_type == QCT_PROPLIB); | | 482 | KASSERT(args->qc_type == QCT_PROPLIB); |
511 | cmddict = args->u.proplib.qc_cmddict; | | 483 | cmddict = args->u.proplib.qc_cmddict; |
512 | q2type = args->u.proplib.qc_q2type; | | 484 | q2type = args->u.proplib.qc_q2type; |
513 | datas = args->u.proplib.qc_datas; | | 485 | datas = args->u.proplib.qc_datas; |
514 | | | 486 | |
515 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 487 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
516 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 488 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
517 | | | 489 | |
518 | if ((ump->um_flags & UFS_QUOTA2) == 0) | | 490 | if ((ump->um_flags & UFS_QUOTA2) == 0) |
519 | return EOPNOTSUPP; | | 491 | return EOPNOTSUPP; |
520 | | | 492 | |
521 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 493 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
522 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | | 494 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); |
523 | if (error) | | 495 | if (error) |
524 | return error; | | 496 | return error; |
525 | | | 497 | |
526 | replies = prop_array_create(); | | 498 | replies = prop_array_create(); |
527 | if (replies == NULL) | | 499 | if (replies == NULL) |
528 | return ENOMEM; | | 500 | return ENOMEM; |
529 | | | 501 | |
530 | #ifdef QUOTA2 | | 502 | #ifdef QUOTA2 |
531 | if (ump->um_flags & UFS_QUOTA2) { | | 503 | if (ump->um_flags & UFS_QUOTA2) { |
532 | error = quota2_handle_cmd_getall(ump, q2type, replies); | | 504 | error = quota2_handle_cmd_getall(ump, q2type, replies); |
533 | } else | | 505 | } else |
534 | #endif | | 506 | #endif |
535 | panic("quota_handle_cmd_getall: no support ?"); | | 507 | panic("quota_handle_cmd_getall: no support ?"); |
536 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | | 508 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { |
537 | error = ENOMEM; | | 509 | error = ENOMEM; |
538 | } else { | | 510 | } else { |
539 | error = 0; | | 511 | error = 0; |
540 | } | | 512 | } |
541 | return error; | | 513 | return error; |
542 | } | | 514 | } |
543 | | | 515 | |
544 | static int | | 516 | static int |
545 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, | | 517 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, |
546 | struct vfs_quotactl_args *args) | | 518 | struct vfs_quotactl_args *args) |
547 | { | | 519 | { |
548 | prop_dictionary_t data; | | 520 | prop_dictionary_t data; |
549 | struct ufsmount *ump = VFSTOUFS(mp); | | 521 | struct ufsmount *ump = VFSTOUFS(mp); |
550 | int error; | | 522 | int error; |
551 | const char *qfile; | | 523 | const char *qfile; |
552 | prop_dictionary_t cmddict; | | 524 | prop_dictionary_t cmddict; |
553 | int q2type; | | 525 | int q2type; |
554 | prop_array_t datas; | | 526 | prop_array_t datas; |
555 | | | 527 | |
556 | KASSERT(args->qc_type == QCT_PROPLIB); | | 528 | KASSERT(args->qc_type == QCT_PROPLIB); |
557 | cmddict = args->u.proplib.qc_cmddict; | | 529 | cmddict = args->u.proplib.qc_cmddict; |
558 | q2type = args->u.proplib.qc_q2type; | | 530 | q2type = args->u.proplib.qc_q2type; |
559 | datas = args->u.proplib.qc_datas; | | 531 | datas = args->u.proplib.qc_datas; |
560 | | | 532 | |
561 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 533 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
562 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 534 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
563 | | | 535 | |
564 | if ((ump->um_flags & UFS_QUOTA2) != 0) | | 536 | if ((ump->um_flags & UFS_QUOTA2) != 0) |
565 | return EBUSY; | | 537 | return EBUSY; |
566 | | | 538 | |
567 | if (prop_array_count(datas) != 1) | | 539 | if (prop_array_count(datas) != 1) |
568 | return EINVAL; | | 540 | return EINVAL; |
569 | | | 541 | |
570 | data = prop_array_get(datas, 0); | | 542 | data = prop_array_get(datas, 0); |
571 | if (data == NULL) | | 543 | if (data == NULL) |
572 | return ENOMEM; | | 544 | return ENOMEM; |
573 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", | | 545 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", |
574 | &qfile)) | | 546 | &qfile)) |
575 | return EINVAL; | | 547 | return EINVAL; |
576 | | | 548 | |
577 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 549 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
578 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | | 550 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); |
579 | if (error != 0) { | | 551 | if (error != 0) { |
580 | return error; | | 552 | return error; |
581 | } | | 553 | } |
582 | #ifdef QUOTA | | 554 | #ifdef QUOTA |
583 | error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); | | 555 | error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); |
584 | #else | | 556 | #else |
585 | error = EOPNOTSUPP; | | 557 | error = EOPNOTSUPP; |
586 | #endif | | 558 | #endif |
587 | | | 559 | |
588 | return error; | | 560 | return error; |
589 | } | | 561 | } |
590 | | | 562 | |
591 | static int | | 563 | static int |
592 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, | | 564 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, |
593 | struct vfs_quotactl_args *args) | | 565 | struct vfs_quotactl_args *args) |
594 | { | | 566 | { |
595 | struct ufsmount *ump = VFSTOUFS(mp); | | 567 | struct ufsmount *ump = VFSTOUFS(mp); |
596 | int error; | | 568 | int error; |
597 | prop_dictionary_t cmddict; | | 569 | prop_dictionary_t cmddict; |
598 | int q2type; | | 570 | int q2type; |
599 | prop_array_t datas; | | 571 | prop_array_t datas; |
600 | | | 572 | |
601 | KASSERT(args->qc_type == QCT_PROPLIB); | | 573 | KASSERT(args->qc_type == QCT_PROPLIB); |
602 | cmddict = args->u.proplib.qc_cmddict; | | 574 | cmddict = args->u.proplib.qc_cmddict; |
603 | q2type = args->u.proplib.qc_q2type; | | 575 | q2type = args->u.proplib.qc_q2type; |
604 | datas = args->u.proplib.qc_datas; | | 576 | datas = args->u.proplib.qc_datas; |
605 | | | 577 | |
606 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 578 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
607 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 579 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
608 | | | 580 | |
609 | if ((ump->um_flags & UFS_QUOTA2) != 0) | | 581 | if ((ump->um_flags & UFS_QUOTA2) != 0) |
610 | return EOPNOTSUPP; | | 582 | return EOPNOTSUPP; |
611 | | | 583 | |
612 | if (prop_array_count(datas) != 0) | | 584 | if (prop_array_count(datas) != 0) |
613 | return EINVAL; | | 585 | return EINVAL; |
614 | | | 586 | |
615 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 587 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
616 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | | 588 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); |
617 | if (error != 0) { | | 589 | if (error != 0) { |
618 | return error; | | 590 | return error; |
619 | } | | 591 | } |
620 | #ifdef QUOTA | | 592 | #ifdef QUOTA |
621 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); | | 593 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); |
622 | #else | | 594 | #else |
623 | error = EOPNOTSUPP; | | 595 | error = EOPNOTSUPP; |
624 | #endif | | 596 | #endif |
625 | | | 597 | |
626 | return error; | | 598 | return error; |
627 | } | | 599 | } |
628 | | | 600 | |
629 | /* | | 601 | /* |
630 | * Initialize the quota system. | | 602 | * Initialize the quota system. |
631 | */ | | 603 | */ |
632 | void | | 604 | void |
633 | dqinit(void) | | 605 | dqinit(void) |
634 | { | | 606 | { |
635 | | | 607 | |
636 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | | 608 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); |
637 | cv_init(&dqcv, "quota"); | | 609 | cv_init(&dqcv, "quota"); |
638 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); | | 610 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); |
639 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", | | 611 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", |
640 | NULL, IPL_NONE, NULL, NULL, NULL); | | 612 | NULL, IPL_NONE, NULL, NULL, NULL); |
641 | } | | 613 | } |
642 | | | 614 | |
643 | void | | 615 | void |
644 | dqreinit(void) | | 616 | dqreinit(void) |
645 | { | | 617 | { |
646 | struct dquot *dq; | | 618 | struct dquot *dq; |
647 | struct dqhashhead *oldhash, *hash; | | 619 | struct dqhashhead *oldhash, *hash; |
648 | struct vnode *dqvp; | | 620 | struct vnode *dqvp; |
649 | u_long oldmask, mask, hashval; | | 621 | u_long oldmask, mask, hashval; |
650 | int i; | | 622 | int i; |
651 | | | 623 | |
652 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); | | 624 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); |
653 | mutex_enter(&dqlock); | | 625 | mutex_enter(&dqlock); |
654 | oldhash = dqhashtbl; | | 626 | oldhash = dqhashtbl; |
655 | oldmask = dqhash; | | 627 | oldmask = dqhash; |
656 | dqhashtbl = hash; | | 628 | dqhashtbl = hash; |
657 | dqhash = mask; | | 629 | dqhash = mask; |
658 | for (i = 0; i <= oldmask; i++) { | | 630 | for (i = 0; i <= oldmask; i++) { |
659 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { | | 631 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { |
660 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; | | 632 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; |
661 | LIST_REMOVE(dq, dq_hash); | | 633 | LIST_REMOVE(dq, dq_hash); |
662 | hashval = DQHASH(dqvp, dq->dq_id); | | 634 | hashval = DQHASH(dqvp, dq->dq_id); |
663 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); | | 635 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); |
664 | } | | 636 | } |
665 | } | | 637 | } |
666 | mutex_exit(&dqlock); | | 638 | mutex_exit(&dqlock); |
667 | hashdone(oldhash, HASH_LIST, oldmask); | | 639 | hashdone(oldhash, HASH_LIST, oldmask); |
668 | } | | 640 | } |
669 | | | 641 | |
670 | /* | | 642 | /* |
671 | * Free resources held by quota system. | | 643 | * Free resources held by quota system. |
672 | */ | | 644 | */ |
673 | void | | 645 | void |
674 | dqdone(void) | | 646 | dqdone(void) |
675 | { | | 647 | { |
676 | | | 648 | |
677 | pool_cache_destroy(dquot_cache); | | 649 | pool_cache_destroy(dquot_cache); |
678 | hashdone(dqhashtbl, HASH_LIST, dqhash); | | 650 | hashdone(dqhashtbl, HASH_LIST, dqhash); |
679 | cv_destroy(&dqcv); | | 651 | cv_destroy(&dqcv); |
680 | mutex_destroy(&dqlock); | | 652 | mutex_destroy(&dqlock); |
681 | } | | 653 | } |
682 | | | 654 | |
683 | /* | | 655 | /* |
684 | * Set up the quotas for an inode. | | 656 | * Set up the quotas for an inode. |
685 | * | | 657 | * |
686 | * This routine completely defines the semantics of quotas. | | 658 | * This routine completely defines the semantics of quotas. |
687 | * If other criterion want to be used to establish quotas, the | | 659 | * If other criterion want to be used to establish quotas, the |
688 | * MAXQUOTAS value in quotas.h should be increased, and the | | 660 | * MAXQUOTAS value in quotas.h should be increased, and the |
689 | * additional dquots set up here. | | 661 | * additional dquots set up here. |
690 | */ | | 662 | */ |
691 | int | | 663 | int |
692 | getinoquota(struct inode *ip) | | 664 | getinoquota(struct inode *ip) |
693 | { | | 665 | { |
694 | struct ufsmount *ump = ip->i_ump; | | 666 | struct ufsmount *ump = ip->i_ump; |
695 | struct vnode *vp = ITOV(ip); | | 667 | struct vnode *vp = ITOV(ip); |
696 | int i, error; | | 668 | int i, error; |
697 | u_int32_t ino_ids[MAXQUOTAS]; | | 669 | u_int32_t ino_ids[MAXQUOTAS]; |
698 | | | 670 | |
699 | /* | | 671 | /* |
700 | * To avoid deadlocks never update quotas for quota files | | 672 | * To avoid deadlocks never update quotas for quota files |
701 | * on the same file system | | 673 | * on the same file system |
702 | */ | | 674 | */ |
703 | for (i = 0; i < MAXQUOTAS; i++) | | 675 | for (i = 0; i < MAXQUOTAS; i++) |
704 | if (vp == ump->um_quotas[i]) | | 676 | if (vp == ump->um_quotas[i]) |
705 | return 0; | | 677 | return 0; |
706 | | | 678 | |
707 | ino_ids[USRQUOTA] = ip->i_uid; | | 679 | ino_ids[USRQUOTA] = ip->i_uid; |
708 | ino_ids[GRPQUOTA] = ip->i_gid; | | 680 | ino_ids[GRPQUOTA] = ip->i_gid; |
709 | for (i = 0; i < MAXQUOTAS; i++) { | | 681 | for (i = 0; i < MAXQUOTAS; i++) { |
710 | /* | | 682 | /* |
711 | * If the file id changed the quota needs update. | | 683 | * If the file id changed the quota needs update. |
712 | */ | | 684 | */ |
713 | if (ip->i_dquot[i] != NODQUOT && | | 685 | if (ip->i_dquot[i] != NODQUOT && |
714 | ip->i_dquot[i]->dq_id != ino_ids[i]) { | | 686 | ip->i_dquot[i]->dq_id != ino_ids[i]) { |
715 | dqrele(ITOV(ip), ip->i_dquot[i]); | | 687 | dqrele(ITOV(ip), ip->i_dquot[i]); |
716 | ip->i_dquot[i] = NODQUOT; | | 688 | ip->i_dquot[i] = NODQUOT; |
717 | } | | 689 | } |
718 | /* | | 690 | /* |
719 | * Set up the quota based on file id. | | 691 | * Set up the quota based on file id. |
720 | * ENODEV means that quotas are not enabled. | | 692 | * ENODEV means that quotas are not enabled. |
721 | */ | | 693 | */ |
722 | if (ip->i_dquot[i] == NODQUOT && | | 694 | if (ip->i_dquot[i] == NODQUOT && |
723 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && | | 695 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && |
724 | error != ENODEV) | | 696 | error != ENODEV) |
725 | return (error); | | 697 | return (error); |
726 | } | | 698 | } |
727 | return 0; | | 699 | return 0; |
728 | } | | 700 | } |
729 | | | 701 | |
730 | /* | | 702 | /* |
731 | * Obtain a dquot structure for the specified identifier and quota file | | 703 | * Obtain a dquot structure for the specified identifier and quota file |
732 | * reading the information from the file if necessary. | | 704 | * reading the information from the file if necessary. |
733 | */ | | 705 | */ |
734 | int | | 706 | int |
735 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, | | 707 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, |
736 | struct dquot **dqp) | | 708 | struct dquot **dqp) |
737 | { | | 709 | { |
738 | struct dquot *dq, *ndq; | | 710 | struct dquot *dq, *ndq; |
739 | struct dqhashhead *dqh; | | 711 | struct dqhashhead *dqh; |
740 | struct vnode *dqvp; | | 712 | struct vnode *dqvp; |
741 | int error = 0; /* XXX gcc */ | | 713 | int error = 0; /* XXX gcc */ |
742 | | | 714 | |
743 | /* Lock to see an up to date value for QTF_CLOSING. */ | | 715 | /* Lock to see an up to date value for QTF_CLOSING. */ |
744 | mutex_enter(&dqlock); | | 716 | mutex_enter(&dqlock); |
745 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { | | 717 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { |
746 | mutex_exit(&dqlock); | | 718 | mutex_exit(&dqlock); |
747 | *dqp = NODQUOT; | | 719 | *dqp = NODQUOT; |
748 | return (ENODEV); | | 720 | return (ENODEV); |
749 | } | | 721 | } |
750 | dqvp = ump->um_quotas[type]; | | 722 | dqvp = ump->um_quotas[type]; |
751 | #ifdef QUOTA | | 723 | #ifdef QUOTA |
752 | if (ump->um_flags & UFS_QUOTA) { | | 724 | if (ump->um_flags & UFS_QUOTA) { |
753 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { | | 725 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { |
754 | mutex_exit(&dqlock); | | 726 | mutex_exit(&dqlock); |
755 | *dqp = NODQUOT; | | 727 | *dqp = NODQUOT; |
756 | return (ENODEV); | | 728 | return (ENODEV); |
757 | } | | 729 | } |
758 | } | | 730 | } |
759 | #endif | | 731 | #endif |
760 | #ifdef QUOTA2 | | 732 | #ifdef QUOTA2 |
761 | if (ump->um_flags & UFS_QUOTA2) { | | 733 | if (ump->um_flags & UFS_QUOTA2) { |
762 | if (dqvp == NULLVP) { | | 734 | if (dqvp == NULLVP) { |
763 | mutex_exit(&dqlock); | | 735 | mutex_exit(&dqlock); |
764 | *dqp = NODQUOT; | | 736 | *dqp = NODQUOT; |
765 | return (ENODEV); | | 737 | return (ENODEV); |
766 | } | | 738 | } |
767 | } | | 739 | } |
768 | #endif | | 740 | #endif |
769 | KASSERT(dqvp != vp); | | 741 | KASSERT(dqvp != vp); |
770 | /* | | 742 | /* |
771 | * Check the cache first. | | 743 | * Check the cache first. |
772 | */ | | 744 | */ |
773 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | | 745 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; |
774 | LIST_FOREACH(dq, dqh, dq_hash) { | | 746 | LIST_FOREACH(dq, dqh, dq_hash) { |
775 | if (dq->dq_id != id || | | 747 | if (dq->dq_id != id || |
776 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | | 748 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) |
777 | continue; | | 749 | continue; |
778 | KASSERT(dq->dq_cnt > 0); | | 750 | KASSERT(dq->dq_cnt > 0); |
779 | dqref(dq); | | 751 | dqref(dq); |
780 | mutex_exit(&dqlock); | | 752 | mutex_exit(&dqlock); |
781 | *dqp = dq; | | 753 | *dqp = dq; |
782 | return (0); | | 754 | return (0); |
783 | } | | 755 | } |
784 | /* | | 756 | /* |
785 | * Not in cache, allocate a new one. | | 757 | * Not in cache, allocate a new one. |
786 | */ | | 758 | */ |
787 | mutex_exit(&dqlock); | | 759 | mutex_exit(&dqlock); |
788 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); | | 760 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); |
789 | /* | | 761 | /* |
790 | * Initialize the contents of the dquot structure. | | 762 | * Initialize the contents of the dquot structure. |
791 | */ | | 763 | */ |
792 | memset((char *)ndq, 0, sizeof *ndq); | | 764 | memset((char *)ndq, 0, sizeof *ndq); |
793 | ndq->dq_flags = 0; | | 765 | ndq->dq_flags = 0; |
794 | ndq->dq_id = id; | | 766 | ndq->dq_id = id; |
795 | ndq->dq_ump = ump; | | 767 | ndq->dq_ump = ump; |
796 | ndq->dq_type = type; | | 768 | ndq->dq_type = type; |
797 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); | | 769 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); |
798 | mutex_enter(&dqlock); | | 770 | mutex_enter(&dqlock); |
799 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | | 771 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; |
800 | LIST_FOREACH(dq, dqh, dq_hash) { | | 772 | LIST_FOREACH(dq, dqh, dq_hash) { |
801 | if (dq->dq_id != id || | | 773 | if (dq->dq_id != id || |
802 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | | 774 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) |
803 | continue; | | 775 | continue; |
804 | /* | | 776 | /* |
805 | * Another thread beat us allocating this dquot. | | 777 | * Another thread beat us allocating this dquot. |
806 | */ | | 778 | */ |
807 | KASSERT(dq->dq_cnt > 0); | | 779 | KASSERT(dq->dq_cnt > 0); |
808 | dqref(dq); | | 780 | dqref(dq); |
809 | mutex_exit(&dqlock); | | 781 | mutex_exit(&dqlock); |
810 | mutex_destroy(&ndq->dq_interlock); | | 782 | mutex_destroy(&ndq->dq_interlock); |
811 | pool_cache_put(dquot_cache, ndq); | | 783 | pool_cache_put(dquot_cache, ndq); |
812 | *dqp = dq; | | 784 | *dqp = dq; |
813 | return 0; | | 785 | return 0; |
814 | } | | 786 | } |
815 | dq = ndq; | | 787 | dq = ndq; |
816 | LIST_INSERT_HEAD(dqh, dq, dq_hash); | | 788 | LIST_INSERT_HEAD(dqh, dq, dq_hash); |
817 | dqref(dq); | | 789 | dqref(dq); |
818 | mutex_enter(&dq->dq_interlock); | | 790 | mutex_enter(&dq->dq_interlock); |
819 | mutex_exit(&dqlock); | | 791 | mutex_exit(&dqlock); |
820 | #ifdef QUOTA | | 792 | #ifdef QUOTA |
821 | if (ump->um_flags & UFS_QUOTA) | | 793 | if (ump->um_flags & UFS_QUOTA) |
822 | error = dq1get(dqvp, id, ump, type, dq); | | 794 | error = dq1get(dqvp, id, ump, type, dq); |
823 | #endif | | 795 | #endif |
824 | #ifdef QUOTA2 | | 796 | #ifdef QUOTA2 |
825 | if (ump->um_flags & UFS_QUOTA2) | | 797 | if (ump->um_flags & UFS_QUOTA2) |
826 | error = dq2get(dqvp, id, ump, type, dq); | | 798 | error = dq2get(dqvp, id, ump, type, dq); |
827 | #endif | | 799 | #endif |
828 | /* | | 800 | /* |
829 | * I/O error in reading quota file, release | | 801 | * I/O error in reading quota file, release |
830 | * quota structure and reflect problem to caller. | | 802 | * quota structure and reflect problem to caller. |
831 | */ | | 803 | */ |
832 | if (error) { | | 804 | if (error) { |
833 | mutex_enter(&dqlock); | | 805 | mutex_enter(&dqlock); |
834 | LIST_REMOVE(dq, dq_hash); | | 806 | LIST_REMOVE(dq, dq_hash); |
835 | mutex_exit(&dqlock); | | 807 | mutex_exit(&dqlock); |
836 | mutex_exit(&dq->dq_interlock); | | 808 | mutex_exit(&dq->dq_interlock); |
837 | dqrele(vp, dq); | | 809 | dqrele(vp, dq); |
838 | *dqp = NODQUOT; | | 810 | *dqp = NODQUOT; |
839 | return (error); | | 811 | return (error); |
840 | } | | 812 | } |
841 | mutex_exit(&dq->dq_interlock); | | 813 | mutex_exit(&dq->dq_interlock); |
842 | *dqp = dq; | | 814 | *dqp = dq; |
843 | return (0); | | 815 | return (0); |
844 | } | | 816 | } |
845 | | | 817 | |
846 | /* | | 818 | /* |
847 | * Obtain a reference to a dquot. | | 819 | * Obtain a reference to a dquot. |
848 | */ | | 820 | */ |
849 | void | | 821 | void |
850 | dqref(struct dquot *dq) | | 822 | dqref(struct dquot *dq) |
851 | { | | 823 | { |
852 | | | 824 | |
853 | KASSERT(mutex_owned(&dqlock)); | | 825 | KASSERT(mutex_owned(&dqlock)); |
854 | dq->dq_cnt++; | | 826 | dq->dq_cnt++; |
855 | KASSERT(dq->dq_cnt > 0); | | 827 | KASSERT(dq->dq_cnt > 0); |
856 | } | | 828 | } |
857 | | | 829 | |
858 | /* | | 830 | /* |
859 | * Release a reference to a dquot. | | 831 | * Release a reference to a dquot. |
860 | */ | | 832 | */ |
861 | void | | 833 | void |
862 | dqrele(struct vnode *vp, struct dquot *dq) | | 834 | dqrele(struct vnode *vp, struct dquot *dq) |
863 | { | | 835 | { |
864 | | | 836 | |
865 | if (dq == NODQUOT) | | 837 | if (dq == NODQUOT) |
866 | return; | | 838 | return; |
867 | mutex_enter(&dq->dq_interlock); | | 839 | mutex_enter(&dq->dq_interlock); |
868 | for (;;) { | | 840 | for (;;) { |
869 | mutex_enter(&dqlock); | | 841 | mutex_enter(&dqlock); |
870 | if (dq->dq_cnt > 1) { | | 842 | if (dq->dq_cnt > 1) { |
871 | dq->dq_cnt--; | | 843 | dq->dq_cnt--; |
872 | mutex_exit(&dqlock); | | 844 | mutex_exit(&dqlock); |
873 | mutex_exit(&dq->dq_interlock); | | 845 | mutex_exit(&dq->dq_interlock); |
874 | return; | | 846 | return; |
875 | } | | 847 | } |
876 | if ((dq->dq_flags & DQ_MOD) == 0) | | 848 | if ((dq->dq_flags & DQ_MOD) == 0) |
877 | break; | | 849 | break; |
878 | mutex_exit(&dqlock); | | 850 | mutex_exit(&dqlock); |
879 | #ifdef QUOTA | | 851 | #ifdef QUOTA |
880 | if (dq->dq_ump->um_flags & UFS_QUOTA) | | 852 | if (dq->dq_ump->um_flags & UFS_QUOTA) |
881 | (void) dq1sync(vp, dq); | | 853 | (void) dq1sync(vp, dq); |
882 | #endif | | 854 | #endif |
883 | #ifdef QUOTA2 | | 855 | #ifdef QUOTA2 |
884 | if (dq->dq_ump->um_flags & UFS_QUOTA2) | | 856 | if (dq->dq_ump->um_flags & UFS_QUOTA2) |
885 | (void) dq2sync(vp, dq); | | 857 | (void) dq2sync(vp, dq); |
886 | #endif | | 858 | #endif |
887 | } | | 859 | } |
888 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); | | 860 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); |
889 | LIST_REMOVE(dq, dq_hash); | | 861 | LIST_REMOVE(dq, dq_hash); |
890 | mutex_exit(&dqlock); | | 862 | mutex_exit(&dqlock); |
891 | mutex_exit(&dq->dq_interlock); | | 863 | mutex_exit(&dq->dq_interlock); |
892 | mutex_destroy(&dq->dq_interlock); | | 864 | mutex_destroy(&dq->dq_interlock); |
893 | pool_cache_put(dquot_cache, dq); | | 865 | pool_cache_put(dquot_cache, dq); |
894 | } | | 866 | } |
895 | | | 867 | |
896 | int | | 868 | int |
897 | qsync(struct mount *mp) | | 869 | qsync(struct mount *mp) |
898 | { | | 870 | { |
899 | struct ufsmount *ump = VFSTOUFS(mp); | | 871 | struct ufsmount *ump = VFSTOUFS(mp); |
900 | #ifdef QUOTA | | 872 | #ifdef QUOTA |
901 | if (ump->um_flags & UFS_QUOTA) | | 873 | if (ump->um_flags & UFS_QUOTA) |
902 | return q1sync(mp); | | 874 | return q1sync(mp); |
903 | #endif | | 875 | #endif |
904 | #ifdef QUOTA2 | | 876 | #ifdef QUOTA2 |
905 | if (ump->um_flags & UFS_QUOTA2) | | 877 | if (ump->um_flags & UFS_QUOTA2) |
906 | return q2sync(mp); | | 878 | return q2sync(mp); |
907 | #endif | | 879 | #endif |
908 | return 0; | | 880 | return 0; |
909 | } | | 881 | } |
910 | | | 882 | |
911 | #ifdef DIAGNOSTIC | | 883 | #ifdef DIAGNOSTIC |
912 | /* | | 884 | /* |
913 | * Check the hash chains for stray dquot's. | | 885 | * Check the hash chains for stray dquot's. |
914 | */ | | 886 | */ |
915 | void | | 887 | void |
916 | dqflush(struct vnode *vp) | | 888 | dqflush(struct vnode *vp) |
917 | { | | 889 | { |
918 | struct dquot *dq; | | 890 | struct dquot *dq; |
919 | int i; | | 891 | int i; |
920 | | | 892 | |
921 | mutex_enter(&dqlock); | | 893 | mutex_enter(&dqlock); |
922 | for (i = 0; i <= dqhash; i++) | | 894 | for (i = 0; i <= dqhash; i++) |
923 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) | | 895 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) |
924 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); | | 896 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); |
925 | mutex_exit(&dqlock); | | 897 | mutex_exit(&dqlock); |
926 | } | | 898 | } |
927 | #endif | | 899 | #endif |