Sun Jan 29 07:09:53 2012 UTC ()
Add QUOTACTL_CURSORSKIPIDTYPE, QUOTACTL_CURSORATEND, QUOTACTL_CURSORREWIND.

This change requires a kernel version bump.


(dholland)
diff -r1.28 -r1.29 src/sys/kern/vfs_quotactl.c
diff -r1.25 -r1.26 src/sys/sys/quotactl.h
diff -r1.97 -r1.98 src/sys/ufs/ufs/ufs_quota.c
diff -r1.19 -r1.20 src/sys/ufs/ufs/ufs_quota.h
diff -r1.25 -r1.26 src/sys/ufs/ufs/ufs_quota2.c

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

--- src/sys/kern/vfs_quotactl.c 2012/01/29 07:08:58 1.28
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 07:09:52 1.29
@@ -1,801 +1,801 @@ @@ -1,801 +1,801 @@
1/* $NetBSD: vfs_quotactl.c,v 1.28 2012/01/29 07:08:58 dholland Exp $ */ 1/* $NetBSD: vfs_quotactl.c,v 1.29 2012/01/29 07:09:52 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.28 2012/01/29 07:08:58 dholland Exp $"); 83__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.29 2012/01/29 07:09:52 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(const struct quotakey *key) 442vfs_quotactl_getall_makereply(const struct quotakey *key)
443{ 443{
444 prop_dictionary_t dict; 444 prop_dictionary_t dict;
445 id_t id; 445 id_t id;
446 int defaultq; 446 int defaultq;
447 447
448 dict = prop_dictionary_create(); 448 dict = prop_dictionary_create();
449 if (dict == NULL) 449 if (dict == NULL)
450 return NULL; 450 return NULL;
451 451
452 id = key->qk_id; 452 id = key->qk_id;
453 if (id == QUOTA_DEFAULTID) { 453 if (id == QUOTA_DEFAULTID) {
454 id = 0; 454 id = 0;
455 defaultq = 1; 455 defaultq = 1;
456 } else { 456 } else {
457 defaultq = 0; 457 defaultq = 0;
458 } 458 }
459 459
460 if (defaultq) { 460 if (defaultq) {
461 if (!prop_dictionary_set_cstring_nocopy(dict, "id", 461 if (!prop_dictionary_set_cstring_nocopy(dict, "id",
462 "default")) { 462 "default")) {
463 goto err; 463 goto err;
464 } 464 }
465 } else { 465 } else {
466 if (!prop_dictionary_set_uint32(dict, "id", id)) { 466 if (!prop_dictionary_set_uint32(dict, "id", id)) {
467 goto err; 467 goto err;
468 } 468 }
469 } 469 }
470 470
471 return dict; 471 return dict;
472 472
473err: 473err:
474 prop_object_release(dict); 474 prop_object_release(dict);
475 return NULL; 475 return NULL;
476} 476}
477 477
478static int 478static int
479vfs_quotactl_getall_addreply(prop_dictionary_t thisreply, 479vfs_quotactl_getall_addreply(prop_dictionary_t thisreply,
480 const struct quotakey *key, const struct quotaval *val) 480 const struct quotakey *key, const struct quotaval *val)
481{ 481{
482#define INITQVNAMES_ALL { \ 482#define INITQVNAMES_ALL { \
483 QUOTADICT_LIMIT_HARD, \ 483 QUOTADICT_LIMIT_HARD, \
484 QUOTADICT_LIMIT_SOFT, \ 484 QUOTADICT_LIMIT_SOFT, \
485 QUOTADICT_LIMIT_USAGE, \ 485 QUOTADICT_LIMIT_USAGE, \
486 QUOTADICT_LIMIT_ETIME, \ 486 QUOTADICT_LIMIT_ETIME, \
487 QUOTADICT_LIMIT_GTIME \ 487 QUOTADICT_LIMIT_GTIME \
488 } 488 }
489#define N_QV 5 489#define N_QV 5
490 490
491 const char *val_names[] = INITQVNAMES_ALL; 491 const char *val_names[] = INITQVNAMES_ALL;
492 uint64_t vals[N_QV]; 492 uint64_t vals[N_QV];
493 prop_dictionary_t dict2; 493 prop_dictionary_t dict2;
494 const char *objtypename; 494 const char *objtypename;
495 495
496 switch (key->qk_objtype) { 496 switch (key->qk_objtype) {
497 case QUOTA_OBJTYPE_BLOCKS: 497 case QUOTA_OBJTYPE_BLOCKS:
498 objtypename = QUOTADICT_LTYPE_BLOCK; 498 objtypename = QUOTADICT_LTYPE_BLOCK;
499 break; 499 break;
500 case QUOTA_OBJTYPE_FILES: 500 case QUOTA_OBJTYPE_FILES:
501 objtypename = QUOTADICT_LTYPE_FILE; 501 objtypename = QUOTADICT_LTYPE_FILE;
502 break; 502 break;
503 default: 503 default:
504 return EINVAL; 504 return EINVAL;
505 } 505 }
506 506
507 vals[0] = val->qv_hardlimit; 507 vals[0] = val->qv_hardlimit;
508 vals[1] = val->qv_softlimit; 508 vals[1] = val->qv_softlimit;
509 vals[2] = val->qv_usage; 509 vals[2] = val->qv_usage;
510 vals[3] = val->qv_expiretime; 510 vals[3] = val->qv_expiretime;
511 vals[4] = val->qv_grace; 511 vals[4] = val->qv_grace;
512 dict2 = limits64toprop(vals, val_names, N_QV); 512 dict2 = limits64toprop(vals, val_names, N_QV);
513 if (dict2 == NULL) 513 if (dict2 == NULL)
514 return ENOMEM; 514 return ENOMEM;
515 515
516 if (!prop_dictionary_set_and_rel(thisreply, objtypename, dict2)) 516 if (!prop_dictionary_set_and_rel(thisreply, objtypename, dict2))
517 return ENOMEM; 517 return ENOMEM;
518 518
519 return 0; 519 return 0;
520} 520}
521 521
522static int 522static int
523vfs_quotactl_getall(struct mount *mp, 523vfs_quotactl_getall(struct mount *mp,
524 prop_dictionary_t cmddict, int q2type, 524 prop_dictionary_t cmddict, int q2type,
525 prop_array_t datas) 525 prop_array_t datas)
526{ 526{
527 struct quotakcursor cursor; 527 struct quotakcursor cursor;
528 struct quotakey *keys; 528 struct quotakey *keys;
529 struct quotaval *vals; 529 struct quotaval *vals;
530 unsigned loopmax = 8; 530 unsigned loopmax = 8;
531 unsigned loopnum; 531 unsigned loopnum;
532 struct vfs_quotactl_args args; 532 struct vfs_quotactl_args args;
533 prop_array_t replies; 533 prop_array_t replies;
534 struct quotakey *key; 534 struct quotakey *key;
535 struct quotaval *val; 535 struct quotaval *val;
536 id_t lastid; 536 id_t lastid;
537 prop_dictionary_t thisreply; 537 prop_dictionary_t thisreply;
538 unsigned i; 538 unsigned i;
539 int error, error2; 539 int error, error2;
540 540
541 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 541 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
542 542
543 args.qc_type = QCT_CURSOROPEN; 543 args.qc_type = QCT_CURSOROPEN;
544 args.u.cursoropen.qc_cursor = &cursor; 544 args.u.cursoropen.qc_cursor = &cursor;
545 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args); 545 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args);
546 if (error) { 546 if (error) {
547 return error; 547 return error;
548 } 548 }
549 549
550 keys = malloc(loopmax * sizeof(keys[0]), M_TEMP, M_WAITOK); 550 keys = malloc(loopmax * sizeof(keys[0]), M_TEMP, M_WAITOK);
551 vals = malloc(loopmax * sizeof(vals[0]), M_TEMP, M_WAITOK); 551 vals = malloc(loopmax * sizeof(vals[0]), M_TEMP, M_WAITOK);
552 552
553 replies = prop_array_create(); 553 replies = prop_array_create();
554 if (replies == NULL) { 554 if (replies == NULL) {
555 error = ENOMEM; 555 error = ENOMEM;
556 goto err; 556 goto err;
557 } 557 }
558 558
559 thisreply = NULL; 559 thisreply = NULL;
560 lastid = 0; /* value not actually referenced */ 560 lastid = 0; /* value not actually referenced */
561 561
562 while (1) { 562 while (1) {
563 args.qc_type = QCT_GETALL; 563 args.qc_type = QCT_CURSORGET;
564 args.u.getall.qc_cursor = &cursor; 564 args.u.cursorget.qc_cursor = &cursor;
565 args.u.getall.qc_keys = keys; 565 args.u.cursorget.qc_keys = keys;
566 args.u.getall.qc_vals = vals; 566 args.u.cursorget.qc_vals = vals;
567 args.u.getall.qc_maxnum = loopmax; 567 args.u.cursorget.qc_maxnum = loopmax;
568 args.u.getall.qc_ret = &loopnum; 568 args.u.cursorget.qc_ret = &loopnum;
569 569
570 error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args); 570 error = VFS_QUOTACTL(mp, QUOTACTL_CURSORGET, &args);
571 if (error) { 571 if (error) {
572 goto err; 572 goto err;
573 } 573 }
574 574
575 if (loopnum == 0) { 575 if (loopnum == 0) {
576 /* end of iteration */ 576 /* end of iteration */
577 break; 577 break;
578 } 578 }
579 579
580 for (i = 0; i < loopnum; i++) { 580 for (i = 0; i < loopnum; i++) {
581 key = &keys[i]; 581 key = &keys[i];
582 val = &vals[i]; 582 val = &vals[i];
583 583
584 if (key->qk_idtype != q2type) { 584 if (key->qk_idtype != q2type) {
585 /* don't want this result */ 585 /* don't want this result */
586 continue; 586 continue;
587 } 587 }
588 588
589 if (thisreply == NULL || key->qk_id != lastid) { 589 if (thisreply == NULL || key->qk_id != lastid) {
590 lastid = key->qk_id; 590 lastid = key->qk_id;
591 thisreply = vfs_quotactl_getall_makereply(key); 591 thisreply = vfs_quotactl_getall_makereply(key);
592 if (thisreply == NULL) { 592 if (thisreply == NULL) {
593 error = ENOMEM; 593 error = ENOMEM;
594 goto err; 594 goto err;
595 } 595 }
596 /* 596 /*
597 * Note: while we release our reference to 597 * Note: while we release our reference to
598 * thisreply here, we can (and do) continue to 598 * thisreply here, we can (and do) continue to
599 * use the pointer in the loop because the 599 * use the pointer in the loop because the
600 * copy attached to the replies array is not 600 * copy attached to the replies array is not
601 * going away. 601 * going away.
602 */ 602 */
603 if (!prop_array_add_and_rel(replies, 603 if (!prop_array_add_and_rel(replies,
604 thisreply)) { 604 thisreply)) {
605 error = ENOMEM; 605 error = ENOMEM;
606 goto err; 606 goto err;
607 } 607 }
608 } 608 }
609 609
610 error = vfs_quotactl_getall_addreply(thisreply, 610 error = vfs_quotactl_getall_addreply(thisreply,
611 key, val); 611 key, val);
612 if (error) { 612 if (error) {
613 goto err; 613 goto err;
614 } 614 }
615 } 615 }
616 } 616 }
617 617
618 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 618 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
619 error = ENOMEM; 619 error = ENOMEM;
620 goto err; 620 goto err;
621 } 621 }
622 622
623 error = 0; 623 error = 0;
624 err: 624 err:
625 free(keys, M_TEMP); 625 free(keys, M_TEMP);
626 free(vals, M_TEMP); 626 free(vals, M_TEMP);
627 627
628 args.qc_type = QCT_CURSORCLOSE; 628 args.qc_type = QCT_CURSORCLOSE;
629 args.u.cursorclose.qc_cursor = &cursor; 629 args.u.cursorclose.qc_cursor = &cursor;
630 error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args); 630 error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args);
631 631
632 if (error) { 632 if (error) {
633 return error; 633 return error;
634 } 634 }
635 error = error2; 635 error = error2;
636 return error; 636 return error;
637} 637}
638 638
639static int 639static int
640vfs_quotactl_clear(struct mount *mp, 640vfs_quotactl_clear(struct mount *mp,
641 prop_dictionary_t cmddict, int q2type, 641 prop_dictionary_t cmddict, int q2type,
642 prop_array_t datas) 642 prop_array_t datas)
643{ 643{
644 prop_array_t replies; 644 prop_array_t replies;
645 prop_object_iterator_t iter; 645 prop_object_iterator_t iter;
646 prop_dictionary_t data; 646 prop_dictionary_t data;
647 uint32_t id; 647 uint32_t id;
648 int defaultq; 648 int defaultq;
649 const char *idstr; 649 const char *idstr;
650 struct quotakey qk; 650 struct quotakey qk;
651 struct vfs_quotactl_args args; 651 struct vfs_quotactl_args args;
652 int error; 652 int error;
653 653
654 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 654 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
655 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 655 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
656 656
657 replies = prop_array_create(); 657 replies = prop_array_create();
658 if (replies == NULL) 658 if (replies == NULL)
659 return ENOMEM; 659 return ENOMEM;
660 660
661 iter = prop_array_iterator(datas); 661 iter = prop_array_iterator(datas);
662 if (iter == NULL) { 662 if (iter == NULL) {
663 prop_object_release(replies); 663 prop_object_release(replies);
664 return ENOMEM; 664 return ENOMEM;
665 } 665 }
666 666
667 while ((data = prop_object_iterator_next(iter)) != NULL) { 667 while ((data = prop_object_iterator_next(iter)) != NULL) {
668 if (!prop_dictionary_get_uint32(data, "id", &id)) { 668 if (!prop_dictionary_get_uint32(data, "id", &id)) {
669 if (!prop_dictionary_get_cstring_nocopy(data, "id", 669 if (!prop_dictionary_get_cstring_nocopy(data, "id",
670 &idstr)) 670 &idstr))
671 continue; 671 continue;
672 if (strcmp(idstr, "default")) 672 if (strcmp(idstr, "default"))
673 continue; 673 continue;
674 id = 0; 674 id = 0;
675 defaultq = 1; 675 defaultq = 1;
676 } else { 676 } else {
677 defaultq = 0; 677 defaultq = 0;
678 } 678 }
679 679
680 qk.qk_idtype = q2type; 680 qk.qk_idtype = q2type;
681 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 681 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
682 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 682 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
683 683
684 args.qc_type = QCT_DELETE; 684 args.qc_type = QCT_DELETE;
685 args.u.delete.qc_key = &qk; 685 args.u.delete.qc_key = &qk;
686 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); 686 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args);
687 if (error) { 687 if (error) {
688 goto err; 688 goto err;
689 } 689 }
690 690
691 qk.qk_idtype = q2type; 691 qk.qk_idtype = q2type;
692 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 692 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
693 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 693 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
694 694
695 args.qc_type = QCT_DELETE; 695 args.qc_type = QCT_DELETE;
696 args.u.delete.qc_key = &qk; 696 args.u.delete.qc_key = &qk;
697 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); 697 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args);
698 if (error) { 698 if (error) {
699 goto err; 699 goto err;
700 } 700 }
701 } 701 }
702 702
703 prop_object_iterator_release(iter); 703 prop_object_iterator_release(iter);
704 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 704 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
705 error = ENOMEM; 705 error = ENOMEM;
706 } else { 706 } else {
707 error = 0; 707 error = 0;
708 } 708 }
709 return error; 709 return error;
710err: 710err:
711 prop_object_iterator_release(iter); 711 prop_object_iterator_release(iter);
712 prop_object_release(replies); 712 prop_object_release(replies);
713 return error; 713 return error;
714} 714}
715 715
716static int 716static int
717vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) 717vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict)
718{ 718{
719 int error; 719 int error;
720 const char *cmd, *type; 720 const char *cmd, *type;
721 prop_array_t datas; 721 prop_array_t datas;
722 int q2type; 722 int q2type;
723 723
724 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) 724 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd))
725 return EINVAL; 725 return EINVAL;
726 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) 726 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type))
727 return EINVAL; 727 return EINVAL;
728 728
729 if (!strcmp(type, QUOTADICT_CLASS_USER)) { 729 if (!strcmp(type, QUOTADICT_CLASS_USER)) {
730 q2type = QUOTA_CLASS_USER; 730 q2type = QUOTA_CLASS_USER;
731 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { 731 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) {
732 q2type = QUOTA_CLASS_GROUP; 732 q2type = QUOTA_CLASS_GROUP;
733 } else { 733 } else {
734 /* XXX this is a bad errno for this case */ 734 /* XXX this is a bad errno for this case */
735 return EOPNOTSUPP; 735 return EOPNOTSUPP;
736 } 736 }
737 737
738 datas = prop_dictionary_get(cmddict, "data"); 738 datas = prop_dictionary_get(cmddict, "data");
739 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) 739 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY)
740 return EINVAL; 740 return EINVAL;
741 741
742 prop_object_retain(datas); 742 prop_object_retain(datas);
743 prop_dictionary_remove(cmddict, "data"); /* prepare for return */ 743 prop_dictionary_remove(cmddict, "data"); /* prepare for return */
744 744
745 if (strcmp(cmd, "get version") == 0) { 745 if (strcmp(cmd, "get version") == 0) {
746 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); 746 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas);
747 } else if (strcmp(cmd, "quotaon") == 0) { 747 } else if (strcmp(cmd, "quotaon") == 0) {
748 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); 748 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas);
749 } else if (strcmp(cmd, "quotaoff") == 0) { 749 } else if (strcmp(cmd, "quotaoff") == 0) {
750 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); 750 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas);
751 } else if (strcmp(cmd, "get") == 0) { 751 } else if (strcmp(cmd, "get") == 0) {
752 error = vfs_quotactl_get(mp, cmddict, q2type, datas); 752 error = vfs_quotactl_get(mp, cmddict, q2type, datas);
753 } else if (strcmp(cmd, "set") == 0) { 753 } else if (strcmp(cmd, "set") == 0) {
754 error = vfs_quotactl_put(mp, cmddict, q2type, datas); 754 error = vfs_quotactl_put(mp, cmddict, q2type, datas);
755 } else if (strcmp(cmd, "getall") == 0) { 755 } else if (strcmp(cmd, "getall") == 0) {
756 error = vfs_quotactl_getall(mp, cmddict, q2type, datas); 756 error = vfs_quotactl_getall(mp, cmddict, q2type, datas);
757 } else if (strcmp(cmd, "clear") == 0) { 757 } else if (strcmp(cmd, "clear") == 0) {
758 error = vfs_quotactl_clear(mp, cmddict, q2type, datas); 758 error = vfs_quotactl_clear(mp, cmddict, q2type, datas);
759 } else { 759 } else {
760 /* XXX this a bad errno for this case */ 760 /* XXX this a bad errno for this case */
761 error = EOPNOTSUPP; 761 error = EOPNOTSUPP;
762 } 762 }
763 763
764 error = (prop_dictionary_set_int8(cmddict, "return", 764 error = (prop_dictionary_set_int8(cmddict, "return",
765 error) ? 0 : ENOMEM); 765 error) ? 0 : ENOMEM);
766 prop_object_release(datas); 766 prop_object_release(datas);
767 767
768 return error; 768 return error;
769} 769}
770 770
771int 771int
772vfs_quotactl(struct mount *mp, prop_dictionary_t dict) 772vfs_quotactl(struct mount *mp, prop_dictionary_t dict)
773{ 773{
774 prop_dictionary_t cmddict; 774 prop_dictionary_t cmddict;
775 prop_array_t commands; 775 prop_array_t commands;
776 prop_object_iterator_t iter; 776 prop_object_iterator_t iter;
777 int error; 777 int error;
778 778
779 error = quota_get_cmds(dict, &commands); 779 error = quota_get_cmds(dict, &commands);
780 if (error) { 780 if (error) {
781 return error; 781 return error;
782 } 782 }
783 783
784 iter = prop_array_iterator(commands); 784 iter = prop_array_iterator(commands);
785 if (iter == NULL) { 785 if (iter == NULL) {
786 return ENOMEM; 786 return ENOMEM;
787 } 787 }
788 788
789 while ((cmddict = prop_object_iterator_next(iter)) != NULL) { 789 while ((cmddict = prop_object_iterator_next(iter)) != NULL) {
790 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { 790 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) {
791 /* XXX shouldn't this be an error? */ 791 /* XXX shouldn't this be an error? */
792 continue; 792 continue;
793 } 793 }
794 error = vfs_quotactl_cmd(mp, cmddict); 794 error = vfs_quotactl_cmd(mp, cmddict);
795 if (error) { 795 if (error) {
796 break; 796 break;
797 } 797 }
798 } 798 }
799 prop_object_iterator_release(iter); 799 prop_object_iterator_release(iter);
800 return error; 800 return error;
801} 801}

