The handling of QUOTACTL_CLEAR does not use the proplib data dictionary, so don't pass it. Note: this change requires a kernel version bump.diff -r1.16 -r1.17 src/sys/kern/vfs_quotactl.c
(dholland)
--- src/sys/kern/vfs_quotactl.c 2012/01/29 06:51:42 1.16
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 06:52:38 1.17
@@ -1,603 +1,602 @@ | @@ -1,603 +1,602 @@ | |||
1 | /* $NetBSD: vfs_quotactl.c,v 1.16 2012/01/29 06:51:42 dholland Exp $ */ | 1 | /* $NetBSD: vfs_quotactl.c,v 1.17 2012/01/29 06:52:38 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.16 2012/01/29 06:51:42 dholland Exp $"); | 83 | __KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.17 2012/01/29 06:52:38 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 | |||
90 | static int | 90 | static int | |
91 | vfs_quotactl_getversion(struct mount *mp, | 91 | vfs_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 | |||
141 | static int | 141 | static int | |
142 | vfs_quotactl_quotaon(struct mount *mp, | 142 | vfs_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 | |||
155 | static int | 155 | static int | |
156 | vfs_quotactl_quotaoff(struct mount *mp, | 156 | vfs_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 | |||
169 | static int | 169 | static int | |
170 | vfs_quotactl_get_addreply(const struct quotakey *qk, | 170 | vfs_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 | |||
205 | static int | 205 | static int | |
206 | vfs_quotactl_get(struct mount *mp, | 206 | vfs_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 | |||
301 | static int | 301 | static int | |
302 | vfs_quotactl_put_extractinfo(prop_dictionary_t data, | 302 | vfs_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 | |||
353 | static int | 353 | static int | |
354 | vfs_quotactl_put(struct mount *mp, | 354 | vfs_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; | |
434 | err: | 434 | err: | |
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 | |||
440 | static int | 440 | static int | |
441 | vfs_quotactl_getall(struct mount *mp, | 441 | vfs_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 | |||
454 | static int | 454 | static int | |
455 | vfs_quotactl_clear(struct mount *mp, | 455 | vfs_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_data = data; | |||
499 | error = VFS_QUOTACTL(mp, QUOTACTL_CLEAR, &args); | 498 | error = VFS_QUOTACTL(mp, QUOTACTL_CLEAR, &args); | |
500 | if (error) { | 499 | if (error) { | |
501 | goto err; | 500 | goto err; | |
502 | } | 501 | } | |
503 | } | 502 | } | |
504 | 503 | |||
505 | prop_object_iterator_release(iter); | 504 | prop_object_iterator_release(iter); | |
506 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 505 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
507 | error = ENOMEM; | 506 | error = ENOMEM; | |
508 | } else { | 507 | } else { | |
509 | error = 0; | 508 | error = 0; | |
510 | } | 509 | } | |
511 | return error; | 510 | return error; | |
512 | err: | 511 | err: | |
513 | prop_object_iterator_release(iter); | 512 | prop_object_iterator_release(iter); | |
514 | prop_object_release(replies); | 513 | prop_object_release(replies); | |
515 | return error; | 514 | return error; | |
516 | } | 515 | } | |
517 | 516 | |||
518 | static int | 517 | static int | |
519 | vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) | 518 | vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) | |
520 | { | 519 | { | |
521 | int error; | 520 | int error; | |
522 | const char *cmd, *type; | 521 | const char *cmd, *type; | |
523 | prop_array_t datas; | 522 | prop_array_t datas; | |
524 | int q2type; | 523 | int q2type; | |
525 | 524 | |||
526 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) | 525 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) | |
527 | return EINVAL; | 526 | return EINVAL; | |
528 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) | 527 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) | |
529 | return EINVAL; | 528 | return EINVAL; | |
530 | 529 | |||
531 | if (!strcmp(type, QUOTADICT_CLASS_USER)) { | 530 | if (!strcmp(type, QUOTADICT_CLASS_USER)) { | |
532 | q2type = QUOTA_CLASS_USER; | 531 | q2type = QUOTA_CLASS_USER; | |
533 | } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { | 532 | } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { | |
534 | q2type = QUOTA_CLASS_GROUP; | 533 | q2type = QUOTA_CLASS_GROUP; | |
535 | } else { | 534 | } else { | |
536 | /* XXX this is a bad errno for this case */ | 535 | /* XXX this is a bad errno for this case */ | |
537 | return EOPNOTSUPP; | 536 | return EOPNOTSUPP; | |
538 | } | 537 | } | |
539 | 538 | |||
540 | datas = prop_dictionary_get(cmddict, "data"); | 539 | datas = prop_dictionary_get(cmddict, "data"); | |
541 | if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) | 540 | if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) | |
542 | return EINVAL; | 541 | return EINVAL; | |
543 | 542 | |||
544 | prop_object_retain(datas); | 543 | prop_object_retain(datas); | |
545 | prop_dictionary_remove(cmddict, "data"); /* prepare for return */ | 544 | prop_dictionary_remove(cmddict, "data"); /* prepare for return */ | |
546 | 545 | |||
547 | if (strcmp(cmd, "get version") == 0) { | 546 | if (strcmp(cmd, "get version") == 0) { | |
548 | error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); | 547 | error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); | |
549 | } else if (strcmp(cmd, "quotaon") == 0) { | 548 | } else if (strcmp(cmd, "quotaon") == 0) { | |
550 | error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); | 549 | error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); | |
551 | } else if (strcmp(cmd, "quotaoff") == 0) { | 550 | } else if (strcmp(cmd, "quotaoff") == 0) { | |
552 | error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); | 551 | error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); | |
553 | } else if (strcmp(cmd, "get") == 0) { | 552 | } else if (strcmp(cmd, "get") == 0) { | |
554 | error = vfs_quotactl_get(mp, cmddict, q2type, datas); | 553 | error = vfs_quotactl_get(mp, cmddict, q2type, datas); | |
555 | } else if (strcmp(cmd, "set") == 0) { | 554 | } else if (strcmp(cmd, "set") == 0) { | |
556 | error = vfs_quotactl_put(mp, cmddict, q2type, datas); | 555 | error = vfs_quotactl_put(mp, cmddict, q2type, datas); | |
557 | } else if (strcmp(cmd, "getall") == 0) { | 556 | } else if (strcmp(cmd, "getall") == 0) { | |
558 | error = vfs_quotactl_getall(mp, cmddict, q2type, datas); | 557 | error = vfs_quotactl_getall(mp, cmddict, q2type, datas); | |
559 | } else if (strcmp(cmd, "clear") == 0) { | 558 | } else if (strcmp(cmd, "clear") == 0) { | |
560 | error = vfs_quotactl_clear(mp, cmddict, q2type, datas); | 559 | error = vfs_quotactl_clear(mp, cmddict, q2type, datas); | |
561 | } else { | 560 | } else { | |
562 | /* XXX this a bad errno for this case */ | 561 | /* XXX this a bad errno for this case */ | |
563 | error = EOPNOTSUPP; | 562 | error = EOPNOTSUPP; | |
564 | } | 563 | } | |
565 | 564 | |||
566 | error = (prop_dictionary_set_int8(cmddict, "return", | 565 | error = (prop_dictionary_set_int8(cmddict, "return", | |
567 | error) ? 0 : ENOMEM); | 566 | error) ? 0 : ENOMEM); | |
568 | prop_object_release(datas); | 567 | prop_object_release(datas); | |
569 | 568 | |||
570 | return error; | 569 | return error; | |
571 | } | 570 | } | |
572 | 571 | |||
573 | int | 572 | int | |
574 | vfs_quotactl(struct mount *mp, prop_dictionary_t dict) | 573 | vfs_quotactl(struct mount *mp, prop_dictionary_t dict) | |
575 | { | 574 | { | |
576 | prop_dictionary_t cmddict; | 575 | prop_dictionary_t cmddict; | |
577 | prop_array_t commands; | 576 | prop_array_t commands; | |
578 | prop_object_iterator_t iter; | 577 | prop_object_iterator_t iter; | |
579 | int error; | 578 | int error; | |
580 | 579 | |||
581 | error = quota_get_cmds(dict, &commands); | 580 | error = quota_get_cmds(dict, &commands); | |
582 | if (error) { | 581 | if (error) { | |
583 | return error; | 582 | return error; | |
584 | } | 583 | } | |
585 | 584 | |||
586 | iter = prop_array_iterator(commands); | 585 | iter = prop_array_iterator(commands); | |
587 | if (iter == NULL) { | 586 | if (iter == NULL) { | |
588 | return ENOMEM; | 587 | return ENOMEM; | |
589 | } | 588 | } | |
590 | 589 | |||
591 | while ((cmddict = prop_object_iterator_next(iter)) != NULL) { | 590 | while ((cmddict = prop_object_iterator_next(iter)) != NULL) { | |
592 | if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { | 591 | if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { | |
593 | /* XXX shouldn't this be an error? */ | 592 | /* XXX shouldn't this be an error? */ | |
594 | continue; | 593 | continue; | |
595 | } | 594 | } | |
596 | error = vfs_quotactl_cmd(mp, cmddict); | 595 | error = vfs_quotactl_cmd(mp, cmddict); | |
597 | if (error) { | 596 | if (error) { | |
598 | break; | 597 | break; | |
599 | } | 598 | } | |
600 | } | 599 | } | |
601 | prop_object_iterator_release(iter); | 600 | prop_object_iterator_release(iter); | |
602 | return error; | 601 | return error; | |
603 | } | 602 | } |
--- src/sys/sys/quotactl.h 2012/01/29 06:51:43 1.14
+++ src/sys/sys/quotactl.h 2012/01/29 06:52:39 1.15
@@ -1,85 +1,84 @@ | @@ -1,85 +1,84 @@ | |||
1 | /* $NetBSD: quotactl.h,v 1.14 2012/01/29 06:51:43 dholland Exp $ */ | 1 | /* $NetBSD: quotactl.h,v 1.15 2012/01/29 06:52:39 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. */ | |
50 | enum vfs_quotactl_argtypes { | 50 | enum 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 | }; | |
57 | struct vfs_quotactl_args { | 57 | struct 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 | prop_dictionary_t qc_data; | |||
81 | } clear; | 80 | } clear; | |
82 | } u; | 81 | } u; | |
83 | }; | 82 | }; | |
84 | 83 | |||
85 | #endif /* _SYS_QUOTACTL_H_ */ | 84 | #endif /* _SYS_QUOTACTL_H_ */ |
--- src/sys/ufs/ufs/ufs_quota.c 2012/01/29 06:51:43 1.88
+++ src/sys/ufs/ufs/ufs_quota.c 2012/01/29 06:52:39 1.89
@@ -1,787 +1,783 @@ | @@ -1,787 +1,783 @@ | |||
1 | /* $NetBSD: ufs_quota.c,v 1.88 2012/01/29 06:51:43 dholland Exp $ */ | 1 | /* $NetBSD: ufs_quota.c,v 1.89 2012/01/29 06:52:39 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.88 2012/01/29 06:51:43 dholland Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.89 2012/01/29 06:52:39 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 | |||
61 | kmutex_t dqlock; | 61 | kmutex_t dqlock; | |
62 | kcondvar_t dqcv; | 62 | kcondvar_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) | |
69 | static LIST_HEAD(dqhashhead, dquot) *dqhashtbl; | 69 | static LIST_HEAD(dqhashhead, dquot) *dqhashtbl; | |
70 | static u_long dqhash; | 70 | static u_long dqhash; | |
71 | static pool_cache_t dquot_cache; | 71 | static pool_cache_t dquot_cache; | |
72 | 72 | |||
73 | 73 | |||
74 | static int quota_handle_cmd_get_version(struct mount *, struct lwp *, | 74 | static int quota_handle_cmd_get_version(struct mount *, struct lwp *, | |
75 | struct vfs_quotactl_args *args); | 75 | struct vfs_quotactl_args *args); | |
76 | static int quota_handle_cmd_get(struct mount *, struct lwp *, | 76 | static int quota_handle_cmd_get(struct mount *, struct lwp *, | |
77 | struct vfs_quotactl_args *args); | 77 | struct vfs_quotactl_args *args); | |
78 | static int quota_handle_cmd_put(struct mount *, struct lwp *, | 78 | static int quota_handle_cmd_put(struct mount *, struct lwp *, | |
79 | struct vfs_quotactl_args *args); | 79 | struct vfs_quotactl_args *args); | |
80 | static int quota_handle_cmd_getall(struct mount *, struct lwp *, | 80 | static int quota_handle_cmd_getall(struct mount *, struct lwp *, | |
81 | struct vfs_quotactl_args *args); | 81 | struct vfs_quotactl_args *args); | |
82 | static int quota_handle_cmd_clear(struct mount *, struct lwp *, | 82 | static int quota_handle_cmd_clear(struct mount *, struct lwp *, | |
83 | struct vfs_quotactl_args *args); | 83 | struct vfs_quotactl_args *args); | |
84 | static int quota_handle_cmd_quotaon(struct mount *, struct lwp *, | 84 | static int quota_handle_cmd_quotaon(struct mount *, struct lwp *, | |
85 | struct vfs_quotactl_args *args); | 85 | struct vfs_quotactl_args *args); | |
86 | static int quota_handle_cmd_quotaoff(struct mount *, struct lwp *, | 86 | static 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 | */ | |
92 | void | 92 | void | |
93 | ufsquota_init(struct inode *ip) | 93 | ufsquota_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 | */ | |
104 | void | 104 | void | |
105 | ufsquota_free(struct inode *ip) | 105 | ufsquota_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 | */ | |
118 | int | 118 | int | |
119 | chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | 119 | chkdq(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 | */ | |
139 | int | 139 | int | |
140 | chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | 140 | chkiq(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 | |||
156 | int | 156 | int | |
157 | quota_handle_cmd(struct mount *mp, struct lwp *l, int op, | 157 | quota_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 | |||
191 | static int | 191 | static int | |
192 | quota_handle_cmd_get_version(struct mount *mp, struct lwp *l, | 192 | quota_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 ? */ | |
220 | static int | 220 | static int | |
221 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { | 221 | quota_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 | |||
229 | static int | 229 | static int | |
230 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | 230 | quota_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 | |||
266 | static int | 266 | static int | |
267 | quota_handle_cmd_put(struct mount *mp, struct lwp *l, | 267 | quota_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 | |||
314 | static int | 314 | static int | |
315 | quota_handle_cmd_clear(struct mount *mp, struct lwp *l, | 315 | quota_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 | prop_dictionary_t data; | |||
323 | int error; | 322 | int error; | |
324 | 323 | |||
325 | KASSERT(args->qc_type == QCT_CLEAR); | 324 | KASSERT(args->qc_type == QCT_CLEAR); | |
326 | idtype = args->u.clear.qc_idtype; | 325 | idtype = args->u.clear.qc_idtype; | |
327 | id = args->u.clear.qc_id; | 326 | id = args->u.clear.qc_id; | |
328 | defaultq = args->u.clear.qc_defaultq; | 327 | defaultq = args->u.clear.qc_defaultq; | |
329 | data = args->u.clear.qc_data; | |||
330 | ||||
331 | KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY); | |||
332 | 328 | |||
333 | if ((ump->um_flags & UFS_QUOTA2) == 0) | 329 | if ((ump->um_flags & UFS_QUOTA2) == 0) | |
334 | return EOPNOTSUPP; | 330 | return EOPNOTSUPP; | |
335 | 331 | |||
336 | /* avoid whitespace changes */ | 332 | /* avoid whitespace changes */ | |
337 | { | 333 | { | |
338 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 334 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
339 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); | 335 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(id), NULL); | |
340 | if (error != 0) | 336 | if (error != 0) | |
341 | goto err; | 337 | goto err; | |
342 | #ifdef QUOTA2 | 338 | #ifdef QUOTA2 | |
343 | if (ump->um_flags & UFS_QUOTA2) { | 339 | if (ump->um_flags & UFS_QUOTA2) { | |
344 | error = quota2_handle_cmd_clear(ump, idtype, id, defaultq, | 340 | error = quota2_handle_cmd_clear(ump, idtype, id, | |
345 | data); | 341 | defaultq); | |
346 | } else | 342 | } else | |
347 | #endif | 343 | #endif | |
348 | panic("quota_handle_cmd_get: no support ?"); | 344 | panic("quota_handle_cmd_get: no support ?"); | |
349 | 345 | |||
350 | if (error && error != ENOENT) | 346 | if (error && error != ENOENT) | |
351 | goto err; | 347 | goto err; | |
352 | } | 348 | } | |
353 | 349 | |||
354 | return 0; | 350 | return 0; | |
355 | err: | 351 | err: | |
356 | return error; | 352 | return error; | |
357 | } | 353 | } | |
358 | 354 | |||
359 | static int | 355 | static int | |
360 | quota_handle_cmd_getall(struct mount *mp, struct lwp *l, | 356 | quota_handle_cmd_getall(struct mount *mp, struct lwp *l, | |
361 | struct vfs_quotactl_args *args) | 357 | struct vfs_quotactl_args *args) | |
362 | { | 358 | { | |
363 | prop_array_t replies; | 359 | prop_array_t replies; | |
364 | struct ufsmount *ump = VFSTOUFS(mp); | 360 | struct ufsmount *ump = VFSTOUFS(mp); | |
365 | int error; | 361 | int error; | |
366 | prop_dictionary_t cmddict; | 362 | prop_dictionary_t cmddict; | |
367 | int q2type; | 363 | int q2type; | |
368 | prop_array_t datas; | 364 | prop_array_t datas; | |
369 | 365 | |||
370 | KASSERT(args->qc_type == QCT_PROPLIB); | 366 | KASSERT(args->qc_type == QCT_PROPLIB); | |
371 | cmddict = args->u.proplib.qc_cmddict; | 367 | cmddict = args->u.proplib.qc_cmddict; | |
372 | q2type = args->u.proplib.qc_q2type; | 368 | q2type = args->u.proplib.qc_q2type; | |
373 | datas = args->u.proplib.qc_datas; | 369 | datas = args->u.proplib.qc_datas; | |
374 | 370 | |||
375 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 371 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
376 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 372 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
377 | 373 | |||
378 | if ((ump->um_flags & UFS_QUOTA2) == 0) | 374 | if ((ump->um_flags & UFS_QUOTA2) == 0) | |
379 | return EOPNOTSUPP; | 375 | return EOPNOTSUPP; | |
380 | 376 | |||
381 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 377 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
382 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | 378 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | |
383 | if (error) | 379 | if (error) | |
384 | return error; | 380 | return error; | |
385 | 381 | |||
386 | replies = prop_array_create(); | 382 | replies = prop_array_create(); | |
387 | if (replies == NULL) | 383 | if (replies == NULL) | |
388 | return ENOMEM; | 384 | return ENOMEM; | |
389 | 385 | |||
390 | #ifdef QUOTA2 | 386 | #ifdef QUOTA2 | |
391 | if (ump->um_flags & UFS_QUOTA2) { | 387 | if (ump->um_flags & UFS_QUOTA2) { | |
392 | error = quota2_handle_cmd_getall(ump, q2type, replies); | 388 | error = quota2_handle_cmd_getall(ump, q2type, replies); | |
393 | } else | 389 | } else | |
394 | #endif | 390 | #endif | |
395 | panic("quota_handle_cmd_getall: no support ?"); | 391 | panic("quota_handle_cmd_getall: no support ?"); | |
396 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 392 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
397 | error = ENOMEM; | 393 | error = ENOMEM; | |
398 | } else { | 394 | } else { | |
399 | error = 0; | 395 | error = 0; | |
400 | } | 396 | } | |
401 | return error; | 397 | return error; | |
402 | } | 398 | } | |
403 | 399 | |||
404 | static int | 400 | static int | |
405 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, | 401 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, | |
406 | struct vfs_quotactl_args *args) | 402 | struct vfs_quotactl_args *args) | |
407 | { | 403 | { | |
408 | prop_dictionary_t data; | 404 | prop_dictionary_t data; | |
409 | struct ufsmount *ump = VFSTOUFS(mp); | 405 | struct ufsmount *ump = VFSTOUFS(mp); | |
410 | int error; | 406 | int error; | |
411 | const char *qfile; | 407 | const char *qfile; | |
412 | prop_dictionary_t cmddict; | 408 | prop_dictionary_t cmddict; | |
413 | int q2type; | 409 | int q2type; | |
414 | prop_array_t datas; | 410 | prop_array_t datas; | |
415 | 411 | |||
416 | KASSERT(args->qc_type == QCT_PROPLIB); | 412 | KASSERT(args->qc_type == QCT_PROPLIB); | |
417 | cmddict = args->u.proplib.qc_cmddict; | 413 | cmddict = args->u.proplib.qc_cmddict; | |
418 | q2type = args->u.proplib.qc_q2type; | 414 | q2type = args->u.proplib.qc_q2type; | |
419 | datas = args->u.proplib.qc_datas; | 415 | datas = args->u.proplib.qc_datas; | |
420 | 416 | |||
421 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 417 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
422 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 418 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
423 | 419 | |||
424 | if ((ump->um_flags & UFS_QUOTA2) != 0) | 420 | if ((ump->um_flags & UFS_QUOTA2) != 0) | |
425 | return EBUSY; | 421 | return EBUSY; | |
426 | 422 | |||
427 | if (prop_array_count(datas) != 1) | 423 | if (prop_array_count(datas) != 1) | |
428 | return EINVAL; | 424 | return EINVAL; | |
429 | 425 | |||
430 | data = prop_array_get(datas, 0); | 426 | data = prop_array_get(datas, 0); | |
431 | if (data == NULL) | 427 | if (data == NULL) | |
432 | return ENOMEM; | 428 | return ENOMEM; | |
433 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", | 429 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", | |
434 | &qfile)) | 430 | &qfile)) | |
435 | return EINVAL; | 431 | return EINVAL; | |
436 | 432 | |||
437 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 433 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
438 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | 434 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | |
439 | if (error != 0) { | 435 | if (error != 0) { | |
440 | return error; | 436 | return error; | |
441 | } | 437 | } | |
442 | #ifdef QUOTA | 438 | #ifdef QUOTA | |
443 | error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); | 439 | error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); | |
444 | #else | 440 | #else | |
445 | error = EOPNOTSUPP; | 441 | error = EOPNOTSUPP; | |
446 | #endif | 442 | #endif | |
447 | 443 | |||
448 | return error; | 444 | return error; | |
449 | } | 445 | } | |
450 | 446 | |||
451 | static int | 447 | static int | |
452 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, | 448 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, | |
453 | struct vfs_quotactl_args *args) | 449 | struct vfs_quotactl_args *args) | |
454 | { | 450 | { | |
455 | struct ufsmount *ump = VFSTOUFS(mp); | 451 | struct ufsmount *ump = VFSTOUFS(mp); | |
456 | int error; | 452 | int error; | |
457 | prop_dictionary_t cmddict; | 453 | prop_dictionary_t cmddict; | |
458 | int q2type; | 454 | int q2type; | |
459 | prop_array_t datas; | 455 | prop_array_t datas; | |
460 | 456 | |||
461 | KASSERT(args->qc_type == QCT_PROPLIB); | 457 | KASSERT(args->qc_type == QCT_PROPLIB); | |
462 | cmddict = args->u.proplib.qc_cmddict; | 458 | cmddict = args->u.proplib.qc_cmddict; | |
463 | q2type = args->u.proplib.qc_q2type; | 459 | q2type = args->u.proplib.qc_q2type; | |
464 | datas = args->u.proplib.qc_datas; | 460 | datas = args->u.proplib.qc_datas; | |
465 | 461 | |||
466 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 462 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
467 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 463 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
468 | 464 | |||
469 | if ((ump->um_flags & UFS_QUOTA2) != 0) | 465 | if ((ump->um_flags & UFS_QUOTA2) != 0) | |
470 | return EOPNOTSUPP; | 466 | return EOPNOTSUPP; | |
471 | 467 | |||
472 | if (prop_array_count(datas) != 0) | 468 | if (prop_array_count(datas) != 0) | |
473 | return EINVAL; | 469 | return EINVAL; | |
474 | 470 | |||
475 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 471 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
476 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | 472 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | |
477 | if (error != 0) { | 473 | if (error != 0) { | |
478 | return error; | 474 | return error; | |
479 | } | 475 | } | |
480 | #ifdef QUOTA | 476 | #ifdef QUOTA | |
481 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); | 477 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); | |
482 | #else | 478 | #else | |
483 | error = EOPNOTSUPP; | 479 | error = EOPNOTSUPP; | |
484 | #endif | 480 | #endif | |
485 | 481 | |||
486 | return error; | 482 | return error; | |
487 | } | 483 | } | |
488 | 484 | |||
489 | /* | 485 | /* | |
490 | * Initialize the quota system. | 486 | * Initialize the quota system. | |
491 | */ | 487 | */ | |
492 | void | 488 | void | |
493 | dqinit(void) | 489 | dqinit(void) | |
494 | { | 490 | { | |
495 | 491 | |||
496 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | 492 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | |
497 | cv_init(&dqcv, "quota"); | 493 | cv_init(&dqcv, "quota"); | |
498 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); | 494 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); | |
499 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", | 495 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", | |
500 | NULL, IPL_NONE, NULL, NULL, NULL); | 496 | NULL, IPL_NONE, NULL, NULL, NULL); | |
501 | } | 497 | } | |
502 | 498 | |||
503 | void | 499 | void | |
504 | dqreinit(void) | 500 | dqreinit(void) | |
505 | { | 501 | { | |
506 | struct dquot *dq; | 502 | struct dquot *dq; | |
507 | struct dqhashhead *oldhash, *hash; | 503 | struct dqhashhead *oldhash, *hash; | |
508 | struct vnode *dqvp; | 504 | struct vnode *dqvp; | |
509 | u_long oldmask, mask, hashval; | 505 | u_long oldmask, mask, hashval; | |
510 | int i; | 506 | int i; | |
511 | 507 | |||
512 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); | 508 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); | |
513 | mutex_enter(&dqlock); | 509 | mutex_enter(&dqlock); | |
514 | oldhash = dqhashtbl; | 510 | oldhash = dqhashtbl; | |
515 | oldmask = dqhash; | 511 | oldmask = dqhash; | |
516 | dqhashtbl = hash; | 512 | dqhashtbl = hash; | |
517 | dqhash = mask; | 513 | dqhash = mask; | |
518 | for (i = 0; i <= oldmask; i++) { | 514 | for (i = 0; i <= oldmask; i++) { | |
519 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { | 515 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { | |
520 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; | 516 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; | |
521 | LIST_REMOVE(dq, dq_hash); | 517 | LIST_REMOVE(dq, dq_hash); | |
522 | hashval = DQHASH(dqvp, dq->dq_id); | 518 | hashval = DQHASH(dqvp, dq->dq_id); | |
523 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); | 519 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); | |
524 | } | 520 | } | |
525 | } | 521 | } | |
526 | mutex_exit(&dqlock); | 522 | mutex_exit(&dqlock); | |
527 | hashdone(oldhash, HASH_LIST, oldmask); | 523 | hashdone(oldhash, HASH_LIST, oldmask); | |
528 | } | 524 | } | |
529 | 525 | |||
530 | /* | 526 | /* | |
531 | * Free resources held by quota system. | 527 | * Free resources held by quota system. | |
532 | */ | 528 | */ | |
533 | void | 529 | void | |
534 | dqdone(void) | 530 | dqdone(void) | |
535 | { | 531 | { | |
536 | 532 | |||
537 | pool_cache_destroy(dquot_cache); | 533 | pool_cache_destroy(dquot_cache); | |
538 | hashdone(dqhashtbl, HASH_LIST, dqhash); | 534 | hashdone(dqhashtbl, HASH_LIST, dqhash); | |
539 | cv_destroy(&dqcv); | 535 | cv_destroy(&dqcv); | |
540 | mutex_destroy(&dqlock); | 536 | mutex_destroy(&dqlock); | |
541 | } | 537 | } | |
542 | 538 | |||
543 | /* | 539 | /* | |
544 | * Set up the quotas for an inode. | 540 | * Set up the quotas for an inode. | |
545 | * | 541 | * | |
546 | * This routine completely defines the semantics of quotas. | 542 | * This routine completely defines the semantics of quotas. | |
547 | * If other criterion want to be used to establish quotas, the | 543 | * If other criterion want to be used to establish quotas, the | |
548 | * MAXQUOTAS value in quotas.h should be increased, and the | 544 | * MAXQUOTAS value in quotas.h should be increased, and the | |
549 | * additional dquots set up here. | 545 | * additional dquots set up here. | |
550 | */ | 546 | */ | |
551 | int | 547 | int | |
552 | getinoquota(struct inode *ip) | 548 | getinoquota(struct inode *ip) | |
553 | { | 549 | { | |
554 | struct ufsmount *ump = ip->i_ump; | 550 | struct ufsmount *ump = ip->i_ump; | |
555 | struct vnode *vp = ITOV(ip); | 551 | struct vnode *vp = ITOV(ip); | |
556 | int i, error; | 552 | int i, error; | |
557 | u_int32_t ino_ids[MAXQUOTAS]; | 553 | u_int32_t ino_ids[MAXQUOTAS]; | |
558 | 554 | |||
559 | /* | 555 | /* | |
560 | * To avoid deadlocks never update quotas for quota files | 556 | * To avoid deadlocks never update quotas for quota files | |
561 | * on the same file system | 557 | * on the same file system | |
562 | */ | 558 | */ | |
563 | for (i = 0; i < MAXQUOTAS; i++) | 559 | for (i = 0; i < MAXQUOTAS; i++) | |
564 | if (vp == ump->um_quotas[i]) | 560 | if (vp == ump->um_quotas[i]) | |
565 | return 0; | 561 | return 0; | |
566 | 562 | |||
567 | ino_ids[USRQUOTA] = ip->i_uid; | 563 | ino_ids[USRQUOTA] = ip->i_uid; | |
568 | ino_ids[GRPQUOTA] = ip->i_gid; | 564 | ino_ids[GRPQUOTA] = ip->i_gid; | |
569 | for (i = 0; i < MAXQUOTAS; i++) { | 565 | for (i = 0; i < MAXQUOTAS; i++) { | |
570 | /* | 566 | /* | |
571 | * If the file id changed the quota needs update. | 567 | * If the file id changed the quota needs update. | |
572 | */ | 568 | */ | |
573 | if (ip->i_dquot[i] != NODQUOT && | 569 | if (ip->i_dquot[i] != NODQUOT && | |
574 | ip->i_dquot[i]->dq_id != ino_ids[i]) { | 570 | ip->i_dquot[i]->dq_id != ino_ids[i]) { | |
575 | dqrele(ITOV(ip), ip->i_dquot[i]); | 571 | dqrele(ITOV(ip), ip->i_dquot[i]); | |
576 | ip->i_dquot[i] = NODQUOT; | 572 | ip->i_dquot[i] = NODQUOT; | |
577 | } | 573 | } | |
578 | /* | 574 | /* | |
579 | * Set up the quota based on file id. | 575 | * Set up the quota based on file id. | |
580 | * ENODEV means that quotas are not enabled. | 576 | * ENODEV means that quotas are not enabled. | |
581 | */ | 577 | */ | |
582 | if (ip->i_dquot[i] == NODQUOT && | 578 | if (ip->i_dquot[i] == NODQUOT && | |
583 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && | 579 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && | |
584 | error != ENODEV) | 580 | error != ENODEV) | |
585 | return (error); | 581 | return (error); | |
586 | } | 582 | } | |
587 | return 0; | 583 | return 0; | |
588 | } | 584 | } | |
589 | 585 | |||
590 | /* | 586 | /* | |
591 | * Obtain a dquot structure for the specified identifier and quota file | 587 | * Obtain a dquot structure for the specified identifier and quota file | |
592 | * reading the information from the file if necessary. | 588 | * reading the information from the file if necessary. | |
593 | */ | 589 | */ | |
594 | int | 590 | int | |
595 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, | 591 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, | |
596 | struct dquot **dqp) | 592 | struct dquot **dqp) | |
597 | { | 593 | { | |
598 | struct dquot *dq, *ndq; | 594 | struct dquot *dq, *ndq; | |
599 | struct dqhashhead *dqh; | 595 | struct dqhashhead *dqh; | |
600 | struct vnode *dqvp; | 596 | struct vnode *dqvp; | |
601 | int error = 0; /* XXX gcc */ | 597 | int error = 0; /* XXX gcc */ | |
602 | 598 | |||
603 | /* Lock to see an up to date value for QTF_CLOSING. */ | 599 | /* Lock to see an up to date value for QTF_CLOSING. */ | |
604 | mutex_enter(&dqlock); | 600 | mutex_enter(&dqlock); | |
605 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { | 601 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { | |
606 | mutex_exit(&dqlock); | 602 | mutex_exit(&dqlock); | |
607 | *dqp = NODQUOT; | 603 | *dqp = NODQUOT; | |
608 | return (ENODEV); | 604 | return (ENODEV); | |
609 | } | 605 | } | |
610 | dqvp = ump->um_quotas[type]; | 606 | dqvp = ump->um_quotas[type]; | |
611 | #ifdef QUOTA | 607 | #ifdef QUOTA | |
612 | if (ump->um_flags & UFS_QUOTA) { | 608 | if (ump->um_flags & UFS_QUOTA) { | |
613 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { | 609 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { | |
614 | mutex_exit(&dqlock); | 610 | mutex_exit(&dqlock); | |
615 | *dqp = NODQUOT; | 611 | *dqp = NODQUOT; | |
616 | return (ENODEV); | 612 | return (ENODEV); | |
617 | } | 613 | } | |
618 | } | 614 | } | |
619 | #endif | 615 | #endif | |
620 | #ifdef QUOTA2 | 616 | #ifdef QUOTA2 | |
621 | if (ump->um_flags & UFS_QUOTA2) { | 617 | if (ump->um_flags & UFS_QUOTA2) { | |
622 | if (dqvp == NULLVP) { | 618 | if (dqvp == NULLVP) { | |
623 | mutex_exit(&dqlock); | 619 | mutex_exit(&dqlock); | |
624 | *dqp = NODQUOT; | 620 | *dqp = NODQUOT; | |
625 | return (ENODEV); | 621 | return (ENODEV); | |
626 | } | 622 | } | |
627 | } | 623 | } | |
628 | #endif | 624 | #endif | |
629 | KASSERT(dqvp != vp); | 625 | KASSERT(dqvp != vp); | |
630 | /* | 626 | /* | |
631 | * Check the cache first. | 627 | * Check the cache first. | |
632 | */ | 628 | */ | |
633 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | 629 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | |
634 | LIST_FOREACH(dq, dqh, dq_hash) { | 630 | LIST_FOREACH(dq, dqh, dq_hash) { | |
635 | if (dq->dq_id != id || | 631 | if (dq->dq_id != id || | |
636 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | 632 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | |
637 | continue; | 633 | continue; | |
638 | KASSERT(dq->dq_cnt > 0); | 634 | KASSERT(dq->dq_cnt > 0); | |
639 | dqref(dq); | 635 | dqref(dq); | |
640 | mutex_exit(&dqlock); | 636 | mutex_exit(&dqlock); | |
641 | *dqp = dq; | 637 | *dqp = dq; | |
642 | return (0); | 638 | return (0); | |
643 | } | 639 | } | |
644 | /* | 640 | /* | |
645 | * Not in cache, allocate a new one. | 641 | * Not in cache, allocate a new one. | |
646 | */ | 642 | */ | |
647 | mutex_exit(&dqlock); | 643 | mutex_exit(&dqlock); | |
648 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); | 644 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); | |
649 | /* | 645 | /* | |
650 | * Initialize the contents of the dquot structure. | 646 | * Initialize the contents of the dquot structure. | |
651 | */ | 647 | */ | |
652 | memset((char *)ndq, 0, sizeof *ndq); | 648 | memset((char *)ndq, 0, sizeof *ndq); | |
653 | ndq->dq_flags = 0; | 649 | ndq->dq_flags = 0; | |
654 | ndq->dq_id = id; | 650 | ndq->dq_id = id; | |
655 | ndq->dq_ump = ump; | 651 | ndq->dq_ump = ump; | |
656 | ndq->dq_type = type; | 652 | ndq->dq_type = type; | |
657 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); | 653 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); | |
658 | mutex_enter(&dqlock); | 654 | mutex_enter(&dqlock); | |
659 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | 655 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | |
660 | LIST_FOREACH(dq, dqh, dq_hash) { | 656 | LIST_FOREACH(dq, dqh, dq_hash) { | |
661 | if (dq->dq_id != id || | 657 | if (dq->dq_id != id || | |
662 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | 658 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | |
663 | continue; | 659 | continue; | |
664 | /* | 660 | /* | |
665 | * Another thread beat us allocating this dquot. | 661 | * Another thread beat us allocating this dquot. | |
666 | */ | 662 | */ | |
667 | KASSERT(dq->dq_cnt > 0); | 663 | KASSERT(dq->dq_cnt > 0); | |
668 | dqref(dq); | 664 | dqref(dq); | |
669 | mutex_exit(&dqlock); | 665 | mutex_exit(&dqlock); | |
670 | mutex_destroy(&ndq->dq_interlock); | 666 | mutex_destroy(&ndq->dq_interlock); | |
671 | pool_cache_put(dquot_cache, ndq); | 667 | pool_cache_put(dquot_cache, ndq); | |
672 | *dqp = dq; | 668 | *dqp = dq; | |
673 | return 0; | 669 | return 0; | |
674 | } | 670 | } | |
675 | dq = ndq; | 671 | dq = ndq; | |
676 | LIST_INSERT_HEAD(dqh, dq, dq_hash); | 672 | LIST_INSERT_HEAD(dqh, dq, dq_hash); | |
677 | dqref(dq); | 673 | dqref(dq); | |
678 | mutex_enter(&dq->dq_interlock); | 674 | mutex_enter(&dq->dq_interlock); | |
679 | mutex_exit(&dqlock); | 675 | mutex_exit(&dqlock); | |
680 | #ifdef QUOTA | 676 | #ifdef QUOTA | |
681 | if (ump->um_flags & UFS_QUOTA) | 677 | if (ump->um_flags & UFS_QUOTA) | |
682 | error = dq1get(dqvp, id, ump, type, dq); | 678 | error = dq1get(dqvp, id, ump, type, dq); | |
683 | #endif | 679 | #endif | |
684 | #ifdef QUOTA2 | 680 | #ifdef QUOTA2 | |
685 | if (ump->um_flags & UFS_QUOTA2) | 681 | if (ump->um_flags & UFS_QUOTA2) | |
686 | error = dq2get(dqvp, id, ump, type, dq); | 682 | error = dq2get(dqvp, id, ump, type, dq); | |
687 | #endif | 683 | #endif | |
688 | /* | 684 | /* | |
689 | * I/O error in reading quota file, release | 685 | * I/O error in reading quota file, release | |
690 | * quota structure and reflect problem to caller. | 686 | * quota structure and reflect problem to caller. | |
691 | */ | 687 | */ | |
692 | if (error) { | 688 | if (error) { | |
693 | mutex_enter(&dqlock); | 689 | mutex_enter(&dqlock); | |
694 | LIST_REMOVE(dq, dq_hash); | 690 | LIST_REMOVE(dq, dq_hash); | |
695 | mutex_exit(&dqlock); | 691 | mutex_exit(&dqlock); | |
696 | mutex_exit(&dq->dq_interlock); | 692 | mutex_exit(&dq->dq_interlock); | |
697 | dqrele(vp, dq); | 693 | dqrele(vp, dq); | |
698 | *dqp = NODQUOT; | 694 | *dqp = NODQUOT; | |
699 | return (error); | 695 | return (error); | |
700 | } | 696 | } | |
701 | mutex_exit(&dq->dq_interlock); | 697 | mutex_exit(&dq->dq_interlock); | |
702 | *dqp = dq; | 698 | *dqp = dq; | |
703 | return (0); | 699 | return (0); | |
704 | } | 700 | } | |
705 | 701 | |||
706 | /* | 702 | /* | |
707 | * Obtain a reference to a dquot. | 703 | * Obtain a reference to a dquot. | |
708 | */ | 704 | */ | |
709 | void | 705 | void | |
710 | dqref(struct dquot *dq) | 706 | dqref(struct dquot *dq) | |
711 | { | 707 | { | |
712 | 708 | |||
713 | KASSERT(mutex_owned(&dqlock)); | 709 | KASSERT(mutex_owned(&dqlock)); | |
714 | dq->dq_cnt++; | 710 | dq->dq_cnt++; | |
715 | KASSERT(dq->dq_cnt > 0); | 711 | KASSERT(dq->dq_cnt > 0); | |
716 | } | 712 | } | |
717 | 713 | |||
718 | /* | 714 | /* | |
719 | * Release a reference to a dquot. | 715 | * Release a reference to a dquot. | |
720 | */ | 716 | */ | |
721 | void | 717 | void | |
722 | dqrele(struct vnode *vp, struct dquot *dq) | 718 | dqrele(struct vnode *vp, struct dquot *dq) | |
723 | { | 719 | { | |
724 | 720 | |||
725 | if (dq == NODQUOT) | 721 | if (dq == NODQUOT) | |
726 | return; | 722 | return; | |
727 | mutex_enter(&dq->dq_interlock); | 723 | mutex_enter(&dq->dq_interlock); | |
728 | for (;;) { | 724 | for (;;) { | |
729 | mutex_enter(&dqlock); | 725 | mutex_enter(&dqlock); | |
730 | if (dq->dq_cnt > 1) { | 726 | if (dq->dq_cnt > 1) { | |
731 | dq->dq_cnt--; | 727 | dq->dq_cnt--; | |
732 | mutex_exit(&dqlock); | 728 | mutex_exit(&dqlock); | |
733 | mutex_exit(&dq->dq_interlock); | 729 | mutex_exit(&dq->dq_interlock); | |
734 | return; | 730 | return; | |
735 | } | 731 | } | |
736 | if ((dq->dq_flags & DQ_MOD) == 0) | 732 | if ((dq->dq_flags & DQ_MOD) == 0) | |
737 | break; | 733 | break; | |
738 | mutex_exit(&dqlock); | 734 | mutex_exit(&dqlock); | |
739 | #ifdef QUOTA | 735 | #ifdef QUOTA | |
740 | if (dq->dq_ump->um_flags & UFS_QUOTA) | 736 | if (dq->dq_ump->um_flags & UFS_QUOTA) | |
741 | (void) dq1sync(vp, dq); | 737 | (void) dq1sync(vp, dq); | |
742 | #endif | 738 | #endif | |
743 | #ifdef QUOTA2 | 739 | #ifdef QUOTA2 | |
744 | if (dq->dq_ump->um_flags & UFS_QUOTA2) | 740 | if (dq->dq_ump->um_flags & UFS_QUOTA2) | |
745 | (void) dq2sync(vp, dq); | 741 | (void) dq2sync(vp, dq); | |
746 | #endif | 742 | #endif | |
747 | } | 743 | } | |
748 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); | 744 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); | |
749 | LIST_REMOVE(dq, dq_hash); | 745 | LIST_REMOVE(dq, dq_hash); | |
750 | mutex_exit(&dqlock); | 746 | mutex_exit(&dqlock); | |
751 | mutex_exit(&dq->dq_interlock); | 747 | mutex_exit(&dq->dq_interlock); | |
752 | mutex_destroy(&dq->dq_interlock); | 748 | mutex_destroy(&dq->dq_interlock); | |
753 | pool_cache_put(dquot_cache, dq); | 749 | pool_cache_put(dquot_cache, dq); | |
754 | } | 750 | } | |
755 | 751 | |||
756 | int | 752 | int | |
757 | qsync(struct mount *mp) | 753 | qsync(struct mount *mp) | |
758 | { | 754 | { | |
759 | struct ufsmount *ump = VFSTOUFS(mp); | 755 | struct ufsmount *ump = VFSTOUFS(mp); | |
760 | #ifdef QUOTA | 756 | #ifdef QUOTA | |
761 | if (ump->um_flags & UFS_QUOTA) | 757 | if (ump->um_flags & UFS_QUOTA) | |
762 | return q1sync(mp); | 758 | return q1sync(mp); | |
763 | #endif | 759 | #endif | |
764 | #ifdef QUOTA2 | 760 | #ifdef QUOTA2 | |
765 | if (ump->um_flags & UFS_QUOTA2) | 761 | if (ump->um_flags & UFS_QUOTA2) | |
766 | return q2sync(mp); | 762 | return q2sync(mp); | |
767 | #endif | 763 | #endif | |
768 | return 0; | 764 | return 0; | |
769 | } | 765 | } | |
770 | 766 | |||
771 | #ifdef DIAGNOSTIC | 767 | #ifdef DIAGNOSTIC | |
772 | /* | 768 | /* | |
773 | * Check the hash chains for stray dquot's. | 769 | * Check the hash chains for stray dquot's. | |
774 | */ | 770 | */ | |
775 | void | 771 | void | |
776 | dqflush(struct vnode *vp) | 772 | dqflush(struct vnode *vp) | |
777 | { | 773 | { | |
778 | struct dquot *dq; | 774 | struct dquot *dq; | |
779 | int i; | 775 | int i; | |
780 | 776 | |||
781 | mutex_enter(&dqlock); | 777 | mutex_enter(&dqlock); | |
782 | for (i = 0; i <= dqhash; i++) | 778 | for (i = 0; i <= dqhash; i++) | |
783 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) | 779 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) | |
784 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); | 780 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); | |
785 | mutex_exit(&dqlock); | 781 | mutex_exit(&dqlock); | |
786 | } | 782 | } | |
787 | #endif | 783 | #endif |
--- src/sys/ufs/ufs/ufs_quota.h 2012/01/29 06:49:44 1.10
+++ src/sys/ufs/ufs/ufs_quota.h 2012/01/29 06:52:39 1.11
@@ -1,134 +1,134 @@ | @@ -1,134 +1,134 @@ | |||
1 | /* $NetBSD: ufs_quota.h,v 1.10 2012/01/29 06:49:44 dholland Exp $ */ | 1 | /* $NetBSD: ufs_quota.h,v 1.11 2012/01/29 06:52:39 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) */ | |
40 | struct dq2_desc { | 40 | struct 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 | */ | |
57 | struct dquot { | 57 | struct 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 | |||
98 | extern kmutex_t dqlock; | 98 | extern kmutex_t dqlock; | |
99 | extern kcondvar_t dqcv; | 99 | extern kcondvar_t dqcv; | |
100 | /* | 100 | /* | |
101 | * Quota name to error message mapping. | 101 | * Quota name to error message mapping. | |
102 | */ | 102 | */ | |
103 | const char *quotatypes[MAXQUOTAS]; | 103 | const char *quotatypes[MAXQUOTAS]; | |
104 | 104 | |||
105 | int getinoquota(struct inode *); | 105 | int getinoquota(struct inode *); | |
106 | int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **); | 106 | int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **); | |
107 | void dqref(struct dquot *); | 107 | void dqref(struct dquot *); | |
108 | void dqrele(struct vnode *, struct dquot *); | 108 | void dqrele(struct vnode *, struct dquot *); | |
109 | void dqflush(struct vnode *); | 109 | void dqflush(struct vnode *); | |
110 | 110 | |||
111 | int chkdq1(struct inode *, int64_t, kauth_cred_t, int); | 111 | int chkdq1(struct inode *, int64_t, kauth_cred_t, int); | |
112 | int chkiq1(struct inode *, int32_t, kauth_cred_t, int); | 112 | int chkiq1(struct inode *, int32_t, kauth_cred_t, int); | |
113 | int q1sync(struct mount *); | 113 | int q1sync(struct mount *); | |
114 | int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | 114 | int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | |
115 | int dq1sync(struct vnode *, struct dquot *); | 115 | int dq1sync(struct vnode *, struct dquot *); | |
116 | int quota1_handle_cmd_get(struct ufsmount *, const struct quotakey *, | 116 | int quota1_handle_cmd_get(struct ufsmount *, const struct quotakey *, | |
117 | struct quotaval *); | 117 | struct quotaval *); | |
118 | int quota1_handle_cmd_put(struct ufsmount *, const struct quotakey *, | 118 | int quota1_handle_cmd_put(struct ufsmount *, const struct quotakey *, | |
119 | const struct quotaval *); | 119 | const struct quotaval *); | |
120 | int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int, | 120 | int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int, | |
121 | const char *); | 121 | const char *); | |
122 | int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int); | 122 | int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int); | |
123 | 123 | |||
124 | int chkdq2(struct inode *, int64_t, kauth_cred_t, int); | 124 | int chkdq2(struct inode *, int64_t, kauth_cred_t, int); | |
125 | int chkiq2(struct inode *, int32_t, kauth_cred_t, int); | 125 | int chkiq2(struct inode *, int32_t, kauth_cred_t, int); | |
126 | int quota2_handle_cmd_get(struct ufsmount *, const struct quotakey *, | 126 | int quota2_handle_cmd_get(struct ufsmount *, const struct quotakey *, | |
127 | struct quotaval *); | 127 | struct quotaval *); | |
128 | int quota2_handle_cmd_put(struct ufsmount *, const struct quotakey *, | 128 | int quota2_handle_cmd_put(struct ufsmount *, const struct quotakey *, | |
129 | const struct quotaval *); | 129 | const struct quotaval *); | |
130 | int quota2_handle_cmd_clear(struct ufsmount *, int, int, int, prop_dictionary_t); | 130 | int quota2_handle_cmd_clear(struct ufsmount *, int, int, int); | |
131 | int quota2_handle_cmd_getall(struct ufsmount *, int, prop_array_t); | 131 | int quota2_handle_cmd_getall(struct ufsmount *, int, prop_array_t); | |
132 | int q2sync(struct mount *); | 132 | int q2sync(struct mount *); | |
133 | int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | 133 | int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | |
134 | int dq2sync(struct vnode *, struct dquot *); | 134 | int dq2sync(struct vnode *, struct dquot *); |
--- src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 06:49:44 1.11
+++ src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 06:52:39 1.12
@@ -1,1084 +1,1084 @@ | @@ -1,1084 +1,1084 @@ | |||
1 | /* $NetBSD: ufs_quota2.c,v 1.11 2012/01/29 06:49:44 dholland Exp $ */ | 1 | /* $NetBSD: ufs_quota2.c,v 1.12 2012/01/29 06:52:39 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.11 2012/01/29 06:49:44 dholland Exp $"); | 29 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.12 2012/01/29 06:52:39 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 | |||
65 | static int quota2_bwrite(struct mount *, struct buf *); | 65 | static int quota2_bwrite(struct mount *, struct buf *); | |
66 | static int getinoquota2(struct inode *, bool, bool, struct buf **, | 66 | static int getinoquota2(struct inode *, bool, bool, struct buf **, | |
67 | struct quota2_entry **); | 67 | struct quota2_entry **); | |
68 | static int getq2h(struct ufsmount *, int, struct buf **, | 68 | static int getq2h(struct ufsmount *, int, struct buf **, | |
69 | struct quota2_header **, int); | 69 | struct quota2_header **, int); | |
70 | static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **, | 70 | static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **, | |
71 | struct quota2_entry **, int); | 71 | struct quota2_entry **, int); | |
72 | static int quota2_walk_list(struct ufsmount *, struct buf *, int, | 72 | static 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 | |||
77 | static prop_dictionary_t q2etoprop(struct quota2_entry *, int); | 77 | static prop_dictionary_t q2etoprop(struct quota2_entry *, int); | |
78 | 78 | |||
79 | static const char *limnames[] = INITQLNAMES; | 79 | static const char *limnames[] = INITQLNAMES; | |
80 | 80 | |||
81 | static void | 81 | static void | |
82 | quota2_dict_update_q2e_limits(int objtype, const struct quotaval *val, | 82 | quota2_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 | |||
94 | static prop_dictionary_t | 94 | static prop_dictionary_t | |
95 | q2etoprop(struct quota2_entry *q2e, int def) | 95 | q2etoprop(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 | |||
125 | err: | 125 | err: | |
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 | */ | |
136 | static void | 136 | static void | |
137 | q2val_to_quotaval(struct quota2_val *q2v, struct quotaval *qv) | 137 | q2val_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 | */ | |
150 | static void | 150 | static void | |
151 | q2e_to_quotaval(struct quota2_entry *q2e, int def, | 151 | q2e_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 | |||
165 | static int | 165 | static int | |
166 | quota2_bwrite(struct mount *mp, struct buf *bp) | 166 | quota2_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 | |||
176 | static int | 176 | static int | |
177 | getq2h(struct ufsmount *ump, int type, | 177 | getq2h(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 | |||
204 | static int | 204 | static int | |
205 | getq2e(struct ufsmount *ump, int type, daddr_t lblkno, int blkoffset, | 205 | getq2e(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 | |||
231 | static int | 231 | static int | |
232 | quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type, | 232 | quota2_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 | |||
307 | int | 307 | int | |
308 | quota2_umount(struct mount *mp, int flags) | 308 | quota2_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 | |||
331 | static int | 331 | static int | |
332 | quota2_q2ealloc(struct ufsmount *ump, int type, uid_t uid, struct dquot *dq, | 332 | quota2_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 | |||
408 | static int | 408 | static int | |
409 | getinoquota2(struct inode *ip, bool alloc, bool modify, struct buf **bpp, | 409 | getinoquota2(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 | |||
474 | static int | 474 | static int | |
475 | quota2_check(struct inode *ip, int vtype, int64_t change, kauth_cred_t cred, | 475 | quota2_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 | |||
601 | int | 601 | int | |
602 | chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | 602 | chkdq2(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 | |||
607 | int | 607 | int | |
608 | chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | 608 | chkiq2(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 | |||
613 | int | 613 | int | |
614 | quota2_handle_cmd_put(struct ufsmount *ump, const struct quotakey *key, | 614 | quota2_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 | |||
672 | out_il: | 672 | out_il: | |
673 | mutex_exit(&dq->dq_interlock); | 673 | mutex_exit(&dq->dq_interlock); | |
674 | dqrele(NULLVP, dq); | 674 | dqrele(NULLVP, dq); | |
675 | out_wapbl: | 675 | out_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 | |||
680 | struct dq2clear_callback { | 680 | struct 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 | |||
686 | static int | 686 | static int | |
687 | dq2clear_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, | 687 | dq2clear_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 | } | |
710 | int | 710 | int | |
711 | quota2_handle_cmd_clear(struct ufsmount *ump, int type, int id, | 711 | quota2_handle_cmd_clear(struct ufsmount *ump, int idtype, int id, | |
712 | int defaultq, prop_dictionary_t data) | 712 | int defaultq) | |
713 | { | 713 | { | |
714 | int error, i; | 714 | int error, i; | |
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[type] == 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, type, &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, type, &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, type, 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 | if (q2ep->q2e_val[QL_BLOCK].q2v_cur != 0 || | |
759 | q2ep->q2e_val[QL_FILE].q2v_cur != 0) { | 759 | q2ep->q2e_val[QL_FILE].q2v_cur != 0) { | |
760 | /* can't free this entry; revert to default */ | 760 | /* can't free this entry; revert to default */ | |
761 | for (i = 0; i < N_QL; i++) { | 761 | for (i = 0; i < N_QL; i++) { | |
762 | q2ep->q2e_val[i].q2v_softlimit = | 762 | q2ep->q2e_val[i].q2v_softlimit = | |
763 | q2e.q2e_val[i].q2v_softlimit; | 763 | q2e.q2e_val[i].q2v_softlimit; | |
764 | q2ep->q2e_val[i].q2v_hardlimit = | 764 | q2ep->q2e_val[i].q2v_hardlimit = | |
765 | q2e.q2e_val[i].q2v_hardlimit; | 765 | q2e.q2e_val[i].q2v_hardlimit; | |
766 | q2ep->q2e_val[i].q2v_grace = | 766 | q2ep->q2e_val[i].q2v_grace = | |
767 | q2e.q2e_val[i].q2v_grace; | 767 | q2e.q2e_val[i].q2v_grace; | |
768 | q2ep->q2e_val[i].q2v_time = 0; | 768 | q2ep->q2e_val[i].q2v_time = 0; | |
769 | } | 769 | } | |
770 | quota2_bwrite(ump->um_mountp, bp); | 770 | quota2_bwrite(ump->um_mountp, bp); | |
771 | goto out_wapbl; | 771 | goto out_wapbl; | |
772 | } | 772 | } | |
773 | /* we can free it. release bp so we can walk the list */ | 773 | /* we can free it. release bp so we can walk the list */ | |
774 | brelse(bp, 0); | 774 | brelse(bp, 0); | |
775 | mutex_enter(&dqlock); | 775 | mutex_enter(&dqlock); | |
776 | error = getq2h(ump, type, &hbp, &q2h, 0); | 776 | error = getq2h(ump, idtype, &hbp, &q2h, 0); | |
777 | if (error) | 777 | if (error) | |
778 | goto out_dqlock; | 778 | goto out_dqlock; | |
779 | 779 | |||
780 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | 780 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | |
781 | c.dq = dq; | 781 | c.dq = dq; | |
782 | c.id = id; | 782 | c.id = id; | |
783 | c.q2h = q2h; | 783 | c.q2h = q2h; | |
784 | error = quota2_walk_list(ump, hbp, type, | 784 | error = quota2_walk_list(ump, hbp, idtype, | |
785 | &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c, | 785 | &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c, | |
786 | dq2clear_callback); | 786 | dq2clear_callback); | |
787 | 787 | |||
788 | bwrite(hbp); | 788 | bwrite(hbp); | |
789 | 789 | |||
790 | out_dqlock: | 790 | out_dqlock: | |
791 | mutex_exit(&dqlock); | 791 | mutex_exit(&dqlock); | |
792 | out_wapbl: | 792 | out_wapbl: | |
793 | UFS_WAPBL_END(ump->um_mountp); | 793 | UFS_WAPBL_END(ump->um_mountp); | |
794 | out_il: | 794 | out_il: | |
795 | mutex_exit(&dq->dq_interlock); | 795 | mutex_exit(&dq->dq_interlock); | |
796 | out_dq: | 796 | out_dq: | |
797 | dqrele(NULLVP, dq); | 797 | dqrele(NULLVP, dq); | |
798 | return error; | 798 | return error; | |
799 | } | 799 | } | |
800 | 800 | |||
801 | static int | 801 | static int | |
802 | quota2_array_add_q2e(struct ufsmount *ump, int type, | 802 | quota2_array_add_q2e(struct ufsmount *ump, int type, | |
803 | int id, prop_array_t replies) | 803 | int id, prop_array_t replies) | |
804 | { | 804 | { | |
805 | struct dquot *dq; | 805 | struct dquot *dq; | |
806 | int error; | 806 | int error; | |
807 | struct quota2_entry *q2ep, q2e; | 807 | struct quota2_entry *q2ep, q2e; | |
808 | struct buf *bp; | 808 | struct buf *bp; | |
809 | const int needswap = UFS_MPNEEDSWAP(ump); | 809 | const int needswap = UFS_MPNEEDSWAP(ump); | |
810 | prop_dictionary_t dict; | 810 | prop_dictionary_t dict; | |
811 | 811 | |||
812 | error = dqget(NULLVP, id, ump, type, &dq); | 812 | error = dqget(NULLVP, id, ump, type, &dq); | |
813 | if (error) | 813 | if (error) | |
814 | return error; | 814 | return error; | |
815 | 815 | |||
816 | mutex_enter(&dq->dq_interlock); | 816 | mutex_enter(&dq->dq_interlock); | |
817 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | 817 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | |
818 | mutex_exit(&dq->dq_interlock); | 818 | mutex_exit(&dq->dq_interlock); | |
819 | dqrele(NULLVP, dq); | 819 | dqrele(NULLVP, dq); | |
820 | return ENOENT; | 820 | return ENOENT; | |
821 | } | 821 | } | |
822 | error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff, | 822 | error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff, | |
823 | &bp, &q2ep, 0); | 823 | &bp, &q2ep, 0); | |
824 | if (error) { | 824 | if (error) { | |
825 | mutex_exit(&dq->dq_interlock); | 825 | mutex_exit(&dq->dq_interlock); | |
826 | dqrele(NULLVP, dq); | 826 | dqrele(NULLVP, dq); | |
827 | return error; | 827 | return error; | |
828 | } | 828 | } | |
829 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | 829 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | |
830 | brelse(bp, 0); | 830 | brelse(bp, 0); | |
831 | mutex_exit(&dq->dq_interlock); | 831 | mutex_exit(&dq->dq_interlock); | |
832 | dqrele(NULLVP, dq); | 832 | dqrele(NULLVP, dq); | |
833 | 833 | |||
834 | dict = q2etoprop(&q2e, 0); | 834 | dict = q2etoprop(&q2e, 0); | |
835 | if (dict == NULL) | 835 | if (dict == NULL) | |
836 | return ENOMEM; | 836 | return ENOMEM; | |
837 | if (!prop_array_add_and_rel(replies, dict)) | 837 | if (!prop_array_add_and_rel(replies, dict)) | |
838 | return ENOMEM; | 838 | return ENOMEM; | |
839 | return 0; | 839 | return 0; | |
840 | } | 840 | } | |
841 | 841 | |||
842 | static int | 842 | static int | |
843 | quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, | 843 | quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, | |
844 | struct quotaval *ret) | 844 | struct quotaval *ret) | |
845 | { | 845 | { | |
846 | struct dquot *dq; | 846 | struct dquot *dq; | |
847 | int error; | 847 | int error; | |
848 | struct quota2_entry *q2ep, q2e; | 848 | struct quota2_entry *q2ep, q2e; | |
849 | struct buf *bp; | 849 | struct buf *bp; | |
850 | const int needswap = UFS_MPNEEDSWAP(ump); | 850 | const int needswap = UFS_MPNEEDSWAP(ump); | |
851 | id_t id2; | 851 | id_t id2; | |
852 | 852 | |||
853 | error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); | 853 | error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); | |
854 | if (error) | 854 | if (error) | |
855 | return error; | 855 | return error; | |
856 | 856 | |||
857 | mutex_enter(&dq->dq_interlock); | 857 | mutex_enter(&dq->dq_interlock); | |
858 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | 858 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | |
859 | mutex_exit(&dq->dq_interlock); | 859 | mutex_exit(&dq->dq_interlock); | |
860 | dqrele(NULLVP, dq); | 860 | dqrele(NULLVP, dq); | |
861 | return ENOENT; | 861 | return ENOENT; | |
862 | } | 862 | } | |
863 | error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff, | 863 | error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff, | |
864 | &bp, &q2ep, 0); | 864 | &bp, &q2ep, 0); | |
865 | if (error) { | 865 | if (error) { | |
866 | mutex_exit(&dq->dq_interlock); | 866 | mutex_exit(&dq->dq_interlock); | |
867 | dqrele(NULLVP, dq); | 867 | dqrele(NULLVP, dq); | |
868 | return error; | 868 | return error; | |
869 | } | 869 | } | |
870 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | 870 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | |
871 | brelse(bp, 0); | 871 | brelse(bp, 0); | |
872 | mutex_exit(&dq->dq_interlock); | 872 | mutex_exit(&dq->dq_interlock); | |
873 | dqrele(NULLVP, dq); | 873 | dqrele(NULLVP, dq); | |
874 | 874 | |||
875 | q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret); | 875 | q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret); | |
876 | KASSERT(id2 == qk->qk_id); | 876 | KASSERT(id2 == qk->qk_id); | |
877 | return 0; | 877 | return 0; | |
878 | } | 878 | } | |
879 | 879 | |||
880 | int | 880 | int | |
881 | quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk, | 881 | quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk, | |
882 | struct quotaval *ret) | 882 | struct quotaval *ret) | |
883 | { | 883 | { | |
884 | int error; | 884 | int error; | |
885 | struct quota2_header *q2h; | 885 | struct quota2_header *q2h; | |
886 | struct quota2_entry q2e; | 886 | struct quota2_entry q2e; | |
887 | struct buf *bp; | 887 | struct buf *bp; | |
888 | const int needswap = UFS_MPNEEDSWAP(ump); | 888 | const int needswap = UFS_MPNEEDSWAP(ump); | |
889 | id_t id2; | 889 | id_t id2; | |
890 | 890 | |||
891 | /* | 891 | /* | |
892 | * Make sure the FS-independent codes match the internal ones, | 892 | * Make sure the FS-independent codes match the internal ones, | |
893 | * so we can use the passed-in objtype without having to | 893 | * so we can use the passed-in objtype without having to | |
894 | * convert it explicitly to QL_BLOCK/QL_FILE. | 894 | * convert it explicitly to QL_BLOCK/QL_FILE. | |
895 | */ | 895 | */ | |
896 | CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS); | 896 | CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS); | |
897 | CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES); | 897 | CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES); | |
898 | CTASSERT(N_QL == 2); | 898 | CTASSERT(N_QL == 2); | |
899 | 899 | |||
900 | if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) { | 900 | if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) { | |
901 | return EINVAL; | 901 | return EINVAL; | |
902 | } | 902 | } | |
903 | 903 | |||
904 | if (ump->um_quotas[qk->qk_idtype] == NULLVP) | 904 | if (ump->um_quotas[qk->qk_idtype] == NULLVP) | |
905 | return ENODEV; | 905 | return ENODEV; | |
906 | if (qk->qk_id == QUOTA_DEFAULTID) { | 906 | if (qk->qk_id == QUOTA_DEFAULTID) { | |
907 | mutex_enter(&dqlock); | 907 | mutex_enter(&dqlock); | |
908 | error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); | 908 | error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); | |
909 | if (error) { | 909 | if (error) { | |
910 | mutex_exit(&dqlock); | 910 | mutex_exit(&dqlock); | |
911 | return error; | 911 | return error; | |
912 | } | 912 | } | |
913 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | 913 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | |
914 | mutex_exit(&dqlock); | 914 | mutex_exit(&dqlock); | |
915 | brelse(bp, 0); | 915 | brelse(bp, 0); | |
916 | q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, | 916 | q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, | |
917 | qk->qk_objtype, ret); | 917 | qk->qk_objtype, ret); | |
918 | (void)id2; | 918 | (void)id2; | |
919 | } else | 919 | } else | |
920 | error = quota2_fetch_q2e(ump, qk, ret); | 920 | error = quota2_fetch_q2e(ump, qk, ret); | |
921 | 921 | |||
922 | return error; | 922 | return error; | |
923 | } | 923 | } | |
924 | 924 | |||
925 | struct getuids { | 925 | struct getuids { | |
926 | long nuids; /* number of uids in array */ | 926 | long nuids; /* number of uids in array */ | |
927 | long size; /* size of array */ | 927 | long size; /* size of array */ | |
928 | uid_t *uids; /* array of uids, dynamically allocated */ | 928 | uid_t *uids; /* array of uids, dynamically allocated */ | |
929 | }; | 929 | }; | |
930 | 930 | |||
931 | static int | 931 | static int | |
932 | quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, | 932 | quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, | |
933 | struct quota2_entry *q2ep, uint64_t off, void *v) | 933 | struct quota2_entry *q2ep, uint64_t off, void *v) | |
934 | { | 934 | { | |
935 | struct getuids *gu = v; | 935 | struct getuids *gu = v; | |
936 | uid_t *newuids; | 936 | uid_t *newuids; | |
937 | #ifdef FFS_EI | 937 | #ifdef FFS_EI | |
938 | const int needswap = UFS_MPNEEDSWAP(ump); | 938 | const int needswap = UFS_MPNEEDSWAP(ump); | |
939 | #endif | 939 | #endif | |
940 | 940 | |||
941 | if (gu->nuids == gu->size) { | 941 | if (gu->nuids == gu->size) { | |
942 | newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP, | 942 | newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP, | |
943 | M_WAITOK); | 943 | M_WAITOK); | |
944 | if (newuids == NULL) { | 944 | if (newuids == NULL) { | |
945 | free(gu->uids, M_TEMP); | 945 | free(gu->uids, M_TEMP); | |
946 | return ENOMEM; | 946 | return ENOMEM; | |
947 | } | 947 | } | |
948 | gu->uids = newuids; | 948 | gu->uids = newuids; | |
949 | gu->size += (PAGE_SIZE / sizeof(uid_t)); | 949 | gu->size += (PAGE_SIZE / sizeof(uid_t)); | |
950 | } | 950 | } | |
951 | gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); | 951 | gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); | |
952 | gu->nuids++; | 952 | gu->nuids++; | |
953 | return 0; | 953 | return 0; | |
954 | } | 954 | } | |
955 | 955 | |||
956 | int | 956 | int | |
957 | quota2_handle_cmd_getall(struct ufsmount *ump, int type, prop_array_t replies) | 957 | quota2_handle_cmd_getall(struct ufsmount *ump, int type, prop_array_t replies) | |
958 | { | 958 | { | |
959 | int error; | 959 | int error; | |
960 | struct quota2_header *q2h; | 960 | struct quota2_header *q2h; | |
961 | struct quota2_entry q2e; | 961 | struct quota2_entry q2e; | |
962 | struct buf *hbp; | 962 | struct buf *hbp; | |
963 | prop_dictionary_t dict; | 963 | prop_dictionary_t dict; | |
964 | uint64_t offset; | 964 | uint64_t offset; | |
965 | int i, j; | 965 | int i, j; | |
966 | int quota2_hash_size; | 966 | int quota2_hash_size; | |
967 | const int needswap = UFS_MPNEEDSWAP(ump); | 967 | const int needswap = UFS_MPNEEDSWAP(ump); | |
968 | struct getuids gu; | 968 | struct getuids gu; | |
969 | 969 | |||
970 | if (ump->um_quotas[type] == NULLVP) | 970 | if (ump->um_quotas[type] == NULLVP) | |
971 | return ENODEV; | 971 | return ENODEV; | |
972 | mutex_enter(&dqlock); | 972 | mutex_enter(&dqlock); | |
973 | error = getq2h(ump, type, &hbp, &q2h, 0); | 973 | error = getq2h(ump, type, &hbp, &q2h, 0); | |
974 | if (error) { | 974 | if (error) { | |
975 | mutex_exit(&dqlock); | 975 | mutex_exit(&dqlock); | |
976 | return error; | 976 | return error; | |
977 | } | 977 | } | |
978 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | 978 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | |
979 | dict = q2etoprop(&q2e, 1); | 979 | dict = q2etoprop(&q2e, 1); | |
980 | if (!prop_array_add_and_rel(replies, dict)) { | 980 | if (!prop_array_add_and_rel(replies, dict)) { | |
981 | error = ENOMEM; | 981 | error = ENOMEM; | |
982 | goto error_bp; | 982 | goto error_bp; | |
983 | } | 983 | } | |
984 | /* | 984 | /* | |
985 | * we can't directly get entries as we can't walk the list | 985 | * we can't directly get entries as we can't walk the list | |
986 | * with qdlock and grab dq_interlock to read the entries | 986 | * 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, | 987 | * at the same time. So just walk the lists to build a list of uid, | |
988 | * and then read entries for these uids | 988 | * and then read entries for these uids | |
989 | */ | 989 | */ | |
990 | memset(&gu, 0, sizeof(gu)); | 990 | memset(&gu, 0, sizeof(gu)); | |
991 | quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); | 991 | quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); | |
992 | for (i = 0; i < quota2_hash_size ; i++) { | 992 | for (i = 0; i < quota2_hash_size ; i++) { | |
993 | offset = q2h->q2h_entries[i]; | 993 | offset = q2h->q2h_entries[i]; | |
994 | error = quota2_walk_list(ump, hbp, type, &offset, 0, &gu, | 994 | error = quota2_walk_list(ump, hbp, type, &offset, 0, &gu, | |
995 | quota2_getuids_callback); | 995 | quota2_getuids_callback); | |
996 | if (error) { | 996 | if (error) { | |
997 | if (gu.uids != NULL) | 997 | if (gu.uids != NULL) | |
998 | free(gu.uids, M_TEMP); | 998 | free(gu.uids, M_TEMP); | |
999 | break; | 999 | break; | |
1000 | } | 1000 | } | |
1001 | } | 1001 | } | |
1002 | error_bp: | 1002 | error_bp: | |
1003 | mutex_exit(&dqlock); | 1003 | mutex_exit(&dqlock); | |
1004 | brelse(hbp, 0); | 1004 | brelse(hbp, 0); | |
1005 | if (error) | 1005 | if (error) | |
1006 | return error; | 1006 | return error; | |
1007 | for (j = 0; j < gu.nuids; j++) { | 1007 | for (j = 0; j < gu.nuids; j++) { | |
1008 | error = quota2_array_add_q2e(ump, type, | 1008 | error = quota2_array_add_q2e(ump, type, | |
1009 | gu.uids[j], replies); | 1009 | gu.uids[j], replies); | |
1010 | if (error && error != ENOENT) | 1010 | if (error && error != ENOENT) | |
1011 | break; | 1011 | break; | |
1012 | } | 1012 | } | |
1013 | free(gu.uids, M_TEMP); | 1013 | free(gu.uids, M_TEMP); | |
1014 | return error; | 1014 | return error; | |
1015 | } | 1015 | } | |
1016 | 1016 | |||
1017 | int | 1017 | int | |
1018 | q2sync(struct mount *mp) | 1018 | q2sync(struct mount *mp) | |
1019 | { | 1019 | { | |
1020 | return 0; | 1020 | return 0; | |
1021 | } | 1021 | } | |
1022 | 1022 | |||
1023 | struct dq2get_callback { | 1023 | struct dq2get_callback { | |
1024 | uid_t id; | 1024 | uid_t id; | |
1025 | struct dquot *dq; | 1025 | struct dquot *dq; | |
1026 | }; | 1026 | }; | |
1027 | 1027 | |||
1028 | static int | 1028 | static int | |
1029 | dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, | 1029 | dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, | |
1030 | uint64_t off, void *v) | 1030 | uint64_t off, void *v) | |
1031 | { | 1031 | { | |
1032 | struct dq2get_callback *c = v; | 1032 | struct dq2get_callback *c = v; | |
1033 | daddr_t lblkno; | 1033 | daddr_t lblkno; | |
1034 | int blkoff; | 1034 | int blkoff; | |
1035 | #ifdef FFS_EI | 1035 | #ifdef FFS_EI | |
1036 | const int needswap = UFS_MPNEEDSWAP(ump); | 1036 | const int needswap = UFS_MPNEEDSWAP(ump); | |
1037 | #endif | 1037 | #endif | |
1038 | 1038 | |||
1039 | if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { | 1039 | if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { | |
1040 | KASSERT(mutex_owned(&c->dq->dq_interlock)); | 1040 | KASSERT(mutex_owned(&c->dq->dq_interlock)); | |
1041 | lblkno = (off >> ump->um_mountp->mnt_fs_bshift); | 1041 | lblkno = (off >> ump->um_mountp->mnt_fs_bshift); | |
1042 | blkoff = (off & ump->umq2_bmask); | 1042 | blkoff = (off & ump->umq2_bmask); | |
1043 | c->dq->dq2_lblkno = lblkno; | 1043 | c->dq->dq2_lblkno = lblkno; | |
1044 | c->dq->dq2_blkoff = blkoff; | 1044 | c->dq->dq2_blkoff = blkoff; | |
1045 | return Q2WL_ABORT; | 1045 | return Q2WL_ABORT; | |
1046 | } | 1046 | } | |
1047 | return 0; | 1047 | return 0; | |
1048 | } | 1048 | } | |
1049 | 1049 | |||
1050 | int | 1050 | int | |
1051 | dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, | 1051 | dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, | |
1052 | struct dquot *dq) | 1052 | struct dquot *dq) | |
1053 | { | 1053 | { | |
1054 | struct buf *bp; | 1054 | struct buf *bp; | |
1055 | struct quota2_header *q2h; | 1055 | struct quota2_header *q2h; | |
1056 | int error; | 1056 | int error; | |
1057 | daddr_t offset; | 1057 | daddr_t offset; | |
1058 | u_long hash_mask; | 1058 | u_long hash_mask; | |
1059 | struct dq2get_callback c = { | 1059 | struct dq2get_callback c = { | |
1060 | .id = id, | 1060 | .id = id, | |
1061 | .dq = dq | 1061 | .dq = dq | |
1062 | }; | 1062 | }; | |
1063 | 1063 | |||
1064 | KASSERT(mutex_owned(&dq->dq_interlock)); | 1064 | KASSERT(mutex_owned(&dq->dq_interlock)); | |
1065 | mutex_enter(&dqlock); | 1065 | mutex_enter(&dqlock); | |
1066 | error = getq2h(ump, type, &bp, &q2h, 0); | 1066 | error = getq2h(ump, type, &bp, &q2h, 0); | |
1067 | if (error) | 1067 | if (error) | |
1068 | goto out_mutex; | 1068 | goto out_mutex; | |
1069 | /* look for our entry */ | 1069 | /* look for our entry */ | |
1070 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | 1070 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | |
1071 | offset = q2h->q2h_entries[id & hash_mask]; | 1071 | offset = q2h->q2h_entries[id & hash_mask]; | |
1072 | error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, | 1072 | error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, | |
1073 | dq2get_callback); | 1073 | dq2get_callback); | |
1074 | brelse(bp, 0); | 1074 | brelse(bp, 0); | |
1075 | out_mutex: | 1075 | out_mutex: | |
1076 | mutex_exit(&dqlock); | 1076 | mutex_exit(&dqlock); | |
1077 | return error; | 1077 | return error; | |
1078 | } | 1078 | } | |
1079 | 1079 | |||
1080 | int | 1080 | int | |
1081 | dq2sync(struct vnode *vp, struct dquot *dq) | 1081 | dq2sync(struct vnode *vp, struct dquot *dq) | |
1082 | { | 1082 | { | |
1083 | return 0; | 1083 | return 0; | |
1084 | } | 1084 | } |