Sun Jan 29 06:57:15 2012 UTC ()
Begin adding quota cursor/iteration interface to VFS_QUOTACTL.

Add struct quotakcursor.
Add QUOTACTL_CURSOROPEN and QUOTACTL_CURSORCLOSE operations.
Implement the plumbing for them.
Add trivial implementations of them for quota2.
(iteration is not supported on quota1 for the time being, just as
getall isn't)
Have the proplib interpreter open and close a cursor around doing
QUOTACTL_GETALL.

Note: this change requires a kernel version bump.


(dholland)
diff -r1.20 -r1.21 src/sys/kern/vfs_quotactl.c
diff -r1.18 -r1.19 src/sys/sys/quotactl.h
diff -r1.92 -r1.93 src/sys/ufs/ufs/ufs_quota.c
diff -r1.14 -r1.15 src/sys/ufs/ufs/ufs_quota.h
diff -r1.15 -r1.16 src/sys/ufs/ufs/ufs_quota2.c

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

--- src/sys/kern/vfs_quotactl.c 2012/01/29 06:55:44 1.20
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 06:57:15 1.21
@@ -1,616 +1,635 @@ @@ -1,616 +1,635 @@
1/* $NetBSD: vfs_quotactl.c,v 1.20 2012/01/29 06:55:44 dholland Exp $ */ 1/* $NetBSD: vfs_quotactl.c,v 1.21 2012/01/29 06:57:15 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.20 2012/01/29 06:55:44 dholland Exp $"); 83__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.21 2012/01/29 06:57:15 dholland Exp $");
84 84
85#include <sys/mount.h> 85#include <sys/mount.h>
86#include <sys/quota.h> 86#include <sys/quota.h>
87#include <sys/quotactl.h> 87#include <sys/quotactl.h>
88#include <quota/quotaprop.h> 88#include <quota/quotaprop.h>
89 89
90static int 90static int
91vfs_quotactl_getversion(struct mount *mp, 91vfs_quotactl_getversion(struct mount *mp,
92 prop_dictionary_t cmddict, int q2type, 92 prop_dictionary_t cmddict, int q2type,
93 prop_array_t datas) 93 prop_array_t datas)
94{ 94{
95 prop_array_t replies; 95 prop_array_t replies;
96 prop_dictionary_t data; 96 prop_dictionary_t data;
97 int q2version; 97 int q2version;
98 struct vfs_quotactl_args args; 98 struct vfs_quotactl_args args;
99 int error; 99 int error;
100 100
101 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 101 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
102 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 102 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
103 103
104 args.qc_type = QCT_GETVERSION; 104 args.qc_type = QCT_GETVERSION;
105 args.u.getversion.qc_version_ret = &q2version; 105 args.u.getversion.qc_version_ret = &q2version;
106 error = VFS_QUOTACTL(mp, QUOTACTL_GETVERSION, &args); 106 error = VFS_QUOTACTL(mp, QUOTACTL_GETVERSION, &args);
107 if (error) { 107 if (error) {
108 return error; 108 return error;
109 } 109 }
110 110
111 data = prop_dictionary_create(); 111 data = prop_dictionary_create();
112 if (data == NULL) { 112 if (data == NULL) {
113 return ENOMEM; 113 return ENOMEM;
114 } 114 }
115 115
116 if (!prop_dictionary_set_int8(data, "version", q2version)) { 116 if (!prop_dictionary_set_int8(data, "version", q2version)) {
117 prop_object_release(data); 117 prop_object_release(data);
118 return ENOMEM; 118 return ENOMEM;
119 } 119 }
120 120
121 replies = prop_array_create(); 121 replies = prop_array_create();
122 if (replies == NULL) { 122 if (replies == NULL) {
123 prop_object_release(data); 123 prop_object_release(data);
124 return ENOMEM; 124 return ENOMEM;
125 } 125 }
126 126
127 if (!prop_array_add_and_rel(replies, data)) { 127 if (!prop_array_add_and_rel(replies, data)) {
128 prop_object_release(data); 128 prop_object_release(data);
129 prop_object_release(replies); 129 prop_object_release(replies);
130 return ENOMEM; 130 return ENOMEM;
131 } 131 }
132 132
133 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 133 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
134 prop_object_release(replies); 134 prop_object_release(replies);
135 return ENOMEM; 135 return ENOMEM;
136 } 136 }
137 137
138 return error; 138 return error;
139} 139}
140 140
141static int 141static int
142vfs_quotactl_quotaon(struct mount *mp, 142vfs_quotactl_quotaon(struct mount *mp,
143 prop_dictionary_t cmddict, int q2type, 143 prop_dictionary_t cmddict, int q2type,
144 prop_array_t datas) 144 prop_array_t datas)
145{ 145{
146 struct vfs_quotactl_args args; 146 struct vfs_quotactl_args args;
147 147
148 args.qc_type = QCT_PROPLIB; 148 args.qc_type = QCT_PROPLIB;
149 args.u.proplib.qc_cmddict = cmddict; 149 args.u.proplib.qc_cmddict = cmddict;
150 args.u.proplib.qc_q2type = q2type; 150 args.u.proplib.qc_q2type = q2type;
151 args.u.proplib.qc_datas = datas; 151 args.u.proplib.qc_datas = datas;
152 return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args); 152 return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args);
153} 153}
154 154
155static int 155static int
156vfs_quotactl_quotaoff(struct mount *mp, 156vfs_quotactl_quotaoff(struct mount *mp,
157 prop_dictionary_t cmddict, int q2type, 157 prop_dictionary_t cmddict, int q2type,
158 prop_array_t datas) 158 prop_array_t datas)
159{ 159{
160 struct vfs_quotactl_args args; 160 struct vfs_quotactl_args args;
161 161
162 args.qc_type = QCT_PROPLIB; 162 args.qc_type = QCT_PROPLIB;
163 args.u.proplib.qc_cmddict = cmddict; 163 args.u.proplib.qc_cmddict = cmddict;
164 args.u.proplib.qc_q2type = q2type; 164 args.u.proplib.qc_q2type = q2type;
165 args.u.proplib.qc_datas = datas; 165 args.u.proplib.qc_datas = datas;
166 return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args); 166 return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args);
167} 167}
168 168
169static int 169static int
170vfs_quotactl_get_addreply(const struct quotakey *qk, 170vfs_quotactl_get_addreply(const struct quotakey *qk,
171 const struct quotaval *blocks, 171 const struct quotaval *blocks,
172 const struct quotaval *files, 172 const struct quotaval *files,
173 prop_array_t replies) 173 prop_array_t replies)
174{ 174{
175 prop_dictionary_t dict; 175 prop_dictionary_t dict;
176 id_t id; 176 id_t id;
177 int defaultq; 177 int defaultq;
178 uint64_t *valuesp[QUOTA_NLIMITS]; 178 uint64_t *valuesp[QUOTA_NLIMITS];
179 179
180 /* XXX illegal casts */ 180 /* XXX illegal casts */
181 valuesp[QUOTA_LIMIT_BLOCK] = (void *)(intptr_t)&blocks->qv_hardlimit; 181 valuesp[QUOTA_LIMIT_BLOCK] = (void *)(intptr_t)&blocks->qv_hardlimit;
182 valuesp[QUOTA_LIMIT_FILE] = (void *)(intptr_t)&files->qv_hardlimit; 182 valuesp[QUOTA_LIMIT_FILE] = (void *)(intptr_t)&files->qv_hardlimit;
183 183
184 if (qk->qk_id == QUOTA_DEFAULTID) { 184 if (qk->qk_id == QUOTA_DEFAULTID) {
185 id = 0; 185 id = 0;
186 defaultq = 1; 186 defaultq = 1;
187 } else { 187 } else {
188 id = qk->qk_id; 188 id = qk->qk_id;
189 defaultq = 0; 189 defaultq = 0;
190 } 190 }
191 191
192 dict = quota64toprop(id, defaultq, valuesp, 192 dict = quota64toprop(id, defaultq, valuesp,
193 ufs_quota_entry_names, UFS_QUOTA_NENTRIES, 193 ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
194 ufs_quota_limit_names, QUOTA_NLIMITS); 194 ufs_quota_limit_names, QUOTA_NLIMITS);
195 if (dict == NULL) 195 if (dict == NULL)
196 return ENOMEM; 196 return ENOMEM;
197 if (!prop_array_add_and_rel(replies, dict)) { 197 if (!prop_array_add_and_rel(replies, dict)) {
198 prop_object_release(dict); 198 prop_object_release(dict);
199 return ENOMEM; 199 return ENOMEM;
200 } 200 }
201 201
202 return 0; 202 return 0;
203} 203}
204 204
205static int 205static int
206vfs_quotactl_get(struct mount *mp, 206vfs_quotactl_get(struct mount *mp,
207 prop_dictionary_t cmddict, int idtype, 207 prop_dictionary_t cmddict, int idtype,
208 prop_array_t datas) 208 prop_array_t datas)
209{ 209{
210 prop_object_iterator_t iter; 210 prop_object_iterator_t iter;
211 prop_dictionary_t data; 211 prop_dictionary_t data;
212 prop_array_t replies; 212 prop_array_t replies;
213 uint32_t id; 213 uint32_t id;
214 const char *idstr; 214 const char *idstr;
215 struct vfs_quotactl_args args; 215 struct vfs_quotactl_args args;
216 struct quotakey qk; 216 struct quotakey qk;
217 struct quotaval blocks, files; 217 struct quotaval blocks, files;
218 int error; 218 int error;
219 219
220 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 220 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
221 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 221 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
222 222
223 replies = prop_array_create(); 223 replies = prop_array_create();
224 if (replies == NULL) { 224 if (replies == NULL) {
225 return ENOMEM; 225 return ENOMEM;
226 } 226 }
227 227
228 iter = prop_array_iterator(datas); 228 iter = prop_array_iterator(datas);
229 if (iter == NULL) { 229 if (iter == NULL) {
230 prop_object_release(replies); 230 prop_object_release(replies);
231 return ENOMEM; 231 return ENOMEM;
232 } 232 }
233 233
234 while ((data = prop_object_iterator_next(iter)) != NULL) { 234 while ((data = prop_object_iterator_next(iter)) != NULL) {
235 qk.qk_idtype = idtype; 235 qk.qk_idtype = idtype;
236 236
237 if (!prop_dictionary_get_uint32(data, "id", &id)) { 237 if (!prop_dictionary_get_uint32(data, "id", &id)) {
238 if (!prop_dictionary_get_cstring_nocopy(data, "id", 238 if (!prop_dictionary_get_cstring_nocopy(data, "id",
239 &idstr)) 239 &idstr))
240 continue; 240 continue;
241 if (strcmp(idstr, "default")) { 241 if (strcmp(idstr, "default")) {
242 error = EINVAL; 242 error = EINVAL;
243 goto fail; 243 goto fail;
244 } 244 }
245 qk.qk_id = QUOTA_DEFAULTID; 245 qk.qk_id = QUOTA_DEFAULTID;
246 } else { 246 } else {
247 qk.qk_id = id; 247 qk.qk_id = id;
248 } 248 }
249 249
250 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 250 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
251 251
252 args.qc_type = QCT_GET; 252 args.qc_type = QCT_GET;
253 args.u.get.qc_key = &qk; 253 args.u.get.qc_key = &qk;
254 args.u.get.qc_ret = &blocks; 254 args.u.get.qc_ret = &blocks;
255 error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); 255 error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args);
256 if (error == EPERM) { 256 if (error == EPERM) {
257 /* XXX does this make sense? */ 257 /* XXX does this make sense? */
258 continue; 258 continue;
259 } else if (error == ENOENT) { 259 } else if (error == ENOENT) {
260 /* XXX does *this* make sense? */ 260 /* XXX does *this* make sense? */
261 continue; 261 continue;
262 } else if (error) { 262 } else if (error) {
263 goto fail; 263 goto fail;
264 } 264 }
265 265
266 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 266 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
267 267
268 args.qc_type = QCT_GET; 268 args.qc_type = QCT_GET;
269 args.u.get.qc_key = &qk; 269 args.u.get.qc_key = &qk;
270 args.u.get.qc_ret = &files; 270 args.u.get.qc_ret = &files;
271 error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); 271 error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args);
272 if (error == EPERM) { 272 if (error == EPERM) {
273 /* XXX does this make sense? */ 273 /* XXX does this make sense? */
274 continue; 274 continue;
275 } else if (error == ENOENT) { 275 } else if (error == ENOENT) {
276 /* XXX does *this* make sense? */ 276 /* XXX does *this* make sense? */
277 continue; 277 continue;
278 } else if (error) { 278 } else if (error) {
279 goto fail; 279 goto fail;
280 } 280 }
281 281
282 error = vfs_quotactl_get_addreply(&qk, &blocks, &files, 282 error = vfs_quotactl_get_addreply(&qk, &blocks, &files,
283 replies); 283 replies);
284 } 284 }
285 285
286 prop_object_iterator_release(iter); 286 prop_object_iterator_release(iter);
287 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 287 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
288 error = ENOMEM; 288 error = ENOMEM;
289 } else { 289 } else {
290 error = 0; 290 error = 0;
291 } 291 }
292 292
293 return error; 293 return error;
294 294
295 fail: 295 fail:
296 prop_object_iterator_release(iter); 296 prop_object_iterator_release(iter);
297 prop_object_release(replies); 297 prop_object_release(replies);
298 return error; 298 return error;
299} 299}
300 300
301static int 301static int
302vfs_quotactl_put_extractinfo(prop_dictionary_t data, 302vfs_quotactl_put_extractinfo(prop_dictionary_t data,
303 struct quotaval *blocks, struct quotaval *files) 303 struct quotaval *blocks, struct quotaval *files)
304{ 304{
305 /* 305 /*
306 * So, the way proptoquota64 works is that you pass it an 306 * So, the way proptoquota64 works is that you pass it an
307 * array of pointers to uint64. Each of these pointers is 307 * array of pointers to uint64. Each of these pointers is
308 * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This 308 * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This
309 * array of pointers is the second argument. The third and 309 * array of pointers is the second argument. The third and
310 * forth argument are the names of the five values to extract, 310 * forth argument are the names of the five values to extract,
311 * and UFS_QUOTA_NENTRIES. The last two arguments are the 311 * and UFS_QUOTA_NENTRIES. The last two arguments are the
312 * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK, 312 * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK,
313 * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of 313 * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of
314 * the existing code was unsafely casting struct quotaval 314 * the existing code was unsafely casting struct quotaval
315 * (formerly struct ufs_quota_entry) to (uint64_t *) and using 315 * (formerly struct ufs_quota_entry) to (uint64_t *) and using
316 * that as the block of 5 uint64s. Or worse, pointing to 316 * that as the block of 5 uint64s. Or worse, pointing to
317 * subregions of that and reducing the number of uint64s to 317 * subregions of that and reducing the number of uint64s to
318 * pull "adjacent" values. Demons fly out of your nose! 318 * pull "adjacent" values. Demons fly out of your nose!
319 */ 319 */
320 320
321 uint64_t bvals[UFS_QUOTA_NENTRIES]; 321 uint64_t bvals[UFS_QUOTA_NENTRIES];
322 uint64_t fvals[UFS_QUOTA_NENTRIES]; 322 uint64_t fvals[UFS_QUOTA_NENTRIES];
323 uint64_t *valptrs[QUOTA_NLIMITS]; 323 uint64_t *valptrs[QUOTA_NLIMITS];
324 int error; 324 int error;
325 325
326 valptrs[QUOTA_LIMIT_BLOCK] = bvals; 326 valptrs[QUOTA_LIMIT_BLOCK] = bvals;
327 valptrs[QUOTA_LIMIT_FILE] = fvals; 327 valptrs[QUOTA_LIMIT_FILE] = fvals;
328 error = proptoquota64(data, valptrs, 328 error = proptoquota64(data, valptrs,
329 ufs_quota_entry_names, UFS_QUOTA_NENTRIES, 329 ufs_quota_entry_names, UFS_QUOTA_NENTRIES,
330 ufs_quota_limit_names, QUOTA_NLIMITS); 330 ufs_quota_limit_names, QUOTA_NLIMITS);
331 if (error) { 331 if (error) {
332 return error; 332 return error;
333 } 333 }
334 334
335 /* 335 /*
336 * There are no symbolic constants for these indexes! 336 * There are no symbolic constants for these indexes!
337 */ 337 */
338 338
339 blocks->qv_hardlimit = bvals[0]; 339 blocks->qv_hardlimit = bvals[0];
340 blocks->qv_softlimit = bvals[1]; 340 blocks->qv_softlimit = bvals[1];
341 blocks->qv_usage = bvals[2]; 341 blocks->qv_usage = bvals[2];
342 blocks->qv_expiretime = bvals[3]; 342 blocks->qv_expiretime = bvals[3];
343 blocks->qv_grace = bvals[4]; 343 blocks->qv_grace = bvals[4];
344 files->qv_hardlimit = fvals[0]; 344 files->qv_hardlimit = fvals[0];
345 files->qv_softlimit = fvals[1]; 345 files->qv_softlimit = fvals[1];
346 files->qv_usage = fvals[2]; 346 files->qv_usage = fvals[2];
347 files->qv_expiretime = fvals[3]; 347 files->qv_expiretime = fvals[3];
348 files->qv_grace = fvals[4]; 348 files->qv_grace = fvals[4];
349 349
350 return 0; 350 return 0;
351} 351}
352 352
353static int 353static int
354vfs_quotactl_put(struct mount *mp, 354vfs_quotactl_put(struct mount *mp,
355 prop_dictionary_t cmddict, int q2type, 355 prop_dictionary_t cmddict, int q2type,
356 prop_array_t datas) 356 prop_array_t datas)
357{ 357{
358 prop_array_t replies; 358 prop_array_t replies;
359 prop_object_iterator_t iter; 359 prop_object_iterator_t iter;
360 prop_dictionary_t data; 360 prop_dictionary_t data;
361 int defaultq; 361 int defaultq;
362 uint32_t id; 362 uint32_t id;
363 const char *idstr; 363 const char *idstr;
364 struct quotakey qk; 364 struct quotakey qk;
365 struct quotaval blocks, files; 365 struct quotaval blocks, files;
366 struct vfs_quotactl_args args; 366 struct vfs_quotactl_args args;
367 int error; 367 int error;
368 368
369 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 369 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
370 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 370 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
371 371
372 replies = prop_array_create(); 372 replies = prop_array_create();
373 if (replies == NULL) 373 if (replies == NULL)
374 return ENOMEM; 374 return ENOMEM;
375 375
376 iter = prop_array_iterator(datas); 376 iter = prop_array_iterator(datas);
377 if (iter == NULL) { 377 if (iter == NULL) {
378 prop_object_release(replies); 378 prop_object_release(replies);
379 return ENOMEM; 379 return ENOMEM;
380 } 380 }
381 381
382 while ((data = prop_object_iterator_next(iter)) != NULL) { 382 while ((data = prop_object_iterator_next(iter)) != NULL) {
383 383
384 KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY); 384 KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY);
385 385
386 if (!prop_dictionary_get_uint32(data, "id", &id)) { 386 if (!prop_dictionary_get_uint32(data, "id", &id)) {
387 if (!prop_dictionary_get_cstring_nocopy(data, "id", 387 if (!prop_dictionary_get_cstring_nocopy(data, "id",
388 &idstr)) 388 &idstr))
389 continue; 389 continue;
390 if (strcmp(idstr, "default")) 390 if (strcmp(idstr, "default"))
391 continue; 391 continue;
392 id = 0; 392 id = 0;
393 defaultq = 1; 393 defaultq = 1;
394 } else { 394 } else {
395 defaultq = 0; 395 defaultq = 0;
396 } 396 }
397 397
398 error = vfs_quotactl_put_extractinfo(data, &blocks, &files); 398 error = vfs_quotactl_put_extractinfo(data, &blocks, &files);
399 if (error) { 399 if (error) {
400 goto err; 400 goto err;
401 } 401 }
402 402
403 qk.qk_idtype = q2type; 403 qk.qk_idtype = q2type;
404 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 404 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
405 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 405 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
406 406
407 args.qc_type = QCT_PUT; 407 args.qc_type = QCT_PUT;
408 args.u.put.qc_key = &qk; 408 args.u.put.qc_key = &qk;
409 args.u.put.qc_val = &blocks; 409 args.u.put.qc_val = &blocks;
410 error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); 410 error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args);
411 if (error) { 411 if (error) {
412 goto err; 412 goto err;
413 } 413 }
414 414
415 qk.qk_idtype = q2type; 415 qk.qk_idtype = q2type;
416 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 416 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
417 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 417 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
418 418
419 args.qc_type = QCT_PUT; 419 args.qc_type = QCT_PUT;
420 args.u.put.qc_key = &qk; 420 args.u.put.qc_key = &qk;
421 args.u.put.qc_val = &files; 421 args.u.put.qc_val = &files;
422 error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); 422 error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args);
423 if (error) { 423 if (error) {
424 goto err; 424 goto err;
425 } 425 }
426 } 426 }
427 prop_object_iterator_release(iter); 427 prop_object_iterator_release(iter);
428 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 428 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
429 error = ENOMEM; 429 error = ENOMEM;
430 } else { 430 } else {
431 error = 0; 431 error = 0;
432 } 432 }
433 return error; 433 return error;
434err: 434err:
435 prop_object_iterator_release(iter); 435 prop_object_iterator_release(iter);
436 prop_object_release(replies); 436 prop_object_release(replies);
437 return error; 437 return error;
438} 438}
439 439
440static int 440static int
441vfs_quotactl_getall(struct mount *mp, 441vfs_quotactl_getall(struct mount *mp,
442 prop_dictionary_t cmddict, int q2type, 442 prop_dictionary_t cmddict, int q2type,
443 prop_array_t datas) 443 prop_array_t datas)
444{ 444{
 445 struct quotakcursor cursor;
445 struct vfs_quotactl_args args; 446 struct vfs_quotactl_args args;
 447 int error, error2;
 448
 449 args.qc_type = QCT_CURSOROPEN;
 450 args.u.cursoropen.qc_cursor = &cursor;
 451 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args);
 452 if (error) {
 453 return error;
 454 }
446 455
447 args.qc_type = QCT_PROPLIB; 456 args.qc_type = QCT_PROPLIB;
448 args.u.proplib.qc_cmddict = cmddict; 457 args.u.proplib.qc_cmddict = cmddict;
449 args.u.proplib.qc_q2type = q2type; 458 args.u.proplib.qc_q2type = q2type;
450 args.u.proplib.qc_datas = datas; 459 args.u.proplib.qc_datas = datas;
451 return VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args); 460 error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args);
 461
 462 args.qc_type = QCT_CURSORCLOSE;
 463 args.u.cursorclose.qc_cursor = &cursor;
 464 error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args);
 465
 466 if (error) {
 467 return error;
 468 }
 469 error = error2;
 470 return error;
