Sun Jan 29 07:06:02 2012 UTC ()
Stop treating the default values specially in QUOTACTL_GETALL.

Note: this change requires a kernel version bump.


(dholland)
diff -r1.24 -r1.25 src/sys/kern/vfs_quotactl.c
diff -r1.22 -r1.23 src/sys/sys/quotactl.h
diff -r1.21 -r1.22 src/sys/ufs/ufs/ufs_quota2.c

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

--- src/sys/kern/vfs_quotactl.c 2012/01/29 07:05:12 1.24
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 07:06:01 1.25
@@ -1,772 +1,774 @@ @@ -1,772 +1,774 @@
1/* $NetBSD: vfs_quotactl.c,v 1.24 2012/01/29 07:05:12 dholland Exp $ */ 1/* $NetBSD: vfs_quotactl.c,v 1.25 2012/01/29 07:06:01 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.24 2012/01/29 07:05:12 dholland Exp $"); 83__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.25 2012/01/29 07:06:01 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 struct vfs_quotactl_args args; 147 struct vfs_quotactl_args args;
148 148
149 args.qc_type = QCT_PROPLIB; 149 args.qc_type = QCT_PROPLIB;
150 args.u.proplib.qc_cmddict = cmddict; 150 args.u.proplib.qc_cmddict = cmddict;
151 args.u.proplib.qc_q2type = q2type; 151 args.u.proplib.qc_q2type = q2type;
152 args.u.proplib.qc_datas = datas; 152 args.u.proplib.qc_datas = datas;
153 return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args); 153 return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args);
154} 154}
155 155
156static int 156static int
157vfs_quotactl_quotaoff(struct mount *mp, 157vfs_quotactl_quotaoff(struct mount *mp,
158 prop_dictionary_t cmddict, int q2type, 158 prop_dictionary_t cmddict, int q2type,
159 prop_array_t datas) 159 prop_array_t datas)
160{ 160{
161 struct vfs_quotactl_args args; 161 struct vfs_quotactl_args args;
162 162
163 args.qc_type = QCT_PROPLIB; 163 args.qc_type = QCT_PROPLIB;
164 args.u.proplib.qc_cmddict = cmddict; 164 args.u.proplib.qc_cmddict = cmddict;
165 args.u.proplib.qc_q2type = q2type; 165 args.u.proplib.qc_q2type = q2type;
166 args.u.proplib.qc_datas = datas; 166 args.u.proplib.qc_datas = datas;
167 return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args); 167 return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args);
168} 168}
169 169
170static int 170static int
171vfs_quotactl_get_addreply(const struct quotakey *qk, 171vfs_quotactl_get_addreply(const struct quotakey *qk,
172 const struct quotaval *blocks, 172 const struct quotaval *blocks,
173 const struct quotaval *files, 173 const struct quotaval *files,
174 prop_array_t replies) 174 prop_array_t replies)
175{ 175{
176 prop_dictionary_t dict; 176 prop_dictionary_t dict;
177 id_t id; 177 id_t id;
178 int defaultq; 178 int defaultq;
179 uint64_t *valuesp[QUOTA_NLIMITS]; 179 uint64_t *valuesp[QUOTA_NLIMITS];
180 180
181 /* XXX illegal casts */ 181 /* XXX illegal casts */
182 valuesp[QUOTA_LIMIT_BLOCK] = (void *)(intptr_t)&blocks->qv_hardlimit; 182 valuesp[QUOTA_LIMIT_BLOCK] = (void *)(intptr_t)&blocks->qv_hardlimit;
183 valuesp[QUOTA_LIMIT_FILE] = (void *)(intptr_t)&files->qv_hardlimit; 183 valuesp[QUOTA_LIMIT_FILE] = (void *)(intptr_t)&files->qv_hardlimit;
184 184
185 if (qk->qk_id == QUOTA_DEFAULTID) { 185 if (qk->qk_id == QUOTA_DEFAULTID) {
186 id = 0; 186 id = 0;
187 defaultq = 1; 187 defaultq = 1;
188 } else { 188 } else {
189 id = qk->qk_id; 189 id = qk->qk_id;
190 defaultq = 0; 190 defaultq = 0;
191 } 191 }
192 192
193 dict = quota64toprop(id, defaultq, valuesp, 193 dict = quota64toprop(id, defaultq, valuesp,
194 ufs_quota_entry_names, UFS_QUOTA_NENTRIES, 194 ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
195 ufs_quota_limit_names, QUOTA_NLIMITS); 195 ufs_quota_limit_names, QUOTA_NLIMITS);
196 if (dict == NULL) 196 if (dict == NULL)
197 return ENOMEM; 197 return ENOMEM;
198 if (!prop_array_add_and_rel(replies, dict)) { 198 if (!prop_array_add_and_rel(replies, dict)) {
199 prop_object_release(dict); 199 prop_object_release(dict);
200 return ENOMEM; 200 return ENOMEM;
201 } 201 }
202 202
203 return 0; 203 return 0;
204} 204}
205 205
206static int 206static int
207vfs_quotactl_get(struct mount *mp, 207vfs_quotactl_get(struct mount *mp,
208 prop_dictionary_t cmddict, int idtype, 208 prop_dictionary_t cmddict, int idtype,
209 prop_array_t datas) 209 prop_array_t datas)
210{ 210{
211 prop_object_iterator_t iter; 211 prop_object_iterator_t iter;
212 prop_dictionary_t data; 212 prop_dictionary_t data;
213 prop_array_t replies; 213 prop_array_t replies;
214 uint32_t id; 214 uint32_t id;
215 const char *idstr; 215 const char *idstr;
216 struct vfs_quotactl_args args; 216 struct vfs_quotactl_args args;
217 struct quotakey qk; 217 struct quotakey qk;
218 struct quotaval blocks, files; 218 struct quotaval blocks, files;
219 int error; 219 int error;
220 220
221 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 221 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
222 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 222 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
223 223
224 replies = prop_array_create(); 224 replies = prop_array_create();
225 if (replies == NULL) { 225 if (replies == NULL) {
226 return ENOMEM; 226 return ENOMEM;
227 } 227 }
228 228
229 iter = prop_array_iterator(datas); 229 iter = prop_array_iterator(datas);
230 if (iter == NULL) { 230 if (iter == NULL) {
231 prop_object_release(replies); 231 prop_object_release(replies);
232 return ENOMEM; 232 return ENOMEM;
233 } 233 }
234 234
235 while ((data = prop_object_iterator_next(iter)) != NULL) { 235 while ((data = prop_object_iterator_next(iter)) != NULL) {
236 qk.qk_idtype = idtype; 236 qk.qk_idtype = idtype;
237 237
238 if (!prop_dictionary_get_uint32(data, "id", &id)) { 238 if (!prop_dictionary_get_uint32(data, "id", &id)) {
239 if (!prop_dictionary_get_cstring_nocopy(data, "id", 239 if (!prop_dictionary_get_cstring_nocopy(data, "id",
240 &idstr)) 240 &idstr))
241 continue; 241 continue;
242 if (strcmp(idstr, "default")) { 242 if (strcmp(idstr, "default")) {
243 error = EINVAL; 243 error = EINVAL;
244 goto fail; 244 goto fail;
245 } 245 }
246 qk.qk_id = QUOTA_DEFAULTID; 246 qk.qk_id = QUOTA_DEFAULTID;
247 } else { 247 } else {
248 qk.qk_id = id; 248 qk.qk_id = id;
249 } 249 }
250 250
251 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 251 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
252 252
253 args.qc_type = QCT_GET; 253 args.qc_type = QCT_GET;
254 args.u.get.qc_key = &qk; 254 args.u.get.qc_key = &qk;
255 args.u.get.qc_ret = &blocks; 255 args.u.get.qc_ret = &blocks;
256 error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); 256 error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args);
257 if (error == EPERM) { 257 if (error == EPERM) {
258 /* XXX does this make sense? */ 258 /* XXX does this make sense? */
259 continue; 259 continue;
260 } else if (error == ENOENT) { 260 } else if (error == ENOENT) {
261 /* XXX does *this* make sense? */ 261 /* XXX does *this* make sense? */
262 continue; 262 continue;
263 } else if (error) { 263 } else if (error) {
264 goto fail; 264 goto fail;
265 } 265 }
266 266
267 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 267 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
268 268
269 args.qc_type = QCT_GET; 269 args.qc_type = QCT_GET;
270 args.u.get.qc_key = &qk; 270 args.u.get.qc_key = &qk;
271 args.u.get.qc_ret = &files; 271 args.u.get.qc_ret = &files;
272 error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); 272 error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args);
273 if (error == EPERM) { 273 if (error == EPERM) {
274 /* XXX does this make sense? */ 274 /* XXX does this make sense? */
275 continue; 275 continue;
276 } else if (error == ENOENT) { 276 } else if (error == ENOENT) {
277 /* XXX does *this* make sense? */ 277 /* XXX does *this* make sense? */
278 continue; 278 continue;
279 } else if (error) { 279 } else if (error) {
280 goto fail; 280 goto fail;
281 } 281 }
282 282
283 error = vfs_quotactl_get_addreply(&qk, &blocks, &files, 283 error = vfs_quotactl_get_addreply(&qk, &blocks, &files,
284 replies); 284 replies);
285 } 285 }
286 286
287 prop_object_iterator_release(iter); 287 prop_object_iterator_release(iter);
288 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 288 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
289 error = ENOMEM; 289 error = ENOMEM;
290 } else { 290 } else {
291 error = 0; 291 error = 0;
292 } 292 }
293 293
294 return error; 294 return error;
295 295
296 fail: 296 fail:
297 prop_object_iterator_release(iter); 297 prop_object_iterator_release(iter);
298 prop_object_release(replies); 298 prop_object_release(replies);
299 return error; 299 return error;
300} 300}
301 301
302static int 302static int
303vfs_quotactl_put_extractinfo(prop_dictionary_t data, 303vfs_quotactl_put_extractinfo(prop_dictionary_t data,
304 struct quotaval *blocks, struct quotaval *files) 304 struct quotaval *blocks, struct quotaval *files)
305{ 305{
306 /* 306 /*
307 * So, the way proptoquota64 works is that you pass it an 307 * So, the way proptoquota64 works is that you pass it an
308 * array of pointers to uint64. Each of these pointers is 308 * array of pointers to uint64. Each of these pointers is
309 * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This 309 * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This
310 * array of pointers is the second argument. The third and 310 * array of pointers is the second argument. The third and
311 * forth argument are the names of the five values to extract, 311 * forth argument are the names of the five values to extract,
312 * and UFS_QUOTA_NENTRIES. The last two arguments are the 312 * and UFS_QUOTA_NENTRIES. The last two arguments are the
313 * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK, 313 * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK,
314 * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of 314 * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of
315 * the existing code was unsafely casting struct quotaval 315 * the existing code was unsafely casting struct quotaval
316 * (formerly struct ufs_quota_entry) to (uint64_t *) and using 316 * (formerly struct ufs_quota_entry) to (uint64_t *) and using
317 * that as the block of 5 uint64s. Or worse, pointing to 317 * that as the block of 5 uint64s. Or worse, pointing to
318 * subregions of that and reducing the number of uint64s to 318 * subregions of that and reducing the number of uint64s to
319 * pull "adjacent" values. Demons fly out of your nose! 319 * pull "adjacent" values. Demons fly out of your nose!
320 */ 320 */
321 321
322 uint64_t bvals[UFS_QUOTA_NENTRIES]; 322 uint64_t bvals[UFS_QUOTA_NENTRIES];
323 uint64_t fvals[UFS_QUOTA_NENTRIES]; 323 uint64_t fvals[UFS_QUOTA_NENTRIES];
324 uint64_t *valptrs[QUOTA_NLIMITS]; 324 uint64_t *valptrs[QUOTA_NLIMITS];
325 int error; 325 int error;
326 326
327 valptrs[QUOTA_LIMIT_BLOCK] = bvals; 327 valptrs[QUOTA_LIMIT_BLOCK] = bvals;
328 valptrs[QUOTA_LIMIT_FILE] = fvals; 328 valptrs[QUOTA_LIMIT_FILE] = fvals;
329 error = proptoquota64(data, valptrs, 329 error = proptoquota64(data, valptrs,
330 ufs_quota_entry_names, UFS_QUOTA_NENTRIES, 330 ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
331 ufs_quota_limit_names, QUOTA_NLIMITS); 331 ufs_quota_limit_names, QUOTA_NLIMITS);
332 if (error) { 332 if (error) {
333 return error; 333 return error;
334 } 334 }
335 335
336 /* 336 /*
337 * There are no symbolic constants for these indexes! 337 * There are no symbolic constants for these indexes!
338 */ 338 */
339 339
340 blocks->qv_hardlimit = bvals[0]; 340 blocks->qv_hardlimit = bvals[0];
341 blocks->qv_softlimit = bvals[1]; 341 blocks->qv_softlimit = bvals[1];
342 blocks->qv_usage = bvals[2]; 342 blocks->qv_usage = bvals[2];
343 blocks->qv_expiretime = bvals[3]; 343 blocks->qv_expiretime = bvals[3];
344 blocks->qv_grace = bvals[4]; 344 blocks->qv_grace = bvals[4];
345 files->qv_hardlimit = fvals[0]; 345 files->qv_hardlimit = fvals[0];
346 files->qv_softlimit = fvals[1]; 346 files->qv_softlimit = fvals[1];
347 files->qv_usage = fvals[2]; 347 files->qv_usage = fvals[2];
348 files->qv_expiretime = fvals[3]; 348 files->qv_expiretime = fvals[3];
349 files->qv_grace = fvals[4]; 349 files->qv_grace = fvals[4];
350 350
351 return 0; 351 return 0;
352} 352}
353 353
354static int 354static int
355vfs_quotactl_put(struct mount *mp, 355vfs_quotactl_put(struct mount *mp,
356 prop_dictionary_t cmddict, int q2type, 356 prop_dictionary_t cmddict, int q2type,
357 prop_array_t datas) 357 prop_array_t datas)
358{ 358{
359 prop_array_t replies; 359 prop_array_t replies;
360 prop_object_iterator_t iter; 360 prop_object_iterator_t iter;
361 prop_dictionary_t data; 361 prop_dictionary_t data;
362 int defaultq; 362 int defaultq;
363 uint32_t id; 363 uint32_t id;
364 const char *idstr; 364 const char *idstr;
365 struct quotakey qk; 365 struct quotakey qk;
366 struct quotaval blocks, files; 366 struct quotaval blocks, files;
367 struct vfs_quotactl_args args; 367 struct vfs_quotactl_args args;
368 int error; 368 int error;
369 369
370 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 370 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
371 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 371 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
372 372
373 replies = prop_array_create(); 373 replies = prop_array_create();
374 if (replies == NULL) 374 if (replies == NULL)
375 return ENOMEM; 375 return ENOMEM;
376 376
377 iter = prop_array_iterator(datas); 377 iter = prop_array_iterator(datas);
378 if (iter == NULL) { 378 if (iter == NULL) {
379 prop_object_release(replies); 379 prop_object_release(replies);
380 return ENOMEM; 380 return ENOMEM;
381 } 381 }
382 382
383 while ((data = prop_object_iterator_next(iter)) != NULL) { 383 while ((data = prop_object_iterator_next(iter)) != NULL) {
384 384
385 KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY); 385 KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY);
386 386
387 if (!prop_dictionary_get_uint32(data, "id", &id)) { 387 if (!prop_dictionary_get_uint32(data, "id", &id)) {
388 if (!prop_dictionary_get_cstring_nocopy(data, "id", 388 if (!prop_dictionary_get_cstring_nocopy(data, "id",
389 &idstr)) 389 &idstr))
390 continue; 390 continue;
391 if (strcmp(idstr, "default")) 391 if (strcmp(idstr, "default"))
392 continue; 392 continue;
393 id = 0; 393 id = 0;
394 defaultq = 1; 394 defaultq = 1;
395 } else { 395 } else {
396 defaultq = 0; 396 defaultq = 0;
397 } 397 }
398 398
399 error = vfs_quotactl_put_extractinfo(data, &blocks, &files); 399 error = vfs_quotactl_put_extractinfo(data, &blocks, &files);
400 if (error) { 400 if (error) {
401 goto err; 401 goto err;
402 } 402 }
403 403
404 qk.qk_idtype = q2type; 404 qk.qk_idtype = q2type;
405 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 405 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
406 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 406 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
407 407
408 args.qc_type = QCT_PUT; 408 args.qc_type = QCT_PUT;
409 args.u.put.qc_key = &qk; 409 args.u.put.qc_key = &qk;
410 args.u.put.qc_val = &blocks; 410 args.u.put.qc_val = &blocks;
411 error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); 411 error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args);
412 if (error) { 412 if (error) {
413 goto err; 413 goto err;
414 } 414 }
415 415
416 qk.qk_idtype = q2type; 416 qk.qk_idtype = q2type;
417 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 417 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
418 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 418 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
419 419
420 args.qc_type = QCT_PUT; 420 args.qc_type = QCT_PUT;
421 args.u.put.qc_key = &qk; 421 args.u.put.qc_key = &qk;
422 args.u.put.qc_val = &files; 422 args.u.put.qc_val = &files;
423 error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); 423 error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args);
424 if (error) { 424 if (error) {
425 goto err; 425 goto err;
426 } 426 }
427 } 427 }
428 prop_object_iterator_release(iter); 428 prop_object_iterator_release(iter);
429 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 429 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
430 error = ENOMEM; 430 error = ENOMEM;
431 } else { 431 } else {
432 error = 0; 432 error = 0;
433 } 433 }
434 return error; 434 return error;
435err: 435err:
436 prop_object_iterator_release(iter); 436 prop_object_iterator_release(iter);
437 prop_object_release(replies); 437 prop_object_release(replies);
438 return error; 438 return error;
439} 439}
440 440
441static prop_dictionary_t 441static prop_dictionary_t
442vfs_quotactl_getall_makereply(id_t id, int def, 442vfs_quotactl_getall_makereply(id_t id, int def,
443 const struct quotaval *blocks, 443 const struct quotaval *blocks,
444 const struct quotaval *files) 444 const struct quotaval *files)
445{ 445{
446#define INITQVNAMES_ALL { \ 446#define INITQVNAMES_ALL { \
447 QUOTADICT_LIMIT_HARD, \ 447 QUOTADICT_LIMIT_HARD, \
448 QUOTADICT_LIMIT_SOFT, \ 448 QUOTADICT_LIMIT_SOFT, \
449 QUOTADICT_LIMIT_USAGE, \ 449 QUOTADICT_LIMIT_USAGE, \
450 QUOTADICT_LIMIT_ETIME, \ 450 QUOTADICT_LIMIT_ETIME, \
451 QUOTADICT_LIMIT_GTIME \ 451 QUOTADICT_LIMIT_GTIME \
452 } 452 }
453#define N_QV 5 453#define N_QV 5
454 454
455 const char *val_names[] = INITQVNAMES_ALL; 455 const char *val_names[] = INITQVNAMES_ALL;
456 uint64_t vals[N_QV]; 456 uint64_t vals[N_QV];
457 prop_dictionary_t dict1 = prop_dictionary_create(); 457 prop_dictionary_t dict1 = prop_dictionary_create();
458 prop_dictionary_t dict2; 458 prop_dictionary_t dict2;
459 459
460 if (dict1 == NULL) 460 if (dict1 == NULL)
461 return NULL; 461 return NULL;
462 462
463 if (def) { 463 if (def) {
464 if (!prop_dictionary_set_cstring_nocopy(dict1, "id", 464 if (!prop_dictionary_set_cstring_nocopy(dict1, "id",
465 "default")) { 465 "default")) {
466 goto err; 466 goto err;
467 } 467 }
468 } else { 468 } else {
469 if (!prop_dictionary_set_uint32(dict1, "id", id)) { 469 if (!prop_dictionary_set_uint32(dict1, "id", id)) {
470 goto err; 470 goto err;
471 } 471 }
472 } 472 }
473 473
474 vals[0] = blocks->qv_hardlimit; 474 vals[0] = blocks->qv_hardlimit;
475 vals[1] = blocks->qv_softlimit; 475 vals[1] = blocks->qv_softlimit;
476 vals[2] = blocks->qv_usage; 476 vals[2] = blocks->qv_usage;
477 vals[3] = blocks->qv_expiretime; 477 vals[3] = blocks->qv_expiretime;
478 vals[4] = blocks->qv_grace; 478 vals[4] = blocks->qv_grace;
479 dict2 = limits64toprop(vals, val_names, N_QV); 479 dict2 = limits64toprop(vals, val_names, N_QV);
480 if (dict2 == NULL) 480 if (dict2 == NULL)
481 goto err; 481 goto err;
482 if (!prop_dictionary_set_and_rel(dict1, QUOTADICT_LTYPE_BLOCK, dict2)) 482 if (!prop_dictionary_set_and_rel(dict1, QUOTADICT_LTYPE_BLOCK, dict2))
483 goto err; 483 goto err;
484 484
485 485
486 vals[0] = files->qv_hardlimit; 486 vals[0] = files->qv_hardlimit;
487 vals[1] = files->qv_softlimit; 487 vals[1] = files->qv_softlimit;
488 vals[2] = files->qv_usage; 488 vals[2] = files->qv_usage;
489 vals[3] = files->qv_expiretime; 489 vals[3] = files->qv_expiretime;
490 vals[4] = files->qv_grace; 490 vals[4] = files->qv_grace;
491 dict2 = limits64toprop(vals, val_names, N_QV); 491 dict2 = limits64toprop(vals, val_names, N_QV);
492 if (dict2 == NULL) 492 if (dict2 == NULL)
493 goto err; 493 goto err;
494 if (!prop_dictionary_set_and_rel(dict1, QUOTADICT_LTYPE_FILE, dict2)) 494 if (!prop_dictionary_set_and_rel(dict1, QUOTADICT_LTYPE_FILE, dict2))
495 goto err; 495 goto err;
496 496
497 return dict1; 497 return dict1;
498 498
499err: 499err:
500 prop_object_release(dict1); 500 prop_object_release(dict1);
501 return NULL; 501 return NULL;
502} 502}
503 503
504static int 504static int
505vfs_quotactl_getall(struct mount *mp, 505vfs_quotactl_getall(struct mount *mp,
506 prop_dictionary_t cmddict, int q2type, 506 prop_dictionary_t cmddict, int q2type,
507 prop_array_t datas) 507 prop_array_t datas)
508{ 508{
509 struct quotakcursor cursor; 509 struct quotakcursor cursor;
510 struct quota_getall_result result; 510 struct quota_getall_result result;
511 struct vfs_quotactl_args args; 511 struct vfs_quotactl_args args;
512 prop_array_t replies; 512 prop_array_t replies;
513 prop_dictionary_t dict; 513 prop_dictionary_t dict;
514 unsigned i; 514 unsigned i;
 515 id_t id;
 516 int defaultq;
515 int error, error2; 517 int error, error2;
516 int skip = 0; 518 int skip = 0;
517 519
518 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 520 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
519 521
520 args.qc_type = QCT_CURSOROPEN; 522 args.qc_type = QCT_CURSOROPEN;
521 args.u.cursoropen.qc_cursor = &cursor; 523 args.u.cursoropen.qc_cursor = &cursor;
522 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args); 524 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args);
523 if (error) { 525 if (error) {
524 return error; 526 return error;
525 } 527 }
526 528
527 result.qr_keys = NULL; 529 result.qr_keys = NULL;
528 result.qr_vals = NULL; 530 result.qr_vals = NULL;
529 result.qr_num = 0; 531 result.qr_num = 0;
530 result.qr_max = 0x7fffffff; /* XXX bogus; but temporary */ 532 result.qr_max = 0x7fffffff; /* XXX bogus; but temporary */
531 533
532 args.qc_type = QCT_GETALL; 534 args.qc_type = QCT_GETALL;
533 args.u.getall.qc_cursor = &cursor; 535 args.u.getall.qc_cursor = &cursor;
534 args.u.getall.qc_idtype = q2type; 536 args.u.getall.qc_idtype = q2type;
535 args.u.getall.qc_result = &result; 537 args.u.getall.qc_result = &result;
536 error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args); 538 error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args);
537 /* 539 /*
538 * XXX this is bogus but up until now *all* errors 540 * XXX this is bogus but up until now *all* errors
539 * from inside quotactl_getall were suppressed by the 541 * from inside quotactl_getall were suppressed by the
540 * dispatching code in ufs_quota.c. Fixing that causes 542 * dispatching code in ufs_quota.c. Fixing that causes
541 * repquota to break in an undesirable way; this is a 543 * repquota to break in an undesirable way; this is a
542 * workaround. 544 * workaround.
543 */ 545 */
544 if (error == ENODEV || error == ENXIO) { 546 if (error == ENODEV || error == ENXIO) {
545 skip = 1; 547 skip = 1;
546 error = 0; 548 error = 0;
547 } 549 }
548 if (error) { 550 if (error) {
549 goto err; 551 goto err;
550 } 552 }
551 553
552 replies = prop_array_create(); 554 replies = prop_array_create();
553 if (replies == NULL) { 555 if (replies == NULL) {
554 error = ENOMEM; 556 error = ENOMEM;
555 goto err; 557 goto err;
556 } 558 }
557 559
558 if (skip) { 560 if (skip) {
559 goto skip; 561 goto skip;
560 } 562 }
561 563
562 dict = vfs_quotactl_getall_makereply(0, 1, &result.qr_defblocks, 
563 &result.qr_deffiles); 
564 if (!prop_array_add_and_rel(replies, dict)) { 
565 error = ENOMEM; 
566 goto err; 
567 } 
568 
569 for (i = 0; i < result.qr_num; i += 2) { 564 for (i = 0; i < result.qr_num; i += 2) {
570 dict = vfs_quotactl_getall_makereply(result.qr_keys[i].qk_id,0, 565 id = result.qr_keys[i].qk_id;
 566 if (id == QUOTA_DEFAULTID) {
 567 id = 0;
 568 defaultq = 1;
 569 } else {
 570 defaultq = 0;
 571 }
 572 dict = vfs_quotactl_getall_makereply(id, defaultq,
571 &result.qr_vals[i], 573 &result.qr_vals[i],
572 &result.qr_vals[i+1]); 574 &result.qr_vals[i+1]);
573 if (dict == NULL) { 575 if (dict == NULL) {
574 error = ENOMEM; 576 error = ENOMEM;
575 goto err; 577 goto err;
576 } 578 }
577 if (!prop_array_add_and_rel(replies, dict)) { 579 if (!prop_array_add_and_rel(replies, dict)) {
578 error = ENOMEM; 580 error = ENOMEM;
579 goto err; 581 goto err;
580 } 582 }
581 } 583 }
582 584
583skip: 585skip:
584 586
585 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 587 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
586 error = ENOMEM; 588 error = ENOMEM;
587 goto err; 589 goto err;
588 } 590 }
589 591
590 error = 0; 592 error = 0;
591 err: 593 err:
592 if (result.qr_keys) { 594 if (result.qr_keys) {
593 free(result.qr_keys, M_TEMP); 595 free(result.qr_keys, M_TEMP);
594 } 596 }
595 if (result.qr_vals) { 597 if (result.qr_vals) {
596 free(result.qr_vals, M_TEMP); 598 free(result.qr_vals, M_TEMP);
597 } 599 }
598 600
599 args.qc_type = QCT_CURSORCLOSE; 601 args.qc_type = QCT_CURSORCLOSE;
600 args.u.cursorclose.qc_cursor = &cursor; 602 args.u.cursorclose.qc_cursor = &cursor;
601 error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args); 603 error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args);
602 604
603 if (error) { 605 if (error) {
604 return error; 606 return error;
605 } 607 }
606 error = error2; 608 error = error2;
607 return error; 609 return error;
608} 610}
609 611
610static int 612static int
611vfs_quotactl_clear(struct mount *mp, 613vfs_quotactl_clear(struct mount *mp,
612 prop_dictionary_t cmddict, int q2type, 614 prop_dictionary_t cmddict, int q2type,
613 prop_array_t datas) 615 prop_array_t datas)
614{ 616{
615 prop_array_t replies; 617 prop_array_t replies;
616 prop_object_iterator_t iter; 618 prop_object_iterator_t iter;
617 prop_dictionary_t data; 619 prop_dictionary_t data;
618 uint32_t id; 620 uint32_t id;
619 int defaultq; 621 int defaultq;
620 const char *idstr; 622 const char *idstr;
621 struct quotakey qk; 623 struct quotakey qk;
622 struct vfs_quotactl_args args; 624 struct vfs_quotactl_args args;
623 int error; 625 int error;
624 626
625 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 627 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
626 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 628 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
627 629
628 replies = prop_array_create(); 630 replies = prop_array_create();
629 if (replies == NULL) 631 if (replies == NULL)
630 return ENOMEM; 632 return ENOMEM;
631 633
632 iter = prop_array_iterator(datas); 634 iter = prop_array_iterator(datas);
633 if (iter == NULL) { 635 if (iter == NULL) {
634 prop_object_release(replies); 636 prop_object_release(replies);
635 return ENOMEM; 637 return ENOMEM;
636 } 638 }
637 639
638 while ((data = prop_object_iterator_next(iter)) != NULL) { 640 while ((data = prop_object_iterator_next(iter)) != NULL) {
639 if (!prop_dictionary_get_uint32(data, "id", &id)) { 641 if (!prop_dictionary_get_uint32(data, "id", &id)) {
640 if (!prop_dictionary_get_cstring_nocopy(data, "id", 642 if (!prop_dictionary_get_cstring_nocopy(data, "id",
641 &idstr)) 643 &idstr))
642 continue; 644 continue;
643 if (strcmp(idstr, "default")) 645 if (strcmp(idstr, "default"))
644 continue; 646 continue;
645 id = 0; 647 id = 0;
646 defaultq = 1; 648 defaultq = 1;
647 } else { 649 } else {
648 defaultq = 0; 650 defaultq = 0;
649 } 651 }
650 652
651 qk.qk_idtype = q2type; 653 qk.qk_idtype = q2type;
652 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 654 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
653 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 655 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
654 656
655 args.qc_type = QCT_DELETE; 657 args.qc_type = QCT_DELETE;
656 args.u.delete.qc_key = &qk; 658 args.u.delete.qc_key = &qk;
657 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); 659 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args);
658 if (error) { 660 if (error) {
659 goto err; 661 goto err;
660 } 662 }
661 663
662 qk.qk_idtype = q2type; 664 qk.qk_idtype = q2type;
663 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 665 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
664 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 666 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
665 667
666 args.qc_type = QCT_DELETE; 668 args.qc_type = QCT_DELETE;
667 args.u.delete.qc_key = &qk; 669 args.u.delete.qc_key = &qk;
668 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); 670 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args);
669 if (error) { 671 if (error) {
670 goto err; 672 goto err;
671 } 673 }
672 } 674 }
673 675
674 prop_object_iterator_release(iter); 676 prop_object_iterator_release(iter);
675 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 677 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
676 error = ENOMEM; 678 error = ENOMEM;
677 } else { 679 } else {
678 error = 0; 680 error = 0;
679 } 681 }
680 return error; 682 return error;
681err: 683err:
682 prop_object_iterator_release(iter); 684 prop_object_iterator_release(iter);
683 prop_object_release(replies); 685 prop_object_release(replies);
684 return error; 686 return error;
685} 687}
686 688
687static int 689static int
688vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) 690vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict)
689{ 691{
690 int error; 692 int error;
691 const char *cmd, *type; 693 const char *cmd, *type;
692 prop_array_t datas; 694 prop_array_t datas;
693 int q2type; 695 int q2type;
694 696
695 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) 697 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd))
696 return EINVAL; 698 return EINVAL;
697 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) 699 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type))
698 return EINVAL; 700 return EINVAL;
699 701
700 if (!strcmp(type, QUOTADICT_CLASS_USER)) { 702 if (!strcmp(type, QUOTADICT_CLASS_USER)) {
701 q2type = QUOTA_CLASS_USER; 703 q2type = QUOTA_CLASS_USER;
702 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { 704 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) {
703 q2type = QUOTA_CLASS_GROUP; 705 q2type = QUOTA_CLASS_GROUP;
704 } else { 706 } else {
705 /* XXX this is a bad errno for this case */ 707 /* XXX this is a bad errno for this case */
706 return EOPNOTSUPP; 708 return EOPNOTSUPP;
707 } 709 }
708 710
709 datas = prop_dictionary_get(cmddict, "data"); 711 datas = prop_dictionary_get(cmddict, "data");
710 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) 712 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY)
711 return EINVAL; 713 return EINVAL;
712 714
713 prop_object_retain(datas); 715 prop_object_retain(datas);
714 prop_dictionary_remove(cmddict, "data"); /* prepare for return */ 716 prop_dictionary_remove(cmddict, "data"); /* prepare for return */
715 717
716 if (strcmp(cmd, "get version") == 0) { 718 if (strcmp(cmd, "get version") == 0) {
717 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); 719 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas);
718 } else if (strcmp(cmd, "quotaon") == 0) { 720 } else if (strcmp(cmd, "quotaon") == 0) {
719 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); 721 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas);
720 } else if (strcmp(cmd, "quotaoff") == 0) { 722 } else if (strcmp(cmd, "quotaoff") == 0) {
721 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); 723 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas);
722 } else if (strcmp(cmd, "get") == 0) { 724 } else if (strcmp(cmd, "get") == 0) {
723 error = vfs_quotactl_get(mp, cmddict, q2type, datas); 725 error = vfs_quotactl_get(mp, cmddict, q2type, datas);
724 } else if (strcmp(cmd, "set") == 0) { 726 } else if (strcmp(cmd, "set") == 0) {
725 error = vfs_quotactl_put(mp, cmddict, q2type, datas); 727 error = vfs_quotactl_put(mp, cmddict, q2type, datas);
726 } else if (strcmp(cmd, "getall") == 0) { 728 } else if (strcmp(cmd, "getall") == 0) {
727 error = vfs_quotactl_getall(mp, cmddict, q2type, datas); 729 error = vfs_quotactl_getall(mp, cmddict, q2type, datas);
728 } else if (strcmp(cmd, "clear") == 0) { 730 } else if (strcmp(cmd, "clear") == 0) {
729 error = vfs_quotactl_clear(mp, cmddict, q2type, datas); 731 error = vfs_quotactl_clear(mp, cmddict, q2type, datas);
730 } else { 732 } else {
731 /* XXX this a bad errno for this case */ 733 /* XXX this a bad errno for this case */
732 error = EOPNOTSUPP; 734 error = EOPNOTSUPP;
733 } 735 }
734 736
735 error = (prop_dictionary_set_int8(cmddict, "return", 737 error = (prop_dictionary_set_int8(cmddict, "return",
736 error) ? 0 : ENOMEM); 738 error) ? 0 : ENOMEM);
737 prop_object_release(datas); 739 prop_object_release(datas);
738 740
739 return error; 741 return error;
740} 742}
741 743
742int 744int
743vfs_quotactl(struct mount *mp, prop_dictionary_t dict) 745vfs_quotactl(struct mount *mp, prop_dictionary_t dict)
744{ 746{
745 prop_dictionary_t cmddict; 747 prop_dictionary_t cmddict;
746 prop_array_t commands; 748 prop_array_t commands;
747 prop_object_iterator_t iter; 749 prop_object_iterator_t iter;
748 int error; 750 int error;
749 751
750 error = quota_get_cmds(dict, &commands); 752 error = quota_get_cmds(dict, &commands);
751 if (error) { 753 if (error) {
752 return error; 754 return error;
753 } 755 }
754 756
755 iter = prop_array_iterator(commands); 757 iter = prop_array_iterator(commands);
756 if (iter == NULL) { 758 if (iter == NULL) {
757 return ENOMEM; 759 return ENOMEM;
758 } 760 }
759 761
760 while ((cmddict = prop_object_iterator_next(iter)) != NULL) { 762 while ((cmddict = prop_object_iterator_next(iter)) != NULL) {
761 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { 763 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) {
762 /* XXX shouldn't this be an error? */ 764 /* XXX shouldn't this be an error? */
763 continue; 765 continue;
764 } 766 }
765 error = vfs_quotactl_cmd(mp, cmddict); 767 error = vfs_quotactl_cmd(mp, cmddict);
766 if (error) { 768 if (error) {
767 break; 769 break;
768 } 770 }
769 } 771 }
770 prop_object_iterator_release(iter); 772 prop_object_iterator_release(iter);
771 return error; 773 return error;
772} 774}

