| @@ -1,850 +1,820 @@ | | | @@ -1,850 +1,820 @@ |
1 | /* $NetBSD: ufs_quota.c,v 1.79 2012/01/29 06:42:14 dholland Exp $ */ | | 1 | /* $NetBSD: ufs_quota.c,v 1.80 2012/01/29 06:44:33 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.79 2012/01/29 06:42:14 dholland Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.80 2012/01/29 06:44:33 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 | int *version_ret; | | 196 | int *version_ret; |
197 | | | 197 | |
198 | KASSERT(args->qc_type == QCT_GETVERSION); | | 198 | KASSERT(args->qc_type == QCT_GETVERSION); |
199 | version_ret = args->u.getversion.qc_version_ret; | | 199 | version_ret = args->u.getversion.qc_version_ret; |
200 | | | 200 | |
201 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | | 201 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) |
202 | return EOPNOTSUPP; | | 202 | return EOPNOTSUPP; |
203 | | | 203 | |
204 | #ifdef QUOTA | | 204 | #ifdef QUOTA |
205 | if (ump->um_flags & UFS_QUOTA) { | | 205 | if (ump->um_flags & UFS_QUOTA) { |
206 | *version_ret = 1; | | 206 | *version_ret = 1; |
207 | } else | | 207 | } else |
208 | #endif | | 208 | #endif |
209 | #ifdef QUOTA2 | | 209 | #ifdef QUOTA2 |
210 | if (ump->um_flags & UFS_QUOTA2) { | | 210 | if (ump->um_flags & UFS_QUOTA2) { |
211 | *version_ret = 2; | | 211 | *version_ret = 2; |
212 | } else | | 212 | } else |
213 | #endif | | 213 | #endif |
214 | return EOPNOTSUPP; | | 214 | return EOPNOTSUPP; |
215 | | | 215 | |
216 | return 0; | | 216 | return 0; |
217 | } | | 217 | } |
218 | | | 218 | |
219 | /* XXX shouldn't all this be in kauth ? */ | | 219 | /* XXX shouldn't all this be in kauth ? */ |
220 | static int | | 220 | static int |
221 | 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) { |
222 | /* The user can always query about his own quota. */ | | 222 | /* The user can always query about his own quota. */ |
223 | if (id == kauth_cred_getuid(l->l_cred)) | | 223 | if (id == kauth_cred_getuid(l->l_cred)) |
224 | return 0; | | 224 | return 0; |
225 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 225 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
226 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); | | 226 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); |
227 | } | | 227 | } |
228 | | | 228 | |
229 | static int | | 229 | static int |
230 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | | 230 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, |
231 | struct vfs_quotactl_args *args) | | 231 | struct vfs_quotactl_args *args) |
232 | { | | 232 | { |
233 | struct ufsmount *ump = VFSTOUFS(mp); | | 233 | struct ufsmount *ump = VFSTOUFS(mp); |
234 | int error; | | 234 | int error; |
235 | const struct quotakey *qk; | | 235 | const struct quotakey *qk; |
236 | struct quotaval *ret; | | 236 | struct quotaval *ret; |
237 | | | 237 | |
238 | KASSERT(args->qc_type == QCT_GET); | | 238 | KASSERT(args->qc_type == QCT_GET); |
239 | qk = args->u.get.qc_key; | | 239 | qk = args->u.get.qc_key; |
240 | ret = args->u.get.qc_ret; | | 240 | ret = args->u.get.qc_ret; |
241 | | | 241 | |
242 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | | 242 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) |
243 | return EOPNOTSUPP; | | 243 | return EOPNOTSUPP; |
244 | | | 244 | |
245 | error = quota_get_auth(mp, l, qk->qk_id); | | 245 | error = quota_get_auth(mp, l, qk->qk_id); |
246 | if (error != 0) | | 246 | if (error != 0) |
247 | return error; | | 247 | return error; |
248 | #ifdef QUOTA | | 248 | #ifdef QUOTA |
249 | if (ump->um_flags & UFS_QUOTA) { | | 249 | if (ump->um_flags & UFS_QUOTA) { |
250 | error = quota1_handle_cmd_get(ump, qk, ret); | | 250 | error = quota1_handle_cmd_get(ump, qk, ret); |
251 | } else | | 251 | } else |
252 | #endif | | 252 | #endif |
253 | #ifdef QUOTA2 | | 253 | #ifdef QUOTA2 |
254 | if (ump->um_flags & UFS_QUOTA2) { | | 254 | if (ump->um_flags & UFS_QUOTA2) { |
255 | error = quota2_handle_cmd_get(ump, qk, ret); | | 255 | error = quota2_handle_cmd_get(ump, qk, ret); |
256 | } else | | 256 | } else |
257 | #endif | | 257 | #endif |
258 | panic("quota_handle_cmd_get: no support ?"); | | 258 | panic("quota_handle_cmd_get: no support ?"); |
259 | | | 259 | |
260 | if (error != 0) | | 260 | if (error != 0) |
261 | return error; | | 261 | return error; |
262 | | | 262 | |
263 | return error; | | 263 | return error; |
264 | } | | 264 | } |
265 | | | 265 | |
266 | static int | | 266 | static int |
267 | quota_handle_cmd_set(struct mount *mp, struct lwp *l, | | 267 | quota_handle_cmd_set(struct mount *mp, struct lwp *l, |
268 | struct vfs_quotactl_args *args) | | 268 | struct vfs_quotactl_args *args) |
269 | { | | 269 | { |
270 | prop_array_t replies; | | | |
271 | prop_object_iterator_t iter; | | | |
272 | prop_dictionary_t data; | | | |
273 | uint32_t id; | | | |
274 | struct ufsmount *ump = VFSTOUFS(mp); | | 270 | struct ufsmount *ump = VFSTOUFS(mp); |
275 | int error, defaultq = 0; | | 271 | id_t id; |
276 | const char *idstr; | | 272 | int defaultq; |
277 | prop_dictionary_t cmddict; | | | |
278 | int q2type; | | 273 | int q2type; |
279 | prop_array_t datas; | | 274 | prop_dictionary_t data; |
| | | 275 | int error; |
280 | | | 276 | |
281 | KASSERT(args->qc_type == QCT_PROPLIB); | | 277 | KASSERT(args->qc_type == QCT_SET); |
282 | cmddict = args->u.proplib.qc_cmddict; | | 278 | id = args->u.set.qc_id; |
283 | q2type = args->u.proplib.qc_q2type; | | 279 | defaultq = args->u.set.qc_defaultq; |
284 | datas = args->u.proplib.qc_datas; | | 280 | q2type = args->u.set.qc_q2type; |
| | | 281 | data = args->u.set.qc_data; |
285 | | | 282 | |
286 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 283 | KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY); |
287 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | | |
288 | | | 284 | |
289 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | | 285 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) |
290 | return EOPNOTSUPP; | | 286 | return EOPNOTSUPP; |
291 | | | | |
292 | replies = prop_array_create(); | | | |
293 | if (replies == NULL) | | | |
294 | return ENOMEM; | | | |
295 | | | 287 | |
296 | iter = prop_array_iterator(datas); | | 288 | /* avoid whitespace changes */ |
297 | if (iter == NULL) { | | 289 | { |
298 | prop_object_release(replies); | | | |
299 | return ENOMEM; | | | |
300 | } | | | |
301 | while ((data = prop_object_iterator_next(iter)) != NULL) { | | | |
302 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | | | |
303 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | | | |
304 | &idstr)) | | | |
305 | continue; | | | |
306 | if (strcmp(idstr, "default")) | | | |
307 | continue; | | | |
308 | id = 0; | | | |
309 | defaultq = 1; | | | |
310 | } else { | | | |
311 | defaultq = 0; | | | |
312 | } | | | |
313 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 290 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
314 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); | | 291 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); |
315 | if (error != 0) | | 292 | if (error != 0) |
316 | goto err; | | 293 | goto err; |
317 | #ifdef QUOTA | | 294 | #ifdef QUOTA |
318 | if (ump->um_flags & UFS_QUOTA) | | 295 | if (ump->um_flags & UFS_QUOTA) |
319 | error = quota1_handle_cmd_set(ump, q2type, id, defaultq, | | 296 | error = quota1_handle_cmd_set(ump, q2type, id, defaultq, |
320 | data); | | 297 | data); |
321 | else | | 298 | else |
322 | #endif | | 299 | #endif |
323 | #ifdef QUOTA2 | | 300 | #ifdef QUOTA2 |
324 | if (ump->um_flags & UFS_QUOTA2) { | | 301 | if (ump->um_flags & UFS_QUOTA2) { |
325 | error = quota2_handle_cmd_set(ump, q2type, id, defaultq, | | 302 | error = quota2_handle_cmd_set(ump, q2type, id, defaultq, |
326 | data); | | 303 | data); |
327 | } else | | 304 | } else |
328 | #endif | | 305 | #endif |
329 | panic("quota_handle_cmd_get: no support ?"); | | 306 | panic("quota_handle_cmd_get: no support ?"); |
330 | | | 307 | |
331 | if (error && error != ENOENT) | | 308 | if (error && error != ENOENT) |
332 | goto err; | | 309 | goto err; |
333 | } | | 310 | } |
334 | prop_object_iterator_release(iter); | | 311 | |
335 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | | 312 | return 0; |
336 | error = ENOMEM; | | 313 | err: |
337 | } else { | | | |
338 | error = 0; | | | |
339 | } | | | |
340 | return error; | | | |
341 | err: | | | |
342 | prop_object_iterator_release(iter); | | | |
343 | prop_object_release(replies); | | | |
344 | return error; | | 314 | return error; |
345 | } | | 315 | } |
346 | | | 316 | |
347 | static int | | 317 | static int |
348 | quota_handle_cmd_clear(struct mount *mp, struct lwp *l, | | 318 | quota_handle_cmd_clear(struct mount *mp, struct lwp *l, |
349 | struct vfs_quotactl_args *args) | | 319 | struct vfs_quotactl_args *args) |
350 | { | | 320 | { |
351 | prop_array_t replies; | | 321 | prop_array_t replies; |
352 | prop_object_iterator_t iter; | | 322 | prop_object_iterator_t iter; |
353 | prop_dictionary_t data; | | 323 | prop_dictionary_t data; |
354 | uint32_t id; | | 324 | uint32_t id; |
355 | struct ufsmount *ump = VFSTOUFS(mp); | | 325 | struct ufsmount *ump = VFSTOUFS(mp); |
356 | int error, defaultq = 0; | | 326 | int error, defaultq = 0; |
357 | const char *idstr; | | 327 | const char *idstr; |
358 | prop_dictionary_t cmddict; | | 328 | prop_dictionary_t cmddict; |
359 | int q2type; | | 329 | int q2type; |
360 | prop_array_t datas; | | 330 | prop_array_t datas; |
361 | | | 331 | |
362 | KASSERT(args->qc_type == QCT_PROPLIB); | | 332 | KASSERT(args->qc_type == QCT_PROPLIB); |
363 | cmddict = args->u.proplib.qc_cmddict; | | 333 | cmddict = args->u.proplib.qc_cmddict; |
364 | q2type = args->u.proplib.qc_q2type; | | 334 | q2type = args->u.proplib.qc_q2type; |
365 | datas = args->u.proplib.qc_datas; | | 335 | datas = args->u.proplib.qc_datas; |
366 | | | 336 | |
367 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 337 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
368 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 338 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
369 | | | 339 | |
370 | if ((ump->um_flags & UFS_QUOTA2) == 0) | | 340 | if ((ump->um_flags & UFS_QUOTA2) == 0) |
371 | return EOPNOTSUPP; | | 341 | return EOPNOTSUPP; |
372 | | | 342 | |
373 | replies = prop_array_create(); | | 343 | replies = prop_array_create(); |
374 | if (replies == NULL) | | 344 | if (replies == NULL) |
375 | return ENOMEM; | | 345 | return ENOMEM; |
376 | | | 346 | |
377 | iter = prop_array_iterator(datas); | | 347 | iter = prop_array_iterator(datas); |
378 | if (iter == NULL) { | | 348 | if (iter == NULL) { |
379 | prop_object_release(replies); | | 349 | prop_object_release(replies); |
380 | return ENOMEM; | | 350 | return ENOMEM; |
381 | } | | 351 | } |
382 | while ((data = prop_object_iterator_next(iter)) != NULL) { | | 352 | while ((data = prop_object_iterator_next(iter)) != NULL) { |
383 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | | 353 | if (!prop_dictionary_get_uint32(data, "id", &id)) { |
384 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | | 354 | if (!prop_dictionary_get_cstring_nocopy(data, "id", |
385 | &idstr)) | | 355 | &idstr)) |
386 | continue; | | 356 | continue; |
387 | if (strcmp(idstr, "default")) | | 357 | if (strcmp(idstr, "default")) |
388 | continue; | | 358 | continue; |
389 | id = 0; | | 359 | id = 0; |
390 | defaultq = 1; | | 360 | defaultq = 1; |
391 | } else { | | 361 | } else { |
392 | defaultq = 0; | | 362 | defaultq = 0; |
393 | } | | 363 | } |
394 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 364 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
395 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); | | 365 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); |
396 | if (error != 0) | | 366 | if (error != 0) |
397 | goto err; | | 367 | goto err; |
398 | #ifdef QUOTA2 | | 368 | #ifdef QUOTA2 |
399 | if (ump->um_flags & UFS_QUOTA2) { | | 369 | if (ump->um_flags & UFS_QUOTA2) { |
400 | error = quota2_handle_cmd_clear(ump, q2type, id, defaultq, | | 370 | error = quota2_handle_cmd_clear(ump, q2type, id, defaultq, |
401 | data); | | 371 | data); |
402 | } else | | 372 | } else |
403 | #endif | | 373 | #endif |
404 | panic("quota_handle_cmd_get: no support ?"); | | 374 | panic("quota_handle_cmd_get: no support ?"); |
405 | | | 375 | |
406 | if (error && error != ENOENT) | | 376 | if (error && error != ENOENT) |
407 | goto err; | | 377 | goto err; |
408 | } | | 378 | } |
409 | prop_object_iterator_release(iter); | | 379 | prop_object_iterator_release(iter); |
410 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | | 380 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { |
411 | error = ENOMEM; | | 381 | error = ENOMEM; |
412 | } else { | | 382 | } else { |
413 | error = 0; | | 383 | error = 0; |
414 | } | | 384 | } |
415 | return error; | | 385 | return error; |
416 | err: | | 386 | err: |
417 | prop_object_iterator_release(iter); | | 387 | prop_object_iterator_release(iter); |
418 | prop_object_release(replies); | | 388 | prop_object_release(replies); |
419 | return error; | | 389 | return error; |
420 | } | | 390 | } |
421 | | | 391 | |
422 | static int | | 392 | static int |
423 | quota_handle_cmd_getall(struct mount *mp, struct lwp *l, | | 393 | quota_handle_cmd_getall(struct mount *mp, struct lwp *l, |
424 | struct vfs_quotactl_args *args) | | 394 | struct vfs_quotactl_args *args) |
425 | { | | 395 | { |
426 | prop_array_t replies; | | 396 | prop_array_t replies; |
427 | struct ufsmount *ump = VFSTOUFS(mp); | | 397 | struct ufsmount *ump = VFSTOUFS(mp); |
428 | int error; | | 398 | int error; |
429 | prop_dictionary_t cmddict; | | 399 | prop_dictionary_t cmddict; |
430 | int q2type; | | 400 | int q2type; |
431 | prop_array_t datas; | | 401 | prop_array_t datas; |
432 | | | 402 | |
433 | KASSERT(args->qc_type == QCT_PROPLIB); | | 403 | KASSERT(args->qc_type == QCT_PROPLIB); |
434 | cmddict = args->u.proplib.qc_cmddict; | | 404 | cmddict = args->u.proplib.qc_cmddict; |
435 | q2type = args->u.proplib.qc_q2type; | | 405 | q2type = args->u.proplib.qc_q2type; |
436 | datas = args->u.proplib.qc_datas; | | 406 | datas = args->u.proplib.qc_datas; |
437 | | | 407 | |
438 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 408 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
439 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 409 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
440 | | | 410 | |
441 | if ((ump->um_flags & UFS_QUOTA2) == 0) | | 411 | if ((ump->um_flags & UFS_QUOTA2) == 0) |
442 | return EOPNOTSUPP; | | 412 | return EOPNOTSUPP; |
443 | | | 413 | |
444 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 414 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
445 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | | 415 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); |
446 | if (error) | | 416 | if (error) |
447 | return error; | | 417 | return error; |
448 | | | 418 | |
449 | replies = prop_array_create(); | | 419 | replies = prop_array_create(); |
450 | if (replies == NULL) | | 420 | if (replies == NULL) |
451 | return ENOMEM; | | 421 | return ENOMEM; |
452 | | | 422 | |
453 | #ifdef QUOTA2 | | 423 | #ifdef QUOTA2 |
454 | if (ump->um_flags & UFS_QUOTA2) { | | 424 | if (ump->um_flags & UFS_QUOTA2) { |
455 | error = quota2_handle_cmd_getall(ump, q2type, replies); | | 425 | error = quota2_handle_cmd_getall(ump, q2type, replies); |
456 | } else | | 426 | } else |
457 | #endif | | 427 | #endif |
458 | panic("quota_handle_cmd_getall: no support ?"); | | 428 | panic("quota_handle_cmd_getall: no support ?"); |
459 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | | 429 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { |
460 | error = ENOMEM; | | 430 | error = ENOMEM; |
461 | } else { | | 431 | } else { |
462 | error = 0; | | 432 | error = 0; |
463 | } | | 433 | } |
464 | return error; | | 434 | return error; |
465 | } | | 435 | } |
466 | | | 436 | |
467 | static int | | 437 | static int |
468 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, | | 438 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, |
469 | struct vfs_quotactl_args *args) | | 439 | struct vfs_quotactl_args *args) |
470 | { | | 440 | { |
471 | prop_dictionary_t data; | | 441 | prop_dictionary_t data; |
472 | struct ufsmount *ump = VFSTOUFS(mp); | | 442 | struct ufsmount *ump = VFSTOUFS(mp); |
473 | int error; | | 443 | int error; |
474 | const char *qfile; | | 444 | const char *qfile; |
475 | prop_dictionary_t cmddict; | | 445 | prop_dictionary_t cmddict; |
476 | int q2type; | | 446 | int q2type; |
477 | prop_array_t datas; | | 447 | prop_array_t datas; |
478 | | | 448 | |
479 | KASSERT(args->qc_type == QCT_PROPLIB); | | 449 | KASSERT(args->qc_type == QCT_PROPLIB); |
480 | cmddict = args->u.proplib.qc_cmddict; | | 450 | cmddict = args->u.proplib.qc_cmddict; |
481 | q2type = args->u.proplib.qc_q2type; | | 451 | q2type = args->u.proplib.qc_q2type; |
482 | datas = args->u.proplib.qc_datas; | | 452 | datas = args->u.proplib.qc_datas; |
483 | | | 453 | |
484 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 454 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
485 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 455 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
486 | | | 456 | |
487 | if ((ump->um_flags & UFS_QUOTA2) != 0) | | 457 | if ((ump->um_flags & UFS_QUOTA2) != 0) |
488 | return EBUSY; | | 458 | return EBUSY; |
489 | | | 459 | |
490 | if (prop_array_count(datas) != 1) | | 460 | if (prop_array_count(datas) != 1) |
491 | return EINVAL; | | 461 | return EINVAL; |
492 | | | 462 | |
493 | data = prop_array_get(datas, 0); | | 463 | data = prop_array_get(datas, 0); |
494 | if (data == NULL) | | 464 | if (data == NULL) |
495 | return ENOMEM; | | 465 | return ENOMEM; |
496 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", | | 466 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", |
497 | &qfile)) | | 467 | &qfile)) |
498 | return EINVAL; | | 468 | return EINVAL; |
499 | | | 469 | |
500 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 470 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
501 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | | 471 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); |
502 | if (error != 0) { | | 472 | if (error != 0) { |
503 | return error; | | 473 | return error; |
504 | } | | 474 | } |
505 | #ifdef QUOTA | | 475 | #ifdef QUOTA |
506 | error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); | | 476 | error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); |
507 | #else | | 477 | #else |
508 | error = EOPNOTSUPP; | | 478 | error = EOPNOTSUPP; |
509 | #endif | | 479 | #endif |
510 | | | 480 | |
511 | return error; | | 481 | return error; |
512 | } | | 482 | } |
513 | | | 483 | |
514 | static int | | 484 | static int |
515 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, | | 485 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, |
516 | struct vfs_quotactl_args *args) | | 486 | struct vfs_quotactl_args *args) |
517 | { | | 487 | { |
518 | struct ufsmount *ump = VFSTOUFS(mp); | | 488 | struct ufsmount *ump = VFSTOUFS(mp); |
519 | int error; | | 489 | int error; |
520 | prop_dictionary_t cmddict; | | 490 | prop_dictionary_t cmddict; |
521 | int q2type; | | 491 | int q2type; |
522 | prop_array_t datas; | | 492 | prop_array_t datas; |
523 | | | 493 | |
524 | KASSERT(args->qc_type == QCT_PROPLIB); | | 494 | KASSERT(args->qc_type == QCT_PROPLIB); |
525 | cmddict = args->u.proplib.qc_cmddict; | | 495 | cmddict = args->u.proplib.qc_cmddict; |
526 | q2type = args->u.proplib.qc_q2type; | | 496 | q2type = args->u.proplib.qc_q2type; |
527 | datas = args->u.proplib.qc_datas; | | 497 | datas = args->u.proplib.qc_datas; |
528 | | | 498 | |
529 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | | 499 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); |
530 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | | 500 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); |
531 | | | 501 | |
532 | if ((ump->um_flags & UFS_QUOTA2) != 0) | | 502 | if ((ump->um_flags & UFS_QUOTA2) != 0) |
533 | return EOPNOTSUPP; | | 503 | return EOPNOTSUPP; |
534 | | | 504 | |
535 | if (prop_array_count(datas) != 0) | | 505 | if (prop_array_count(datas) != 0) |
536 | return EINVAL; | | 506 | return EINVAL; |
537 | | | 507 | |
538 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | | 508 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, |
539 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | | 509 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); |
540 | if (error != 0) { | | 510 | if (error != 0) { |
541 | return error; | | 511 | return error; |
542 | } | | 512 | } |
543 | #ifdef QUOTA | | 513 | #ifdef QUOTA |
544 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); | | 514 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); |
545 | #else | | 515 | #else |
546 | error = EOPNOTSUPP; | | 516 | error = EOPNOTSUPP; |
547 | #endif | | 517 | #endif |
548 | | | 518 | |
549 | return error; | | 519 | return error; |
550 | } | | 520 | } |
551 | | | 521 | |
552 | /* | | 522 | /* |
553 | * Initialize the quota system. | | 523 | * Initialize the quota system. |
554 | */ | | 524 | */ |
555 | void | | 525 | void |
556 | dqinit(void) | | 526 | dqinit(void) |
557 | { | | 527 | { |
558 | | | 528 | |
559 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | | 529 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); |
560 | cv_init(&dqcv, "quota"); | | 530 | cv_init(&dqcv, "quota"); |
561 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); | | 531 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); |
562 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", | | 532 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", |
563 | NULL, IPL_NONE, NULL, NULL, NULL); | | 533 | NULL, IPL_NONE, NULL, NULL, NULL); |
564 | } | | 534 | } |
565 | | | 535 | |
566 | void | | 536 | void |
567 | dqreinit(void) | | 537 | dqreinit(void) |
568 | { | | 538 | { |
569 | struct dquot *dq; | | 539 | struct dquot *dq; |
570 | struct dqhashhead *oldhash, *hash; | | 540 | struct dqhashhead *oldhash, *hash; |
571 | struct vnode *dqvp; | | 541 | struct vnode *dqvp; |
572 | u_long oldmask, mask, hashval; | | 542 | u_long oldmask, mask, hashval; |
573 | int i; | | 543 | int i; |
574 | | | 544 | |
575 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); | | 545 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); |
576 | mutex_enter(&dqlock); | | 546 | mutex_enter(&dqlock); |
577 | oldhash = dqhashtbl; | | 547 | oldhash = dqhashtbl; |
578 | oldmask = dqhash; | | 548 | oldmask = dqhash; |
579 | dqhashtbl = hash; | | 549 | dqhashtbl = hash; |
580 | dqhash = mask; | | 550 | dqhash = mask; |
581 | for (i = 0; i <= oldmask; i++) { | | 551 | for (i = 0; i <= oldmask; i++) { |
582 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { | | 552 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { |
583 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; | | 553 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; |
584 | LIST_REMOVE(dq, dq_hash); | | 554 | LIST_REMOVE(dq, dq_hash); |
585 | hashval = DQHASH(dqvp, dq->dq_id); | | 555 | hashval = DQHASH(dqvp, dq->dq_id); |
586 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); | | 556 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); |
587 | } | | 557 | } |
588 | } | | 558 | } |
589 | mutex_exit(&dqlock); | | 559 | mutex_exit(&dqlock); |
590 | hashdone(oldhash, HASH_LIST, oldmask); | | 560 | hashdone(oldhash, HASH_LIST, oldmask); |
591 | } | | 561 | } |
592 | | | 562 | |
593 | /* | | 563 | /* |
594 | * Free resources held by quota system. | | 564 | * Free resources held by quota system. |
595 | */ | | 565 | */ |
596 | void | | 566 | void |
597 | dqdone(void) | | 567 | dqdone(void) |
598 | { | | 568 | { |
599 | | | 569 | |
600 | pool_cache_destroy(dquot_cache); | | 570 | pool_cache_destroy(dquot_cache); |
601 | hashdone(dqhashtbl, HASH_LIST, dqhash); | | 571 | hashdone(dqhashtbl, HASH_LIST, dqhash); |
602 | cv_destroy(&dqcv); | | 572 | cv_destroy(&dqcv); |
603 | mutex_destroy(&dqlock); | | 573 | mutex_destroy(&dqlock); |
604 | } | | 574 | } |
605 | | | 575 | |
606 | /* | | 576 | /* |
607 | * Set up the quotas for an inode. | | 577 | * Set up the quotas for an inode. |
608 | * | | 578 | * |
609 | * This routine completely defines the semantics of quotas. | | 579 | * This routine completely defines the semantics of quotas. |
610 | * If other criterion want to be used to establish quotas, the | | 580 | * If other criterion want to be used to establish quotas, the |
611 | * MAXQUOTAS value in quotas.h should be increased, and the | | 581 | * MAXQUOTAS value in quotas.h should be increased, and the |
612 | * additional dquots set up here. | | 582 | * additional dquots set up here. |
613 | */ | | 583 | */ |
614 | int | | 584 | int |
615 | getinoquota(struct inode *ip) | | 585 | getinoquota(struct inode *ip) |
616 | { | | 586 | { |
617 | struct ufsmount *ump = ip->i_ump; | | 587 | struct ufsmount *ump = ip->i_ump; |
618 | struct vnode *vp = ITOV(ip); | | 588 | struct vnode *vp = ITOV(ip); |
619 | int i, error; | | 589 | int i, error; |
620 | u_int32_t ino_ids[MAXQUOTAS]; | | 590 | u_int32_t ino_ids[MAXQUOTAS]; |
621 | | | 591 | |
622 | /* | | 592 | /* |
623 | * To avoid deadlocks never update quotas for quota files | | 593 | * To avoid deadlocks never update quotas for quota files |
624 | * on the same file system | | 594 | * on the same file system |
625 | */ | | 595 | */ |
626 | for (i = 0; i < MAXQUOTAS; i++) | | 596 | for (i = 0; i < MAXQUOTAS; i++) |
627 | if (vp == ump->um_quotas[i]) | | 597 | if (vp == ump->um_quotas[i]) |
628 | return 0; | | 598 | return 0; |
629 | | | 599 | |
630 | ino_ids[USRQUOTA] = ip->i_uid; | | 600 | ino_ids[USRQUOTA] = ip->i_uid; |
631 | ino_ids[GRPQUOTA] = ip->i_gid; | | 601 | ino_ids[GRPQUOTA] = ip->i_gid; |
632 | for (i = 0; i < MAXQUOTAS; i++) { | | 602 | for (i = 0; i < MAXQUOTAS; i++) { |
633 | /* | | 603 | /* |
634 | * If the file id changed the quota needs update. | | 604 | * If the file id changed the quota needs update. |
635 | */ | | 605 | */ |
636 | if (ip->i_dquot[i] != NODQUOT && | | 606 | if (ip->i_dquot[i] != NODQUOT && |
637 | ip->i_dquot[i]->dq_id != ino_ids[i]) { | | 607 | ip->i_dquot[i]->dq_id != ino_ids[i]) { |
638 | dqrele(ITOV(ip), ip->i_dquot[i]); | | 608 | dqrele(ITOV(ip), ip->i_dquot[i]); |
639 | ip->i_dquot[i] = NODQUOT; | | 609 | ip->i_dquot[i] = NODQUOT; |
640 | } | | 610 | } |
641 | /* | | 611 | /* |
642 | * Set up the quota based on file id. | | 612 | * Set up the quota based on file id. |
643 | * ENODEV means that quotas are not enabled. | | 613 | * ENODEV means that quotas are not enabled. |
644 | */ | | 614 | */ |
645 | if (ip->i_dquot[i] == NODQUOT && | | 615 | if (ip->i_dquot[i] == NODQUOT && |
646 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && | | 616 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && |
647 | error != ENODEV) | | 617 | error != ENODEV) |
648 | return (error); | | 618 | return (error); |
649 | } | | 619 | } |
650 | return 0; | | 620 | return 0; |
651 | } | | 621 | } |
652 | | | 622 | |
653 | /* | | 623 | /* |
654 | * Obtain a dquot structure for the specified identifier and quota file | | 624 | * Obtain a dquot structure for the specified identifier and quota file |
655 | * reading the information from the file if necessary. | | 625 | * reading the information from the file if necessary. |
656 | */ | | 626 | */ |
657 | int | | 627 | int |
658 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, | | 628 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, |
659 | struct dquot **dqp) | | 629 | struct dquot **dqp) |
660 | { | | 630 | { |
661 | struct dquot *dq, *ndq; | | 631 | struct dquot *dq, *ndq; |
662 | struct dqhashhead *dqh; | | 632 | struct dqhashhead *dqh; |
663 | struct vnode *dqvp; | | 633 | struct vnode *dqvp; |
664 | int error = 0; /* XXX gcc */ | | 634 | int error = 0; /* XXX gcc */ |
665 | | | 635 | |
666 | /* Lock to see an up to date value for QTF_CLOSING. */ | | 636 | /* Lock to see an up to date value for QTF_CLOSING. */ |
667 | mutex_enter(&dqlock); | | 637 | mutex_enter(&dqlock); |
668 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { | | 638 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { |
669 | mutex_exit(&dqlock); | | 639 | mutex_exit(&dqlock); |
670 | *dqp = NODQUOT; | | 640 | *dqp = NODQUOT; |
671 | return (ENODEV); | | 641 | return (ENODEV); |
672 | } | | 642 | } |
673 | dqvp = ump->um_quotas[type]; | | 643 | dqvp = ump->um_quotas[type]; |
674 | #ifdef QUOTA | | 644 | #ifdef QUOTA |
675 | if (ump->um_flags & UFS_QUOTA) { | | 645 | if (ump->um_flags & UFS_QUOTA) { |
676 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { | | 646 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { |
677 | mutex_exit(&dqlock); | | 647 | mutex_exit(&dqlock); |
678 | *dqp = NODQUOT; | | 648 | *dqp = NODQUOT; |
679 | return (ENODEV); | | 649 | return (ENODEV); |
680 | } | | 650 | } |
681 | } | | 651 | } |
682 | #endif | | 652 | #endif |
683 | #ifdef QUOTA2 | | 653 | #ifdef QUOTA2 |
684 | if (ump->um_flags & UFS_QUOTA2) { | | 654 | if (ump->um_flags & UFS_QUOTA2) { |
685 | if (dqvp == NULLVP) { | | 655 | if (dqvp == NULLVP) { |
686 | mutex_exit(&dqlock); | | 656 | mutex_exit(&dqlock); |
687 | *dqp = NODQUOT; | | 657 | *dqp = NODQUOT; |
688 | return (ENODEV); | | 658 | return (ENODEV); |
689 | } | | 659 | } |
690 | } | | 660 | } |
691 | #endif | | 661 | #endif |
692 | KASSERT(dqvp != vp); | | 662 | KASSERT(dqvp != vp); |
693 | /* | | 663 | /* |
694 | * Check the cache first. | | 664 | * Check the cache first. |
695 | */ | | 665 | */ |
696 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | | 666 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; |
697 | LIST_FOREACH(dq, dqh, dq_hash) { | | 667 | LIST_FOREACH(dq, dqh, dq_hash) { |
698 | if (dq->dq_id != id || | | 668 | if (dq->dq_id != id || |
699 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | | 669 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) |
700 | continue; | | 670 | continue; |
701 | KASSERT(dq->dq_cnt > 0); | | 671 | KASSERT(dq->dq_cnt > 0); |
702 | dqref(dq); | | 672 | dqref(dq); |
703 | mutex_exit(&dqlock); | | 673 | mutex_exit(&dqlock); |
704 | *dqp = dq; | | 674 | *dqp = dq; |
705 | return (0); | | 675 | return (0); |
706 | } | | 676 | } |
707 | /* | | 677 | /* |
708 | * Not in cache, allocate a new one. | | 678 | * Not in cache, allocate a new one. |
709 | */ | | 679 | */ |
710 | mutex_exit(&dqlock); | | 680 | mutex_exit(&dqlock); |
711 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); | | 681 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); |
712 | /* | | 682 | /* |
713 | * Initialize the contents of the dquot structure. | | 683 | * Initialize the contents of the dquot structure. |
714 | */ | | 684 | */ |
715 | memset((char *)ndq, 0, sizeof *ndq); | | 685 | memset((char *)ndq, 0, sizeof *ndq); |
716 | ndq->dq_flags = 0; | | 686 | ndq->dq_flags = 0; |
717 | ndq->dq_id = id; | | 687 | ndq->dq_id = id; |
718 | ndq->dq_ump = ump; | | 688 | ndq->dq_ump = ump; |
719 | ndq->dq_type = type; | | 689 | ndq->dq_type = type; |
720 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); | | 690 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); |
721 | mutex_enter(&dqlock); | | 691 | mutex_enter(&dqlock); |
722 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | | 692 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; |
723 | LIST_FOREACH(dq, dqh, dq_hash) { | | 693 | LIST_FOREACH(dq, dqh, dq_hash) { |
724 | if (dq->dq_id != id || | | 694 | if (dq->dq_id != id || |
725 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | | 695 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) |
726 | continue; | | 696 | continue; |
727 | /* | | 697 | /* |
728 | * Another thread beat us allocating this dquot. | | 698 | * Another thread beat us allocating this dquot. |
729 | */ | | 699 | */ |
730 | KASSERT(dq->dq_cnt > 0); | | 700 | KASSERT(dq->dq_cnt > 0); |
731 | dqref(dq); | | 701 | dqref(dq); |
732 | mutex_exit(&dqlock); | | 702 | mutex_exit(&dqlock); |
733 | mutex_destroy(&ndq->dq_interlock); | | 703 | mutex_destroy(&ndq->dq_interlock); |
734 | pool_cache_put(dquot_cache, ndq); | | 704 | pool_cache_put(dquot_cache, ndq); |
735 | *dqp = dq; | | 705 | *dqp = dq; |
736 | return 0; | | 706 | return 0; |
737 | } | | 707 | } |
738 | dq = ndq; | | 708 | dq = ndq; |
739 | LIST_INSERT_HEAD(dqh, dq, dq_hash); | | 709 | LIST_INSERT_HEAD(dqh, dq, dq_hash); |
740 | dqref(dq); | | 710 | dqref(dq); |
741 | mutex_enter(&dq->dq_interlock); | | 711 | mutex_enter(&dq->dq_interlock); |
742 | mutex_exit(&dqlock); | | 712 | mutex_exit(&dqlock); |
743 | #ifdef QUOTA | | 713 | #ifdef QUOTA |
744 | if (ump->um_flags & UFS_QUOTA) | | 714 | if (ump->um_flags & UFS_QUOTA) |
745 | error = dq1get(dqvp, id, ump, type, dq); | | 715 | error = dq1get(dqvp, id, ump, type, dq); |
746 | #endif | | 716 | #endif |
747 | #ifdef QUOTA2 | | 717 | #ifdef QUOTA2 |
748 | if (ump->um_flags & UFS_QUOTA2) | | 718 | if (ump->um_flags & UFS_QUOTA2) |
749 | error = dq2get(dqvp, id, ump, type, dq); | | 719 | error = dq2get(dqvp, id, ump, type, dq); |
750 | #endif | | 720 | #endif |
751 | /* | | 721 | /* |
752 | * I/O error in reading quota file, release | | 722 | * I/O error in reading quota file, release |
753 | * quota structure and reflect problem to caller. | | 723 | * quota structure and reflect problem to caller. |
754 | */ | | 724 | */ |
755 | if (error) { | | 725 | if (error) { |
756 | mutex_enter(&dqlock); | | 726 | mutex_enter(&dqlock); |
757 | LIST_REMOVE(dq, dq_hash); | | 727 | LIST_REMOVE(dq, dq_hash); |
758 | mutex_exit(&dqlock); | | 728 | mutex_exit(&dqlock); |
759 | mutex_exit(&dq->dq_interlock); | | 729 | mutex_exit(&dq->dq_interlock); |
760 | dqrele(vp, dq); | | 730 | dqrele(vp, dq); |
761 | *dqp = NODQUOT; | | 731 | *dqp = NODQUOT; |
762 | return (error); | | 732 | return (error); |
763 | } | | 733 | } |
764 | mutex_exit(&dq->dq_interlock); | | 734 | mutex_exit(&dq->dq_interlock); |
765 | *dqp = dq; | | 735 | *dqp = dq; |
766 | return (0); | | 736 | return (0); |
767 | } | | 737 | } |
768 | | | 738 | |
769 | /* | | 739 | /* |
770 | * Obtain a reference to a dquot. | | 740 | * Obtain a reference to a dquot. |
771 | */ | | 741 | */ |
772 | void | | 742 | void |
773 | dqref(struct dquot *dq) | | 743 | dqref(struct dquot *dq) |
774 | { | | 744 | { |
775 | | | 745 | |
776 | KASSERT(mutex_owned(&dqlock)); | | 746 | KASSERT(mutex_owned(&dqlock)); |
777 | dq->dq_cnt++; | | 747 | dq->dq_cnt++; |
778 | KASSERT(dq->dq_cnt > 0); | | 748 | KASSERT(dq->dq_cnt > 0); |
779 | } | | 749 | } |
780 | | | 750 | |
781 | /* | | 751 | /* |
782 | * Release a reference to a dquot. | | 752 | * Release a reference to a dquot. |
783 | */ | | 753 | */ |
784 | void | | 754 | void |
785 | dqrele(struct vnode *vp, struct dquot *dq) | | 755 | dqrele(struct vnode *vp, struct dquot *dq) |
786 | { | | 756 | { |
787 | | | 757 | |
788 | if (dq == NODQUOT) | | 758 | if (dq == NODQUOT) |
789 | return; | | 759 | return; |
790 | mutex_enter(&dq->dq_interlock); | | 760 | mutex_enter(&dq->dq_interlock); |
791 | for (;;) { | | 761 | for (;;) { |
792 | mutex_enter(&dqlock); | | 762 | mutex_enter(&dqlock); |
793 | if (dq->dq_cnt > 1) { | | 763 | if (dq->dq_cnt > 1) { |
794 | dq->dq_cnt--; | | 764 | dq->dq_cnt--; |
795 | mutex_exit(&dqlock); | | 765 | mutex_exit(&dqlock); |
796 | mutex_exit(&dq->dq_interlock); | | 766 | mutex_exit(&dq->dq_interlock); |
797 | return; | | 767 | return; |
798 | } | | 768 | } |
799 | if ((dq->dq_flags & DQ_MOD) == 0) | | 769 | if ((dq->dq_flags & DQ_MOD) == 0) |
800 | break; | | 770 | break; |
801 | mutex_exit(&dqlock); | | 771 | mutex_exit(&dqlock); |
802 | #ifdef QUOTA | | 772 | #ifdef QUOTA |
803 | if (dq->dq_ump->um_flags & UFS_QUOTA) | | 773 | if (dq->dq_ump->um_flags & UFS_QUOTA) |
804 | (void) dq1sync(vp, dq); | | 774 | (void) dq1sync(vp, dq); |
805 | #endif | | 775 | #endif |
806 | #ifdef QUOTA2 | | 776 | #ifdef QUOTA2 |
807 | if (dq->dq_ump->um_flags & UFS_QUOTA2) | | 777 | if (dq->dq_ump->um_flags & UFS_QUOTA2) |
808 | (void) dq2sync(vp, dq); | | 778 | (void) dq2sync(vp, dq); |
809 | #endif | | 779 | #endif |
810 | } | | 780 | } |
811 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); | | 781 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); |
812 | LIST_REMOVE(dq, dq_hash); | | 782 | LIST_REMOVE(dq, dq_hash); |
813 | mutex_exit(&dqlock); | | 783 | mutex_exit(&dqlock); |
814 | mutex_exit(&dq->dq_interlock); | | 784 | mutex_exit(&dq->dq_interlock); |
815 | mutex_destroy(&dq->dq_interlock); | | 785 | mutex_destroy(&dq->dq_interlock); |
816 | pool_cache_put(dquot_cache, dq); | | 786 | pool_cache_put(dquot_cache, dq); |
817 | } | | 787 | } |
818 | | | 788 | |
819 | int | | 789 | int |
820 | qsync(struct mount *mp) | | 790 | qsync(struct mount *mp) |
821 | { | | 791 | { |
822 | struct ufsmount *ump = VFSTOUFS(mp); | | 792 | struct ufsmount *ump = VFSTOUFS(mp); |
823 | #ifdef QUOTA | | 793 | #ifdef QUOTA |
824 | if (ump->um_flags & UFS_QUOTA) | | 794 | if (ump->um_flags & UFS_QUOTA) |
825 | return q1sync(mp); | | 795 | return q1sync(mp); |
826 | #endif | | 796 | #endif |
827 | #ifdef QUOTA2 | | 797 | #ifdef QUOTA2 |
828 | if (ump->um_flags & UFS_QUOTA2) | | 798 | if (ump->um_flags & UFS_QUOTA2) |
829 | return q2sync(mp); | | 799 | return q2sync(mp); |
830 | #endif | | 800 | #endif |
831 | return 0; | | 801 | return 0; |
832 | } | | 802 | } |
833 | | | 803 | |
834 | #ifdef DIAGNOSTIC | | 804 | #ifdef DIAGNOSTIC |
835 | /* | | 805 | /* |
836 | * Check the hash chains for stray dquot's. | | 806 | * Check the hash chains for stray dquot's. |
837 | */ | | 807 | */ |
838 | void | | 808 | void |
839 | dqflush(struct vnode *vp) | | 809 | dqflush(struct vnode *vp) |
840 | { | | 810 | { |
841 | struct dquot *dq; | | 811 | struct dquot *dq; |
842 | int i; | | 812 | int i; |
843 | | | 813 | |
844 | mutex_enter(&dqlock); | | 814 | mutex_enter(&dqlock); |
845 | for (i = 0; i <= dqhash; i++) | | 815 | for (i = 0; i <= dqhash; i++) |
846 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) | | 816 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) |
847 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); | | 817 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); |
848 | mutex_exit(&dqlock); | | 818 | mutex_exit(&dqlock); |
849 | } | | 819 | } |
850 | #endif | | 820 | #endif |