Sun Jan 29 07:11:55 2012 UTC ()
Move proplib bits for QUOTACTL_QUOTAOFF out of the ufs code.

This change requires a kernel version bump.


(dholland)
diff -r1.31 -r1.32 src/sys/kern/vfs_quotactl.c
diff -r1.27 -r1.28 src/sys/sys/quotactl.h
diff -r1.99 -r1.100 src/sys/ufs/ufs/ufs_quota.c

cvs diff -r1.31 -r1.32 src/sys/kern/vfs_quotactl.c (switch to unified diff)

--- 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
91static int 91static int
92vfs_quotactl_getversion(struct mount *mp, 92vfs_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
142static int 142static int
143vfs_quotactl_quotaon(struct mount *mp, 143vfs_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
170static int 170static int
171vfs_quotactl_quotaoff(struct mount *mp, 171vfs_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
184static int 188static int
185vfs_quotactl_get_addreply(const struct quotakey *qk, 189vfs_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
220static int 224static int
221vfs_quotactl_get(struct mount *mp, 225vfs_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
316static int 320static int
317vfs_quotactl_put_extractinfo(prop_dictionary_t data, 321vfs_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
368static int 372static int
369vfs_quotactl_put(struct mount *mp, 373vfs_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;
449err: 453err:
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
455static prop_dictionary_t 459static prop_dictionary_t
456vfs_quotactl_getall_makereply(const struct quotakey *key) 460vfs_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
487err: 491err:
488 prop_object_release(dict); 492 prop_object_release(dict);
489 return NULL; 493 return NULL;
490} 494}
491 495
492static int 496static int
493vfs_quotactl_getall_addreply(prop_dictionary_t thisreply, 497vfs_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
536static int 540static int
537vfs_quotactl_getall(struct mount *mp, 541vfs_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
727static int 731static int
728vfs_quotactl_clear(struct mount *mp, 732vfs_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;
798err: 802err:
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
804static int 808static int
805vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) 809vfs_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
859int 863int
860vfs_quotactl(struct mount *mp, prop_dictionary_t dict) 864vfs_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}

cvs diff -r1.27 -r1.28 src/sys/sys/quotactl.h (switch to unified diff)

--- 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 */
47struct quotakcursor { 47struct 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. */
69enum vfs_quotactl_argtypes { 69enum 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};
83struct vfs_quotactl_args { 84struct 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_ */

cvs diff -r1.99 -r1.100 src/sys/ufs/ufs/ufs_quota.c (switch to unified diff)

--- 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
61kmutex_t dqlock; 61kmutex_t dqlock;
62kcondvar_t dqcv; 62kcondvar_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)
69static LIST_HEAD(dqhashhead, dquot) *dqhashtbl; 69static LIST_HEAD(dqhashhead, dquot) *dqhashtbl;
70static u_long dqhash; 70static u_long dqhash;
71static pool_cache_t dquot_cache; 71static pool_cache_t dquot_cache;
72 72
73 73
74static int quota_handle_cmd_get_version(struct mount *, struct lwp *, 74static int quota_handle_cmd_get_version(struct mount *, struct lwp *,
75 struct vfs_quotactl_args *args); 75 struct vfs_quotactl_args *args);
76static int quota_handle_cmd_get(struct mount *, struct lwp *, 76static int quota_handle_cmd_get(struct mount *, struct lwp *,
77 struct vfs_quotactl_args *args); 77 struct vfs_quotactl_args *args);
78static int quota_handle_cmd_put(struct mount *, struct lwp *, 78static int quota_handle_cmd_put(struct mount *, struct lwp *,
79 struct vfs_quotactl_args *args); 79 struct vfs_quotactl_args *args);
80static int quota_handle_cmd_cursorget(struct mount *, struct lwp *, 80static int quota_handle_cmd_cursorget(struct mount *, struct lwp *,
81 struct vfs_quotactl_args *args); 81 struct vfs_quotactl_args *args);
82static int quota_handle_cmd_delete(struct mount *, struct lwp *, 82static int quota_handle_cmd_delete(struct mount *, struct lwp *,
83 struct vfs_quotactl_args *args); 83 struct vfs_quotactl_args *args);
84static int quota_handle_cmd_quotaon(struct mount *, struct lwp *,  84static int quota_handle_cmd_quotaon(struct mount *, struct lwp *,
85 struct vfs_quotactl_args *args); 85 struct vfs_quotactl_args *args);
86static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *,  86static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *,
87 struct vfs_quotactl_args *args); 87 struct vfs_quotactl_args *args);
88static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *, 88static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *,
89 struct vfs_quotactl_args *args); 89 struct vfs_quotactl_args *args);
90static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *, 90static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *,
91 struct vfs_quotactl_args *args); 91 struct vfs_quotactl_args *args);
92static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *, 92static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *,
93 struct vfs_quotactl_args *args); 93 struct vfs_quotactl_args *args);
94static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *, 94static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *,
95 struct vfs_quotactl_args *args); 95 struct vfs_quotactl_args *args);
96static int quota_handle_cmd_cursorrewind(struct mount *, struct lwp *, 96static 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 */
102void 102void
103ufsquota_init(struct inode *ip) 103ufsquota_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 */
114void 114void
115ufsquota_free(struct inode *ip) 115ufsquota_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 */
128int 128int
129chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) 129chkdq(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 */
149int 149int
150chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) 150chkiq(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
166int 166int
167quota_handle_cmd(struct mount *mp, struct lwp *l, int op, 167quota_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
216static int  216static int
217quota_handle_cmd_get_version(struct mount *mp, struct lwp *l,  217quota_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 ? */
245static int 245static int
246quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { 246quota_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
254static int  254static int
255quota_handle_cmd_get(struct mount *mp, struct lwp *l,  255quota_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
291static int  291static int
292quota_handle_cmd_put(struct mount *mp, struct lwp *l,  292quota_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
339static int  339static int
340quota_handle_cmd_delete(struct mount *mp, struct lwp *l,  340quota_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
382static int  382static int
383quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l,  383quota_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
420static int  420static int
421quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l,  421quota_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
446static int  446static int
447quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l,  447quota_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
472static int  472static int
473quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l,  473quota_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
495static int  495static int
496quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l,  496quota_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
518static int  518static int
519quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l,  519quota_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
539static int  539static int
540quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,  540quota_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
569static int  569static int
570quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,  570quota_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 */
610void 600void
611dqinit(void) 601dqinit(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
621void 611void
622dqreinit(void) 612dqreinit(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 */
651void 641void
652dqdone(void) 642dqdone(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 */
669int 659int
670getinoquota(struct inode *ip) 660getinoquota(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 */
712int 702int
713dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, 703dqget(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 */
827void 817void
828dqref(struct dquot *dq) 818dqref(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 */
839void 829void
840dqrele(struct vnode *vp, struct dquot *dq) 830dqrele(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
874int 864int
875qsync(struct mount *mp) 865qsync(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 */
893void 883void
894dqflush(struct vnode *vp) 884dqflush(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