cvs diff -r1.22 -r1.23 src/sys/sys/quotactl.h (switch to unified diff)

--- src/sys/sys/quotactl.h 2012/01/29 07:05:12 1.22
+++ src/sys/sys/quotactl.h 2012/01/29 07:06:01 1.23
@@ -1,121 +1,119 @@ @@ -1,121 +1,119 @@
1/* $NetBSD: quotactl.h,v 1.22 2012/01/29 07:05:12 dholland Exp $ */ 1/* $NetBSD: quotactl.h,v 1.23 2012/01/29 07:06:01 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#include <sys/quota.h> 40#include <sys/quota.h>
41 41
42/* 42/*
43 * Semi-opaque structure for cursors. This holds the cursor state in 43 * Semi-opaque structure for cursors. This holds the cursor state in
44 * userland; the size is exposed only to libquota, not to client code, 44 * userland; the size is exposed only to libquota, not to client code,
45 * and is meant to be large enough to accomodate all likely future 45 * and is meant to be large enough to accomodate all likely future
46 * expansion without being unduly bloated, as it will need to be 46 * expansion without being unduly bloated, as it will need to be
47 * copied in and out for every call using it. 47 * copied in and out for every call using it.
48 */ 48 */
49struct quotakcursor { 49struct quotakcursor {
50 union { 50 union {
51 char qkc_space[64]; 51 char qkc_space[64];
52 uintmax_t __qkc_forcealign; 52 uintmax_t __qkc_forcealign;
53 } u; 53 } u;
54}; 54};
55 55
56/* Command codes. */ 56/* Command codes. */
57#define QUOTACTL_GETVERSION 0 57#define QUOTACTL_GETVERSION 0
58#define QUOTACTL_QUOTAON 1 58#define QUOTACTL_QUOTAON 1
59#define QUOTACTL_QUOTAOFF 2 59#define QUOTACTL_QUOTAOFF 2
60#define QUOTACTL_GET 3 60#define QUOTACTL_GET 3
61#define QUOTACTL_PUT 4 61#define QUOTACTL_PUT 4
62#define QUOTACTL_GETALL 5 62#define QUOTACTL_GETALL 5
63#define QUOTACTL_DELETE 6 63#define QUOTACTL_DELETE 6
64#define QUOTACTL_CURSOROPEN 7 64#define QUOTACTL_CURSOROPEN 7
65#define QUOTACTL_CURSORCLOSE 8 65#define QUOTACTL_CURSORCLOSE 8
66 66
67/* Argument encoding. */ 67/* Argument encoding. */
68enum vfs_quotactl_argtypes { 68enum vfs_quotactl_argtypes {
69 QCT_PROPLIB, /* quotaon/off */ 69 QCT_PROPLIB, /* quotaon/off */
70 QCT_GETVERSION, /* getversion */ 70 QCT_GETVERSION, /* getversion */
71 QCT_GET, /* get */ 71 QCT_GET, /* get */
72 QCT_PUT, /* put */ 72 QCT_PUT, /* put */
73 QCT_DELETE, /* delete */ 73 QCT_DELETE, /* delete */
74 QCT_CURSOROPEN, /* open cursor */ 74 QCT_CURSOROPEN, /* open cursor */
75 QCT_CURSORCLOSE,/* close cursor */ 75 QCT_CURSORCLOSE,/* close cursor */
76 QCT_GETALL, /* get all */ 76 QCT_GETALL, /* get all */
77}; 77};
78struct vfs_quotactl_args { 78struct vfs_quotactl_args {
79 enum vfs_quotactl_argtypes qc_type; 79 enum vfs_quotactl_argtypes qc_type;
80 union { 80 union {
81 struct { 81 struct {
82 prop_dictionary_t qc_cmddict; 82 prop_dictionary_t qc_cmddict;
83 int qc_q2type; 83 int qc_q2type;
84 prop_array_t qc_datas; 84 prop_array_t qc_datas;
85 } proplib; 85 } proplib;
86 struct { 86 struct {
87 int *qc_version_ret; 87 int *qc_version_ret;
88 } getversion; 88 } getversion;
89 struct { 89 struct {
90 const struct quotakey *qc_key; 90 const struct quotakey *qc_key;
91 struct quotaval *qc_ret; 91 struct quotaval *qc_ret;
92 } get; 92 } get;
93 struct { 93 struct {
94 const struct quotakey *qc_key; 94 const struct quotakey *qc_key;
95 const struct quotaval *qc_val; 95 const struct quotaval *qc_val;
96 } put; 96 } put;
97 struct { 97 struct {
98 const struct quotakey *qc_key; 98 const struct quotakey *qc_key;
99 } delete; 99 } delete;
100 struct { 100 struct {
101 struct quotakcursor *qc_cursor; 101 struct quotakcursor *qc_cursor;
102 } cursoropen; 102 } cursoropen;
103 struct { 103 struct {
104 struct quotakcursor *qc_cursor; 104 struct quotakcursor *qc_cursor;
105 } cursorclose; 105 } cursorclose;
106 struct { 106 struct {
107 struct quotakcursor *qc_cursor; 107 struct quotakcursor *qc_cursor;
108 int qc_idtype; 108 int qc_idtype;
109 struct quota_getall_result { 109 struct quota_getall_result {
110 struct quotaval qr_defblocks; 
111 struct quotaval qr_deffiles; 
112 struct quotakey *qr_keys; 110 struct quotakey *qr_keys;
113 struct quotaval *qr_vals; 111 struct quotaval *qr_vals;
114 unsigned qr_num; 112 unsigned qr_num;
115 unsigned qr_max; 113 unsigned qr_max;
116 } *qc_result; 114 } *qc_result;
117 } getall; 115 } getall;
118 } u; 116 } u;
119}; 117};
120 118
121#endif /* _SYS_QUOTACTL_H_ */ 119#endif /* _SYS_QUOTACTL_H_ */