452} 471}
453 472
454static int 473static int
455vfs_quotactl_clear(struct mount *mp, 474vfs_quotactl_clear(struct mount *mp,
456 prop_dictionary_t cmddict, int q2type, 475 prop_dictionary_t cmddict, int q2type,
457 prop_array_t datas) 476 prop_array_t datas)
458{ 477{
459 prop_array_t replies; 478 prop_array_t replies;
460 prop_object_iterator_t iter; 479 prop_object_iterator_t iter;
461 prop_dictionary_t data; 480 prop_dictionary_t data;
462 uint32_t id; 481 uint32_t id;
463 int defaultq; 482 int defaultq;
464 const char *idstr; 483 const char *idstr;
465 struct quotakey qk; 484 struct quotakey qk;
466 struct vfs_quotactl_args args; 485 struct vfs_quotactl_args args;
467 int error; 486 int error;
468 487
469 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 488 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
470 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 489 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
471 490
472 replies = prop_array_create(); 491 replies = prop_array_create();
473 if (replies == NULL) 492 if (replies == NULL)
474 return ENOMEM; 493 return ENOMEM;
475 494
476 iter = prop_array_iterator(datas); 495 iter = prop_array_iterator(datas);
477 if (iter == NULL) { 496 if (iter == NULL) {
478 prop_object_release(replies); 497 prop_object_release(replies);
479 return ENOMEM; 498 return ENOMEM;
480 } 499 }
481 500
482 while ((data = prop_object_iterator_next(iter)) != NULL) { 501 while ((data = prop_object_iterator_next(iter)) != NULL) {
483 if (!prop_dictionary_get_uint32(data, "id", &id)) { 502 if (!prop_dictionary_get_uint32(data, "id", &id)) {
484 if (!prop_dictionary_get_cstring_nocopy(data, "id", 503 if (!prop_dictionary_get_cstring_nocopy(data, "id",
485 &idstr)) 504 &idstr))
486 continue; 505 continue;
487 if (strcmp(idstr, "default")) 506 if (strcmp(idstr, "default"))
488 continue; 507 continue;
489 id = 0; 508 id = 0;
490 defaultq = 1; 509 defaultq = 1;
491 } else { 510 } else {
492 defaultq = 0; 511 defaultq = 0;
493 } 512 }
494 513
495 qk.qk_idtype = q2type; 514 qk.qk_idtype = q2type;
496 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 515 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
497 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; 516 qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
498 517
499 args.qc_type = QCT_DELETE; 518 args.qc_type = QCT_DELETE;
500 args.u.delete.qc_key = &qk; 519 args.u.delete.qc_key = &qk;
501 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); 520 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args);
502 if (error) { 521 if (error) {
503 goto err; 522 goto err;
504 } 523 }
505 524
506 qk.qk_idtype = q2type; 525 qk.qk_idtype = q2type;
507 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; 526 qk.qk_id = defaultq ? QUOTA_DEFAULTID : id;
508 qk.qk_objtype = QUOTA_OBJTYPE_FILES; 527 qk.qk_objtype = QUOTA_OBJTYPE_FILES;
509 528
510 args.qc_type = QCT_DELETE; 529 args.qc_type = QCT_DELETE;
511 args.u.delete.qc_key = &qk; 530 args.u.delete.qc_key = &qk;
512 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); 531 error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args);
513 if (error) { 532 if (error) {
514 goto err; 533 goto err;
515 } 534 }
516 } 535 }
517 536
518 prop_object_iterator_release(iter); 537 prop_object_iterator_release(iter);
519 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 538 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
520 error = ENOMEM; 539 error = ENOMEM;
521 } else { 540 } else {
522 error = 0; 541 error = 0;
523 } 542 }
524 return error; 543 return error;
525err: 544err:
526 prop_object_iterator_release(iter); 545 prop_object_iterator_release(iter);
527 prop_object_release(replies); 546 prop_object_release(replies);
528 return error; 547 return error;
529} 548}
530 549
531static int 550static int
532vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) 551vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict)
533{ 552{
534 int error; 553 int error;
535 const char *cmd, *type; 554 const char *cmd, *type;
536 prop_array_t datas; 555 prop_array_t datas;
537 int q2type; 556 int q2type;
538 557
539 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) 558 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd))
540 return EINVAL; 559 return EINVAL;
541 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) 560 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type))
542 return EINVAL; 561 return EINVAL;
543 562
544 if (!strcmp(type, QUOTADICT_CLASS_USER)) { 563 if (!strcmp(type, QUOTADICT_CLASS_USER)) {
545 q2type = QUOTA_CLASS_USER; 564 q2type = QUOTA_CLASS_USER;
546 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { 565 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) {
547 q2type = QUOTA_CLASS_GROUP; 566 q2type = QUOTA_CLASS_GROUP;
548 } else { 567 } else {
549 /* XXX this is a bad errno for this case */ 568 /* XXX this is a bad errno for this case */
550 return EOPNOTSUPP; 569 return EOPNOTSUPP;
551 } 570 }
552 571
553 datas = prop_dictionary_get(cmddict, "data"); 572 datas = prop_dictionary_get(cmddict, "data");
554 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) 573 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY)
555 return EINVAL; 574 return EINVAL;
556 575
557 prop_object_retain(datas); 576 prop_object_retain(datas);
558 prop_dictionary_remove(cmddict, "data"); /* prepare for return */ 577 prop_dictionary_remove(cmddict, "data"); /* prepare for return */
559 578
560 if (strcmp(cmd, "get version") == 0) { 579 if (strcmp(cmd, "get version") == 0) {
561 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); 580 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas);
562 } else if (strcmp(cmd, "quotaon") == 0) { 581 } else if (strcmp(cmd, "quotaon") == 0) {
563 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); 582 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas);
564 } else if (strcmp(cmd, "quotaoff") == 0) { 583 } else if (strcmp(cmd, "quotaoff") == 0) {
565 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); 584 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas);
566 } else if (strcmp(cmd, "get") == 0) { 585 } else if (strcmp(cmd, "get") == 0) {
567 error = vfs_quotactl_get(mp, cmddict, q2type, datas); 586 error = vfs_quotactl_get(mp, cmddict, q2type, datas);
568 } else if (strcmp(cmd, "set") == 0) { 587 } else if (strcmp(cmd, "set") == 0) {
569 error = vfs_quotactl_put(mp, cmddict, q2type, datas); 588 error = vfs_quotactl_put(mp, cmddict, q2type, datas);
570 } else if (strcmp(cmd, "getall") == 0) { 589 } else if (strcmp(cmd, "getall") == 0) {
571 error = vfs_quotactl_getall(mp, cmddict, q2type, datas); 590 error = vfs_quotactl_getall(mp, cmddict, q2type, datas);
572 } else if (strcmp(cmd, "clear") == 0) { 591 } else if (strcmp(cmd, "clear") == 0) {
573 error = vfs_quotactl_clear(mp, cmddict, q2type, datas); 592 error = vfs_quotactl_clear(mp, cmddict, q2type, datas);
574 } else { 593 } else {
575 /* XXX this a bad errno for this case */ 594 /* XXX this a bad errno for this case */
576 error = EOPNOTSUPP; 595 error = EOPNOTSUPP;
577 } 596 }
578 597
579 error = (prop_dictionary_set_int8(cmddict, "return", 598 error = (prop_dictionary_set_int8(cmddict, "return",
580 error) ? 0 : ENOMEM); 599 error) ? 0 : ENOMEM);
581 prop_object_release(datas); 600 prop_object_release(datas);
582 601
583 return error; 602 return error;
584} 603}
585 604
586int 605int
587vfs_quotactl(struct mount *mp, prop_dictionary_t dict) 606vfs_quotactl(struct mount *mp, prop_dictionary_t dict)
588{ 607{
589 prop_dictionary_t cmddict; 608 prop_dictionary_t cmddict;
590 prop_array_t commands; 609 prop_array_t commands;
591 prop_object_iterator_t iter; 610 prop_object_iterator_t iter;
592 int error; 611 int error;
593 612
594 error = quota_get_cmds(dict, &commands); 613 error = quota_get_cmds(dict, &commands);
595 if (error) { 614 if (error) {
596 return error; 615 return error;
597 } 616 }
598 617
599 iter = prop_array_iterator(commands); 618 iter = prop_array_iterator(commands);
600 if (iter == NULL) { 619 if (iter == NULL) {
601 return ENOMEM; 620 return ENOMEM;
602 } 621 }
603 622
604 while ((cmddict = prop_object_iterator_next(iter)) != NULL) { 623 while ((cmddict = prop_object_iterator_next(iter)) != NULL) {
605 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { 624 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) {
606 /* XXX shouldn't this be an error? */ 625 /* XXX shouldn't this be an error? */
607 continue; 626 continue;
608 } 627 }
609 error = vfs_quotactl_cmd(mp, cmddict); 628 error = vfs_quotactl_cmd(mp, cmddict);
610 if (error) { 629 if (error) {
611 break; 630 break;
612 } 631 }
613 } 632 }
614 prop_object_iterator_release(iter); 633 prop_object_iterator_release(iter);
615 return error; 634 return error;
616} 635}

cvs diff -r1.18 -r1.19 src/sys/sys/quotactl.h (switch to unified diff)

--- src/sys/sys/quotactl.h 2012/01/29 06:55:44 1.18
+++ src/sys/sys/quotactl.h 2012/01/29 06:57:15 1.19
@@ -1,82 +1,106 @@ @@ -1,82 +1,106 @@
1/* $NetBSD: quotactl.h,v 1.18 2012/01/29 06:55:44 dholland Exp $ */ 1/* $NetBSD: quotactl.h,v 1.19 2012/01/29 06:57:15 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/*
 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,
 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
 45 * copied in and out for every call using it.
 46 */
 47struct quotakcursor {
 48 union {
 49 char qkc_space[64];
 50 uintmax_t __qkc_forcealign;
 51 } u;
 52};
 53
40/* Command codes. */ 54/* Command codes. */
41#define QUOTACTL_GETVERSION 0 55#define QUOTACTL_GETVERSION 0
42#define QUOTACTL_QUOTAON 1 56#define QUOTACTL_QUOTAON 1
43#define QUOTACTL_QUOTAOFF 2 57#define QUOTACTL_QUOTAOFF 2
44#define QUOTACTL_GET 3 58#define QUOTACTL_GET 3
45#define QUOTACTL_PUT 4 59#define QUOTACTL_PUT 4
46#define QUOTACTL_GETALL 5 60#define QUOTACTL_GETALL 5
47#define QUOTACTL_DELETE 6 61#define QUOTACTL_DELETE 6
 62#define QUOTACTL_CURSOROPEN 7
 63#define QUOTACTL_CURSORCLOSE 8
48 64
49/* Argument encoding. */ 65/* Argument encoding. */
50enum vfs_quotactl_argtypes { 66enum vfs_quotactl_argtypes {
51 QCT_PROPLIB, /* quotaon/off, getall */ 67 QCT_PROPLIB, /* quotaon/off, getall */
52 QCT_GETVERSION, /* getversion */ 68 QCT_GETVERSION, /* getversion */
53 QCT_GET, /* get */ 69 QCT_GET, /* get */
54 QCT_PUT, /* put */ 70 QCT_PUT, /* put */
55 QCT_DELETE, /* delete */ 71 QCT_DELETE, /* delete */
 72 QCT_CURSOROPEN, /* open cursor */
 73 QCT_CURSORCLOSE,/* close cursor */
56}; 74};
57struct vfs_quotactl_args { 75struct vfs_quotactl_args {
58 enum vfs_quotactl_argtypes qc_type; 76 enum vfs_quotactl_argtypes qc_type;
59 union { 77 union {
60 struct { 78 struct {
61 prop_dictionary_t qc_cmddict; 79 prop_dictionary_t qc_cmddict;
62 int qc_q2type; 80 int qc_q2type;
63 prop_array_t qc_datas; 81 prop_array_t qc_datas;
64 } proplib; 82 } proplib;
65 struct { 83 struct {
66 int *qc_version_ret; 84 int *qc_version_ret;
67 } getversion; 85 } getversion;
68 struct { 86 struct {
69 const struct quotakey *qc_key; 87 const struct quotakey *qc_key;
70 struct quotaval *qc_ret; 88 struct quotaval *qc_ret;
71 } get; 89 } get;
72 struct { 90 struct {
73 const struct quotakey *qc_key; 91 const struct quotakey *qc_key;
74 const struct quotaval *qc_val; 92 const struct quotaval *qc_val;
75 } put; 93 } put;
76 struct { 94 struct {
77 const struct quotakey *qc_key; 95 const struct quotakey *qc_key;
78 } delete; 96 } delete;
 97 struct {
 98 struct quotakcursor *qc_cursor;
 99 } cursoropen;
 100 struct {
 101 struct quotakcursor *qc_cursor;
 102 } cursorclose;
79 } u; 103 } u;
80}; 104};
81 105
82#endif /* _SYS_QUOTACTL_H_ */ 106#endif /* _SYS_QUOTACTL_H_ */

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

