Sun Jan 29 07:05:13 2012 UTC ()
Teach quota2 QUOTACTL_GETALL to acecpt a limit on how much it sends back.
Pass in a dummy limit for now.

Note: this change requires a kernel version bump.


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

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

--- src/sys/kern/vfs_quotactl.c 2012/01/29 07:02:06 1.23
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 07:05:12 1.24
@@ -1,770 +1,772 @@ @@ -1,770 +1,772 @@
1/* $NetBSD: vfs_quotactl.c,v 1.23 2012/01/29 07:02:06 dholland Exp $ */ 1/* $NetBSD: vfs_quotactl.c,v 1.24 2012/01/29 07:05:12 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.23 2012/01/29 07:02:06 dholland Exp $"); 83__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.24 2012/01/29 07:05:12 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 int error, error2; 515 int error, error2;
516 int skip = 0; 516 int skip = 0;
517 517
518 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 518 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
519 519
520 args.qc_type = QCT_CURSOROPEN; 520 args.qc_type = QCT_CURSOROPEN;
521 args.u.cursoropen.qc_cursor = &cursor; 521 args.u.cursoropen.qc_cursor = &cursor;
522 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args); 522 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args);
523 if (error) { 523 if (error) {
524 return error; 524 return error;
525 } 525 }
526 526
527 result.qr_keys = NULL; 527 result.qr_keys = NULL;
528 result.qr_vals = NULL; 528 result.qr_vals = NULL;
 529 result.qr_num = 0;
 530 result.qr_max = 0x7fffffff; /* XXX bogus; but temporary */