cvs diff -r1.21 -r1.22 src/sys/ufs/ufs/ufs_quota2.c (switch to unified diff)

--- src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:05:12 1.21
+++ src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:06:02 1.22
@@ -1,1280 +1,1319 @@ @@ -1,1280 +1,1319 @@
1/* $NetBSD: ufs_quota2.c,v 1.21 2012/01/29 07:05:12 dholland Exp $ */ 1/* $NetBSD: ufs_quota2.c,v 1.22 2012/01/29 07:06:02 dholland Exp $ */
2/*- 2/*-
3 * Copyright (c) 2010 Manuel Bouyer 3 * Copyright (c) 2010 Manuel Bouyer
4 * All rights reserved. 4 * All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE. 25 * POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.21 2012/01/29 07:05:12 dholland Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.22 2012/01/29 07:06:02 dholland Exp $");
30 30
31#include <sys/buf.h> 31#include <sys/buf.h>
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/kernel.h> 33#include <sys/kernel.h>
34#include <sys/systm.h> 34#include <sys/systm.h>
35#include <sys/malloc.h> 35#include <sys/malloc.h>
36#include <sys/namei.h> 36#include <sys/namei.h>
37#include <sys/file.h> 37#include <sys/file.h>
38#include <sys/proc.h> 38#include <sys/proc.h>
39#include <sys/vnode.h> 39#include <sys/vnode.h>
40#include <sys/mount.h> 40#include <sys/mount.h>
41#include <sys/fstrans.h> 41#include <sys/fstrans.h>
42#include <sys/kauth.h> 42#include <sys/kauth.h>
43#include <sys/wapbl.h> 43#include <sys/wapbl.h>
44#include <sys/quota.h> 44#include <sys/quota.h>
45#include <sys/quotactl.h> 45#include <sys/quotactl.h>
46 46
47#include <ufs/ufs/quota2.h> 47#include <ufs/ufs/quota2.h>
48#include <ufs/ufs/inode.h> 48#include <ufs/ufs/inode.h>
49#include <ufs/ufs/ufsmount.h> 49#include <ufs/ufs/ufsmount.h>
50#include <ufs/ufs/ufs_bswap.h> 50#include <ufs/ufs/ufs_bswap.h>
51#include <ufs/ufs/ufs_extern.h> 51#include <ufs/ufs/ufs_extern.h>
52#include <ufs/ufs/ufs_quota.h> 52#include <ufs/ufs/ufs_quota.h>
53#include <ufs/ufs/ufs_wapbl.h> 53#include <ufs/ufs/ufs_wapbl.h>
54#include <quota/quotaprop.h> 54#include <quota/quotaprop.h>
55 55
56/* 56/*
57 * LOCKING: 57 * LOCKING:
58 * Data in the entries are protected by the associated struct dquot's 58 * Data in the entries are protected by the associated struct dquot's
59 * dq_interlock (this means we can't read or change a quota entry without 59 * dq_interlock (this means we can't read or change a quota entry without
60 * grabing a dquot for it). 60 * grabing a dquot for it).
61 * The header and lists (including pointers in the data entries, and q2e_uid) 61 * The header and lists (including pointers in the data entries, and q2e_uid)
62 * are protected by the global dqlock. 62 * are protected by the global dqlock.
63 * the locking order is dq_interlock -> dqlock 63 * the locking order is dq_interlock -> dqlock
64 */ 64 */
65 65
66static int quota2_bwrite(struct mount *, struct buf *); 66static int quota2_bwrite(struct mount *, struct buf *);
67static int getinoquota2(struct inode *, bool, bool, struct buf **, 67static int getinoquota2(struct inode *, bool, bool, struct buf **,
68 struct quota2_entry **); 68 struct quota2_entry **);
69static int getq2h(struct ufsmount *, int, struct buf **, 69static int getq2h(struct ufsmount *, int, struct buf **,
70 struct quota2_header **, int); 70 struct quota2_header **, int);
71static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **, 71static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **,
72 struct quota2_entry **, int); 72 struct quota2_entry **, int);
73static int quota2_walk_list(struct ufsmount *, struct buf *, int, 73static int quota2_walk_list(struct ufsmount *, struct buf *, int,
74 uint64_t *, int, void *, 74 uint64_t *, int, void *,
75 int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, 75 int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *,
76 uint64_t, void *)); 76 uint64_t, void *));
77 77
78#if 0 78#if 0
79static prop_dictionary_t q2etoprop(struct quota2_entry *, int); 79static prop_dictionary_t q2etoprop(struct quota2_entry *, int);
80#endif 80#endif
81 81
82static const char *limnames[] = INITQLNAMES; 82static const char *limnames[] = INITQLNAMES;
83 83
84static void 84static void
85quota2_dict_update_q2e_limits(int objtype, const struct quotaval *val, 85quota2_dict_update_q2e_limits(int objtype, const struct quotaval *val,
86 struct quota2_entry *q2e) 86 struct quota2_entry *q2e)
87{ 87{
88 /* make sure we can index q2e_val[] by the fs-independent objtype */ 88 /* make sure we can index q2e_val[] by the fs-independent objtype */
89 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK); 89 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK);
90 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE); 90 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE);
91 91
92 q2e->q2e_val[objtype].q2v_hardlimit = val->qv_hardlimit; 92 q2e->q2e_val[objtype].q2v_hardlimit = val->qv_hardlimit;
93 q2e->q2e_val[objtype].q2v_softlimit = val->qv_softlimit; 93 q2e->q2e_val[objtype].q2v_softlimit = val->qv_softlimit;
94 q2e->q2e_val[objtype].q2v_grace = val->qv_grace; 94 q2e->q2e_val[objtype].q2v_grace = val->qv_grace;
95} 95}
96 96
97#if 0 97#if 0
98static prop_dictionary_t 98static prop_dictionary_t
99q2etoprop(struct quota2_entry *q2e, int def) 99q2etoprop(struct quota2_entry *q2e, int def)
100{ 100{
101 const char *val_names[] = INITQVNAMES_ALL; 101 const char *val_names[] = INITQVNAMES_ALL;
102 prop_dictionary_t dict1 = prop_dictionary_create(); 102 prop_dictionary_t dict1 = prop_dictionary_create();
103 prop_dictionary_t dict2; 103 prop_dictionary_t dict2;
104 int i; 104 int i;
105 105
106 if (dict1 == NULL) 106 if (dict1 == NULL)
107 return NULL; 107 return NULL;
108 108
109 if (def) { 109 if (def) {
110 if (!prop_dictionary_set_cstring_nocopy(dict1, "id", 110 if (!prop_dictionary_set_cstring_nocopy(dict1, "id",
111 "default")) { 111 "default")) {
112 goto err; 112 goto err;
113 } 113 }
114 } else { 114 } else {
115 if (!prop_dictionary_set_uint32(dict1, "id", q2e->q2e_uid)) { 115 if (!prop_dictionary_set_uint32(dict1, "id", q2e->q2e_uid)) {
116 goto err; 116 goto err;
117 } 117 }
118 } 118 }
119 for (i = 0; i < N_QL; i++) { 119 for (i = 0; i < N_QL; i++) {
120 dict2 = limits64toprop(&q2e->q2e_val[i].q2v_hardlimit, 120 dict2 = limits64toprop(&q2e->q2e_val[i].q2v_hardlimit,
121 val_names, N_QV); 121 val_names, N_QV);
122 if (dict2 == NULL) 122 if (dict2 == NULL)
123 goto err; 123 goto err;
124 if (!prop_dictionary_set_and_rel(dict1, limnames[i], dict2)) 124 if (!prop_dictionary_set_and_rel(dict1, limnames[i], dict2))
125 goto err; 125 goto err;
126 } 126 }
127 return dict1; 127 return dict1;
128 128
129err: 129err:
130 prop_object_release(dict1); 130 prop_object_release(dict1);
131 return NULL; 131 return NULL;
132} 132}
133#endif 133#endif
134 134
135/* 135/*
136 * Convert internal representation to FS-independent representation. 136 * Convert internal representation to FS-independent representation.
137 * (Note that while the two types are currently identical, the 137 * (Note that while the two types are currently identical, the
138 * internal representation is an on-disk struct and the FS-independent 138 * internal representation is an on-disk struct and the FS-independent
139 * representation is not, and they might diverge in the future.) 139 * representation is not, and they might diverge in the future.)
140 */ 140 */
141static void 141static void
142q2val_to_quotaval(struct quota2_val *q2v, struct quotaval *qv) 142q2val_to_quotaval(struct quota2_val *q2v, struct quotaval *qv)
143{ 143{
144 qv->qv_softlimit = q2v->q2v_softlimit; 144 qv->qv_softlimit = q2v->q2v_softlimit;
145 qv->qv_hardlimit = q2v->q2v_hardlimit; 145 qv->qv_hardlimit = q2v->q2v_hardlimit;
146 qv->qv_usage = q2v->q2v_cur; 146 qv->qv_usage = q2v->q2v_cur;
147 qv->qv_expiretime = q2v->q2v_time; 147 qv->qv_expiretime = q2v->q2v_time;
148 qv->qv_grace = q2v->q2v_grace; 148 qv->qv_grace = q2v->q2v_grace;
149} 149}
150 150
151/* 151/*
152 * Convert a quota2entry and default-flag to the FS-independent 152 * Convert a quota2entry and default-flag to the FS-independent
153 * representation. 153 * representation.
154 */ 154 */
155static void 155static void
156q2e_to_quotaval(struct quota2_entry *q2e, int def, 156q2e_to_quotaval(struct quota2_entry *q2e, int def,
157 id_t *id, int objtype, struct quotaval *ret) 157 id_t *id, int objtype, struct quotaval *ret)
158{ 158{
159 if (def) { 159 if (def) {
160 *id = QUOTA_DEFAULTID; 160 *id = QUOTA_DEFAULTID;
161 } else { 161 } else {
162 *id = q2e->q2e_uid; 162 *id = q2e->q2e_uid;
163 } 163 }
164 164
165 KASSERT(objtype >= 0 && objtype < N_QL); 165 KASSERT(objtype >= 0 && objtype < N_QL);
166 q2val_to_quotaval(&q2e->q2e_val[objtype], ret); 166 q2val_to_quotaval(&q2e->q2e_val[objtype], ret);
167} 167}
168 168
169 169
170static int 170static int
171quota2_bwrite(struct mount *mp, struct buf *bp) 171quota2_bwrite(struct mount *mp, struct buf *bp)
172{ 172{
173 if (mp->mnt_flag & MNT_SYNCHRONOUS) 173 if (mp->mnt_flag & MNT_SYNCHRONOUS)
174 return bwrite(bp); 174 return bwrite(bp);
175 else { 175 else {
176 bdwrite(bp); 176 bdwrite(bp);
177 return 0; 177 return 0;
178 } 178 }
179} 179}
180 180
181static int 181static int
182getq2h(struct ufsmount *ump, int type, 182getq2h(struct ufsmount *ump, int type,
183 struct buf **bpp, struct quota2_header **q2hp, int flags) 183 struct buf **bpp, struct quota2_header **q2hp, int flags)
184{ 184{
185#ifdef FFS_EI 185#ifdef FFS_EI
186 const int needswap = UFS_MPNEEDSWAP(ump); 186 const int needswap = UFS_MPNEEDSWAP(ump);
187#endif 187#endif
188 int error; 188 int error;
189 struct buf *bp; 189 struct buf *bp;
190 struct quota2_header *q2h; 190 struct quota2_header *q2h;
191 191
192 KASSERT(mutex_owned(&dqlock)); 192 KASSERT(mutex_owned(&dqlock));
193 error = bread(ump->um_quotas[type], 0, ump->umq2_bsize, 193 error = bread(ump->um_quotas[type], 0, ump->umq2_bsize,
194 ump->um_cred[type], flags, &bp); 194 ump->um_cred[type], flags, &bp);
195 if (error) 195 if (error)
196 return error; 196 return error;
197 if (bp->b_resid != 0)  197 if (bp->b_resid != 0)
198 panic("dq2get: %s quota file truncated", quotatypes[type]); 198 panic("dq2get: %s quota file truncated", quotatypes[type]);
199 199
200 q2h = (void *)bp->b_data; 200 q2h = (void *)bp->b_data;
201 if (ufs_rw32(q2h->q2h_magic_number, needswap) != Q2_HEAD_MAGIC || 201 if (ufs_rw32(q2h->q2h_magic_number, needswap) != Q2_HEAD_MAGIC ||
202 q2h->q2h_type != type) 202 q2h->q2h_type != type)
203 panic("dq2get: corrupted %s quota header", quotatypes[type]); 203 panic("dq2get: corrupted %s quota header", quotatypes[type]);
204 *bpp = bp; 204 *bpp = bp;
205 *q2hp = q2h; 205 *q2hp = q2h;
206 return 0; 206 return 0;
207} 207}
208 208
209static int 209static int
210getq2e(struct ufsmount *ump, int type, daddr_t lblkno, int blkoffset, 210getq2e(struct ufsmount *ump, int type, daddr_t lblkno, int blkoffset,
211 struct buf **bpp, struct quota2_entry **q2ep, int flags) 211 struct buf **bpp, struct quota2_entry **q2ep, int flags)
212{ 212{
213 int error; 213 int error;
214 struct buf *bp; 214 struct buf *bp;
215 215
216 if (blkoffset & (sizeof(uint64_t) - 1)) { 216 if (blkoffset & (sizeof(uint64_t) - 1)) {
217 panic("dq2get: %s quota file corrupted", 217 panic("dq2get: %s quota file corrupted",
218 quotatypes[type]); 218 quotatypes[type]);
219 } 219 }
220 error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize, 220 error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize,
221 ump->um_cred[type], flags, &bp); 221 ump->um_cred[type], flags, &bp);
222 if (error) 222 if (error)
223 return error; 223 return error;
224 if (bp->b_resid != 0) { 224 if (bp->b_resid != 0) {
225 panic("dq2get: %s quota file corrupted", 225 panic("dq2get: %s quota file corrupted",
226 quotatypes[type]); 226 quotatypes[type]);
227 } 227 }
228 *q2ep = (void *)((char *)bp->b_data + blkoffset); 228 *q2ep = (void *)((char *)bp->b_data + blkoffset);
229 *bpp = bp; 229 *bpp = bp;
230 return 0; 230 return 0;
231} 231}
232 232
233/* walk a quota entry list, calling the callback for each entry */ 233/* walk a quota entry list, calling the callback for each entry */
234#define Q2WL_ABORT 0x10000000 234#define Q2WL_ABORT 0x10000000
235 235
236static int 236static int
237quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type, 237quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type,
238 uint64_t *offp, int flags, void *a, 238 uint64_t *offp, int flags, void *a,
239 int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *)) 239 int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *))
240{ 240{
241#ifdef FFS_EI 241#ifdef FFS_EI
242 const int needswap = UFS_MPNEEDSWAP(ump); 242 const int needswap = UFS_MPNEEDSWAP(ump);
243#endif 243#endif
244 daddr_t off = ufs_rw64(*offp, needswap); 244 daddr_t off = ufs_rw64(*offp, needswap);
245 struct buf *bp, *obp = hbp; 245 struct buf *bp, *obp = hbp;
246 int ret = 0, ret2 = 0; 246 int ret = 0, ret2 = 0;
247 struct quota2_entry *q2e; 247 struct quota2_entry *q2e;
248 daddr_t lblkno, blkoff, olblkno = 0; 248 daddr_t lblkno, blkoff, olblkno = 0;
249 249
250 KASSERT(mutex_owner(&dqlock)); 250 KASSERT(mutex_owner(&dqlock));
251 251
252 while (off != 0) { 252 while (off != 0) {
253 lblkno = (off >> ump->um_mountp->mnt_fs_bshift); 253 lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
254 blkoff = (off & ump->umq2_bmask); 254 blkoff = (off & ump->umq2_bmask);
255 if (lblkno == 0) { 255 if (lblkno == 0) {
256 /* in the header block */ 256 /* in the header block */
257 bp = hbp; 257 bp = hbp;
258 } else if (lblkno == olblkno) { 258 } else if (lblkno == olblkno) {
259 /* still in the same buf */ 259 /* still in the same buf */
260 bp = obp; 260 bp = obp;
261 } else { 261 } else {
262 ret = bread(ump->um_quotas[type], lblkno,  262 ret = bread(ump->um_quotas[type], lblkno,
263 ump->umq2_bsize, 263 ump->umq2_bsize,
264 ump->um_cred[type], flags, &bp); 264 ump->um_cred[type], flags, &bp);
265 if (ret) 265 if (ret)
266 return ret; 266 return ret;
267 if (bp->b_resid != 0) { 267 if (bp->b_resid != 0) {
268 panic("quota2_walk_list: %s quota file corrupted", 268 panic("quota2_walk_list: %s quota file corrupted",
269 quotatypes[type]); 269 quotatypes[type]);
270 } 270 }
271 } 271 }
272 q2e = (void *)((char *)(bp->b_data) + blkoff); 272 q2e = (void *)((char *)(bp->b_data) + blkoff);
273 ret = (*func)(ump, offp, q2e, off, a); 273 ret = (*func)(ump, offp, q2e, off, a);
274 if (off != ufs_rw64(*offp, needswap)) { 274 if (off != ufs_rw64(*offp, needswap)) {
275 /* callback changed parent's pointer, redo */ 275 /* callback changed parent's pointer, redo */
276 off = ufs_rw64(*offp, needswap); 276 off = ufs_rw64(*offp, needswap);
277 if (bp != hbp && bp != obp) 277 if (bp != hbp && bp != obp)
278 ret2 = bwrite(bp); 278 ret2 = bwrite(bp);
279 } else { 279 } else {
280 /* parent if now current */ 280 /* parent if now current */
281 if (obp != bp && obp != hbp) { 281 if (obp != bp && obp != hbp) {
282 if (flags & B_MODIFY) 282 if (flags & B_MODIFY)
283 ret2 = bwrite(obp); 283 ret2 = bwrite(obp);
284 else 284 else
285 brelse(obp, 0); 285 brelse(obp, 0);
286 } 286 }
287 obp = bp; 287 obp = bp;
288 olblkno = lblkno; 288 olblkno = lblkno;
289 offp = &(q2e->q2e_next); 289 offp = &(q2e->q2e_next);
290 off = ufs_rw64(*offp, needswap); 290 off = ufs_rw64(*offp, needswap);
291 } 291 }
292 if (ret) 292 if (ret)
293 break; 293 break;
294 if (ret2) { 294 if (ret2) {
295 ret = ret2; 295 ret = ret2;
296 break; 296 break;
297 } 297 }
298 } 298 }
299 if (obp != hbp) { 299 if (obp != hbp) {
300 if (flags & B_MODIFY) 300 if (flags & B_MODIFY)
301 ret2 = bwrite(obp); 301 ret2 = bwrite(obp);
302 else 302 else
303 brelse(obp, 0); 303 brelse(obp, 0);
304 } 304 }
305 if (ret & Q2WL_ABORT) 305 if (ret & Q2WL_ABORT)
306 return 0; 306 return 0;
307 if (ret == 0) 307 if (ret == 0)
308 return ret2; 308 return ret2;
309 return ret; 309 return ret;
310} 310}
311 311
312int 312int
313quota2_umount(struct mount *mp, int flags) 313quota2_umount(struct mount *mp, int flags)
314{ 314{
315 int i, error; 315 int i, error;
316 struct ufsmount *ump = VFSTOUFS(mp); 316 struct ufsmount *ump = VFSTOUFS(mp);
317 317
318 if ((ump->um_flags & UFS_QUOTA2) == 0) 318 if ((ump->um_flags & UFS_QUOTA2) == 0)
319 return 0; 319 return 0;
320 320
321 for (i = 0; i < MAXQUOTAS; i++) { 321 for (i = 0; i < MAXQUOTAS; i++) {
322 if (ump->um_quotas[i] != NULLVP) { 322 if (ump->um_quotas[i] != NULLVP) {
323 error = vn_close(ump->um_quotas[i], FREAD|FWRITE, 323 error = vn_close(ump->um_quotas[i], FREAD|FWRITE,
324 ump->um_cred[i]); 324 ump->um_cred[i]);
325 if (error) { 325 if (error) {
326 printf("quota2_umount failed: close(%p) %d\n", 326 printf("quota2_umount failed: close(%p) %d\n",
327 ump->um_quotas[i], error); 327 ump->um_quotas[i], error);
328 return error; 328 return error;
329 } 329 }
330 } 330 }
331 ump->um_quotas[i] = NULLVP; 331 ump->um_quotas[i] = NULLVP;
332 } 332 }
333 return 0; 333 return 0;
334} 334}
335 335
336static int  336static int
337quota2_q2ealloc(struct ufsmount *ump, int type, uid_t uid, struct dquot *dq, 337quota2_q2ealloc(struct ufsmount *ump, int type, uid_t uid, struct dquot *dq,
338 struct buf **bpp, struct quota2_entry **q2ep) 338 struct buf **bpp, struct quota2_entry **q2ep)
339{ 339{
340 int error, error2; 340 int error, error2;
341 struct buf *hbp, *bp; 341 struct buf *hbp, *bp;
342 struct quota2_header *q2h; 342 struct quota2_header *q2h;
343 struct quota2_entry *q2e; 343 struct quota2_entry *q2e;
344 daddr_t offset; 344 daddr_t offset;
345 u_long hash_mask; 345 u_long hash_mask;
346 const int needswap = UFS_MPNEEDSWAP(ump); 346 const int needswap = UFS_MPNEEDSWAP(ump);
347 347
348 KASSERT(mutex_owned(&dq->dq_interlock)); 348 KASSERT(mutex_owned(&dq->dq_interlock));
349 KASSERT(mutex_owned(&dqlock)); 349 KASSERT(mutex_owned(&dqlock));
350 error = getq2h(ump, type, &hbp, &q2h, B_MODIFY); 350 error = getq2h(ump, type, &hbp, &q2h, B_MODIFY);
351 if (error) 351 if (error)
352 return error; 352 return error;
353 offset = ufs_rw64(q2h->q2h_free, needswap); 353 offset = ufs_rw64(q2h->q2h_free, needswap);
354 if (offset == 0) { 354 if (offset == 0) {
355 struct vnode *vp = ump->um_quotas[type]; 355 struct vnode *vp = ump->um_quotas[type];
356 struct inode *ip = VTOI(vp); 356 struct inode *ip = VTOI(vp);
357 uint64_t size = ip->i_size; 357 uint64_t size = ip->i_size;
358 /* need to alocate a new disk block */ 358 /* need to alocate a new disk block */
359 error = UFS_BALLOC(vp, size, ump->umq2_bsize, 359 error = UFS_BALLOC(vp, size, ump->umq2_bsize,
360 ump->um_cred[type], B_CLRBUF | B_SYNC, &bp); 360 ump->um_cred[type], B_CLRBUF | B_SYNC, &bp);
361 if (error) { 361 if (error) {
362 brelse(hbp, 0); 362 brelse(hbp, 0);
363 return error; 363 return error;
364 } 364 }
365 KASSERT((ip->i_size % ump->umq2_bsize) == 0); 365 KASSERT((ip->i_size % ump->umq2_bsize) == 0);
366 ip->i_size += ump->umq2_bsize; 366 ip->i_size += ump->umq2_bsize;
367 DIP_ASSIGN(ip, size, ip->i_size); 367 DIP_ASSIGN(ip, size, ip->i_size);
368 ip->i_flag |= IN_CHANGE | IN_UPDATE; 368 ip->i_flag |= IN_CHANGE | IN_UPDATE;
369 uvm_vnp_setsize(vp, ip->i_size); 369 uvm_vnp_setsize(vp, ip->i_size);
370 quota2_addfreeq2e(q2h, bp->b_data, size, ump->umq2_bsize, 370 quota2_addfreeq2e(q2h, bp->b_data, size, ump->umq2_bsize,
371 needswap); 371 needswap);
372 error = bwrite(bp); 372 error = bwrite(bp);
373 error2 = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT); 373 error2 = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
374 if (error || error2) { 374 if (error || error2) {
375 brelse(hbp, 0); 375 brelse(hbp, 0);
376 if (error) 376 if (error)
377 return error; 377 return error;
378 return error2; 378 return error2;
379 } 379 }
380 offset = ufs_rw64(q2h->q2h_free, needswap); 380 offset = ufs_rw64(q2h->q2h_free, needswap);
381 KASSERT(offset != 0); 381 KASSERT(offset != 0);
382 } 382 }
383 dq->dq2_lblkno = (offset >> ump->um_mountp->mnt_fs_bshift); 383 dq->dq2_lblkno = (offset >> ump->um_mountp->mnt_fs_bshift);
384 dq->dq2_blkoff = (offset & ump->umq2_bmask); 384 dq->dq2_blkoff = (offset & ump->umq2_bmask);
385 if (dq->dq2_lblkno == 0) { 385 if (dq->dq2_lblkno == 0) {
386 bp = hbp; 386 bp = hbp;
387 q2e = (void *)((char *)bp->b_data + dq->dq2_blkoff); 387 q2e = (void *)((char *)bp->b_data + dq->dq2_blkoff);
388 } else { 388 } else {
389 error = getq2e(ump, type, dq->dq2_lblkno, 389 error = getq2e(ump, type, dq->dq2_lblkno,
390 dq->dq2_blkoff, &bp, &q2e, B_MODIFY); 390 dq->dq2_blkoff, &bp, &q2e, B_MODIFY);
391 if (error) { 391 if (error) {
392 brelse(hbp, 0); 392 brelse(hbp, 0);
393 return error; 393 return error;
394 } 394 }
395 } 395 }
396 hash_mask = ((1 << q2h->q2h_hash_shift) - 1); 396 hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
397 /* remove from free list */ 397 /* remove from free list */
398 q2h->q2h_free = q2e->q2e_next; 398 q2h->q2h_free = q2e->q2e_next;
399 399
400 memcpy(q2e, &q2h->q2h_defentry, sizeof(*q2e)); 400 memcpy(q2e, &q2h->q2h_defentry, sizeof(*q2e));
401 q2e->q2e_uid = ufs_rw32(uid, needswap); 401 q2e->q2e_uid = ufs_rw32(uid, needswap);
402 /* insert in hash list */  402 /* insert in hash list */
403 q2e->q2e_next = q2h->q2h_entries[uid & hash_mask]; 403 q2e->q2e_next = q2h->q2h_entries[uid & hash_mask];
404 q2h->q2h_entries[uid & hash_mask] = ufs_rw64(offset, needswap); 404 q2h->q2h_entries[uid & hash_mask] = ufs_rw64(offset, needswap);
405 if (hbp != bp) { 405 if (hbp != bp) {
406 bwrite(hbp); 406 bwrite(hbp);
407 } 407 }
408 *q2ep = q2e; 408 *q2ep = q2e;
409 *bpp = bp; 409 *bpp = bp;
410 return 0; 410 return 0;
411} 411}
412 412
413static int 413static int
414getinoquota2(struct inode *ip, bool alloc, bool modify, struct buf **bpp, 414getinoquota2(struct inode *ip, bool alloc, bool modify, struct buf **bpp,
415 struct quota2_entry **q2ep) 415 struct quota2_entry **q2ep)
416{ 416{
417 int error; 417 int error;
418 int i; 418 int i;
419 struct dquot *dq; 419 struct dquot *dq;
420 struct ufsmount *ump = ip->i_ump; 420 struct ufsmount *ump = ip->i_ump;
421 u_int32_t ino_ids[MAXQUOTAS]; 421 u_int32_t ino_ids[MAXQUOTAS];
422 422
423 error = getinoquota(ip); 423 error = getinoquota(ip);
424 if (error) 424 if (error)
425 return error; 425 return error;
426 426
427 if (alloc) { 427 if (alloc) {
428 UFS_WAPBL_JLOCK_ASSERT(ump->um_mountp); 428 UFS_WAPBL_JLOCK_ASSERT(ump->um_mountp);
429 } 429 }
430 ino_ids[USRQUOTA] = ip->i_uid; 430 ino_ids[USRQUOTA] = ip->i_uid;
431 ino_ids[GRPQUOTA] = ip->i_gid; 431 ino_ids[GRPQUOTA] = ip->i_gid;
432 /* first get the interlock for all dquot */ 432 /* first get the interlock for all dquot */
433 for (i = 0; i < MAXQUOTAS; i++) { 433 for (i = 0; i < MAXQUOTAS; i++) {
434 dq = ip->i_dquot[i]; 434 dq = ip->i_dquot[i];
435 if (dq == NODQUOT) 435 if (dq == NODQUOT)
436 continue; 436 continue;
437 mutex_enter(&dq->dq_interlock); 437 mutex_enter(&dq->dq_interlock);
438 } 438 }
439 /* now get the corresponding quota entry */ 439 /* now get the corresponding quota entry */
440 for (i = 0; i < MAXQUOTAS; i++) { 440 for (i = 0; i < MAXQUOTAS; i++) {
441 bpp[i] = NULL; 441 bpp[i] = NULL;
442 q2ep[i] = NULL; 442 q2ep[i] = NULL;
443 dq = ip->i_dquot[i]; 443 dq = ip->i_dquot[i];
444 if (dq == NODQUOT) 444 if (dq == NODQUOT)
445 continue; 445 continue;
446 if (__predict_false(ump->um_quotas[i] == NULL)) { 446 if (__predict_false(ump->um_quotas[i] == NULL)) {
447 /* 447 /*
448 * quotas have been turned off. This can happen 448 * quotas have been turned off. This can happen
449 * at umount time. 449 * at umount time.
450 */ 450 */
451 mutex_exit(&dq->dq_interlock); 451 mutex_exit(&dq->dq_interlock);
452 dqrele(NULLVP, dq); 452 dqrele(NULLVP, dq);
453 ip->i_dquot[i] = NULL; 453 ip->i_dquot[i] = NULL;
454 continue; 454 continue;
455 } 455 }
456 456
457 if ((dq->dq2_lblkno | dq->dq2_blkoff) == 0) { 457 if ((dq->dq2_lblkno | dq->dq2_blkoff) == 0) {
458 if (!alloc) { 458 if (!alloc) {
459 continue; 459 continue;
460 } 460 }
461 /* need to alloc a new on-disk quot */ 461 /* need to alloc a new on-disk quot */
462 mutex_enter(&dqlock); 462 mutex_enter(&dqlock);
463 error = quota2_q2ealloc(ump, i, ino_ids[i], dq, 463 error = quota2_q2ealloc(ump, i, ino_ids[i], dq,
464 &bpp[i], &q2ep[i]); 464 &bpp[i], &q2ep[i]);
465 mutex_exit(&dqlock); 465 mutex_exit(&dqlock);
466 if (error) 466 if (error)
467 return error; 467 return error;
468 } else { 468 } else {
469 error = getq2e(ump, i, dq->dq2_lblkno, 469 error = getq2e(ump, i, dq->dq2_lblkno,
470 dq->dq2_blkoff, &bpp[i], &q2ep[i], 470 dq->dq2_blkoff, &bpp[i], &q2ep[i],
471 modify ? B_MODIFY : 0); 471 modify ? B_MODIFY : 0);
472 if (error) 472 if (error)
473 return error; 473 return error;
474 } 474 }
475 } 475 }
476 return 0; 476 return 0;
477} 477}
478 478
479static int 479static int
480quota2_check(struct inode *ip, int vtype, int64_t change, kauth_cred_t cred, 480quota2_check(struct inode *ip, int vtype, int64_t change, kauth_cred_t cred,
481 int flags) 481 int flags)
482{ 482{
483 int error; 483 int error;
484 struct buf *bp[MAXQUOTAS]; 484 struct buf *bp[MAXQUOTAS];
485 struct quota2_entry *q2e[MAXQUOTAS]; 485 struct quota2_entry *q2e[MAXQUOTAS];
486 struct quota2_val *q2vp; 486 struct quota2_val *q2vp;
487 struct dquot *dq; 487 struct dquot *dq;
488 uint64_t ncurblks; 488 uint64_t ncurblks;
489 struct ufsmount *ump = ip->i_ump; 489 struct ufsmount *ump = ip->i_ump;
490 struct mount *mp = ump->um_mountp; 490 struct mount *mp = ump->um_mountp;
491 const int needswap = UFS_MPNEEDSWAP(ump); 491 const int needswap = UFS_MPNEEDSWAP(ump);
492 int i; 492 int i;
493 493
494 if ((error = getinoquota2(ip, change > 0, change != 0, bp, q2e)) != 0) 494 if ((error = getinoquota2(ip, change > 0, change != 0, bp, q2e)) != 0)
495 return error; 495 return error;
496 if (change == 0) { 496 if (change == 0) {
497 for (i = 0; i < MAXQUOTAS; i++) { 497 for (i = 0; i < MAXQUOTAS; i++) {
498 dq = ip->i_dquot[i]; 498 dq = ip->i_dquot[i];
499 if (dq == NODQUOT) 499 if (dq == NODQUOT)
500 continue; 500 continue;
501 if (bp[i]) 501 if (bp[i])
502 brelse(bp[i], 0); 502 brelse(bp[i], 0);
503 mutex_exit(&dq->dq_interlock); 503 mutex_exit(&dq->dq_interlock);
504 } 504 }
505 return 0; 505 return 0;
506 } 506 }
507 if (change < 0) { 507 if (change < 0) {
508 for (i = 0; i < MAXQUOTAS; i++) { 508 for (i = 0; i < MAXQUOTAS; i++) {
509 dq = ip->i_dquot[i]; 509 dq = ip->i_dquot[i];
510 if (dq == NODQUOT) 510 if (dq == NODQUOT)
511 continue; 511 continue;
512 if (q2e[i] == NULL) { 512 if (q2e[i] == NULL) {
513 mutex_exit(&dq->dq_interlock); 513 mutex_exit(&dq->dq_interlock);
514 continue; 514 continue;
515 } 515 }
516 q2vp = &q2e[i]->q2e_val[vtype]; 516 q2vp = &q2e[i]->q2e_val[vtype];
517 ncurblks = ufs_rw64(q2vp->q2v_cur, needswap); 517 ncurblks = ufs_rw64(q2vp->q2v_cur, needswap);
518 if (ncurblks < -change) 518 if (ncurblks < -change)
519 ncurblks = 0; 519 ncurblks = 0;
520 else 520 else
521 ncurblks += change; 521 ncurblks += change;
522 q2vp->q2v_cur = ufs_rw64(ncurblks, needswap); 522 q2vp->q2v_cur = ufs_rw64(ncurblks, needswap);
523 quota2_bwrite(mp, bp[i]); 523 quota2_bwrite(mp, bp[i]);
524 mutex_exit(&dq->dq_interlock); 524 mutex_exit(&dq->dq_interlock);
525 } 525 }
526 return 0; 526 return 0;
527 } 527 }
528 /* see if the allocation is allowed */ 528 /* see if the allocation is allowed */
529 for (i = 0; i < MAXQUOTAS; i++) { 529 for (i = 0; i < MAXQUOTAS; i++) {
530 struct quota2_val q2v; 530 struct quota2_val q2v;
531 int ql_stat; 531 int ql_stat;
532 dq = ip->i_dquot[i]; 532 dq = ip->i_dquot[i];
533 if (dq == NODQUOT) 533 if (dq == NODQUOT)
534 continue; 534 continue;
535 KASSERT(q2e[i] != NULL); 535 KASSERT(q2e[i] != NULL);
536 quota2_ufs_rwq2v(&q2e[i]->q2e_val[vtype], &q2v, needswap); 536 quota2_ufs_rwq2v(&q2e[i]->q2e_val[vtype], &q2v, needswap);
537 ql_stat = quota2_check_limit(&q2v, change, time_second); 537 ql_stat = quota2_check_limit(&q2v, change, time_second);
538 538
539 if ((flags & FORCE) == 0 && 539 if ((flags & FORCE) == 0 &&
540 kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA, 540 kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA,
541 KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, 541 KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT,
542 KAUTH_ARG(i), KAUTH_ARG(vtype), NULL) != 0) { 542 KAUTH_ARG(i), KAUTH_ARG(vtype), NULL) != 0) {
543 /* enforce this limit */ 543 /* enforce this limit */
544 switch(QL_STATUS(ql_stat)) { 544 switch(QL_STATUS(ql_stat)) {
545 case QL_S_DENY_HARD: 545 case QL_S_DENY_HARD:
546 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { 546 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
547 uprintf("\n%s: write failed, %s %s " 547 uprintf("\n%s: write failed, %s %s "
548 "limit reached\n", 548 "limit reached\n",
549 mp->mnt_stat.f_mntonname, 549 mp->mnt_stat.f_mntonname,
550 quotatypes[i], limnames[vtype]); 550 quotatypes[i], limnames[vtype]);
551 dq->dq_flags |= DQ_WARN(vtype); 551 dq->dq_flags |= DQ_WARN(vtype);
552 } 552 }
553 error = EDQUOT; 553 error = EDQUOT;
554 break; 554 break;
555 case QL_S_DENY_GRACE: 555 case QL_S_DENY_GRACE:
556 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { 556 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
557 uprintf("\n%s: write failed, %s %s " 557 uprintf("\n%s: write failed, %s %s "
558 "limit reached\n", 558 "limit reached\n",
559 mp->mnt_stat.f_mntonname, 559 mp->mnt_stat.f_mntonname,
560 quotatypes[i], limnames[vtype]); 560 quotatypes[i], limnames[vtype]);
561 dq->dq_flags |= DQ_WARN(vtype); 561 dq->dq_flags |= DQ_WARN(vtype);
562 } 562 }
563 error = EDQUOT; 563 error = EDQUOT;
564 break; 564 break;
565 case QL_S_ALLOW_SOFT: 565 case QL_S_ALLOW_SOFT:
566 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { 566 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
567 uprintf("\n%s: warning, %s %s " 567 uprintf("\n%s: warning, %s %s "
568 "quota exceeded\n", 568 "quota exceeded\n",
569 mp->mnt_stat.f_mntonname, 569 mp->mnt_stat.f_mntonname,
570 quotatypes[i], limnames[vtype]); 570 quotatypes[i], limnames[vtype]);
571 dq->dq_flags |= DQ_WARN(vtype); 571 dq->dq_flags |= DQ_WARN(vtype);
572 } 572 }
573 break; 573 break;
574 } 574 }
575 } 575 }
576 /* 576 /*
577 * always do this; we don't know if the allocation will 577 * always do this; we don't know if the allocation will
578 * succed or not in the end. if we don't do the allocation 578 * succed or not in the end. if we don't do the allocation
579 * q2v_time will be ignored anyway 579 * q2v_time will be ignored anyway
580 */ 580 */
581 if (ql_stat & QL_F_CROSS) { 581 if (ql_stat & QL_F_CROSS) {
582 q2v.q2v_time = time_second + q2v.q2v_grace; 582 q2v.q2v_time = time_second + q2v.q2v_grace;
583 quota2_ufs_rwq2v(&q2v, &q2e[i]->q2e_val[vtype], 583 quota2_ufs_rwq2v(&q2v, &q2e[i]->q2e_val[vtype],
584 needswap); 584 needswap);
585 } 585 }
586 } 586 }
587 587
588 /* now do the allocation if allowed */ 588 /* now do the allocation if allowed */
589 for (i = 0; i < MAXQUOTAS; i++) { 589 for (i = 0; i < MAXQUOTAS; i++) {
590 dq = ip->i_dquot[i]; 590 dq = ip->i_dquot[i];
591 if (dq == NODQUOT) 591 if (dq == NODQUOT)
592 continue; 592 continue;
593 KASSERT(q2e[i] != NULL); 593 KASSERT(q2e[i] != NULL);
594 if (error == 0) { 594 if (error == 0) {
595 q2vp = &q2e[i]->q2e_val[vtype]; 595 q2vp = &q2e[i]->q2e_val[vtype];
596 ncurblks = ufs_rw64(q2vp->q2v_cur, needswap); 596 ncurblks = ufs_rw64(q2vp->q2v_cur, needswap);
597 q2vp->q2v_cur = ufs_rw64(ncurblks + change, needswap); 597 q2vp->q2v_cur = ufs_rw64(ncurblks + change, needswap);
598 quota2_bwrite(mp, bp[i]); 598 quota2_bwrite(mp, bp[i]);
599 } else 599 } else
600 brelse(bp[i], 0); 600 brelse(bp[i], 0);
601 mutex_exit(&dq->dq_interlock); 601 mutex_exit(&dq->dq_interlock);
602 } 602 }
603 return error; 603 return error;
604} 604}
605 605
606int 606int
607chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) 607chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
608{ 608{
609 return quota2_check(ip, QL_BLOCK, change, cred, flags); 609 return quota2_check(ip, QL_BLOCK, change, cred, flags);
610} 610}
611 611
612int 612int
613chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) 613chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
614{ 614{
615 return quota2_check(ip, QL_FILE, change, cred, flags); 615 return quota2_check(ip, QL_FILE, change, cred, flags);
616} 616}
617 617
618int 618int
619quota2_handle_cmd_put(struct ufsmount *ump, const struct quotakey *key, 619quota2_handle_cmd_put(struct ufsmount *ump, const struct quotakey *key,
620 const struct quotaval *val) 620 const struct quotaval *val)
621{ 621{
622 int error; 622 int error;
623 struct dquot *dq; 623 struct dquot *dq;
624 struct quota2_header *q2h; 624 struct quota2_header *q2h;
625 struct quota2_entry q2e, *q2ep; 625 struct quota2_entry q2e, *q2ep;
626 struct buf *bp; 626 struct buf *bp;
627 const int needswap = UFS_MPNEEDSWAP(ump); 627 const int needswap = UFS_MPNEEDSWAP(ump);
628 628
629 /* make sure we can index by the fs-independent idtype */ 629 /* make sure we can index by the fs-independent idtype */
630 CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA); 630 CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA);
631 CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA); 631 CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA);
632 632
633 if (ump->um_quotas[key->qk_idtype] == NULLVP) 633 if (ump->um_quotas[key->qk_idtype] == NULLVP)
634 return ENODEV; 634 return ENODEV;
635 error = UFS_WAPBL_BEGIN(ump->um_mountp); 635 error = UFS_WAPBL_BEGIN(ump->um_mountp);
636 if (error) 636 if (error)
637 return error; 637 return error;
638  638
639 if (key->qk_id == QUOTA_DEFAULTID) { 639 if (key->qk_id == QUOTA_DEFAULTID) {
640 mutex_enter(&dqlock); 640 mutex_enter(&dqlock);
641 error = getq2h(ump, key->qk_idtype, &bp, &q2h, B_MODIFY); 641 error = getq2h(ump, key->qk_idtype, &bp, &q2h, B_MODIFY);
642 if (error) { 642 if (error) {
643 mutex_exit(&dqlock); 643 mutex_exit(&dqlock);
644 goto out_wapbl; 644 goto out_wapbl;
645 } 645 }
646 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 646 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
647 quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e); 647 quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e);
648 quota2_ufs_rwq2e(&q2e, &q2h->q2h_defentry, needswap); 648 quota2_ufs_rwq2e(&q2e, &q2h->q2h_defentry, needswap);
649 mutex_exit(&dqlock); 649 mutex_exit(&dqlock);
650 quota2_bwrite(ump->um_mountp, bp); 650 quota2_bwrite(ump->um_mountp, bp);
651 goto out_wapbl; 651 goto out_wapbl;
652 } 652 }
653 653
654 error = dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq); 654 error = dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq);
655 if (error) 655 if (error)
656 goto out_wapbl; 656 goto out_wapbl;
657 657
658 mutex_enter(&dq->dq_interlock); 658 mutex_enter(&dq->dq_interlock);
659 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 659 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
660 /* need to alloc a new on-disk quot */ 660 /* need to alloc a new on-disk quot */
661 mutex_enter(&dqlock); 661 mutex_enter(&dqlock);
662 error = quota2_q2ealloc(ump, key->qk_idtype, key->qk_id, dq, 662 error = quota2_q2ealloc(ump, key->qk_idtype, key->qk_id, dq,
663 &bp, &q2ep); 663 &bp, &q2ep);
664 mutex_exit(&dqlock); 664 mutex_exit(&dqlock);
665 } else { 665 } else {
666 error = getq2e(ump, key->qk_idtype, dq->dq2_lblkno, 666 error = getq2e(ump, key->qk_idtype, dq->dq2_lblkno,
667 dq->dq2_blkoff, &bp, &q2ep, B_MODIFY); 667 dq->dq2_blkoff, &bp, &q2ep, B_MODIFY);
668 } 668 }
669 if (error) 669 if (error)
670 goto out_il; 670 goto out_il;
671  671
672 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 672 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
673 quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e); 673 quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e);
674 quota2_ufs_rwq2e(&q2e, q2ep, needswap); 674 quota2_ufs_rwq2e(&q2e, q2ep, needswap);
675 quota2_bwrite(ump->um_mountp, bp); 675 quota2_bwrite(ump->um_mountp, bp);
676 676
677out_il: 677out_il:
678 mutex_exit(&dq->dq_interlock); 678 mutex_exit(&dq->dq_interlock);
679 dqrele(NULLVP, dq); 679 dqrele(NULLVP, dq);
680out_wapbl: 680out_wapbl:
681 UFS_WAPBL_END(ump->um_mountp); 681 UFS_WAPBL_END(ump->um_mountp);
682 return error; 682 return error;
683} 683}
684 684
685struct dq2clear_callback { 685struct dq2clear_callback {
686 uid_t id; 686 uid_t id;
687 struct dquot *dq; 687 struct dquot *dq;
688 struct quota2_header *q2h; 688 struct quota2_header *q2h;
689}; 689};
690 690
691static int 691static int
692dq2clear_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, 692dq2clear_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e,
693 uint64_t off, void *v) 693 uint64_t off, void *v)
694{ 694{
695 struct dq2clear_callback *c = v; 695 struct dq2clear_callback *c = v;
696#ifdef FFS_EI 696#ifdef FFS_EI
697 const int needswap = UFS_MPNEEDSWAP(ump); 697 const int needswap = UFS_MPNEEDSWAP(ump);
698#endif 698#endif
699 uint64_t myoff; 699 uint64_t myoff;
700 700
701 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { 701 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
702 KASSERT(mutex_owned(&c->dq->dq_interlock)); 702 KASSERT(mutex_owned(&c->dq->dq_interlock));
703 c->dq->dq2_lblkno = 0; 703 c->dq->dq2_lblkno = 0;
704 c->dq->dq2_blkoff = 0; 704 c->dq->dq2_blkoff = 0;
705 myoff = *offp; 705 myoff = *offp;
706 /* remove from hash list */ 706 /* remove from hash list */
707 *offp = q2e->q2e_next; 707 *offp = q2e->q2e_next;
708 /* add to free list */ 708 /* add to free list */
709 q2e->q2e_next = c->q2h->q2h_free; 709 q2e->q2e_next = c->q2h->q2h_free;
710 c->q2h->q2h_free = myoff; 710 c->q2h->q2h_free = myoff;
711 return Q2WL_ABORT; 711 return Q2WL_ABORT;
712 } 712 }
713 return 0; 713 return 0;
714} 714}
715int 715int
716quota2_handle_cmd_delete(struct ufsmount *ump, const struct quotakey *qk) 716quota2_handle_cmd_delete(struct ufsmount *ump, const struct quotakey *qk)
717{ 717{
718 int idtype; 718 int idtype;
719 id_t id; 719 id_t id;
720 int objtype; 720 int objtype;
721 int error, i, canfree; 721 int error, i, canfree;
722 struct dquot *dq; 722 struct dquot *dq;
723 struct quota2_header *q2h; 723 struct quota2_header *q2h;
724 struct quota2_entry q2e, *q2ep; 724 struct quota2_entry q2e, *q2ep;
725 struct buf *hbp, *bp; 725 struct buf *hbp, *bp;
726 u_long hash_mask; 726 u_long hash_mask;
727 struct dq2clear_callback c; 727 struct dq2clear_callback c;
728 728
729 idtype = qk->qk_idtype; 729 idtype = qk->qk_idtype;
730 id = qk->qk_id; 730 id = qk->qk_id;
731 objtype = qk->qk_objtype; 731 objtype = qk->qk_objtype;
732 732
733 if (ump->um_quotas[idtype] == NULLVP) 733 if (ump->um_quotas[idtype] == NULLVP)
734 return ENODEV; 734 return ENODEV;
735 if (id == QUOTA_DEFAULTID) 735 if (id == QUOTA_DEFAULTID)
736 return EOPNOTSUPP; 736 return EOPNOTSUPP;
737 737
738 /* get the default entry before locking the entry's buffer */ 738 /* get the default entry before locking the entry's buffer */
739 mutex_enter(&dqlock); 739 mutex_enter(&dqlock);
740 error = getq2h(ump, idtype, &hbp, &q2h, 0); 740 error = getq2h(ump, idtype, &hbp, &q2h, 0);
741 if (error) { 741 if (error) {
742 mutex_exit(&dqlock); 742 mutex_exit(&dqlock);
743 return error; 743 return error;
744 } 744 }
745 /* we'll copy to another disk entry, so no need to swap */ 745 /* we'll copy to another disk entry, so no need to swap */
746 memcpy(&q2e, &q2h->q2h_defentry, sizeof(q2e)); 746 memcpy(&q2e, &q2h->q2h_defentry, sizeof(q2e));
747 mutex_exit(&dqlock); 747 mutex_exit(&dqlock);
748 brelse(hbp, 0); 748 brelse(hbp, 0);
749 749
750 error = dqget(NULLVP, id, ump, idtype, &dq); 750 error = dqget(NULLVP, id, ump, idtype, &dq);
751 if (error) 751 if (error)
752 return error; 752 return error;
753 753
754 mutex_enter(&dq->dq_interlock); 754 mutex_enter(&dq->dq_interlock);
755 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 755 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
756 /* already clear, nothing to do */ 756 /* already clear, nothing to do */
757 error = ENOENT; 757 error = ENOENT;
758 goto out_il; 758 goto out_il;
759 } 759 }
760 error = UFS_WAPBL_BEGIN(ump->um_mountp); 760 error = UFS_WAPBL_BEGIN(ump->um_mountp);
761 if (error) 761 if (error)
762 goto out_dq; 762 goto out_dq;
763  763
764 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, 764 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff,
765 &bp, &q2ep, B_MODIFY); 765 &bp, &q2ep, B_MODIFY);
766 if (error) 766 if (error)
767 goto out_wapbl; 767 goto out_wapbl;
768 768
769 /* make sure we can index by the objtype passed in */ 769 /* make sure we can index by the objtype passed in */
770 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK); 770 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK);
771 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE); 771 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE);
772 772
773 /* clear the requested objtype by copying from the default entry */ 773 /* clear the requested objtype by copying from the default entry */
774 q2ep->q2e_val[objtype].q2v_softlimit = 774 q2ep->q2e_val[objtype].q2v_softlimit =
775 q2e.q2e_val[objtype].q2v_softlimit; 775 q2e.q2e_val[objtype].q2v_softlimit;
776 q2ep->q2e_val[objtype].q2v_hardlimit = 776 q2ep->q2e_val[objtype].q2v_hardlimit =
777 q2e.q2e_val[objtype].q2v_hardlimit; 777 q2e.q2e_val[objtype].q2v_hardlimit;
778 q2ep->q2e_val[objtype].q2v_grace = 778 q2ep->q2e_val[objtype].q2v_grace =
779 q2e.q2e_val[objtype].q2v_grace; 779 q2e.q2e_val[objtype].q2v_grace;
780 q2ep->q2e_val[objtype].q2v_time = 0; 780 q2ep->q2e_val[objtype].q2v_time = 0;
781 781
782 /* if this entry now contains no information, we can free it */ 782 /* if this entry now contains no information, we can free it */
783 canfree = 1; 783 canfree = 1;
784 for (i = 0; i < N_QL; i++) { 784 for (i = 0; i < N_QL; i++) {
785 if (q2ep->q2e_val[i].q2v_cur != 0 || 785 if (q2ep->q2e_val[i].q2v_cur != 0 ||
786 (q2ep->q2e_val[i].q2v_softlimit !=  786 (q2ep->q2e_val[i].q2v_softlimit !=
787 q2e.q2e_val[i].q2v_softlimit) || 787 q2e.q2e_val[i].q2v_softlimit) ||
788 (q2ep->q2e_val[i].q2v_hardlimit !=  788 (q2ep->q2e_val[i].q2v_hardlimit !=
789 q2e.q2e_val[i].q2v_hardlimit) || 789 q2e.q2e_val[i].q2v_hardlimit) ||
790 (q2ep->q2e_val[i].q2v_grace !=  790 (q2ep->q2e_val[i].q2v_grace !=
791 q2e.q2e_val[i].q2v_grace)) { 791 q2e.q2e_val[i].q2v_grace)) {
792 canfree = 0; 792 canfree = 0;
793 break; 793 break;
794 } 794 }
795 /* note: do not need to check q2v_time */ 795 /* note: do not need to check q2v_time */
796 } 796 }
797 797
798 if (canfree == 0) { 798 if (canfree == 0) {
799 quota2_bwrite(ump->um_mountp, bp); 799 quota2_bwrite(ump->um_mountp, bp);
800 goto out_wapbl; 800 goto out_wapbl;
801 } 801 }
802 /* we can free it. release bp so we can walk the list */ 802 /* we can free it. release bp so we can walk the list */
803 brelse(bp, 0); 803 brelse(bp, 0);
804 mutex_enter(&dqlock); 804 mutex_enter(&dqlock);
805 error = getq2h(ump, idtype, &hbp, &q2h, 0); 805 error = getq2h(ump, idtype, &hbp, &q2h, 0);
806 if (error) 806 if (error)
807 goto out_dqlock; 807 goto out_dqlock;
808 808
809 hash_mask = ((1 << q2h->q2h_hash_shift) - 1); 809 hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
810 c.dq = dq; 810 c.dq = dq;
811 c.id = id; 811 c.id = id;
812 c.q2h = q2h; 812 c.q2h = q2h;
813 error = quota2_walk_list(ump, hbp, idtype, 813 error = quota2_walk_list(ump, hbp, idtype,
814 &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c, 814 &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c,
815 dq2clear_callback); 815 dq2clear_callback);
816 816
817 bwrite(hbp); 817 bwrite(hbp);
818 818
819out_dqlock: 819out_dqlock:
820 mutex_exit(&dqlock); 820 mutex_exit(&dqlock);
821out_wapbl: 821out_wapbl:
822 UFS_WAPBL_END(ump->um_mountp); 822 UFS_WAPBL_END(ump->um_mountp);
823out_il: 823out_il:
824 mutex_exit(&dq->dq_interlock); 824 mutex_exit(&dq->dq_interlock);
825out_dq: 825out_dq:
826 dqrele(NULLVP, dq); 826 dqrele(NULLVP, dq);
827 return error; 827 return error;
828} 828}
829 829
830static int 830static int
831quota2_result_add_q2e(struct ufsmount *ump, int idtype, 831quota2_result_add_q2e(struct ufsmount *ump, int idtype,
832 int id, struct quota_getall_result *result, unsigned pos, 832 int id, struct quota_getall_result *result, unsigned pos,
833 int skipfirst, int skiplast) 833 int skipfirst, int skiplast)
834{ 834{
835 struct dquot *dq; 835 struct dquot *dq;
836 int error; 836 int error;
837 struct quota2_entry *q2ep, q2e; 837 struct quota2_entry *q2ep, q2e;
838 struct buf *bp; 838 struct buf *bp;
839 const int needswap = UFS_MPNEEDSWAP(ump); 839 const int needswap = UFS_MPNEEDSWAP(ump);
840 840
841 error = dqget(NULLVP, id, ump, idtype, &dq); 841 error = dqget(NULLVP, id, ump, idtype, &dq);
842 if (error) 842 if (error)
843 return error; 843 return error;
844 844
845 mutex_enter(&dq->dq_interlock); 845 mutex_enter(&dq->dq_interlock);
846 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 846 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
847 mutex_exit(&dq->dq_interlock); 847 mutex_exit(&dq->dq_interlock);
848 dqrele(NULLVP, dq); 848 dqrele(NULLVP, dq);
849 return ENOENT; 849 return ENOENT;
850 } 850 }
851 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, 851 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff,
852 &bp, &q2ep, 0); 852 &bp, &q2ep, 0);
853 if (error) { 853 if (error) {
854 mutex_exit(&dq->dq_interlock); 854 mutex_exit(&dq->dq_interlock);
855 dqrele(NULLVP, dq); 855 dqrele(NULLVP, dq);
856 return error; 856 return error;
857 } 857 }
858 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 858 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
859 brelse(bp, 0); 859 brelse(bp, 0);
860 mutex_exit(&dq->dq_interlock); 860 mutex_exit(&dq->dq_interlock);
861 dqrele(NULLVP, dq); 861 dqrele(NULLVP, dq);
862 862
863 if (skipfirst == 0) { 863 if (skipfirst == 0) {
864 result->qr_keys[pos].qk_idtype = idtype; 864 result->qr_keys[pos].qk_idtype = idtype;
865 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS; 865 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
866 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id, 866 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id,
867 QL_BLOCK, &result->qr_vals[pos]); 867 QL_BLOCK, &result->qr_vals[pos]);
868 pos++; 868 pos++;
869 } 869 }
870 870
871 if (skiplast == 0) { 871 if (skiplast == 0) {
872 result->qr_keys[pos].qk_idtype = idtype; 872 result->qr_keys[pos].qk_idtype = idtype;
873 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES; 873 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES;
874 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id, 874 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id,
875 QL_FILE, &result->qr_vals[pos]); 875 QL_FILE, &result->qr_vals[pos]);
876 pos++; 876 pos++;
877 } 877 }
878 878
879 return 0; 879 return 0;
880} 880}
881 881
882static int 882static int
883quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, 883quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
884 struct quotaval *ret) 884 struct quotaval *ret)
885{ 885{
886 struct dquot *dq; 886 struct dquot *dq;
887 int error; 887 int error;
888 struct quota2_entry *q2ep, q2e; 888 struct quota2_entry *q2ep, q2e;
889 struct buf *bp; 889 struct buf *bp;
890 const int needswap = UFS_MPNEEDSWAP(ump); 890 const int needswap = UFS_MPNEEDSWAP(ump);
891 id_t id2; 891 id_t id2;
892 892
893 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); 893 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
894 if (error) 894 if (error)
895 return error; 895 return error;
896 896
897 mutex_enter(&dq->dq_interlock); 897 mutex_enter(&dq->dq_interlock);
898 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 898 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
899 mutex_exit(&dq->dq_interlock); 899 mutex_exit(&dq->dq_interlock);
900 dqrele(NULLVP, dq); 900 dqrele(NULLVP, dq);
901 return ENOENT; 901 return ENOENT;
902 } 902 }
903 error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff, 903 error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff,
904 &bp, &q2ep, 0); 904 &bp, &q2ep, 0);
905 if (error) { 905 if (error) {
906 mutex_exit(&dq->dq_interlock); 906 mutex_exit(&dq->dq_interlock);
907 dqrele(NULLVP, dq); 907 dqrele(NULLVP, dq);
908 return error; 908 return error;
909 } 909 }
910 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 910 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
911 brelse(bp, 0); 911 brelse(bp, 0);
912 mutex_exit(&dq->dq_interlock); 912 mutex_exit(&dq->dq_interlock);
913 dqrele(NULLVP, dq); 913 dqrele(NULLVP, dq);
914 914
915 q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret); 915 q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret);
916 KASSERT(id2 == qk->qk_id); 916 KASSERT(id2 == qk->qk_id);
917 return 0; 917 return 0;
918} 918}
919 919
920int 920int
921quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk, 921quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk,
922 struct quotaval *ret) 922 struct quotaval *ret)
923{ 923{
924 int error; 924 int error;
925 struct quota2_header *q2h; 925 struct quota2_header *q2h;
926 struct quota2_entry q2e; 926 struct quota2_entry q2e;
927 struct buf *bp; 927 struct buf *bp;
928 const int needswap = UFS_MPNEEDSWAP(ump); 928 const int needswap = UFS_MPNEEDSWAP(ump);
929 id_t id2; 929 id_t id2;
930 930
931 /* 931 /*
932 * Make sure the FS-independent codes match the internal ones, 932 * Make sure the FS-independent codes match the internal ones,
933 * so we can use the passed-in objtype without having to 933 * so we can use the passed-in objtype without having to
934 * convert it explicitly to QL_BLOCK/QL_FILE. 934 * convert it explicitly to QL_BLOCK/QL_FILE.
935 */ 935 */
936 CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS); 936 CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS);
937 CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES); 937 CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES);
938 CTASSERT(N_QL == 2); 938 CTASSERT(N_QL == 2);
939 939
940 if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) { 940 if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) {
941 return EINVAL; 941 return EINVAL;
942 } 942 }
943 943
944 if (ump->um_quotas[qk->qk_idtype] == NULLVP) 944 if (ump->um_quotas[qk->qk_idtype] == NULLVP)
945 return ENODEV; 945 return ENODEV;
946 if (qk->qk_id == QUOTA_DEFAULTID) { 946 if (qk->qk_id == QUOTA_DEFAULTID) {
947 mutex_enter(&dqlock); 947 mutex_enter(&dqlock);
948 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); 948 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0);
949 if (error) { 949 if (error) {
950 mutex_exit(&dqlock); 950 mutex_exit(&dqlock);
951 return error; 951 return error;
952 } 952 }
953 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 953 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
954 mutex_exit(&dqlock); 954 mutex_exit(&dqlock);
955 brelse(bp, 0); 955 brelse(bp, 0);
956 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, 956 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2,
957 qk->qk_objtype, ret); 957 qk->qk_objtype, ret);
958 (void)id2; 958 (void)id2;
959 } else 959 } else
960 error = quota2_fetch_q2e(ump, qk, ret); 960 error = quota2_fetch_q2e(ump, qk, ret);
961  961
962 return error; 962 return error;
963} 963}
964 964
965struct ufsq2_cursor { 965struct ufsq2_cursor {
966 uint32_t q2c_magic; /* magic number */ 966 uint32_t q2c_magic; /* magic number */
967 int q2c_hashsize; /* size of hash table at last go */ 967 int q2c_hashsize; /* size of hash table at last go */
968 968
969 int q2c_defaults_done; /* true if we've returned the default values */ 969 int q2c_defaults_done; /* true if we've returned the default values */
970 int q2c_hashpos; /* slot to start at in hash table */ 970 int q2c_hashpos; /* slot to start at in hash table */
971 int q2c_uidpos; /* number of ids we've handled */ 971 int q2c_uidpos; /* number of ids we've handled */
972 int q2c_blocks_done; /* true if we've returned the blocks value */ 972 int q2c_blocks_done; /* true if we've returned the blocks value */
973}; 973};
974 974
975#define Q2C_MAGIC (0xbeebe111) 975#define Q2C_MAGIC (0xbeebe111)
976 976
977#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0]) 977#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0])
978 978
979static int 979static int
980q2cursor_check(struct ufsq2_cursor *cursor) 980q2cursor_check(struct ufsq2_cursor *cursor)
981{ 981{
982 if (cursor->q2c_magic != Q2C_MAGIC) { 982 if (cursor->q2c_magic != Q2C_MAGIC) {
983 return EINVAL; 983 return EINVAL;
984 } 984 }
985 if (cursor->q2c_hashsize < 0) { 985 if (cursor->q2c_hashsize < 0) {
986 return EINVAL; 986 return EINVAL;
987 } 987 }
988 988
989 if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) { 989 if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) {
990 return EINVAL; 990 return EINVAL;
991 } 991 }
992 if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) { 992 if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) {
993 return EINVAL; 993 return EINVAL;
994 } 994 }
995 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) { 995 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) {
996 return EINVAL; 996 return EINVAL;
997 } 997 }
998 return 0; 998 return 0;
999} 999}
1000 1000
1001struct getuids { 1001struct getuids {
1002 long nuids; /* number of uids in array */ 1002 long nuids; /* number of uids in array */
1003 long size; /* size of array */ 1003 long size; /* size of array */
1004 uid_t *uids; /* array of uids, dynamically allocated */ 1004 uid_t *uids; /* array of uids, dynamically allocated */
1005 long skip; 1005 long skip;
1006 long seen; 1006 long seen;
1007 long limit; 1007 long limit;
1008}; 1008};
1009 1009
1010static int 1010static int
1011quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, 1011quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp,
1012 struct quota2_entry *q2ep, uint64_t off, void *v) 1012 struct quota2_entry *q2ep, uint64_t off, void *v)
1013{ 1013{
1014 struct getuids *gu = v; 1014 struct getuids *gu = v;
1015 uid_t *newuids; 1015 uid_t *newuids;
1016#ifdef FFS_EI 1016#ifdef FFS_EI
1017 const int needswap = UFS_MPNEEDSWAP(ump); 1017 const int needswap = UFS_MPNEEDSWAP(ump);
1018#endif 1018#endif
1019 1019
1020 if (gu->skip > 0) { 1020 if (gu->skip > 0) {
1021 gu->skip--; 1021 gu->skip--;
1022 return 0; 1022 return 0;
1023 } 1023 }
1024 if (gu->nuids == gu->size) { 1024 if (gu->nuids == gu->size) {
1025 newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP, 1025 newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP,
1026 M_WAITOK); 1026 M_WAITOK);
1027 if (newuids == NULL) { 1027 if (newuids == NULL) {
1028 free(gu->uids, M_TEMP); 1028 free(gu->uids, M_TEMP);
1029 return ENOMEM; 1029 return ENOMEM;
1030 } 1030 }
1031 gu->uids = newuids; 1031 gu->uids = newuids;
1032 gu->size += (PAGE_SIZE / sizeof(uid_t)); 1032 gu->size += (PAGE_SIZE / sizeof(uid_t));
1033 } 1033 }
1034 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); 1034 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap);
1035 gu->nuids++; 1035 gu->nuids++;
1036 gu->seen++; 1036 gu->seen++;
1037 if (gu->nuids == gu->limit) { 1037 if (gu->nuids == gu->limit) {
1038 return Q2WL_ABORT; 1038 return Q2WL_ABORT;
1039 } 1039 }
1040 return 0; 1040 return 0;
1041} 1041}
1042 1042
1043int 1043int
1044quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc, 1044quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc,
1045 int idtype, struct quota_getall_result *result) 1045 int idtype, struct quota_getall_result *result)
1046{ 1046{
1047 int error; 1047 int error;
1048 struct ufsq2_cursor *cursor; 1048 struct ufsq2_cursor *cursor;
1049 struct quota2_header *q2h; 1049 struct quota2_header *q2h;
1050 struct quota2_entry q2e; 1050 struct quota2_entry q2e;
1051 struct buf *hbp; 1051 struct buf *hbp;
1052 uint64_t offset; 1052 uint64_t offset;
1053 int i, j; 1053 int i, j;
1054 int quota2_hash_size; 1054 int quota2_hash_size;
1055 const int needswap = UFS_MPNEEDSWAP(ump); 1055 const int needswap = UFS_MPNEEDSWAP(ump);
1056 struct getuids gu; 1056 struct getuids gu;
1057 id_t junkid; 1057 id_t junkid;
1058 struct quotaval qv; 1058 struct quotakey bkey, fkey;
 1059 struct quotaval bval, fval;
 1060 int dobval = 0, dofval = 0;
1059 unsigned num, maxnum; 1061 unsigned num, maxnum;
1060 int skipfirst, skiplast; 1062 int skipfirst, skiplast;
 1063 int maxreturn, numreturn;
1061 1064
1062 cursor = Q2CURSOR(qkc); 1065 cursor = Q2CURSOR(qkc);
1063 error = q2cursor_check(cursor); 1066 error = q2cursor_check(cursor);
1064 if (error) { 1067 if (error) {
1065 return error; 1068 return error;
1066 } 1069 }
1067 1070
1068 if (ump->um_quotas[idtype] == NULLVP) { 1071 if (ump->um_quotas[idtype] == NULLVP) {
1069 return ENODEV; 1072 return ENODEV;
1070 } 1073 }
1071 1074
 1075 maxreturn = result->qr_max;
 1076 numreturn = 0;
 1077
1072 mutex_enter(&dqlock); 1078 mutex_enter(&dqlock);
1073 error = getq2h(ump, idtype, &hbp, &q2h, 0); 1079 error = getq2h(ump, idtype, &hbp, &q2h, 0);
1074 if (error) { 1080 if (error) {
1075 mutex_exit(&dqlock); 1081 mutex_exit(&dqlock);
1076 return error; 1082 return error;
1077 } 1083 }
1078 1084
1079 if (cursor->q2c_defaults_done == 0) { 1085 if (cursor->q2c_defaults_done == 0) {
1080 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 1086 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
1081 if (cursor->q2c_blocks_done == 0) { 1087 if (cursor->q2c_blocks_done == 0) {
1082 q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv); 1088 q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &bval);
1083 result->qr_defblocks = qv; 1089 bkey.qk_idtype = idtype;
 1090 bkey.qk_id = QUOTA_DEFAULTID;
 1091 bkey.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
 1092 dobval = 1;
1084 cursor->q2c_blocks_done = 1; 1093 cursor->q2c_blocks_done = 1;
1085 } 1094 }
1086 if (cursor->q2c_blocks_done == 1) { 1095 if (cursor->q2c_blocks_done == 1) {
1087 q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv); 1096 q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &fval);
1088 result->qr_deffiles = qv; 1097 fkey.qk_idtype = idtype;
 1098 fkey.qk_id = QUOTA_DEFAULTID;
 1099 fkey.qk_objtype = QUOTA_OBJTYPE_FILES;
 1100 dofval = 1;
1089 cursor->q2c_blocks_done = 0; 1101 cursor->q2c_blocks_done = 0;
1090 cursor->q2c_defaults_done = 1; 1102 cursor->q2c_defaults_done = 1;
1091 } 1103 }
1092 } 1104 }
1093 1105
1094 /* 1106 /*
1095 * we can't directly get entries as we can't walk the list 1107 * we can't directly get entries as we can't walk the list
1096 * with qdlock and grab dq_interlock to read the entries 1108 * with qdlock and grab dq_interlock to read the entries
1097 * at the same time. So just walk the lists to build a list of uid, 1109 * at the same time. So just walk the lists to build a list of uid,
1098 * and then read entries for these uids 1110 * and then read entries for these uids
1099 */ 1111 */
1100 memset(&gu, 0, sizeof(gu)); 1112 memset(&gu, 0, sizeof(gu));
1101 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); 1113 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
1102 1114
1103 /* if the table size has changed, make the caller start over */ 1115 /* if the table size has changed, make the caller start over */
1104 if (cursor->q2c_hashsize == 0) { 1116 if (cursor->q2c_hashsize == 0) {
1105 cursor->q2c_hashsize = quota2_hash_size; 1117 cursor->q2c_hashsize = quota2_hash_size;
1106 } else if (cursor->q2c_hashsize != quota2_hash_size) { 1118 } else if (cursor->q2c_hashsize != quota2_hash_size) {
1107 error = EDEADLK; 1119 error = EDEADLK;
1108 goto fail; 1120 goto fail;
1109 } 1121 }
1110 1122
1111 gu.skip = cursor->q2c_uidpos; 1123 gu.skip = cursor->q2c_uidpos;
1112 gu.seen = 0; 1124 gu.seen = 0;
1113 gu.limit = result->qr_max / 2; 1125 gu.limit = (maxreturn - numreturn) / 2;
1114 if (gu.limit == 0 && result->qr_max > 0) { 1126 if (gu.limit == 0 && (maxreturn - numreturn) > 0) {
1115 gu.limit = 1; 1127 gu.limit = 1;
1116 } 1128 }
 1129 if (dobval && gu.limit > 0)
 1130 gu.limit--;
 1131 if (dofval && gu.limit > 0)
 1132 gu.limit--;