--- src/sys/ufs/ufs/ufs_quota.c 2012/01/29 06:55:44 1.92
+++ src/sys/ufs/ufs/ufs_quota.c 2012/01/29 06:57:15 1.93
@@ -1,785 +1,847 @@ @@ -1,785 +1,847 @@
1/* $NetBSD: ufs_quota.c,v 1.92 2012/01/29 06:55:44 dholland Exp $ */ 1/* $NetBSD: ufs_quota.c,v 1.93 2012/01/29 06:57:15 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.92 2012/01/29 06:55:44 dholland Exp $"); 38__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.93 2012/01/29 06:57:15 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_getall(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 *,
 89 struct vfs_quotactl_args *args);
 90static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *,
 91 struct vfs_quotactl_args *args);
88 92
89/* 93/*
90 * Initialize the quota fields of an inode. 94 * Initialize the quota fields of an inode.
91 */ 95 */
92void 96void
93ufsquota_init(struct inode *ip) 97ufsquota_init(struct inode *ip)
94{ 98{
95 int i; 99 int i;
96 100
97 for (i = 0; i < MAXQUOTAS; i++) 101 for (i = 0; i < MAXQUOTAS; i++)
98 ip->i_dquot[i] = NODQUOT; 102 ip->i_dquot[i] = NODQUOT;
99} 103}
100 104
101/* 105/*
102 * Release the quota fields from an inode. 106 * Release the quota fields from an inode.
103 */ 107 */
104void 108void
105ufsquota_free(struct inode *ip) 109ufsquota_free(struct inode *ip)
106{ 110{
107 int i; 111 int i;
108 112
109 for (i = 0; i < MAXQUOTAS; i++) { 113 for (i = 0; i < MAXQUOTAS; i++) {
110 dqrele(ITOV(ip), ip->i_dquot[i]); 114 dqrele(ITOV(ip), ip->i_dquot[i]);
111 ip->i_dquot[i] = NODQUOT; 115 ip->i_dquot[i] = NODQUOT;
112 } 116 }
113} 117}
114 118
115/* 119/*
116 * Update disk usage, and take corrective action. 120 * Update disk usage, and take corrective action.
117 */ 121 */
118int 122int
119chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) 123chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
120{ 124{
121 /* do not track snapshot usage, or we will deadlock */ 125 /* do not track snapshot usage, or we will deadlock */
122 if ((ip->i_flags & SF_SNAPSHOT) != 0) 126 if ((ip->i_flags & SF_SNAPSHOT) != 0)
123 return 0; 127 return 0;
124 128
125#ifdef QUOTA 129#ifdef QUOTA
126 if (ip->i_ump->um_flags & UFS_QUOTA) 130 if (ip->i_ump->um_flags & UFS_QUOTA)
127 return chkdq1(ip, change, cred, flags); 131 return chkdq1(ip, change, cred, flags);
128#endif 132#endif
129#ifdef QUOTA2 133#ifdef QUOTA2
130 if (ip->i_ump->um_flags & UFS_QUOTA2) 134 if (ip->i_ump->um_flags & UFS_QUOTA2)
131 return chkdq2(ip, change, cred, flags); 135 return chkdq2(ip, change, cred, flags);
132#endif 136#endif
133 return 0; 137 return 0;
134} 138}
135 139
136/* 140/*
137 * Check the inode limit, applying corrective action. 141 * Check the inode limit, applying corrective action.
138 */ 142 */
139int 143int
140chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) 144chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
141{ 145{
142 /* do not track snapshot usage, or we will deadlock */ 146 /* do not track snapshot usage, or we will deadlock */
143 if ((ip->i_flags & SF_SNAPSHOT) != 0) 147 if ((ip->i_flags & SF_SNAPSHOT) != 0)
144 return 0; 148 return 0;
145#ifdef QUOTA 149#ifdef QUOTA
146 if (ip->i_ump->um_flags & UFS_QUOTA) 150 if (ip->i_ump->um_flags & UFS_QUOTA)
147 return chkiq1(ip, change, cred, flags); 151 return chkiq1(ip, change, cred, flags);
148#endif 152#endif
149#ifdef QUOTA2 153#ifdef QUOTA2
150 if (ip->i_ump->um_flags & UFS_QUOTA2) 154 if (ip->i_ump->um_flags & UFS_QUOTA2)
151 return chkiq2(ip, change, cred, flags); 155 return chkiq2(ip, change, cred, flags);
152#endif 156#endif
153 return 0; 157 return 0;
154} 158}
155 159
156int 160int
157quota_handle_cmd(struct mount *mp, struct lwp *l, int op, 161quota_handle_cmd(struct mount *mp, struct lwp *l, int op,
158 struct vfs_quotactl_args *args) 162 struct vfs_quotactl_args *args)
159{ 163{
160 int error = 0; 164 int error = 0;
161 165
162 switch (op) { 166 switch (op) {
163 case QUOTACTL_GETVERSION: 167 case QUOTACTL_GETVERSION:
164 error = quota_handle_cmd_get_version(mp, l, args); 168 error = quota_handle_cmd_get_version(mp, l, args);
165 break; 169 break;
166 case QUOTACTL_QUOTAON: 170 case QUOTACTL_QUOTAON:
167 error = quota_handle_cmd_quotaon(mp, l, args); 171 error = quota_handle_cmd_quotaon(mp, l, args);
168 break; 172 break;
169 case QUOTACTL_QUOTAOFF: 173 case QUOTACTL_QUOTAOFF:
170 error = quota_handle_cmd_quotaoff(mp, l, args); 174 error = quota_handle_cmd_quotaoff(mp, l, args);
171 break; 175 break;
172 case QUOTACTL_GET: 176 case QUOTACTL_GET:
173 error = quota_handle_cmd_get(mp, l, args); 177 error = quota_handle_cmd_get(mp, l, args);
174 break; 178 break;
175 case QUOTACTL_PUT: 179 case QUOTACTL_PUT:
176 error = quota_handle_cmd_put(mp, l, args); 180 error = quota_handle_cmd_put(mp, l, args);
177 break; 181 break;
178 case QUOTACTL_GETALL: 182 case QUOTACTL_GETALL:
179 error = quota_handle_cmd_getall(mp, l, args); 183 error = quota_handle_cmd_getall(mp, l, args);
180 break; 184 break;
181 case QUOTACTL_DELETE: 185 case QUOTACTL_DELETE:
182 error = quota_handle_cmd_delete(mp, l, args); 186 error = quota_handle_cmd_delete(mp, l, args);
183 break; 187 break;
 188 case QUOTACTL_CURSOROPEN:
 189 error = quota_handle_cmd_cursoropen(mp, l, args);
 190 break;
 191 case QUOTACTL_CURSORCLOSE:
 192 error = quota_handle_cmd_cursorclose(mp, l, args);
 193 break;
184 default: 194 default:
185 panic("Invalid quotactl operation %d\n", op); 195 panic("Invalid quotactl operation %d\n", op);
186 } 196 }
187 197
188 return error; 198 return error;
189} 199}
190 200
191static int  201static int
192quota_handle_cmd_get_version(struct mount *mp, struct lwp *l,  202quota_handle_cmd_get_version(struct mount *mp, struct lwp *l,
193 struct vfs_quotactl_args *args) 203 struct vfs_quotactl_args *args)
194{ 204{
195 struct ufsmount *ump = VFSTOUFS(mp); 205 struct ufsmount *ump = VFSTOUFS(mp);
196 int *version_ret; 206 int *version_ret;
197 207
198 KASSERT(args->qc_type == QCT_GETVERSION); 208 KASSERT(args->qc_type == QCT_GETVERSION);
199 version_ret = args->u.getversion.qc_version_ret; 209 version_ret = args->u.getversion.qc_version_ret;
200 210
201 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) 211 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
202 return EOPNOTSUPP; 212 return EOPNOTSUPP;
203 213
204#ifdef QUOTA 214#ifdef QUOTA
205 if (ump->um_flags & UFS_QUOTA) { 215 if (ump->um_flags & UFS_QUOTA) {
206 *version_ret = 1; 216 *version_ret = 1;
207 } else 217 } else
208#endif 218#endif
209#ifdef QUOTA2 219#ifdef QUOTA2
210 if (ump->um_flags & UFS_QUOTA2) { 220 if (ump->um_flags & UFS_QUOTA2) {
211 *version_ret = 2; 221 *version_ret = 2;
212 } else 222 } else
213#endif 223#endif
214 return EOPNOTSUPP; 224 return EOPNOTSUPP;
215 225
216 return 0; 226 return 0;
217} 227}
218 228
219/* XXX shouldn't all this be in kauth ? */ 229/* XXX shouldn't all this be in kauth ? */
220static int 230static int
221quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { 231quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) {
222 /* The user can always query about his own quota. */ 232 /* The user can always query about his own quota. */
223 if (id == kauth_cred_getuid(l->l_cred)) 233 if (id == kauth_cred_getuid(l->l_cred))
224 return 0; 234 return 0;
225 return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 235 return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
226 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); 236 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL);
227} 237}
228 238
229static int  239static int
230quota_handle_cmd_get(struct mount *mp, struct lwp *l,  240quota_handle_cmd_get(struct mount *mp, struct lwp *l,
231 struct vfs_quotactl_args *args) 241 struct vfs_quotactl_args *args)
232{ 242{
233 struct ufsmount *ump = VFSTOUFS(mp); 243 struct ufsmount *ump = VFSTOUFS(mp);
234 int error; 244 int error;
235 const struct quotakey *qk; 245 const struct quotakey *qk;
236 struct quotaval *ret; 246 struct quotaval *ret;
237 247
238 KASSERT(args->qc_type == QCT_GET); 248 KASSERT(args->qc_type == QCT_GET);
239 qk = args->u.get.qc_key; 249 qk = args->u.get.qc_key;
240 ret = args->u.get.qc_ret; 250 ret = args->u.get.qc_ret;
241 251
242 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) 252 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
243 return EOPNOTSUPP; 253 return EOPNOTSUPP;
244  254
245 error = quota_get_auth(mp, l, qk->qk_id); 255 error = quota_get_auth(mp, l, qk->qk_id);
246 if (error != 0)  256 if (error != 0)
247 return error; 257 return error;
248#ifdef QUOTA 258#ifdef QUOTA
249 if (ump->um_flags & UFS_QUOTA) { 259 if (ump->um_flags & UFS_QUOTA) {
250 error = quota1_handle_cmd_get(ump, qk, ret); 260 error = quota1_handle_cmd_get(ump, qk, ret);
251 } else 261 } else
252#endif 262#endif
253#ifdef QUOTA2 263#ifdef QUOTA2
254 if (ump->um_flags & UFS_QUOTA2) { 264 if (ump->um_flags & UFS_QUOTA2) {
255 error = quota2_handle_cmd_get(ump, qk, ret); 265 error = quota2_handle_cmd_get(ump, qk, ret);
256 } else 266 } else
257#endif 267#endif
258 panic("quota_handle_cmd_get: no support ?"); 268 panic("quota_handle_cmd_get: no support ?");
259  269
260 if (error != 0) 270 if (error != 0)
261 return error; 271 return error;
262 272
263 return error; 273 return error;
264} 274}
265 275
266static int  276static int
267quota_handle_cmd_put(struct mount *mp, struct lwp *l,  277quota_handle_cmd_put(struct mount *mp, struct lwp *l,
268 struct vfs_quotactl_args *args) 278 struct vfs_quotactl_args *args)
269{ 279{
270 struct ufsmount *ump = VFSTOUFS(mp); 280 struct ufsmount *ump = VFSTOUFS(mp);
271 const struct quotakey *qk; 281 const struct quotakey *qk;
272 const struct quotaval *qv; 282 const struct quotaval *qv;
273 id_t kauth_id; 283 id_t kauth_id;
274 int error; 284 int error;
275 285
276 KASSERT(args->qc_type == QCT_PUT); 286 KASSERT(args->qc_type == QCT_PUT);
277 qk = args->u.put.qc_key; 287 qk = args->u.put.qc_key;
278 qv = args->u.put.qc_val; 288 qv = args->u.put.qc_val;
279 289
280 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) 290 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0)
281 return EOPNOTSUPP; 291 return EOPNOTSUPP;
282 292
283 kauth_id = qk->qk_id; 293 kauth_id = qk->qk_id;
284 if (kauth_id == QUOTA_DEFAULTID) { 294 if (kauth_id == QUOTA_DEFAULTID) {
285 kauth_id = 0; 295 kauth_id = 0;
286 } 296 }
287 297
288 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 298 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
289 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), 299 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
290 NULL); 300 NULL);
291 if (error != 0) { 301 if (error != 0) {
292 return error; 302 return error;
293 } 303 }
294 304
295#ifdef QUOTA 305#ifdef QUOTA
296 if (ump->um_flags & UFS_QUOTA) 306 if (ump->um_flags & UFS_QUOTA)
297 error = quota1_handle_cmd_put(ump, qk, qv); 307 error = quota1_handle_cmd_put(ump, qk, qv);
298 else 308 else
299#endif 309#endif
300#ifdef QUOTA2 310#ifdef QUOTA2
301 if (ump->um_flags & UFS_QUOTA2) { 311 if (ump->um_flags & UFS_QUOTA2) {
302 error = quota2_handle_cmd_put(ump, qk, qv); 312 error = quota2_handle_cmd_put(ump, qk, qv);
303 } else 313 } else
304#endif 314#endif
305 panic("quota_handle_cmd_get: no support ?"); 315 panic("quota_handle_cmd_get: no support ?");
306  316
307 if (error == ENOENT) { 317 if (error == ENOENT) {
308 error = 0; 318 error = 0;
309 } 319 }
310 320
311 return error; 321 return error;
312} 322}
313 323
314static int  324static int
315quota_handle_cmd_delete(struct mount *mp, struct lwp *l,  325quota_handle_cmd_delete(struct mount *mp, struct lwp *l,
316 struct vfs_quotactl_args *args) 326 struct vfs_quotactl_args *args)
317{ 327{
318 struct ufsmount *ump = VFSTOUFS(mp); 328 struct ufsmount *ump = VFSTOUFS(mp);
319 const struct quotakey *qk; 329 const struct quotakey *qk;
320 id_t kauth_id; 330 id_t kauth_id;
321 int error; 331 int error;
322 332
323 KASSERT(args->qc_type == QCT_DELETE); 333 KASSERT(args->qc_type == QCT_DELETE);
324 qk = args->u.delete.qc_key; 334 qk = args->u.delete.qc_key;
325 335
326 kauth_id = qk->qk_id; 336 kauth_id = qk->qk_id;
327 if (kauth_id == QUOTA_DEFAULTID) { 337 if (kauth_id == QUOTA_DEFAULTID) {
328 kauth_id = 0; 338 kauth_id = 0;
329 } 339 }
330 340
331 if ((ump->um_flags & UFS_QUOTA2) == 0) 341 if ((ump->um_flags & UFS_QUOTA2) == 0)
332 return EOPNOTSUPP; 342 return EOPNOTSUPP;
333 343
334 /* avoid whitespace changes */ 344 /* avoid whitespace changes */
335 { 345 {
336 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 346 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
337 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), 347 KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id),
338 NULL); 348 NULL);
339 if (error != 0) 349 if (error != 0)
340 goto err; 350 goto err;
341#ifdef QUOTA2 351#ifdef QUOTA2
342 if (ump->um_flags & UFS_QUOTA2) { 352 if (ump->um_flags & UFS_QUOTA2) {
343 error = quota2_handle_cmd_delete(ump, qk); 353 error = quota2_handle_cmd_delete(ump, qk);
344 } else 354 } else
345#endif 355#endif
346 panic("quota_handle_cmd_get: no support ?"); 356 panic("quota_handle_cmd_get: no support ?");
347  357
348 if (error && error != ENOENT) 358 if (error && error != ENOENT)
349 goto err; 359 goto err;
350 } 360 }
351 361
352 return 0; 362 return 0;
353 err: 363 err:
354 return error; 364 return error;
355} 365}
356 366
357static int  367static int
358quota_handle_cmd_getall(struct mount *mp, struct lwp *l,  368quota_handle_cmd_getall(struct mount *mp, struct lwp *l,
359 struct vfs_quotactl_args *args) 369 struct vfs_quotactl_args *args)
360{ 370{
361 prop_array_t replies; 371 prop_array_t replies;
362 struct ufsmount *ump = VFSTOUFS(mp); 372 struct ufsmount *ump = VFSTOUFS(mp);
363 int error; 373 int error;
364 prop_dictionary_t cmddict; 374 prop_dictionary_t cmddict;
365 int q2type; 375 int q2type;
366 prop_array_t datas; 376 prop_array_t datas;
367 377
368 KASSERT(args->qc_type == QCT_PROPLIB); 378 KASSERT(args->qc_type == QCT_PROPLIB);
369 cmddict = args->u.proplib.qc_cmddict; 379 cmddict = args->u.proplib.qc_cmddict;
370 q2type = args->u.proplib.qc_q2type; 380 q2type = args->u.proplib.qc_q2type;
371 datas = args->u.proplib.qc_datas; 381 datas = args->u.proplib.qc_datas;
372 382
373 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 383 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
374 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 384 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
375 385
376 if ((ump->um_flags & UFS_QUOTA2) == 0) 386 if ((ump->um_flags & UFS_QUOTA2) == 0)
377 return EOPNOTSUPP; 387 return EOPNOTSUPP;
378  388
379 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 389 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
380 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); 390 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
381 if (error) 391 if (error)
382 return error; 392 return error;
383  393
384 replies = prop_array_create(); 394 replies = prop_array_create();
385 if (replies == NULL) 395 if (replies == NULL)
386 return ENOMEM; 396 return ENOMEM;
387 397
388#ifdef QUOTA2 398#ifdef QUOTA2
389 if (ump->um_flags & UFS_QUOTA2) { 399 if (ump->um_flags & UFS_QUOTA2) {
390 error = quota2_handle_cmd_getall(ump, q2type, replies); 400 error = quota2_handle_cmd_getall(ump, q2type, replies);
391 } else 401 } else
392#endif 402#endif
393 panic("quota_handle_cmd_getall: no support ?"); 403 panic("quota_handle_cmd_getall: no support ?");
394 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 404 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
395 error = ENOMEM; 405 error = ENOMEM;
396 } else { 406 } else {
397 error = 0; 407 error = 0;
398 } 408 }
399 return error; 409 return error;
400} 410}
401 411
402static int  412static int
 413quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l,
 414 struct vfs_quotactl_args *args)
 415{
 416 struct ufsmount *ump = VFSTOUFS(mp);
 417 struct quotakcursor *cursor;
 418 int error;
 419
 420 KASSERT(args->qc_type == QCT_CURSOROPEN);
 421 cursor = args->u.cursoropen.qc_cursor;
 422
 423 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
 424 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
 425 if (error)
 426 return error;
 427
 428#ifdef QUOTA2
 429 if (ump->um_flags & UFS_QUOTA2) {
 430 error = quota2_handle_cmd_cursoropen(ump, cursor);
 431 } else
 432#endif
 433 error = EOPNOTSUPP;
 434
 435 return error;
 436}
 437
 438static int
 439quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l,
 440 struct vfs_quotactl_args *args)
 441{
 442 struct ufsmount *ump = VFSTOUFS(mp);
 443 struct quotakcursor *cursor;
 444 int error;
 445
 446 KASSERT(args->qc_type == QCT_CURSORCLOSE);
 447 cursor = args->u.cursorclose.qc_cursor;
 448
 449 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
 450 KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL);
 451 if (error)
 452 return error;
 453
 454#ifdef QUOTA2
 455 if (ump->um_flags & UFS_QUOTA2) {
 456 error = quota2_handle_cmd_cursorclose(ump, cursor);
 457 } else
 458#endif
 459 error = EOPNOTSUPP;
 460
 461 return error;
 462}
 463
 464static int
403quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,  465quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l,
404 struct vfs_quotactl_args *args) 466 struct vfs_quotactl_args *args)
405{ 467{
406 prop_dictionary_t data; 468 prop_dictionary_t data;
407 struct ufsmount *ump = VFSTOUFS(mp); 469 struct ufsmount *ump = VFSTOUFS(mp);
408 int error; 470 int error;
409 const char *qfile; 471 const char *qfile;
410 prop_dictionary_t cmddict; 472 prop_dictionary_t cmddict;
411 int q2type; 473 int q2type;
412 prop_array_t datas; 474 prop_array_t datas;
413 475
414 KASSERT(args->qc_type == QCT_PROPLIB); 476 KASSERT(args->qc_type == QCT_PROPLIB);
415 cmddict = args->u.proplib.qc_cmddict; 477 cmddict = args->u.proplib.qc_cmddict;
416 q2type = args->u.proplib.qc_q2type; 478 q2type = args->u.proplib.qc_q2type;
417 datas = args->u.proplib.qc_datas; 479 datas = args->u.proplib.qc_datas;
418 480
419 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 481 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
420 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 482 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
421 483
422 if ((ump->um_flags & UFS_QUOTA2) != 0) 484 if ((ump->um_flags & UFS_QUOTA2) != 0)
423 return EBUSY; 485 return EBUSY;
424  486
425 if (prop_array_count(datas) != 1) 487 if (prop_array_count(datas) != 1)
426 return EINVAL; 488 return EINVAL;
427 489
428 data = prop_array_get(datas, 0); 490 data = prop_array_get(datas, 0);
429 if (data == NULL) 491 if (data == NULL)
430 return ENOMEM; 492 return ENOMEM;
431 if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", 493 if (!prop_dictionary_get_cstring_nocopy(data, "quotafile",
432 &qfile)) 494 &qfile))
433 return EINVAL; 495 return EINVAL;
434 496
435 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 497 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
436 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); 498 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
437 if (error != 0) { 499 if (error != 0) {
438 return error; 500 return error;
439 } 501 }
440#ifdef QUOTA 502#ifdef QUOTA
441 error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); 503 error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile);
442#else 504#else
443 error = EOPNOTSUPP; 505 error = EOPNOTSUPP;
444#endif 506#endif
445  507
446 return error; 508 return error;
447} 509}
448 510
449static int  511static int
450quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,  512quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l,
451 struct vfs_quotactl_args *args) 513 struct vfs_quotactl_args *args)
452{ 514{
453 struct ufsmount *ump = VFSTOUFS(mp); 515 struct ufsmount *ump = VFSTOUFS(mp);
454 int error; 516 int error;
455 prop_dictionary_t cmddict; 517 prop_dictionary_t cmddict;
456 int q2type; 518 int q2type;
457 prop_array_t datas; 519 prop_array_t datas;
458 520
459 KASSERT(args->qc_type == QCT_PROPLIB); 521 KASSERT(args->qc_type == QCT_PROPLIB);
460 cmddict = args->u.proplib.qc_cmddict; 522 cmddict = args->u.proplib.qc_cmddict;
461 q2type = args->u.proplib.qc_q2type; 523 q2type = args->u.proplib.qc_q2type;
462 datas = args->u.proplib.qc_datas; 524 datas = args->u.proplib.qc_datas;
463 525
464 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 526 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
465 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 527 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
466 528
467 if ((ump->um_flags & UFS_QUOTA2) != 0) 529 if ((ump->um_flags & UFS_QUOTA2) != 0)
468 return EOPNOTSUPP; 530 return EOPNOTSUPP;
469  531
470 if (prop_array_count(datas) != 0) 532 if (prop_array_count(datas) != 0)
471 return EINVAL; 533 return EINVAL;
472 534
473 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, 535 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA,
474 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); 536 KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL);
475 if (error != 0) { 537 if (error != 0) {
476 return error; 538 return error;
477 } 539 }
478#ifdef QUOTA 540#ifdef QUOTA
479 error = quota1_handle_cmd_quotaoff(l, ump, q2type); 541 error = quota1_handle_cmd_quotaoff(l, ump, q2type);
480#else 542#else
481 error = EOPNOTSUPP; 543 error = EOPNOTSUPP;
482#endif 544#endif
483  545
484 return error; 546 return error;
485} 547}
486 548
487/* 549/*
488 * Initialize the quota system. 550 * Initialize the quota system.
489 */ 551 */
490void 552void
491dqinit(void) 553dqinit(void)
492{ 554{
493 555
494 mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); 556 mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE);
495 cv_init(&dqcv, "quota"); 557 cv_init(&dqcv, "quota");
496 dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); 558 dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash);
497 dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", 559 dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq",
498 NULL, IPL_NONE, NULL, NULL, NULL); 560 NULL, IPL_NONE, NULL, NULL, NULL);
499} 561}
500 562
501void 563void
502dqreinit(void) 564dqreinit(void)
503{ 565{
504 struct dquot *dq; 566 struct dquot *dq;
505 struct dqhashhead *oldhash, *hash; 567 struct dqhashhead *oldhash, *hash;
506 struct vnode *dqvp; 568 struct vnode *dqvp;
507 u_long oldmask, mask, hashval; 569 u_long oldmask, mask, hashval;
508 int i; 570 int i;
509 571
510 hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); 572 hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
511 mutex_enter(&dqlock); 573 mutex_enter(&dqlock);
512 oldhash = dqhashtbl; 574 oldhash = dqhashtbl;
513 oldmask = dqhash; 575 oldmask = dqhash;
514 dqhashtbl = hash; 576 dqhashtbl = hash;
515 dqhash = mask; 577 dqhash = mask;
516 for (i = 0; i <= oldmask; i++) { 578 for (i = 0; i <= oldmask; i++) {
517 while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { 579 while ((dq = LIST_FIRST(&oldhash[i])) != NULL) {
518 dqvp = dq->dq_ump->um_quotas[dq->dq_type]; 580 dqvp = dq->dq_ump->um_quotas[dq->dq_type];
519 LIST_REMOVE(dq, dq_hash); 581 LIST_REMOVE(dq, dq_hash);
520 hashval = DQHASH(dqvp, dq->dq_id); 582 hashval = DQHASH(dqvp, dq->dq_id);
521 LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); 583 LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash);
522 } 584 }
523 } 585 }
524 mutex_exit(&dqlock); 586 mutex_exit(&dqlock);
525 hashdone(oldhash, HASH_LIST, oldmask); 587 hashdone(oldhash, HASH_LIST, oldmask);
526} 588}
527 589
528/* 590/*
529 * Free resources held by quota system. 591 * Free resources held by quota system.
530 */ 592 */
531void 593void
532dqdone(void) 594dqdone(void)
533{ 595{
534 596
535 pool_cache_destroy(dquot_cache); 597 pool_cache_destroy(dquot_cache);
536 hashdone(dqhashtbl, HASH_LIST, dqhash); 598 hashdone(dqhashtbl, HASH_LIST, dqhash);
537 cv_destroy(&dqcv); 599 cv_destroy(&dqcv);
538 mutex_destroy(&dqlock); 600 mutex_destroy(&dqlock);
539} 601}
540 602
541/* 603/*
542 * Set up the quotas for an inode. 604 * Set up the quotas for an inode.
543 * 605 *
544 * This routine completely defines the semantics of quotas. 606 * This routine completely defines the semantics of quotas.
545 * If other criterion want to be used to establish quotas, the 607 * If other criterion want to be used to establish quotas, the
546 * MAXQUOTAS value in quotas.h should be increased, and the 608 * MAXQUOTAS value in quotas.h should be increased, and the
547 * additional dquots set up here. 609 * additional dquots set up here.
548 */ 610 */
549int 611int
550getinoquota(struct inode *ip) 612getinoquota(struct inode *ip)
551{ 613{
552 struct ufsmount *ump = ip->i_ump; 614 struct ufsmount *ump = ip->i_ump;
553 struct vnode *vp = ITOV(ip); 615 struct vnode *vp = ITOV(ip);
554 int i, error; 616 int i, error;
555 u_int32_t ino_ids[MAXQUOTAS]; 617 u_int32_t ino_ids[MAXQUOTAS];
556 618
557 /* 619 /*
558 * To avoid deadlocks never update quotas for quota files 620 * To avoid deadlocks never update quotas for quota files
559 * on the same file system 621 * on the same file system
560 */ 622 */
561 for (i = 0; i < MAXQUOTAS; i++) 623 for (i = 0; i < MAXQUOTAS; i++)
562 if (vp == ump->um_quotas[i]) 624 if (vp == ump->um_quotas[i])
563 return 0; 625 return 0;
564 626
565 ino_ids[USRQUOTA] = ip->i_uid; 627 ino_ids[USRQUOTA] = ip->i_uid;
566 ino_ids[GRPQUOTA] = ip->i_gid; 628 ino_ids[GRPQUOTA] = ip->i_gid;
567 for (i = 0; i < MAXQUOTAS; i++) { 629 for (i = 0; i < MAXQUOTAS; i++) {
568 /* 630 /*
569 * If the file id changed the quota needs update. 631 * If the file id changed the quota needs update.
570 */ 632 */
571 if (ip->i_dquot[i] != NODQUOT && 633 if (ip->i_dquot[i] != NODQUOT &&
572 ip->i_dquot[i]->dq_id != ino_ids[i]) { 634 ip->i_dquot[i]->dq_id != ino_ids[i]) {
573 dqrele(ITOV(ip), ip->i_dquot[i]); 635 dqrele(ITOV(ip), ip->i_dquot[i]);
574 ip->i_dquot[i] = NODQUOT; 636 ip->i_dquot[i] = NODQUOT;
575 } 637 }
576 /* 638 /*
577 * Set up the quota based on file id. 639 * Set up the quota based on file id.
578 * ENODEV means that quotas are not enabled. 640 * ENODEV means that quotas are not enabled.
579 */ 641 */
580 if (ip->i_dquot[i] == NODQUOT && 642 if (ip->i_dquot[i] == NODQUOT &&
581 (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && 643 (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) &&
582 error != ENODEV) 644 error != ENODEV)
583 return (error); 645 return (error);
584 } 646 }
585 return 0; 647 return 0;
586} 648}
587 649
588/* 650/*
589 * Obtain a dquot structure for the specified identifier and quota file 651 * Obtain a dquot structure for the specified identifier and quota file
590 * reading the information from the file if necessary. 652 * reading the information from the file if necessary.
591 */ 653 */
592int 654int
593dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, 655dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type,
594 struct dquot **dqp) 656 struct dquot **dqp)
595{ 657{
596 struct dquot *dq, *ndq; 658 struct dquot *dq, *ndq;
597 struct dqhashhead *dqh; 659 struct dqhashhead *dqh;
598 struct vnode *dqvp; 660 struct vnode *dqvp;
599 int error = 0; /* XXX gcc */ 661 int error = 0; /* XXX gcc */
600 662
601 /* Lock to see an up to date value for QTF_CLOSING. */ 663 /* Lock to see an up to date value for QTF_CLOSING. */
602 mutex_enter(&dqlock); 664 mutex_enter(&dqlock);
603 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { 665 if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) {
604 mutex_exit(&dqlock); 666 mutex_exit(&dqlock);
605 *dqp = NODQUOT; 667 *dqp = NODQUOT;
606 return (ENODEV); 668 return (ENODEV);
607 } 669 }
608 dqvp = ump->um_quotas[type]; 670 dqvp = ump->um_quotas[type];
609#ifdef QUOTA 671#ifdef QUOTA
610 if (ump->um_flags & UFS_QUOTA) { 672 if (ump->um_flags & UFS_QUOTA) {
611 if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { 673 if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) {
612 mutex_exit(&dqlock); 674 mutex_exit(&dqlock);
613 *dqp = NODQUOT; 675 *dqp = NODQUOT;
614 return (ENODEV); 676 return (ENODEV);
615 } 677 }
616 } 678 }
617#endif 679#endif
618#ifdef QUOTA2 680#ifdef QUOTA2
619 if (ump->um_flags & UFS_QUOTA2) { 681 if (ump->um_flags & UFS_QUOTA2) {
620 if (dqvp == NULLVP) { 682 if (dqvp == NULLVP) {
621 mutex_exit(&dqlock); 683 mutex_exit(&dqlock);
622 *dqp = NODQUOT; 684 *dqp = NODQUOT;
623 return (ENODEV); 685 return (ENODEV);
624 } 686 }
625 } 687 }
626#endif 688#endif
627 KASSERT(dqvp != vp); 689 KASSERT(dqvp != vp);
628 /* 690 /*
629 * Check the cache first. 691 * Check the cache first.
630 */ 692 */
631 dqh = &dqhashtbl[DQHASH(dqvp, id)]; 693 dqh = &dqhashtbl[DQHASH(dqvp, id)];
632 LIST_FOREACH(dq, dqh, dq_hash) { 694 LIST_FOREACH(dq, dqh, dq_hash) {
633 if (dq->dq_id != id || 695 if (dq->dq_id != id ||
634 dq->dq_ump->um_quotas[dq->dq_type] != dqvp) 696 dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
635 continue; 697 continue;
636 KASSERT(dq->dq_cnt > 0); 698 KASSERT(dq->dq_cnt > 0);
637 dqref(dq); 699 dqref(dq);
638 mutex_exit(&dqlock); 700 mutex_exit(&dqlock);
639 *dqp = dq; 701 *dqp = dq;
640 return (0); 702 return (0);
641 } 703 }
642 /* 704 /*
643 * Not in cache, allocate a new one. 705 * Not in cache, allocate a new one.
644 */ 706 */
645 mutex_exit(&dqlock); 707 mutex_exit(&dqlock);
646 ndq = pool_cache_get(dquot_cache, PR_WAITOK); 708 ndq = pool_cache_get(dquot_cache, PR_WAITOK);
647 /* 709 /*
648 * Initialize the contents of the dquot structure. 710 * Initialize the contents of the dquot structure.
649 */ 711 */
650 memset((char *)ndq, 0, sizeof *ndq); 712 memset((char *)ndq, 0, sizeof *ndq);
651 ndq->dq_flags = 0; 713 ndq->dq_flags = 0;
652 ndq->dq_id = id; 714 ndq->dq_id = id;
653 ndq->dq_ump = ump; 715 ndq->dq_ump = ump;
654 ndq->dq_type = type; 716 ndq->dq_type = type;
655 mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); 717 mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE);
656 mutex_enter(&dqlock); 718 mutex_enter(&dqlock);
657 dqh = &dqhashtbl[DQHASH(dqvp, id)]; 719 dqh = &dqhashtbl[DQHASH(dqvp, id)];
658 LIST_FOREACH(dq, dqh, dq_hash) { 720 LIST_FOREACH(dq, dqh, dq_hash) {
659 if (dq->dq_id != id || 721 if (dq->dq_id != id ||
660 dq->dq_ump->um_quotas[dq->dq_type] != dqvp) 722 dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
661 continue; 723 continue;
662 /* 724 /*
663 * Another thread beat us allocating this dquot. 725 * Another thread beat us allocating this dquot.
664 */ 726 */
665 KASSERT(dq->dq_cnt > 0); 727 KASSERT(dq->dq_cnt > 0);
666 dqref(dq); 728 dqref(dq);
667 mutex_exit(&dqlock); 729 mutex_exit(&dqlock);
668 mutex_destroy(&ndq->dq_interlock); 730 mutex_destroy(&ndq->dq_interlock);
669 pool_cache_put(dquot_cache, ndq); 731 pool_cache_put(dquot_cache, ndq);
670 *dqp = dq; 732 *dqp = dq;
671 return 0; 733 return 0;
672 } 734 }
673 dq = ndq; 735 dq = ndq;
674 LIST_INSERT_HEAD(dqh, dq, dq_hash); 736 LIST_INSERT_HEAD(dqh, dq, dq_hash);
675 dqref(dq); 737 dqref(dq);
676 mutex_enter(&dq->dq_interlock); 738 mutex_enter(&dq->dq_interlock);
677 mutex_exit(&dqlock); 739 mutex_exit(&dqlock);
678#ifdef QUOTA 740#ifdef QUOTA
679 if (ump->um_flags & UFS_QUOTA) 741 if (ump->um_flags & UFS_QUOTA)
680 error = dq1get(dqvp, id, ump, type, dq); 742 error = dq1get(dqvp, id, ump, type, dq);
681#endif 743#endif
682#ifdef QUOTA2 744#ifdef QUOTA2
683 if (ump->um_flags & UFS_QUOTA2) 745 if (ump->um_flags & UFS_QUOTA2)
684 error = dq2get(dqvp, id, ump, type, dq); 746 error = dq2get(dqvp, id, ump, type, dq);
685#endif 747#endif
686 /* 748 /*
687 * I/O error in reading quota file, release 749 * I/O error in reading quota file, release
688 * quota structure and reflect problem to caller. 750 * quota structure and reflect problem to caller.
689 */ 751 */
690 if (error) { 752 if (error) {
691 mutex_enter(&dqlock); 753 mutex_enter(&dqlock);
692 LIST_REMOVE(dq, dq_hash); 754 LIST_REMOVE(dq, dq_hash);
693 mutex_exit(&dqlock); 755 mutex_exit(&dqlock);
694 mutex_exit(&dq->dq_interlock); 756 mutex_exit(&dq->dq_interlock);
695 dqrele(vp, dq); 757 dqrele(vp, dq);
696 *dqp = NODQUOT; 758 *dqp = NODQUOT;
697 return (error); 759 return (error);
698 } 760 }
699 mutex_exit(&dq->dq_interlock); 761 mutex_exit(&dq->dq_interlock);
700 *dqp = dq; 762 *dqp = dq;
701 return (0); 763 return (0);
702} 764}
703 765
704/* 766/*
705 * Obtain a reference to a dquot. 767 * Obtain a reference to a dquot.
706 */ 768 */
707void 769void
708dqref(struct dquot *dq) 770dqref(struct dquot *dq)
709{ 771{
710 772
711 KASSERT(mutex_owned(&dqlock)); 773 KASSERT(mutex_owned(&dqlock));
712 dq->dq_cnt++; 774 dq->dq_cnt++;
713 KASSERT(dq->dq_cnt > 0); 775 KASSERT(dq->dq_cnt > 0);
714} 776}
715 777
716/* 778/*
717 * Release a reference to a dquot. 779 * Release a reference to a dquot.
718 */ 780 */
719void 781void
720dqrele(struct vnode *vp, struct dquot *dq) 782dqrele(struct vnode *vp, struct dquot *dq)
721{ 783{
722 784
723 if (dq == NODQUOT) 785 if (dq == NODQUOT)
724 return; 786 return;
725 mutex_enter(&dq->dq_interlock); 787 mutex_enter(&dq->dq_interlock);
726 for (;;) { 788 for (;;) {
727 mutex_enter(&dqlock); 789 mutex_enter(&dqlock);
728 if (dq->dq_cnt > 1) { 790 if (dq->dq_cnt > 1) {
729 dq->dq_cnt--; 791 dq->dq_cnt--;
730 mutex_exit(&dqlock); 792 mutex_exit(&dqlock);
731 mutex_exit(&dq->dq_interlock); 793 mutex_exit(&dq->dq_interlock);
732 return; 794 return;
733 } 795 }
734 if ((dq->dq_flags & DQ_MOD) == 0) 796 if ((dq->dq_flags & DQ_MOD) == 0)
735 break; 797 break;
736 mutex_exit(&dqlock); 798 mutex_exit(&dqlock);
737#ifdef QUOTA 799#ifdef QUOTA
738 if (dq->dq_ump->um_flags & UFS_QUOTA) 800 if (dq->dq_ump->um_flags & UFS_QUOTA)
739 (void) dq1sync(vp, dq); 801 (void) dq1sync(vp, dq);
740#endif 802#endif
741#ifdef QUOTA2 803#ifdef QUOTA2
742 if (dq->dq_ump->um_flags & UFS_QUOTA2) 804 if (dq->dq_ump->um_flags & UFS_QUOTA2)
743 (void) dq2sync(vp, dq); 805 (void) dq2sync(vp, dq);
744#endif 806#endif
745 } 807 }
746 KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); 808 KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0);
747 LIST_REMOVE(dq, dq_hash); 809 LIST_REMOVE(dq, dq_hash);
748 mutex_exit(&dqlock); 810 mutex_exit(&dqlock);
749 mutex_exit(&dq->dq_interlock); 811 mutex_exit(&dq->dq_interlock);
750 mutex_destroy(&dq->dq_interlock); 812 mutex_destroy(&dq->dq_interlock);
751 pool_cache_put(dquot_cache, dq); 813 pool_cache_put(dquot_cache, dq);
752} 814}
753 815
754int 816int
755qsync(struct mount *mp) 817qsync(struct mount *mp)
756{ 818{
757 struct ufsmount *ump = VFSTOUFS(mp); 819 struct ufsmount *ump = VFSTOUFS(mp);
758#ifdef QUOTA 820#ifdef QUOTA
759 if (ump->um_flags & UFS_QUOTA) 821 if (ump->um_flags & UFS_QUOTA)
760 return q1sync(mp); 822 return q1sync(mp);
761#endif 823#endif
762#ifdef QUOTA2 824#ifdef QUOTA2
763 if (ump->um_flags & UFS_QUOTA2) 825 if (ump->um_flags & UFS_QUOTA2)
764 return q2sync(mp); 826 return q2sync(mp);
765#endif 827#endif
766 return 0; 828 return 0;
767} 829}
768 830
769#ifdef DIAGNOSTIC 831#ifdef DIAGNOSTIC
770/* 832/*
771 * Check the hash chains for stray dquot's. 833 * Check the hash chains for stray dquot's.
772 */ 834 */
773void 835void
774dqflush(struct vnode *vp) 836dqflush(struct vnode *vp)
775{ 837{
776 struct dquot *dq; 838 struct dquot *dq;
777 int i; 839 int i;
778 840
779 mutex_enter(&dqlock); 841 mutex_enter(&dqlock);
780 for (i = 0; i <= dqhash; i++) 842 for (i = 0; i <= dqhash; i++)
781 LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) 843 LIST_FOREACH(dq, &dqhashtbl[i], dq_hash)
782 KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); 844 KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp);
783 mutex_exit(&dqlock); 845 mutex_exit(&dqlock);
784} 846}
785#endif 847#endif

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

--- src/sys/ufs/ufs/ufs_quota.h 2012/01/29 06:55:44 1.14
+++ src/sys/ufs/ufs/ufs_quota.h 2012/01/29 06:57:15 1.15
@@ -1,134 +1,139 @@ @@ -1,134 +1,139 @@
1/* $NetBSD: ufs_quota.h,v 1.14 2012/01/29 06:55:44 dholland Exp $ */ 1/* $NetBSD: ufs_quota.h,v 1.15 2012/01/29 06:57:15 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> */
 40
 41