cvs diff -r1.25 -r1.26 src/sys/sys/quotactl.h (switch to unified diff)

--- src/sys/sys/quotactl.h 2012/01/29 07:08:58 1.25
+++ src/sys/sys/quotactl.h 2012/01/29 07:09:52 1.26
@@ -1,114 +1,131 @@ @@ -1,114 +1,131 @@
1/* $NetBSD: quotactl.h,v 1.25 2012/01/29 07:08:58 dholland Exp $ */ 1/* $NetBSD: quotactl.h,v 1.26 2012/01/29 07:09:52 dholland Exp $ */
2/*- 2/*-
3 * Copyright (c) 2011 The NetBSD Foundation, Inc. 3 * Copyright (c) 2011 The NetBSD Foundation, Inc.
4 * All rights reserved. 4 * All rights reserved.
5 * 5 *
6 * This code is derived from software contributed to The NetBSD Foundation 6 * This code is derived from software contributed to The NetBSD Foundation
7 * by David A. Holland. 7 * by David A. Holland.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the 15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution. 16 * documentation and/or other materials provided with the distribution.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE. 28 * POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31#ifndef _SYS_QUOTACTL_H_ 31#ifndef _SYS_QUOTACTL_H_
32#define _SYS_QUOTACTL_H_ 32#define _SYS_QUOTACTL_H_
33 33
34/* 34/*
35 * Note - this is an internal interface. Application code (and, 35 * Note - this is an internal interface. Application code (and,
36 * really, anything that isn't libquota or inside the kernel) should 36 * really, anything that isn't libquota or inside the kernel) should
37 * use the <quota.h> API instead. 37 * use the <quota.h> API instead.
38 */ 38 */
39 39
40/* 40/*
41 * Semi-opaque structure for cursors. This holds the cursor state in 41 * Semi-opaque structure for cursors. This holds the cursor state in
42 * userland; the size is exposed only to libquota, not to client code, 42 * userland; the size is exposed only to libquota, not to client code,
43 * and is meant to be large enough to accomodate all likely future 43 * and is meant to be large enough to accomodate all likely future
44 * expansion without being unduly bloated, as it will need to be 44 * expansion without being unduly bloated, as it will need to be
45 * copied in and out for every call using it. 45 * copied in and out for every call using it.
46 */ 46 */
47struct quotakcursor { 47struct quotakcursor {
48 union { 48 union {
49 char qkc_space[64]; 49 char qkc_space[64];
50 uintmax_t __qkc_forcealign; 50 uintmax_t __qkc_forcealign;
51 } u; 51 } u;
52}; 52};
53 53
54/* Command codes. */ 54/* Command codes. */
55#define QUOTACTL_GETVERSION 0 55#define QUOTACTL_GETVERSION 0
56#define QUOTACTL_QUOTAON 1 56#define QUOTACTL_QUOTAON 1
57#define QUOTACTL_QUOTAOFF 2 57#define QUOTACTL_QUOTAOFF 2
58#define QUOTACTL_GET 3 58#define QUOTACTL_GET 3
59#define QUOTACTL_PUT 4 59#define QUOTACTL_PUT 4
60#define QUOTACTL_GETALL 5 60#define QUOTACTL_CURSORGET 5
61#define QUOTACTL_DELETE 6 61#define QUOTACTL_DELETE 6
62#define QUOTACTL_CURSOROPEN 7 62#define QUOTACTL_CURSOROPEN 7
63#define QUOTACTL_CURSORCLOSE 8 63#define QUOTACTL_CURSORCLOSE 8
 64#define QUOTACTL_CURSORSKIPIDTYPE 9
 65#define QUOTACTL_CURSORATEND 10
 66#define QUOTACTL_CURSORREWIND 11