1117 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { 1133 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) {
1118 offset = q2h->q2h_entries[i]; 1134 offset = q2h->q2h_entries[i];
1119 gu.seen = 0; 1135 gu.seen = 0;
1120 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, 1136 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu,
1121 quota2_getuids_callback); 1137 quota2_getuids_callback);
1122 if (error == Q2WL_ABORT) { 1138 if (error == Q2WL_ABORT) {
1123 /* got enough uids for now */ 1139 /* got enough uids for now */
1124 error = 0; 1140 error = 0;
1125 break; 1141 break;
1126 } 1142 }
1127 if (error) { 1143 if (error) {
1128 if (gu.uids != NULL) 1144 if (gu.uids != NULL)
1129 free(gu.uids, M_TEMP); 1145 free(gu.uids, M_TEMP);
1130 break; 1146 break;
1131 } 1147 }
1132 } 1148 }
1133 cursor->q2c_hashpos = i; 1149 cursor->q2c_hashpos = i;
1134 cursor->q2c_uidpos = gu.seen; 1150 cursor->q2c_uidpos = gu.seen;
1135 1151
1136fail: 1152fail:
1137 mutex_exit(&dqlock); 1153 mutex_exit(&dqlock);
1138 brelse(hbp, 0); 1154 brelse(hbp, 0);
1139 if (error) 1155 if (error)
1140 return error; 1156 return error;
1141 1157
1142 maxnum = gu.nuids*2; 1158 maxnum = gu.nuids*2;
 1159 if (dobval)
 1160 maxnum++;
 1161 if (dofval)
 1162 maxnum++;