39/* link to this quota in the quota inode (for QUOTA2) */ 42/* link to this quota in the quota inode (for QUOTA2) */
40struct dq2_desc { 43struct dq2_desc {
41 uint64_t dq2_lblkno; /* logical disk block holding this quota */ 44 uint64_t dq2_lblkno; /* logical disk block holding this quota */
42 u_int dq2_blkoff; /* offset in disk block holding this quota */ 45 u_int dq2_blkoff; /* offset in disk block holding this quota */
43}; 46};
44 47
45/* 48/*
46 * 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
47 * 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
48 * 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
49 * used entries. 52 * used entries.
50 * Field markings and the corresponding locks: 53 * Field markings and the corresponding locks:
51 * h: dqlock 54 * h: dqlock
52 * d: dq_interlock 55 * d: dq_interlock
53 * 56 *
54 * Lock order is: dq_interlock -> dqlock 57 * Lock order is: dq_interlock -> dqlock
55 * dq_interlock -> dqvp 58 * dq_interlock -> dqvp
56 */ 59 */
57struct dquot { 60struct dquot {
58 LIST_ENTRY(dquot) dq_hash; /* h: hash list */ 61 LIST_ENTRY(dquot) dq_hash; /* h: hash list */
59 u_int16_t dq_flags; /* d: flags, see below */ 62 u_int16_t dq_flags; /* d: flags, see below */
60 u_int16_t dq_type; /* d: quota type of this dquot */ 63 u_int16_t dq_type; /* d: quota type of this dquot */
61 u_int32_t dq_cnt; /* h: count of active references */ 64 u_int32_t dq_cnt; /* h: count of active references */
62 u_int32_t dq_id; /* d: identifier this applies to */ 65 u_int32_t dq_id; /* d: identifier this applies to */
63 struct ufsmount *dq_ump; /* d: filesystem this is taken from */ 66 struct ufsmount *dq_ump; /* d: filesystem this is taken from */
64 kmutex_t dq_interlock; /* d: lock this dquot */ 67 kmutex_t dq_interlock; /* d: lock this dquot */
65 union { 68 union {
66 struct dqblk dq1_dqb; /* d: actual usage & quotas */ 69 struct dqblk dq1_dqb; /* d: actual usage & quotas */
67 struct dq2_desc dq2_desc; /* d: pointer to quota data */ 70 struct dq2_desc dq2_desc; /* d: pointer to quota data */
68 } dq_un; 71 } dq_un;
69}; 72};
70 73
71/* 74/*
72 * Flag values. 75 * Flag values.
73 */ 76 */
74#define DQ_MOD 0x04 /* this quota modified since read */ 77#define DQ_MOD 0x04 /* this quota modified since read */
75#define DQ_FAKE 0x08 /* no limits here, just usage */ 78#define DQ_FAKE 0x08 /* no limits here, just usage */
76#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 */
77/* 80/*
78 * Shorthand notation. 81 * Shorthand notation.
79 */ 82 */
80#define dq_bhardlimit dq_un.dq1_dqb.dqb_bhardlimit 83#define dq_bhardlimit dq_un.dq1_dqb.dqb_bhardlimit
81#define dq_bsoftlimit dq_un.dq1_dqb.dqb_bsoftlimit 84#define dq_bsoftlimit dq_un.dq1_dqb.dqb_bsoftlimit
82#define dq_curblocks dq_un.dq1_dqb.dqb_curblocks 85#define dq_curblocks dq_un.dq1_dqb.dqb_curblocks
83#define dq_ihardlimit dq_un.dq1_dqb.dqb_ihardlimit 86#define dq_ihardlimit dq_un.dq1_dqb.dqb_ihardlimit
84#define dq_isoftlimit dq_un.dq1_dqb.dqb_isoftlimit 87#define dq_isoftlimit dq_un.dq1_dqb.dqb_isoftlimit
85#define dq_curinodes dq_un.dq1_dqb.dqb_curinodes 88#define dq_curinodes dq_un.dq1_dqb.dqb_curinodes
86#define dq_btime dq_un.dq1_dqb.dqb_btime 89#define dq_btime dq_un.dq1_dqb.dqb_btime
87#define dq_itime dq_un.dq1_dqb.dqb_itime 90#define dq_itime dq_un.dq1_dqb.dqb_itime
88 91
89#define dq2_lblkno dq_un.dq2_desc.dq2_lblkno 92#define dq2_lblkno dq_un.dq2_desc.dq2_lblkno
90#define dq2_blkoff dq_un.dq2_desc.dq2_blkoff 93#define dq2_blkoff dq_un.dq2_desc.dq2_blkoff
91/* 94/*
92 * 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
93 * 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
94 * to reference a dquot structure. 97 * to reference a dquot structure.
95 */ 98 */
96#define NODQUOT NULL 99#define NODQUOT NULL
97 100
98extern kmutex_t dqlock; 101extern kmutex_t dqlock;
99extern kcondvar_t dqcv; 102extern kcondvar_t dqcv;
100/* 103/*
101 * Quota name to error message mapping. 104 * Quota name to error message mapping.
102 */ 105 */
103const char *quotatypes[MAXQUOTAS]; 106const char *quotatypes[MAXQUOTAS];
104 107
105int getinoquota(struct inode *); 108int getinoquota(struct inode *);
106int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **); 109int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **);
107void dqref(struct dquot *); 110void dqref(struct dquot *);
108void dqrele(struct vnode *, struct dquot *); 111void dqrele(struct vnode *, struct dquot *);
109void dqflush(struct vnode *); 112void dqflush(struct vnode *);
110 113
111int chkdq1(struct inode *, int64_t, kauth_cred_t, int); 114int chkdq1(struct inode *, int64_t, kauth_cred_t, int);
112int chkiq1(struct inode *, int32_t, kauth_cred_t, int); 115int chkiq1(struct inode *, int32_t, kauth_cred_t, int);
113int q1sync(struct mount *); 116int q1sync(struct mount *);
114int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); 117int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
115int dq1sync(struct vnode *, struct dquot *); 118int dq1sync(struct vnode *, struct dquot *);
116int quota1_handle_cmd_get(struct ufsmount *, const struct quotakey *, 119int quota1_handle_cmd_get(struct ufsmount *, const struct quotakey *,
117 struct quotaval *); 120 struct quotaval *);
118int quota1_handle_cmd_put(struct ufsmount *, const struct quotakey *, 121int quota1_handle_cmd_put(struct ufsmount *, const struct quotakey *,
119 const struct quotaval *); 122 const struct quotaval *);
120int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int, 123int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int,
121 const char *); 124 const char *);
122int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int); 125int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int);
123 126
124int chkdq2(struct inode *, int64_t, kauth_cred_t, int); 127int chkdq2(struct inode *, int64_t, kauth_cred_t, int);
125int chkiq2(struct inode *, int32_t, kauth_cred_t, int); 128int chkiq2(struct inode *, int32_t, kauth_cred_t, int);
126int quota2_handle_cmd_get(struct ufsmount *, const struct quotakey *, 129int quota2_handle_cmd_get(struct ufsmount *, const struct quotakey *,
127 struct quotaval *); 130 struct quotaval *);
128int quota2_handle_cmd_put(struct ufsmount *, const struct quotakey *, 131int quota2_handle_cmd_put(struct ufsmount *, const struct quotakey *,
129 const struct quotaval *); 132 const struct quotaval *);
130int quota2_handle_cmd_delete(struct ufsmount *, const struct quotakey *); 133int quota2_handle_cmd_delete(struct ufsmount *, const struct quotakey *);
131int quota2_handle_cmd_getall(struct ufsmount *, int, prop_array_t); 134int quota2_handle_cmd_getall(struct ufsmount *, int, prop_array_t);
 135int quota2_handle_cmd_cursoropen(struct ufsmount *, struct quotakcursor *);
 136int quota2_handle_cmd_cursorclose(struct ufsmount *, struct quotakcursor *);
132int q2sync(struct mount *); 137int q2sync(struct mount *);
133int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); 138int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *);
134int dq2sync(struct vnode *, struct dquot *); 139int dq2sync(struct vnode *, struct dquot *);

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