529 531
530 args.qc_type = QCT_GETALL; 532 args.qc_type = QCT_GETALL;
531 args.u.getall.qc_cursor = &cursor; 533 args.u.getall.qc_cursor = &cursor;
532 args.u.getall.qc_idtype = q2type; 534 args.u.getall.qc_idtype = q2type;
533 args.u.getall.qc_result = &result; 535 args.u.getall.qc_result = &result;
534 error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args); 536 error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args);
535 /* 537 /*
536 * XXX this is bogus but up until now *all* errors 538 * XXX this is bogus but up until now *all* errors
537 * from inside quotactl_getall were suppressed by the 539 * from inside quotactl_getall were suppressed by the
538 * dispatching code in ufs_quota.c. Fixing that causes 540 * dispatching code in ufs_quota.c. Fixing that causes
539 * repquota to break in an undesirable way; this is a 541 * repquota to break in an undesirable way; this is a
540 * workaround. 542 * workaround.
541 */ 543 */
542 if (error == ENODEV || error == ENXIO) { 544 if (error == ENODEV || error == ENXIO) {
543 skip = 1; 545 skip = 1;
544 error = 0; 546 error = 0;
545 } 547 }
546 if (error) { 548 if (error) {
547 goto err; 549 goto err;
548 } 550 }
549 551
550 replies = prop_array_create(); 552 replies = prop_array_create();
551 if (replies == NULL) { 553 if (replies == NULL) {
552 error = ENOMEM; 554 error = ENOMEM;
553 goto err; 555 goto err;
554 } 556 }
555 557
556 if (skip) { 558 if (skip) {
557 goto skip; 559 goto skip;
558 } 560 }
559 561
560 dict = vfs_quotactl_getall_makereply(0, 1, &result.qr_defblocks, 562 dict = vfs_quotactl_getall_makereply(0, 1, &result.qr_defblocks,
561 &result.qr_deffiles); 563 &result.qr_deffiles);
562 if (!prop_array_add_and_rel(replies, dict)) { 564 if (!prop_array_add_and_rel(replies, dict)) {
563 error = ENOMEM; 565 error = ENOMEM;
564 goto err; 566 goto err;
565 } 567 }
566 568
567 for (i = 0; i < result.qr_num; i += 2) { 569 for (i = 0; i < result.qr_num; i += 2) {
568 dict = vfs_quotactl_getall_makereply(result.qr_keys[i].qk_id,0, 570 dict = vfs_quotactl_getall_makereply(result.qr_keys[i].qk_id,0,
569 &result.qr_vals[i], 571 &result.qr_vals[i],
570 &result.qr_vals[i+1]); 572 &result.qr_vals[i+1]);
571 if (dict == NULL) { 573 if (dict == NULL) {
572 error = ENOMEM; 574 error = ENOMEM;
573 goto err; 575 goto err;
574 } 576 }
575 if (!prop_array_add_and_rel(replies, dict)) { 577 if (!prop_array_add_and_rel(replies, dict)) {
576 error = ENOMEM; 578 error = ENOMEM;
577 goto err; 579 goto err;
578 } 580 }
579 } 581 }
580 582
581skip: 583skip:
582 584
583 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 585 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
584 error = ENOMEM; 586 error = ENOMEM;
585 goto err; 587 goto err;
586 } 588 }
587 589
588 error = 0; 590 error = 0;
589 err: 591 err:
590 if (result.qr_keys) { 592 if (result.qr_keys) {
591 free(result.qr_keys, M_TEMP); 593 free(result.qr_keys, M_TEMP);
592 } 594 }
593 if (result.qr_vals) { 595 if (result.qr_vals) {
594 free(result.qr_vals, M_TEMP); 596 free(result.qr_vals, M_TEMP);
595 } 597 }
596 598
597 args.qc_type = QCT_CURSORCLOSE; 599 args.qc_type = QCT_CURSORCLOSE;
598 args.u.cursorclose.qc_cursor = &cursor; 600 args.u.cursorclose.qc_cursor = &cursor;
599 error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args); 601 error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args);
600 602
601 if (error) { 603 if (error) {
602 return error; 604 return error;
603 } 605 }
604 error = error2; 606 error = error2;
605 return error; 607 return error;
606} 608}
607 609
608static int 610static int
609vfs_quotactl_clear(struct mount *mp, 611vfs_quotactl_clear(struct mount *mp,
610 prop_dictionary_t cmddict, int q2type, 612 prop_dictionary_t cmddict, int q2type,
611 prop_array_t datas) 613 prop_array_t datas)
612{ 614{
613 prop_array_t replies; 615 prop_array_t replies;
614 prop_object_iterator_t iter; 616 prop_object_iterator_t iter;
615 prop_dictionary_t data; 617 prop_dictionary_t data;
616 uint32_t id; 618 uint32_t id;
617 int defaultq; 619 int defaultq;
618 const char *idstr; 620 const char *idstr;
619 struct quotakey qk; 621 struct quotakey qk;
620 struct vfs_quotactl_args args; 622 struct vfs_quotactl_args args;
621 int error; 623 int error;
622 624
623 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 625 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
624 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 626 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
625 627
626 replies = prop_array_create(); 628 replies = prop_array_create();
627 if (replies == NULL) 629 if (replies == NULL)
628 return ENOMEM; 630 return ENOMEM;
629 631
630 iter = prop_array_iterator(datas); 632 iter = prop_array_iterator(datas);
631 if (iter == NULL) { 633 if (iter == NULL) {
632 prop_object_release(replies); 634 prop_object_release(replies);
633 return ENOMEM; 635 return ENOMEM;
634 } 636 }
635 637
636 while ((data = prop_object_iterator_next(iter)) != NULL) { 638 while ((data = prop_object_iterator_next(iter)) != NULL) {
637 if (!prop_dictionary_get_uint32(data, "id", &id)) { 639 if (!prop_dictionary_get_uint32(data, "id", &id)) {
638 if (!prop_dictionary_get_cstring_nocopy(data, "id", 640 if (!prop_dictionary_get_cstring_nocopy(data, "id",
639 &idstr)) 641 &idstr))
640 continue; 642 continue;
641 if (strcmp(idstr, "default")) 643 if (strcmp(idstr, "default"))
642 continue; 644 continue;
643 id = 0; 645 id = 0;
644 defaultq = 1; 646 defaultq = 1;
645 } else { 647 } else {
646 defaultq = 0; 648 defaultq = 0;
647 } 649 }
648 650
649 qk.qk_idtype = q2type; 651 qk.qk_idtype = q2type;
650 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 652 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
651 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 653 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
652 654
653 args.qc_type = QCT_DELETE; 655 args.qc_type = QCT_DELETE;
654 args.u.delete.qc_key = &qk; 656 args.u.delete.qc_key = &qk;
655 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); 657 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args);
656 if (error) { 658 if (error) {
657 goto err; 659 goto err;
658 } 660 }
659 661
660 qk.qk_idtype = q2type; 662 qk.qk_idtype = q2type;
661 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 663 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
662 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 664 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
663 665
664 args.qc_type = QCT_DELETE; 666 args.qc_type = QCT_DELETE;
665 args.u.delete.qc_key = &qk; 667 args.u.delete.qc_key = &qk;
666 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); 668 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args);
667 if (error) { 669 if (error) {
668 goto err; 670 goto err;
669 } 671 }
670 } 672 }
671 673
672 prop_object_iterator_release(iter); 674 prop_object_iterator_release(iter);
673 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 675 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
674 error = ENOMEM; 676 error = ENOMEM;
675 } else { 677 } else {
676 error = 0; 678 error = 0;
677 } 679 }
678 return error; 680 return error;
679err: 681err:
680 prop_object_iterator_release(iter); 682 prop_object_iterator_release(iter);
681 prop_object_release(replies); 683 prop_object_release(replies);
682 return error; 684 return error;
683} 685}
684 686
685static int 687static int
686vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) 688vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict)
687{ 689{
688 int error; 690 int error;
689 const char *cmd, *type; 691 const char *cmd, *type;
690 prop_array_t datas; 692 prop_array_t datas;
691 int q2type; 693 int q2type;
692 694
693 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) 695 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd))
694 return EINVAL; 696 return EINVAL;
695 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) 697 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type))
696 return EINVAL; 698 return EINVAL;
697 699
698 if (!strcmp(type, QUOTADICT_CLASS_USER)) { 700 if (!strcmp(type, QUOTADICT_CLASS_USER)) {
699 q2type = QUOTA_CLASS_USER; 701 q2type = QUOTA_CLASS_USER;
700 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { 702 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) {
701 q2type = QUOTA_CLASS_GROUP; 703 q2type = QUOTA_CLASS_GROUP;
702 } else { 704 } else {
703 /* XXX this is a bad errno for this case */ 705 /* XXX this is a bad errno for this case */
704 return EOPNOTSUPP; 706 return EOPNOTSUPP;
705 } 707 }
706 708
707 datas = prop_dictionary_get(cmddict, "data"); 709 datas = prop_dictionary_get(cmddict, "data");
708 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) 710 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY)
709 return EINVAL; 711 return EINVAL;
710 712
711 prop_object_retain(datas); 713 prop_object_retain(datas);
712 prop_dictionary_remove(cmddict, "data"); /* prepare for return */ 714 prop_dictionary_remove(cmddict, "data"); /* prepare for return */
713 715
714 if (strcmp(cmd, "get version") == 0) { 716 if (strcmp(cmd, "get version") == 0) {
715 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); 717 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas);
716 } else if (strcmp(cmd, "quotaon") == 0) { 718 } else if (strcmp(cmd, "quotaon") == 0) {
717 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); 719 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas);
718 } else if (strcmp(cmd, "quotaoff") == 0) { 720 } else if (strcmp(cmd, "quotaoff") == 0) {
719 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); 721 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas);
720 } else if (strcmp(cmd, "get") == 0) { 722 } else if (strcmp(cmd, "get") == 0) {
721 error = vfs_quotactl_get(mp, cmddict, q2type, datas); 723 error = vfs_quotactl_get(mp, cmddict, q2type, datas);
722 } else if (strcmp(cmd, "set") == 0) { 724 } else if (strcmp(cmd, "set") == 0) {
723 error = vfs_quotactl_put(mp, cmddict, q2type, datas); 725 error = vfs_quotactl_put(mp, cmddict, q2type, datas);
724 } else if (strcmp(cmd, "getall") == 0) { 726 } else if (strcmp(cmd, "getall") == 0) {
725 error = vfs_quotactl_getall(mp, cmddict, q2type, datas); 727 error = vfs_quotactl_getall(mp, cmddict, q2type, datas);
726 } else if (strcmp(cmd, "clear") == 0) { 728 } else if (strcmp(cmd, "clear") == 0) {
727 error = vfs_quotactl_clear(mp, cmddict, q2type, datas); 729 error = vfs_quotactl_clear(mp, cmddict, q2type, datas);
728 } else { 730 } else {
729 /* XXX this a bad errno for this case */ 731 /* XXX this a bad errno for this case */
730 error = EOPNOTSUPP; 732 error = EOPNOTSUPP;
731 } 733 }
732 734
733 error = (prop_dictionary_set_int8(cmddict, "return", 735 error = (prop_dictionary_set_int8(cmddict, "return",
734 error) ? 0 : ENOMEM); 736 error) ? 0 : ENOMEM);
735 prop_object_release(datas); 737 prop_object_release(datas);
736 738
737 return error; 739 return error;
738} 740}
739 741
740int 742int
741vfs_quotactl(struct mount *mp, prop_dictionary_t dict) 743vfs_quotactl(struct mount *mp, prop_dictionary_t dict)
742{ 744{
743 prop_dictionary_t cmddict; 745 prop_dictionary_t cmddict;
744 prop_array_t commands; 746 prop_array_t commands;
745 prop_object_iterator_t iter; 747 prop_object_iterator_t iter;
746 int error; 748 int error;
747 749
748 error = quota_get_cmds(dict, &commands); 750 error = quota_get_cmds(dict, &commands);
749 if (error) { 751 if (error) {
750 return error; 752 return error;
751 } 753 }
752 754
753 iter = prop_array_iterator(commands); 755 iter = prop_array_iterator(commands);
754 if (iter == NULL) { 756 if (iter == NULL) {
755 return ENOMEM; 757 return ENOMEM;
756 } 758 }
757 759
758 while ((cmddict = prop_object_iterator_next(iter)) != NULL) { 760 while ((cmddict = prop_object_iterator_next(iter)) != NULL) {
759 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { 761 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) {
760 /* XXX shouldn't this be an error? */ 762 /* XXX shouldn't this be an error? */
761 continue; 763 continue;
762 } 764 }
763 error = vfs_quotactl_cmd(mp, cmddict); 765 error = vfs_quotactl_cmd(mp, cmddict);
764 if (error) { 766 if (error) {
765 break; 767 break;
766 } 768 }
767 } 769 }
768 prop_object_iterator_release(iter); 770 prop_object_iterator_release(iter);
769 return error; 771 return error;
770} 772}

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

