Sun Jan 29 06:53:36 2012 UTC ()
Improve the quota2 QUOTACTL_CLEAR code to allow clearing blocks and
files independently.

Note: this change requires a kernel version bump.


(dholland)
diff -r1.17 -r1.18 src/sys/kern/vfs_quotactl.c
diff -r1.15 -r1.16 src/sys/sys/quotactl.h
diff -r1.89 -r1.90 src/sys/ufs/ufs/ufs_quota.c
diff -r1.11 -r1.12 src/sys/ufs/ufs/ufs_quota.h
diff -r1.12 -r1.13 src/sys/ufs/ufs/ufs_quota2.c

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

--- src/sys/kern/vfs_quotactl.c 2012/01/29 06:52:38 1.17
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 06:53:35 1.18
@@ -1,602 +1,613 @@ @@ -1,602 +1,613 @@
1/* $NetBSD: vfs_quotactl.c,v 1.17 2012/01/29 06:52:38 dholland Exp $ */ 1/* $NetBSD: vfs_quotactl.c,v 1.18 2012/01/29 06:53:35 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.17 2012/01/29 06:52:38 dholland Exp $"); 83__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.18 2012/01/29 06:53:35 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 vfs_quotactl_args args; 445 struct vfs_quotactl_args args;
446 446
447 args.qc_type = QCT_PROPLIB; 447 args.qc_type = QCT_PROPLIB;
448 args.u.proplib.qc_cmddict = cmddict; 448 args.u.proplib.qc_cmddict = cmddict;
449 args.u.proplib.qc_q2type = q2type; 449 args.u.proplib.qc_q2type = q2type;
450 args.u.proplib.qc_datas = datas; 450 args.u.proplib.qc_datas = datas;
451 return VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args); 451 return VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args);
452} 452}
453 453
454static int 454static int
455vfs_quotactl_clear(struct mount *mp, 455vfs_quotactl_clear(struct mount *mp,
456 prop_dictionary_t cmddict, int q2type, 456 prop_dictionary_t cmddict, int q2type,
457 prop_array_t datas) 457 prop_array_t datas)
458{ 458{
459 prop_array_t replies; 459 prop_array_t replies;
460 prop_object_iterator_t iter; 460 prop_object_iterator_t iter;
461 prop_dictionary_t data; 461 prop_dictionary_t data;
462 uint32_t id; 462 uint32_t id;
463 int defaultq; 463 int defaultq;
464 const char *idstr; 464 const char *idstr;
465 struct vfs_quotactl_args args; 465 struct vfs_quotactl_args args;
466 int error; 466 int error;
467 467
468 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 468 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
469 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); 469 KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY);
470 470
471 replies = prop_array_create(); 471 replies = prop_array_create();
472 if (replies == NULL) 472 if (replies == NULL)
473 return ENOMEM; 473 return ENOMEM;
474 474
475 iter = prop_array_iterator(datas); 475 iter = prop_array_iterator(datas);
476 if (iter == NULL) { 476 if (iter == NULL) {
477 prop_object_release(replies); 477 prop_object_release(replies);
478 return ENOMEM; 478 return ENOMEM;
479 } 479 }
480 480
481 while ((data = prop_object_iterator_next(iter)) != NULL) { 481 while ((data = prop_object_iterator_next(iter)) != NULL) {
482 if (!prop_dictionary_get_uint32(data, "id", &id)) { 482 if (!prop_dictionary_get_uint32(data, "id", &id)) {
483 if (!prop_dictionary_get_cstring_nocopy(data, "id", 483 if (!prop_dictionary_get_cstring_nocopy(data, "id",
484 &idstr)) 484 &idstr))
485 continue; 485 continue;
486 if (strcmp(idstr, "default")) 486 if (strcmp(idstr, "default"))
487 continue; 487 continue;
488 id = 0; 488 id = 0;
489 defaultq = 1; 489 defaultq = 1;
490 } else { 490 } else {
491 defaultq = 0; 491 defaultq = 0;
492 } 492 }
493 493
494 args.qc_type = QCT_CLEAR; 494 args.qc_type = QCT_CLEAR;
495 args.u.clear.qc_idtype = q2type; 495 args.u.clear.qc_idtype = q2type;
496 args.u.clear.qc_id = id; 496 args.u.clear.qc_id = id;
497 args.u.clear.qc_defaultq = defaultq; 497 args.u.clear.qc_defaultq = defaultq;
 498 args.u.clear.qc_objtype = QUOTA_OBJTYPE_BLOCKS;
 499 error = VFS_QUOTACTL(mp, QUOTACTL_CLEAR, &args);
 500 if (error) {
 501 goto err;
 502 }
 503
 504 args.qc_type = QCT_CLEAR;
 505 args.u.clear.qc_idtype = q2type;
 506 args.u.clear.qc_id = id;
 507 args.u.clear.qc_defaultq = defaultq;
 508 args.u.clear.qc_objtype = QUOTA_OBJTYPE_FILES;
498 error = VFS_QUOTACTL(mp, QUOTACTL_CLEAR, &args); 509 error = VFS_QUOTACTL(mp, QUOTACTL_CLEAR, &args);
499 if (error) { 510 if (error) {
500 goto err; 511 goto err;
501 } 512 }
502 } 513 }
503 514
504 prop_object_iterator_release(iter); 515 prop_object_iterator_release(iter);
505 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { 516 if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
506 error = ENOMEM; 517 error = ENOMEM;
507 } else { 518 } else {
508 error = 0; 519 error = 0;
509 } 520 }
510 return error; 521 return error;
511err: 522err:
512 prop_object_iterator_release(iter); 523 prop_object_iterator_release(iter);
513 prop_object_release(replies); 524 prop_object_release(replies);
514 return error; 525 return error;
515} 526}
516 527
517static int 528static int
518vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) 529vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict)
519{ 530{
520 int error; 531 int error;
521 const char *cmd, *type; 532 const char *cmd, *type;
522 prop_array_t datas; 533 prop_array_t datas;
523 int q2type; 534 int q2type;
524 535
525 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) 536 if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd))
526 return EINVAL; 537 return EINVAL;
527 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) 538 if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type))
528 return EINVAL; 539 return EINVAL;
529 540
530 if (!strcmp(type, QUOTADICT_CLASS_USER)) { 541 if (!strcmp(type, QUOTADICT_CLASS_USER)) {
531 q2type = QUOTA_CLASS_USER; 542 q2type = QUOTA_CLASS_USER;
532 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { 543 } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) {
533 q2type = QUOTA_CLASS_GROUP; 544 q2type = QUOTA_CLASS_GROUP;
534 } else { 545 } else {
535 /* XXX this is a bad errno for this case */ 546 /* XXX this is a bad errno for this case */
536 return EOPNOTSUPP; 547 return EOPNOTSUPP;
537 } 548 }
538 549
539 datas = prop_dictionary_get(cmddict, "data"); 550 datas = prop_dictionary_get(cmddict, "data");
540 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) 551 if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY)
541 return EINVAL; 552 return EINVAL;
542 553
543 prop_object_retain(datas); 554 prop_object_retain(datas);
544 prop_dictionary_remove(cmddict, "data"); /* prepare for return */ 555 prop_dictionary_remove(cmddict, "data"); /* prepare for return */
545 556
546 if (strcmp(cmd, "get version") == 0) { 557 if (strcmp(cmd, "get version") == 0) {
547 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); 558 error = vfs_quotactl_getversion(mp, cmddict, q2type, datas);
548 } else if (strcmp(cmd, "quotaon") == 0) { 559 } else if (strcmp(cmd, "quotaon") == 0) {
549 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); 560 error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas);
550 } else if (strcmp(cmd, "quotaoff") == 0) { 561 } else if (strcmp(cmd, "quotaoff") == 0) {
551 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); 562 error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas);
552 } else if (strcmp(cmd, "get") == 0) { 563 } else if (strcmp(cmd, "get") == 0) {
553 error = vfs_quotactl_get(mp, cmddict, q2type, datas); 564 error = vfs_quotactl_get(mp, cmddict, q2type, datas);
554 } else if (strcmp(cmd, "set") == 0) { 565 } else if (strcmp(cmd, "set") == 0) {
555 error = vfs_quotactl_put(mp, cmddict, q2type, datas); 566 error = vfs_quotactl_put(mp, cmddict, q2type, datas);
556 } else if (strcmp(cmd, "getall") == 0) { 567 } else if (strcmp(cmd, "getall") == 0) {
557 error = vfs_quotactl_getall(mp, cmddict, q2type, datas); 568 error = vfs_quotactl_getall(mp, cmddict, q2type, datas);
558 } else if (strcmp(cmd, "clear") == 0) { 569 } else if (strcmp(cmd, "clear") == 0) {
559 error = vfs_quotactl_clear(mp, cmddict, q2type, datas); 570 error = vfs_quotactl_clear(mp, cmddict, q2type, datas);
560 } else { 571 } else {
561 /* XXX this a bad errno for this case */ 572 /* XXX this a bad errno for this case */
562 error = EOPNOTSUPP; 573 error = EOPNOTSUPP;
563 } 574 }
564 575
565 error = (prop_dictionary_set_int8(cmddict, "return", 576 error = (prop_dictionary_set_int8(cmddict, "return",
566 error) ? 0 : ENOMEM); 577 error) ? 0 : ENOMEM);
567 prop_object_release(datas); 578 prop_object_release(datas);
568 579
569 return error; 580 return error;
570} 581}
571 582
572int 583int
573vfs_quotactl(struct mount *mp, prop_dictionary_t dict) 584vfs_quotactl(struct mount *mp, prop_dictionary_t dict)
574{ 585{
575 prop_dictionary_t cmddict; 586 prop_dictionary_t cmddict;
576 prop_array_t commands; 587 prop_array_t commands;
577 prop_object_iterator_t iter; 588 prop_object_iterator_t iter;
578 int error; 589 int error;
579 590
580 error = quota_get_cmds(dict, &commands); 591 error = quota_get_cmds(dict, &commands);
581 if (error) { 592 if (error) {
582 return error; 593 return error;
583 } 594 }
584 595
585 iter = prop_array_iterator(commands); 596 iter = prop_array_iterator(commands);
586 if (iter == NULL) { 597 if (iter == NULL) {
587 return ENOMEM; 598 return ENOMEM;
588 } 599 }
589 600
590 while ((cmddict = prop_object_iterator_next(iter)) != NULL) { 601 while ((cmddict = prop_object_iterator_next(iter)) != NULL) {
591 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { 602 if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) {
592 /* XXX shouldn't this be an error? */ 603 /* XXX shouldn't this be an error? */
593 continue; 604 continue;
594 } 605 }
595 error = vfs_quotactl_cmd(mp, cmddict); 606 error = vfs_quotactl_cmd(mp, cmddict);
596 if (error) { 607 if (error) {
597 break; 608 break;
598 } 609 }
599 } 610 }
600 prop_object_iterator_release(iter); 611 prop_object_iterator_release(iter);
601 return error; 612 return error;
602} 613}