64 67
65/* Argument encoding. */ 68/* Argument encoding. */
66enum vfs_quotactl_argtypes { 69enum vfs_quotactl_argtypes {
67 QCT_PROPLIB, /* quotaon/off */ 70 QCT_PROPLIB, /* quotaon/off */
68 QCT_GETVERSION, /* getversion */ 71 QCT_GETVERSION, /* getversion */
69 QCT_GET, /* get */ 72 QCT_GET, /* get */
70 QCT_PUT, /* put */ 73 QCT_PUT, /* put */
71 QCT_DELETE, /* delete */ 74 QCT_DELETE, /* delete */
72 QCT_CURSOROPEN, /* open cursor */ 75 QCT_CURSOROPEN, /* open cursor */
73 QCT_CURSORCLOSE,/* close cursor */ 76 QCT_CURSORCLOSE,/* close cursor */
74 QCT_GETALL, /* get all */ 77 QCT_CURSORGET, /* get from cursor */
 78 QCT_CURSORSKIPIDTYPE, /* iteration hint */
 79 QCT_CURSORATEND,/* test cursor */
 80 QCT_CURSORREWIND,/* reset cursor */
75}; 81};
76struct vfs_quotactl_args { 82struct vfs_quotactl_args {
77 enum vfs_quotactl_argtypes qc_type; 83 enum vfs_quotactl_argtypes qc_type;
78 union { 84 union {
79 struct { 85 struct {
80 prop_dictionary_t qc_cmddict; 86 prop_dictionary_t qc_cmddict;
81 int qc_q2type; 87 int qc_q2type;
82 prop_array_t qc_datas; 88 prop_array_t qc_datas;
83 } proplib; 89 } proplib;
84 struct { 90 struct {
85 int *qc_version_ret; 91 int *qc_version_ret;
86 } getversion; 92 } getversion;
87 struct { 93 struct {
88 const struct quotakey *qc_key; 94 const struct quotakey *qc_key;
89 struct quotaval *qc_ret; 95 struct quotaval *qc_ret;
90 } get; 96 } get;
91 struct { 97 struct {
92 const struct quotakey *qc_key; 98 const struct quotakey *qc_key;
93 const struct quotaval *qc_val; 99 const struct quotaval *qc_val;
94 } put; 100 } put;
95 struct { 101 struct {
96 const struct quotakey *qc_key; 102 const struct quotakey *qc_key;
97 } delete; 103 } delete;
98 struct { 104 struct {
99 struct quotakcursor *qc_cursor; 105 struct quotakcursor *qc_cursor;
100 } cursoropen; 106 } cursoropen;
101 struct { 107 struct {
102 struct quotakcursor *qc_cursor; 108 struct quotakcursor *qc_cursor;
103 } cursorclose; 109 } cursorclose;
104 struct { 110 struct {
105 struct quotakcursor *qc_cursor; 111 struct quotakcursor *qc_cursor;
 112 unsigned qc_idtype;
 113 } cursorskipidtype;
 114 struct {
 115 struct quotakcursor *qc_cursor;
106 struct quotakey *qc_keys; 116 struct quotakey *qc_keys;
107 struct quotaval *qc_vals; 117 struct quotaval *qc_vals;
108 unsigned qc_maxnum; 118 unsigned qc_maxnum;
109 unsigned *qc_ret; 119 unsigned *qc_ret;
110 } getall; 120 } cursorget;
 121 struct {
 122 struct quotakcursor *qc_cursor;
 123 int *qc_ret; /* really boolean */
 124 } cursoratend;
 125 struct {
 126 struct quotakcursor *qc_cursor;
 127 } cursorrewind;
111 } u; 128 } u;
112}; 129};
113 130
114#endif /* _SYS_QUOTACTL_H_ */ 131#endif /* _SYS_QUOTACTL_H_ */

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

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