--- src/sys/sys/quotactl.h 2012/01/29 07:02:06 1.21
+++ src/sys/sys/quotactl.h 2012/01/29 07:05:12 1.22
@@ -1,120 +1,121 @@ @@ -1,120 +1,121 @@
1/* $NetBSD: quotactl.h,v 1.21 2012/01/29 07:02:06 dholland Exp $ */ 1/* $NetBSD: quotactl.h,v 1.22 2012/01/29 07:05:12 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; 110 struct quotaval qr_defblocks;
111 struct quotaval qr_deffiles; 111 struct quotaval qr_deffiles;
112 struct quotakey *qr_keys; 112 struct quotakey *qr_keys;
113 struct quotaval *qr_vals; 113 struct quotaval *qr_vals;
114 unsigned qr_num; 114 unsigned qr_num;
 115 unsigned qr_max;
115 } *qc_result; 116 } *qc_result;
116 } getall; 117 } getall;
117 } u; 118 } u;
118}; 119};
119 120
120#endif /* _SYS_QUOTACTL_H_ */ 121#endif /* _SYS_QUOTACTL_H_ */

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

--- src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:04:21 1.20
+++ src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:05:12 1.21
@@ -1,1245 +1,1280 @@ @@ -1,1245 +1,1280 @@
1/* $NetBSD: ufs_quota2.c,v 1.20 2012/01/29 07:04:21 dholland Exp $ */ 1/* $NetBSD: ufs_quota2.c,v 1.21 2012/01/29 07:05:12 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.20 2012/01/29 07:04:21 dholland Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.21 2012/01/29 07:05:12 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{ 834{
834 struct dquot *dq; 835 struct dquot *dq;
835 int error; 836 int error;
836 struct quota2_entry *q2ep, q2e; 837 struct quota2_entry *q2ep, q2e;
837 struct buf *bp; 838 struct buf *bp;
838 const int needswap = UFS_MPNEEDSWAP(ump); 839 const int needswap = UFS_MPNEEDSWAP(ump);
839 840
840 error = dqget(NULLVP, id, ump, idtype, &dq); 841 error = dqget(NULLVP, id, ump, idtype, &dq);
841 if (error) 842 if (error)
842 return error; 843 return error;
843 844
844 mutex_enter(&dq->dq_interlock); 845 mutex_enter(&dq->dq_interlock);
845 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 846 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
846 mutex_exit(&dq->dq_interlock); 847 mutex_exit(&dq->dq_interlock);
847 dqrele(NULLVP, dq); 848 dqrele(NULLVP, dq);
848 return ENOENT; 849 return ENOENT;
849 } 850 }
850 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, 851 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff,
851 &bp, &q2ep, 0); 852 &bp, &q2ep, 0);
852 if (error) { 853 if (error) {
853 mutex_exit(&dq->dq_interlock); 854 mutex_exit(&dq->dq_interlock);
854 dqrele(NULLVP, dq); 855 dqrele(NULLVP, dq);
855 return error; 856 return error;
856 } 857 }
857 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 858 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
858 brelse(bp, 0); 859 brelse(bp, 0);
859 mutex_exit(&dq->dq_interlock); 860 mutex_exit(&dq->dq_interlock);
860 dqrele(NULLVP, dq); 861 dqrele(NULLVP, dq);
861 862
862 result->qr_keys[pos].qk_idtype = idtype; 863 if (skipfirst == 0) {
863 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS; 864 result->qr_keys[pos].qk_idtype = idtype;
864 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id, 865 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
865 QL_BLOCK, &result->qr_vals[pos]); 866 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id,
866 867 QL_BLOCK, &result->qr_vals[pos]);
867 result->qr_keys[pos+1].qk_idtype = idtype; 868 pos++;
868 result->qr_keys[pos+1].qk_objtype = QUOTA_OBJTYPE_FILES; 869 }
869 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos+1].qk_id, 870
870 QL_FILE, &result->qr_vals[pos+1]); 871 if (skiplast == 0) {
 872 result->qr_keys[pos].qk_idtype = idtype;
 873 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES;
 874 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id,
 875 QL_FILE, &result->qr_vals[pos]);
 876 pos++;
 877 }
871 878
872 return 0; 879 return 0;
873} 880}
874 881
875static int 882static int
876quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, 883quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
877 struct quotaval *ret) 884 struct quotaval *ret)
878{ 885{
879 struct dquot *dq; 886 struct dquot *dq;
880 int error; 887 int error;
881 struct quota2_entry *q2ep, q2e; 888 struct quota2_entry *q2ep, q2e;
882 struct buf *bp; 889 struct buf *bp;
883 const int needswap = UFS_MPNEEDSWAP(ump); 890 const int needswap = UFS_MPNEEDSWAP(ump);
884 id_t id2; 891 id_t id2;
885 892
886 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); 893 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
887 if (error) 894 if (error)
888 return error; 895 return error;
889 896
890 mutex_enter(&dq->dq_interlock); 897 mutex_enter(&dq->dq_interlock);
891 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 898 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
892 mutex_exit(&dq->dq_interlock); 899 mutex_exit(&dq->dq_interlock);
893 dqrele(NULLVP, dq); 900 dqrele(NULLVP, dq);
894 return ENOENT; 901 return ENOENT;
895 } 902 }
896 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,
897 &bp, &q2ep, 0); 904 &bp, &q2ep, 0);
898 if (error) { 905 if (error) {
899 mutex_exit(&dq->dq_interlock); 906 mutex_exit(&dq->dq_interlock);
900 dqrele(NULLVP, dq); 907 dqrele(NULLVP, dq);
901 return error; 908 return error;
902 } 909 }
903 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 910 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
904 brelse(bp, 0); 911 brelse(bp, 0);
905 mutex_exit(&dq->dq_interlock); 912 mutex_exit(&dq->dq_interlock);
906 dqrele(NULLVP, dq); 913 dqrele(NULLVP, dq);
907 914
908 q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret); 915 q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret);
909 KASSERT(id2 == qk->qk_id); 916 KASSERT(id2 == qk->qk_id);
910 return 0; 917 return 0;
911} 918}
912 919
913int 920int
914quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk, 921quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk,
915 struct quotaval *ret) 922 struct quotaval *ret)
916{ 923{
917 int error; 924 int error;
918 struct quota2_header *q2h; 925 struct quota2_header *q2h;
919 struct quota2_entry q2e; 926 struct quota2_entry q2e;
920 struct buf *bp; 927 struct buf *bp;
921 const int needswap = UFS_MPNEEDSWAP(ump); 928 const int needswap = UFS_MPNEEDSWAP(ump);
922 id_t id2; 929 id_t id2;
923 930
924 /* 931 /*
925 * Make sure the FS-independent codes match the internal ones, 932 * Make sure the FS-independent codes match the internal ones,
926 * so we can use the passed-in objtype without having to 933 * so we can use the passed-in objtype without having to
927 * convert it explicitly to QL_BLOCK/QL_FILE. 934 * convert it explicitly to QL_BLOCK/QL_FILE.
928 */ 935 */
929 CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS); 936 CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS);
930 CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES); 937 CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES);
931 CTASSERT(N_QL == 2); 938 CTASSERT(N_QL == 2);
932 939
933 if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) { 940 if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) {
934 return EINVAL; 941 return EINVAL;
935 } 942 }
936 943
937 if (ump->um_quotas[qk->qk_idtype] == NULLVP) 944 if (ump->um_quotas[qk->qk_idtype] == NULLVP)
938 return ENODEV; 945 return ENODEV;
939 if (qk->qk_id == QUOTA_DEFAULTID) { 946 if (qk->qk_id == QUOTA_DEFAULTID) {
940 mutex_enter(&dqlock); 947 mutex_enter(&dqlock);
941 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); 948 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0);
942 if (error) { 949 if (error) {
943 mutex_exit(&dqlock); 950 mutex_exit(&dqlock);
944 return error; 951 return error;
945 } 952 }
946 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 953 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
947 mutex_exit(&dqlock); 954 mutex_exit(&dqlock);
948 brelse(bp, 0); 955 brelse(bp, 0);
949 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, 956 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2,
950 qk->qk_objtype, ret); 957 qk->qk_objtype, ret);
951 (void)id2; 958 (void)id2;
952 } else 959 } else
953 error = quota2_fetch_q2e(ump, qk, ret); 960 error = quota2_fetch_q2e(ump, qk, ret);
954  961
955 return error; 962 return error;
956} 963}
957 964
958struct ufsq2_cursor { 965struct ufsq2_cursor {
959 uint32_t q2c_magic; /* magic number */ 966 uint32_t q2c_magic; /* magic number */
960 int q2c_hashsize; /* size of hash table at last go */ 967 int q2c_hashsize; /* size of hash table at last go */
961 968
962 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 */
963 int q2c_hashpos; /* slot to start at in hash table */ 970 int q2c_hashpos; /* slot to start at in hash table */
964 int q2c_uidpos; /* number of ids we've handled */ 971 int q2c_uidpos; /* number of ids we've handled */
965 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 */
966}; 973};
967 974
968#define Q2C_MAGIC (0xbeebe111) 975#define Q2C_MAGIC (0xbeebe111)
969 976
970#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0]) 977#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0])
971 978
972static int 979static int
973q2cursor_check(struct ufsq2_cursor *cursor) 980q2cursor_check(struct ufsq2_cursor *cursor)
974{ 981{
975 if (cursor->q2c_magic != Q2C_MAGIC) { 982 if (cursor->q2c_magic != Q2C_MAGIC) {
976 return EINVAL; 983 return EINVAL;
977 } 984 }
978 if (cursor->q2c_hashsize < 0) { 985 if (cursor->q2c_hashsize < 0) {
979 return EINVAL; 986 return EINVAL;
980 } 987 }
981 988
982 if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) { 989 if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) {
983 return EINVAL; 990 return EINVAL;
984 } 991 }
985 if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) { 992 if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) {
986 return EINVAL; 993 return EINVAL;
987 } 994 }
988 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) { 995 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) {
989 return EINVAL; 996 return EINVAL;
990 } 997 }
991 return 0; 998 return 0;
992} 999}
993 1000
994struct getuids { 1001struct getuids {
995 long nuids; /* number of uids in array */ 1002 long nuids; /* number of uids in array */
996 long size; /* size of array */ 1003 long size; /* size of array */
997 uid_t *uids; /* array of uids, dynamically allocated */ 1004 uid_t *uids; /* array of uids, dynamically allocated */
998 long skip; 1005 long skip;
999 long seen; 1006 long seen;
 1007 long limit;
1000}; 1008};
1001 1009
1002static int 1010static int
1003quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, 1011quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp,
1004 struct quota2_entry *q2ep, uint64_t off, void *v) 1012 struct quota2_entry *q2ep, uint64_t off, void *v)
1005{ 1013{
1006 struct getuids *gu = v; 1014 struct getuids *gu = v;
1007 uid_t *newuids; 1015 uid_t *newuids;
1008#ifdef FFS_EI 1016#ifdef FFS_EI
1009 const int needswap = UFS_MPNEEDSWAP(ump); 1017 const int needswap = UFS_MPNEEDSWAP(ump);
1010#endif 1018#endif
1011 1019
1012 if (gu->skip > 0) { 1020 if (gu->skip > 0) {
1013 gu->skip--; 1021 gu->skip--;
1014 return 0; 1022 return 0;
1015 } 1023 }
1016 if (gu->nuids == gu->size) { 1024 if (gu->nuids == gu->size) {
1017 newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP, 1025 newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP,
1018 M_WAITOK); 1026 M_WAITOK);
1019 if (newuids == NULL) { 1027 if (newuids == NULL) {
1020 free(gu->uids, M_TEMP); 1028 free(gu->uids, M_TEMP);
1021 return ENOMEM; 1029 return ENOMEM;
1022 } 1030 }
1023 gu->uids = newuids; 1031 gu->uids = newuids;
1024 gu->size += (PAGE_SIZE / sizeof(uid_t)); 1032 gu->size += (PAGE_SIZE / sizeof(uid_t));
1025 } 1033 }
1026 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); 1034 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap);
1027 gu->nuids++; 1035 gu->nuids++;
1028 gu->seen++; 1036 gu->seen++;
 1037 if (gu->nuids == gu->limit) {
 1038 return Q2WL_ABORT;
 1039 }
