Move proplib bits for QUOTACTL_QUOTAOFF out of the ufs code. This change requires a kernel version bump.diff -r1.31 -r1.32 src/sys/kern/vfs_quotactl.c
(dholland)
--- src/sys/kern/vfs_quotactl.c 2012/01/29 07:11:12 1.31
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 07:11:55 1.32
@@ -1,889 +1,893 @@ | @@ -1,889 +1,893 @@ | |||
1 | /* $NetBSD: vfs_quotactl.c,v 1.31 2012/01/29 07:11:12 dholland Exp $ */ | 1 | /* $NetBSD: vfs_quotactl.c,v 1.32 2012/01/29 07:11:55 dholland Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1991, 1993, 1994 | 4 | * Copyright (c) 1991, 1993, 1994 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * (c) UNIX System Laboratories, Inc. | 6 | * (c) UNIX System Laboratories, Inc. | |
7 | * All or some portions of this file are derived from material licensed | 7 | * All or some portions of this file are derived from material licensed | |
8 | * to the University of California by American Telephone and Telegraph | 8 | * to the University of California by American Telephone and Telegraph | |
9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | 9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
10 | * the permission of UNIX System Laboratories, Inc. | 10 | * the permission of UNIX System Laboratories, Inc. | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | 15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | 16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | 17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | 18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | 19 | * documentation and/or other materials provided with the distribution. | |
20 | * 3. Neither the name of the University nor the names of its contributors | 20 | * 3. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | 21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | 22 | * without specific prior written permission. | |
23 | * | 23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | 34 | * SUCH DAMAGE. | |
35 | * | 35 | * | |
36 | * @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 | 36 | * @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 | |
37 | * From NetBSD: ufs_vfsops.c,v 1.42 2011/03/24 17:05:46 bouyer Exp | 37 | * From NetBSD: ufs_vfsops.c,v 1.42 2011/03/24 17:05:46 bouyer Exp | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | /* | 40 | /* | |
41 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | 41 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | |
42 | * The Regents of the University of California. All rights reserved. | 42 | * The Regents of the University of California. All rights reserved. | |
43 | * | 43 | * | |
44 | * This code is derived from software contributed to Berkeley by | 44 | * This code is derived from software contributed to Berkeley by | |
45 | * Robert Elz at The University of Melbourne. | 45 | * Robert Elz at The University of Melbourne. | |
46 | * | 46 | * | |
47 | * Redistribution and use in source and binary forms, with or without | 47 | * Redistribution and use in source and binary forms, with or without | |
48 | * modification, are permitted provided that the following conditions | 48 | * modification, are permitted provided that the following conditions | |
49 | * are met: | 49 | * are met: | |
50 | * 1. Redistributions of source code must retain the above copyright | 50 | * 1. Redistributions of source code must retain the above copyright | |
51 | * notice, this list of conditions and the following disclaimer. | 51 | * notice, this list of conditions and the following disclaimer. | |
52 | * 2. Redistributions in binary form must reproduce the above copyright | 52 | * 2. Redistributions in binary form must reproduce the above copyright | |
53 | * notice, this list of conditions and the following disclaimer in the | 53 | * notice, this list of conditions and the following disclaimer in the | |
54 | * documentation and/or other materials provided with the distribution. | 54 | * documentation and/or other materials provided with the distribution. | |
55 | * 3. Neither the name of the University nor the names of its contributors | 55 | * 3. Neither the name of the University nor the names of its contributors | |
56 | * may be used to endorse or promote products derived from this software | 56 | * may be used to endorse or promote products derived from this software | |
57 | * without specific prior written permission. | 57 | * without specific prior written permission. | |
58 | * | 58 | * | |
59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
69 | * SUCH DAMAGE. | 69 | * SUCH DAMAGE. | |
70 | * | 70 | * | |
71 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | 71 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | |
72 | * From NetBSD: ufs_quota.c,v 1.70 2011/03/24 17:05:46 bouyer Exp | 72 | * From NetBSD: ufs_quota.c,v 1.70 2011/03/24 17:05:46 bouyer Exp | |
73 | */ | 73 | */ | |
74 | 74 | |||
75 | /* | 75 | /* | |
76 | * Note that both of the copyrights above are moderately spurious; | 76 | * Note that both of the copyrights above are moderately spurious; | |
77 | * this code should almost certainly have the Copyright 2010 Manuel | 77 | * this code should almost certainly have the Copyright 2010 Manuel | |
78 | * Bouyer notice and license found in e.g. sys/ufs/ufs/quota2_subr.c. | 78 | * Bouyer notice and license found in e.g. sys/ufs/ufs/quota2_subr.c. | |
79 | * However, they're what was on the files this code was sliced out of. | 79 | * However, they're what was on the files this code was sliced out of. | |
80 | */ | 80 | */ | |
81 | 81 | |||
82 | #include <sys/cdefs.h> | 82 | #include <sys/cdefs.h> | |
83 | __KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.31 2012/01/29 07:11:12 dholland Exp $"); | 83 | __KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.32 2012/01/29 07:11:55 dholland Exp $"); | |
84 | 84 | |||
85 | #include <sys/malloc.h> /* XXX: temporary */ | 85 | #include <sys/malloc.h> /* XXX: temporary */ | |
86 | #include <sys/mount.h> | 86 | #include <sys/mount.h> | |
87 | #include <sys/quota.h> | 87 | #include <sys/quota.h> | |
88 | #include <sys/quotactl.h> | 88 | #include <sys/quotactl.h> | |
89 | #include <quota/quotaprop.h> | 89 | #include <quota/quotaprop.h> | |
90 | 90 | |||
91 | static int | 91 | static int | |
92 | vfs_quotactl_getversion(struct mount *mp, | 92 | vfs_quotactl_getversion(struct mount *mp, | |
93 | prop_dictionary_t cmddict, int q2type, | 93 | prop_dictionary_t cmddict, int q2type, | |
94 | prop_array_t datas) | 94 | prop_array_t datas) | |
95 | { | 95 | { | |
96 | prop_array_t replies; | 96 | prop_array_t replies; | |
97 | prop_dictionary_t data; | 97 | prop_dictionary_t data; | |
98 | int q2version; | 98 | int q2version; | |
99 | struct vfs_quotactl_args args; | 99 | struct vfs_quotactl_args args; | |
100 | int error; | 100 | int error; | |
101 | 101 | |||
102 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 102 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
103 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 103 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
104 | 104 | |||
105 | args.qc_type = QCT_GETVERSION; | 105 | args.qc_type = QCT_GETVERSION; | |
106 | args.u.getversion.qc_version_ret = &q2version; | 106 | args.u.getversion.qc_version_ret = &q2version; | |
107 | error = VFS_QUOTACTL(mp, QUOTACTL_GETVERSION, &args); | 107 | error = VFS_QUOTACTL(mp, QUOTACTL_GETVERSION, &args); | |
108 | if (error) { | 108 | if (error) { | |
109 | return error; | 109 | return error; | |
110 | } | 110 | } | |
111 | 111 | |||
112 | data = prop_dictionary_create(); | 112 | data = prop_dictionary_create(); | |
113 | if (data == NULL) { | 113 | if (data == NULL) { | |
114 | return ENOMEM; | 114 | return ENOMEM; | |
115 | } | 115 | } | |
116 | 116 | |||
117 | if (!prop_dictionary_set_int8(data, "version", q2version)) { | 117 | if (!prop_dictionary_set_int8(data, "version", q2version)) { | |
118 | prop_object_release(data); | 118 | prop_object_release(data); | |
119 | return ENOMEM; | 119 | return ENOMEM; | |
120 | } | 120 | } | |
121 | 121 | |||
122 | replies = prop_array_create(); | 122 | replies = prop_array_create(); | |
123 | if (replies == NULL) { | 123 | if (replies == NULL) { | |
124 | prop_object_release(data); | 124 | prop_object_release(data); | |
125 | return ENOMEM; | 125 | return ENOMEM; | |
126 | } | 126 | } | |
127 | 127 | |||
128 | if (!prop_array_add_and_rel(replies, data)) { | 128 | if (!prop_array_add_and_rel(replies, data)) { | |
129 | prop_object_release(data); | 129 | prop_object_release(data); | |
130 | prop_object_release(replies); | 130 | prop_object_release(replies); | |
131 | return ENOMEM; | 131 | return ENOMEM; | |
132 | } | 132 | } | |
133 | 133 | |||
134 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 134 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
135 | prop_object_release(replies); | 135 | prop_object_release(replies); | |
136 | return ENOMEM; | 136 | return ENOMEM; | |
137 | } | 137 | } | |
138 | 138 | |||
139 | return error; | 139 | return error; | |
140 | } | 140 | } | |
141 | 141 | |||
142 | static int | 142 | static int | |
143 | vfs_quotactl_quotaon(struct mount *mp, | 143 | vfs_quotactl_quotaon(struct mount *mp, | |
144 | prop_dictionary_t cmddict, int q2type, | 144 | prop_dictionary_t cmddict, int q2type, | |
145 | prop_array_t datas) | 145 | prop_array_t datas) | |
146 | { | 146 | { | |
147 | prop_dictionary_t data; | 147 | prop_dictionary_t data; | |
148 | const char *qfile; | 148 | const char *qfile; | |
149 | struct vfs_quotactl_args args; | 149 | struct vfs_quotactl_args args; | |
150 | 150 | |||
151 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 151 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
152 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 152 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
153 | 153 | |||
154 | if (prop_array_count(datas) != 1) | 154 | if (prop_array_count(datas) != 1) | |
155 | return EINVAL; | 155 | return EINVAL; | |
156 | 156 | |||
157 | data = prop_array_get(datas, 0); | 157 | data = prop_array_get(datas, 0); | |
158 | if (data == NULL) | 158 | if (data == NULL) | |
159 | return ENOMEM; | 159 | return ENOMEM; | |
160 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", | 160 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", | |
161 | &qfile)) | 161 | &qfile)) | |
162 | return EINVAL; | 162 | return EINVAL; | |
163 | 163 | |||
164 | args.qc_type = QCT_QUOTAON; | 164 | args.qc_type = QCT_QUOTAON; | |
165 | args.u.quotaon.qc_idtype = q2type; | 165 | args.u.quotaon.qc_idtype = q2type; | |
166 | args.u.quotaon.qc_quotafile = qfile; | 166 | args.u.quotaon.qc_quotafile = qfile; | |
167 | return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args); | 167 | return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args); | |
168 | } | 168 | } | |
169 | 169 | |||
170 | static int | 170 | static int | |
171 | vfs_quotactl_quotaoff(struct mount *mp, | 171 | vfs_quotactl_quotaoff(struct mount *mp, | |
172 | prop_dictionary_t cmddict, int q2type, | 172 | prop_dictionary_t cmddict, int q2type, | |
173 | prop_array_t datas) | 173 | prop_array_t datas) | |
174 | { | 174 | { | |
175 | struct vfs_quotactl_args args; | 175 | struct vfs_quotactl_args args; | |
176 | 176 | |||
177 | args.qc_type = QCT_PROPLIB; | 177 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
178 | args.u.proplib.qc_cmddict = cmddict; | 178 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
179 | args.u.proplib.qc_q2type = q2type; | 179 | ||
180 | args.u.proplib.qc_datas = datas; | 180 | if (prop_array_count(datas) != 0) | |
181 | return EINVAL; | |||
182 | ||||
183 | args.qc_type = QCT_QUOTAOFF; | |||
184 | args.u.quotaoff.qc_idtype = q2type; | |||
181 | return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args); | 185 | return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args); | |
182 | } | 186 | } | |
183 | 187 | |||
184 | static int | 188 | static int | |
185 | vfs_quotactl_get_addreply(const struct quotakey *qk, | 189 | vfs_quotactl_get_addreply(const struct quotakey *qk, | |
186 | const struct quotaval *blocks, | 190 | const struct quotaval *blocks, | |
187 | const struct quotaval *files, | 191 | const struct quotaval *files, | |
188 | prop_array_t replies) | 192 | prop_array_t replies) | |
189 | { | 193 | { | |
190 | prop_dictionary_t dict; | 194 | prop_dictionary_t dict; | |
191 | id_t id; | 195 | id_t id; | |
192 | int defaultq; | 196 | int defaultq; | |
193 | uint64_t *valuesp[QUOTA_NLIMITS]; | 197 | uint64_t *valuesp[QUOTA_NLIMITS]; | |
194 | 198 | |||
195 | /* XXX illegal casts */ | 199 | /* XXX illegal casts */ | |
196 | valuesp[QUOTA_LIMIT_BLOCK] = (void *)(intptr_t)&blocks->qv_hardlimit; | 200 | valuesp[QUOTA_LIMIT_BLOCK] = (void *)(intptr_t)&blocks->qv_hardlimit; | |
197 | valuesp[QUOTA_LIMIT_FILE] = (void *)(intptr_t)&files->qv_hardlimit; | 201 | valuesp[QUOTA_LIMIT_FILE] = (void *)(intptr_t)&files->qv_hardlimit; | |
198 | 202 | |||
199 | if (qk->qk_id == QUOTA_DEFAULTID) { | 203 | if (qk->qk_id == QUOTA_DEFAULTID) { | |
200 | id = 0; | 204 | id = 0; | |
201 | defaultq = 1; | 205 | defaultq = 1; | |
202 | } else { | 206 | } else { | |
203 | id = qk->qk_id; | 207 | id = qk->qk_id; | |
204 | defaultq = 0; | 208 | defaultq = 0; | |
205 | } | 209 | } | |
206 | 210 | |||
207 | dict = quota64toprop(id, defaultq, valuesp, | 211 | dict = quota64toprop(id, defaultq, valuesp, | |
208 | ufs_quota_entry_names, UFS_QUOTA_NENTRIES, | 212 | ufs_quota_entry_names, UFS_QUOTA_NENTRIES, | |
209 | ufs_quota_limit_names, QUOTA_NLIMITS); | 213 | ufs_quota_limit_names, QUOTA_NLIMITS); | |
210 | if (dict == NULL) | 214 | if (dict == NULL) | |
211 | return ENOMEM; | 215 | return ENOMEM; | |
212 | if (!prop_array_add_and_rel(replies, dict)) { | 216 | if (!prop_array_add_and_rel(replies, dict)) { | |
213 | prop_object_release(dict); | 217 | prop_object_release(dict); | |
214 | return ENOMEM; | 218 | return ENOMEM; | |
215 | } | 219 | } | |
216 | 220 | |||
217 | return 0; | 221 | return 0; | |
218 | } | 222 | } | |
219 | 223 | |||
220 | static int | 224 | static int | |
221 | vfs_quotactl_get(struct mount *mp, | 225 | vfs_quotactl_get(struct mount *mp, | |
222 | prop_dictionary_t cmddict, int idtype, | 226 | prop_dictionary_t cmddict, int idtype, | |
223 | prop_array_t datas) | 227 | prop_array_t datas) | |
224 | { | 228 | { | |
225 | prop_object_iterator_t iter; | 229 | prop_object_iterator_t iter; | |
226 | prop_dictionary_t data; | 230 | prop_dictionary_t data; | |
227 | prop_array_t replies; | 231 | prop_array_t replies; | |
228 | uint32_t id; | 232 | uint32_t id; | |
229 | const char *idstr; | 233 | const char *idstr; | |
230 | struct vfs_quotactl_args args; | 234 | struct vfs_quotactl_args args; | |
231 | struct quotakey qk; | 235 | struct quotakey qk; | |
232 | struct quotaval blocks, files; | 236 | struct quotaval blocks, files; | |
233 | int error; | 237 | int error; | |
234 | 238 | |||
235 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 239 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
236 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 240 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
237 | 241 | |||
238 | replies = prop_array_create(); | 242 | replies = prop_array_create(); | |
239 | if (replies == NULL) { | 243 | if (replies == NULL) { | |
240 | return ENOMEM; | 244 | return ENOMEM; | |
241 | } | 245 | } | |
242 | 246 | |||
243 | iter = prop_array_iterator(datas); | 247 | iter = prop_array_iterator(datas); | |
244 | if (iter == NULL) { | 248 | if (iter == NULL) { | |
245 | prop_object_release(replies); | 249 | prop_object_release(replies); | |
246 | return ENOMEM; | 250 | return ENOMEM; | |
247 | } | 251 | } | |
248 | 252 | |||
249 | while ((data = prop_object_iterator_next(iter)) != NULL) { | 253 | while ((data = prop_object_iterator_next(iter)) != NULL) { | |
250 | qk.qk_idtype = idtype; | 254 | qk.qk_idtype = idtype; | |
251 | 255 | |||
252 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | 256 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | |
253 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | 257 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | |
254 | &idstr)) | 258 | &idstr)) | |
255 | continue; | 259 | continue; | |
256 | if (strcmp(idstr, "default")) { | 260 | if (strcmp(idstr, "default")) { | |
257 | error = EINVAL; | 261 | error = EINVAL; | |
258 | goto fail; | 262 | goto fail; | |
259 | } | 263 | } | |
260 | qk.qk_id = QUOTA_DEFAULTID; | 264 | qk.qk_id = QUOTA_DEFAULTID; | |
261 | } else { | 265 | } else { | |
262 | qk.qk_id = id; | 266 | qk.qk_id = id; | |
263 | } | 267 | } | |
264 | 268 | |||
265 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | 269 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | |
266 | 270 | |||
267 | args.qc_type = QCT_GET; | 271 | args.qc_type = QCT_GET; | |
268 | args.u.get.qc_key = &qk; | 272 | args.u.get.qc_key = &qk; | |
269 | args.u.get.qc_ret = &blocks; | 273 | args.u.get.qc_ret = &blocks; | |
270 | error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); | 274 | error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); | |
271 | if (error == EPERM) { | 275 | if (error == EPERM) { | |
272 | /* XXX does this make sense? */ | 276 | /* XXX does this make sense? */ | |
273 | continue; | 277 | continue; | |
274 | } else if (error == ENOENT) { | 278 | } else if (error == ENOENT) { | |
275 | /* XXX does *this* make sense? */ | 279 | /* XXX does *this* make sense? */ | |
276 | continue; | 280 | continue; | |
277 | } else if (error) { | 281 | } else if (error) { | |
278 | goto fail; | 282 | goto fail; | |
279 | } | 283 | } | |
280 | 284 | |||
281 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | 285 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | |
282 | 286 | |||
283 | args.qc_type = QCT_GET; | 287 | args.qc_type = QCT_GET; | |
284 | args.u.get.qc_key = &qk; | 288 | args.u.get.qc_key = &qk; | |
285 | args.u.get.qc_ret = &files; | 289 | args.u.get.qc_ret = &files; | |
286 | error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); | 290 | error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); | |
287 | if (error == EPERM) { | 291 | if (error == EPERM) { | |
288 | /* XXX does this make sense? */ | 292 | /* XXX does this make sense? */ | |
289 | continue; | 293 | continue; | |
290 | } else if (error == ENOENT) { | 294 | } else if (error == ENOENT) { | |
291 | /* XXX does *this* make sense? */ | 295 | /* XXX does *this* make sense? */ | |
292 | continue; | 296 | continue; | |
293 | } else if (error) { | 297 | } else if (error) { | |
294 | goto fail; | 298 | goto fail; | |
295 | } | 299 | } | |
296 | 300 | |||
297 | error = vfs_quotactl_get_addreply(&qk, &blocks, &files, | 301 | error = vfs_quotactl_get_addreply(&qk, &blocks, &files, | |
298 | replies); | 302 | replies); | |
299 | } | 303 | } | |
300 | 304 | |||
301 | prop_object_iterator_release(iter); | 305 | prop_object_iterator_release(iter); | |
302 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 306 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
303 | error = ENOMEM; | 307 | error = ENOMEM; | |
304 | } else { | 308 | } else { | |
305 | error = 0; | 309 | error = 0; | |
306 | } | 310 | } | |
307 | 311 | |||
308 | return error; | 312 | return error; | |
309 | 313 | |||
310 | fail: | 314 | fail: | |
311 | prop_object_iterator_release(iter); | 315 | prop_object_iterator_release(iter); | |
312 | prop_object_release(replies); | 316 | prop_object_release(replies); | |
313 | return error; | 317 | return error; | |
314 | } | 318 | } | |
315 | 319 | |||
316 | static int | 320 | static int | |
317 | vfs_quotactl_put_extractinfo(prop_dictionary_t data, | 321 | vfs_quotactl_put_extractinfo(prop_dictionary_t data, | |
318 | struct quotaval *blocks, struct quotaval *files) | 322 | struct quotaval *blocks, struct quotaval *files) | |
319 | { | 323 | { | |
320 | /* | 324 | /* | |
321 | * So, the way proptoquota64 works is that you pass it an | 325 | * So, the way proptoquota64 works is that you pass it an | |
322 | * array of pointers to uint64. Each of these pointers is | 326 | * array of pointers to uint64. Each of these pointers is | |
323 | * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This | 327 | * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This | |
324 | * array of pointers is the second argument. The third and | 328 | * array of pointers is the second argument. The third and | |
325 | * forth argument are the names of the five values to extract, | 329 | * forth argument are the names of the five values to extract, | |
326 | * and UFS_QUOTA_NENTRIES. The last two arguments are the | 330 | * and UFS_QUOTA_NENTRIES. The last two arguments are the | |
327 | * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK, | 331 | * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK, | |
328 | * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of | 332 | * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of | |
329 | * the existing code was unsafely casting struct quotaval | 333 | * the existing code was unsafely casting struct quotaval | |
330 | * (formerly struct ufs_quota_entry) to (uint64_t *) and using | 334 | * (formerly struct ufs_quota_entry) to (uint64_t *) and using | |
331 | * that as the block of 5 uint64s. Or worse, pointing to | 335 | * that as the block of 5 uint64s. Or worse, pointing to | |
332 | * subregions of that and reducing the number of uint64s to | 336 | * subregions of that and reducing the number of uint64s to | |
333 | * pull "adjacent" values. Demons fly out of your nose! | 337 | * pull "adjacent" values. Demons fly out of your nose! | |
334 | */ | 338 | */ | |
335 | 339 | |||
336 | uint64_t bvals[UFS_QUOTA_NENTRIES]; | 340 | uint64_t bvals[UFS_QUOTA_NENTRIES]; | |
337 | uint64_t fvals[UFS_QUOTA_NENTRIES]; | 341 | uint64_t fvals[UFS_QUOTA_NENTRIES]; | |
338 | uint64_t *valptrs[QUOTA_NLIMITS]; | 342 | uint64_t *valptrs[QUOTA_NLIMITS]; | |
339 | int error; | 343 | int error; | |
340 | 344 | |||
341 | valptrs[QUOTA_LIMIT_BLOCK] = bvals; | 345 | valptrs[QUOTA_LIMIT_BLOCK] = bvals; | |
342 | valptrs[QUOTA_LIMIT_FILE] = fvals; | 346 | valptrs[QUOTA_LIMIT_FILE] = fvals; | |
343 | error = proptoquota64(data, valptrs, | 347 | error = proptoquota64(data, valptrs, | |
344 | ufs_quota_entry_names, UFS_QUOTA_NENTRIES, | 348 | ufs_quota_entry_names, UFS_QUOTA_NENTRIES, | |
345 | ufs_quota_limit_names, QUOTA_NLIMITS); | 349 | ufs_quota_limit_names, QUOTA_NLIMITS); | |
346 | if (error) { | 350 | if (error) { | |
347 | return error; | 351 | return error; | |
348 | } | 352 | } | |
349 | 353 | |||
350 | /* | 354 | /* | |
351 | * There are no symbolic constants for these indexes! | 355 | * There are no symbolic constants for these indexes! | |
352 | */ | 356 | */ | |
353 | 357 | |||
354 | blocks->qv_hardlimit = bvals[0]; | 358 | blocks->qv_hardlimit = bvals[0]; | |
355 | blocks->qv_softlimit = bvals[1]; | 359 | blocks->qv_softlimit = bvals[1]; | |
356 | blocks->qv_usage = bvals[2]; | 360 | blocks->qv_usage = bvals[2]; | |
357 | blocks->qv_expiretime = bvals[3]; | 361 | blocks->qv_expiretime = bvals[3]; | |
358 | blocks->qv_grace = bvals[4]; | 362 | blocks->qv_grace = bvals[4]; | |
359 | files->qv_hardlimit = fvals[0]; | 363 | files->qv_hardlimit = fvals[0]; | |
360 | files->qv_softlimit = fvals[1]; | 364 | files->qv_softlimit = fvals[1]; | |
361 | files->qv_usage = fvals[2]; | 365 | files->qv_usage = fvals[2]; | |
362 | files->qv_expiretime = fvals[3]; | 366 | files->qv_expiretime = fvals[3]; | |
363 | files->qv_grace = fvals[4]; | 367 | files->qv_grace = fvals[4]; | |
364 | 368 | |||
365 | return 0; | 369 | return 0; | |
366 | } | 370 | } | |
367 | 371 | |||
368 | static int | 372 | static int | |
369 | vfs_quotactl_put(struct mount *mp, | 373 | vfs_quotactl_put(struct mount *mp, | |
370 | prop_dictionary_t cmddict, int q2type, | 374 | prop_dictionary_t cmddict, int q2type, | |
371 | prop_array_t datas) | 375 | prop_array_t datas) | |
372 | { | 376 | { | |
373 | prop_array_t replies; | 377 | prop_array_t replies; | |
374 | prop_object_iterator_t iter; | 378 | prop_object_iterator_t iter; | |
375 | prop_dictionary_t data; | 379 | prop_dictionary_t data; | |
376 | int defaultq; | 380 | int defaultq; | |
377 | uint32_t id; | 381 | uint32_t id; | |
378 | const char *idstr; | 382 | const char *idstr; | |
379 | struct quotakey qk; | 383 | struct quotakey qk; | |
380 | struct quotaval blocks, files; | 384 | struct quotaval blocks, files; | |
381 | struct vfs_quotactl_args args; | 385 | struct vfs_quotactl_args args; | |
382 | int error; | 386 | int error; | |
383 | 387 | |||
384 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 388 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
385 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 389 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
386 | 390 | |||
387 | replies = prop_array_create(); | 391 | replies = prop_array_create(); | |
388 | if (replies == NULL) | 392 | if (replies == NULL) | |
389 | return ENOMEM; | 393 | return ENOMEM; | |
390 | 394 | |||
391 | iter = prop_array_iterator(datas); | 395 | iter = prop_array_iterator(datas); | |
392 | if (iter == NULL) { | 396 | if (iter == NULL) { | |
393 | prop_object_release(replies); | 397 | prop_object_release(replies); | |
394 | return ENOMEM; | 398 | return ENOMEM; | |
395 | } | 399 | } | |
396 | 400 | |||
397 | while ((data = prop_object_iterator_next(iter)) != NULL) { | 401 | while ((data = prop_object_iterator_next(iter)) != NULL) { | |
398 | 402 | |||
399 | KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY); | 403 | KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY); | |
400 | 404 | |||
401 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | 405 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | |
402 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | 406 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | |
403 | &idstr)) | 407 | &idstr)) | |
404 | continue; | 408 | continue; | |
405 | if (strcmp(idstr, "default")) | 409 | if (strcmp(idstr, "default")) | |
406 | continue; | 410 | continue; | |
407 | id = 0; | 411 | id = 0; | |
408 | defaultq = 1; | 412 | defaultq = 1; | |
409 | } else { | 413 | } else { | |
410 | defaultq = 0; | 414 | defaultq = 0; | |
411 | } | 415 | } | |
412 | 416 | |||
413 | error = vfs_quotactl_put_extractinfo(data, &blocks, &files); | 417 | error = vfs_quotactl_put_extractinfo(data, &blocks, &files); | |
414 | if (error) { | 418 | if (error) { | |
415 | goto err; | 419 | goto err; | |
416 | } | 420 | } | |
417 | 421 | |||
418 | qk.qk_idtype = q2type; | 422 | qk.qk_idtype = q2type; | |
419 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | 423 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | |
420 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | 424 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | |
421 | 425 | |||
422 | args.qc_type = QCT_PUT; | 426 | args.qc_type = QCT_PUT; | |
423 | args.u.put.qc_key = &qk; | 427 | args.u.put.qc_key = &qk; | |
424 | args.u.put.qc_val = &blocks; | 428 | args.u.put.qc_val = &blocks; | |
425 | error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); | 429 | error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); | |
426 | if (error) { | 430 | if (error) { | |
427 | goto err; | 431 | goto err; | |
428 | } | 432 | } | |
429 | 433 | |||
430 | qk.qk_idtype = q2type; | 434 | qk.qk_idtype = q2type; | |
431 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | 435 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | |
432 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | 436 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | |
433 | 437 | |||
434 | args.qc_type = QCT_PUT; | 438 | args.qc_type = QCT_PUT; | |
435 | args.u.put.qc_key = &qk; | 439 | args.u.put.qc_key = &qk; | |
436 | args.u.put.qc_val = &files; | 440 | args.u.put.qc_val = &files; | |
437 | error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); | 441 | error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); | |
438 | if (error) { | 442 | if (error) { | |
439 | goto err; | 443 | goto err; | |
440 | } | 444 | } | |
441 | } | 445 | } | |
442 | prop_object_iterator_release(iter); | 446 | prop_object_iterator_release(iter); | |
443 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 447 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
444 | error = ENOMEM; | 448 | error = ENOMEM; | |
445 | } else { | 449 | } else { | |
446 | error = 0; | 450 | error = 0; | |
447 | } | 451 | } | |
448 | return error; | 452 | return error; | |
449 | err: | 453 | err: | |
450 | prop_object_iterator_release(iter); | 454 | prop_object_iterator_release(iter); | |
451 | prop_object_release(replies); | 455 | prop_object_release(replies); | |
452 | return error; | 456 | return error; | |
453 | } | 457 | } | |
454 | 458 | |||
455 | static prop_dictionary_t | 459 | static prop_dictionary_t | |
456 | vfs_quotactl_getall_makereply(const struct quotakey *key) | 460 | vfs_quotactl_getall_makereply(const struct quotakey *key) | |
457 | { | 461 | { | |
458 | prop_dictionary_t dict; | 462 | prop_dictionary_t dict; | |
459 | id_t id; | 463 | id_t id; | |
460 | int defaultq; | 464 | int defaultq; | |
461 | 465 | |||
462 | dict = prop_dictionary_create(); | 466 | dict = prop_dictionary_create(); | |
463 | if (dict == NULL) | 467 | if (dict == NULL) | |
464 | return NULL; | 468 | return NULL; | |
465 | 469 | |||
466 | id = key->qk_id; | 470 | id = key->qk_id; | |
467 | if (id == QUOTA_DEFAULTID) { | 471 | if (id == QUOTA_DEFAULTID) { | |
468 | id = 0; | 472 | id = 0; | |
469 | defaultq = 1; | 473 | defaultq = 1; | |
470 | } else { | 474 | } else { | |
471 | defaultq = 0; | 475 | defaultq = 0; | |
472 | } | 476 | } | |
473 | 477 | |||
474 | if (defaultq) { | 478 | if (defaultq) { | |
475 | if (!prop_dictionary_set_cstring_nocopy(dict, "id", | 479 | if (!prop_dictionary_set_cstring_nocopy(dict, "id", | |
476 | "default")) { | 480 | "default")) { | |
477 | goto err; | 481 | goto err; | |
478 | } | 482 | } | |
479 | } else { | 483 | } else { | |
480 | if (!prop_dictionary_set_uint32(dict, "id", id)) { | 484 | if (!prop_dictionary_set_uint32(dict, "id", id)) { | |
481 | goto err; | 485 | goto err; | |
482 | } | 486 | } | |
483 | } | 487 | } | |
484 | 488 | |||
485 | return dict; | 489 | return dict; | |
486 | 490 | |||
487 | err: | 491 | err: | |
488 | prop_object_release(dict); | 492 | prop_object_release(dict); | |
489 | return NULL; | 493 | return NULL; | |
490 | } | 494 | } | |
491 | 495 | |||
492 | static int | 496 | static int | |
493 | vfs_quotactl_getall_addreply(prop_dictionary_t thisreply, | 497 | vfs_quotactl_getall_addreply(prop_dictionary_t thisreply, | |
494 | const struct quotakey *key, const struct quotaval *val) | 498 | const struct quotakey *key, const struct quotaval *val) | |
495 | { | 499 | { | |
496 | #define INITQVNAMES_ALL { \ | 500 | #define INITQVNAMES_ALL { \ | |
497 | QUOTADICT_LIMIT_HARD, \ | 501 | QUOTADICT_LIMIT_HARD, \ | |
498 | QUOTADICT_LIMIT_SOFT, \ | 502 | QUOTADICT_LIMIT_SOFT, \ | |
499 | QUOTADICT_LIMIT_USAGE, \ | 503 | QUOTADICT_LIMIT_USAGE, \ | |
500 | QUOTADICT_LIMIT_ETIME, \ | 504 | QUOTADICT_LIMIT_ETIME, \ | |
501 | QUOTADICT_LIMIT_GTIME \ | 505 | QUOTADICT_LIMIT_GTIME \ | |
502 | } | 506 | } | |
503 | #define N_QV 5 | 507 | #define N_QV 5 | |
504 | 508 | |||
505 | const char *val_names[] = INITQVNAMES_ALL; | 509 | const char *val_names[] = INITQVNAMES_ALL; | |
506 | uint64_t vals[N_QV]; | 510 | uint64_t vals[N_QV]; | |
507 | prop_dictionary_t dict2; | 511 | prop_dictionary_t dict2; | |
508 | const char *objtypename; | 512 | const char *objtypename; | |
509 | 513 | |||
510 | switch (key->qk_objtype) { | 514 | switch (key->qk_objtype) { | |
511 | case QUOTA_OBJTYPE_BLOCKS: | 515 | case QUOTA_OBJTYPE_BLOCKS: | |
512 | objtypename = QUOTADICT_LTYPE_BLOCK; | 516 | objtypename = QUOTADICT_LTYPE_BLOCK; | |
513 | break; | 517 | break; | |
514 | case QUOTA_OBJTYPE_FILES: | 518 | case QUOTA_OBJTYPE_FILES: | |
515 | objtypename = QUOTADICT_LTYPE_FILE; | 519 | objtypename = QUOTADICT_LTYPE_FILE; | |
516 | break; | 520 | break; | |
517 | default: | 521 | default: | |
518 | return EINVAL; | 522 | return EINVAL; | |
519 | } | 523 | } | |
520 | 524 | |||
521 | vals[0] = val->qv_hardlimit; | 525 | vals[0] = val->qv_hardlimit; | |
522 | vals[1] = val->qv_softlimit; | 526 | vals[1] = val->qv_softlimit; | |
523 | vals[2] = val->qv_usage; | 527 | vals[2] = val->qv_usage; | |
524 | vals[3] = val->qv_expiretime; | 528 | vals[3] = val->qv_expiretime; | |
525 | vals[4] = val->qv_grace; | 529 | vals[4] = val->qv_grace; | |
526 | dict2 = limits64toprop(vals, val_names, N_QV); | 530 | dict2 = limits64toprop(vals, val_names, N_QV); | |
527 | if (dict2 == NULL) | 531 | if (dict2 == NULL) | |
528 | return ENOMEM; | 532 | return ENOMEM; | |
529 | 533 | |||
530 | if (!prop_dictionary_set_and_rel(thisreply, objtypename, dict2)) | 534 | if (!prop_dictionary_set_and_rel(thisreply, objtypename, dict2)) | |
531 | return ENOMEM; | 535 | return ENOMEM; | |
532 | 536 | |||
533 | return 0; | 537 | return 0; | |
534 | } | 538 | } | |
535 | 539 | |||
536 | static int | 540 | static int | |
537 | vfs_quotactl_getall(struct mount *mp, | 541 | vfs_quotactl_getall(struct mount *mp, | |
538 | prop_dictionary_t cmddict, int q2type, | 542 | prop_dictionary_t cmddict, int q2type, | |
539 | prop_array_t datas) | 543 | prop_array_t datas) | |
540 | { | 544 | { | |
541 | struct quotakcursor cursor; | 545 | struct quotakcursor cursor; | |
542 | struct quotakey *keys; | 546 | struct quotakey *keys; | |
543 | struct quotaval *vals; | 547 | struct quotaval *vals; | |
544 | unsigned loopmax = 8; | 548 | unsigned loopmax = 8; | |
545 | unsigned loopnum; | 549 | unsigned loopnum; | |
546 | int skipidtype; | 550 | int skipidtype; | |
547 | struct vfs_quotactl_args args; | 551 | struct vfs_quotactl_args args; | |
548 | prop_array_t replies; | 552 | prop_array_t replies; | |
549 | int atend, atzero; | 553 | int atend, atzero; | |
550 | struct quotakey *key; | 554 | struct quotakey *key; | |
551 | struct quotaval *val; | 555 | struct quotaval *val; | |
552 | id_t lastid; | 556 | id_t lastid; | |
553 | prop_dictionary_t thisreply; | 557 | prop_dictionary_t thisreply; | |
554 | unsigned i; | 558 | unsigned i; | |
555 | int error, error2; | 559 | int error, error2; | |
556 | 560 | |||
557 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 561 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
558 | 562 | |||
559 | args.qc_type = QCT_CURSOROPEN; | 563 | args.qc_type = QCT_CURSOROPEN; | |
560 | args.u.cursoropen.qc_cursor = &cursor; | 564 | args.u.cursoropen.qc_cursor = &cursor; | |
561 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args); | 565 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args); | |
562 | if (error) { | 566 | if (error) { | |
563 | return error; | 567 | return error; | |
564 | } | 568 | } | |
565 | 569 | |||
566 | keys = malloc(loopmax * sizeof(keys[0]), M_TEMP, M_WAITOK); | 570 | keys = malloc(loopmax * sizeof(keys[0]), M_TEMP, M_WAITOK); | |
567 | vals = malloc(loopmax * sizeof(vals[0]), M_TEMP, M_WAITOK); | 571 | vals = malloc(loopmax * sizeof(vals[0]), M_TEMP, M_WAITOK); | |
568 | 572 | |||
569 | skipidtype = (q2type == QUOTA_IDTYPE_USER ? | 573 | skipidtype = (q2type == QUOTA_IDTYPE_USER ? | |
570 | QUOTA_IDTYPE_GROUP : QUOTA_IDTYPE_USER); | 574 | QUOTA_IDTYPE_GROUP : QUOTA_IDTYPE_USER); | |
571 | args.qc_type = QCT_CURSORSKIPIDTYPE; | 575 | args.qc_type = QCT_CURSORSKIPIDTYPE; | |
572 | args.u.cursorskipidtype.qc_cursor = &cursor; | 576 | args.u.cursorskipidtype.qc_cursor = &cursor; | |
573 | args.u.cursorskipidtype.qc_idtype = skipidtype; | 577 | args.u.cursorskipidtype.qc_idtype = skipidtype; | |
574 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORSKIPIDTYPE, &args); | 578 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORSKIPIDTYPE, &args); | |
575 | /* ignore if it fails */ | 579 | /* ignore if it fails */ | |
576 | (void)error; | 580 | (void)error; | |
577 | 581 | |||
578 | replies = prop_array_create(); | 582 | replies = prop_array_create(); | |
579 | if (replies == NULL) { | 583 | if (replies == NULL) { | |
580 | error = ENOMEM; | 584 | error = ENOMEM; | |
581 | goto err; | 585 | goto err; | |
582 | } | 586 | } | |
583 | 587 | |||
584 | thisreply = NULL; | 588 | thisreply = NULL; | |
585 | lastid = 0; /* value not actually referenced */ | 589 | lastid = 0; /* value not actually referenced */ | |
586 | atzero = 0; | 590 | atzero = 0; | |
587 | 591 | |||
588 | while (1) { | 592 | while (1) { | |
589 | args.qc_type = QCT_CURSORATEND; | 593 | args.qc_type = QCT_CURSORATEND; | |
590 | args.u.cursoratend.qc_cursor = &cursor; | 594 | args.u.cursoratend.qc_cursor = &cursor; | |
591 | args.u.cursoratend.qc_ret = &atend; | 595 | args.u.cursoratend.qc_ret = &atend; | |
592 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORATEND, &args); | 596 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORATEND, &args); | |
593 | if (error) { | 597 | if (error) { | |
594 | goto err; | 598 | goto err; | |
595 | } | 599 | } | |
596 | if (atend) { | 600 | if (atend) { | |
597 | break; | 601 | break; | |
598 | } | 602 | } | |
599 | 603 | |||
600 | args.qc_type = QCT_CURSORGET; | 604 | args.qc_type = QCT_CURSORGET; | |
601 | args.u.cursorget.qc_cursor = &cursor; | 605 | args.u.cursorget.qc_cursor = &cursor; | |
602 | args.u.cursorget.qc_keys = keys; | 606 | args.u.cursorget.qc_keys = keys; | |
603 | args.u.cursorget.qc_vals = vals; | 607 | args.u.cursorget.qc_vals = vals; | |
604 | args.u.cursorget.qc_maxnum = loopmax; | 608 | args.u.cursorget.qc_maxnum = loopmax; | |
605 | args.u.cursorget.qc_ret = &loopnum; | 609 | args.u.cursorget.qc_ret = &loopnum; | |
606 | 610 | |||
607 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORGET, &args); | 611 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORGET, &args); | |
608 | if (error == EDEADLK) { | 612 | if (error == EDEADLK) { | |
609 | /* | 613 | /* | |
610 | * transaction abort, start over | 614 | * transaction abort, start over | |
611 | */ | 615 | */ | |
612 | 616 | |||
613 | args.qc_type = QCT_CURSORREWIND; | 617 | args.qc_type = QCT_CURSORREWIND; | |
614 | args.u.cursorrewind.qc_cursor = &cursor; | 618 | args.u.cursorrewind.qc_cursor = &cursor; | |
615 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORREWIND, &args); | 619 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORREWIND, &args); | |
616 | if (error) { | 620 | if (error) { | |
617 | goto err; | 621 | goto err; | |
618 | } | 622 | } | |
619 | 623 | |||
620 | args.qc_type = QCT_CURSORSKIPIDTYPE; | 624 | args.qc_type = QCT_CURSORSKIPIDTYPE; | |
621 | args.u.cursorskipidtype.qc_cursor = &cursor; | 625 | args.u.cursorskipidtype.qc_cursor = &cursor; | |
622 | args.u.cursorskipidtype.qc_idtype = skipidtype; | 626 | args.u.cursorskipidtype.qc_idtype = skipidtype; | |
623 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORSKIPIDTYPE, | 627 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORSKIPIDTYPE, | |
624 | &args); | 628 | &args); | |
625 | /* ignore if it fails */ | 629 | /* ignore if it fails */ | |
626 | (void)error; | 630 | (void)error; | |
627 | 631 | |||
628 | prop_object_release(replies); | 632 | prop_object_release(replies); | |
629 | replies = prop_array_create(); | 633 | replies = prop_array_create(); | |
630 | if (replies == NULL) { | 634 | if (replies == NULL) { | |
631 | error = ENOMEM; | 635 | error = ENOMEM; | |
632 | goto err; | 636 | goto err; | |
633 | } | 637 | } | |
634 | 638 | |||
635 | thisreply = NULL; | 639 | thisreply = NULL; | |
636 | lastid = 0; | 640 | lastid = 0; | |
637 | atzero = 0; | 641 | atzero = 0; | |
638 | 642 | |||
639 | continue; | 643 | continue; | |
640 | } | 644 | } | |
641 | if (error) { | 645 | if (error) { | |
642 | goto err; | 646 | goto err; | |
643 | } | 647 | } | |
644 | 648 | |||
645 | if (loopnum == 0) { | 649 | if (loopnum == 0) { | |
646 | /* | 650 | /* | |
647 | * This is not supposed to happen. However, | 651 | * This is not supposed to happen. However, | |
648 | * allow a return of zero items once as long | 652 | * allow a return of zero items once as long | |
649 | * as something happens (including an atend | 653 | * as something happens (including an atend | |
650 | * indication) on the next pass. If it happens | 654 | * indication) on the next pass. If it happens | |
651 | * twice, warn and assume end of iteration. | 655 | * twice, warn and assume end of iteration. | |
652 | */ | 656 | */ | |
653 | if (atzero) { | 657 | if (atzero) { | |
654 | printf("vfs_quotactl: zero items returned\n"); | 658 | printf("vfs_quotactl: zero items returned\n"); | |
655 | break; | 659 | break; | |
656 | } | 660 | } | |
657 | atzero = 1; | 661 | atzero = 1; | |
658 | } else { | 662 | } else { | |
659 | atzero = 0; | 663 | atzero = 0; | |
660 | } | 664 | } | |
661 | 665 | |||
662 | for (i = 0; i < loopnum; i++) { | 666 | for (i = 0; i < loopnum; i++) { | |
663 | key = &keys[i]; | 667 | key = &keys[i]; | |
664 | val = &vals[i]; | 668 | val = &vals[i]; | |
665 | 669 | |||
666 | if (key->qk_idtype != q2type) { | 670 | if (key->qk_idtype != q2type) { | |
667 | /* don't want this result */ | 671 | /* don't want this result */ | |
668 | continue; | 672 | continue; | |
669 | } | 673 | } | |
670 | 674 | |||
671 | if (thisreply == NULL || key->qk_id != lastid) { | 675 | if (thisreply == NULL || key->qk_id != lastid) { | |
672 | lastid = key->qk_id; | 676 | lastid = key->qk_id; | |
673 | thisreply = vfs_quotactl_getall_makereply(key); | 677 | thisreply = vfs_quotactl_getall_makereply(key); | |
674 | if (thisreply == NULL) { | 678 | if (thisreply == NULL) { | |
675 | error = ENOMEM; | 679 | error = ENOMEM; | |
676 | goto err; | 680 | goto err; | |
677 | } | 681 | } | |
678 | /* | 682 | /* | |
679 | * Note: while we release our reference to | 683 | * Note: while we release our reference to | |
680 | * thisreply here, we can (and do) continue to | 684 | * thisreply here, we can (and do) continue to | |
681 | * use the pointer in the loop because the | 685 | * use the pointer in the loop because the | |
682 | * copy attached to the replies array is not | 686 | * copy attached to the replies array is not | |
683 | * going away. | 687 | * going away. | |
684 | */ | 688 | */ | |
685 | if (!prop_array_add_and_rel(replies, | 689 | if (!prop_array_add_and_rel(replies, | |
686 | thisreply)) { | 690 | thisreply)) { | |
687 | error = ENOMEM; | 691 | error = ENOMEM; | |
688 | goto err; | 692 | goto err; | |
689 | } | 693 | } | |
690 | } | 694 | } | |
691 | 695 | |||
692 | error = vfs_quotactl_getall_addreply(thisreply, | 696 | error = vfs_quotactl_getall_addreply(thisreply, | |
693 | key, val); | 697 | key, val); | |
694 | if (error) { | 698 | if (error) { | |
695 | goto err; | 699 | goto err; | |
696 | } | 700 | } | |
697 | } | 701 | } | |
698 | } | 702 | } | |
699 | 703 | |||
700 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 704 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
701 | replies = NULL; | 705 | replies = NULL; | |
702 | error = ENOMEM; | 706 | error = ENOMEM; | |
703 | goto err; | 707 | goto err; | |
704 | } | 708 | } | |
705 | replies = NULL; | 709 | replies = NULL; | |
706 | error = 0; | 710 | error = 0; | |
707 | 711 | |||
708 | err: | 712 | err: | |
709 | free(keys, M_TEMP); | 713 | free(keys, M_TEMP); | |
710 | free(vals, M_TEMP); | 714 | free(vals, M_TEMP); | |
711 | 715 | |||
712 | if (replies != NULL) { | 716 | if (replies != NULL) { | |
713 | prop_object_release(replies); | 717 | prop_object_release(replies); | |
714 | } | 718 | } | |
715 | 719 | |||
716 | args.qc_type = QCT_CURSORCLOSE; | 720 | args.qc_type = QCT_CURSORCLOSE; | |
717 | args.u.cursorclose.qc_cursor = &cursor; | 721 | args.u.cursorclose.qc_cursor = &cursor; | |
718 | error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args); | 722 | error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args); | |
719 | 723 | |||
720 | if (error) { | 724 | if (error) { | |
721 | return error; | 725 | return error; | |
722 | } | 726 | } | |
723 | error = error2; | 727 | error = error2; | |
724 | return error; | 728 | return error; | |
725 | } | 729 | } | |
726 | 730 | |||
727 | static int | 731 | static int | |
728 | vfs_quotactl_clear(struct mount *mp, | 732 | vfs_quotactl_clear(struct mount *mp, | |
729 | prop_dictionary_t cmddict, int q2type, | 733 | prop_dictionary_t cmddict, int q2type, | |
730 | prop_array_t datas) | 734 | prop_array_t datas) | |
731 | { | 735 | { | |
732 | prop_array_t replies; | 736 | prop_array_t replies; | |
733 | prop_object_iterator_t iter; | 737 | prop_object_iterator_t iter; | |
734 | prop_dictionary_t data; | 738 | prop_dictionary_t data; | |
735 | uint32_t id; | 739 | uint32_t id; | |
736 | int defaultq; | 740 | int defaultq; | |
737 | const char *idstr; | 741 | const char *idstr; | |
738 | struct quotakey qk; | 742 | struct quotakey qk; | |
739 | struct vfs_quotactl_args args; | 743 | struct vfs_quotactl_args args; | |
740 | int error; | 744 | int error; | |
741 | 745 | |||
742 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 746 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
743 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 747 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
744 | 748 | |||
745 | replies = prop_array_create(); | 749 | replies = prop_array_create(); | |
746 | if (replies == NULL) | 750 | if (replies == NULL) | |
747 | return ENOMEM; | 751 | return ENOMEM; | |
748 | 752 | |||
749 | iter = prop_array_iterator(datas); | 753 | iter = prop_array_iterator(datas); | |
750 | if (iter == NULL) { | 754 | if (iter == NULL) { | |
751 | prop_object_release(replies); | 755 | prop_object_release(replies); | |
752 | return ENOMEM; | 756 | return ENOMEM; | |
753 | } | 757 | } | |
754 | 758 | |||
755 | while ((data = prop_object_iterator_next(iter)) != NULL) { | 759 | while ((data = prop_object_iterator_next(iter)) != NULL) { | |
756 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | 760 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | |
757 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | 761 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | |
758 | &idstr)) | 762 | &idstr)) | |
759 | continue; | 763 | continue; | |
760 | if (strcmp(idstr, "default")) | 764 | if (strcmp(idstr, "default")) | |
761 | continue; | 765 | continue; | |
762 | id = 0; | 766 | id = 0; | |
763 | defaultq = 1; | 767 | defaultq = 1; | |
764 | } else { | 768 | } else { | |
765 | defaultq = 0; | 769 | defaultq = 0; | |
766 | } | 770 | } | |
767 | 771 | |||
768 | qk.qk_idtype = q2type; | 772 | qk.qk_idtype = q2type; | |
769 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | 773 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | |
770 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | 774 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | |
771 | 775 | |||
772 | args.qc_type = QCT_DELETE; | 776 | args.qc_type = QCT_DELETE; | |
773 | args.u.delete.qc_key = &qk; | 777 | args.u.delete.qc_key = &qk; | |
774 | error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); | 778 | error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); | |
775 | if (error) { | 779 | if (error) { | |
776 | goto err; | 780 | goto err; | |
777 | } | 781 | } | |
778 | 782 | |||
779 | qk.qk_idtype = q2type; | 783 | qk.qk_idtype = q2type; | |
780 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | 784 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | |
781 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | 785 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | |
782 | 786 | |||
783 | args.qc_type = QCT_DELETE; | 787 | args.qc_type = QCT_DELETE; | |
784 | args.u.delete.qc_key = &qk; | 788 | args.u.delete.qc_key = &qk; | |
785 | error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); | 789 | error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); | |
786 | if (error) { | 790 | if (error) { | |
787 | goto err; | 791 | goto err; | |
788 | } | 792 | } | |
789 | } | 793 | } | |
790 | 794 | |||
791 | prop_object_iterator_release(iter); | 795 | prop_object_iterator_release(iter); | |
792 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 796 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
793 | error = ENOMEM; | 797 | error = ENOMEM; | |
794 | } else { | 798 | } else { | |
795 | error = 0; | 799 | error = 0; | |
796 | } | 800 | } | |
797 | return error; | 801 | return error; | |
798 | err: | 802 | err: | |
799 | prop_object_iterator_release(iter); | 803 | prop_object_iterator_release(iter); | |
800 | prop_object_release(replies); | 804 | prop_object_release(replies); | |
801 | return error; | 805 | return error; | |
802 | } | 806 | } | |
803 | 807 | |||
804 | static int | 808 | static int | |
805 | vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) | 809 | vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) | |
806 | { | 810 | { | |
807 | int error; | 811 | int error; | |
808 | const char *cmd, *type; | 812 | const char *cmd, *type; | |
809 | prop_array_t datas; | 813 | prop_array_t datas; | |
810 | int q2type; | 814 | int q2type; | |
811 | 815 | |||
812 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) | 816 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) | |
813 | return EINVAL; | 817 | return EINVAL; | |
814 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) | 818 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) | |
815 | return EINVAL; | 819 | return EINVAL; | |
816 | 820 | |||
817 | if (!strcmp(type, QUOTADICT_CLASS_USER)) { | 821 | if (!strcmp(type, QUOTADICT_CLASS_USER)) { | |
818 | q2type = QUOTA_CLASS_USER; | 822 | q2type = QUOTA_CLASS_USER; | |
819 | } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { | 823 | } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { | |
820 | q2type = QUOTA_CLASS_GROUP; | 824 | q2type = QUOTA_CLASS_GROUP; | |
821 | } else { | 825 | } else { | |
822 | /* XXX this is a bad errno for this case */ | 826 | /* XXX this is a bad errno for this case */ | |
823 | return EOPNOTSUPP; | 827 | return EOPNOTSUPP; | |
824 | } | 828 | } | |
825 | 829 | |||
826 | datas = prop_dictionary_get(cmddict, "data"); | 830 | datas = prop_dictionary_get(cmddict, "data"); | |
827 | if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) | 831 | if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) | |
828 | return EINVAL; | 832 | return EINVAL; | |
829 | 833 | |||
830 | prop_object_retain(datas); | 834 | prop_object_retain(datas); | |
831 | prop_dictionary_remove(cmddict, "data"); /* prepare for return */ | 835 | prop_dictionary_remove(cmddict, "data"); /* prepare for return */ | |
832 | 836 | |||
833 | if (strcmp(cmd, "get version") == 0) { | 837 | if (strcmp(cmd, "get version") == 0) { | |
834 | error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); | 838 | error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); | |
835 | } else if (strcmp(cmd, "quotaon") == 0) { | 839 | } else if (strcmp(cmd, "quotaon") == 0) { | |
836 | error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); | 840 | error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); | |
837 | } else if (strcmp(cmd, "quotaoff") == 0) { | 841 | } else if (strcmp(cmd, "quotaoff") == 0) { | |
838 | error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); | 842 | error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); | |
839 | } else if (strcmp(cmd, "get") == 0) { | 843 | } else if (strcmp(cmd, "get") == 0) { | |
840 | error = vfs_quotactl_get(mp, cmddict, q2type, datas); | 844 | error = vfs_quotactl_get(mp, cmddict, q2type, datas); | |
841 | } else if (strcmp(cmd, "set") == 0) { | 845 | } else if (strcmp(cmd, "set") == 0) { | |
842 | error = vfs_quotactl_put(mp, cmddict, q2type, datas); | 846 | error = vfs_quotactl_put(mp, cmddict, q2type, datas); | |
843 | } else if (strcmp(cmd, "getall") == 0) { | 847 | } else if (strcmp(cmd, "getall") == 0) { | |
844 | error = vfs_quotactl_getall(mp, cmddict, q2type, datas); | 848 | error = vfs_quotactl_getall(mp, cmddict, q2type, datas); | |
845 | } else if (strcmp(cmd, "clear") == 0) { | 849 | } else if (strcmp(cmd, "clear") == 0) { | |
846 | error = vfs_quotactl_clear(mp, cmddict, q2type, datas); | 850 | error = vfs_quotactl_clear(mp, cmddict, q2type, datas); | |
847 | } else { | 851 | } else { | |
848 | /* XXX this a bad errno for this case */ | 852 | /* XXX this a bad errno for this case */ | |
849 | error = EOPNOTSUPP; | 853 | error = EOPNOTSUPP; | |
850 | } | 854 | } | |
851 | 855 | |||
852 | error = (prop_dictionary_set_int8(cmddict, "return", | 856 | error = (prop_dictionary_set_int8(cmddict, "return", | |
853 | error) ? 0 : ENOMEM); | 857 | error) ? 0 : ENOMEM); | |
854 | prop_object_release(datas); | 858 | prop_object_release(datas); | |
855 | 859 | |||
856 | return error; | 860 | return error; | |
857 | } | 861 | } | |
858 | 862 | |||
859 | int | 863 | int | |
860 | vfs_quotactl(struct mount *mp, prop_dictionary_t dict) | 864 | vfs_quotactl(struct mount *mp, prop_dictionary_t dict) | |
861 | { | 865 | { | |
862 | prop_dictionary_t cmddict; | 866 | prop_dictionary_t cmddict; | |
863 | prop_array_t commands; | 867 | prop_array_t commands; | |
864 | prop_object_iterator_t iter; | 868 | prop_object_iterator_t iter; | |
865 | int error; | 869 | int error; | |
866 | 870 | |||
867 | error = quota_get_cmds(dict, &commands); | 871 | error = quota_get_cmds(dict, &commands); | |
868 | if (error) { | 872 | if (error) { | |
869 | return error; | 873 | return error; | |
870 | } | 874 | } | |
871 | 875 | |||
872 | iter = prop_array_iterator(commands); | 876 | iter = prop_array_iterator(commands); | |
873 | if (iter == NULL) { | 877 | if (iter == NULL) { | |
874 | return ENOMEM; | 878 | return ENOMEM; | |
875 | } | 879 | } | |
876 | 880 | |||
877 | while ((cmddict = prop_object_iterator_next(iter)) != NULL) { | 881 | while ((cmddict = prop_object_iterator_next(iter)) != NULL) { | |
878 | if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { | 882 | if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { | |
879 | /* XXX shouldn't this be an error? */ | 883 | /* XXX shouldn't this be an error? */ | |
880 | continue; | 884 | continue; | |
881 | } | 885 | } | |
882 | error = vfs_quotactl_cmd(mp, cmddict); | 886 | error = vfs_quotactl_cmd(mp, cmddict); | |
883 | if (error) { | 887 | if (error) { | |
884 | break; | 888 | break; | |
885 | } | 889 | } | |
886 | } | 890 | } | |
887 | prop_object_iterator_release(iter); | 891 | prop_object_iterator_release(iter); | |
888 | return error; | 892 | return error; | |
889 | } | 893 | } |
--- src/sys/sys/quotactl.h 2012/01/29 07:11:12 1.27
+++ src/sys/sys/quotactl.h 2012/01/29 07:11:55 1.28
@@ -1,136 +1,140 @@ | @@ -1,136 +1,140 @@ | |||
1 | /* $NetBSD: quotactl.h,v 1.27 2012/01/29 07:11:12 dholland Exp $ */ | 1 | /* $NetBSD: quotactl.h,v 1.28 2012/01/29 07:11:55 dholland Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2011 The NetBSD Foundation, Inc. | 3 | * Copyright (c) 2011 The NetBSD Foundation, Inc. | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * | 5 | * | |
6 | * This code is derived from software contributed to The NetBSD Foundation | 6 | * This code is derived from software contributed to The NetBSD Foundation | |
7 | * by David A. Holland. | 7 | * by David A. Holland. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | 15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | 16 | * documentation and/or other materials provided with the distribution. | |
17 | * | 17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
28 | * POSSIBILITY OF SUCH DAMAGE. | 28 | * POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | #ifndef _SYS_QUOTACTL_H_ | 31 | #ifndef _SYS_QUOTACTL_H_ | |
32 | #define _SYS_QUOTACTL_H_ | 32 | #define _SYS_QUOTACTL_H_ | |
33 | 33 | |||
34 | /* | 34 | /* | |
35 | * Note - this is an internal interface. Application code (and, | 35 | * Note - this is an internal interface. Application code (and, | |
36 | * really, anything that isn't libquota or inside the kernel) should | 36 | * really, anything that isn't libquota or inside the kernel) should | |
37 | * use the <quota.h> API instead. | 37 | * use the <quota.h> API instead. | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | /* | 40 | /* | |
41 | * Semi-opaque structure for cursors. This holds the cursor state in | 41 | * Semi-opaque structure for cursors. This holds the cursor state in | |
42 | * userland; the size is exposed only to libquota, not to client code, | 42 | * userland; the size is exposed only to libquota, not to client code, | |
43 | * and is meant to be large enough to accomodate all likely future | 43 | * and is meant to be large enough to accomodate all likely future | |
44 | * expansion without being unduly bloated, as it will need to be | 44 | * expansion without being unduly bloated, as it will need to be | |
45 | * copied in and out for every call using it. | 45 | * copied in and out for every call using it. | |
46 | */ | 46 | */ | |
47 | struct quotakcursor { | 47 | struct quotakcursor { | |
48 | union { | 48 | union { | |
49 | char qkc_space[64]; | 49 | char qkc_space[64]; | |
50 | uintmax_t __qkc_forcealign; | 50 | uintmax_t __qkc_forcealign; | |
51 | } u; | 51 | } u; | |
52 | }; | 52 | }; | |
53 | 53 | |||
54 | /* Command codes. */ | 54 | /* Command codes. */ | |
55 | #define QUOTACTL_GETVERSION 0 | 55 | #define QUOTACTL_GETVERSION 0 | |
56 | #define QUOTACTL_QUOTAON 1 | 56 | #define QUOTACTL_QUOTAON 1 | |
57 | #define QUOTACTL_QUOTAOFF 2 | 57 | #define QUOTACTL_QUOTAOFF 2 | |
58 | #define QUOTACTL_GET 3 | 58 | #define QUOTACTL_GET 3 | |
59 | #define QUOTACTL_PUT 4 | 59 | #define QUOTACTL_PUT 4 | |
60 | #define QUOTACTL_CURSORGET 5 | 60 | #define QUOTACTL_CURSORGET 5 | |
61 | #define QUOTACTL_DELETE 6 | 61 | #define QUOTACTL_DELETE 6 | |
62 | #define QUOTACTL_CURSOROPEN 7 | 62 | #define QUOTACTL_CURSOROPEN 7 | |
63 | #define QUOTACTL_CURSORCLOSE 8 | 63 | #define QUOTACTL_CURSORCLOSE 8 | |
64 | #define QUOTACTL_CURSORSKIPIDTYPE 9 | 64 | #define QUOTACTL_CURSORSKIPIDTYPE 9 | |
65 | #define QUOTACTL_CURSORATEND 10 | 65 | #define QUOTACTL_CURSORATEND 10 | |
66 | #define QUOTACTL_CURSORREWIND 11 | 66 | #define QUOTACTL_CURSORREWIND 11 | |
67 | 67 | |||
68 | /* Argument encoding. */ | 68 | /* Argument encoding. */ | |
69 | enum vfs_quotactl_argtypes { | 69 | enum vfs_quotactl_argtypes { | |
70 | QCT_PROPLIB, /* quotaoff */ | 70 | QCT_PROPLIB, /* unused */ | |
71 | QCT_GETVERSION, /* getversion */ | 71 | QCT_GETVERSION, /* getversion */ | |
72 | QCT_GET, /* get */ | 72 | QCT_GET, /* get */ | |
73 | QCT_PUT, /* put */ | 73 | QCT_PUT, /* put */ | |
74 | QCT_DELETE, /* delete */ | 74 | QCT_DELETE, /* delete */ | |
75 | QCT_CURSOROPEN, /* open cursor */ | 75 | QCT_CURSOROPEN, /* open cursor */ | |
76 | QCT_CURSORCLOSE,/* close cursor */ | 76 | QCT_CURSORCLOSE,/* close cursor */ | |
77 | QCT_CURSORGET, /* get from cursor */ | 77 | QCT_CURSORGET, /* get from cursor */ | |
78 | QCT_CURSORSKIPIDTYPE, /* iteration hint */ | 78 | QCT_CURSORSKIPIDTYPE, /* iteration hint */ | |
79 | QCT_CURSORATEND,/* test cursor */ | 79 | QCT_CURSORATEND,/* test cursor */ | |
80 | QCT_CURSORREWIND,/* reset cursor */ | 80 | QCT_CURSORREWIND,/* reset cursor */ | |
81 | QCT_QUOTAON, /* quotaon */ | 81 | QCT_QUOTAON, /* quotaon */ | |
82 | QCT_QUOTAOFF, /* quotaoff */ | |||
82 | }; | 83 | }; | |
83 | struct vfs_quotactl_args { | 84 | struct vfs_quotactl_args { | |
84 | enum vfs_quotactl_argtypes qc_type; | 85 | enum vfs_quotactl_argtypes qc_type; | |
85 | union { | 86 | union { | |
86 | struct { | 87 | struct { | |
87 | prop_dictionary_t qc_cmddict; | 88 | prop_dictionary_t qc_cmddict; | |
88 | int qc_q2type; | 89 | int qc_q2type; | |
89 | prop_array_t qc_datas; | 90 | prop_array_t qc_datas; | |
90 | } proplib; | 91 | } proplib; | |
91 | struct { | 92 | struct { | |
92 | int *qc_version_ret; | 93 | int *qc_version_ret; | |
93 | } getversion; | 94 | } getversion; | |
94 | struct { | 95 | struct { | |
95 | const struct quotakey *qc_key; | 96 | const struct quotakey *qc_key; | |
96 | struct quotaval *qc_ret; | 97 | struct quotaval *qc_ret; | |
97 | } get; | 98 | } get; | |
98 | struct { | 99 | struct { | |
99 | const struct quotakey *qc_key; | 100 | const struct quotakey *qc_key; | |
100 | const struct quotaval *qc_val; | 101 | const struct quotaval *qc_val; | |
101 | } put; | 102 | } put; | |
102 | struct { | 103 | struct { | |
103 | const struct quotakey *qc_key; | 104 | const struct quotakey *qc_key; | |
104 | } delete; | 105 | } delete; | |
105 | struct { | 106 | struct { | |
106 | struct quotakcursor *qc_cursor; | 107 | struct quotakcursor *qc_cursor; | |
107 | } cursoropen; | 108 | } cursoropen; | |
108 | struct { | 109 | struct { | |
109 | struct quotakcursor *qc_cursor; | 110 | struct quotakcursor *qc_cursor; | |
110 | } cursorclose; | 111 | } cursorclose; | |
111 | struct { | 112 | struct { | |
112 | struct quotakcursor *qc_cursor; | 113 | struct quotakcursor *qc_cursor; | |
113 | unsigned qc_idtype; | 114 | unsigned qc_idtype; | |
114 | } cursorskipidtype; | 115 | } cursorskipidtype; | |
115 | struct { | 116 | struct { | |
116 | struct quotakcursor *qc_cursor; | 117 | struct quotakcursor *qc_cursor; | |
117 | struct quotakey *qc_keys; | 118 | struct quotakey *qc_keys; | |
118 | struct quotaval *qc_vals; | 119 | struct quotaval *qc_vals; | |
119 | unsigned qc_maxnum; | 120 | unsigned qc_maxnum; | |
120 | unsigned *qc_ret; | 121 | unsigned *qc_ret; | |
121 | } cursorget; | 122 | } cursorget; | |
122 | struct { | 123 | struct { | |
123 | struct quotakcursor *qc_cursor; | 124 | struct quotakcursor *qc_cursor; | |
124 | int *qc_ret; /* really boolean */ | 125 | int *qc_ret; /* really boolean */ | |
125 | } cursoratend; | 126 | } cursoratend; | |
126 | struct { | 127 | struct { | |
127 | struct quotakcursor *qc_cursor; | 128 | struct quotakcursor *qc_cursor; | |
128 | } cursorrewind; | 129 | } cursorrewind; | |
129 | struct { | 130 | struct { | |
130 | int qc_idtype; | 131 | int qc_idtype; | |
131 | const char *qc_quotafile; | 132 | const char *qc_quotafile; | |
132 | } quotaon; | 133 | } quotaon; | |
134 | struct { | |||
135 | int qc_idtype; | |||
136 | } quotaoff; | |||
133 | } u; | 137 | } u; | |
134 | }; | 138 | }; | |
135 | 139 | |||
136 | #endif /* _SYS_QUOTACTL_H_ */ | 140 | #endif /* _SYS_QUOTACTL_H_ */ |
--- src/sys/ufs/ufs/ufs_quota.c 2012/01/29 07:11:12 1.99
+++ src/sys/ufs/ufs/ufs_quota.c 2012/01/29 07:11:55 1.100
@@ -1,905 +1,895 @@ | @@ -1,905 +1,895 @@ | |||
1 | /* $NetBSD: ufs_quota.c,v 1.99 2012/01/29 07:11:12 dholland Exp $ */ | 1 | /* $NetBSD: ufs_quota.c,v 1.100 2012/01/29 07:11:55 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.99 2012/01/29 07:11:12 dholland Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.100 2012/01/29 07:11:55 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_put(struct mount *, struct lwp *, | 78 | static int quota_handle_cmd_put(struct mount *, struct lwp *, | |
79 | struct vfs_quotactl_args *args); | 79 | struct vfs_quotactl_args *args); | |
80 | static int quota_handle_cmd_cursorget(struct mount *, struct lwp *, | 80 | static int quota_handle_cmd_cursorget(struct mount *, struct lwp *, | |
81 | struct vfs_quotactl_args *args); | 81 | struct vfs_quotactl_args *args); | |
82 | static int quota_handle_cmd_delete(struct mount *, struct lwp *, | 82 | static int quota_handle_cmd_delete(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 | static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *, | 88 | static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *, | |
89 | struct vfs_quotactl_args *args); | 89 | struct vfs_quotactl_args *args); | |
90 | static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *, | 90 | static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *, | |
91 | struct vfs_quotactl_args *args); | 91 | struct vfs_quotactl_args *args); | |
92 | static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *, | 92 | static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *, | |
93 | struct vfs_quotactl_args *args); | 93 | struct vfs_quotactl_args *args); | |
94 | static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *, | 94 | static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *, | |
95 | struct vfs_quotactl_args *args); | 95 | struct vfs_quotactl_args *args); | |
96 | static int quota_handle_cmd_cursorrewind(struct mount *, struct lwp *, | 96 | static int quota_handle_cmd_cursorrewind(struct mount *, struct lwp *, | |
97 | struct vfs_quotactl_args *args); | 97 | struct vfs_quotactl_args *args); | |
98 | 98 | |||
99 | /* | 99 | /* | |
100 | * Initialize the quota fields of an inode. | 100 | * Initialize the quota fields of an inode. | |
101 | */ | 101 | */ | |
102 | void | 102 | void | |
103 | ufsquota_init(struct inode *ip) | 103 | ufsquota_init(struct inode *ip) | |
104 | { | 104 | { | |
105 | int i; | 105 | int i; | |
106 | 106 | |||
107 | for (i = 0; i < MAXQUOTAS; i++) | 107 | for (i = 0; i < MAXQUOTAS; i++) | |
108 | ip->i_dquot[i] = NODQUOT; | 108 | ip->i_dquot[i] = NODQUOT; | |
109 | } | 109 | } | |
110 | 110 | |||
111 | /* | 111 | /* | |
112 | * Release the quota fields from an inode. | 112 | * Release the quota fields from an inode. | |
113 | */ | 113 | */ | |
114 | void | 114 | void | |
115 | ufsquota_free(struct inode *ip) | 115 | ufsquota_free(struct inode *ip) | |
116 | { | 116 | { | |
117 | int i; | 117 | int i; | |
118 | 118 | |||
119 | for (i = 0; i < MAXQUOTAS; i++) { | 119 | for (i = 0; i < MAXQUOTAS; i++) { | |
120 | dqrele(ITOV(ip), ip->i_dquot[i]); | 120 | dqrele(ITOV(ip), ip->i_dquot[i]); | |
121 | ip->i_dquot[i] = NODQUOT; | 121 | ip->i_dquot[i] = NODQUOT; | |
122 | } | 122 | } | |
123 | } | 123 | } | |
124 | 124 | |||
125 | /* | 125 | /* | |
126 | * Update disk usage, and take corrective action. | 126 | * Update disk usage, and take corrective action. | |
127 | */ | 127 | */ | |
128 | int | 128 | int | |
129 | chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | 129 | chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | |
130 | { | 130 | { | |
131 | /* do not track snapshot usage, or we will deadlock */ | 131 | /* do not track snapshot usage, or we will deadlock */ | |
132 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | 132 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | |
133 | return 0; | 133 | return 0; | |
134 | 134 | |||
135 | #ifdef QUOTA | 135 | #ifdef QUOTA | |
136 | if (ip->i_ump->um_flags & UFS_QUOTA) | 136 | if (ip->i_ump->um_flags & UFS_QUOTA) | |
137 | return chkdq1(ip, change, cred, flags); | 137 | return chkdq1(ip, change, cred, flags); | |
138 | #endif | 138 | #endif | |
139 | #ifdef QUOTA2 | 139 | #ifdef QUOTA2 | |
140 | if (ip->i_ump->um_flags & UFS_QUOTA2) | 140 | if (ip->i_ump->um_flags & UFS_QUOTA2) | |
141 | return chkdq2(ip, change, cred, flags); | 141 | return chkdq2(ip, change, cred, flags); | |
142 | #endif | 142 | #endif | |
143 | return 0; | 143 | return 0; | |
144 | } | 144 | } | |
145 | 145 | |||
146 | /* | 146 | /* | |
147 | * Check the inode limit, applying corrective action. | 147 | * Check the inode limit, applying corrective action. | |
148 | */ | 148 | */ | |
149 | int | 149 | int | |
150 | chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | 150 | chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | |
151 | { | 151 | { | |
152 | /* do not track snapshot usage, or we will deadlock */ | 152 | /* do not track snapshot usage, or we will deadlock */ | |
153 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | 153 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | |
154 | return 0; | 154 | return 0; | |
155 | #ifdef QUOTA | 155 | #ifdef QUOTA | |
156 | if (ip->i_ump->um_flags & UFS_QUOTA) | 156 | if (ip->i_ump->um_flags & UFS_QUOTA) | |
157 | return chkiq1(ip, change, cred, flags); | 157 | return chkiq1(ip, change, cred, flags); | |
158 | #endif | 158 | #endif | |
159 | #ifdef QUOTA2 | 159 | #ifdef QUOTA2 | |
160 | if (ip->i_ump->um_flags & UFS_QUOTA2) | 160 | if (ip->i_ump->um_flags & UFS_QUOTA2) | |
161 | return chkiq2(ip, change, cred, flags); | 161 | return chkiq2(ip, change, cred, flags); | |
162 | #endif | 162 | #endif | |
163 | return 0; | 163 | return 0; | |
164 | } | 164 | } | |
165 | 165 | |||
166 | int | 166 | int | |
167 | quota_handle_cmd(struct mount *mp, struct lwp *l, int op, | 167 | quota_handle_cmd(struct mount *mp, struct lwp *l, int op, | |
168 | struct vfs_quotactl_args *args) | 168 | struct vfs_quotactl_args *args) | |
169 | { | 169 | { | |
170 | int error = 0; | 170 | int error = 0; | |
171 | 171 | |||
172 | switch (op) { | 172 | switch (op) { | |
173 | case QUOTACTL_GETVERSION: | 173 | case QUOTACTL_GETVERSION: | |
174 | error = quota_handle_cmd_get_version(mp, l, args); | 174 | error = quota_handle_cmd_get_version(mp, l, args); | |
175 | break; | 175 | break; | |
176 | case QUOTACTL_QUOTAON: | 176 | case QUOTACTL_QUOTAON: | |
177 | error = quota_handle_cmd_quotaon(mp, l, args); | 177 | error = quota_handle_cmd_quotaon(mp, l, args); | |
178 | break; | 178 | break; | |
179 | case QUOTACTL_QUOTAOFF: | 179 | case QUOTACTL_QUOTAOFF: | |
180 | error = quota_handle_cmd_quotaoff(mp, l, args); | 180 | error = quota_handle_cmd_quotaoff(mp, l, args); | |
181 | break; | 181 | break; | |
182 | case QUOTACTL_GET: | 182 | case QUOTACTL_GET: | |
183 | error = quota_handle_cmd_get(mp, l, args); | 183 | error = quota_handle_cmd_get(mp, l, args); | |
184 | break; | 184 | break; | |
185 | case QUOTACTL_PUT: | 185 | case QUOTACTL_PUT: | |
186 | error = quota_handle_cmd_put(mp, l, args); | 186 | error = quota_handle_cmd_put(mp, l, args); | |
187 | break; | 187 | break; | |
188 | case QUOTACTL_CURSORGET: | 188 | case QUOTACTL_CURSORGET: | |
189 | error = quota_handle_cmd_cursorget(mp, l, args); | 189 | error = quota_handle_cmd_cursorget(mp, l, args); | |
190 | break; | 190 | break; | |
191 | case QUOTACTL_DELETE: | 191 | case QUOTACTL_DELETE: | |
192 | error = quota_handle_cmd_delete(mp, l, args); | 192 | error = quota_handle_cmd_delete(mp, l, args); | |
193 | break; | 193 | break; | |
194 | case QUOTACTL_CURSOROPEN: | 194 | case QUOTACTL_CURSOROPEN: | |
195 | error = quota_handle_cmd_cursoropen(mp, l, args); | 195 | error = quota_handle_cmd_cursoropen(mp, l, args); | |
196 | break; | 196 | break; | |
197 | case QUOTACTL_CURSORCLOSE: | 197 | case QUOTACTL_CURSORCLOSE: | |
198 | error = quota_handle_cmd_cursorclose(mp, l, args); | 198 | error = quota_handle_cmd_cursorclose(mp, l, args); | |
199 | break; | 199 | break; | |
200 | case QUOTACTL_CURSORSKIPIDTYPE: | 200 | case QUOTACTL_CURSORSKIPIDTYPE: | |
201 | error = quota_handle_cmd_cursorskipidtype(mp, l, args); | 201 | error = quota_handle_cmd_cursorskipidtype(mp, l, args); | |
202 | break; | 202 | break; | |
203 | case QUOTACTL_CURSORATEND: | 203 | case QUOTACTL_CURSORATEND: | |
204 | error = quota_handle_cmd_cursoratend(mp, l, args); | 204 | error = quota_handle_cmd_cursoratend(mp, l, args); | |
205 | break; | 205 | break; | |
206 | case QUOTACTL_CURSORREWIND: | 206 | case QUOTACTL_CURSORREWIND: | |
207 | error = quota_handle_cmd_cursorrewind(mp, l, args); | 207 | error = quota_handle_cmd_cursorrewind(mp, l, args); | |
208 | break; | 208 | break; | |
209 | default: | 209 | default: | |
210 | panic("Invalid quotactl operation %d\n", op); | 210 | panic("Invalid quotactl operation %d\n", op); | |
211 | } | 211 | } | |
212 | 212 | |||
213 | return error; | 213 | return error; | |
214 | } | 214 | } | |
215 | 215 | |||
216 | static int | 216 | static int | |
217 | quota_handle_cmd_get_version(struct mount *mp, struct lwp *l, | 217 | quota_handle_cmd_get_version(struct mount *mp, struct lwp *l, | |
218 | struct vfs_quotactl_args *args) | 218 | struct vfs_quotactl_args *args) | |
219 | { | 219 | { | |
220 | struct ufsmount *ump = VFSTOUFS(mp); | 220 | struct ufsmount *ump = VFSTOUFS(mp); | |
221 | int *version_ret; | 221 | int *version_ret; | |
222 | 222 | |||
223 | KASSERT(args->qc_type == QCT_GETVERSION); | 223 | KASSERT(args->qc_type == QCT_GETVERSION); | |
224 | version_ret = args->u.getversion.qc_version_ret; | 224 | version_ret = args->u.getversion.qc_version_ret; | |
225 | 225 | |||
226 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | 226 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | |
227 | return EOPNOTSUPP; | 227 | return EOPNOTSUPP; | |
228 | 228 | |||
229 | #ifdef QUOTA | 229 | #ifdef QUOTA | |
230 | if (ump->um_flags & UFS_QUOTA) { | 230 | if (ump->um_flags & UFS_QUOTA) { | |
231 | *version_ret = 1; | 231 | *version_ret = 1; | |
232 | } else | 232 | } else | |
233 | #endif | 233 | #endif | |
234 | #ifdef QUOTA2 | 234 | #ifdef QUOTA2 | |
235 | if (ump->um_flags & UFS_QUOTA2) { | 235 | if (ump->um_flags & UFS_QUOTA2) { | |
236 | *version_ret = 2; | 236 | *version_ret = 2; | |
237 | } else | 237 | } else | |
238 | #endif | 238 | #endif | |
239 | return EOPNOTSUPP; | 239 | return EOPNOTSUPP; | |
240 | 240 | |||
241 | return 0; | 241 | return 0; | |
242 | } | 242 | } | |
243 | 243 | |||
244 | /* XXX shouldn't all this be in kauth ? */ | 244 | /* XXX shouldn't all this be in kauth ? */ | |
245 | static int | 245 | static int | |
246 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { | 246 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { | |
247 | /* The user can always query about his own quota. */ | 247 | /* The user can always query about his own quota. */ | |
248 | if (id == kauth_cred_getuid(l->l_cred)) | 248 | if (id == kauth_cred_getuid(l->l_cred)) | |
249 | return 0; | 249 | return 0; | |
250 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 250 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
251 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); | 251 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); | |
252 | } | 252 | } | |
253 | 253 | |||
254 | static int | 254 | static int | |
255 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | 255 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | |
256 | struct vfs_quotactl_args *args) | 256 | struct vfs_quotactl_args *args) | |
257 | { | 257 | { | |
258 | struct ufsmount *ump = VFSTOUFS(mp); | 258 | struct ufsmount *ump = VFSTOUFS(mp); | |
259 | int error; | 259 | int error; | |
260 | const struct quotakey *qk; | 260 | const struct quotakey *qk; | |
261 | struct quotaval *ret; | 261 | struct quotaval *ret; | |
262 | 262 | |||
263 | KASSERT(args->qc_type == QCT_GET); | 263 | KASSERT(args->qc_type == QCT_GET); | |
264 | qk = args->u.get.qc_key; | 264 | qk = args->u.get.qc_key; | |
265 | ret = args->u.get.qc_ret; | 265 | ret = args->u.get.qc_ret; | |
266 | 266 | |||
267 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | 267 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | |
268 | return EOPNOTSUPP; | 268 | return EOPNOTSUPP; | |
269 | 269 | |||
270 | error = quota_get_auth(mp, l, qk->qk_id); | 270 | error = quota_get_auth(mp, l, qk->qk_id); | |
271 | if (error != 0) | 271 | if (error != 0) | |
272 | return error; | 272 | return error; | |
273 | #ifdef QUOTA | 273 | #ifdef QUOTA | |
274 | if (ump->um_flags & UFS_QUOTA) { | 274 | if (ump->um_flags & UFS_QUOTA) { | |
275 | error = quota1_handle_cmd_get(ump, qk, ret); | 275 | error = quota1_handle_cmd_get(ump, qk, ret); | |
276 | } else | 276 | } else | |
277 | #endif | 277 | #endif | |
278 | #ifdef QUOTA2 | 278 | #ifdef QUOTA2 | |
279 | if (ump->um_flags & UFS_QUOTA2) { | 279 | if (ump->um_flags & UFS_QUOTA2) { | |
280 | error = quota2_handle_cmd_get(ump, qk, ret); | 280 | error = quota2_handle_cmd_get(ump, qk, ret); | |
281 | } else | 281 | } else | |
282 | #endif | 282 | #endif | |
283 | panic("quota_handle_cmd_get: no support ?"); | 283 | panic("quota_handle_cmd_get: no support ?"); | |
284 | 284 | |||
285 | if (error != 0) | 285 | if (error != 0) | |
286 | return error; | 286 | return error; | |
287 | 287 | |||
288 | return error; | 288 | return error; | |
289 | } | 289 | } | |
290 | 290 | |||
291 | static int | 291 | static int | |
292 | quota_handle_cmd_put(struct mount *mp, struct lwp *l, | 292 | quota_handle_cmd_put(struct mount *mp, struct lwp *l, | |
293 | struct vfs_quotactl_args *args) | 293 | struct vfs_quotactl_args *args) | |
294 | { | 294 | { | |
295 | struct ufsmount *ump = VFSTOUFS(mp); | 295 | struct ufsmount *ump = VFSTOUFS(mp); | |
296 | const struct quotakey *qk; | 296 | const struct quotakey *qk; | |
297 | const struct quotaval *qv; | 297 | const struct quotaval *qv; | |
298 | id_t kauth_id; | 298 | id_t kauth_id; | |
299 | int error; | 299 | int error; | |
300 | 300 | |||
301 | KASSERT(args->qc_type == QCT_PUT); | 301 | KASSERT(args->qc_type == QCT_PUT); | |
302 | qk = args->u.put.qc_key; | 302 | qk = args->u.put.qc_key; | |
303 | qv = args->u.put.qc_val; | 303 | qv = args->u.put.qc_val; | |
304 | 304 | |||
305 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | 305 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | |
306 | return EOPNOTSUPP; | 306 | return EOPNOTSUPP; | |
307 | 307 | |||
308 | kauth_id = qk->qk_id; | 308 | kauth_id = qk->qk_id; | |
309 | if (kauth_id == QUOTA_DEFAULTID) { | 309 | if (kauth_id == QUOTA_DEFAULTID) { | |
310 | kauth_id = 0; | 310 | kauth_id = 0; | |
311 | } | 311 | } | |
312 | 312 | |||
313 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 313 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
314 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), | 314 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), | |
315 | NULL); | 315 | NULL); | |
316 | if (error != 0) { | 316 | if (error != 0) { | |
317 | return error; | 317 | return error; | |
318 | } | 318 | } | |
319 | 319 | |||
320 | #ifdef QUOTA | 320 | #ifdef QUOTA | |
321 | if (ump->um_flags & UFS_QUOTA) | 321 | if (ump->um_flags & UFS_QUOTA) | |
322 | error = quota1_handle_cmd_put(ump, qk, qv); | 322 | error = quota1_handle_cmd_put(ump, qk, qv); | |
323 | else | 323 | else | |
324 | #endif | 324 | #endif | |
325 | #ifdef QUOTA2 | 325 | #ifdef QUOTA2 | |
326 | if (ump->um_flags & UFS_QUOTA2) { | 326 | if (ump->um_flags & UFS_QUOTA2) { | |
327 | error = quota2_handle_cmd_put(ump, qk, qv); | 327 | error = quota2_handle_cmd_put(ump, qk, qv); | |
328 | } else | 328 | } else | |
329 | #endif | 329 | #endif | |
330 | panic("quota_handle_cmd_get: no support ?"); | 330 | panic("quota_handle_cmd_get: no support ?"); | |
331 | 331 | |||
332 | if (error == ENOENT) { | 332 | if (error == ENOENT) { | |
333 | error = 0; | 333 | error = 0; | |
334 | } | 334 | } | |
335 | 335 | |||
336 | return error; | 336 | return error; | |
337 | } | 337 | } | |
338 | 338 | |||
339 | static int | 339 | static int | |
340 | quota_handle_cmd_delete(struct mount *mp, struct lwp *l, | 340 | quota_handle_cmd_delete(struct mount *mp, struct lwp *l, | |
341 | struct vfs_quotactl_args *args) | 341 | struct vfs_quotactl_args *args) | |
342 | { | 342 | { | |
343 | struct ufsmount *ump = VFSTOUFS(mp); | 343 | struct ufsmount *ump = VFSTOUFS(mp); | |
344 | const struct quotakey *qk; | 344 | const struct quotakey *qk; | |
345 | id_t kauth_id; | 345 | id_t kauth_id; | |
346 | int error; | 346 | int error; | |
347 | 347 | |||
348 | KASSERT(args->qc_type == QCT_DELETE); | 348 | KASSERT(args->qc_type == QCT_DELETE); | |
349 | qk = args->u.delete.qc_key; | 349 | qk = args->u.delete.qc_key; | |
350 | 350 | |||
351 | kauth_id = qk->qk_id; | 351 | kauth_id = qk->qk_id; | |
352 | if (kauth_id == QUOTA_DEFAULTID) { | 352 | if (kauth_id == QUOTA_DEFAULTID) { | |
353 | kauth_id = 0; | 353 | kauth_id = 0; | |
354 | } | 354 | } | |
355 | 355 | |||
356 | if ((ump->um_flags & UFS_QUOTA2) == 0) | 356 | if ((ump->um_flags & UFS_QUOTA2) == 0) | |
357 | return EOPNOTSUPP; | 357 | return EOPNOTSUPP; | |
358 | 358 | |||
359 | /* avoid whitespace changes */ | 359 | /* avoid whitespace changes */ | |
360 | { | 360 | { | |
361 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 361 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
362 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), | 362 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), | |
363 | NULL); | 363 | NULL); | |
364 | if (error != 0) | 364 | if (error != 0) | |
365 | goto err; | 365 | goto err; | |
366 | #ifdef QUOTA2 | 366 | #ifdef QUOTA2 | |
367 | if (ump->um_flags & UFS_QUOTA2) { | 367 | if (ump->um_flags & UFS_QUOTA2) { | |
368 | error = quota2_handle_cmd_delete(ump, qk); | 368 | error = quota2_handle_cmd_delete(ump, qk); | |
369 | } else | 369 | } else | |
370 | #endif | 370 | #endif | |
371 | panic("quota_handle_cmd_get: no support ?"); | 371 | panic("quota_handle_cmd_get: no support ?"); | |
372 | 372 | |||
373 | if (error && error != ENOENT) | 373 | if (error && error != ENOENT) | |
374 | goto err; | 374 | goto err; | |
375 | } | 375 | } | |
376 | 376 | |||
377 | return 0; | 377 | return 0; | |
378 | err: | 378 | err: | |
379 | return error; | 379 | return error; | |
380 | } | 380 | } | |
381 | 381 | |||
382 | static int | 382 | static int | |
383 | quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l, | 383 | quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l, | |
384 | struct vfs_quotactl_args *args) | 384 | struct vfs_quotactl_args *args) | |
385 | { | 385 | { | |
386 | struct ufsmount *ump = VFSTOUFS(mp); | 386 | struct ufsmount *ump = VFSTOUFS(mp); | |
387 | struct quotakcursor *cursor; | 387 | struct quotakcursor *cursor; | |
388 | struct quotakey *keys; | 388 | struct quotakey *keys; | |
389 | struct quotaval *vals; | 389 | struct quotaval *vals; | |
390 | unsigned maxnum; | 390 | unsigned maxnum; | |
391 | unsigned *ret; | 391 | unsigned *ret; | |
392 | int error; | 392 | int error; | |
393 | 393 | |||
394 | KASSERT(args->qc_type == QCT_CURSORGET); | 394 | KASSERT(args->qc_type == QCT_CURSORGET); | |
395 | cursor = args->u.cursorget.qc_cursor; | 395 | cursor = args->u.cursorget.qc_cursor; | |
396 | keys = args->u.cursorget.qc_keys; | 396 | keys = args->u.cursorget.qc_keys; | |
397 | vals = args->u.cursorget.qc_vals; | 397 | vals = args->u.cursorget.qc_vals; | |
398 | maxnum = args->u.cursorget.qc_maxnum; | 398 | maxnum = args->u.cursorget.qc_maxnum; | |
399 | ret = args->u.cursorget.qc_ret; | 399 | ret = args->u.cursorget.qc_ret; | |
400 | 400 | |||
401 | if ((ump->um_flags & UFS_QUOTA2) == 0) | 401 | if ((ump->um_flags & UFS_QUOTA2) == 0) | |
402 | return EOPNOTSUPP; | 402 | return EOPNOTSUPP; | |
403 | 403 | |||
404 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 404 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
405 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | 405 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | |
406 | if (error) | 406 | if (error) | |
407 | return error; | 407 | return error; | |
408 | 408 | |||
409 | #ifdef QUOTA2 | 409 | #ifdef QUOTA2 | |
410 | if (ump->um_flags & UFS_QUOTA2) { | 410 | if (ump->um_flags & UFS_QUOTA2) { | |
411 | error = quota2_handle_cmd_cursorget(ump, cursor, keys, vals, | 411 | error = quota2_handle_cmd_cursorget(ump, cursor, keys, vals, | |
412 | maxnum, ret); | 412 | maxnum, ret); | |
413 | } else | 413 | } else | |
414 | #endif | 414 | #endif | |
415 | panic("quota_handle_cmd_cursorget: no support ?"); | 415 | panic("quota_handle_cmd_cursorget: no support ?"); | |
416 | 416 | |||
417 | return error; | 417 | return error; | |
418 | } | 418 | } | |
419 | 419 | |||
420 | static int | 420 | static int | |
421 | quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l, | 421 | quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l, | |
422 | struct vfs_quotactl_args *args) | 422 | struct vfs_quotactl_args *args) | |
423 | { | 423 | { | |
424 | struct ufsmount *ump = VFSTOUFS(mp); | 424 | struct ufsmount *ump = VFSTOUFS(mp); | |
425 | struct quotakcursor *cursor; | 425 | struct quotakcursor *cursor; | |
426 | int error; | 426 | int error; | |
427 | 427 | |||
428 | KASSERT(args->qc_type == QCT_CURSOROPEN); | 428 | KASSERT(args->qc_type == QCT_CURSOROPEN); | |
429 | cursor = args->u.cursoropen.qc_cursor; | 429 | cursor = args->u.cursoropen.qc_cursor; | |
430 | 430 | |||
431 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 431 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
432 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | 432 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | |
433 | if (error) | 433 | if (error) | |
434 | return error; | 434 | return error; | |
435 | 435 | |||
436 | #ifdef QUOTA2 | 436 | #ifdef QUOTA2 | |
437 | if (ump->um_flags & UFS_QUOTA2) { | 437 | if (ump->um_flags & UFS_QUOTA2) { | |
438 | error = quota2_handle_cmd_cursoropen(ump, cursor); | 438 | error = quota2_handle_cmd_cursoropen(ump, cursor); | |
439 | } else | 439 | } else | |
440 | #endif | 440 | #endif | |
441 | error = EOPNOTSUPP; | 441 | error = EOPNOTSUPP; | |
442 | 442 | |||
443 | return error; | 443 | return error; | |
444 | } | 444 | } | |
445 | 445 | |||
446 | static int | 446 | static int | |
447 | quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l, | 447 | quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l, | |
448 | struct vfs_quotactl_args *args) | 448 | struct vfs_quotactl_args *args) | |
449 | { | 449 | { | |
450 | struct ufsmount *ump = VFSTOUFS(mp); | 450 | struct ufsmount *ump = VFSTOUFS(mp); | |
451 | struct quotakcursor *cursor; | 451 | struct quotakcursor *cursor; | |
452 | int error; | 452 | int error; | |
453 | 453 | |||
454 | KASSERT(args->qc_type == QCT_CURSORCLOSE); | 454 | KASSERT(args->qc_type == QCT_CURSORCLOSE); | |
455 | cursor = args->u.cursorclose.qc_cursor; | 455 | cursor = args->u.cursorclose.qc_cursor; | |
456 | 456 | |||
457 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 457 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
458 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | 458 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | |
459 | if (error) | 459 | if (error) | |
460 | return error; | 460 | return error; | |
461 | 461 | |||
462 | #ifdef QUOTA2 | 462 | #ifdef QUOTA2 | |
463 | if (ump->um_flags & UFS_QUOTA2) { | 463 | if (ump->um_flags & UFS_QUOTA2) { | |
464 | error = quota2_handle_cmd_cursorclose(ump, cursor); | 464 | error = quota2_handle_cmd_cursorclose(ump, cursor); | |
465 | } else | 465 | } else | |
466 | #endif | 466 | #endif | |
467 | error = EOPNOTSUPP; | 467 | error = EOPNOTSUPP; | |
468 | 468 | |||
469 | return error; | 469 | return error; | |
470 | } | 470 | } | |
471 | 471 | |||
472 | static int | 472 | static int | |
473 | quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l, | 473 | quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l, | |
474 | struct vfs_quotactl_args *args) | 474 | struct vfs_quotactl_args *args) | |
475 | { | 475 | { | |
476 | struct ufsmount *ump = VFSTOUFS(mp); | 476 | struct ufsmount *ump = VFSTOUFS(mp); | |
477 | struct quotakcursor *cursor; | 477 | struct quotakcursor *cursor; | |
478 | int idtype; | 478 | int idtype; | |
479 | int error; | 479 | int error; | |
480 | 480 | |||
481 | KASSERT(args->qc_type == QCT_CURSORSKIPIDTYPE); | 481 | KASSERT(args->qc_type == QCT_CURSORSKIPIDTYPE); | |
482 | cursor = args->u.cursorskipidtype.qc_cursor; | 482 | cursor = args->u.cursorskipidtype.qc_cursor; | |
483 | idtype = args->u.cursorskipidtype.qc_idtype; | 483 | idtype = args->u.cursorskipidtype.qc_idtype; | |
484 | 484 | |||
485 | #ifdef QUOTA2 | 485 | #ifdef QUOTA2 | |
486 | if (ump->um_flags & UFS_QUOTA2) { | 486 | if (ump->um_flags & UFS_QUOTA2) { | |
487 | error = quota2_handle_cmd_cursorskipidtype(ump, cursor, idtype); | 487 | error = quota2_handle_cmd_cursorskipidtype(ump, cursor, idtype); | |
488 | } else | 488 | } else | |
489 | #endif | 489 | #endif | |
490 | error = EOPNOTSUPP; | 490 | error = EOPNOTSUPP; | |
491 | 491 | |||
492 | return error; | 492 | return error; | |
493 | } | 493 | } | |
494 | 494 | |||
495 | static int | 495 | static int | |
496 | quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l, | 496 | quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l, | |
497 | struct vfs_quotactl_args *args) | 497 | struct vfs_quotactl_args *args) | |
498 | { | 498 | { | |
499 | struct ufsmount *ump = VFSTOUFS(mp); | 499 | struct ufsmount *ump = VFSTOUFS(mp); | |
500 | struct quotakcursor *cursor; | 500 | struct quotakcursor *cursor; | |
501 | int *ret; | 501 | int *ret; | |
502 | int error; | 502 | int error; | |
503 | 503 | |||
504 | KASSERT(args->qc_type == QCT_CURSORATEND); | 504 | KASSERT(args->qc_type == QCT_CURSORATEND); | |
505 | cursor = args->u.cursoratend.qc_cursor; | 505 | cursor = args->u.cursoratend.qc_cursor; | |
506 | ret = args->u.cursoratend.qc_ret; | 506 | ret = args->u.cursoratend.qc_ret; | |
507 | 507 | |||
508 | #ifdef QUOTA2 | 508 | #ifdef QUOTA2 | |
509 | if (ump->um_flags & UFS_QUOTA2) { | 509 | if (ump->um_flags & UFS_QUOTA2) { | |
510 | error = quota2_handle_cmd_cursoratend(ump, cursor, ret); | 510 | error = quota2_handle_cmd_cursoratend(ump, cursor, ret); | |
511 | } else | 511 | } else | |
512 | #endif | 512 | #endif | |
513 | error = EOPNOTSUPP; | 513 | error = EOPNOTSUPP; | |
514 | 514 | |||
515 | return error; | 515 | return error; | |
516 | } | 516 | } | |
517 | 517 | |||
518 | static int | 518 | static int | |
519 | quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l, | 519 | quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l, | |
520 | struct vfs_quotactl_args *args) | 520 | struct vfs_quotactl_args *args) | |
521 | { | 521 | { | |
522 | struct ufsmount *ump = VFSTOUFS(mp); | 522 | struct ufsmount *ump = VFSTOUFS(mp); | |
523 | struct quotakcursor *cursor; | 523 | struct quotakcursor *cursor; | |
524 | int error; | 524 | int error; | |
525 | 525 | |||
526 | KASSERT(args->qc_type == QCT_CURSORREWIND); | 526 | KASSERT(args->qc_type == QCT_CURSORREWIND); | |
527 | cursor = args->u.cursorrewind.qc_cursor; | 527 | cursor = args->u.cursorrewind.qc_cursor; | |
528 | 528 | |||
529 | #ifdef QUOTA2 | 529 | #ifdef QUOTA2 | |
530 | if (ump->um_flags & UFS_QUOTA2) { | 530 | if (ump->um_flags & UFS_QUOTA2) { | |
531 | error = quota2_handle_cmd_cursorrewind(ump, cursor); | 531 | error = quota2_handle_cmd_cursorrewind(ump, cursor); | |
532 | } else | 532 | } else | |
533 | #endif | 533 | #endif | |
534 | error = EOPNOTSUPP; | 534 | error = EOPNOTSUPP; | |
535 | 535 | |||
536 | return error; | 536 | return error; | |
537 | } | 537 | } | |
538 | 538 | |||
539 | static int | 539 | static int | |
540 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, | 540 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, | |
541 | struct vfs_quotactl_args *args) | 541 | struct vfs_quotactl_args *args) | |
542 | { | 542 | { | |
543 | struct ufsmount *ump = VFSTOUFS(mp); | 543 | struct ufsmount *ump = VFSTOUFS(mp); | |
544 | int idtype; | 544 | int idtype; | |
545 | const char *qfile; | 545 | const char *qfile; | |
546 | int error; | 546 | int error; | |
547 | 547 | |||
548 | KASSERT(args->qc_type == QCT_QUOTAON); | 548 | KASSERT(args->qc_type == QCT_QUOTAON); | |
549 | idtype = args->u.quotaon.qc_idtype; | 549 | idtype = args->u.quotaon.qc_idtype; | |
550 | qfile = args->u.quotaon.qc_quotafile; | 550 | qfile = args->u.quotaon.qc_quotafile; | |
551 | 551 | |||
552 | if ((ump->um_flags & UFS_QUOTA2) != 0) | 552 | if ((ump->um_flags & UFS_QUOTA2) != 0) | |
553 | return EBUSY; | 553 | return EBUSY; | |
554 | 554 | |||
555 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 555 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
556 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | 556 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | |
557 | if (error != 0) { | 557 | if (error != 0) { | |
558 | return error; | 558 | return error; | |
559 | } | 559 | } | |
560 | #ifdef QUOTA | 560 | #ifdef QUOTA | |
561 | error = quota1_handle_cmd_quotaon(l, ump, idtype, qfile); | 561 | error = quota1_handle_cmd_quotaon(l, ump, idtype, qfile); | |
562 | #else | 562 | #else | |
563 | error = EOPNOTSUPP; | 563 | error = EOPNOTSUPP; | |
564 | #endif | 564 | #endif | |
565 | 565 | |||
566 | return error; | 566 | return error; | |
567 | } | 567 | } | |
568 | 568 | |||
569 | static int | 569 | static int | |
570 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, | 570 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, | |
571 | struct vfs_quotactl_args *args) | 571 | struct vfs_quotactl_args *args) | |
572 | { | 572 | { | |
573 | struct ufsmount *ump = VFSTOUFS(mp); | 573 | struct ufsmount *ump = VFSTOUFS(mp); | |
574 | int idtype; | |||
574 | int error; | 575 | int error; | |
575 | prop_dictionary_t cmddict; | |||
576 | int q2type; | |||
577 | prop_array_t datas; | |||
578 | ||||
579 | KASSERT(args->qc_type == QCT_PROPLIB); | |||
580 | cmddict = args->u.proplib.qc_cmddict; | |||
581 | q2type = args->u.proplib.qc_q2type; | |||
582 | datas = args->u.proplib.qc_datas; | |||
583 | 576 | |||
584 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 577 | KASSERT(args->qc_type == QCT_QUOTAOFF); | |
585 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 578 | idtype = args->u.quotaoff.qc_idtype; | |
586 | 579 | |||
587 | if ((ump->um_flags & UFS_QUOTA2) != 0) | 580 | if ((ump->um_flags & UFS_QUOTA2) != 0) | |
588 | return EOPNOTSUPP; | 581 | return EOPNOTSUPP; | |
589 | 582 | |||
590 | if (prop_array_count(datas) != 0) | |||
591 | return EINVAL; | |||
592 | ||||
593 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 583 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
594 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | 584 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | |
595 | if (error != 0) { | 585 | if (error != 0) { | |
596 | return error; | 586 | return error; | |
597 | } | 587 | } | |
598 | #ifdef QUOTA | 588 | #ifdef QUOTA | |
599 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); | 589 | error = quota1_handle_cmd_quotaoff(l, ump, idtype); | |
600 | #else | 590 | #else | |
601 | error = EOPNOTSUPP; | 591 | error = EOPNOTSUPP; | |
602 | #endif | 592 | #endif | |
603 | 593 | |||
604 | return error; | 594 | return error; | |
605 | } | 595 | } | |
606 | 596 | |||
607 | /* | 597 | /* | |
608 | * Initialize the quota system. | 598 | * Initialize the quota system. | |
609 | */ | 599 | */ | |
610 | void | 600 | void | |
611 | dqinit(void) | 601 | dqinit(void) | |
612 | { | 602 | { | |
613 | 603 | |||
614 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | 604 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | |
615 | cv_init(&dqcv, "quota"); | 605 | cv_init(&dqcv, "quota"); | |
616 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); | 606 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); | |
617 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", | 607 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", | |
618 | NULL, IPL_NONE, NULL, NULL, NULL); | 608 | NULL, IPL_NONE, NULL, NULL, NULL); | |
619 | } | 609 | } | |
620 | 610 | |||
621 | void | 611 | void | |
622 | dqreinit(void) | 612 | dqreinit(void) | |
623 | { | 613 | { | |
624 | struct dquot *dq; | 614 | struct dquot *dq; | |
625 | struct dqhashhead *oldhash, *hash; | 615 | struct dqhashhead *oldhash, *hash; | |
626 | struct vnode *dqvp; | 616 | struct vnode *dqvp; | |
627 | u_long oldmask, mask, hashval; | 617 | u_long oldmask, mask, hashval; | |
628 | int i; | 618 | int i; | |
629 | 619 | |||
630 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); | 620 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); | |
631 | mutex_enter(&dqlock); | 621 | mutex_enter(&dqlock); | |
632 | oldhash = dqhashtbl; | 622 | oldhash = dqhashtbl; | |
633 | oldmask = dqhash; | 623 | oldmask = dqhash; | |
634 | dqhashtbl = hash; | 624 | dqhashtbl = hash; | |
635 | dqhash = mask; | 625 | dqhash = mask; | |
636 | for (i = 0; i <= oldmask; i++) { | 626 | for (i = 0; i <= oldmask; i++) { | |
637 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { | 627 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { | |
638 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; | 628 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; | |
639 | LIST_REMOVE(dq, dq_hash); | 629 | LIST_REMOVE(dq, dq_hash); | |
640 | hashval = DQHASH(dqvp, dq->dq_id); | 630 | hashval = DQHASH(dqvp, dq->dq_id); | |
641 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); | 631 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); | |
642 | } | 632 | } | |
643 | } | 633 | } | |
644 | mutex_exit(&dqlock); | 634 | mutex_exit(&dqlock); | |
645 | hashdone(oldhash, HASH_LIST, oldmask); | 635 | hashdone(oldhash, HASH_LIST, oldmask); | |
646 | } | 636 | } | |
647 | 637 | |||
648 | /* | 638 | /* | |
649 | * Free resources held by quota system. | 639 | * Free resources held by quota system. | |
650 | */ | 640 | */ | |
651 | void | 641 | void | |
652 | dqdone(void) | 642 | dqdone(void) | |
653 | { | 643 | { | |
654 | 644 | |||
655 | pool_cache_destroy(dquot_cache); | 645 | pool_cache_destroy(dquot_cache); | |
656 | hashdone(dqhashtbl, HASH_LIST, dqhash); | 646 | hashdone(dqhashtbl, HASH_LIST, dqhash); | |
657 | cv_destroy(&dqcv); | 647 | cv_destroy(&dqcv); | |
658 | mutex_destroy(&dqlock); | 648 | mutex_destroy(&dqlock); | |
659 | } | 649 | } | |
660 | 650 | |||
661 | /* | 651 | /* | |
662 | * Set up the quotas for an inode. | 652 | * Set up the quotas for an inode. | |
663 | * | 653 | * | |
664 | * This routine completely defines the semantics of quotas. | 654 | * This routine completely defines the semantics of quotas. | |
665 | * If other criterion want to be used to establish quotas, the | 655 | * If other criterion want to be used to establish quotas, the | |
666 | * MAXQUOTAS value in quotas.h should be increased, and the | 656 | * MAXQUOTAS value in quotas.h should be increased, and the | |
667 | * additional dquots set up here. | 657 | * additional dquots set up here. | |
668 | */ | 658 | */ | |
669 | int | 659 | int | |
670 | getinoquota(struct inode *ip) | 660 | getinoquota(struct inode *ip) | |
671 | { | 661 | { | |
672 | struct ufsmount *ump = ip->i_ump; | 662 | struct ufsmount *ump = ip->i_ump; | |
673 | struct vnode *vp = ITOV(ip); | 663 | struct vnode *vp = ITOV(ip); | |
674 | int i, error; | 664 | int i, error; | |
675 | u_int32_t ino_ids[MAXQUOTAS]; | 665 | u_int32_t ino_ids[MAXQUOTAS]; | |
676 | 666 | |||
677 | /* | 667 | /* | |
678 | * To avoid deadlocks never update quotas for quota files | 668 | * To avoid deadlocks never update quotas for quota files | |
679 | * on the same file system | 669 | * on the same file system | |
680 | */ | 670 | */ | |
681 | for (i = 0; i < MAXQUOTAS; i++) | 671 | for (i = 0; i < MAXQUOTAS; i++) | |
682 | if (vp == ump->um_quotas[i]) | 672 | if (vp == ump->um_quotas[i]) | |
683 | return 0; | 673 | return 0; | |
684 | 674 | |||
685 | ino_ids[USRQUOTA] = ip->i_uid; | 675 | ino_ids[USRQUOTA] = ip->i_uid; | |
686 | ino_ids[GRPQUOTA] = ip->i_gid; | 676 | ino_ids[GRPQUOTA] = ip->i_gid; | |
687 | for (i = 0; i < MAXQUOTAS; i++) { | 677 | for (i = 0; i < MAXQUOTAS; i++) { | |
688 | /* | 678 | /* | |
689 | * If the file id changed the quota needs update. | 679 | * If the file id changed the quota needs update. | |
690 | */ | 680 | */ | |
691 | if (ip->i_dquot[i] != NODQUOT && | 681 | if (ip->i_dquot[i] != NODQUOT && | |
692 | ip->i_dquot[i]->dq_id != ino_ids[i]) { | 682 | ip->i_dquot[i]->dq_id != ino_ids[i]) { | |
693 | dqrele(ITOV(ip), ip->i_dquot[i]); | 683 | dqrele(ITOV(ip), ip->i_dquot[i]); | |
694 | ip->i_dquot[i] = NODQUOT; | 684 | ip->i_dquot[i] = NODQUOT; | |
695 | } | 685 | } | |
696 | /* | 686 | /* | |
697 | * Set up the quota based on file id. | 687 | * Set up the quota based on file id. | |
698 | * ENODEV means that quotas are not enabled. | 688 | * ENODEV means that quotas are not enabled. | |
699 | */ | 689 | */ | |
700 | if (ip->i_dquot[i] == NODQUOT && | 690 | if (ip->i_dquot[i] == NODQUOT && | |
701 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && | 691 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && | |
702 | error != ENODEV) | 692 | error != ENODEV) | |
703 | return (error); | 693 | return (error); | |
704 | } | 694 | } | |
705 | return 0; | 695 | return 0; | |
706 | } | 696 | } | |
707 | 697 | |||
708 | /* | 698 | /* | |
709 | * Obtain a dquot structure for the specified identifier and quota file | 699 | * Obtain a dquot structure for the specified identifier and quota file | |
710 | * reading the information from the file if necessary. | 700 | * reading the information from the file if necessary. | |
711 | */ | 701 | */ | |
712 | int | 702 | int | |
713 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, | 703 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, | |
714 | struct dquot **dqp) | 704 | struct dquot **dqp) | |
715 | { | 705 | { | |
716 | struct dquot *dq, *ndq; | 706 | struct dquot *dq, *ndq; | |
717 | struct dqhashhead *dqh; | 707 | struct dqhashhead *dqh; | |
718 | struct vnode *dqvp; | 708 | struct vnode *dqvp; | |
719 | int error = 0; /* XXX gcc */ | 709 | int error = 0; /* XXX gcc */ | |
720 | 710 | |||
721 | /* Lock to see an up to date value for QTF_CLOSING. */ | 711 | /* Lock to see an up to date value for QTF_CLOSING. */ | |
722 | mutex_enter(&dqlock); | 712 | mutex_enter(&dqlock); | |
723 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { | 713 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { | |
724 | mutex_exit(&dqlock); | 714 | mutex_exit(&dqlock); | |
725 | *dqp = NODQUOT; | 715 | *dqp = NODQUOT; | |
726 | return (ENODEV); | 716 | return (ENODEV); | |
727 | } | 717 | } | |
728 | dqvp = ump->um_quotas[type]; | 718 | dqvp = ump->um_quotas[type]; | |
729 | #ifdef QUOTA | 719 | #ifdef QUOTA | |
730 | if (ump->um_flags & UFS_QUOTA) { | 720 | if (ump->um_flags & UFS_QUOTA) { | |
731 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { | 721 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { | |
732 | mutex_exit(&dqlock); | 722 | mutex_exit(&dqlock); | |
733 | *dqp = NODQUOT; | 723 | *dqp = NODQUOT; | |
734 | return (ENODEV); | 724 | return (ENODEV); | |
735 | } | 725 | } | |
736 | } | 726 | } | |
737 | #endif | 727 | #endif | |
738 | #ifdef QUOTA2 | 728 | #ifdef QUOTA2 | |
739 | if (ump->um_flags & UFS_QUOTA2) { | 729 | if (ump->um_flags & UFS_QUOTA2) { | |
740 | if (dqvp == NULLVP) { | 730 | if (dqvp == NULLVP) { | |
741 | mutex_exit(&dqlock); | 731 | mutex_exit(&dqlock); | |
742 | *dqp = NODQUOT; | 732 | *dqp = NODQUOT; | |
743 | return (ENODEV); | 733 | return (ENODEV); | |
744 | } | 734 | } | |
745 | } | 735 | } | |
746 | #endif | 736 | #endif | |
747 | KASSERT(dqvp != vp); | 737 | KASSERT(dqvp != vp); | |
748 | /* | 738 | /* | |
749 | * Check the cache first. | 739 | * Check the cache first. | |
750 | */ | 740 | */ | |
751 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | 741 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | |
752 | LIST_FOREACH(dq, dqh, dq_hash) { | 742 | LIST_FOREACH(dq, dqh, dq_hash) { | |
753 | if (dq->dq_id != id || | 743 | if (dq->dq_id != id || | |
754 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | 744 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | |
755 | continue; | 745 | continue; | |
756 | KASSERT(dq->dq_cnt > 0); | 746 | KASSERT(dq->dq_cnt > 0); | |
757 | dqref(dq); | 747 | dqref(dq); | |
758 | mutex_exit(&dqlock); | 748 | mutex_exit(&dqlock); | |
759 | *dqp = dq; | 749 | *dqp = dq; | |
760 | return (0); | 750 | return (0); | |
761 | } | 751 | } | |
762 | /* | 752 | /* | |
763 | * Not in cache, allocate a new one. | 753 | * Not in cache, allocate a new one. | |
764 | */ | 754 | */ | |
765 | mutex_exit(&dqlock); | 755 | mutex_exit(&dqlock); | |
766 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); | 756 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); | |
767 | /* | 757 | /* | |
768 | * Initialize the contents of the dquot structure. | 758 | * Initialize the contents of the dquot structure. | |
769 | */ | 759 | */ | |
770 | memset((char *)ndq, 0, sizeof *ndq); | 760 | memset((char *)ndq, 0, sizeof *ndq); | |
771 | ndq->dq_flags = 0; | 761 | ndq->dq_flags = 0; | |
772 | ndq->dq_id = id; | 762 | ndq->dq_id = id; | |
773 | ndq->dq_ump = ump; | 763 | ndq->dq_ump = ump; | |
774 | ndq->dq_type = type; | 764 | ndq->dq_type = type; | |
775 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); | 765 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); | |
776 | mutex_enter(&dqlock); | 766 | mutex_enter(&dqlock); | |
777 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | 767 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | |
778 | LIST_FOREACH(dq, dqh, dq_hash) { | 768 | LIST_FOREACH(dq, dqh, dq_hash) { | |
779 | if (dq->dq_id != id || | 769 | if (dq->dq_id != id || | |
780 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | 770 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | |
781 | continue; | 771 | continue; | |
782 | /* | 772 | /* | |
783 | * Another thread beat us allocating this dquot. | 773 | * Another thread beat us allocating this dquot. | |
784 | */ | 774 | */ | |
785 | KASSERT(dq->dq_cnt > 0); | 775 | KASSERT(dq->dq_cnt > 0); | |
786 | dqref(dq); | 776 | dqref(dq); | |
787 | mutex_exit(&dqlock); | 777 | mutex_exit(&dqlock); | |
788 | mutex_destroy(&ndq->dq_interlock); | 778 | mutex_destroy(&ndq->dq_interlock); | |
789 | pool_cache_put(dquot_cache, ndq); | 779 | pool_cache_put(dquot_cache, ndq); | |
790 | *dqp = dq; | 780 | *dqp = dq; | |
791 | return 0; | 781 | return 0; | |
792 | } | 782 | } | |
793 | dq = ndq; | 783 | dq = ndq; | |
794 | LIST_INSERT_HEAD(dqh, dq, dq_hash); | 784 | LIST_INSERT_HEAD(dqh, dq, dq_hash); | |
795 | dqref(dq); | 785 | dqref(dq); | |
796 | mutex_enter(&dq->dq_interlock); | 786 | mutex_enter(&dq->dq_interlock); | |
797 | mutex_exit(&dqlock); | 787 | mutex_exit(&dqlock); | |
798 | #ifdef QUOTA | 788 | #ifdef QUOTA | |
799 | if (ump->um_flags & UFS_QUOTA) | 789 | if (ump->um_flags & UFS_QUOTA) | |
800 | error = dq1get(dqvp, id, ump, type, dq); | 790 | error = dq1get(dqvp, id, ump, type, dq); | |
801 | #endif | 791 | #endif | |
802 | #ifdef QUOTA2 | 792 | #ifdef QUOTA2 | |
803 | if (ump->um_flags & UFS_QUOTA2) | 793 | if (ump->um_flags & UFS_QUOTA2) | |
804 | error = dq2get(dqvp, id, ump, type, dq); | 794 | error = dq2get(dqvp, id, ump, type, dq); | |
805 | #endif | 795 | #endif | |
806 | /* | 796 | /* | |
807 | * I/O error in reading quota file, release | 797 | * I/O error in reading quota file, release | |
808 | * quota structure and reflect problem to caller. | 798 | * quota structure and reflect problem to caller. | |
809 | */ | 799 | */ | |
810 | if (error) { | 800 | if (error) { | |
811 | mutex_enter(&dqlock); | 801 | mutex_enter(&dqlock); | |
812 | LIST_REMOVE(dq, dq_hash); | 802 | LIST_REMOVE(dq, dq_hash); | |
813 | mutex_exit(&dqlock); | 803 | mutex_exit(&dqlock); | |
814 | mutex_exit(&dq->dq_interlock); | 804 | mutex_exit(&dq->dq_interlock); | |
815 | dqrele(vp, dq); | 805 | dqrele(vp, dq); | |
816 | *dqp = NODQUOT; | 806 | *dqp = NODQUOT; | |
817 | return (error); | 807 | return (error); | |
818 | } | 808 | } | |
819 | mutex_exit(&dq->dq_interlock); | 809 | mutex_exit(&dq->dq_interlock); | |
820 | *dqp = dq; | 810 | *dqp = dq; | |
821 | return (0); | 811 | return (0); | |
822 | } | 812 | } | |
823 | 813 | |||
824 | /* | 814 | /* | |
825 | * Obtain a reference to a dquot. | 815 | * Obtain a reference to a dquot. | |
826 | */ | 816 | */ | |
827 | void | 817 | void | |
828 | dqref(struct dquot *dq) | 818 | dqref(struct dquot *dq) | |
829 | { | 819 | { | |
830 | 820 | |||
831 | KASSERT(mutex_owned(&dqlock)); | 821 | KASSERT(mutex_owned(&dqlock)); | |
832 | dq->dq_cnt++; | 822 | dq->dq_cnt++; | |
833 | KASSERT(dq->dq_cnt > 0); | 823 | KASSERT(dq->dq_cnt > 0); | |
834 | } | 824 | } | |
835 | 825 | |||
836 | /* | 826 | /* | |
837 | * Release a reference to a dquot. | 827 | * Release a reference to a dquot. | |
838 | */ | 828 | */ | |
839 | void | 829 | void | |
840 | dqrele(struct vnode *vp, struct dquot *dq) | 830 | dqrele(struct vnode *vp, struct dquot *dq) | |
841 | { | 831 | { | |
842 | 832 | |||
843 | if (dq == NODQUOT) | 833 | if (dq == NODQUOT) | |
844 | return; | 834 | return; | |
845 | mutex_enter(&dq->dq_interlock); | 835 | mutex_enter(&dq->dq_interlock); | |
846 | for (;;) { | 836 | for (;;) { | |
847 | mutex_enter(&dqlock); | 837 | mutex_enter(&dqlock); | |
848 | if (dq->dq_cnt > 1) { | 838 | if (dq->dq_cnt > 1) { | |
849 | dq->dq_cnt--; | 839 | dq->dq_cnt--; | |
850 | mutex_exit(&dqlock); | 840 | mutex_exit(&dqlock); | |
851 | mutex_exit(&dq->dq_interlock); | 841 | mutex_exit(&dq->dq_interlock); | |
852 | return; | 842 | return; | |
853 | } | 843 | } | |
854 | if ((dq->dq_flags & DQ_MOD) == 0) | 844 | if ((dq->dq_flags & DQ_MOD) == 0) | |
855 | break; | 845 | break; | |
856 | mutex_exit(&dqlock); | 846 | mutex_exit(&dqlock); | |
857 | #ifdef QUOTA | 847 | #ifdef QUOTA | |
858 | if (dq->dq_ump->um_flags & UFS_QUOTA) | 848 | if (dq->dq_ump->um_flags & UFS_QUOTA) | |
859 | (void) dq1sync(vp, dq); | 849 | (void) dq1sync(vp, dq); | |
860 | #endif | 850 | #endif | |
861 | #ifdef QUOTA2 | 851 | #ifdef QUOTA2 | |
862 | if (dq->dq_ump->um_flags & UFS_QUOTA2) | 852 | if (dq->dq_ump->um_flags & UFS_QUOTA2) | |
863 | (void) dq2sync(vp, dq); | 853 | (void) dq2sync(vp, dq); | |
864 | #endif | 854 | #endif | |
865 | } | 855 | } | |
866 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); | 856 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); | |
867 | LIST_REMOVE(dq, dq_hash); | 857 | LIST_REMOVE(dq, dq_hash); | |
868 | mutex_exit(&dqlock); | 858 | mutex_exit(&dqlock); | |
869 | mutex_exit(&dq->dq_interlock); | 859 | mutex_exit(&dq->dq_interlock); | |
870 | mutex_destroy(&dq->dq_interlock); | 860 | mutex_destroy(&dq->dq_interlock); | |
871 | pool_cache_put(dquot_cache, dq); | 861 | pool_cache_put(dquot_cache, dq); | |
872 | } | 862 | } | |
873 | 863 | |||
874 | int | 864 | int | |
875 | qsync(struct mount *mp) | 865 | qsync(struct mount *mp) | |
876 | { | 866 | { | |
877 | struct ufsmount *ump = VFSTOUFS(mp); | 867 | struct ufsmount *ump = VFSTOUFS(mp); | |
878 | #ifdef QUOTA | 868 | #ifdef QUOTA | |
879 | if (ump->um_flags & UFS_QUOTA) | 869 | if (ump->um_flags & UFS_QUOTA) | |
880 | return q1sync(mp); | 870 | return q1sync(mp); | |
881 | #endif | 871 | #endif | |
882 | #ifdef QUOTA2 | 872 | #ifdef QUOTA2 | |
883 | if (ump->um_flags & UFS_QUOTA2) | 873 | if (ump->um_flags & UFS_QUOTA2) | |
884 | return q2sync(mp); | 874 | return q2sync(mp); | |
885 | #endif | 875 | #endif | |
886 | return 0; | 876 | return 0; | |
887 | } | 877 | } | |
888 | 878 | |||
889 | #ifdef DIAGNOSTIC | 879 | #ifdef DIAGNOSTIC | |
890 | /* | 880 | /* | |
891 | * Check the hash chains for stray dquot's. | 881 | * Check the hash chains for stray dquot's. | |
892 | */ | 882 | */ | |
893 | void | 883 | void | |
894 | dqflush(struct vnode *vp) | 884 | dqflush(struct vnode *vp) | |
895 | { | 885 | { | |
896 | struct dquot *dq; | 886 | struct dquot *dq; | |
897 | int i; | 887 | int i; | |
898 | 888 | |||
899 | mutex_enter(&dqlock); | 889 | mutex_enter(&dqlock); | |
900 | for (i = 0; i <= dqhash; i++) | 890 | for (i = 0; i <= dqhash; i++) | |
901 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) | 891 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) | |
902 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); | 892 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); | |
903 | mutex_exit(&dqlock); | 893 | mutex_exit(&dqlock); | |
904 | } | 894 | } | |
905 | #endif | 895 | #endif |