cvs diff -r1.15 -r1.16 src/sys/sys/quotactl.h (switch to unified diff)

--- src/sys/sys/quotactl.h 2012/01/29 06:52:39 1.15
+++ src/sys/sys/quotactl.h 2012/01/29 06:53:35 1.16
@@ -1,84 +1,85 @@ @@ -1,84 +1,85 @@
1/* $NetBSD: quotactl.h,v 1.15 2012/01/29 06:52:39 dholland Exp $ */ 1/* $NetBSD: quotactl.h,v 1.16 2012/01/29 06:53:35 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/* Command codes. */ 40/* Command codes. */
41#define QUOTACTL_GETVERSION 0 41#define QUOTACTL_GETVERSION 0
42#define QUOTACTL_QUOTAON 1 42#define QUOTACTL_QUOTAON 1
43#define QUOTACTL_QUOTAOFF 2 43#define QUOTACTL_QUOTAOFF 2
44#define QUOTACTL_GET 3 44#define QUOTACTL_GET 3
45#define QUOTACTL_PUT 4 45#define QUOTACTL_PUT 4
46#define QUOTACTL_GETALL 5 46#define QUOTACTL_GETALL 5
47#define QUOTACTL_CLEAR 6 47#define QUOTACTL_CLEAR 6
48 48
49/* Argument encoding. */ 49/* Argument encoding. */
50enum vfs_quotactl_argtypes { 50enum vfs_quotactl_argtypes {
51 QCT_PROPLIB, /* quotaon/off, get, set, getall, clear */ 51 QCT_PROPLIB, /* quotaon/off, get, set, getall, clear */
52 QCT_GETVERSION, /* getversion */ 52 QCT_GETVERSION, /* getversion */
53 QCT_GET, /* get */ 53 QCT_GET, /* get */
54 QCT_PUT, /* put */ 54 QCT_PUT, /* put */
55 QCT_CLEAR, /* clear */ 55 QCT_CLEAR, /* clear */
56}; 56};
57struct vfs_quotactl_args { 57struct vfs_quotactl_args {
58 enum vfs_quotactl_argtypes qc_type; 58 enum vfs_quotactl_argtypes qc_type;
59 union { 59 union {
60 struct { 60 struct {
61 prop_dictionary_t qc_cmddict; 61 prop_dictionary_t qc_cmddict;
62 int qc_q2type; 62 int qc_q2type;
63 prop_array_t qc_datas; 63 prop_array_t qc_datas;
64 } proplib; 64 } proplib;
65 struct { 65 struct {
66 int *qc_version_ret; 66 int *qc_version_ret;
67 } getversion; 67 } getversion;
68 struct { 68 struct {
69 const struct quotakey *qc_key; 69 const struct quotakey *qc_key;
70 struct quotaval *qc_ret; 70 struct quotaval *qc_ret;
71 } get; 71 } get;
72 struct { 72 struct {
73 const struct quotakey *qc_key; 73 const struct quotakey *qc_key;
74 const struct quotaval *qc_val; 74 const struct quotaval *qc_val;
75 } put; 75 } put;
76 struct { 76 struct {
77 int qc_idtype; 77 int qc_idtype;
78 id_t qc_id; 78 id_t qc_id;
79 int qc_defaultq; 79 int qc_defaultq;
 80 int qc_objtype;
80 } clear; 81 } clear;
81 } u; 82 } u;
82}; 83};
83 84
84#endif /* _SYS_QUOTACTL_H_ */ 85#endif /* _SYS_QUOTACTL_H_ */

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

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

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

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

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

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