cvs diff -r1.19 -r1.20 src/sys/ufs/ufs/ufs_quota.h (switch to unified diff)

--- src/sys/ufs/ufs/ufs_quota.h 2012/01/29 07:08:58 1.19
+++ src/sys/ufs/ufs/ufs_quota.h 2012/01/29 07:09:52 1.20
@@ -1,140 +1,145 @@ @@ -1,140 +1,145 @@
1/* $NetBSD: ufs_quota.h,v 1.19 2012/01/29 07:08:58 dholland Exp $ */ 1/* $NetBSD: ufs_quota.h,v 1.20 2012/01/29 07:09:52 dholland Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1982, 1986, 1990, 1993, 1995 4 * Copyright (c) 1982, 1986, 1990, 1993, 1995
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Robert Elz at The University of Melbourne. 8 * Robert Elz at The University of Melbourne.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 * 33 *
34 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 34 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
35 */ 35 */
36#include <ufs/ufs/quota1.h> 36#include <ufs/ufs/quota1.h>
37#include <ufs/ufs/quota2.h> 37#include <ufs/ufs/quota2.h>
38 38
39struct quotakcursor; /* from <sys/quotactl.h> */ 39struct quotakcursor; /* from <sys/quotactl.h> */
40 40
41 41
42/* link to this quota in the quota inode (for QUOTA2) */ 42/* link to this quota in the quota inode (for QUOTA2) */
43struct dq2_desc { 43struct dq2_desc {
44 uint64_t dq2_lblkno; /* logical disk block holding this quota */ 44 uint64_t dq2_lblkno; /* logical disk block holding this quota */
45 u_int dq2_blkoff; /* offset in disk block holding this quota */ 45 u_int dq2_blkoff; /* offset in disk block holding this quota */
46}; 46};
47 47
48/* 48/*
49 * The following structure records disk usage for a user or group on a 49 * The following structure records disk usage for a user or group on a
50 * filesystem. There is one allocated for each quota that exists on any 50 * filesystem. There is one allocated for each quota that exists on any
51 * filesystem for the current user or group. A cache is kept of recently 51 * filesystem for the current user or group. A cache is kept of recently
52 * used entries. 52 * used entries.
53 * Field markings and the corresponding locks: 53 * Field markings and the corresponding locks:
54 * h: dqlock 54 * h: dqlock
55 * d: dq_interlock 55 * d: dq_interlock
56 * 56 *
57 * Lock order is: dq_interlock -> dqlock 57 * Lock order is: dq_interlock -> dqlock
58 * dq_interlock -> dqvp 58 * dq_interlock -> dqvp
59 */ 59 */
60struct dquot { 60struct dquot {
61 LIST_ENTRY(dquot) dq_hash; /* h: hash list */ 61 LIST_ENTRY(dquot) dq_hash; /* h: hash list */
62 u_int16_t dq_flags; /* d: flags, see below */ 62 u_int16_t dq_flags; /* d: flags, see below */
63 u_int16_t dq_type; /* d: quota type of this dquot */ 63 u_int16_t dq_type; /* d: quota type of this dquot */
64 u_int32_t dq_cnt; /* h: count of active references */ 64 u_int32_t dq_cnt; /* h: count of active references */
65 u_int32_t dq_id; /* d: identifier this applies to */ 65 u_int32_t dq_id; /* d: identifier this applies to */
66 struct ufsmount *dq_ump; /* d: filesystem this is taken from */ 66 struct ufsmount *dq_ump; /* d: filesystem this is taken from */
67 kmutex_t dq_interlock; /* d: lock this dquot */ 67 kmutex_t dq_interlock; /* d: lock this dquot */
68 union { 68 union {
69 struct dqblk dq1_dqb; /* d: actual usage & quotas */ 69 struct dqblk dq1_dqb; /* d: actual usage & quotas */
70 struct dq2_desc dq2_desc; /* d: pointer to quota data */ 70 struct dq2_desc dq2_desc; /* d: pointer to quota data */
71 } dq_un; 71 } dq_un;
72}; 72};
73 73
74/* 74/*
75 * Flag values. 75 * Flag values.
76 */ 76 */
77#define DQ_MOD 0x04 /* this quota modified since read */ 77#define DQ_MOD 0x04 /* this quota modified since read */
78#define DQ_FAKE 0x08 /* no limits here, just usage */ 78#define DQ_FAKE 0x08 /* no limits here, just usage */
79#define DQ_WARN(ltype) (0x10 << ltype) /* has been warned about "type" limit */ 79#define DQ_WARN(ltype) (0x10 << ltype) /* has been warned about "type" limit */
80/* 80/*
81 * Shorthand notation. 81 * Shorthand notation.
82 */ 82 */
83#define dq_bhardlimit dq_un.dq1_dqb.dqb_bhardlimit 83#define dq_bhardlimit dq_un.dq1_dqb.dqb_bhardlimit
84#define dq_bsoftlimit dq_un.dq1_dqb.dqb_bsoftlimit 84#define dq_bsoftlimit dq_un.dq1_dqb.dqb_bsoftlimit
85#define dq_curblocks dq_un.dq1_dqb.dqb_curblocks 85#define dq_curblocks dq_un.dq1_dqb.dqb_curblocks
86#define dq_ihardlimit dq_un.dq1_dqb.dqb_ihardlimit 86#define dq_ihardlimit dq_un.dq1_dqb.dqb_ihardlimit
87#define dq_isoftlimit dq_un.dq1_dqb.dqb_isoftlimit 87#define dq_isoftlimit dq_un.dq1_dqb.dqb_isoftlimit
88#define dq_curinodes dq_un.dq1_dqb.dqb_curinodes 88#define dq_curinodes dq_un.dq1_dqb.dqb_curinodes
89#define dq_btime dq_un.dq1_dqb.dqb_btime 89#define dq_btime dq_un.dq1_dqb.dqb_btime
90#define dq_itime dq_un.dq1_dqb.dqb_itime 90#define dq_itime dq_un.dq1_dqb.dqb_itime
91 91
92#define dq2_lblkno dq_un.dq2_desc.dq2_lblkno 92#define dq2_lblkno dq_un.dq2_desc.dq2_lblkno
93#define dq2_blkoff dq_un.dq2_desc.dq2_blkoff 93#define dq2_blkoff dq_un.dq2_desc.dq2_blkoff
94/* 94/*
95 * If the system has never checked for a quota for this file, then it is 95 * If the system has never checked for a quota for this file, then it is
96 * set to NODQUOT. Once a write attempt is made the inode pointer is set 96 * set to NODQUOT. Once a write attempt is made the inode pointer is set
97 * to reference a dquot structure. 97 * to reference a dquot structure.
98 */ 98 */
99#define NODQUOT NULL 99#define NODQUOT NULL
100 100
101extern kmutex_t dqlock; 101extern kmutex_t dqlock;
102extern kcondvar_t dqcv; 102extern kcondvar_t dqcv;
103/* 103/*
104 * Quota name to error message mapping. 104 * Quota name to error message mapping.
105 */ 105 */
106const char *quotatypes[MAXQUOTAS]; 106const char *quotatypes[MAXQUOTAS];
107 107
108int getinoquota(struct inode *); 108int getinoquota(struct inode *);
109int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **); 109int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **);
110void dqref(struct dquot *); 110void dqref(struct dquot *);
111void dqrele(struct vnode *, struct dquot *); 111void dqrele(struct vnode *, struct dquot *);
112void dqflush(struct vnode *); 112void dqflush(struct vnode *);
113 113
114int chkdq1(struct inode *, int64_t, kauth_cred_t, int); 114int chkdq1(struct inode *, int64_t, kauth_cred_t, int);
115int chkiq1(struct inode *, int32_t, kauth_cred_t, int); 115int chkiq1(struct inode *, int32_t, kauth_cred_t, int);
116int q1sync(struct mount *); 116int q1sync(struct mount *);
117int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); 117int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
118int dq1sync(struct vnode *, struct dquot *); 118int dq1sync(struct vnode *, struct dquot *);
119int quota1_handle_cmd_get(struct ufsmount *, const struct quotakey *, 119int quota1_handle_cmd_get(struct ufsmount *, const struct quotakey *,
120 struct quotaval *); 120 struct quotaval *);
121int quota1_handle_cmd_put(struct ufsmount *, const struct quotakey *, 121int quota1_handle_cmd_put(struct ufsmount *, const struct quotakey *,
122 const struct quotaval *); 122 const struct quotaval *);
123int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int, 123int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int,
124 const char *); 124 const char *);
125int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int); 125int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int);
126 126
127int chkdq2(struct inode *, int64_t, kauth_cred_t, int); 127int chkdq2(struct inode *, int64_t, kauth_cred_t, int);
128int chkiq2(struct inode *, int32_t, kauth_cred_t, int); 128int chkiq2(struct inode *, int32_t, kauth_cred_t, int);
129int quota2_handle_cmd_get(struct ufsmount *, const struct quotakey *, 129int quota2_handle_cmd_get(struct ufsmount *, const struct quotakey *,
130 struct quotaval *); 130 struct quotaval *);
131int quota2_handle_cmd_put(struct ufsmount *, const struct quotakey *, 131int quota2_handle_cmd_put(struct ufsmount *, const struct quotakey *,
132 const struct quotaval *); 132 const struct quotaval *);
133int quota2_handle_cmd_delete(struct ufsmount *, const struct quotakey *); 133int quota2_handle_cmd_delete(struct ufsmount *, const struct quotakey *);
134int quota2_handle_cmd_getall(struct ufsmount *, struct quotakcursor *, 134int quota2_handle_cmd_cursorget(struct ufsmount *, struct quotakcursor *,
135 struct quotakey *, struct quotaval *, unsigned, unsigned *); 135 struct quotakey *, struct quotaval *, unsigned, unsigned *);
136int quota2_handle_cmd_cursoropen(struct ufsmount *, struct quotakcursor *); 136int quota2_handle_cmd_cursoropen(struct ufsmount *, struct quotakcursor *);
137int quota2_handle_cmd_cursorclose(struct ufsmount *, struct quotakcursor *); 137int quota2_handle_cmd_cursorclose(struct ufsmount *, struct quotakcursor *);
 138int quota2_handle_cmd_cursorskipidtype(struct ufsmount *, struct quotakcursor *,
 139 int);
 140int quota2_handle_cmd_cursoratend(struct ufsmount *, struct quotakcursor *,
 141 int *);
 142int quota2_handle_cmd_cursorrewind(struct ufsmount *, struct quotakcursor *);