1143 result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]), 1163 result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]),
1144 M_TEMP, M_WAITOK); 1164 M_TEMP, M_WAITOK);
1145 result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]), 1165 result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]),
1146 M_TEMP, M_WAITOK); 1166 M_TEMP, M_WAITOK);
1147 1167
 1168 if (dobval && numreturn < maxreturn) {
 1169 result->qr_keys[numreturn] = bkey;
 1170 result->qr_vals[numreturn] = bval;
 1171 numreturn++;
 1172 }
 1173 if (dofval && numreturn < maxreturn) {
 1174 result->qr_keys[numreturn] = fkey;
 1175 result->qr_vals[numreturn] = fval;
 1176 numreturn++;
 1177 }
 1178 if (numreturn == maxreturn) {
 1179 return 0;
 1180 }
 1181
1148 /* 1182 /*
1149 * If we've already sent back the blocks value for the first id, 1183 * If we've already sent back the blocks value for the first id,
1150 * don't send it again (skipfirst). 1184 * don't send it again (skipfirst).
1151 * 1185 *
1152 * If we have an odd number of available result slots and we 1186 * If we have an odd number of available result slots and we
1153 * aren't going to skip the first result entry, we need to 1187 * aren't going to skip the first result entry, we need to
1154 * leave off the last result entry (skiplast). 1188 * leave off the last result entry (skiplast).
1155 */ 1189 */
1156 skipfirst = (cursor->q2c_blocks_done != 0); 1190 skipfirst = (cursor->q2c_blocks_done != 0);
1157 skiplast = skipfirst == 0 && (result->qr_max < maxnum); 1191 skiplast = skipfirst == 0 && (result->qr_max < maxnum);
1158 num = 0; 1192 num = 0;
1159 for (j = 0; j < gu.nuids; j++) { 1193 for (j = 0; j < gu.nuids; j++) {
1160 error = quota2_result_add_q2e(ump, idtype, 1194 error = quota2_result_add_q2e(ump, idtype,
1161 gu.uids[j], result, j*2, 1195 gu.uids[j], result, numreturn + j*2,
1162 j == 0 && skipfirst, 1196 j == 0 && skipfirst,
1163 j + 1 == gu.nuids && skiplast); 1197 j + 1 == gu.nuids && skiplast);
1164 if (error == ENOENT) 1198 if (error == ENOENT)
1165 continue; 1199 continue;
1166 if (error) 1200 if (error)
1167 break; 1201 break;
1168 num += 2; 1202 if ((j == 0 && skipfirst) || (j + 1 == gu.nuids && skiplast)) {
 1203 num += 1;
 1204 } else {
 1205 num += 2;
 1206 }
1169 } 1207 }
1170 result->qr_num = num; 1208 numreturn += num;
 1209 result->qr_num = numreturn;