--- src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 06:55:44 1.15
+++ src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 06:57:15 1.16
@@ -1,1108 +1,1142 @@ @@ -1,1108 +1,1142 @@
1/* $NetBSD: ufs_quota2.c,v 1.15 2012/01/29 06:55:44 dholland Exp $ */ 1/* $NetBSD: ufs_quota2.c,v 1.16 2012/01/29 06:57:15 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.15 2012/01/29 06:55:44 dholland Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.16 2012/01/29 06:57:15 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 46
46#include <ufs/ufs/quota2.h> 47#include <ufs/ufs/quota2.h>
47#include <ufs/ufs/inode.h> 48#include <ufs/ufs/inode.h>
48#include <ufs/ufs/ufsmount.h> 49#include <ufs/ufs/ufsmount.h>
49#include <ufs/ufs/ufs_bswap.h> 50#include <ufs/ufs/ufs_bswap.h>
50#include <ufs/ufs/ufs_extern.h> 51#include <ufs/ufs/ufs_extern.h>
51#include <ufs/ufs/ufs_quota.h> 52#include <ufs/ufs/ufs_quota.h>
52#include <ufs/ufs/ufs_wapbl.h> 53#include <ufs/ufs/ufs_wapbl.h>
53#include <quota/quotaprop.h> 54#include <quota/quotaprop.h>
54 55
55/* 56/*
56 * LOCKING: 57 * LOCKING:
57 * 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
58 * 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
59 * grabing a dquot for it). 60 * grabing a dquot for it).
60 * 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)
61 * are protected by the global dqlock. 62 * are protected by the global dqlock.
62 * the locking order is dq_interlock -> dqlock 63 * the locking order is dq_interlock -> dqlock
63 */ 64 */
64 65
65static int quota2_bwrite(struct mount *, struct buf *); 66static int quota2_bwrite(struct mount *, struct buf *);
66static int getinoquota2(struct inode *, bool, bool, struct buf **, 67static int getinoquota2(struct inode *, bool, bool, struct buf **,
67 struct quota2_entry **); 68 struct quota2_entry **);
68static int getq2h(struct ufsmount *, int, struct buf **, 69static int getq2h(struct ufsmount *, int, struct buf **,
69 struct quota2_header **, int); 70 struct quota2_header **, int);
70static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **, 71static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **,
71 struct quota2_entry **, int); 72 struct quota2_entry **, int);
72static int quota2_walk_list(struct ufsmount *, struct buf *, int, 73static int quota2_walk_list(struct ufsmount *, struct buf *, int,
73 uint64_t *, int, void *, 74 uint64_t *, int, void *,
74 int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, 75 int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *,
75 uint64_t, void *)); 76 uint64_t, void *));
76 77
77static prop_dictionary_t q2etoprop(struct quota2_entry *, int); 78static prop_dictionary_t q2etoprop(struct quota2_entry *, int);
78 79
79static const char *limnames[] = INITQLNAMES; 80static const char *limnames[] = INITQLNAMES;
80 81
81static void 82static void
82quota2_dict_update_q2e_limits(int objtype, const struct quotaval *val, 83quota2_dict_update_q2e_limits(int objtype, const struct quotaval *val,
83 struct quota2_entry *q2e) 84 struct quota2_entry *q2e)
84{ 85{
85 /* make sure we can index q2e_val[] by the fs-independent objtype */ 86 /* make sure we can index q2e_val[] by the fs-independent objtype */
86 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK); 87 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK);
87 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE); 88 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE);
88 89
89 q2e->q2e_val[objtype].q2v_hardlimit = val->qv_hardlimit; 90 q2e->q2e_val[objtype].q2v_hardlimit = val->qv_hardlimit;
90 q2e->q2e_val[objtype].q2v_softlimit = val->qv_softlimit; 91 q2e->q2e_val[objtype].q2v_softlimit = val->qv_softlimit;
91 q2e->q2e_val[objtype].q2v_grace = val->qv_grace; 92 q2e->q2e_val[objtype].q2v_grace = val->qv_grace;
92} 93}
93 94
94static prop_dictionary_t 95static prop_dictionary_t
95q2etoprop(struct quota2_entry *q2e, int def) 96q2etoprop(struct quota2_entry *q2e, int def)
96{ 97{
97 const char *val_names[] = INITQVNAMES_ALL; 98 const char *val_names[] = INITQVNAMES_ALL;
98 prop_dictionary_t dict1 = prop_dictionary_create(); 99 prop_dictionary_t dict1 = prop_dictionary_create();
99 prop_dictionary_t dict2; 100 prop_dictionary_t dict2;
100 int i; 101 int i;
101 102
102 if (dict1 == NULL) 103 if (dict1 == NULL)
103 return NULL; 104 return NULL;
104 105
105 if (def) { 106 if (def) {
106 if (!prop_dictionary_set_cstring_nocopy(dict1, "id", 107 if (!prop_dictionary_set_cstring_nocopy(dict1, "id",
107 "default")) { 108 "default")) {
108 goto err; 109 goto err;
109 } 110 }
110 } else { 111 } else {
111 if (!prop_dictionary_set_uint32(dict1, "id", q2e->q2e_uid)) { 112 if (!prop_dictionary_set_uint32(dict1, "id", q2e->q2e_uid)) {
112 goto err; 113 goto err;
113 } 114 }
114 } 115 }
115 for (i = 0; i < N_QL; i++) { 116 for (i = 0; i < N_QL; i++) {
116 dict2 = limits64toprop(&q2e->q2e_val[i].q2v_hardlimit, 117 dict2 = limits64toprop(&q2e->q2e_val[i].q2v_hardlimit,
117 val_names, N_QV); 118 val_names, N_QV);
118 if (dict2 == NULL) 119 if (dict2 == NULL)
119 goto err; 120 goto err;
120 if (!prop_dictionary_set_and_rel(dict1, limnames[i], dict2)) 121 if (!prop_dictionary_set_and_rel(dict1, limnames[i], dict2))
121 goto err; 122 goto err;
122 } 123 }
123 return dict1; 124 return dict1;
124 125
125err: 126err:
126 prop_object_release(dict1); 127 prop_object_release(dict1);
127 return NULL; 128 return NULL;
128} 129}
129 130
130/* 131/*
131 * Convert internal representation to FS-independent representation. 132 * Convert internal representation to FS-independent representation.
132 * (Note that while the two types are currently identical, the 133 * (Note that while the two types are currently identical, the
133 * internal representation is an on-disk struct and the FS-independent 134 * internal representation is an on-disk struct and the FS-independent
134 * representation is not, and they might diverge in the future.) 135 * representation is not, and they might diverge in the future.)
135 */ 136 */
136static void 137static void
137q2val_to_quotaval(struct quota2_val *q2v, struct quotaval *qv) 138q2val_to_quotaval(struct quota2_val *q2v, struct quotaval *qv)
138{ 139{
139 qv->qv_softlimit = q2v->q2v_softlimit; 140 qv->qv_softlimit = q2v->q2v_softlimit;
140 qv->qv_hardlimit = q2v->q2v_hardlimit; 141 qv->qv_hardlimit = q2v->q2v_hardlimit;
141 qv->qv_usage = q2v->q2v_cur; 142 qv->qv_usage = q2v->q2v_cur;
142 qv->qv_expiretime = q2v->q2v_time; 143 qv->qv_expiretime = q2v->q2v_time;
143 qv->qv_grace = q2v->q2v_grace; 144 qv->qv_grace = q2v->q2v_grace;
144} 145}
145 146
146/* 147/*
147 * Convert a quota2entry and default-flag to the FS-independent 148 * Convert a quota2entry and default-flag to the FS-independent
148 * representation. 149 * representation.
149 */ 150 */
150static void 151static void
151q2e_to_quotaval(struct quota2_entry *q2e, int def, 152q2e_to_quotaval(struct quota2_entry *q2e, int def,
152 id_t *id, int objtype, struct quotaval *ret) 153 id_t *id, int objtype, struct quotaval *ret)
153{ 154{
154 if (def) { 155 if (def) {
155 *id = QUOTA_DEFAULTID; 156 *id = QUOTA_DEFAULTID;
156 } else { 157 } else {
157 *id = q2e->q2e_uid; 158 *id = q2e->q2e_uid;
158 } 159 }
159 160
160 KASSERT(objtype >= 0 && objtype < N_QL); 161 KASSERT(objtype >= 0 && objtype < N_QL);
161 q2val_to_quotaval(&q2e->q2e_val[objtype], ret); 162 q2val_to_quotaval(&q2e->q2e_val[objtype], ret);
162} 163}
163 164
164 165
165static int 166static int
166quota2_bwrite(struct mount *mp, struct buf *bp) 167quota2_bwrite(struct mount *mp, struct buf *bp)
167{ 168{
168 if (mp->mnt_flag & MNT_SYNCHRONOUS) 169 if (mp->mnt_flag & MNT_SYNCHRONOUS)
169 return bwrite(bp); 170 return bwrite(bp);
170 else { 171 else {
171 bdwrite(bp); 172 bdwrite(bp);
172 return 0; 173 return 0;
173 } 174 }
174} 175}
175 176
176static int 177static int
177getq2h(struct ufsmount *ump, int type, 178getq2h(struct ufsmount *ump, int type,
178 struct buf **bpp, struct quota2_header **q2hp, int flags) 179 struct buf **bpp, struct quota2_header **q2hp, int flags)
179{ 180{
180#ifdef FFS_EI 181#ifdef FFS_EI
181 const int needswap = UFS_MPNEEDSWAP(ump); 182 const int needswap = UFS_MPNEEDSWAP(ump);
182#endif 183#endif
183 int error; 184 int error;
184 struct buf *bp; 185 struct buf *bp;
185 struct quota2_header *q2h; 186 struct quota2_header *q2h;
186 187
187 KASSERT(mutex_owned(&dqlock)); 188 KASSERT(mutex_owned(&dqlock));
188 error = bread(ump->um_quotas[type], 0, ump->umq2_bsize, 189 error = bread(ump->um_quotas[type], 0, ump->umq2_bsize,
189 ump->um_cred[type], flags, &bp); 190 ump->um_cred[type], flags, &bp);
190 if (error) 191 if (error)
191 return error; 192 return error;
192 if (bp->b_resid != 0)  193 if (bp->b_resid != 0)
193 panic("dq2get: %s quota file truncated", quotatypes[type]); 194 panic("dq2get: %s quota file truncated", quotatypes[type]);
194 195
195 q2h = (void *)bp->b_data; 196 q2h = (void *)bp->b_data;
196 if (ufs_rw32(q2h->q2h_magic_number, needswap) != Q2_HEAD_MAGIC || 197 if (ufs_rw32(q2h->q2h_magic_number, needswap) != Q2_HEAD_MAGIC ||
197 q2h->q2h_type != type) 198 q2h->q2h_type != type)
198 panic("dq2get: corrupted %s quota header", quotatypes[type]); 199 panic("dq2get: corrupted %s quota header", quotatypes[type]);
199 *bpp = bp; 200 *bpp = bp;
200 *q2hp = q2h; 201 *q2hp = q2h;
201 return 0; 202 return 0;
202} 203}
203 204
204static int 205static int
205getq2e(struct ufsmount *ump, int type, daddr_t lblkno, int blkoffset, 206getq2e(struct ufsmount *ump, int type, daddr_t lblkno, int blkoffset,
206 struct buf **bpp, struct quota2_entry **q2ep, int flags) 207 struct buf **bpp, struct quota2_entry **q2ep, int flags)
207{ 208{
208 int error; 209 int error;
209 struct buf *bp; 210 struct buf *bp;
210 211
211 if (blkoffset & (sizeof(uint64_t) - 1)) { 212 if (blkoffset & (sizeof(uint64_t) - 1)) {
212 panic("dq2get: %s quota file corrupted", 213 panic("dq2get: %s quota file corrupted",
213 quotatypes[type]); 214 quotatypes[type]);
214 } 215 }
215 error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize, 216 error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize,
216 ump->um_cred[type], flags, &bp); 217 ump->um_cred[type], flags, &bp);
217 if (error) 218 if (error)
218 return error; 219 return error;
219 if (bp->b_resid != 0) { 220 if (bp->b_resid != 0) {
220 panic("dq2get: %s quota file corrupted", 221 panic("dq2get: %s quota file corrupted",
221 quotatypes[type]); 222 quotatypes[type]);
222 } 223 }
223 *q2ep = (void *)((char *)bp->b_data + blkoffset); 224 *q2ep = (void *)((char *)bp->b_data + blkoffset);
224 *bpp = bp; 225 *bpp = bp;
225 return 0; 226 return 0;
226} 227}
227 228
228/* walk a quota entry list, calling the callback for each entry */ 229/* walk a quota entry list, calling the callback for each entry */
229#define Q2WL_ABORT 0x10000000 230#define Q2WL_ABORT 0x10000000
230 231
231static int 232static int
232quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type, 233quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type,
233 uint64_t *offp, int flags, void *a, 234 uint64_t *offp, int flags, void *a,
234 int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *)) 235 int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *))
235{ 236{
236#ifdef FFS_EI 237#ifdef FFS_EI
237 const int needswap = UFS_MPNEEDSWAP(ump); 238 const int needswap = UFS_MPNEEDSWAP(ump);
238#endif 239#endif
239 daddr_t off = ufs_rw64(*offp, needswap); 240 daddr_t off = ufs_rw64(*offp, needswap);
240 struct buf *bp, *obp = hbp; 241 struct buf *bp, *obp = hbp;
241 int ret = 0, ret2 = 0; 242 int ret = 0, ret2 = 0;
242 struct quota2_entry *q2e; 243 struct quota2_entry *q2e;
243 daddr_t lblkno, blkoff, olblkno = 0; 244 daddr_t lblkno, blkoff, olblkno = 0;
244 245
245 KASSERT(mutex_owner(&dqlock)); 246 KASSERT(mutex_owner(&dqlock));
246 247
247 while (off != 0) { 248 while (off != 0) {
248 lblkno = (off >> ump->um_mountp->mnt_fs_bshift); 249 lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
249 blkoff = (off & ump->umq2_bmask); 250 blkoff = (off & ump->umq2_bmask);
250 if (lblkno == 0) { 251 if (lblkno == 0) {
251 /* in the header block */ 252 /* in the header block */
252 bp = hbp; 253 bp = hbp;
253 } else if (lblkno == olblkno) { 254 } else if (lblkno == olblkno) {
254 /* still in the same buf */ 255 /* still in the same buf */
255 bp = obp; 256 bp = obp;
256 } else { 257 } else {
257 ret = bread(ump->um_quotas[type], lblkno,  258 ret = bread(ump->um_quotas[type], lblkno,
258 ump->umq2_bsize, 259 ump->umq2_bsize,
259 ump->um_cred[type], flags, &bp); 260 ump->um_cred[type], flags, &bp);
260 if (ret) 261 if (ret)
261 return ret; 262 return ret;
262 if (bp->b_resid != 0) { 263 if (bp->b_resid != 0) {
263 panic("quota2_walk_list: %s quota file corrupted", 264 panic("quota2_walk_list: %s quota file corrupted",
264 quotatypes[type]); 265 quotatypes[type]);
265 } 266 }
266 } 267 }
267 q2e = (void *)((char *)(bp->b_data) + blkoff); 268 q2e = (void *)((char *)(bp->b_data) + blkoff);
268 ret = (*func)(ump, offp, q2e, off, a); 269 ret = (*func)(ump, offp, q2e, off, a);
269 if (off != ufs_rw64(*offp, needswap)) { 270 if (off != ufs_rw64(*offp, needswap)) {
270 /* callback changed parent's pointer, redo */ 271 /* callback changed parent's pointer, redo */
271 off = ufs_rw64(*offp, needswap); 272 off = ufs_rw64(*offp, needswap);
272 if (bp != hbp && bp != obp) 273 if (bp != hbp && bp != obp)
273 ret2 = bwrite(bp); 274 ret2 = bwrite(bp);
274 } else { 275 } else {
275 /* parent if now current */ 276 /* parent if now current */
276 if (obp != bp && obp != hbp) { 277 if (obp != bp && obp != hbp) {
277 if (flags & B_MODIFY) 278 if (flags & B_MODIFY)
278 ret2 = bwrite(obp); 279 ret2 = bwrite(obp);
279 else 280 else
280 brelse(obp, 0); 281 brelse(obp, 0);
281 } 282 }
282 obp = bp; 283 obp = bp;
283 olblkno = lblkno; 284 olblkno = lblkno;
284 offp = &(q2e->q2e_next); 285 offp = &(q2e->q2e_next);
285 off = ufs_rw64(*offp, needswap); 286 off = ufs_rw64(*offp, needswap);
286 } 287 }
287 if (ret) 288 if (ret)
288 break; 289 break;
289 if (ret2) { 290 if (ret2) {
290 ret = ret2; 291 ret = ret2;
291 break; 292 break;
292 } 293 }
293 } 294 }
294 if (obp != hbp) { 295 if (obp != hbp) {
295 if (flags & B_MODIFY) 296 if (flags & B_MODIFY)
296 ret2 = bwrite(obp); 297 ret2 = bwrite(obp);
297 else 298 else
298 brelse(obp, 0); 299 brelse(obp, 0);
299 } 300 }
300 if (ret & Q2WL_ABORT) 301 if (ret & Q2WL_ABORT)
301 return 0; 302 return 0;
302 if (ret == 0) 303 if (ret == 0)
303 return ret2; 304 return ret2;
304 return ret; 305 return ret;
305} 306}
306 307
307int 308int
308quota2_umount(struct mount *mp, int flags) 309quota2_umount(struct mount *mp, int flags)
309{ 310{
310 int i, error; 311 int i, error;
311 struct ufsmount *ump = VFSTOUFS(mp); 312 struct ufsmount *ump = VFSTOUFS(mp);
312 313
313 if ((ump->um_flags & UFS_QUOTA2) == 0) 314 if ((ump->um_flags & UFS_QUOTA2) == 0)
314 return 0; 315 return 0;
315 316
316 for (i = 0; i < MAXQUOTAS; i++) { 317 for (i = 0; i < MAXQUOTAS; i++) {
317 if (ump->um_quotas[i] != NULLVP) { 318 if (ump->um_quotas[i] != NULLVP) {
318 error = vn_close(ump->um_quotas[i], FREAD|FWRITE, 319 error = vn_close(ump->um_quotas[i], FREAD|FWRITE,
319 ump->um_cred[i]); 320 ump->um_cred[i]);
320 if (error) { 321 if (error) {
321 printf("quota2_umount failed: close(%p) %d\n", 322 printf("quota2_umount failed: close(%p) %d\n",
322 ump->um_quotas[i], error); 323 ump->um_quotas[i], error);
323 return error; 324 return error;
324 } 325 }
325 } 326 }
326 ump->um_quotas[i] = NULLVP; 327 ump->um_quotas[i] = NULLVP;
327 } 328 }
328 return 0; 329 return 0;
329} 330}
330 331
331static int  332static int
332quota2_q2ealloc(struct ufsmount *ump, int type, uid_t uid, struct dquot *dq, 333quota2_q2ealloc(struct ufsmount *ump, int type, uid_t uid, struct dquot *dq,
333 struct buf **bpp, struct quota2_entry **q2ep) 334 struct buf **bpp, struct quota2_entry **q2ep)
334{ 335{
335 int error, error2; 336 int error, error2;
336 struct buf *hbp, *bp; 337 struct buf *hbp, *bp;
337 struct quota2_header *q2h; 338 struct quota2_header *q2h;
338 struct quota2_entry *q2e; 339 struct quota2_entry *q2e;
339 daddr_t offset; 340 daddr_t offset;
340 u_long hash_mask; 341 u_long hash_mask;
341 const int needswap = UFS_MPNEEDSWAP(ump); 342 const int needswap = UFS_MPNEEDSWAP(ump);
342 343
343 KASSERT(mutex_owned(&dq->dq_interlock)); 344 KASSERT(mutex_owned(&dq->dq_interlock));
344 KASSERT(mutex_owned(&dqlock)); 345 KASSERT(mutex_owned(&dqlock));
345 error = getq2h(ump, type, &hbp, &q2h, B_MODIFY); 346 error = getq2h(ump, type, &hbp, &q2h, B_MODIFY);
346 if (error) 347 if (error)
347 return error; 348 return error;
348 offset = ufs_rw64(q2h->q2h_free, needswap); 349 offset = ufs_rw64(q2h->q2h_free, needswap);
349 if (offset == 0) { 350 if (offset == 0) {
350 struct vnode *vp = ump->um_quotas[type]; 351 struct vnode *vp = ump->um_quotas[type];
351 struct inode *ip = VTOI(vp); 352 struct inode *ip = VTOI(vp);
352 uint64_t size = ip->i_size; 353 uint64_t size = ip->i_size;
353 /* need to alocate a new disk block */ 354 /* need to alocate a new disk block */
354 error = UFS_BALLOC(vp, size, ump->umq2_bsize, 355 error = UFS_BALLOC(vp, size, ump->umq2_bsize,
355 ump->um_cred[type], B_CLRBUF | B_SYNC, &bp); 356 ump->um_cred[type], B_CLRBUF | B_SYNC, &bp);
356 if (error) { 357 if (error) {
357 brelse(hbp, 0); 358 brelse(hbp, 0);
358 return error; 359 return error;
359 } 360 }
360 KASSERT((ip->i_size % ump->umq2_bsize) == 0); 361 KASSERT((ip->i_size % ump->umq2_bsize) == 0);
361 ip->i_size += ump->umq2_bsize; 362 ip->i_size += ump->umq2_bsize;
362 DIP_ASSIGN(ip, size, ip->i_size); 363 DIP_ASSIGN(ip, size, ip->i_size);
363 ip->i_flag |= IN_CHANGE | IN_UPDATE; 364 ip->i_flag |= IN_CHANGE | IN_UPDATE;
364 uvm_vnp_setsize(vp, ip->i_size); 365 uvm_vnp_setsize(vp, ip->i_size);
365 quota2_addfreeq2e(q2h, bp->b_data, size, ump->umq2_bsize, 366 quota2_addfreeq2e(q2h, bp->b_data, size, ump->umq2_bsize,
366 needswap); 367 needswap);
367 error = bwrite(bp); 368 error = bwrite(bp);
368 error2 = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT); 369 error2 = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
369 if (error || error2) { 370 if (error || error2) {
370 brelse(hbp, 0); 371 brelse(hbp, 0);
371 if (error) 372 if (error)
372 return error; 373 return error;
373 return error2; 374 return error2;
374 } 375 }
375 offset = ufs_rw64(q2h->q2h_free, needswap); 376 offset = ufs_rw64(q2h->q2h_free, needswap);
376 KASSERT(offset != 0); 377 KASSERT(offset != 0);
377 } 378 }
378 dq->dq2_lblkno = (offset >> ump->um_mountp->mnt_fs_bshift); 379 dq->dq2_lblkno = (offset >> ump->um_mountp->mnt_fs_bshift);
379 dq->dq2_blkoff = (offset & ump->umq2_bmask); 380 dq->dq2_blkoff = (offset & ump->umq2_bmask);
380 if (dq->dq2_lblkno == 0) { 381 if (dq->dq2_lblkno == 0) {
381 bp = hbp; 382 bp = hbp;
382 q2e = (void *)((char *)bp->b_data + dq->dq2_blkoff); 383 q2e = (void *)((char *)bp->b_data + dq->dq2_blkoff);
383 } else { 384 } else {
384 error = getq2e(ump, type, dq->dq2_lblkno, 385 error = getq2e(ump, type, dq->dq2_lblkno,
385 dq->dq2_blkoff, &bp, &q2e, B_MODIFY); 386 dq->dq2_blkoff, &bp, &q2e, B_MODIFY);
386 if (error) { 387 if (error) {
387 brelse(hbp, 0); 388 brelse(hbp, 0);
388 return error; 389 return error;
389 } 390 }
390 } 391 }
391 hash_mask = ((1 << q2h->q2h_hash_shift) - 1); 392 hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
392 /* remove from free list */ 393 /* remove from free list */
393 q2h->q2h_free = q2e->q2e_next; 394 q2h->q2h_free = q2e->q2e_next;
394 395
395 memcpy(q2e, &q2h->q2h_defentry, sizeof(*q2e)); 396 memcpy(q2e, &q2h->q2h_defentry, sizeof(*q2e));
396 q2e->q2e_uid = ufs_rw32(uid, needswap); 397 q2e->q2e_uid = ufs_rw32(uid, needswap);
397 /* insert in hash list */  398 /* insert in hash list */
398 q2e->q2e_next = q2h->q2h_entries[uid & hash_mask]; 399 q2e->q2e_next = q2h->q2h_entries[uid & hash_mask];
399 q2h->q2h_entries[uid & hash_mask] = ufs_rw64(offset, needswap); 400 q2h->q2h_entries[uid & hash_mask] = ufs_rw64(offset, needswap);
400 if (hbp != bp) { 401 if (hbp != bp) {
401 bwrite(hbp); 402 bwrite(hbp);
402 } 403 }
403 *q2ep = q2e; 404 *q2ep = q2e;
404 *bpp = bp; 405 *bpp = bp;
405 return 0; 406 return 0;
406} 407}
407 408
408static int 409static int
409getinoquota2(struct inode *ip, bool alloc, bool modify, struct buf **bpp, 410getinoquota2(struct inode *ip, bool alloc, bool modify, struct buf **bpp,
410 struct quota2_entry **q2ep) 411 struct quota2_entry **q2ep)
411{ 412{
412 int error; 413 int error;
413 int i; 414 int i;
414 struct dquot *dq; 415 struct dquot *dq;
415 struct ufsmount *ump = ip->i_ump; 416 struct ufsmount *ump = ip->i_ump;
416 u_int32_t ino_ids[MAXQUOTAS]; 417 u_int32_t ino_ids[MAXQUOTAS];
417 418
418 error = getinoquota(ip); 419 error = getinoquota(ip);
419 if (error) 420 if (error)
420 return error; 421 return error;
421 422
422 if (alloc) { 423 if (alloc) {
423 UFS_WAPBL_JLOCK_ASSERT(ump->um_mountp); 424 UFS_WAPBL_JLOCK_ASSERT(ump->um_mountp);
424 } 425 }
425 ino_ids[USRQUOTA] = ip->i_uid; 426 ino_ids[USRQUOTA] = ip->i_uid;
426 ino_ids[GRPQUOTA] = ip->i_gid; 427 ino_ids[GRPQUOTA] = ip->i_gid;
427 /* first get the interlock for all dquot */ 428 /* first get the interlock for all dquot */
428 for (i = 0; i < MAXQUOTAS; i++) { 429 for (i = 0; i < MAXQUOTAS; i++) {
429 dq = ip->i_dquot[i]; 430 dq = ip->i_dquot[i];
430 if (dq == NODQUOT) 431 if (dq == NODQUOT)
431 continue; 432 continue;
432 mutex_enter(&dq->dq_interlock); 433 mutex_enter(&dq->dq_interlock);
433 } 434 }
434 /* now get the corresponding quota entry */ 435 /* now get the corresponding quota entry */
435 for (i = 0; i < MAXQUOTAS; i++) { 436 for (i = 0; i < MAXQUOTAS; i++) {
436 bpp[i] = NULL; 437 bpp[i] = NULL;
437 q2ep[i] = NULL; 438 q2ep[i] = NULL;
438 dq = ip->i_dquot[i]; 439 dq = ip->i_dquot[i];
439 if (dq == NODQUOT) 440 if (dq == NODQUOT)
440 continue; 441 continue;
441 if (__predict_false(ump->um_quotas[i] == NULL)) { 442 if (__predict_false(ump->um_quotas[i] == NULL)) {
442 /* 443 /*
443 * quotas have been turned off. This can happen 444 * quotas have been turned off. This can happen
444 * at umount time. 445 * at umount time.
445 */ 446 */
446 mutex_exit(&dq->dq_interlock); 447 mutex_exit(&dq->dq_interlock);
447 dqrele(NULLVP, dq); 448 dqrele(NULLVP, dq);
448 ip->i_dquot[i] = NULL; 449 ip->i_dquot[i] = NULL;
449 continue; 450 continue;
450 } 451 }
451 452
452 if ((dq->dq2_lblkno | dq->dq2_blkoff) == 0) { 453 if ((dq->dq2_lblkno | dq->dq2_blkoff) == 0) {
453 if (!alloc) { 454 if (!alloc) {
454 continue; 455 continue;
455 } 456 }
456 /* need to alloc a new on-disk quot */ 457 /* need to alloc a new on-disk quot */
457 mutex_enter(&dqlock); 458 mutex_enter(&dqlock);
458 error = quota2_q2ealloc(ump, i, ino_ids[i], dq, 459 error = quota2_q2ealloc(ump, i, ino_ids[i], dq,
459 &bpp[i], &q2ep[i]); 460 &bpp[i], &q2ep[i]);
460 mutex_exit(&dqlock); 461 mutex_exit(&dqlock);
461 if (error) 462 if (error)
462 return error; 463 return error;
463 } else { 464 } else {
464 error = getq2e(ump, i, dq->dq2_lblkno, 465 error = getq2e(ump, i, dq->dq2_lblkno,
465 dq->dq2_blkoff, &bpp[i], &q2ep[i], 466 dq->dq2_blkoff, &bpp[i], &q2ep[i],
466 modify ? B_MODIFY : 0); 467 modify ? B_MODIFY : 0);
467 if (error) 468 if (error)
468 return error; 469 return error;
469 } 470 }
470 } 471 }
471 return 0; 472 return 0;
472} 473}
473 474
474static int 475static int
475quota2_check(struct inode *ip, int vtype, int64_t change, kauth_cred_t cred, 476quota2_check(struct inode *ip, int vtype, int64_t change, kauth_cred_t cred,
476 int flags) 477 int flags)
477{ 478{
478 int error; 479 int error;
479 struct buf *bp[MAXQUOTAS]; 480 struct buf *bp[MAXQUOTAS];
480 struct quota2_entry *q2e[MAXQUOTAS]; 481 struct quota2_entry *q2e[MAXQUOTAS];
481 struct quota2_val *q2vp; 482 struct quota2_val *q2vp;
482 struct dquot *dq; 483 struct dquot *dq;
483 uint64_t ncurblks; 484 uint64_t ncurblks;
484 struct ufsmount *ump = ip->i_ump; 485 struct ufsmount *ump = ip->i_ump;
485 struct mount *mp = ump->um_mountp; 486 struct mount *mp = ump->um_mountp;
486 const int needswap = UFS_MPNEEDSWAP(ump); 487 const int needswap = UFS_MPNEEDSWAP(ump);
487 int i; 488 int i;
488 489
489 if ((error = getinoquota2(ip, change > 0, change != 0, bp, q2e)) != 0) 490 if ((error = getinoquota2(ip, change > 0, change != 0, bp, q2e)) != 0)
490 return error; 491 return error;
491 if (change == 0) { 492 if (change == 0) {
492 for (i = 0; i < MAXQUOTAS; i++) { 493 for (i = 0; i < MAXQUOTAS; i++) {
493 dq = ip->i_dquot[i]; 494 dq = ip->i_dquot[i];
494 if (dq == NODQUOT) 495 if (dq == NODQUOT)
495 continue; 496 continue;
496 if (bp[i]) 497 if (bp[i])
497 brelse(bp[i], 0); 498 brelse(bp[i], 0);
498 mutex_exit(&dq->dq_interlock); 499 mutex_exit(&dq->dq_interlock);
499 } 500 }
500 return 0; 501 return 0;
501 } 502 }
502 if (change < 0) { 503 if (change < 0) {
503 for (i = 0; i < MAXQUOTAS; i++) { 504 for (i = 0; i < MAXQUOTAS; i++) {
504 dq = ip->i_dquot[i]; 505 dq = ip->i_dquot[i];
505 if (dq == NODQUOT) 506 if (dq == NODQUOT)
506 continue; 507 continue;
507 if (q2e[i] == NULL) { 508 if (q2e[i] == NULL) {
508 mutex_exit(&dq->dq_interlock); 509 mutex_exit(&dq->dq_interlock);
509 continue; 510 continue;
510 } 511 }
511 q2vp = &q2e[i]->q2e_val[vtype]; 512 q2vp = &q2e[i]->q2e_val[vtype];
512 ncurblks = ufs_rw64(q2vp->q2v_cur, needswap); 513 ncurblks = ufs_rw64(q2vp->q2v_cur, needswap);
513 if (ncurblks < -change) 514 if (ncurblks < -change)
514 ncurblks = 0; 515 ncurblks = 0;
515 else 516 else
516 ncurblks += change; 517 ncurblks += change;
517 q2vp->q2v_cur = ufs_rw64(ncurblks, needswap); 518 q2vp->q2v_cur = ufs_rw64(ncurblks, needswap);
518 quota2_bwrite(mp, bp[i]); 519 quota2_bwrite(mp, bp[i]);
519 mutex_exit(&dq->dq_interlock); 520 mutex_exit(&dq->dq_interlock);
520 } 521 }
521 return 0; 522 return 0;
522 } 523 }
523 /* see if the allocation is allowed */ 524 /* see if the allocation is allowed */
524 for (i = 0; i < MAXQUOTAS; i++) { 525 for (i = 0; i < MAXQUOTAS; i++) {
525 struct quota2_val q2v; 526 struct quota2_val q2v;
526 int ql_stat; 527 int ql_stat;
527 dq = ip->i_dquot[i]; 528 dq = ip->i_dquot[i];
528 if (dq == NODQUOT) 529 if (dq == NODQUOT)
529 continue; 530 continue;
530 KASSERT(q2e[i] != NULL); 531 KASSERT(q2e[i] != NULL);
531 quota2_ufs_rwq2v(&q2e[i]->q2e_val[vtype], &q2v, needswap); 532 quota2_ufs_rwq2v(&q2e[i]->q2e_val[vtype], &q2v, needswap);
532 ql_stat = quota2_check_limit(&q2v, change, time_second); 533 ql_stat = quota2_check_limit(&q2v, change, time_second);
533 534
534 if ((flags & FORCE) == 0 && 535 if ((flags & FORCE) == 0 &&
535 kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA, 536 kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA,
536 KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, 537 KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT,
537 KAUTH_ARG(i), KAUTH_ARG(vtype), NULL) != 0) { 538 KAUTH_ARG(i), KAUTH_ARG(vtype), NULL) != 0) {
538 /* enforce this limit */ 539 /* enforce this limit */
539 switch(QL_STATUS(ql_stat)) { 540 switch(QL_STATUS(ql_stat)) {
540 case QL_S_DENY_HARD: 541 case QL_S_DENY_HARD:
541 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { 542 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
542 uprintf("\n%s: write failed, %s %s " 543 uprintf("\n%s: write failed, %s %s "
543 "limit reached\n", 544 "limit reached\n",
544 mp->mnt_stat.f_mntonname, 545 mp->mnt_stat.f_mntonname,
545 quotatypes[i], limnames[vtype]); 546 quotatypes[i], limnames[vtype]);
546 dq->dq_flags |= DQ_WARN(vtype); 547 dq->dq_flags |= DQ_WARN(vtype);
547 } 548 }
548 error = EDQUOT; 549 error = EDQUOT;
549 break; 550 break;
550 case QL_S_DENY_GRACE: 551 case QL_S_DENY_GRACE:
551 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { 552 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
552 uprintf("\n%s: write failed, %s %s " 553 uprintf("\n%s: write failed, %s %s "
553 "limit reached\n", 554 "limit reached\n",
554 mp->mnt_stat.f_mntonname, 555 mp->mnt_stat.f_mntonname,
555 quotatypes[i], limnames[vtype]); 556 quotatypes[i], limnames[vtype]);
556 dq->dq_flags |= DQ_WARN(vtype); 557 dq->dq_flags |= DQ_WARN(vtype);
557 } 558 }
558 error = EDQUOT; 559 error = EDQUOT;
559 break; 560 break;
560 case QL_S_ALLOW_SOFT: 561 case QL_S_ALLOW_SOFT:
561 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { 562 if ((dq->dq_flags & DQ_WARN(vtype)) == 0) {
562 uprintf("\n%s: warning, %s %s " 563 uprintf("\n%s: warning, %s %s "
563 "quota exceeded\n", 564 "quota exceeded\n",
564 mp->mnt_stat.f_mntonname, 565 mp->mnt_stat.f_mntonname,
565 quotatypes[i], limnames[vtype]); 566 quotatypes[i], limnames[vtype]);
566 dq->dq_flags |= DQ_WARN(vtype); 567 dq->dq_flags |= DQ_WARN(vtype);
567 } 568 }
568 break; 569 break;
569 } 570 }
570 } 571 }
571 /* 572 /*
572 * always do this; we don't know if the allocation will 573 * always do this; we don't know if the allocation will
573 * succed or not in the end. if we don't do the allocation 574 * succed or not in the end. if we don't do the allocation
574 * q2v_time will be ignored anyway 575 * q2v_time will be ignored anyway
575 */ 576 */
576 if (ql_stat & QL_F_CROSS) { 577 if (ql_stat & QL_F_CROSS) {
577 q2v.q2v_time = time_second + q2v.q2v_grace; 578 q2v.q2v_time = time_second + q2v.q2v_grace;
578 quota2_ufs_rwq2v(&q2v, &q2e[i]->q2e_val[vtype], 579 quota2_ufs_rwq2v(&q2v, &q2e[i]->q2e_val[vtype],
579 needswap); 580 needswap);
580 } 581 }
581 } 582 }
582 583
583 /* now do the allocation if allowed */ 584 /* now do the allocation if allowed */
584 for (i = 0; i < MAXQUOTAS; i++) { 585 for (i = 0; i < MAXQUOTAS; i++) {
585 dq = ip->i_dquot[i]; 586 dq = ip->i_dquot[i];
586 if (dq == NODQUOT) 587 if (dq == NODQUOT)
587 continue; 588 continue;
588 KASSERT(q2e[i] != NULL); 589 KASSERT(q2e[i] != NULL);
589 if (error == 0) { 590 if (error == 0) {
590 q2vp = &q2e[i]->q2e_val[vtype]; 591 q2vp = &q2e[i]->q2e_val[vtype];
591 ncurblks = ufs_rw64(q2vp->q2v_cur, needswap); 592 ncurblks = ufs_rw64(q2vp->q2v_cur, needswap);
592 q2vp->q2v_cur = ufs_rw64(ncurblks + change, needswap); 593 q2vp->q2v_cur = ufs_rw64(ncurblks + change, needswap);
593 quota2_bwrite(mp, bp[i]); 594 quota2_bwrite(mp, bp[i]);
594 } else 595 } else
595 brelse(bp[i], 0); 596 brelse(bp[i], 0);
596 mutex_exit(&dq->dq_interlock); 597 mutex_exit(&dq->dq_interlock);
597 } 598 }
598 return error; 599 return error;
599} 600}
600 601
601int 602int
602chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) 603chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags)
603{ 604{
604 return quota2_check(ip, QL_BLOCK, change, cred, flags); 605 return quota2_check(ip, QL_BLOCK, change, cred, flags);
605} 606}
606 607
607int 608int
608chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) 609chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags)
609{ 610{
610 return quota2_check(ip, QL_FILE, change, cred, flags); 611 return quota2_check(ip, QL_FILE, change, cred, flags);
611} 612}
612 613
613int 614int
614quota2_handle_cmd_put(struct ufsmount *ump, const struct quotakey *key, 615quota2_handle_cmd_put(struct ufsmount *ump, const struct quotakey *key,
615 const struct quotaval *val) 616 const struct quotaval *val)
616{ 617{
617 int error; 618 int error;
618 struct dquot *dq; 619 struct dquot *dq;
619 struct quota2_header *q2h; 620 struct quota2_header *q2h;
620 struct quota2_entry q2e, *q2ep; 621 struct quota2_entry q2e, *q2ep;
621 struct buf *bp; 622 struct buf *bp;
622 const int needswap = UFS_MPNEEDSWAP(ump); 623 const int needswap = UFS_MPNEEDSWAP(ump);
623 624
624 /* make sure we can index by the fs-independent idtype */ 625 /* make sure we can index by the fs-independent idtype */
625 CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA); 626 CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA);
626 CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA); 627 CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA);
627 628
628 if (ump->um_quotas[key->qk_idtype] == NULLVP) 629 if (ump->um_quotas[key->qk_idtype] == NULLVP)
629 return ENODEV; 630 return ENODEV;
630 error = UFS_WAPBL_BEGIN(ump->um_mountp); 631 error = UFS_WAPBL_BEGIN(ump->um_mountp);
631 if (error) 632 if (error)
632 return error; 633 return error;
633  634
634 if (key->qk_id == QUOTA_DEFAULTID) { 635 if (key->qk_id == QUOTA_DEFAULTID) {
635 mutex_enter(&dqlock); 636 mutex_enter(&dqlock);
636 error = getq2h(ump, key->qk_idtype, &bp, &q2h, B_MODIFY); 637 error = getq2h(ump, key->qk_idtype, &bp, &q2h, B_MODIFY);
637 if (error) { 638 if (error) {
638 mutex_exit(&dqlock); 639 mutex_exit(&dqlock);
639 goto out_wapbl; 640 goto out_wapbl;
640 } 641 }
641 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 642 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
642 quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e); 643 quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e);
643 quota2_ufs_rwq2e(&q2e, &q2h->q2h_defentry, needswap); 644 quota2_ufs_rwq2e(&q2e, &q2h->q2h_defentry, needswap);
644 mutex_exit(&dqlock); 645 mutex_exit(&dqlock);
645 quota2_bwrite(ump->um_mountp, bp); 646 quota2_bwrite(ump->um_mountp, bp);
646 goto out_wapbl; 647 goto out_wapbl;
647 } 648 }
648 649
649 error = dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq); 650 error = dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq);
650 if (error) 651 if (error)
651 goto out_wapbl; 652 goto out_wapbl;
652 653
653 mutex_enter(&dq->dq_interlock); 654 mutex_enter(&dq->dq_interlock);
654 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 655 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
655 /* need to alloc a new on-disk quot */ 656 /* need to alloc a new on-disk quot */
656 mutex_enter(&dqlock); 657 mutex_enter(&dqlock);
657 error = quota2_q2ealloc(ump, key->qk_idtype, key->qk_id, dq, 658 error = quota2_q2ealloc(ump, key->qk_idtype, key->qk_id, dq,
658 &bp, &q2ep); 659 &bp, &q2ep);
659 mutex_exit(&dqlock); 660 mutex_exit(&dqlock);
660 } else { 661 } else {
661 error = getq2e(ump, key->qk_idtype, dq->dq2_lblkno, 662 error = getq2e(ump, key->qk_idtype, dq->dq2_lblkno,
662 dq->dq2_blkoff, &bp, &q2ep, B_MODIFY); 663 dq->dq2_blkoff, &bp, &q2ep, B_MODIFY);
663 } 664 }
664 if (error) 665 if (error)
665 goto out_il; 666 goto out_il;
666  667
667 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 668 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
668 quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e); 669 quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e);
669 quota2_ufs_rwq2e(&q2e, q2ep, needswap); 670 quota2_ufs_rwq2e(&q2e, q2ep, needswap);
670 quota2_bwrite(ump->um_mountp, bp); 671 quota2_bwrite(ump->um_mountp, bp);
671 672
672out_il: 673out_il:
673 mutex_exit(&dq->dq_interlock); 674 mutex_exit(&dq->dq_interlock);
674 dqrele(NULLVP, dq); 675 dqrele(NULLVP, dq);
675out_wapbl: 676out_wapbl:
676 UFS_WAPBL_END(ump->um_mountp); 677 UFS_WAPBL_END(ump->um_mountp);
677 return error; 678 return error;
678} 679}
679 680
680struct dq2clear_callback { 681struct dq2clear_callback {
681 uid_t id; 682 uid_t id;
682 struct dquot *dq; 683 struct dquot *dq;
683 struct quota2_header *q2h; 684 struct quota2_header *q2h;
684}; 685};
685 686
686static int 687static int
687dq2clear_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, 688dq2clear_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e,
688 uint64_t off, void *v) 689 uint64_t off, void *v)
689{ 690{
690 struct dq2clear_callback *c = v; 691 struct dq2clear_callback *c = v;
691#ifdef FFS_EI 692#ifdef FFS_EI
692 const int needswap = UFS_MPNEEDSWAP(ump); 693 const int needswap = UFS_MPNEEDSWAP(ump);
693#endif 694#endif
694 uint64_t myoff; 695 uint64_t myoff;
695 696
696 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { 697 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
697 KASSERT(mutex_owned(&c->dq->dq_interlock)); 698 KASSERT(mutex_owned(&c->dq->dq_interlock));
698 c->dq->dq2_lblkno = 0; 699 c->dq->dq2_lblkno = 0;
699 c->dq->dq2_blkoff = 0; 700 c->dq->dq2_blkoff = 0;
700 myoff = *offp; 701 myoff = *offp;
701 /* remove from hash list */ 702 /* remove from hash list */
702 *offp = q2e->q2e_next; 703 *offp = q2e->q2e_next;
703 /* add to free list */ 704 /* add to free list */
704 q2e->q2e_next = c->q2h->q2h_free; 705 q2e->q2e_next = c->q2h->q2h_free;
705 c->q2h->q2h_free = myoff; 706 c->q2h->q2h_free = myoff;
706 return Q2WL_ABORT; 707 return Q2WL_ABORT;
707 } 708 }
708 return 0; 709 return 0;
709} 710}
710int 711int
711quota2_handle_cmd_delete(struct ufsmount *ump, const struct quotakey *qk) 712quota2_handle_cmd_delete(struct ufsmount *ump, const struct quotakey *qk)
712{ 713{
713 int idtype; 714 int idtype;
714 id_t id; 715 id_t id;
715 int objtype; 716 int objtype;
716 int error, i, canfree; 717 int error, i, canfree;
717 struct dquot *dq; 718 struct dquot *dq;
718 struct quota2_header *q2h; 719 struct quota2_header *q2h;
719 struct quota2_entry q2e, *q2ep; 720 struct quota2_entry q2e, *q2ep;
720 struct buf *hbp, *bp; 721 struct buf *hbp, *bp;
721 u_long hash_mask; 722 u_long hash_mask;
722 struct dq2clear_callback c; 723 struct dq2clear_callback c;
723 724
724 idtype = qk->qk_idtype; 725 idtype = qk->qk_idtype;
725 id = qk->qk_id; 726 id = qk->qk_id;
726 objtype = qk->qk_objtype; 727 objtype = qk->qk_objtype;
727 728
728 if (ump->um_quotas[idtype] == NULLVP) 729 if (ump->um_quotas[idtype] == NULLVP)
729 return ENODEV; 730 return ENODEV;
730 if (id == QUOTA_DEFAULTID) 731 if (id == QUOTA_DEFAULTID)
731 return EOPNOTSUPP; 732 return EOPNOTSUPP;
732 733
733 /* get the default entry before locking the entry's buffer */ 734 /* get the default entry before locking the entry's buffer */
734 mutex_enter(&dqlock); 735 mutex_enter(&dqlock);
735 error = getq2h(ump, idtype, &hbp, &q2h, 0); 736 error = getq2h(ump, idtype, &hbp, &q2h, 0);
736 if (error) { 737 if (error) {
737 mutex_exit(&dqlock); 738 mutex_exit(&dqlock);
738 return error; 739 return error;
739 } 740 }
740 /* we'll copy to another disk entry, so no need to swap */ 741 /* we'll copy to another disk entry, so no need to swap */
741 memcpy(&q2e, &q2h->q2h_defentry, sizeof(q2e)); 742 memcpy(&q2e, &q2h->q2h_defentry, sizeof(q2e));
742 mutex_exit(&dqlock); 743 mutex_exit(&dqlock);
743 brelse(hbp, 0); 744 brelse(hbp, 0);
744 745
745 error = dqget(NULLVP, id, ump, idtype, &dq); 746 error = dqget(NULLVP, id, ump, idtype, &dq);
746 if (error) 747 if (error)
747 return error; 748 return error;
748 749
749 mutex_enter(&dq->dq_interlock); 750 mutex_enter(&dq->dq_interlock);
750 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 751 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
751 /* already clear, nothing to do */ 752 /* already clear, nothing to do */
752 error = ENOENT; 753 error = ENOENT;
753 goto out_il; 754 goto out_il;
754 } 755 }
755 error = UFS_WAPBL_BEGIN(ump->um_mountp); 756 error = UFS_WAPBL_BEGIN(ump->um_mountp);
756 if (error) 757 if (error)
757 goto out_dq; 758 goto out_dq;
758  759
759 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, 760 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff,
760 &bp, &q2ep, B_MODIFY); 761 &bp, &q2ep, B_MODIFY);
761 if (error) 762 if (error)
762 goto out_wapbl; 763 goto out_wapbl;
763 764
764 /* make sure we can index by the objtype passed in */ 765 /* make sure we can index by the objtype passed in */
765 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK); 766 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK);
766 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE); 767 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE);
767 768
768 /* clear the requested objtype by copying from the default entry */ 769 /* clear the requested objtype by copying from the default entry */
769 q2ep->q2e_val[objtype].q2v_softlimit = 770 q2ep->q2e_val[objtype].q2v_softlimit =
770 q2e.q2e_val[objtype].q2v_softlimit; 771 q2e.q2e_val[objtype].q2v_softlimit;
771 q2ep->q2e_val[objtype].q2v_hardlimit = 772 q2ep->q2e_val[objtype].q2v_hardlimit =
772 q2e.q2e_val[objtype].q2v_hardlimit; 773 q2e.q2e_val[objtype].q2v_hardlimit;
773 q2ep->q2e_val[objtype].q2v_grace = 774 q2ep->q2e_val[objtype].q2v_grace =
774 q2e.q2e_val[objtype].q2v_grace; 775 q2e.q2e_val[objtype].q2v_grace;
775 q2ep->q2e_val[objtype].q2v_time = 0; 776 q2ep->q2e_val[objtype].q2v_time = 0;
776 777
777 /* if this entry now contains no information, we can free it */ 778 /* if this entry now contains no information, we can free it */
778 canfree = 1; 779 canfree = 1;
779 for (i = 0; i < N_QL; i++) { 780 for (i = 0; i < N_QL; i++) {
780 if (q2ep->q2e_val[i].q2v_cur != 0 || 781 if (q2ep->q2e_val[i].q2v_cur != 0 ||
781 (q2ep->q2e_val[i].q2v_softlimit !=  782 (q2ep->q2e_val[i].q2v_softlimit !=
782 q2e.q2e_val[i].q2v_softlimit) || 783 q2e.q2e_val[i].q2v_softlimit) ||
783 (q2ep->q2e_val[i].q2v_hardlimit !=  784 (q2ep->q2e_val[i].q2v_hardlimit !=
784 q2e.q2e_val[i].q2v_hardlimit) || 785 q2e.q2e_val[i].q2v_hardlimit) ||
785 (q2ep->q2e_val[i].q2v_grace !=  786 (q2ep->q2e_val[i].q2v_grace !=
786 q2e.q2e_val[i].q2v_grace)) { 787 q2e.q2e_val[i].q2v_grace)) {
787 canfree = 0; 788 canfree = 0;
788 break; 789 break;
789 } 790 }
790 /* note: do not need to check q2v_time */ 791 /* note: do not need to check q2v_time */
791 } 792 }
792 793
793 if (canfree == 0) { 794 if (canfree == 0) {
794 quota2_bwrite(ump->um_mountp, bp); 795 quota2_bwrite(ump->um_mountp, bp);
795 goto out_wapbl; 796 goto out_wapbl;
796 } 797 }
797 /* we can free it. release bp so we can walk the list */ 798 /* we can free it. release bp so we can walk the list */
798 brelse(bp, 0); 799 brelse(bp, 0);
799 mutex_enter(&dqlock); 800 mutex_enter(&dqlock);
800 error = getq2h(ump, idtype, &hbp, &q2h, 0); 801 error = getq2h(ump, idtype, &hbp, &q2h, 0);
801 if (error) 802 if (error)
802 goto out_dqlock; 803 goto out_dqlock;
803 804
804 hash_mask = ((1 << q2h->q2h_hash_shift) - 1); 805 hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
805 c.dq = dq; 806 c.dq = dq;
806 c.id = id; 807 c.id = id;
807 c.q2h = q2h; 808 c.q2h = q2h;
808 error = quota2_walk_list(ump, hbp, idtype, 809 error = quota2_walk_list(ump, hbp, idtype,
809 &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c, 810 &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c,
810 dq2clear_callback); 811 dq2clear_callback);
811 812
812 bwrite(hbp); 813 bwrite(hbp);
813 814
814out_dqlock: 815out_dqlock:
815 mutex_exit(&dqlock); 816 mutex_exit(&dqlock);
816out_wapbl: 817out_wapbl:
817 UFS_WAPBL_END(ump->um_mountp); 818 UFS_WAPBL_END(ump->um_mountp);
818out_il: 819out_il:
819 mutex_exit(&dq->dq_interlock); 820 mutex_exit(&dq->dq_interlock);
820out_dq: 821out_dq:
821 dqrele(NULLVP, dq); 822 dqrele(NULLVP, dq);
822 return error; 823 return error;
823} 824}
824 825
825static int 826static int
826quota2_array_add_q2e(struct ufsmount *ump, int type, 827quota2_array_add_q2e(struct ufsmount *ump, int type,
827 int id, prop_array_t replies) 828 int id, prop_array_t replies)
828{ 829{
829 struct dquot *dq; 830 struct dquot *dq;
830 int error; 831 int error;
831 struct quota2_entry *q2ep, q2e; 832 struct quota2_entry *q2ep, q2e;
832 struct buf *bp; 833 struct buf *bp;
833 const int needswap = UFS_MPNEEDSWAP(ump); 834 const int needswap = UFS_MPNEEDSWAP(ump);
834 prop_dictionary_t dict; 835 prop_dictionary_t dict;
835 836
836 error = dqget(NULLVP, id, ump, type, &dq); 837 error = dqget(NULLVP, id, ump, type, &dq);
837 if (error) 838 if (error)
838 return error; 839 return error;
839 840
840 mutex_enter(&dq->dq_interlock); 841 mutex_enter(&dq->dq_interlock);
841 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 842 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
842 mutex_exit(&dq->dq_interlock); 843 mutex_exit(&dq->dq_interlock);
843 dqrele(NULLVP, dq); 844 dqrele(NULLVP, dq);
844 return ENOENT; 845 return ENOENT;
845 } 846 }
846 error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff, 847 error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff,
847 &bp, &q2ep, 0); 848 &bp, &q2ep, 0);
848 if (error) { 849 if (error) {
849 mutex_exit(&dq->dq_interlock); 850 mutex_exit(&dq->dq_interlock);
850 dqrele(NULLVP, dq); 851 dqrele(NULLVP, dq);
851 return error; 852 return error;
852 } 853 }
853 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 854 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
854 brelse(bp, 0); 855 brelse(bp, 0);
855 mutex_exit(&dq->dq_interlock); 856 mutex_exit(&dq->dq_interlock);
856 dqrele(NULLVP, dq); 857 dqrele(NULLVP, dq);
857 858
858 dict = q2etoprop(&q2e, 0); 859 dict = q2etoprop(&q2e, 0);
859 if (dict == NULL) 860 if (dict == NULL)
860 return ENOMEM; 861 return ENOMEM;
861 if (!prop_array_add_and_rel(replies, dict)) 862 if (!prop_array_add_and_rel(replies, dict))
862 return ENOMEM; 863 return ENOMEM;
863 return 0; 864 return 0;
864} 865}
865 866
866static int 867static int
867quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, 868quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
868 struct quotaval *ret) 869 struct quotaval *ret)
869{ 870{
870 struct dquot *dq; 871 struct dquot *dq;
871 int error; 872 int error;
872 struct quota2_entry *q2ep, q2e; 873 struct quota2_entry *q2ep, q2e;
873 struct buf *bp; 874 struct buf *bp;
874 const int needswap = UFS_MPNEEDSWAP(ump); 875 const int needswap = UFS_MPNEEDSWAP(ump);
875 id_t id2; 876 id_t id2;
876 877
877 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); 878 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
878 if (error) 879 if (error)
879 return error; 880 return error;
880 881
881 mutex_enter(&dq->dq_interlock); 882 mutex_enter(&dq->dq_interlock);
882 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 883 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
883 mutex_exit(&dq->dq_interlock); 884 mutex_exit(&dq->dq_interlock);
884 dqrele(NULLVP, dq); 885 dqrele(NULLVP, dq);
885 return ENOENT; 886 return ENOENT;
886 } 887 }
887 error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff, 888 error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff,
888 &bp, &q2ep, 0); 889 &bp, &q2ep, 0);
889 if (error) { 890 if (error) {
890 mutex_exit(&dq->dq_interlock); 891 mutex_exit(&dq->dq_interlock);
891 dqrele(NULLVP, dq); 892 dqrele(NULLVP, dq);
892 return error; 893 return error;
893 } 894 }
894 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 895 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
895 brelse(bp, 0); 896 brelse(bp, 0);
896 mutex_exit(&dq->dq_interlock); 897 mutex_exit(&dq->dq_interlock);
897 dqrele(NULLVP, dq); 898 dqrele(NULLVP, dq);
898 899
899 q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret); 900 q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret);
900 KASSERT(id2 == qk->qk_id); 901 KASSERT(id2 == qk->qk_id);
901 return 0; 902 return 0;
902} 903}
903 904
904int 905int
905quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk, 906quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk,
906 struct quotaval *ret) 907 struct quotaval *ret)
907{ 908{
908 int error; 909 int error;
909 struct quota2_header *q2h; 910 struct quota2_header *q2h;
910 struct quota2_entry q2e; 911 struct quota2_entry q2e;
911 struct buf *bp; 912 struct buf *bp;
912 const int needswap = UFS_MPNEEDSWAP(ump); 913 const int needswap = UFS_MPNEEDSWAP(ump);
913 id_t id2; 914 id_t id2;
914 915
915 /* 916 /*
916 * Make sure the FS-independent codes match the internal ones, 917 * Make sure the FS-independent codes match the internal ones,
917 * so we can use the passed-in objtype without having to 918 * so we can use the passed-in objtype without having to
918 * convert it explicitly to QL_BLOCK/QL_FILE. 919 * convert it explicitly to QL_BLOCK/QL_FILE.
919 */ 920 */
920 CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS); 921 CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS);
921 CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES); 922 CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES);
922 CTASSERT(N_QL == 2); 923 CTASSERT(N_QL == 2);
923 924
924 if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) { 925 if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) {
925 return EINVAL; 926 return EINVAL;
926 } 927 }
927 928
928 if (ump->um_quotas[qk->qk_idtype] == NULLVP) 929 if (ump->um_quotas[qk->qk_idtype] == NULLVP)
929 return ENODEV; 930 return ENODEV;
930 if (qk->qk_id == QUOTA_DEFAULTID) { 931 if (qk->qk_id == QUOTA_DEFAULTID) {
931 mutex_enter(&dqlock); 932 mutex_enter(&dqlock);
932 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); 933 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0);
933 if (error) { 934 if (error) {
934 mutex_exit(&dqlock); 935 mutex_exit(&dqlock);
935 return error; 936 return error;
936 } 937 }
937 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 938 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
938 mutex_exit(&dqlock); 939 mutex_exit(&dqlock);
939 brelse(bp, 0); 940 brelse(bp, 0);
940 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, 941 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2,
941 qk->qk_objtype, ret); 942 qk->qk_objtype, ret);
942 (void)id2; 943 (void)id2;
943 } else 944 } else
944 error = quota2_fetch_q2e(ump, qk, ret); 945 error = quota2_fetch_q2e(ump, qk, ret);
945  946
946 return error; 947 return error;
947} 948}
948 949
949struct getuids { 950struct getuids {
950 long nuids; /* number of uids in array */ 951 long nuids; /* number of uids in array */
951 long size; /* size of array */ 952 long size; /* size of array */
952 uid_t *uids; /* array of uids, dynamically allocated */ 953 uid_t *uids; /* array of uids, dynamically allocated */
953}; 954};
954 955
955static int 956static int
956quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, 957quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp,
957 struct quota2_entry *q2ep, uint64_t off, void *v) 958 struct quota2_entry *q2ep, uint64_t off, void *v)
958{ 959{
959 struct getuids *gu = v; 960 struct getuids *gu = v;
960 uid_t *newuids; 961 uid_t *newuids;
961#ifdef FFS_EI 962#ifdef FFS_EI
962 const int needswap = UFS_MPNEEDSWAP(ump); 963 const int needswap = UFS_MPNEEDSWAP(ump);
963#endif 964#endif
964 965
965 if (gu->nuids == gu->size) { 966 if (gu->nuids == gu->size) {
966 newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP, 967 newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP,
967 M_WAITOK); 968 M_WAITOK);
968 if (newuids == NULL) { 969 if (newuids == NULL) {
969 free(gu->uids, M_TEMP); 970 free(gu->uids, M_TEMP);
970 return ENOMEM; 971 return ENOMEM;
971 } 972 }
972 gu->uids = newuids; 973 gu->uids = newuids;
973 gu->size += (PAGE_SIZE / sizeof(uid_t)); 974 gu->size += (PAGE_SIZE / sizeof(uid_t));
974 } 975 }
975 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); 976 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap);
976 gu->nuids++; 977 gu->nuids++;
977 return 0; 978 return 0;
978} 979}
979 980
980int 981int
981quota2_handle_cmd_getall(struct ufsmount *ump, int type, prop_array_t replies) 982quota2_handle_cmd_getall(struct ufsmount *ump, int type, prop_array_t replies)
982{ 983{
983 int error; 984 int error;
984 struct quota2_header *q2h; 985 struct quota2_header *q2h;
985 struct quota2_entry q2e; 986 struct quota2_entry q2e;
986 struct buf *hbp; 987 struct buf *hbp;
987 prop_dictionary_t dict; 988 prop_dictionary_t dict;
988 uint64_t offset; 989 uint64_t offset;
989 int i, j; 990 int i, j;
990 int quota2_hash_size; 991 int quota2_hash_size;
991 const int needswap = UFS_MPNEEDSWAP(ump); 992 const int needswap = UFS_MPNEEDSWAP(ump);
992 struct getuids gu; 993 struct getuids gu;
993 994
994 if (ump->um_quotas[type] == NULLVP) 995 if (ump->um_quotas[type] == NULLVP)
995 return ENODEV; 996 return ENODEV;
996 mutex_enter(&dqlock); 997 mutex_enter(&dqlock);
997 error = getq2h(ump, type, &hbp, &q2h, 0); 998 error = getq2h(ump, type, &hbp, &q2h, 0);
998 if (error) { 999 if (error) {
999 mutex_exit(&dqlock); 1000 mutex_exit(&dqlock);
1000 return error; 1001 return error;
1001 } 1002 }
1002 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 1003 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
1003 dict = q2etoprop(&q2e, 1); 1004 dict = q2etoprop(&q2e, 1);
1004 if (!prop_array_add_and_rel(replies, dict)) { 1005 if (!prop_array_add_and_rel(replies, dict)) {
1005 error = ENOMEM; 1006 error = ENOMEM;
1006 goto error_bp; 1007 goto error_bp;
1007 } 1008 }
1008 /* 1009 /*
1009 * we can't directly get entries as we can't walk the list 1010 * we can't directly get entries as we can't walk the list
1010 * with qdlock and grab dq_interlock to read the entries 1011 * with qdlock and grab dq_interlock to read the entries
1011 * at the same time. So just walk the lists to build a list of uid, 1012 * at the same time. So just walk the lists to build a list of uid,
1012 * and then read entries for these uids 1013 * and then read entries for these uids
1013 */ 1014 */
1014 memset(&gu, 0, sizeof(gu)); 1015 memset(&gu, 0, sizeof(gu));
1015 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); 1016 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
1016 for (i = 0; i < quota2_hash_size ; i++) { 1017 for (i = 0; i < quota2_hash_size ; i++) {
1017 offset = q2h->q2h_entries[i]; 1018 offset = q2h->q2h_entries[i];
1018 error = quota2_walk_list(ump, hbp, type, &offset, 0, &gu, 1019 error = quota2_walk_list(ump, hbp, type, &offset, 0, &gu,
1019 quota2_getuids_callback); 1020 quota2_getuids_callback);
1020 if (error) { 1021 if (error) {
1021 if (gu.uids != NULL) 1022 if (gu.uids != NULL)
1022 free(gu.uids, M_TEMP); 1023 free(gu.uids, M_TEMP);
1023 break; 1024 break;
1024 } 1025 }
1025 } 1026 }
1026error_bp: 1027error_bp:
1027 mutex_exit(&dqlock); 1028 mutex_exit(&dqlock);
1028 brelse(hbp, 0); 1029 brelse(hbp, 0);
1029 if (error) 1030 if (error)
1030 return error; 1031 return error;
1031 for (j = 0; j < gu.nuids; j++) { 1032 for (j = 0; j < gu.nuids; j++) {
1032 error = quota2_array_add_q2e(ump, type, 1033 error = quota2_array_add_q2e(ump, type,
1033 gu.uids[j], replies); 1034 gu.uids[j], replies);
1034 if (error && error != ENOENT) 1035 if (error && error != ENOENT)
1035 break; 1036 break;
1036 } 1037 }
1037 free(gu.uids, M_TEMP); 1038 free(gu.uids, M_TEMP);
1038 return error; 1039 return error;
1039} 1040}
1040 1041
 1042struct ufsq2_cursor {
 1043 uint32_t q2c_magic;
 1044};
 1045
 1046#define Q2C_MAGIC (0xbeebe111)
 1047
 1048#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0])
 1049
 1050int
 1051quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc)
 1052{
 1053 struct ufsq2_cursor *cursor;
 1054
 1055 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space));
 1056 cursor = Q2CURSOR(qkc);
 1057
 1058 cursor->q2c_magic = Q2C_MAGIC;
 1059 return 0;
 1060}
 1061
 1062int
 1063quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc)
 1064{
 1065 struct ufsq2_cursor *cursor;
 1066
 1067 cursor = Q2CURSOR(qkc);
 1068 if (cursor->q2c_magic != Q2C_MAGIC) {
 1069 return EINVAL;
 1070 }
 1071
 1072 return 0;
 1073}
 1074