138int q2sync(struct mount *); 143int q2sync(struct mount *);
139int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); 144int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
140int dq2sync(struct vnode *, struct dquot *); 145int dq2sync(struct vnode *, struct dquot *);

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

--- src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:08:58 1.25
+++ src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:09:52 1.26
@@ -1,1349 +1,1417 @@ @@ -1,1349 +1,1417 @@
1/* $NetBSD: ufs_quota2.c,v 1.25 2012/01/29 07:08:58 dholland Exp $ */ 1/* $NetBSD: ufs_quota2.c,v 1.26 2012/01/29 07:09:52 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.25 2012/01/29 07:08:58 dholland Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.26 2012/01/29 07:09:52 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 quotakey *keys, struct quotaval *vals, unsigned pos, 832 int id, struct quotakey *keys, struct quotaval *vals, unsigned pos,
833 int skipfirst, int skiplast) 833 int skipfirst, int skiplast)
834{ 834{
835 struct dquot *dq; 835 struct dquot *dq;
836 int error; 836 int error;
837 struct quota2_entry *q2ep, q2e; 837 struct quota2_entry *q2ep, q2e;
838 struct buf *bp; 838 struct buf *bp;
839 const int needswap = UFS_MPNEEDSWAP(ump); 839 const int needswap = UFS_MPNEEDSWAP(ump);
840 840
841 error = dqget(NULLVP, id, ump, idtype, &dq); 841 error = dqget(NULLVP, id, ump, idtype, &dq);
842 if (error) 842 if (error)
843 return error; 843 return error;
844 844
845 mutex_enter(&dq->dq_interlock); 845 mutex_enter(&dq->dq_interlock);
846 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 846 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
847 mutex_exit(&dq->dq_interlock); 847 mutex_exit(&dq->dq_interlock);
848 dqrele(NULLVP, dq); 848 dqrele(NULLVP, dq);
849 return ENOENT; 849 return ENOENT;
850 } 850 }
851 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, 851 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff,
852 &bp, &q2ep, 0); 852 &bp, &q2ep, 0);
853 if (error) { 853 if (error) {
854 mutex_exit(&dq->dq_interlock); 854 mutex_exit(&dq->dq_interlock);
855 dqrele(NULLVP, dq); 855 dqrele(NULLVP, dq);
856 return error; 856 return error;
857 } 857 }
858 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 858 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
859 brelse(bp, 0); 859 brelse(bp, 0);
860 mutex_exit(&dq->dq_interlock); 860 mutex_exit(&dq->dq_interlock);
861 dqrele(NULLVP, dq); 861 dqrele(NULLVP, dq);
862 862
863 if (skipfirst == 0) { 863 if (skipfirst == 0) {
864 keys[pos].qk_idtype = idtype; 864 keys[pos].qk_idtype = idtype;
865 keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS; 865 keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
866 q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id, 866 q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id,
867 QL_BLOCK, &vals[pos]); 867 QL_BLOCK, &vals[pos]);
868 pos++; 868 pos++;
869 } 869 }
870 870
871 if (skiplast == 0) { 871 if (skiplast == 0) {
872 keys[pos].qk_idtype = idtype; 872 keys[pos].qk_idtype = idtype;
873 keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES; 873 keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES;
874 q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id, 874 q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id,
875 QL_FILE, &vals[pos]); 875 QL_FILE, &vals[pos]);
876 pos++; 876 pos++;
877 } 877 }
878 878
879 return 0; 879 return 0;
880} 880}
881 881
882static int 882static int
883quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, 883quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
884 struct quotaval *ret) 884 struct quotaval *ret)
885{ 885{
886 struct dquot *dq; 886 struct dquot *dq;
887 int error; 887 int error;
888 struct quota2_entry *q2ep, q2e; 888 struct quota2_entry *q2ep, q2e;
889 struct buf *bp; 889 struct buf *bp;
890 const int needswap = UFS_MPNEEDSWAP(ump); 890 const int needswap = UFS_MPNEEDSWAP(ump);
891 id_t id2; 891 id_t id2;
892 892
893 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); 893 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
894 if (error) 894 if (error)
895 return error; 895 return error;
896 896
897 mutex_enter(&dq->dq_interlock); 897 mutex_enter(&dq->dq_interlock);
898 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 898 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
899 mutex_exit(&dq->dq_interlock); 899 mutex_exit(&dq->dq_interlock);
900 dqrele(NULLVP, dq); 900 dqrele(NULLVP, dq);
901 return ENOENT; 901 return ENOENT;
902 } 902 }
903 error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff, 903 error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff,
904 &bp, &q2ep, 0); 904 &bp, &q2ep, 0);
905 if (error) { 905 if (error) {
906 mutex_exit(&dq->dq_interlock); 906 mutex_exit(&dq->dq_interlock);
907 dqrele(NULLVP, dq); 907 dqrele(NULLVP, dq);
908 return error; 908 return error;
909 } 909 }
910 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 910 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
911 brelse(bp, 0); 911 brelse(bp, 0);
912 mutex_exit(&dq->dq_interlock); 912 mutex_exit(&dq->dq_interlock);
913 dqrele(NULLVP, dq); 913 dqrele(NULLVP, dq);
914 914
915 q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret); 915 q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret);
916 KASSERT(id2 == qk->qk_id); 916 KASSERT(id2 == qk->qk_id);
917 return 0; 917 return 0;
918} 918}
919 919
920int 920int
921quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk, 921quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk,
922 struct quotaval *ret) 922 struct quotaval *ret)
923{ 923{
924 int error; 924 int error;
925 struct quota2_header *q2h; 925 struct quota2_header *q2h;
926 struct quota2_entry q2e; 926 struct quota2_entry q2e;
927 struct buf *bp; 927 struct buf *bp;
928 const int needswap = UFS_MPNEEDSWAP(ump); 928 const int needswap = UFS_MPNEEDSWAP(ump);
929 id_t id2; 929 id_t id2;
930 930
931 /* 931 /*
932 * Make sure the FS-independent codes match the internal ones, 932 * Make sure the FS-independent codes match the internal ones,
933 * so we can use the passed-in objtype without having to 933 * so we can use the passed-in objtype without having to
934 * convert it explicitly to QL_BLOCK/QL_FILE. 934 * convert it explicitly to QL_BLOCK/QL_FILE.
935 */ 935 */
936 CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS); 936 CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS);
937 CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES); 937 CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES);
938 CTASSERT(N_QL == 2); 938 CTASSERT(N_QL == 2);
939 939
940 if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) { 940 if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) {
941 return EINVAL; 941 return EINVAL;
942 } 942 }
943 943
944 if (ump->um_quotas[qk->qk_idtype] == NULLVP) 944 if (ump->um_quotas[qk->qk_idtype] == NULLVP)
945 return ENODEV; 945 return ENODEV;
946 if (qk->qk_id == QUOTA_DEFAULTID) { 946 if (qk->qk_id == QUOTA_DEFAULTID) {
947 mutex_enter(&dqlock); 947 mutex_enter(&dqlock);
948 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); 948 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0);
949 if (error) { 949 if (error) {
950 mutex_exit(&dqlock); 950 mutex_exit(&dqlock);
951 return error; 951 return error;
952 } 952 }
953 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 953 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
954 mutex_exit(&dqlock); 954 mutex_exit(&dqlock);
955 brelse(bp, 0); 955 brelse(bp, 0);
956 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, 956 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2,
957 qk->qk_objtype, ret); 957 qk->qk_objtype, ret);
958 (void)id2; 958 (void)id2;
959 } else 959 } else
960 error = quota2_fetch_q2e(ump, qk, ret); 960 error = quota2_fetch_q2e(ump, qk, ret);
961  961
962 return error; 962 return error;
963} 963}
964 964
965struct ufsq2_cursor { 965struct ufsq2_cursor {
966 uint32_t q2c_magic; /* magic number */ 966 uint32_t q2c_magic; /* magic number */
967 int q2c_hashsize; /* size of hash table at last go */ 967 int q2c_hashsize; /* size of hash table at last go */
968 968
969 int q2c_users_done; /* true if we've returned all user data */ 969 int q2c_users_done; /* true if we've returned all user data */
970 int q2c_groups_done; /* true if we've returned all group data */ 970 int q2c_groups_done; /* true if we've returned all group data */
971 int q2c_defaults_done; /* true if we've returned the default values */ 971 int q2c_defaults_done; /* true if we've returned the default values */
972 int q2c_hashpos; /* slot to start at in hash table */ 972 int q2c_hashpos; /* slot to start at in hash table */
973 int q2c_uidpos; /* number of ids we've handled */ 973 int q2c_uidpos; /* number of ids we've handled */
974 int q2c_blocks_done; /* true if we've returned the blocks value */ 974 int q2c_blocks_done; /* true if we've returned the blocks value */
975}; 975};
976 976
977#define Q2C_MAGIC (0xbeebe111) 977#define Q2C_MAGIC (0xbeebe111)
978 978
979#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0]) 979#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0])
980 980
981static int 981static int
982q2cursor_check(struct ufsq2_cursor *cursor) 982q2cursor_check(struct ufsq2_cursor *cursor)
983{ 983{
984 if (cursor->q2c_magic != Q2C_MAGIC) { 984 if (cursor->q2c_magic != Q2C_MAGIC) {
985 return EINVAL; 985 return EINVAL;
986 } 986 }
987 if (cursor->q2c_hashsize < 0) { 987 if (cursor->q2c_hashsize < 0) {
988 return EINVAL; 988 return EINVAL;
989 } 989 }
990 990
991 if (cursor->q2c_users_done != 0 && cursor->q2c_users_done != 1) { 991 if (cursor->q2c_users_done != 0 && cursor->q2c_users_done != 1) {
992 return EINVAL; 992 return EINVAL;
993 } 993 }
994 if (cursor->q2c_groups_done != 0 && cursor->q2c_groups_done != 1) { 994 if (cursor->q2c_groups_done != 0 && cursor->q2c_groups_done != 1) {
995 return EINVAL; 995 return EINVAL;
996 } 996 }
997 if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) { 997 if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) {
998 return EINVAL; 998 return EINVAL;
999 } 999 }
1000 if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) { 1000 if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) {
1001 return EINVAL; 1001 return EINVAL;
1002 } 1002 }
1003 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) { 1003 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) {
1004 return EINVAL; 1004 return EINVAL;
1005 } 1005 }
1006 return 0; 1006 return 0;
1007} 1007}
1008 1008
1009struct getuids { 1009struct getuids {
1010 long nuids; /* number of uids in array */ 1010 long nuids; /* number of uids in array */
1011 long maxuids; /* number of uids allocated */ 1011 long maxuids; /* number of uids allocated */
1012 uid_t *uids; /* array of uids, dynamically allocated */ 1012 uid_t *uids; /* array of uids, dynamically allocated */
1013 long skip; 1013 long skip;
1014 long seen; 1014 long seen;
1015 long limit; 1015 long limit;
1016}; 1016};
1017 1017
1018static int 1018static int
1019quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, 1019quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp,
1020 struct quota2_entry *q2ep, uint64_t off, void *v) 1020 struct quota2_entry *q2ep, uint64_t off, void *v)
1021{ 1021{
1022 struct getuids *gu = v; 1022 struct getuids *gu = v;
1023 uid_t *newuids; 1023 uid_t *newuids;
1024 long newmax; 1024 long newmax;
1025#ifdef FFS_EI 1025#ifdef FFS_EI
1026 const int needswap = UFS_MPNEEDSWAP(ump); 1026 const int needswap = UFS_MPNEEDSWAP(ump);
1027#endif 1027#endif
1028 1028
1029 if (gu->skip > 0) { 1029 if (gu->skip > 0) {
1030 gu->skip--; 1030 gu->skip--;
1031 return 0; 1031 return 0;
1032 } 1032 }
1033 if (gu->nuids == gu->maxuids) { 1033 if (gu->nuids == gu->maxuids) {
1034 newmax = gu->maxuids + PAGE_SIZE / sizeof(uid_t); 1034 newmax = gu->maxuids + PAGE_SIZE / sizeof(uid_t);
1035 newuids = realloc(gu->uids, newmax * sizeof(gu->uids[0]), 1035 newuids = realloc(gu->uids, newmax * sizeof(gu->uids[0]),
1036 M_TEMP, M_WAITOK); 1036 M_TEMP, M_WAITOK);
1037 if (newuids == NULL) { 1037 if (newuids == NULL) {
1038 return ENOMEM; 1038 return ENOMEM;
1039 } 1039 }
1040 gu->uids = newuids; 1040 gu->uids = newuids;
1041 gu->maxuids = newmax; 1041 gu->maxuids = newmax;
1042 } 1042 }
1043 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); 1043 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap);
1044 gu->nuids++; 1044 gu->nuids++;
1045 gu->seen++; 1045 gu->seen++;
1046 if (gu->nuids == gu->limit) { 1046 if (gu->nuids == gu->limit) {
1047 return Q2WL_ABORT; 1047 return Q2WL_ABORT;
1048 } 1048 }
1049 return 0; 1049 return 0;
1050} 1050}
1051 1051
1052int 1052int
1053quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc, 1053quota2_handle_cmd_cursorget(struct ufsmount *ump, struct quotakcursor *qkc,
1054 struct quotakey *keys, struct quotaval *vals, unsigned maxreturn, 1054 struct quotakey *keys, struct quotaval *vals, unsigned maxreturn,
1055 unsigned *ret) 1055 unsigned *ret)
1056{ 1056{
1057 int error; 1057 int error;
1058 struct ufsq2_cursor *cursor; 1058 struct ufsq2_cursor *cursor;
1059 struct quota2_header *q2h; 1059 struct quota2_header *q2h;
1060 struct quota2_entry q2e; 1060 struct quota2_entry q2e;
1061 struct buf *hbp; 1061 struct buf *hbp;
1062 uint64_t offset; 1062 uint64_t offset;
1063 int idtype; 1063 int idtype;
1064 int can_switch_idtype; 1064 int can_switch_idtype;
1065 int i, j; 1065 int i, j;
1066 int quota2_hash_size; 1066 int quota2_hash_size;
1067 const int needswap = UFS_MPNEEDSWAP(ump); 1067 const int needswap = UFS_MPNEEDSWAP(ump);
1068 struct getuids gu; 1068 struct getuids gu;
1069 long excess; 1069 long excess;
1070 id_t junkid; 1070 id_t junkid;
1071 struct quotaval qv; 1071 struct quotaval qv;
1072 unsigned num, maxnum; 1072 unsigned num, maxnum;
1073 int skipfirst, skiplast; 1073 int skipfirst, skiplast;
1074 int numreturn; 1074 int numreturn;
1075 1075
1076 cursor = Q2CURSOR(qkc); 1076 cursor = Q2CURSOR(qkc);
1077 error = q2cursor_check(cursor); 1077 error = q2cursor_check(cursor);
1078 if (error) { 1078 if (error) {
1079 return error; 1079 return error;
1080 } 1080 }
1081 1081
1082 CTASSERT(USRQUOTA == QUOTA_IDTYPE_USER); 1082 CTASSERT(USRQUOTA == QUOTA_IDTYPE_USER);
1083 CTASSERT(GRPQUOTA == QUOTA_IDTYPE_GROUP); 1083 CTASSERT(GRPQUOTA == QUOTA_IDTYPE_GROUP);
1084 1084
1085 if (cursor->q2c_users_done == 0 && 1085 if (cursor->q2c_users_done == 0 &&
1086 ump->um_quotas[USRQUOTA] == NULLVP) { 1086 ump->um_quotas[USRQUOTA] == NULLVP) {
1087 cursor->q2c_users_done = 1; 1087 cursor->q2c_users_done = 1;
1088 } 1088 }
1089 if (cursor->q2c_groups_done == 0 && 1089 if (cursor->q2c_groups_done == 0 &&
1090 ump->um_quotas[GRPQUOTA] == NULLVP) { 1090 ump->um_quotas[GRPQUOTA] == NULLVP) {
1091 cursor->q2c_groups_done = 1; 1091 cursor->q2c_groups_done = 1;
1092 } 1092 }
1093 1093
1094restart: 1094restart:
1095 1095
1096 if (cursor->q2c_users_done == 0) { 1096 if (cursor->q2c_users_done == 0) {
1097 idtype = QUOTA_IDTYPE_USER; 1097 idtype = QUOTA_IDTYPE_USER;
1098 can_switch_idtype = 1; 1098 can_switch_idtype = 1;
1099 } else if (cursor->q2c_groups_done == 0) { 1099 } else if (cursor->q2c_groups_done == 0) {
1100 idtype = QUOTA_IDTYPE_GROUP; 1100 idtype = QUOTA_IDTYPE_GROUP;
1101 can_switch_idtype = 0; 1101 can_switch_idtype = 0;
1102 } else { 1102 } else {
1103 /* nothing more to do, return 0 */ 1103 /* nothing more to do, return 0 */
1104 *ret = 0; 1104 *ret = 0;
1105 return 0; 1105 return 0;
1106 } 1106 }
1107 1107
1108 KASSERT(ump->um_quotas[idtype] != NULLVP); 1108 KASSERT(ump->um_quotas[idtype] != NULLVP);
1109 1109
1110 numreturn = 0; 1110 numreturn = 0;
1111 1111
1112 mutex_enter(&dqlock); 1112 mutex_enter(&dqlock);
1113 error = getq2h(ump, idtype, &hbp, &q2h, 0); 1113 error = getq2h(ump, idtype, &hbp, &q2h, 0);
1114 if (error) { 1114 if (error) {
1115 mutex_exit(&dqlock); 1115 mutex_exit(&dqlock);
1116 return error; 1116 return error;
1117 } 1117 }
1118 1118
1119 if (cursor->q2c_defaults_done == 0) { 1119 if (cursor->q2c_defaults_done == 0) {
1120 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 1120 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
1121 if (cursor->q2c_blocks_done == 0) { 1121 if (cursor->q2c_blocks_done == 0) {
1122 q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv); 1122 q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv);
1123 keys[numreturn].qk_idtype = idtype; 1123 keys[numreturn].qk_idtype = idtype;
1124 keys[numreturn].qk_id = QUOTA_DEFAULTID; 1124 keys[numreturn].qk_id = QUOTA_DEFAULTID;
1125 keys[numreturn].qk_objtype = QUOTA_OBJTYPE_BLOCKS; 1125 keys[numreturn].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
1126 vals[numreturn++] = qv; 1126 vals[numreturn++] = qv;
1127 cursor->q2c_blocks_done = 1; 1127 cursor->q2c_blocks_done = 1;
1128 } 1128 }
1129 if (cursor->q2c_blocks_done == 1) { 1129 if (cursor->q2c_blocks_done == 1) {
1130 q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv); 1130 q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv);
1131 keys[numreturn].qk_idtype = idtype; 1131 keys[numreturn].qk_idtype = idtype;
1132 keys[numreturn].qk_id = QUOTA_DEFAULTID; 1132 keys[numreturn].qk_id = QUOTA_DEFAULTID;
1133 keys[numreturn].qk_objtype = QUOTA_OBJTYPE_FILES; 1133 keys[numreturn].qk_objtype = QUOTA_OBJTYPE_FILES;
1134 vals[numreturn++] = qv; 1134 vals[numreturn++] = qv;
1135 cursor->q2c_blocks_done = 0; 1135 cursor->q2c_blocks_done = 0;
1136 cursor->q2c_defaults_done = 1; 1136 cursor->q2c_defaults_done = 1;
1137 } 1137 }
1138 } 1138 }
1139 1139
1140 /* 1140 /*
1141 * we can't directly get entries as we can't walk the list 1141 * we can't directly get entries as we can't walk the list
1142 * with qdlock and grab dq_interlock to read the entries 1142 * with qdlock and grab dq_interlock to read the entries
1143 * at the same time. So just walk the lists to build a list of uid, 1143 * at the same time. So just walk the lists to build a list of uid,
1144 * and then read entries for these uids 1144 * and then read entries for these uids
1145 */ 1145 */
1146 memset(&gu, 0, sizeof(gu)); 1146 memset(&gu, 0, sizeof(gu));
1147 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); 1147 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
1148 1148
1149 /* if the table size has changed, make the caller start over */ 1149 /* if the table size has changed, make the caller start over */
1150 if (cursor->q2c_hashsize == 0) { 1150 if (cursor->q2c_hashsize == 0) {
1151 cursor->q2c_hashsize = quota2_hash_size; 1151 cursor->q2c_hashsize = quota2_hash_size;
1152 } else if (cursor->q2c_hashsize != quota2_hash_size) { 1152 } else if (cursor->q2c_hashsize != quota2_hash_size) {
1153 error = EDEADLK; 1153 error = EDEADLK;
1154 goto fail; 1154 goto fail;
1155 } 1155 }
1156 1156
1157 gu.skip = cursor->q2c_uidpos; 1157 gu.skip = cursor->q2c_uidpos;
1158 gu.seen = 0; 1158 gu.seen = 0;
1159 gu.limit = (maxreturn - numreturn) / 2; 1159 gu.limit = (maxreturn - numreturn) / 2;
1160 if (gu.limit == 0 && (maxreturn - numreturn) > 0) { 1160 if (gu.limit == 0 && (maxreturn - numreturn) > 0) {
1161 gu.limit = 1; 1161 gu.limit = 1;
1162 } 1162 }
1163 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { 1163 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) {
1164 offset = q2h->q2h_entries[i]; 1164 offset = q2h->q2h_entries[i];
1165 gu.seen = 0; 1165 gu.seen = 0;
1166 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, 1166 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu,
1167 quota2_getuids_callback); 1167 quota2_getuids_callback);
1168 if (error && error != Q2WL_ABORT) { 1168 if (error && error != Q2WL_ABORT) {
1169 if (gu.uids != NULL) 1169 if (gu.uids != NULL)
1170 free(gu.uids, M_TEMP); 1170 free(gu.uids, M_TEMP);
1171 break; 1171 break;
1172 } 1172 }
1173 if (error == Q2WL_ABORT) { 1173 if (error == Q2WL_ABORT) {
1174 /* got enough uids for now */ 1174 /* got enough uids for now */
1175 error = 0; 1175 error = 0;
1176 } 1176 }
1177 if (gu.nuids > gu.limit) { 1177 if (gu.nuids > gu.limit) {
1178 excess = gu.nuids - gu.limit; 1178 excess = gu.nuids - gu.limit;
1179 KASSERT(excess < gu.seen); 1179 KASSERT(excess < gu.seen);
1180 gu.seen -= excess; 1180 gu.seen -= excess;
1181 gu.nuids -= excess; 1181 gu.nuids -= excess;
1182 } 1182 }
1183 if (gu.nuids == gu.limit) { 1183 if (gu.nuids == gu.limit) {
1184 break; 1184 break;
1185 } 1185 }
1186 } 1186 }
1187 KASSERT(gu.nuids <= gu.limit); 1187 KASSERT(gu.nuids <= gu.limit);
1188 cursor->q2c_hashpos = i; 1188 cursor->q2c_hashpos = i;
1189 cursor->q2c_uidpos = gu.seen; 1189 cursor->q2c_uidpos = gu.seen;
1190 1190
1191fail: 1191fail:
1192 mutex_exit(&dqlock); 1192 mutex_exit(&dqlock);
1193 brelse(hbp, 0); 1193 brelse(hbp, 0);
1194 if (error) 1194 if (error)
1195 return error; 1195 return error;
1196 1196
1197 if (gu.nuids == 0) { 1197 if (gu.nuids == 0) {
1198 if (idtype == QUOTA_IDTYPE_USER) 1198 if (idtype == QUOTA_IDTYPE_USER)
1199 cursor->q2c_users_done = 1; 1199 cursor->q2c_users_done = 1;
1200 else 1200 else
1201 cursor->q2c_groups_done = 1; 1201 cursor->q2c_groups_done = 1;
1202 if (can_switch_idtype) { 1202 if (can_switch_idtype) {
1203 goto restart; 1203 goto restart;
1204 } 1204 }
1205 } 1205 }
1206 1206
1207 maxnum = gu.nuids*2; 1207 maxnum = gu.nuids*2;
1208 1208
1209 /* 1209 /*
1210 * If we've already sent back the blocks value for the first id, 1210 * If we've already sent back the blocks value for the first id,
1211 * don't send it again (skipfirst). 1211 * don't send it again (skipfirst).
1212 * 1212 *
1213 * If we have an odd number of available result slots and we 1213 * If we have an odd number of available result slots and we
1214 * aren't going to skip the first result entry, we need to 1214 * aren't going to skip the first result entry, we need to
1215 * leave off the last result entry (skiplast). 1215 * leave off the last result entry (skiplast).
1216 */ 1216 */
1217 skipfirst = (cursor->q2c_blocks_done != 0); 1217 skipfirst = (cursor->q2c_blocks_done != 0);
1218 skiplast = skipfirst == 0 && (maxreturn < maxnum); 1218 skiplast = skipfirst == 0 && (maxreturn < maxnum);
1219 num = 0; 1219 num = 0;
1220 for (j = 0; j < gu.nuids; j++) { 1220 for (j = 0; j < gu.nuids; j++) {
1221 error = quota2_result_add_q2e(ump, idtype, 1221 error = quota2_result_add_q2e(ump, idtype,
1222 gu.uids[j], keys, vals, numreturn + j*2, 1222 gu.uids[j], keys, vals, numreturn + j*2,
1223 j == 0 && skipfirst, 1223 j == 0 && skipfirst,
1224 j + 1 == gu.nuids && skiplast); 1224 j + 1 == gu.nuids && skiplast);
1225 if (error == ENOENT) 1225 if (error == ENOENT)
1226 continue; 1226 continue;
1227 if (error) 1227 if (error)
1228 break; 1228 break;
1229 if ((j == 0 && skipfirst) || (j + 1 == gu.nuids && skiplast)) { 1229 if ((j == 0 && skipfirst) || (j + 1 == gu.nuids && skiplast)) {
1230 num += 1; 1230 num += 1;
1231 } else { 1231 } else {
1232 num += 2; 1232 num += 2;
1233 } 1233 }
1234 } 1234 }
1235 numreturn += num; 1235 numreturn += num;
1236 *ret = numreturn; 1236 *ret = numreturn;
1237 1237
1238 cursor->q2c_blocks_done = skiplast; 1238 cursor->q2c_blocks_done = skiplast;
1239 1239
1240 if (gu.uids != NULL) 1240 if (gu.uids != NULL)
1241 free(gu.uids, M_TEMP); 1241 free(gu.uids, M_TEMP);
1242 return error; 1242 return error;
1243} 1243}
1244 1244
1245int 1245int
1246quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) 1246quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc)
1247{ 1247{
1248 struct ufsq2_cursor *cursor; 1248 struct ufsq2_cursor *cursor;
1249 1249
1250 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); 1250 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space));
1251 cursor = Q2CURSOR(qkc); 1251 cursor = Q2CURSOR(qkc);
1252 1252
1253 cursor->q2c_magic = Q2C_MAGIC; 1253 cursor->q2c_magic = Q2C_MAGIC;
1254 cursor->q2c_hashsize = 0; 1254 cursor->q2c_hashsize = 0;
1255 1255
1256 cursor->q2c_users_done = 0; 1256 cursor->q2c_users_done = 0;
1257 cursor->q2c_groups_done = 0; 1257 cursor->q2c_groups_done = 0;
1258 cursor->q2c_defaults_done = 0; 1258 cursor->q2c_defaults_done = 0;
1259 cursor->q2c_hashpos = 0; 1259 cursor->q2c_hashpos = 0;
1260 cursor->q2c_uidpos = 0; 1260 cursor->q2c_uidpos = 0;
1261 cursor->q2c_blocks_done = 0; 1261 cursor->q2c_blocks_done = 0;
1262 return 0; 1262 return 0;
1263} 1263}
1264 1264
1265int 1265int
1266quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc) 1266quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc)
1267{ 1267{
1268 struct ufsq2_cursor *cursor; 1268 struct ufsq2_cursor *cursor;
1269 int error; 1269 int error;
1270 1270
1271 cursor = Q2CURSOR(qkc); 1271 cursor = Q2CURSOR(qkc);
1272 error = q2cursor_check(cursor); 1272 error = q2cursor_check(cursor);
1273 if (error) { 1273 if (error) {
1274 return error; 1274 return error;
1275 } 1275 }
1276 1276
1277 /* nothing to do */ 1277 /* nothing to do */
1278 1278
1279 return 0; 1279 return 0;
1280} 1280}
1281 1281
1282int 1282int
 1283quota2_handle_cmd_cursorskipidtype(struct ufsmount *ump,
 1284 struct quotakcursor *qkc, int idtype)
 1285{
 1286 struct ufsq2_cursor *cursor;
 1287 int error;
 1288
 1289 cursor = Q2CURSOR(qkc);
 1290 error = q2cursor_check(cursor);
 1291 if (error) {
 1292 return error;
 1293 }
 1294
 1295 switch (idtype) {
 1296 case QUOTA_IDTYPE_USER:
 1297 cursor->q2c_users_done = 1;
 1298 break;
 1299 case QUOTA_IDTYPE_GROUP:
 1300 cursor->q2c_groups_done = 1;
 1301 break;
 1302 default:
 1303 return EINVAL;
 1304 }
 1305
 1306 return 0;
 1307}
 1308
 1309int
 1310quota2_handle_cmd_cursoratend(struct ufsmount *ump, struct quotakcursor *qkc,
 1311 int *ret)
 1312{
 1313 struct ufsq2_cursor *cursor;
 1314 int error;
 1315
 1316 cursor = Q2CURSOR(qkc);
 1317 error = q2cursor_check(cursor);
 1318 if (error) {
 1319 return error;
 1320 }
 1321
 1322 *ret = (cursor->q2c_users_done && cursor->q2c_groups_done);
 1323 return 0;
 1324}
 1325
 1326int
 1327quota2_handle_cmd_cursorrewind(struct ufsmount *ump, struct quotakcursor *qkc)
 1328{
 1329 struct ufsq2_cursor *cursor;
 1330 int error;
 1331
 1332 cursor = Q2CURSOR(qkc);
 1333 error = q2cursor_check(cursor);
 1334 if (error) {
 1335 return error;
 1336 }
 1337
 1338 cursor->q2c_hashsize = 0;
 1339
 1340 cursor->q2c_users_done = 0;
 1341 cursor->q2c_groups_done = 0;
 1342 cursor->q2c_defaults_done = 0;
 1343 cursor->q2c_hashpos = 0;
 1344 cursor->q2c_uidpos = 0;
 1345 cursor->q2c_blocks_done = 0;
 1346
 1347 return 0;
 1348}
 1349
 1350int