1029 return 0; 1040 return 0;
1030} 1041}
1031 1042
1032int 1043int
1033quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc, 1044quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc,
1034 int idtype, struct quota_getall_result *result) 1045 int idtype, struct quota_getall_result *result)
1035{ 1046{
1036 int error; 1047 int error;
1037 struct ufsq2_cursor *cursor; 1048 struct ufsq2_cursor *cursor;
1038 struct quota2_header *q2h; 1049 struct quota2_header *q2h;
1039 struct quota2_entry q2e; 1050 struct quota2_entry q2e;
1040 struct buf *hbp; 1051 struct buf *hbp;
1041 uint64_t offset; 1052 uint64_t offset;
1042 int i, j; 1053 int i, j;
1043 int quota2_hash_size; 1054 int quota2_hash_size;
1044 const int needswap = UFS_MPNEEDSWAP(ump); 1055 const int needswap = UFS_MPNEEDSWAP(ump);
1045 struct getuids gu; 1056 struct getuids gu;
1046 id_t junkid; 1057 id_t junkid;
1047 struct quotaval qv; 1058 struct quotaval qv;
1048 unsigned num, maxnum; 1059 unsigned num, maxnum;
 1060 int skipfirst, skiplast;
1049 1061
1050 cursor = Q2CURSOR(qkc); 1062 cursor = Q2CURSOR(qkc);
1051 error = q2cursor_check(cursor); 1063 error = q2cursor_check(cursor);
1052 if (error) { 1064 if (error) {
1053 return error; 1065 return error;
1054 } 1066 }
1055 1067
1056 if (ump->um_quotas[idtype] == NULLVP) { 1068 if (ump->um_quotas[idtype] == NULLVP) {
1057 return ENODEV; 1069 return ENODEV;
1058 } 1070 }
1059 1071
1060 mutex_enter(&dqlock); 1072 mutex_enter(&dqlock);
1061 error = getq2h(ump, idtype, &hbp, &q2h, 0); 1073 error = getq2h(ump, idtype, &hbp, &q2h, 0);
1062 if (error) { 1074 if (error) {
1063 mutex_exit(&dqlock); 1075 mutex_exit(&dqlock);
1064 return error; 1076 return error;
1065 } 1077 }
1066 1078
1067 if (cursor->q2c_defaults_done == 0) { 1079 if (cursor->q2c_defaults_done == 0) {
1068 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 1080 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
1069 if (cursor->q2c_blocks_done == 0) { 1081 if (cursor->q2c_blocks_done == 0) {
1070 q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv); 1082 q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv);
1071 result->qr_defblocks = qv; 1083 result->qr_defblocks = qv;
1072 cursor->q2c_blocks_done = 1; 1084 cursor->q2c_blocks_done = 1;
1073 } 1085 }
1074 if (cursor->q2c_blocks_done == 1) { 1086 if (cursor->q2c_blocks_done == 1) {
1075 q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv); 1087 q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv);
1076 result->qr_deffiles = qv; 1088 result->qr_deffiles = qv;
1077 cursor->q2c_blocks_done = 0; 1089 cursor->q2c_blocks_done = 0;
1078 cursor->q2c_defaults_done = 1; 1090 cursor->q2c_defaults_done = 1;
1079 } 1091 }
1080 } 1092 }
1081 1093
1082 /* 1094 /*
1083 * we can't directly get entries as we can't walk the list 1095 * we can't directly get entries as we can't walk the list
1084 * with qdlock and grab dq_interlock to read the entries 1096 * with qdlock and grab dq_interlock to read the entries
1085 * at the same time. So just walk the lists to build a list of uid, 1097 * at the same time. So just walk the lists to build a list of uid,
1086 * and then read entries for these uids 1098 * and then read entries for these uids
1087 */ 1099 */
1088 memset(&gu, 0, sizeof(gu)); 1100 memset(&gu, 0, sizeof(gu));
1089 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); 1101 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
1090 1102
1091 /* if the table size has changed, make the caller start over */ 1103 /* if the table size has changed, make the caller start over */
1092 if (cursor->q2c_hashsize == 0) { 1104 if (cursor->q2c_hashsize == 0) {
1093 cursor->q2c_hashsize = quota2_hash_size; 1105 cursor->q2c_hashsize = quota2_hash_size;
1094 } else if (cursor->q2c_hashsize != quota2_hash_size) { 1106 } else if (cursor->q2c_hashsize != quota2_hash_size) {
1095 error = EDEADLK; 1107 error = EDEADLK;
1096 goto fail; 1108 goto fail;
1097 } 1109 }
1098 1110
1099 gu.skip = cursor->q2c_uidpos; 1111 gu.skip = cursor->q2c_uidpos;
1100 gu.seen = 0; 1112 gu.seen = 0;
 1113 gu.limit = result->qr_max / 2;
 1114 if (gu.limit == 0 && result->qr_max > 0) {
 1115 gu.limit = 1;
 1116 }