1171 1210
1172 cursor->q2c_blocks_done = skiplast; 1211 cursor->q2c_blocks_done = skiplast;
1173 1212
1174 free(gu.uids, M_TEMP); 1213 free(gu.uids, M_TEMP);
1175 return error; 1214 return error;
1176} 1215}
1177 1216
1178int 1217int
1179quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) 1218quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc)
1180{ 1219{
1181 struct ufsq2_cursor *cursor; 1220 struct ufsq2_cursor *cursor;
1182 1221
1183 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); 1222 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space));
1184 cursor = Q2CURSOR(qkc); 1223 cursor = Q2CURSOR(qkc);
1185 1224
1186 cursor->q2c_magic = Q2C_MAGIC; 1225 cursor->q2c_magic = Q2C_MAGIC;
1187 cursor->q2c_hashsize = 0; 1226 cursor->q2c_hashsize = 0;
1188 1227
1189 cursor->q2c_defaults_done = 0; 1228 cursor->q2c_defaults_done = 0;
1190 cursor->q2c_hashpos = 0; 1229 cursor->q2c_hashpos = 0;
1191 cursor->q2c_uidpos = 0; 1230 cursor->q2c_uidpos = 0;
1192 cursor->q2c_blocks_done = 0; 1231 cursor->q2c_blocks_done = 0;
1193 return 0; 1232 return 0;
1194} 1233}
1195 1234
1196int 1235int
1197quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc) 1236quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc)
1198{ 1237{
1199 struct ufsq2_cursor *cursor; 1238 struct ufsq2_cursor *cursor;
1200 int error; 1239 int error;
1201 1240
1202 cursor = Q2CURSOR(qkc); 1241 cursor = Q2CURSOR(qkc);
1203 error = q2cursor_check(cursor); 1242 error = q2cursor_check(cursor);
1204 if (error) { 1243 if (error) {
1205 return error; 1244 return error;
1206 } 1245 }
1207 1246
1208 /* nothing to do */ 1247 /* nothing to do */
1209 1248
1210 return 0; 1249 return 0;
1211} 1250}
1212 1251
1213int 1252int
1214q2sync(struct mount *mp) 1253q2sync(struct mount *mp)
1215{ 1254{
1216 return 0; 1255 return 0;
1217} 1256}
1218 1257
1219struct dq2get_callback { 1258struct dq2get_callback {
1220 uid_t id; 1259 uid_t id;
1221 struct dquot *dq; 1260 struct dquot *dq;
1222}; 1261};
1223 1262
1224static int 1263static int
1225dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, 1264dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e,
1226 uint64_t off, void *v) 1265 uint64_t off, void *v)
1227{ 1266{
1228 struct dq2get_callback *c = v; 1267 struct dq2get_callback *c = v;
1229 daddr_t lblkno; 1268 daddr_t lblkno;
1230 int blkoff; 1269 int blkoff;
1231#ifdef FFS_EI 1270#ifdef FFS_EI
1232 const int needswap = UFS_MPNEEDSWAP(ump); 1271 const int needswap = UFS_MPNEEDSWAP(ump);
1233#endif 1272#endif
1234 1273
1235 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { 1274 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
1236 KASSERT(mutex_owned(&c->dq->dq_interlock)); 1275 KASSERT(mutex_owned(&c->dq->dq_interlock));
1237 lblkno = (off >> ump->um_mountp->mnt_fs_bshift); 1276 lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
1238 blkoff = (off & ump->umq2_bmask); 1277 blkoff = (off & ump->umq2_bmask);
1239 c->dq->dq2_lblkno = lblkno; 1278 c->dq->dq2_lblkno = lblkno;
1240 c->dq->dq2_blkoff = blkoff; 1279 c->dq->dq2_blkoff = blkoff;
1241 return Q2WL_ABORT; 1280 return Q2WL_ABORT;
1242 } 1281 }
1243 return 0; 1282 return 0;
1244} 1283}
1245 1284
1246int 1285int
1247dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, 1286dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type,
1248 struct dquot *dq) 1287 struct dquot *dq)
1249{ 1288{
1250 struct buf *bp; 1289 struct buf *bp;
1251 struct quota2_header *q2h; 1290 struct quota2_header *q2h;
1252 int error; 1291 int error;
1253 daddr_t offset; 1292 daddr_t offset;
1254 u_long hash_mask; 1293 u_long hash_mask;
1255 struct dq2get_callback c = { 1294 struct dq2get_callback c = {
1256 .id = id, 1295 .id = id,
1257 .dq = dq 1296 .dq = dq
1258 }; 1297 };
1259 1298
1260 KASSERT(mutex_owned(&dq->dq_interlock)); 1299 KASSERT(mutex_owned(&dq->dq_interlock));
1261 mutex_enter(&dqlock); 1300 mutex_enter(&dqlock);
1262 error = getq2h(ump, type, &bp, &q2h, 0); 1301 error = getq2h(ump, type, &bp, &q2h, 0);
1263 if (error) 1302 if (error)
1264 goto out_mutex; 1303 goto out_mutex;
1265 /* look for our entry */ 1304 /* look for our entry */
1266 hash_mask = ((1 << q2h->q2h_hash_shift) - 1); 1305 hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
1267 offset = q2h->q2h_entries[id & hash_mask]; 1306 offset = q2h->q2h_entries[id & hash_mask];
1268 error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, 1307 error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c,
1269 dq2get_callback); 1308 dq2get_callback);
1270 brelse(bp, 0); 1309 brelse(bp, 0);
1271out_mutex: 1310out_mutex:
1272 mutex_exit(&dqlock); 1311 mutex_exit(&dqlock);
1273 return error; 1312 return error;
1274} 1313}
1275 1314
1276int 1315int
1277dq2sync(struct vnode *vp, struct dquot *dq) 1316dq2sync(struct vnode *vp, struct dquot *dq)
1278{ 1317{
1279 return 0; 1318 return 0;
1280} 1319}