1283q2sync(struct mount *mp) 1351q2sync(struct mount *mp)
1284{ 1352{
1285 return 0; 1353 return 0;
1286} 1354}
1287 1355
1288struct dq2get_callback { 1356struct dq2get_callback {
1289 uid_t id; 1357 uid_t id;
1290 struct dquot *dq; 1358 struct dquot *dq;
1291}; 1359};
1292 1360
1293static int 1361static int
1294dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, 1362dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e,
1295 uint64_t off, void *v) 1363 uint64_t off, void *v)
1296{ 1364{
1297 struct dq2get_callback *c = v; 1365 struct dq2get_callback *c = v;
1298 daddr_t lblkno; 1366 daddr_t lblkno;
1299 int blkoff; 1367 int blkoff;
1300#ifdef FFS_EI 1368#ifdef FFS_EI
1301 const int needswap = UFS_MPNEEDSWAP(ump); 1369 const int needswap = UFS_MPNEEDSWAP(ump);
1302#endif 1370#endif
1303 1371
1304 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { 1372 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
1305 KASSERT(mutex_owned(&c->dq->dq_interlock)); 1373 KASSERT(mutex_owned(&c->dq->dq_interlock));
1306 lblkno = (off >> ump->um_mountp->mnt_fs_bshift); 1374 lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
1307 blkoff = (off & ump->umq2_bmask); 1375 blkoff = (off & ump->umq2_bmask);
1308 c->dq->dq2_lblkno = lblkno; 1376 c->dq->dq2_lblkno = lblkno;
1309 c->dq->dq2_blkoff = blkoff; 1377 c->dq->dq2_blkoff = blkoff;
1310 return Q2WL_ABORT; 1378 return Q2WL_ABORT;
1311 } 1379 }
1312 return 0; 1380 return 0;
1313} 1381}
1314 1382
1315int 1383int
1316dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, 1384dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type,
1317 struct dquot *dq) 1385 struct dquot *dq)
1318{ 1386{
1319 struct buf *bp; 1387 struct buf *bp;
1320 struct quota2_header *q2h; 1388 struct quota2_header *q2h;
1321 int error; 1389 int error;
1322 daddr_t offset; 1390 daddr_t offset;
1323 u_long hash_mask; 1391 u_long hash_mask;
1324 struct dq2get_callback c = { 1392 struct dq2get_callback c = {
1325 .id = id, 1393 .id = id,
1326 .dq = dq 1394 .dq = dq
1327 }; 1395 };
1328 1396
1329 KASSERT(mutex_owned(&dq->dq_interlock)); 1397 KASSERT(mutex_owned(&dq->dq_interlock));
1330 mutex_enter(&dqlock); 1398 mutex_enter(&dqlock);
1331 error = getq2h(ump, type, &bp, &q2h, 0); 1399 error = getq2h(ump, type, &bp, &q2h, 0);
1332 if (error) 1400 if (error)
1333 goto out_mutex; 1401 goto out_mutex;
1334 /* look for our entry */ 1402 /* look for our entry */
1335 hash_mask = ((1 << q2h->q2h_hash_shift) - 1); 1403 hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
1336 offset = q2h->q2h_entries[id & hash_mask]; 1404 offset = q2h->q2h_entries[id & hash_mask];
1337 error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, 1405 error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c,
1338 dq2get_callback); 1406 dq2get_callback);
1339 brelse(bp, 0); 1407 brelse(bp, 0);
1340out_mutex: 1408out_mutex:
1341 mutex_exit(&dqlock); 1409 mutex_exit(&dqlock);
1342 return error; 1410 return error;
1343} 1411}
1344 1412
1345int 1413int
1346dq2sync(struct vnode *vp, struct dquot *dq) 1414dq2sync(struct vnode *vp, struct dquot *dq)
1347{ 1415{
1348 return 0; 1416 return 0;
1349} 1417}