1101 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { 1117 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) {
1102 offset = q2h->q2h_entries[i]; 1118 offset = q2h->q2h_entries[i];
1103 gu.seen = 0; 1119 gu.seen = 0;
1104 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, 1120 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu,
1105 quota2_getuids_callback); 1121 quota2_getuids_callback);
 1122 if (error == Q2WL_ABORT) {
 1123 /* got enough uids for now */
 1124 error = 0;
 1125 break;
 1126 }
1106 if (error) { 1127 if (error) {
1107 if (gu.uids != NULL) 1128 if (gu.uids != NULL)
1108 free(gu.uids, M_TEMP); 1129 free(gu.uids, M_TEMP);
1109 break; 1130 break;
1110 } 1131 }
1111 } 1132 }
1112 cursor->q2c_hashpos = i; 1133 cursor->q2c_hashpos = i;
1113 cursor->q2c_uidpos = gu.seen; 1134 cursor->q2c_uidpos = gu.seen;
1114 1135
1115fail: 1136fail:
1116 mutex_exit(&dqlock); 1137 mutex_exit(&dqlock);
1117 brelse(hbp, 0); 1138 brelse(hbp, 0);
1118 if (error) 1139 if (error)
1119 return error; 1140 return error;
1120 1141
1121 maxnum = gu.nuids*2; 1142 maxnum = gu.nuids*2;
1122 result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]), 1143 result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]),
1123 M_TEMP, M_WAITOK); 1144 M_TEMP, M_WAITOK);
1124 result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]), 1145 result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]),
1125 M_TEMP, M_WAITOK); 1146 M_TEMP, M_WAITOK);
1126 1147
 1148 /*
 1149 * If we've already sent back the blocks value for the first id,
 1150 * don't send it again (skipfirst).
 1151 *
 1152 * 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
 1154 * leave off the last result entry (skiplast).
 1155 */
 1156 skipfirst = (cursor->q2c_blocks_done != 0);
 1157 skiplast = skipfirst == 0 && (result->qr_max < maxnum);