1041int 1075int
1042q2sync(struct mount *mp) 1076q2sync(struct mount *mp)
1043{ 1077{
1044 return 0; 1078 return 0;
1045} 1079}
1046 1080
1047struct dq2get_callback { 1081struct dq2get_callback {
1048 uid_t id; 1082 uid_t id;
1049 struct dquot *dq; 1083 struct dquot *dq;
1050}; 1084};
1051 1085
1052static int 1086static int
1053dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, 1087dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e,
1054 uint64_t off, void *v) 1088 uint64_t off, void *v)
1055{ 1089{
1056 struct dq2get_callback *c = v; 1090 struct dq2get_callback *c = v;
1057 daddr_t lblkno; 1091 daddr_t lblkno;
1058 int blkoff; 1092 int blkoff;
1059#ifdef FFS_EI 1093#ifdef FFS_EI
1060 const int needswap = UFS_MPNEEDSWAP(ump); 1094 const int needswap = UFS_MPNEEDSWAP(ump);
1061#endif 1095#endif
1062 1096
1063 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { 1097 if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) {
1064 KASSERT(mutex_owned(&c->dq->dq_interlock)); 1098 KASSERT(mutex_owned(&c->dq->dq_interlock));
1065 lblkno = (off >> ump->um_mountp->mnt_fs_bshift); 1099 lblkno = (off >> ump->um_mountp->mnt_fs_bshift);
1066 blkoff = (off & ump->umq2_bmask); 1100 blkoff = (off & ump->umq2_bmask);
1067 c->dq->dq2_lblkno = lblkno; 1101 c->dq->dq2_lblkno = lblkno;
1068 c->dq->dq2_blkoff = blkoff; 1102 c->dq->dq2_blkoff = blkoff;
1069 return Q2WL_ABORT; 1103 return Q2WL_ABORT;
1070 } 1104 }
1071 return 0; 1105 return 0;
1072} 1106}
1073 1107
1074int 1108int
1075dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, 1109dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type,
1076 struct dquot *dq) 1110 struct dquot *dq)
1077{ 1111{
1078 struct buf *bp; 1112 struct buf *bp;
1079 struct quota2_header *q2h; 1113 struct quota2_header *q2h;
1080 int error; 1114 int error;
1081 daddr_t offset; 1115 daddr_t offset;
1082 u_long hash_mask; 1116 u_long hash_mask;
1083 struct dq2get_callback c = { 1117 struct dq2get_callback c = {
1084 .id = id, 1118 .id = id,
1085 .dq = dq 1119 .dq = dq
1086 }; 1120 };
1087 1121
1088 KASSERT(mutex_owned(&dq->dq_interlock)); 1122 KASSERT(mutex_owned(&dq->dq_interlock));
1089 mutex_enter(&dqlock); 1123 mutex_enter(&dqlock);
1090 error = getq2h(ump, type, &bp, &q2h, 0); 1124 error = getq2h(ump, type, &bp, &q2h, 0);
1091 if (error) 1125 if (error)
1092 goto out_mutex; 1126 goto out_mutex;
1093 /* look for our entry */ 1127 /* look for our entry */
1094 hash_mask = ((1 << q2h->q2h_hash_shift) - 1); 1128 hash_mask = ((1 << q2h->q2h_hash_shift) - 1);
1095 offset = q2h->q2h_entries[id & hash_mask]; 1129 offset = q2h->q2h_entries[id & hash_mask];
1096 error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, 1130 error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c,
1097 dq2get_callback); 1131 dq2get_callback);
1098 brelse(bp, 0); 1132 brelse(bp, 0);
1099out_mutex: 1133out_mutex:
1100 mutex_exit(&dqlock); 1134 mutex_exit(&dqlock);
1101 return error; 1135 return error;
1102} 1136}
1103 1137
1104int 1138int
1105dq2sync(struct vnode *vp, struct dquot *dq) 1139dq2sync(struct vnode *vp, struct dquot *dq)
1106{ 1140{
1107 return 0; 1141 return 0;
1108} 1142}