1127 num = 0; 1158 num = 0;
1128 for (j = 0; j < gu.nuids; j++) { 1159 for (j = 0; j < gu.nuids; j++) {
1129 error = quota2_result_add_q2e(ump, idtype, 1160 error = quota2_result_add_q2e(ump, idtype,
1130 gu.uids[j], result, j*2); 1161 gu.uids[j], result, j*2,
 1162 j == 0 && skipfirst,
 1163 j + 1 == gu.nuids && skiplast);
1131 if (error == ENOENT) 1164 if (error == ENOENT)
1132 continue; 1165 continue;
1133 if (error) 1166 if (error)
1134 break; 1167 break;
1135 num += 2; 1168 num += 2;
1136 } 1169 }
1137 result->qr_num = num; 1170 result->qr_num = num;
1138 1171
 1172 cursor->q2c_blocks_done = skiplast;
 1173
1139 free(gu.uids, M_TEMP); 1174 free(gu.uids, M_TEMP);
1140 return error; 1175 return error;
1141} 1176}
1142 1177
1143int 1178int
1144quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) 1179quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc)
1145{ 1180{
1146 struct ufsq2_cursor *cursor; 1181 struct ufsq2_cursor *cursor;
1147 1182
1148 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); 1183 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space));
1149 cursor = Q2CURSOR(qkc); 1184 cursor = Q2CURSOR(qkc);
1150 1185
1151 cursor->q2c_magic = Q2C_MAGIC; 1186 cursor->q2c_magic = Q2C_MAGIC;
1152 cursor->q2c_hashsize = 0; 1187 cursor->q2c_hashsize = 0;
1153 1188
1154 cursor->q2c_defaults_done = 0; 1189 cursor->q2c_defaults_done = 0;
1155 cursor->q2c_hashpos = 0; 1190 cursor->q2c_hashpos = 0;
1156 cursor->q2c_uidpos = 0; 1191 cursor->q2c_uidpos = 0;
1157 cursor->q2c_blocks_done = 0; 1192 cursor->q2c_blocks_done = 0;
1158 return 0; 1193 return 0;
1159} 1194}
1160 1195
1161int 1196int
1162quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc) 1197quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc)
1163{ 1198{
1164 struct ufsq2_cursor *cursor; 1199 struct ufsq2_cursor *cursor;
1165 int error; 1200 int error;
1166 1201
1167 cursor = Q2CURSOR(qkc); 1202 cursor = Q2CURSOR(qkc);
1168 error = q2cursor_check(cursor); 1203 error = q2cursor_check(cursor);
1169 if (error) { 1204 if (error) {
1170 return error; 1205 return error;
1171 } 1206 }
1172 1207
1173 /* nothing to do */ 1208 /* nothing to do */
1174 1209
1175 return 0; 1210 return 0;
1176} 1211}
1177 1212
1178int 1213int
1179q2sync(struct mount *mp) 1214q2sync(struct mount *mp)
1180{ 1215{
1181 return 0; 1216 return 0;
1182} 1217}
1183 1218
1184struct dq2get_callback { 1219struct dq2get_callback {
1185 uid_t id; 1220 uid_t id;
1186 struct dquot *dq; 1221 struct dquot *dq;
1187}; 1222};
1188 1223
1189static int 1224static int
1190dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, 1225dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e,
1191 uint64_t off, void *v) 1226 uint64_t off, void *v)
1192{ 1227{
1193 struct dq2get_callback *c = v; 1228 struct dq2get_callback *c = v;
1194 daddr_t lblkno; 1229 daddr_t lblkno;
1195 int blkoff; 1230 int blkoff;
1196#ifdef FFS_EI 1231#ifdef FFS_EI
1197 const int needswap = UFS_MPNEEDSWAP(ump); 1232 const int needswap = UFS_MPNEEDSWAP(ump);
1198#endif 1233#endif
1199 1234
1200 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { 1235 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
1201 KASSERT(mutex_owned(&c->dq->dq_interlock)); 1236 KASSERT(mutex_owned(&c->dq->dq_interlock));
1202 lblkno = (off >> ump->um_mountp->mnt_fs_bshift); 1237 lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
1203 blkoff = (off & ump->umq2_bmask); 1238 blkoff = (off & ump->umq2_bmask);
1204 c->dq->dq2_lblkno = lblkno; 1239 c->dq->dq2_lblkno = lblkno;
1205 c->dq->dq2_blkoff = blkoff; 1240 c->dq->dq2_blkoff = blkoff;
1206 return Q2WL_ABORT; 1241 return Q2WL_ABORT;
1207 } 1242 }
1208 return 0; 1243 return 0;
1209} 1244}
1210 1245
1211int 1246int
1212dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, 1247dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type,
1213 struct dquot *dq) 1248 struct dquot *dq)
1214{ 1249{
1215 struct buf *bp; 1250 struct buf *bp;
1216 struct quota2_header *q2h; 1251 struct quota2_header *q2h;
1217 int error; 1252 int error;
1218 daddr_t offset; 1253 daddr_t offset;
1219 u_long hash_mask; 1254 u_long hash_mask;
1220 struct dq2get_callback c = { 1255 struct dq2get_callback c = {
1221 .id = id, 1256 .id = id,
1222 .dq = dq 1257 .dq = dq
1223 }; 1258 };
1224 1259
1225 KASSERT(mutex_owned(&dq->dq_interlock)); 1260 KASSERT(mutex_owned(&dq->dq_interlock));
1226 mutex_enter(&dqlock); 1261 mutex_enter(&dqlock);
1227 error = getq2h(ump, type, &bp, &q2h, 0); 1262 error = getq2h(ump, type, &bp, &q2h, 0);
1228 if (error) 1263 if (error)
1229 goto out_mutex; 1264 goto out_mutex;
1230 /* look for our entry */ 1265 /* look for our entry */
1231 hash_mask = ((1 << q2h->q2h_hash_shift) - 1); 1266 hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
1232 offset = q2h->q2h_entries[id & hash_mask]; 1267 offset = q2h->q2h_entries[id & hash_mask];
1233 error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, 1268 error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c,
1234 dq2get_callback); 1269 dq2get_callback);
1235 brelse(bp, 0); 1270 brelse(bp, 0);
1236out_mutex: 1271out_mutex:
1237 mutex_exit(&dqlock); 1272 mutex_exit(&dqlock);
1238 return error; 1273 return error;
1239} 1274}
1240 1275
1241int 1276int
1242dq2sync(struct vnode *vp, struct dquot *dq) 1277dq2sync(struct vnode *vp, struct dquot *dq)
1243{ 1278{
1244 return 0; 1279 return 0;
1245} 1280}