Add QUOTACTL_CURSORSKIPIDTYPE, QUOTACTL_CURSORATEND, QUOTACTL_CURSORREWIND. This change requires a kernel version bump.diff -r1.28 -r1.29 src/sys/kern/vfs_quotactl.c
(dholland)
--- src/sys/kern/vfs_quotactl.c 2012/01/29 07:08:58 1.28
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 07:09:52 1.29
@@ -1,801 +1,801 @@ | @@ -1,801 +1,801 @@ | |||
1 | /* $NetBSD: vfs_quotactl.c,v 1.28 2012/01/29 07:08:58 dholland Exp $ */ | 1 | /* $NetBSD: vfs_quotactl.c,v 1.29 2012/01/29 07:09:52 dholland Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1991, 1993, 1994 | 4 | * Copyright (c) 1991, 1993, 1994 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * (c) UNIX System Laboratories, Inc. | 6 | * (c) UNIX System Laboratories, Inc. | |
7 | * All or some portions of this file are derived from material licensed | 7 | * All or some portions of this file are derived from material licensed | |
8 | * to the University of California by American Telephone and Telegraph | 8 | * to the University of California by American Telephone and Telegraph | |
9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | 9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
10 | * the permission of UNIX System Laboratories, Inc. | 10 | * the permission of UNIX System Laboratories, Inc. | |
11 | * | 11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | 12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | 13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | 14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | 15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | 16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | 17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | 18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | 19 | * documentation and/or other materials provided with the distribution. | |
20 | * 3. Neither the name of the University nor the names of its contributors | 20 | * 3. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | 21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | 22 | * without specific prior written permission. | |
23 | * | 23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | 34 | * SUCH DAMAGE. | |
35 | * | 35 | * | |
36 | * @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 | 36 | * @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 | |
37 | * From NetBSD: ufs_vfsops.c,v 1.42 2011/03/24 17:05:46 bouyer Exp | 37 | * From NetBSD: ufs_vfsops.c,v 1.42 2011/03/24 17:05:46 bouyer Exp | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | /* | 40 | /* | |
41 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | 41 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | |
42 | * The Regents of the University of California. All rights reserved. | 42 | * The Regents of the University of California. All rights reserved. | |
43 | * | 43 | * | |
44 | * This code is derived from software contributed to Berkeley by | 44 | * This code is derived from software contributed to Berkeley by | |
45 | * Robert Elz at The University of Melbourne. | 45 | * Robert Elz at The University of Melbourne. | |
46 | * | 46 | * | |
47 | * Redistribution and use in source and binary forms, with or without | 47 | * Redistribution and use in source and binary forms, with or without | |
48 | * modification, are permitted provided that the following conditions | 48 | * modification, are permitted provided that the following conditions | |
49 | * are met: | 49 | * are met: | |
50 | * 1. Redistributions of source code must retain the above copyright | 50 | * 1. Redistributions of source code must retain the above copyright | |
51 | * notice, this list of conditions and the following disclaimer. | 51 | * notice, this list of conditions and the following disclaimer. | |
52 | * 2. Redistributions in binary form must reproduce the above copyright | 52 | * 2. Redistributions in binary form must reproduce the above copyright | |
53 | * notice, this list of conditions and the following disclaimer in the | 53 | * notice, this list of conditions and the following disclaimer in the | |
54 | * documentation and/or other materials provided with the distribution. | 54 | * documentation and/or other materials provided with the distribution. | |
55 | * 3. Neither the name of the University nor the names of its contributors | 55 | * 3. Neither the name of the University nor the names of its contributors | |
56 | * may be used to endorse or promote products derived from this software | 56 | * may be used to endorse or promote products derived from this software | |
57 | * without specific prior written permission. | 57 | * without specific prior written permission. | |
58 | * | 58 | * | |
59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
69 | * SUCH DAMAGE. | 69 | * SUCH DAMAGE. | |
70 | * | 70 | * | |
71 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | 71 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | |
72 | * From NetBSD: ufs_quota.c,v 1.70 2011/03/24 17:05:46 bouyer Exp | 72 | * From NetBSD: ufs_quota.c,v 1.70 2011/03/24 17:05:46 bouyer Exp | |
73 | */ | 73 | */ | |
74 | 74 | |||
75 | /* | 75 | /* | |
76 | * Note that both of the copyrights above are moderately spurious; | 76 | * Note that both of the copyrights above are moderately spurious; | |
77 | * this code should almost certainly have the Copyright 2010 Manuel | 77 | * this code should almost certainly have the Copyright 2010 Manuel | |
78 | * Bouyer notice and license found in e.g. sys/ufs/ufs/quota2_subr.c. | 78 | * Bouyer notice and license found in e.g. sys/ufs/ufs/quota2_subr.c. | |
79 | * However, they're what was on the files this code was sliced out of. | 79 | * However, they're what was on the files this code was sliced out of. | |
80 | */ | 80 | */ | |
81 | 81 | |||
82 | #include <sys/cdefs.h> | 82 | #include <sys/cdefs.h> | |
83 | __KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.28 2012/01/29 07:08:58 dholland Exp $"); | 83 | __KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.29 2012/01/29 07:09:52 dholland Exp $"); | |
84 | 84 | |||
85 | #include <sys/malloc.h> /* XXX: temporary */ | 85 | #include <sys/malloc.h> /* XXX: temporary */ | |
86 | #include <sys/mount.h> | 86 | #include <sys/mount.h> | |
87 | #include <sys/quota.h> | 87 | #include <sys/quota.h> | |
88 | #include <sys/quotactl.h> | 88 | #include <sys/quotactl.h> | |
89 | #include <quota/quotaprop.h> | 89 | #include <quota/quotaprop.h> | |
90 | 90 | |||
91 | static int | 91 | static int | |
92 | vfs_quotactl_getversion(struct mount *mp, | 92 | vfs_quotactl_getversion(struct mount *mp, | |
93 | prop_dictionary_t cmddict, int q2type, | 93 | prop_dictionary_t cmddict, int q2type, | |
94 | prop_array_t datas) | 94 | prop_array_t datas) | |
95 | { | 95 | { | |
96 | prop_array_t replies; | 96 | prop_array_t replies; | |
97 | prop_dictionary_t data; | 97 | prop_dictionary_t data; | |
98 | int q2version; | 98 | int q2version; | |
99 | struct vfs_quotactl_args args; | 99 | struct vfs_quotactl_args args; | |
100 | int error; | 100 | int error; | |
101 | 101 | |||
102 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 102 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
103 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 103 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
104 | 104 | |||
105 | args.qc_type = QCT_GETVERSION; | 105 | args.qc_type = QCT_GETVERSION; | |
106 | args.u.getversion.qc_version_ret = &q2version; | 106 | args.u.getversion.qc_version_ret = &q2version; | |
107 | error = VFS_QUOTACTL(mp, QUOTACTL_GETVERSION, &args); | 107 | error = VFS_QUOTACTL(mp, QUOTACTL_GETVERSION, &args); | |
108 | if (error) { | 108 | if (error) { | |
109 | return error; | 109 | return error; | |
110 | } | 110 | } | |
111 | 111 | |||
112 | data = prop_dictionary_create(); | 112 | data = prop_dictionary_create(); | |
113 | if (data == NULL) { | 113 | if (data == NULL) { | |
114 | return ENOMEM; | 114 | return ENOMEM; | |
115 | } | 115 | } | |
116 | 116 | |||
117 | if (!prop_dictionary_set_int8(data, "version", q2version)) { | 117 | if (!prop_dictionary_set_int8(data, "version", q2version)) { | |
118 | prop_object_release(data); | 118 | prop_object_release(data); | |
119 | return ENOMEM; | 119 | return ENOMEM; | |
120 | } | 120 | } | |
121 | 121 | |||
122 | replies = prop_array_create(); | 122 | replies = prop_array_create(); | |
123 | if (replies == NULL) { | 123 | if (replies == NULL) { | |
124 | prop_object_release(data); | 124 | prop_object_release(data); | |
125 | return ENOMEM; | 125 | return ENOMEM; | |
126 | } | 126 | } | |
127 | 127 | |||
128 | if (!prop_array_add_and_rel(replies, data)) { | 128 | if (!prop_array_add_and_rel(replies, data)) { | |
129 | prop_object_release(data); | 129 | prop_object_release(data); | |
130 | prop_object_release(replies); | 130 | prop_object_release(replies); | |
131 | return ENOMEM; | 131 | return ENOMEM; | |
132 | } | 132 | } | |
133 | 133 | |||
134 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 134 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
135 | prop_object_release(replies); | 135 | prop_object_release(replies); | |
136 | return ENOMEM; | 136 | return ENOMEM; | |
137 | } | 137 | } | |
138 | 138 | |||
139 | return error; | 139 | return error; | |
140 | } | 140 | } | |
141 | 141 | |||
142 | static int | 142 | static int | |
143 | vfs_quotactl_quotaon(struct mount *mp, | 143 | vfs_quotactl_quotaon(struct mount *mp, | |
144 | prop_dictionary_t cmddict, int q2type, | 144 | prop_dictionary_t cmddict, int q2type, | |
145 | prop_array_t datas) | 145 | prop_array_t datas) | |
146 | { | 146 | { | |
147 | struct vfs_quotactl_args args; | 147 | struct vfs_quotactl_args args; | |
148 | 148 | |||
149 | args.qc_type = QCT_PROPLIB; | 149 | args.qc_type = QCT_PROPLIB; | |
150 | args.u.proplib.qc_cmddict = cmddict; | 150 | args.u.proplib.qc_cmddict = cmddict; | |
151 | args.u.proplib.qc_q2type = q2type; | 151 | args.u.proplib.qc_q2type = q2type; | |
152 | args.u.proplib.qc_datas = datas; | 152 | args.u.proplib.qc_datas = datas; | |
153 | return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args); | 153 | return VFS_QUOTACTL(mp, QUOTACTL_QUOTAON, &args); | |
154 | } | 154 | } | |
155 | 155 | |||
156 | static int | 156 | static int | |
157 | vfs_quotactl_quotaoff(struct mount *mp, | 157 | vfs_quotactl_quotaoff(struct mount *mp, | |
158 | prop_dictionary_t cmddict, int q2type, | 158 | prop_dictionary_t cmddict, int q2type, | |
159 | prop_array_t datas) | 159 | prop_array_t datas) | |
160 | { | 160 | { | |
161 | struct vfs_quotactl_args args; | 161 | struct vfs_quotactl_args args; | |
162 | 162 | |||
163 | args.qc_type = QCT_PROPLIB; | 163 | args.qc_type = QCT_PROPLIB; | |
164 | args.u.proplib.qc_cmddict = cmddict; | 164 | args.u.proplib.qc_cmddict = cmddict; | |
165 | args.u.proplib.qc_q2type = q2type; | 165 | args.u.proplib.qc_q2type = q2type; | |
166 | args.u.proplib.qc_datas = datas; | 166 | args.u.proplib.qc_datas = datas; | |
167 | return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args); | 167 | return VFS_QUOTACTL(mp, QUOTACTL_QUOTAOFF, &args); | |
168 | } | 168 | } | |
169 | 169 | |||
170 | static int | 170 | static int | |
171 | vfs_quotactl_get_addreply(const struct quotakey *qk, | 171 | vfs_quotactl_get_addreply(const struct quotakey *qk, | |
172 | const struct quotaval *blocks, | 172 | const struct quotaval *blocks, | |
173 | const struct quotaval *files, | 173 | const struct quotaval *files, | |
174 | prop_array_t replies) | 174 | prop_array_t replies) | |
175 | { | 175 | { | |
176 | prop_dictionary_t dict; | 176 | prop_dictionary_t dict; | |
177 | id_t id; | 177 | id_t id; | |
178 | int defaultq; | 178 | int defaultq; | |
179 | uint64_t *valuesp[QUOTA_NLIMITS]; | 179 | uint64_t *valuesp[QUOTA_NLIMITS]; | |
180 | 180 | |||
181 | /* XXX illegal casts */ | 181 | /* XXX illegal casts */ | |
182 | valuesp[QUOTA_LIMIT_BLOCK] = (void *)(intptr_t)&blocks->qv_hardlimit; | 182 | valuesp[QUOTA_LIMIT_BLOCK] = (void *)(intptr_t)&blocks->qv_hardlimit; | |
183 | valuesp[QUOTA_LIMIT_FILE] = (void *)(intptr_t)&files->qv_hardlimit; | 183 | valuesp[QUOTA_LIMIT_FILE] = (void *)(intptr_t)&files->qv_hardlimit; | |
184 | 184 | |||
185 | if (qk->qk_id == QUOTA_DEFAULTID) { | 185 | if (qk->qk_id == QUOTA_DEFAULTID) { | |
186 | id = 0; | 186 | id = 0; | |
187 | defaultq = 1; | 187 | defaultq = 1; | |
188 | } else { | 188 | } else { | |
189 | id = qk->qk_id; | 189 | id = qk->qk_id; | |
190 | defaultq = 0; | 190 | defaultq = 0; | |
191 | } | 191 | } | |
192 | 192 | |||
193 | dict = quota64toprop(id, defaultq, valuesp, | 193 | dict = quota64toprop(id, defaultq, valuesp, | |
194 | ufs_quota_entry_names, UFS_QUOTA_NENTRIES, | 194 | ufs_quota_entry_names, UFS_QUOTA_NENTRIES, | |
195 | ufs_quota_limit_names, QUOTA_NLIMITS); | 195 | ufs_quota_limit_names, QUOTA_NLIMITS); | |
196 | if (dict == NULL) | 196 | if (dict == NULL) | |
197 | return ENOMEM; | 197 | return ENOMEM; | |
198 | if (!prop_array_add_and_rel(replies, dict)) { | 198 | if (!prop_array_add_and_rel(replies, dict)) { | |
199 | prop_object_release(dict); | 199 | prop_object_release(dict); | |
200 | return ENOMEM; | 200 | return ENOMEM; | |
201 | } | 201 | } | |
202 | 202 | |||
203 | return 0; | 203 | return 0; | |
204 | } | 204 | } | |
205 | 205 | |||
206 | static int | 206 | static int | |
207 | vfs_quotactl_get(struct mount *mp, | 207 | vfs_quotactl_get(struct mount *mp, | |
208 | prop_dictionary_t cmddict, int idtype, | 208 | prop_dictionary_t cmddict, int idtype, | |
209 | prop_array_t datas) | 209 | prop_array_t datas) | |
210 | { | 210 | { | |
211 | prop_object_iterator_t iter; | 211 | prop_object_iterator_t iter; | |
212 | prop_dictionary_t data; | 212 | prop_dictionary_t data; | |
213 | prop_array_t replies; | 213 | prop_array_t replies; | |
214 | uint32_t id; | 214 | uint32_t id; | |
215 | const char *idstr; | 215 | const char *idstr; | |
216 | struct vfs_quotactl_args args; | 216 | struct vfs_quotactl_args args; | |
217 | struct quotakey qk; | 217 | struct quotakey qk; | |
218 | struct quotaval blocks, files; | 218 | struct quotaval blocks, files; | |
219 | int error; | 219 | int error; | |
220 | 220 | |||
221 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 221 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
222 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 222 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
223 | 223 | |||
224 | replies = prop_array_create(); | 224 | replies = prop_array_create(); | |
225 | if (replies == NULL) { | 225 | if (replies == NULL) { | |
226 | return ENOMEM; | 226 | return ENOMEM; | |
227 | } | 227 | } | |
228 | 228 | |||
229 | iter = prop_array_iterator(datas); | 229 | iter = prop_array_iterator(datas); | |
230 | if (iter == NULL) { | 230 | if (iter == NULL) { | |
231 | prop_object_release(replies); | 231 | prop_object_release(replies); | |
232 | return ENOMEM; | 232 | return ENOMEM; | |
233 | } | 233 | } | |
234 | 234 | |||
235 | while ((data = prop_object_iterator_next(iter)) != NULL) { | 235 | while ((data = prop_object_iterator_next(iter)) != NULL) { | |
236 | qk.qk_idtype = idtype; | 236 | qk.qk_idtype = idtype; | |
237 | 237 | |||
238 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | 238 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | |
239 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | 239 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | |
240 | &idstr)) | 240 | &idstr)) | |
241 | continue; | 241 | continue; | |
242 | if (strcmp(idstr, "default")) { | 242 | if (strcmp(idstr, "default")) { | |
243 | error = EINVAL; | 243 | error = EINVAL; | |
244 | goto fail; | 244 | goto fail; | |
245 | } | 245 | } | |
246 | qk.qk_id = QUOTA_DEFAULTID; | 246 | qk.qk_id = QUOTA_DEFAULTID; | |
247 | } else { | 247 | } else { | |
248 | qk.qk_id = id; | 248 | qk.qk_id = id; | |
249 | } | 249 | } | |
250 | 250 | |||
251 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | 251 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | |
252 | 252 | |||
253 | args.qc_type = QCT_GET; | 253 | args.qc_type = QCT_GET; | |
254 | args.u.get.qc_key = &qk; | 254 | args.u.get.qc_key = &qk; | |
255 | args.u.get.qc_ret = &blocks; | 255 | args.u.get.qc_ret = &blocks; | |
256 | error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); | 256 | error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); | |
257 | if (error == EPERM) { | 257 | if (error == EPERM) { | |
258 | /* XXX does this make sense? */ | 258 | /* XXX does this make sense? */ | |
259 | continue; | 259 | continue; | |
260 | } else if (error == ENOENT) { | 260 | } else if (error == ENOENT) { | |
261 | /* XXX does *this* make sense? */ | 261 | /* XXX does *this* make sense? */ | |
262 | continue; | 262 | continue; | |
263 | } else if (error) { | 263 | } else if (error) { | |
264 | goto fail; | 264 | goto fail; | |
265 | } | 265 | } | |
266 | 266 | |||
267 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | 267 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | |
268 | 268 | |||
269 | args.qc_type = QCT_GET; | 269 | args.qc_type = QCT_GET; | |
270 | args.u.get.qc_key = &qk; | 270 | args.u.get.qc_key = &qk; | |
271 | args.u.get.qc_ret = &files; | 271 | args.u.get.qc_ret = &files; | |
272 | error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); | 272 | error = VFS_QUOTACTL(mp, QUOTACTL_GET, &args); | |
273 | if (error == EPERM) { | 273 | if (error == EPERM) { | |
274 | /* XXX does this make sense? */ | 274 | /* XXX does this make sense? */ | |
275 | continue; | 275 | continue; | |
276 | } else if (error == ENOENT) { | 276 | } else if (error == ENOENT) { | |
277 | /* XXX does *this* make sense? */ | 277 | /* XXX does *this* make sense? */ | |
278 | continue; | 278 | continue; | |
279 | } else if (error) { | 279 | } else if (error) { | |
280 | goto fail; | 280 | goto fail; | |
281 | } | 281 | } | |
282 | 282 | |||
283 | error = vfs_quotactl_get_addreply(&qk, &blocks, &files, | 283 | error = vfs_quotactl_get_addreply(&qk, &blocks, &files, | |
284 | replies); | 284 | replies); | |
285 | } | 285 | } | |
286 | 286 | |||
287 | prop_object_iterator_release(iter); | 287 | prop_object_iterator_release(iter); | |
288 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 288 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
289 | error = ENOMEM; | 289 | error = ENOMEM; | |
290 | } else { | 290 | } else { | |
291 | error = 0; | 291 | error = 0; | |
292 | } | 292 | } | |
293 | 293 | |||
294 | return error; | 294 | return error; | |
295 | 295 | |||
296 | fail: | 296 | fail: | |
297 | prop_object_iterator_release(iter); | 297 | prop_object_iterator_release(iter); | |
298 | prop_object_release(replies); | 298 | prop_object_release(replies); | |
299 | return error; | 299 | return error; | |
300 | } | 300 | } | |
301 | 301 | |||
302 | static int | 302 | static int | |
303 | vfs_quotactl_put_extractinfo(prop_dictionary_t data, | 303 | vfs_quotactl_put_extractinfo(prop_dictionary_t data, | |
304 | struct quotaval *blocks, struct quotaval *files) | 304 | struct quotaval *blocks, struct quotaval *files) | |
305 | { | 305 | { | |
306 | /* | 306 | /* | |
307 | * So, the way proptoquota64 works is that you pass it an | 307 | * So, the way proptoquota64 works is that you pass it an | |
308 | * array of pointers to uint64. Each of these pointers is | 308 | * array of pointers to uint64. Each of these pointers is | |
309 | * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This | 309 | * supposed to point to 5 (UFS_QUOTA_NENTRIES) uint64s. This | |
310 | * array of pointers is the second argument. The third and | 310 | * array of pointers is the second argument. The third and | |
311 | * forth argument are the names of the five values to extract, | 311 | * forth argument are the names of the five values to extract, | |
312 | * and UFS_QUOTA_NENTRIES. The last two arguments are the | 312 | * and UFS_QUOTA_NENTRIES. The last two arguments are the | |
313 | * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK, | 313 | * names assocated with the pointers (QUOTATYPE_LDICT_BLOCK, | |
314 | * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of | 314 | * QUOTADICT_LTYPE_FILE) and the number of pointers. Most of | |
315 | * the existing code was unsafely casting struct quotaval | 315 | * the existing code was unsafely casting struct quotaval | |
316 | * (formerly struct ufs_quota_entry) to (uint64_t *) and using | 316 | * (formerly struct ufs_quota_entry) to (uint64_t *) and using | |
317 | * that as the block of 5 uint64s. Or worse, pointing to | 317 | * that as the block of 5 uint64s. Or worse, pointing to | |
318 | * subregions of that and reducing the number of uint64s to | 318 | * subregions of that and reducing the number of uint64s to | |
319 | * pull "adjacent" values. Demons fly out of your nose! | 319 | * pull "adjacent" values. Demons fly out of your nose! | |
320 | */ | 320 | */ | |
321 | 321 | |||
322 | uint64_t bvals[UFS_QUOTA_NENTRIES]; | 322 | uint64_t bvals[UFS_QUOTA_NENTRIES]; | |
323 | uint64_t fvals[UFS_QUOTA_NENTRIES]; | 323 | uint64_t fvals[UFS_QUOTA_NENTRIES]; | |
324 | uint64_t *valptrs[QUOTA_NLIMITS]; | 324 | uint64_t *valptrs[QUOTA_NLIMITS]; | |
325 | int error; | 325 | int error; | |
326 | 326 | |||
327 | valptrs[QUOTA_LIMIT_BLOCK] = bvals; | 327 | valptrs[QUOTA_LIMIT_BLOCK] = bvals; | |
328 | valptrs[QUOTA_LIMIT_FILE] = fvals; | 328 | valptrs[QUOTA_LIMIT_FILE] = fvals; | |
329 | error = proptoquota64(data, valptrs, | 329 | error = proptoquota64(data, valptrs, | |
330 | ufs_quota_entry_names, UFS_QUOTA_NENTRIES, | 330 | ufs_quota_entry_names, UFS_QUOTA_NENTRIES, | |
331 | ufs_quota_limit_names, QUOTA_NLIMITS); | 331 | ufs_quota_limit_names, QUOTA_NLIMITS); | |
332 | if (error) { | 332 | if (error) { | |
333 | return error; | 333 | return error; | |
334 | } | 334 | } | |
335 | 335 | |||
336 | /* | 336 | /* | |
337 | * There are no symbolic constants for these indexes! | 337 | * There are no symbolic constants for these indexes! | |
338 | */ | 338 | */ | |
339 | 339 | |||
340 | blocks->qv_hardlimit = bvals[0]; | 340 | blocks->qv_hardlimit = bvals[0]; | |
341 | blocks->qv_softlimit = bvals[1]; | 341 | blocks->qv_softlimit = bvals[1]; | |
342 | blocks->qv_usage = bvals[2]; | 342 | blocks->qv_usage = bvals[2]; | |
343 | blocks->qv_expiretime = bvals[3]; | 343 | blocks->qv_expiretime = bvals[3]; | |
344 | blocks->qv_grace = bvals[4]; | 344 | blocks->qv_grace = bvals[4]; | |
345 | files->qv_hardlimit = fvals[0]; | 345 | files->qv_hardlimit = fvals[0]; | |
346 | files->qv_softlimit = fvals[1]; | 346 | files->qv_softlimit = fvals[1]; | |
347 | files->qv_usage = fvals[2]; | 347 | files->qv_usage = fvals[2]; | |
348 | files->qv_expiretime = fvals[3]; | 348 | files->qv_expiretime = fvals[3]; | |
349 | files->qv_grace = fvals[4]; | 349 | files->qv_grace = fvals[4]; | |
350 | 350 | |||
351 | return 0; | 351 | return 0; | |
352 | } | 352 | } | |
353 | 353 | |||
354 | static int | 354 | static int | |
355 | vfs_quotactl_put(struct mount *mp, | 355 | vfs_quotactl_put(struct mount *mp, | |
356 | prop_dictionary_t cmddict, int q2type, | 356 | prop_dictionary_t cmddict, int q2type, | |
357 | prop_array_t datas) | 357 | prop_array_t datas) | |
358 | { | 358 | { | |
359 | prop_array_t replies; | 359 | prop_array_t replies; | |
360 | prop_object_iterator_t iter; | 360 | prop_object_iterator_t iter; | |
361 | prop_dictionary_t data; | 361 | prop_dictionary_t data; | |
362 | int defaultq; | 362 | int defaultq; | |
363 | uint32_t id; | 363 | uint32_t id; | |
364 | const char *idstr; | 364 | const char *idstr; | |
365 | struct quotakey qk; | 365 | struct quotakey qk; | |
366 | struct quotaval blocks, files; | 366 | struct quotaval blocks, files; | |
367 | struct vfs_quotactl_args args; | 367 | struct vfs_quotactl_args args; | |
368 | int error; | 368 | int error; | |
369 | 369 | |||
370 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 370 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
371 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 371 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
372 | 372 | |||
373 | replies = prop_array_create(); | 373 | replies = prop_array_create(); | |
374 | if (replies == NULL) | 374 | if (replies == NULL) | |
375 | return ENOMEM; | 375 | return ENOMEM; | |
376 | 376 | |||
377 | iter = prop_array_iterator(datas); | 377 | iter = prop_array_iterator(datas); | |
378 | if (iter == NULL) { | 378 | if (iter == NULL) { | |
379 | prop_object_release(replies); | 379 | prop_object_release(replies); | |
380 | return ENOMEM; | 380 | return ENOMEM; | |
381 | } | 381 | } | |
382 | 382 | |||
383 | while ((data = prop_object_iterator_next(iter)) != NULL) { | 383 | while ((data = prop_object_iterator_next(iter)) != NULL) { | |
384 | 384 | |||
385 | KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY); | 385 | KASSERT(prop_object_type(data) == PROP_TYPE_DICTIONARY); | |
386 | 386 | |||
387 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | 387 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | |
388 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | 388 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | |
389 | &idstr)) | 389 | &idstr)) | |
390 | continue; | 390 | continue; | |
391 | if (strcmp(idstr, "default")) | 391 | if (strcmp(idstr, "default")) | |
392 | continue; | 392 | continue; | |
393 | id = 0; | 393 | id = 0; | |
394 | defaultq = 1; | 394 | defaultq = 1; | |
395 | } else { | 395 | } else { | |
396 | defaultq = 0; | 396 | defaultq = 0; | |
397 | } | 397 | } | |
398 | 398 | |||
399 | error = vfs_quotactl_put_extractinfo(data, &blocks, &files); | 399 | error = vfs_quotactl_put_extractinfo(data, &blocks, &files); | |
400 | if (error) { | 400 | if (error) { | |
401 | goto err; | 401 | goto err; | |
402 | } | 402 | } | |
403 | 403 | |||
404 | qk.qk_idtype = q2type; | 404 | qk.qk_idtype = q2type; | |
405 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | 405 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | |
406 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | 406 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | |
407 | 407 | |||
408 | args.qc_type = QCT_PUT; | 408 | args.qc_type = QCT_PUT; | |
409 | args.u.put.qc_key = &qk; | 409 | args.u.put.qc_key = &qk; | |
410 | args.u.put.qc_val = &blocks; | 410 | args.u.put.qc_val = &blocks; | |
411 | error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); | 411 | error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); | |
412 | if (error) { | 412 | if (error) { | |
413 | goto err; | 413 | goto err; | |
414 | } | 414 | } | |
415 | 415 | |||
416 | qk.qk_idtype = q2type; | 416 | qk.qk_idtype = q2type; | |
417 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | 417 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | |
418 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | 418 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | |
419 | 419 | |||
420 | args.qc_type = QCT_PUT; | 420 | args.qc_type = QCT_PUT; | |
421 | args.u.put.qc_key = &qk; | 421 | args.u.put.qc_key = &qk; | |
422 | args.u.put.qc_val = &files; | 422 | args.u.put.qc_val = &files; | |
423 | error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); | 423 | error = VFS_QUOTACTL(mp, QUOTACTL_PUT, &args); | |
424 | if (error) { | 424 | if (error) { | |
425 | goto err; | 425 | goto err; | |
426 | } | 426 | } | |
427 | } | 427 | } | |
428 | prop_object_iterator_release(iter); | 428 | prop_object_iterator_release(iter); | |
429 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 429 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
430 | error = ENOMEM; | 430 | error = ENOMEM; | |
431 | } else { | 431 | } else { | |
432 | error = 0; | 432 | error = 0; | |
433 | } | 433 | } | |
434 | return error; | 434 | return error; | |
435 | err: | 435 | err: | |
436 | prop_object_iterator_release(iter); | 436 | prop_object_iterator_release(iter); | |
437 | prop_object_release(replies); | 437 | prop_object_release(replies); | |
438 | return error; | 438 | return error; | |
439 | } | 439 | } | |
440 | 440 | |||
441 | static prop_dictionary_t | 441 | static prop_dictionary_t | |
442 | vfs_quotactl_getall_makereply(const struct quotakey *key) | 442 | vfs_quotactl_getall_makereply(const struct quotakey *key) | |
443 | { | 443 | { | |
444 | prop_dictionary_t dict; | 444 | prop_dictionary_t dict; | |
445 | id_t id; | 445 | id_t id; | |
446 | int defaultq; | 446 | int defaultq; | |
447 | 447 | |||
448 | dict = prop_dictionary_create(); | 448 | dict = prop_dictionary_create(); | |
449 | if (dict == NULL) | 449 | if (dict == NULL) | |
450 | return NULL; | 450 | return NULL; | |
451 | 451 | |||
452 | id = key->qk_id; | 452 | id = key->qk_id; | |
453 | if (id == QUOTA_DEFAULTID) { | 453 | if (id == QUOTA_DEFAULTID) { | |
454 | id = 0; | 454 | id = 0; | |
455 | defaultq = 1; | 455 | defaultq = 1; | |
456 | } else { | 456 | } else { | |
457 | defaultq = 0; | 457 | defaultq = 0; | |
458 | } | 458 | } | |
459 | 459 | |||
460 | if (defaultq) { | 460 | if (defaultq) { | |
461 | if (!prop_dictionary_set_cstring_nocopy(dict, "id", | 461 | if (!prop_dictionary_set_cstring_nocopy(dict, "id", | |
462 | "default")) { | 462 | "default")) { | |
463 | goto err; | 463 | goto err; | |
464 | } | 464 | } | |
465 | } else { | 465 | } else { | |
466 | if (!prop_dictionary_set_uint32(dict, "id", id)) { | 466 | if (!prop_dictionary_set_uint32(dict, "id", id)) { | |
467 | goto err; | 467 | goto err; | |
468 | } | 468 | } | |
469 | } | 469 | } | |
470 | 470 | |||
471 | return dict; | 471 | return dict; | |
472 | 472 | |||
473 | err: | 473 | err: | |
474 | prop_object_release(dict); | 474 | prop_object_release(dict); | |
475 | return NULL; | 475 | return NULL; | |
476 | } | 476 | } | |
477 | 477 | |||
478 | static int | 478 | static int | |
479 | vfs_quotactl_getall_addreply(prop_dictionary_t thisreply, | 479 | vfs_quotactl_getall_addreply(prop_dictionary_t thisreply, | |
480 | const struct quotakey *key, const struct quotaval *val) | 480 | const struct quotakey *key, const struct quotaval *val) | |
481 | { | 481 | { | |
482 | #define INITQVNAMES_ALL { \ | 482 | #define INITQVNAMES_ALL { \ | |
483 | QUOTADICT_LIMIT_HARD, \ | 483 | QUOTADICT_LIMIT_HARD, \ | |
484 | QUOTADICT_LIMIT_SOFT, \ | 484 | QUOTADICT_LIMIT_SOFT, \ | |
485 | QUOTADICT_LIMIT_USAGE, \ | 485 | QUOTADICT_LIMIT_USAGE, \ | |
486 | QUOTADICT_LIMIT_ETIME, \ | 486 | QUOTADICT_LIMIT_ETIME, \ | |
487 | QUOTADICT_LIMIT_GTIME \ | 487 | QUOTADICT_LIMIT_GTIME \ | |
488 | } | 488 | } | |
489 | #define N_QV 5 | 489 | #define N_QV 5 | |
490 | 490 | |||
491 | const char *val_names[] = INITQVNAMES_ALL; | 491 | const char *val_names[] = INITQVNAMES_ALL; | |
492 | uint64_t vals[N_QV]; | 492 | uint64_t vals[N_QV]; | |
493 | prop_dictionary_t dict2; | 493 | prop_dictionary_t dict2; | |
494 | const char *objtypename; | 494 | const char *objtypename; | |
495 | 495 | |||
496 | switch (key->qk_objtype) { | 496 | switch (key->qk_objtype) { | |
497 | case QUOTA_OBJTYPE_BLOCKS: | 497 | case QUOTA_OBJTYPE_BLOCKS: | |
498 | objtypename = QUOTADICT_LTYPE_BLOCK; | 498 | objtypename = QUOTADICT_LTYPE_BLOCK; | |
499 | break; | 499 | break; | |
500 | case QUOTA_OBJTYPE_FILES: | 500 | case QUOTA_OBJTYPE_FILES: | |
501 | objtypename = QUOTADICT_LTYPE_FILE; | 501 | objtypename = QUOTADICT_LTYPE_FILE; | |
502 | break; | 502 | break; | |
503 | default: | 503 | default: | |
504 | return EINVAL; | 504 | return EINVAL; | |
505 | } | 505 | } | |
506 | 506 | |||
507 | vals[0] = val->qv_hardlimit; | 507 | vals[0] = val->qv_hardlimit; | |
508 | vals[1] = val->qv_softlimit; | 508 | vals[1] = val->qv_softlimit; | |
509 | vals[2] = val->qv_usage; | 509 | vals[2] = val->qv_usage; | |
510 | vals[3] = val->qv_expiretime; | 510 | vals[3] = val->qv_expiretime; | |
511 | vals[4] = val->qv_grace; | 511 | vals[4] = val->qv_grace; | |
512 | dict2 = limits64toprop(vals, val_names, N_QV); | 512 | dict2 = limits64toprop(vals, val_names, N_QV); | |
513 | if (dict2 == NULL) | 513 | if (dict2 == NULL) | |
514 | return ENOMEM; | 514 | return ENOMEM; | |
515 | 515 | |||
516 | if (!prop_dictionary_set_and_rel(thisreply, objtypename, dict2)) | 516 | if (!prop_dictionary_set_and_rel(thisreply, objtypename, dict2)) | |
517 | return ENOMEM; | 517 | return ENOMEM; | |
518 | 518 | |||
519 | return 0; | 519 | return 0; | |
520 | } | 520 | } | |
521 | 521 | |||
522 | static int | 522 | static int | |
523 | vfs_quotactl_getall(struct mount *mp, | 523 | vfs_quotactl_getall(struct mount *mp, | |
524 | prop_dictionary_t cmddict, int q2type, | 524 | prop_dictionary_t cmddict, int q2type, | |
525 | prop_array_t datas) | 525 | prop_array_t datas) | |
526 | { | 526 | { | |
527 | struct quotakcursor cursor; | 527 | struct quotakcursor cursor; | |
528 | struct quotakey *keys; | 528 | struct quotakey *keys; | |
529 | struct quotaval *vals; | 529 | struct quotaval *vals; | |
530 | unsigned loopmax = 8; | 530 | unsigned loopmax = 8; | |
531 | unsigned loopnum; | 531 | unsigned loopnum; | |
532 | struct vfs_quotactl_args args; | 532 | struct vfs_quotactl_args args; | |
533 | prop_array_t replies; | 533 | prop_array_t replies; | |
534 | struct quotakey *key; | 534 | struct quotakey *key; | |
535 | struct quotaval *val; | 535 | struct quotaval *val; | |
536 | id_t lastid; | 536 | id_t lastid; | |
537 | prop_dictionary_t thisreply; | 537 | prop_dictionary_t thisreply; | |
538 | unsigned i; | 538 | unsigned i; | |
539 | int error, error2; | 539 | int error, error2; | |
540 | 540 | |||
541 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 541 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
542 | 542 | |||
543 | args.qc_type = QCT_CURSOROPEN; | 543 | args.qc_type = QCT_CURSOROPEN; | |
544 | args.u.cursoropen.qc_cursor = &cursor; | 544 | args.u.cursoropen.qc_cursor = &cursor; | |
545 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args); | 545 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args); | |
546 | if (error) { | 546 | if (error) { | |
547 | return error; | 547 | return error; | |
548 | } | 548 | } | |
549 | 549 | |||
550 | keys = malloc(loopmax * sizeof(keys[0]), M_TEMP, M_WAITOK); | 550 | keys = malloc(loopmax * sizeof(keys[0]), M_TEMP, M_WAITOK); | |
551 | vals = malloc(loopmax * sizeof(vals[0]), M_TEMP, M_WAITOK); | 551 | vals = malloc(loopmax * sizeof(vals[0]), M_TEMP, M_WAITOK); | |
552 | 552 | |||
553 | replies = prop_array_create(); | 553 | replies = prop_array_create(); | |
554 | if (replies == NULL) { | 554 | if (replies == NULL) { | |
555 | error = ENOMEM; | 555 | error = ENOMEM; | |
556 | goto err; | 556 | goto err; | |
557 | } | 557 | } | |
558 | 558 | |||
559 | thisreply = NULL; | 559 | thisreply = NULL; | |
560 | lastid = 0; /* value not actually referenced */ | 560 | lastid = 0; /* value not actually referenced */ | |
561 | 561 | |||
562 | while (1) { | 562 | while (1) { | |
563 | args.qc_type = QCT_GETALL; | 563 | args.qc_type = QCT_CURSORGET; | |
564 | args.u.getall.qc_cursor = &cursor; | 564 | args.u.cursorget.qc_cursor = &cursor; | |
565 | args.u.getall.qc_keys = keys; | 565 | args.u.cursorget.qc_keys = keys; | |
566 | args.u.getall.qc_vals = vals; | 566 | args.u.cursorget.qc_vals = vals; | |
567 | args.u.getall.qc_maxnum = loopmax; | 567 | args.u.cursorget.qc_maxnum = loopmax; | |
568 | args.u.getall.qc_ret = &loopnum; | 568 | args.u.cursorget.qc_ret = &loopnum; | |
569 | 569 | |||
570 | error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args); | 570 | error = VFS_QUOTACTL(mp, QUOTACTL_CURSORGET, &args); | |
571 | if (error) { | 571 | if (error) { | |
572 | goto err; | 572 | goto err; | |
573 | } | 573 | } | |
574 | 574 | |||
575 | if (loopnum == 0) { | 575 | if (loopnum == 0) { | |
576 | /* end of iteration */ | 576 | /* end of iteration */ | |
577 | break; | 577 | break; | |
578 | } | 578 | } | |
579 | 579 | |||
580 | for (i = 0; i < loopnum; i++) { | 580 | for (i = 0; i < loopnum; i++) { | |
581 | key = &keys[i]; | 581 | key = &keys[i]; | |
582 | val = &vals[i]; | 582 | val = &vals[i]; | |
583 | 583 | |||
584 | if (key->qk_idtype != q2type) { | 584 | if (key->qk_idtype != q2type) { | |
585 | /* don't want this result */ | 585 | /* don't want this result */ | |
586 | continue; | 586 | continue; | |
587 | } | 587 | } | |
588 | 588 | |||
589 | if (thisreply == NULL || key->qk_id != lastid) { | 589 | if (thisreply == NULL || key->qk_id != lastid) { | |
590 | lastid = key->qk_id; | 590 | lastid = key->qk_id; | |
591 | thisreply = vfs_quotactl_getall_makereply(key); | 591 | thisreply = vfs_quotactl_getall_makereply(key); | |
592 | if (thisreply == NULL) { | 592 | if (thisreply == NULL) { | |
593 | error = ENOMEM; | 593 | error = ENOMEM; | |
594 | goto err; | 594 | goto err; | |
595 | } | 595 | } | |
596 | /* | 596 | /* | |
597 | * Note: while we release our reference to | 597 | * Note: while we release our reference to | |
598 | * thisreply here, we can (and do) continue to | 598 | * thisreply here, we can (and do) continue to | |
599 | * use the pointer in the loop because the | 599 | * use the pointer in the loop because the | |
600 | * copy attached to the replies array is not | 600 | * copy attached to the replies array is not | |
601 | * going away. | 601 | * going away. | |
602 | */ | 602 | */ | |
603 | if (!prop_array_add_and_rel(replies, | 603 | if (!prop_array_add_and_rel(replies, | |
604 | thisreply)) { | 604 | thisreply)) { | |
605 | error = ENOMEM; | 605 | error = ENOMEM; | |
606 | goto err; | 606 | goto err; | |
607 | } | 607 | } | |
608 | } | 608 | } | |
609 | 609 | |||
610 | error = vfs_quotactl_getall_addreply(thisreply, | 610 | error = vfs_quotactl_getall_addreply(thisreply, | |
611 | key, val); | 611 | key, val); | |
612 | if (error) { | 612 | if (error) { | |
613 | goto err; | 613 | goto err; | |
614 | } | 614 | } | |
615 | } | 615 | } | |
616 | } | 616 | } | |
617 | 617 | |||
618 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 618 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
619 | error = ENOMEM; | 619 | error = ENOMEM; | |
620 | goto err; | 620 | goto err; | |
621 | } | 621 | } | |
622 | 622 | |||
623 | error = 0; | 623 | error = 0; | |
624 | err: | 624 | err: | |
625 | free(keys, M_TEMP); | 625 | free(keys, M_TEMP); | |
626 | free(vals, M_TEMP); | 626 | free(vals, M_TEMP); | |
627 | 627 | |||
628 | args.qc_type = QCT_CURSORCLOSE; | 628 | args.qc_type = QCT_CURSORCLOSE; | |
629 | args.u.cursorclose.qc_cursor = &cursor; | 629 | args.u.cursorclose.qc_cursor = &cursor; | |
630 | error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args); | 630 | error2 = VFS_QUOTACTL(mp, QUOTACTL_CURSORCLOSE, &args); | |
631 | 631 | |||
632 | if (error) { | 632 | if (error) { | |
633 | return error; | 633 | return error; | |
634 | } | 634 | } | |
635 | error = error2; | 635 | error = error2; | |
636 | return error; | 636 | return error; | |
637 | } | 637 | } | |
638 | 638 | |||
639 | static int | 639 | static int | |
640 | vfs_quotactl_clear(struct mount *mp, | 640 | vfs_quotactl_clear(struct mount *mp, | |
641 | prop_dictionary_t cmddict, int q2type, | 641 | prop_dictionary_t cmddict, int q2type, | |
642 | prop_array_t datas) | 642 | prop_array_t datas) | |
643 | { | 643 | { | |
644 | prop_array_t replies; | 644 | prop_array_t replies; | |
645 | prop_object_iterator_t iter; | 645 | prop_object_iterator_t iter; | |
646 | prop_dictionary_t data; | 646 | prop_dictionary_t data; | |
647 | uint32_t id; | 647 | uint32_t id; | |
648 | int defaultq; | 648 | int defaultq; | |
649 | const char *idstr; | 649 | const char *idstr; | |
650 | struct quotakey qk; | 650 | struct quotakey qk; | |
651 | struct vfs_quotactl_args args; | 651 | struct vfs_quotactl_args args; | |
652 | int error; | 652 | int error; | |
653 | 653 | |||
654 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 654 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
655 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 655 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
656 | 656 | |||
657 | replies = prop_array_create(); | 657 | replies = prop_array_create(); | |
658 | if (replies == NULL) | 658 | if (replies == NULL) | |
659 | return ENOMEM; | 659 | return ENOMEM; | |
660 | 660 | |||
661 | iter = prop_array_iterator(datas); | 661 | iter = prop_array_iterator(datas); | |
662 | if (iter == NULL) { | 662 | if (iter == NULL) { | |
663 | prop_object_release(replies); | 663 | prop_object_release(replies); | |
664 | return ENOMEM; | 664 | return ENOMEM; | |
665 | } | 665 | } | |
666 | 666 | |||
667 | while ((data = prop_object_iterator_next(iter)) != NULL) { | 667 | while ((data = prop_object_iterator_next(iter)) != NULL) { | |
668 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | 668 | if (!prop_dictionary_get_uint32(data, "id", &id)) { | |
669 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | 669 | if (!prop_dictionary_get_cstring_nocopy(data, "id", | |
670 | &idstr)) | 670 | &idstr)) | |
671 | continue; | 671 | continue; | |
672 | if (strcmp(idstr, "default")) | 672 | if (strcmp(idstr, "default")) | |
673 | continue; | 673 | continue; | |
674 | id = 0; | 674 | id = 0; | |
675 | defaultq = 1; | 675 | defaultq = 1; | |
676 | } else { | 676 | } else { | |
677 | defaultq = 0; | 677 | defaultq = 0; | |
678 | } | 678 | } | |
679 | 679 | |||
680 | qk.qk_idtype = q2type; | 680 | qk.qk_idtype = q2type; | |
681 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | 681 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | |
682 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | 682 | qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS; | |
683 | 683 | |||
684 | args.qc_type = QCT_DELETE; | 684 | args.qc_type = QCT_DELETE; | |
685 | args.u.delete.qc_key = &qk; | 685 | args.u.delete.qc_key = &qk; | |
686 | error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); | 686 | error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); | |
687 | if (error) { | 687 | if (error) { | |
688 | goto err; | 688 | goto err; | |
689 | } | 689 | } | |
690 | 690 | |||
691 | qk.qk_idtype = q2type; | 691 | qk.qk_idtype = q2type; | |
692 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | 692 | qk.qk_id = defaultq ? QUOTA_DEFAULTID : id; | |
693 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | 693 | qk.qk_objtype = QUOTA_OBJTYPE_FILES; | |
694 | 694 | |||
695 | args.qc_type = QCT_DELETE; | 695 | args.qc_type = QCT_DELETE; | |
696 | args.u.delete.qc_key = &qk; | 696 | args.u.delete.qc_key = &qk; | |
697 | error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); | 697 | error = VFS_QUOTACTL(mp, QUOTACTL_DELETE, &args); | |
698 | if (error) { | 698 | if (error) { | |
699 | goto err; | 699 | goto err; | |
700 | } | 700 | } | |
701 | } | 701 | } | |
702 | 702 | |||
703 | prop_object_iterator_release(iter); | 703 | prop_object_iterator_release(iter); | |
704 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | 704 | if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { | |
705 | error = ENOMEM; | 705 | error = ENOMEM; | |
706 | } else { | 706 | } else { | |
707 | error = 0; | 707 | error = 0; | |
708 | } | 708 | } | |
709 | return error; | 709 | return error; | |
710 | err: | 710 | err: | |
711 | prop_object_iterator_release(iter); | 711 | prop_object_iterator_release(iter); | |
712 | prop_object_release(replies); | 712 | prop_object_release(replies); | |
713 | return error; | 713 | return error; | |
714 | } | 714 | } | |
715 | 715 | |||
716 | static int | 716 | static int | |
717 | vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) | 717 | vfs_quotactl_cmd(struct mount *mp, prop_dictionary_t cmddict) | |
718 | { | 718 | { | |
719 | int error; | 719 | int error; | |
720 | const char *cmd, *type; | 720 | const char *cmd, *type; | |
721 | prop_array_t datas; | 721 | prop_array_t datas; | |
722 | int q2type; | 722 | int q2type; | |
723 | 723 | |||
724 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) | 724 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "command", &cmd)) | |
725 | return EINVAL; | 725 | return EINVAL; | |
726 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) | 726 | if (!prop_dictionary_get_cstring_nocopy(cmddict, "type", &type)) | |
727 | return EINVAL; | 727 | return EINVAL; | |
728 | 728 | |||
729 | if (!strcmp(type, QUOTADICT_CLASS_USER)) { | 729 | if (!strcmp(type, QUOTADICT_CLASS_USER)) { | |
730 | q2type = QUOTA_CLASS_USER; | 730 | q2type = QUOTA_CLASS_USER; | |
731 | } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { | 731 | } else if (!strcmp(type, QUOTADICT_CLASS_GROUP)) { | |
732 | q2type = QUOTA_CLASS_GROUP; | 732 | q2type = QUOTA_CLASS_GROUP; | |
733 | } else { | 733 | } else { | |
734 | /* XXX this is a bad errno for this case */ | 734 | /* XXX this is a bad errno for this case */ | |
735 | return EOPNOTSUPP; | 735 | return EOPNOTSUPP; | |
736 | } | 736 | } | |
737 | 737 | |||
738 | datas = prop_dictionary_get(cmddict, "data"); | 738 | datas = prop_dictionary_get(cmddict, "data"); | |
739 | if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) | 739 | if (datas == NULL || prop_object_type(datas) != PROP_TYPE_ARRAY) | |
740 | return EINVAL; | 740 | return EINVAL; | |
741 | 741 | |||
742 | prop_object_retain(datas); | 742 | prop_object_retain(datas); | |
743 | prop_dictionary_remove(cmddict, "data"); /* prepare for return */ | 743 | prop_dictionary_remove(cmddict, "data"); /* prepare for return */ | |
744 | 744 | |||
745 | if (strcmp(cmd, "get version") == 0) { | 745 | if (strcmp(cmd, "get version") == 0) { | |
746 | error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); | 746 | error = vfs_quotactl_getversion(mp, cmddict, q2type, datas); | |
747 | } else if (strcmp(cmd, "quotaon") == 0) { | 747 | } else if (strcmp(cmd, "quotaon") == 0) { | |
748 | error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); | 748 | error = vfs_quotactl_quotaon(mp, cmddict, q2type, datas); | |
749 | } else if (strcmp(cmd, "quotaoff") == 0) { | 749 | } else if (strcmp(cmd, "quotaoff") == 0) { | |
750 | error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); | 750 | error = vfs_quotactl_quotaoff(mp, cmddict, q2type, datas); | |
751 | } else if (strcmp(cmd, "get") == 0) { | 751 | } else if (strcmp(cmd, "get") == 0) { | |
752 | error = vfs_quotactl_get(mp, cmddict, q2type, datas); | 752 | error = vfs_quotactl_get(mp, cmddict, q2type, datas); | |
753 | } else if (strcmp(cmd, "set") == 0) { | 753 | } else if (strcmp(cmd, "set") == 0) { | |
754 | error = vfs_quotactl_put(mp, cmddict, q2type, datas); | 754 | error = vfs_quotactl_put(mp, cmddict, q2type, datas); | |
755 | } else if (strcmp(cmd, "getall") == 0) { | 755 | } else if (strcmp(cmd, "getall") == 0) { | |
756 | error = vfs_quotactl_getall(mp, cmddict, q2type, datas); | 756 | error = vfs_quotactl_getall(mp, cmddict, q2type, datas); | |
757 | } else if (strcmp(cmd, "clear") == 0) { | 757 | } else if (strcmp(cmd, "clear") == 0) { | |
758 | error = vfs_quotactl_clear(mp, cmddict, q2type, datas); | 758 | error = vfs_quotactl_clear(mp, cmddict, q2type, datas); | |
759 | } else { | 759 | } else { | |
760 | /* XXX this a bad errno for this case */ | 760 | /* XXX this a bad errno for this case */ | |
761 | error = EOPNOTSUPP; | 761 | error = EOPNOTSUPP; | |
762 | } | 762 | } | |
763 | 763 | |||
764 | error = (prop_dictionary_set_int8(cmddict, "return", | 764 | error = (prop_dictionary_set_int8(cmddict, "return", | |
765 | error) ? 0 : ENOMEM); | 765 | error) ? 0 : ENOMEM); | |
766 | prop_object_release(datas); | 766 | prop_object_release(datas); | |
767 | 767 | |||
768 | return error; | 768 | return error; | |
769 | } | 769 | } | |
770 | 770 | |||
771 | int | 771 | int | |
772 | vfs_quotactl(struct mount *mp, prop_dictionary_t dict) | 772 | vfs_quotactl(struct mount *mp, prop_dictionary_t dict) | |
773 | { | 773 | { | |
774 | prop_dictionary_t cmddict; | 774 | prop_dictionary_t cmddict; | |
775 | prop_array_t commands; | 775 | prop_array_t commands; | |
776 | prop_object_iterator_t iter; | 776 | prop_object_iterator_t iter; | |
777 | int error; | 777 | int error; | |
778 | 778 | |||
779 | error = quota_get_cmds(dict, &commands); | 779 | error = quota_get_cmds(dict, &commands); | |
780 | if (error) { | 780 | if (error) { | |
781 | return error; | 781 | return error; | |
782 | } | 782 | } | |
783 | 783 | |||
784 | iter = prop_array_iterator(commands); | 784 | iter = prop_array_iterator(commands); | |
785 | if (iter == NULL) { | 785 | if (iter == NULL) { | |
786 | return ENOMEM; | 786 | return ENOMEM; | |
787 | } | 787 | } | |
788 | 788 | |||
789 | while ((cmddict = prop_object_iterator_next(iter)) != NULL) { | 789 | while ((cmddict = prop_object_iterator_next(iter)) != NULL) { | |
790 | if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { | 790 | if (prop_object_type(cmddict) != PROP_TYPE_DICTIONARY) { | |
791 | /* XXX shouldn't this be an error? */ | 791 | /* XXX shouldn't this be an error? */ | |
792 | continue; | 792 | continue; | |
793 | } | 793 | } | |
794 | error = vfs_quotactl_cmd(mp, cmddict); | 794 | error = vfs_quotactl_cmd(mp, cmddict); | |
795 | if (error) { | 795 | if (error) { | |
796 | break; | 796 | break; | |
797 | } | 797 | } | |
798 | } | 798 | } | |
799 | prop_object_iterator_release(iter); | 799 | prop_object_iterator_release(iter); | |
800 | return error; | 800 | return error; | |
801 | } | 801 | } |
--- src/sys/sys/quotactl.h 2012/01/29 07:08:58 1.25
+++ src/sys/sys/quotactl.h 2012/01/29 07:09:52 1.26
@@ -1,114 +1,131 @@ | @@ -1,114 +1,131 @@ | |||
1 | /* $NetBSD: quotactl.h,v 1.25 2012/01/29 07:08:58 dholland Exp $ */ | 1 | /* $NetBSD: quotactl.h,v 1.26 2012/01/29 07:09:52 dholland Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2011 The NetBSD Foundation, Inc. | 3 | * Copyright (c) 2011 The NetBSD Foundation, Inc. | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * | 5 | * | |
6 | * This code is derived from software contributed to The NetBSD Foundation | 6 | * This code is derived from software contributed to The NetBSD Foundation | |
7 | * by David A. Holland. | 7 | * by David A. Holland. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | 15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | 16 | * documentation and/or other materials provided with the distribution. | |
17 | * | 17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
28 | * POSSIBILITY OF SUCH DAMAGE. | 28 | * POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | #ifndef _SYS_QUOTACTL_H_ | 31 | #ifndef _SYS_QUOTACTL_H_ | |
32 | #define _SYS_QUOTACTL_H_ | 32 | #define _SYS_QUOTACTL_H_ | |
33 | 33 | |||
34 | /* | 34 | /* | |
35 | * Note - this is an internal interface. Application code (and, | 35 | * Note - this is an internal interface. Application code (and, | |
36 | * really, anything that isn't libquota or inside the kernel) should | 36 | * really, anything that isn't libquota or inside the kernel) should | |
37 | * use the <quota.h> API instead. | 37 | * use the <quota.h> API instead. | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | /* | 40 | /* | |
41 | * Semi-opaque structure for cursors. This holds the cursor state in | 41 | * Semi-opaque structure for cursors. This holds the cursor state in | |
42 | * userland; the size is exposed only to libquota, not to client code, | 42 | * userland; the size is exposed only to libquota, not to client code, | |
43 | * and is meant to be large enough to accomodate all likely future | 43 | * and is meant to be large enough to accomodate all likely future | |
44 | * expansion without being unduly bloated, as it will need to be | 44 | * expansion without being unduly bloated, as it will need to be | |
45 | * copied in and out for every call using it. | 45 | * copied in and out for every call using it. | |
46 | */ | 46 | */ | |
47 | struct quotakcursor { | 47 | struct quotakcursor { | |
48 | union { | 48 | union { | |
49 | char qkc_space[64]; | 49 | char qkc_space[64]; | |
50 | uintmax_t __qkc_forcealign; | 50 | uintmax_t __qkc_forcealign; | |
51 | } u; | 51 | } u; | |
52 | }; | 52 | }; | |
53 | 53 | |||
54 | /* Command codes. */ | 54 | /* Command codes. */ | |
55 | #define QUOTACTL_GETVERSION 0 | 55 | #define QUOTACTL_GETVERSION 0 | |
56 | #define QUOTACTL_QUOTAON 1 | 56 | #define QUOTACTL_QUOTAON 1 | |
57 | #define QUOTACTL_QUOTAOFF 2 | 57 | #define QUOTACTL_QUOTAOFF 2 | |
58 | #define QUOTACTL_GET 3 | 58 | #define QUOTACTL_GET 3 | |
59 | #define QUOTACTL_PUT 4 | 59 | #define QUOTACTL_PUT 4 | |
60 | #define QUOTACTL_GETALL 5 | 60 | #define QUOTACTL_CURSORGET 5 | |
61 | #define QUOTACTL_DELETE 6 | 61 | #define QUOTACTL_DELETE 6 | |
62 | #define QUOTACTL_CURSOROPEN 7 | 62 | #define QUOTACTL_CURSOROPEN 7 | |
63 | #define QUOTACTL_CURSORCLOSE 8 | 63 | #define QUOTACTL_CURSORCLOSE 8 | |
64 | #define QUOTACTL_CURSORSKIPIDTYPE 9 | |||
65 | #define QUOTACTL_CURSORATEND 10 | |||
66 | #define QUOTACTL_CURSORREWIND 11 | |||
64 | 67 | |||
65 | /* Argument encoding. */ | 68 | /* Argument encoding. */ | |
66 | enum vfs_quotactl_argtypes { | 69 | enum vfs_quotactl_argtypes { | |
67 | QCT_PROPLIB, /* quotaon/off */ | 70 | QCT_PROPLIB, /* quotaon/off */ | |
68 | QCT_GETVERSION, /* getversion */ | 71 | QCT_GETVERSION, /* getversion */ | |
69 | QCT_GET, /* get */ | 72 | QCT_GET, /* get */ | |
70 | QCT_PUT, /* put */ | 73 | QCT_PUT, /* put */ | |
71 | QCT_DELETE, /* delete */ | 74 | QCT_DELETE, /* delete */ | |
72 | QCT_CURSOROPEN, /* open cursor */ | 75 | QCT_CURSOROPEN, /* open cursor */ | |
73 | QCT_CURSORCLOSE,/* close cursor */ | 76 | QCT_CURSORCLOSE,/* close cursor */ | |
74 | QCT_GETALL, /* get all */ | 77 | QCT_CURSORGET, /* get from cursor */ | |
78 | QCT_CURSORSKIPIDTYPE, /* iteration hint */ | |||
79 | QCT_CURSORATEND,/* test cursor */ | |||
80 | QCT_CURSORREWIND,/* reset cursor */ | |||
75 | }; | 81 | }; | |
76 | struct vfs_quotactl_args { | 82 | struct vfs_quotactl_args { | |
77 | enum vfs_quotactl_argtypes qc_type; | 83 | enum vfs_quotactl_argtypes qc_type; | |
78 | union { | 84 | union { | |
79 | struct { | 85 | struct { | |
80 | prop_dictionary_t qc_cmddict; | 86 | prop_dictionary_t qc_cmddict; | |
81 | int qc_q2type; | 87 | int qc_q2type; | |
82 | prop_array_t qc_datas; | 88 | prop_array_t qc_datas; | |
83 | } proplib; | 89 | } proplib; | |
84 | struct { | 90 | struct { | |
85 | int *qc_version_ret; | 91 | int *qc_version_ret; | |
86 | } getversion; | 92 | } getversion; | |
87 | struct { | 93 | struct { | |
88 | const struct quotakey *qc_key; | 94 | const struct quotakey *qc_key; | |
89 | struct quotaval *qc_ret; | 95 | struct quotaval *qc_ret; | |
90 | } get; | 96 | } get; | |
91 | struct { | 97 | struct { | |
92 | const struct quotakey *qc_key; | 98 | const struct quotakey *qc_key; | |
93 | const struct quotaval *qc_val; | 99 | const struct quotaval *qc_val; | |
94 | } put; | 100 | } put; | |
95 | struct { | 101 | struct { | |
96 | const struct quotakey *qc_key; | 102 | const struct quotakey *qc_key; | |
97 | } delete; | 103 | } delete; | |
98 | struct { | 104 | struct { | |
99 | struct quotakcursor *qc_cursor; | 105 | struct quotakcursor *qc_cursor; | |
100 | } cursoropen; | 106 | } cursoropen; | |
101 | struct { | 107 | struct { | |
102 | struct quotakcursor *qc_cursor; | 108 | struct quotakcursor *qc_cursor; | |
103 | } cursorclose; | 109 | } cursorclose; | |
104 | struct { | 110 | struct { | |
105 | struct quotakcursor *qc_cursor; | 111 | struct quotakcursor *qc_cursor; | |
112 | unsigned qc_idtype; | |||
113 | } cursorskipidtype; | |||
114 | struct { | |||
115 | struct quotakcursor *qc_cursor; | |||
106 | struct quotakey *qc_keys; | 116 | struct quotakey *qc_keys; | |
107 | struct quotaval *qc_vals; | 117 | struct quotaval *qc_vals; | |
108 | unsigned qc_maxnum; | 118 | unsigned qc_maxnum; | |
109 | unsigned *qc_ret; | 119 | unsigned *qc_ret; | |
110 | } getall; | 120 | } cursorget; | |
121 | struct { | |||
122 | struct quotakcursor *qc_cursor; | |||
123 | int *qc_ret; /* really boolean */ | |||
124 | } cursoratend; | |||
125 | struct { | |||
126 | struct quotakcursor *qc_cursor; | |||
127 | } cursorrewind; | |||
111 | } u; | 128 | } u; | |
112 | }; | 129 | }; | |
113 | 130 | |||
114 | #endif /* _SYS_QUOTACTL_H_ */ | 131 | #endif /* _SYS_QUOTACTL_H_ */ |
--- src/sys/ufs/ufs/ufs_quota.c 2012/01/29 07:08:58 1.97
+++ src/sys/ufs/ufs/ufs_quota.c 2012/01/29 07:09:52 1.98
@@ -1,840 +1,922 @@ | @@ -1,840 +1,922 @@ | |||
1 | /* $NetBSD: ufs_quota.c,v 1.97 2012/01/29 07:08:58 dholland Exp $ */ | 1 | /* $NetBSD: ufs_quota.c,v 1.98 2012/01/29 07:09:52 dholland Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | 4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Robert Elz at The University of Melbourne. | 8 | * Robert Elz at The University of Melbourne. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | 34 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.97 2012/01/29 07:08:58 dholland Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.98 2012/01/29 07:09:52 dholland Exp $"); | |
39 | 39 | |||
40 | #if defined(_KERNEL_OPT) | 40 | #if defined(_KERNEL_OPT) | |
41 | #include "opt_quota.h" | 41 | #include "opt_quota.h" | |
42 | #endif | 42 | #endif | |
43 | #include <sys/param.h> | 43 | #include <sys/param.h> | |
44 | #include <sys/kernel.h> | 44 | #include <sys/kernel.h> | |
45 | #include <sys/systm.h> | 45 | #include <sys/systm.h> | |
46 | #include <sys/namei.h> | 46 | #include <sys/namei.h> | |
47 | #include <sys/file.h> | 47 | #include <sys/file.h> | |
48 | #include <sys/proc.h> | 48 | #include <sys/proc.h> | |
49 | #include <sys/vnode.h> | 49 | #include <sys/vnode.h> | |
50 | #include <sys/mount.h> | 50 | #include <sys/mount.h> | |
51 | #include <sys/kauth.h> | 51 | #include <sys/kauth.h> | |
52 | 52 | |||
53 | #include <sys/quotactl.h> | 53 | #include <sys/quotactl.h> | |
54 | #include <ufs/ufs/quota.h> | 54 | #include <ufs/ufs/quota.h> | |
55 | #include <ufs/ufs/inode.h> | 55 | #include <ufs/ufs/inode.h> | |
56 | #include <ufs/ufs/ufsmount.h> | 56 | #include <ufs/ufs/ufsmount.h> | |
57 | #include <ufs/ufs/ufs_extern.h> | 57 | #include <ufs/ufs/ufs_extern.h> | |
58 | #include <ufs/ufs/ufs_quota.h> | 58 | #include <ufs/ufs/ufs_quota.h> | |
59 | #include <quota/quotaprop.h> | 59 | #include <quota/quotaprop.h> | |
60 | 60 | |||
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_cursorget(struct mount *, struct lwp *, | |
81 | struct vfs_quotactl_args *args); | 81 | struct vfs_quotactl_args *args); | |
82 | static int quota_handle_cmd_delete(struct mount *, struct lwp *, | 82 | static int quota_handle_cmd_delete(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 | static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *, | 88 | static int quota_handle_cmd_cursoropen(struct mount *, struct lwp *, | |
89 | struct vfs_quotactl_args *args); | 89 | struct vfs_quotactl_args *args); | |
90 | static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *, | 90 | static int quota_handle_cmd_cursorclose(struct mount *, struct lwp *, | |
91 | struct vfs_quotactl_args *args); | 91 | struct vfs_quotactl_args *args); | |
92 | static int quota_handle_cmd_cursorskipidtype(struct mount *, struct lwp *, | |||
93 | struct vfs_quotactl_args *args); | |||
94 | static int quota_handle_cmd_cursoratend(struct mount *, struct lwp *, | |||
95 | struct vfs_quotactl_args *args); | |||
96 | static int quota_handle_cmd_cursorrewind(struct mount *, struct lwp *, | |||
97 | struct vfs_quotactl_args *args); | |||
92 | 98 | |||
93 | /* | 99 | /* | |
94 | * Initialize the quota fields of an inode. | 100 | * Initialize the quota fields of an inode. | |
95 | */ | 101 | */ | |
96 | void | 102 | void | |
97 | ufsquota_init(struct inode *ip) | 103 | ufsquota_init(struct inode *ip) | |
98 | { | 104 | { | |
99 | int i; | 105 | int i; | |
100 | 106 | |||
101 | for (i = 0; i < MAXQUOTAS; i++) | 107 | for (i = 0; i < MAXQUOTAS; i++) | |
102 | ip->i_dquot[i] = NODQUOT; | 108 | ip->i_dquot[i] = NODQUOT; | |
103 | } | 109 | } | |
104 | 110 | |||
105 | /* | 111 | /* | |
106 | * Release the quota fields from an inode. | 112 | * Release the quota fields from an inode. | |
107 | */ | 113 | */ | |
108 | void | 114 | void | |
109 | ufsquota_free(struct inode *ip) | 115 | ufsquota_free(struct inode *ip) | |
110 | { | 116 | { | |
111 | int i; | 117 | int i; | |
112 | 118 | |||
113 | for (i = 0; i < MAXQUOTAS; i++) { | 119 | for (i = 0; i < MAXQUOTAS; i++) { | |
114 | dqrele(ITOV(ip), ip->i_dquot[i]); | 120 | dqrele(ITOV(ip), ip->i_dquot[i]); | |
115 | ip->i_dquot[i] = NODQUOT; | 121 | ip->i_dquot[i] = NODQUOT; | |
116 | } | 122 | } | |
117 | } | 123 | } | |
118 | 124 | |||
119 | /* | 125 | /* | |
120 | * Update disk usage, and take corrective action. | 126 | * Update disk usage, and take corrective action. | |
121 | */ | 127 | */ | |
122 | int | 128 | int | |
123 | chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | 129 | chkdq(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | |
124 | { | 130 | { | |
125 | /* do not track snapshot usage, or we will deadlock */ | 131 | /* do not track snapshot usage, or we will deadlock */ | |
126 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | 132 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | |
127 | return 0; | 133 | return 0; | |
128 | 134 | |||
129 | #ifdef QUOTA | 135 | #ifdef QUOTA | |
130 | if (ip->i_ump->um_flags & UFS_QUOTA) | 136 | if (ip->i_ump->um_flags & UFS_QUOTA) | |
131 | return chkdq1(ip, change, cred, flags); | 137 | return chkdq1(ip, change, cred, flags); | |
132 | #endif | 138 | #endif | |
133 | #ifdef QUOTA2 | 139 | #ifdef QUOTA2 | |
134 | if (ip->i_ump->um_flags & UFS_QUOTA2) | 140 | if (ip->i_ump->um_flags & UFS_QUOTA2) | |
135 | return chkdq2(ip, change, cred, flags); | 141 | return chkdq2(ip, change, cred, flags); | |
136 | #endif | 142 | #endif | |
137 | return 0; | 143 | return 0; | |
138 | } | 144 | } | |
139 | 145 | |||
140 | /* | 146 | /* | |
141 | * Check the inode limit, applying corrective action. | 147 | * Check the inode limit, applying corrective action. | |
142 | */ | 148 | */ | |
143 | int | 149 | int | |
144 | chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | 150 | chkiq(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | |
145 | { | 151 | { | |
146 | /* do not track snapshot usage, or we will deadlock */ | 152 | /* do not track snapshot usage, or we will deadlock */ | |
147 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | 153 | if ((ip->i_flags & SF_SNAPSHOT) != 0) | |
148 | return 0; | 154 | return 0; | |
149 | #ifdef QUOTA | 155 | #ifdef QUOTA | |
150 | if (ip->i_ump->um_flags & UFS_QUOTA) | 156 | if (ip->i_ump->um_flags & UFS_QUOTA) | |
151 | return chkiq1(ip, change, cred, flags); | 157 | return chkiq1(ip, change, cred, flags); | |
152 | #endif | 158 | #endif | |
153 | #ifdef QUOTA2 | 159 | #ifdef QUOTA2 | |
154 | if (ip->i_ump->um_flags & UFS_QUOTA2) | 160 | if (ip->i_ump->um_flags & UFS_QUOTA2) | |
155 | return chkiq2(ip, change, cred, flags); | 161 | return chkiq2(ip, change, cred, flags); | |
156 | #endif | 162 | #endif | |
157 | return 0; | 163 | return 0; | |
158 | } | 164 | } | |
159 | 165 | |||
160 | int | 166 | int | |
161 | quota_handle_cmd(struct mount *mp, struct lwp *l, int op, | 167 | quota_handle_cmd(struct mount *mp, struct lwp *l, int op, | |
162 | struct vfs_quotactl_args *args) | 168 | struct vfs_quotactl_args *args) | |
163 | { | 169 | { | |
164 | int error = 0; | 170 | int error = 0; | |
165 | 171 | |||
166 | switch (op) { | 172 | switch (op) { | |
167 | case QUOTACTL_GETVERSION: | 173 | case QUOTACTL_GETVERSION: | |
168 | error = quota_handle_cmd_get_version(mp, l, args); | 174 | error = quota_handle_cmd_get_version(mp, l, args); | |
169 | break; | 175 | break; | |
170 | case QUOTACTL_QUOTAON: | 176 | case QUOTACTL_QUOTAON: | |
171 | error = quota_handle_cmd_quotaon(mp, l, args); | 177 | error = quota_handle_cmd_quotaon(mp, l, args); | |
172 | break; | 178 | break; | |
173 | case QUOTACTL_QUOTAOFF: | 179 | case QUOTACTL_QUOTAOFF: | |
174 | error = quota_handle_cmd_quotaoff(mp, l, args); | 180 | error = quota_handle_cmd_quotaoff(mp, l, args); | |
175 | break; | 181 | break; | |
176 | case QUOTACTL_GET: | 182 | case QUOTACTL_GET: | |
177 | error = quota_handle_cmd_get(mp, l, args); | 183 | error = quota_handle_cmd_get(mp, l, args); | |
178 | break; | 184 | break; | |
179 | case QUOTACTL_PUT: | 185 | case QUOTACTL_PUT: | |
180 | error = quota_handle_cmd_put(mp, l, args); | 186 | error = quota_handle_cmd_put(mp, l, args); | |
181 | break; | 187 | break; | |
182 | case QUOTACTL_GETALL: | 188 | case QUOTACTL_CURSORGET: | |
183 | error = quota_handle_cmd_getall(mp, l, args); | 189 | error = quota_handle_cmd_cursorget(mp, l, args); | |
184 | break; | 190 | break; | |
185 | case QUOTACTL_DELETE: | 191 | case QUOTACTL_DELETE: | |
186 | error = quota_handle_cmd_delete(mp, l, args); | 192 | error = quota_handle_cmd_delete(mp, l, args); | |
187 | break; | 193 | break; | |
188 | case QUOTACTL_CURSOROPEN: | 194 | case QUOTACTL_CURSOROPEN: | |
189 | error = quota_handle_cmd_cursoropen(mp, l, args); | 195 | error = quota_handle_cmd_cursoropen(mp, l, args); | |
190 | break; | 196 | break; | |
191 | case QUOTACTL_CURSORCLOSE: | 197 | case QUOTACTL_CURSORCLOSE: | |
192 | error = quota_handle_cmd_cursorclose(mp, l, args); | 198 | error = quota_handle_cmd_cursorclose(mp, l, args); | |
193 | break; | 199 | break; | |
200 | case QUOTACTL_CURSORSKIPIDTYPE: | |||
201 | error = quota_handle_cmd_cursorskipidtype(mp, l, args); | |||
202 | break; | |||
203 | case QUOTACTL_CURSORATEND: | |||
204 | error = quota_handle_cmd_cursoratend(mp, l, args); | |||
205 | break; | |||
206 | case QUOTACTL_CURSORREWIND: | |||
207 | error = quota_handle_cmd_cursorrewind(mp, l, args); | |||
208 | break; | |||
194 | default: | 209 | default: | |
195 | panic("Invalid quotactl operation %d\n", op); | 210 | panic("Invalid quotactl operation %d\n", op); | |
196 | } | 211 | } | |
197 | 212 | |||
198 | return error; | 213 | return error; | |
199 | } | 214 | } | |
200 | 215 | |||
201 | static int | 216 | static int | |
202 | quota_handle_cmd_get_version(struct mount *mp, struct lwp *l, | 217 | quota_handle_cmd_get_version(struct mount *mp, struct lwp *l, | |
203 | struct vfs_quotactl_args *args) | 218 | struct vfs_quotactl_args *args) | |
204 | { | 219 | { | |
205 | struct ufsmount *ump = VFSTOUFS(mp); | 220 | struct ufsmount *ump = VFSTOUFS(mp); | |
206 | int *version_ret; | 221 | int *version_ret; | |
207 | 222 | |||
208 | KASSERT(args->qc_type == QCT_GETVERSION); | 223 | KASSERT(args->qc_type == QCT_GETVERSION); | |
209 | version_ret = args->u.getversion.qc_version_ret; | 224 | version_ret = args->u.getversion.qc_version_ret; | |
210 | 225 | |||
211 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | 226 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | |
212 | return EOPNOTSUPP; | 227 | return EOPNOTSUPP; | |
213 | 228 | |||
214 | #ifdef QUOTA | 229 | #ifdef QUOTA | |
215 | if (ump->um_flags & UFS_QUOTA) { | 230 | if (ump->um_flags & UFS_QUOTA) { | |
216 | *version_ret = 1; | 231 | *version_ret = 1; | |
217 | } else | 232 | } else | |
218 | #endif | 233 | #endif | |
219 | #ifdef QUOTA2 | 234 | #ifdef QUOTA2 | |
220 | if (ump->um_flags & UFS_QUOTA2) { | 235 | if (ump->um_flags & UFS_QUOTA2) { | |
221 | *version_ret = 2; | 236 | *version_ret = 2; | |
222 | } else | 237 | } else | |
223 | #endif | 238 | #endif | |
224 | return EOPNOTSUPP; | 239 | return EOPNOTSUPP; | |
225 | 240 | |||
226 | return 0; | 241 | return 0; | |
227 | } | 242 | } | |
228 | 243 | |||
229 | /* XXX shouldn't all this be in kauth ? */ | 244 | /* XXX shouldn't all this be in kauth ? */ | |
230 | static int | 245 | static int | |
231 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { | 246 | quota_get_auth(struct mount *mp, struct lwp *l, uid_t id) { | |
232 | /* The user can always query about his own quota. */ | 247 | /* The user can always query about his own quota. */ | |
233 | if (id == kauth_cred_getuid(l->l_cred)) | 248 | if (id == kauth_cred_getuid(l->l_cred)) | |
234 | return 0; | 249 | return 0; | |
235 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 250 | return kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
236 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); | 251 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, KAUTH_ARG(id), NULL); | |
237 | } | 252 | } | |
238 | 253 | |||
239 | static int | 254 | static int | |
240 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | 255 | quota_handle_cmd_get(struct mount *mp, struct lwp *l, | |
241 | struct vfs_quotactl_args *args) | 256 | struct vfs_quotactl_args *args) | |
242 | { | 257 | { | |
243 | struct ufsmount *ump = VFSTOUFS(mp); | 258 | struct ufsmount *ump = VFSTOUFS(mp); | |
244 | int error; | 259 | int error; | |
245 | const struct quotakey *qk; | 260 | const struct quotakey *qk; | |
246 | struct quotaval *ret; | 261 | struct quotaval *ret; | |
247 | 262 | |||
248 | KASSERT(args->qc_type == QCT_GET); | 263 | KASSERT(args->qc_type == QCT_GET); | |
249 | qk = args->u.get.qc_key; | 264 | qk = args->u.get.qc_key; | |
250 | ret = args->u.get.qc_ret; | 265 | ret = args->u.get.qc_ret; | |
251 | 266 | |||
252 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | 267 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | |
253 | return EOPNOTSUPP; | 268 | return EOPNOTSUPP; | |
254 | 269 | |||
255 | error = quota_get_auth(mp, l, qk->qk_id); | 270 | error = quota_get_auth(mp, l, qk->qk_id); | |
256 | if (error != 0) | 271 | if (error != 0) | |
257 | return error; | 272 | return error; | |
258 | #ifdef QUOTA | 273 | #ifdef QUOTA | |
259 | if (ump->um_flags & UFS_QUOTA) { | 274 | if (ump->um_flags & UFS_QUOTA) { | |
260 | error = quota1_handle_cmd_get(ump, qk, ret); | 275 | error = quota1_handle_cmd_get(ump, qk, ret); | |
261 | } else | 276 | } else | |
262 | #endif | 277 | #endif | |
263 | #ifdef QUOTA2 | 278 | #ifdef QUOTA2 | |
264 | if (ump->um_flags & UFS_QUOTA2) { | 279 | if (ump->um_flags & UFS_QUOTA2) { | |
265 | error = quota2_handle_cmd_get(ump, qk, ret); | 280 | error = quota2_handle_cmd_get(ump, qk, ret); | |
266 | } else | 281 | } else | |
267 | #endif | 282 | #endif | |
268 | panic("quota_handle_cmd_get: no support ?"); | 283 | panic("quota_handle_cmd_get: no support ?"); | |
269 | 284 | |||
270 | if (error != 0) | 285 | if (error != 0) | |
271 | return error; | 286 | return error; | |
272 | 287 | |||
273 | return error; | 288 | return error; | |
274 | } | 289 | } | |
275 | 290 | |||
276 | static int | 291 | static int | |
277 | quota_handle_cmd_put(struct mount *mp, struct lwp *l, | 292 | quota_handle_cmd_put(struct mount *mp, struct lwp *l, | |
278 | struct vfs_quotactl_args *args) | 293 | struct vfs_quotactl_args *args) | |
279 | { | 294 | { | |
280 | struct ufsmount *ump = VFSTOUFS(mp); | 295 | struct ufsmount *ump = VFSTOUFS(mp); | |
281 | const struct quotakey *qk; | 296 | const struct quotakey *qk; | |
282 | const struct quotaval *qv; | 297 | const struct quotaval *qv; | |
283 | id_t kauth_id; | 298 | id_t kauth_id; | |
284 | int error; | 299 | int error; | |
285 | 300 | |||
286 | KASSERT(args->qc_type == QCT_PUT); | 301 | KASSERT(args->qc_type == QCT_PUT); | |
287 | qk = args->u.put.qc_key; | 302 | qk = args->u.put.qc_key; | |
288 | qv = args->u.put.qc_val; | 303 | qv = args->u.put.qc_val; | |
289 | 304 | |||
290 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | 305 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) | |
291 | return EOPNOTSUPP; | 306 | return EOPNOTSUPP; | |
292 | 307 | |||
293 | kauth_id = qk->qk_id; | 308 | kauth_id = qk->qk_id; | |
294 | if (kauth_id == QUOTA_DEFAULTID) { | 309 | if (kauth_id == QUOTA_DEFAULTID) { | |
295 | kauth_id = 0; | 310 | kauth_id = 0; | |
296 | } | 311 | } | |
297 | 312 | |||
298 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 313 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
299 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), | 314 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), | |
300 | NULL); | 315 | NULL); | |
301 | if (error != 0) { | 316 | if (error != 0) { | |
302 | return error; | 317 | return error; | |
303 | } | 318 | } | |
304 | 319 | |||
305 | #ifdef QUOTA | 320 | #ifdef QUOTA | |
306 | if (ump->um_flags & UFS_QUOTA) | 321 | if (ump->um_flags & UFS_QUOTA) | |
307 | error = quota1_handle_cmd_put(ump, qk, qv); | 322 | error = quota1_handle_cmd_put(ump, qk, qv); | |
308 | else | 323 | else | |
309 | #endif | 324 | #endif | |
310 | #ifdef QUOTA2 | 325 | #ifdef QUOTA2 | |
311 | if (ump->um_flags & UFS_QUOTA2) { | 326 | if (ump->um_flags & UFS_QUOTA2) { | |
312 | error = quota2_handle_cmd_put(ump, qk, qv); | 327 | error = quota2_handle_cmd_put(ump, qk, qv); | |
313 | } else | 328 | } else | |
314 | #endif | 329 | #endif | |
315 | panic("quota_handle_cmd_get: no support ?"); | 330 | panic("quota_handle_cmd_get: no support ?"); | |
316 | 331 | |||
317 | if (error == ENOENT) { | 332 | if (error == ENOENT) { | |
318 | error = 0; | 333 | error = 0; | |
319 | } | 334 | } | |
320 | 335 | |||
321 | return error; | 336 | return error; | |
322 | } | 337 | } | |
323 | 338 | |||
324 | static int | 339 | static int | |
325 | quota_handle_cmd_delete(struct mount *mp, struct lwp *l, | 340 | quota_handle_cmd_delete(struct mount *mp, struct lwp *l, | |
326 | struct vfs_quotactl_args *args) | 341 | struct vfs_quotactl_args *args) | |
327 | { | 342 | { | |
328 | struct ufsmount *ump = VFSTOUFS(mp); | 343 | struct ufsmount *ump = VFSTOUFS(mp); | |
329 | const struct quotakey *qk; | 344 | const struct quotakey *qk; | |
330 | id_t kauth_id; | 345 | id_t kauth_id; | |
331 | int error; | 346 | int error; | |
332 | 347 | |||
333 | KASSERT(args->qc_type == QCT_DELETE); | 348 | KASSERT(args->qc_type == QCT_DELETE); | |
334 | qk = args->u.delete.qc_key; | 349 | qk = args->u.delete.qc_key; | |
335 | 350 | |||
336 | kauth_id = qk->qk_id; | 351 | kauth_id = qk->qk_id; | |
337 | if (kauth_id == QUOTA_DEFAULTID) { | 352 | if (kauth_id == QUOTA_DEFAULTID) { | |
338 | kauth_id = 0; | 353 | kauth_id = 0; | |
339 | } | 354 | } | |
340 | 355 | |||
341 | if ((ump->um_flags & UFS_QUOTA2) == 0) | 356 | if ((ump->um_flags & UFS_QUOTA2) == 0) | |
342 | return EOPNOTSUPP; | 357 | return EOPNOTSUPP; | |
343 | 358 | |||
344 | /* avoid whitespace changes */ | 359 | /* avoid whitespace changes */ | |
345 | { | 360 | { | |
346 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 361 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
347 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), | 362 | KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE, mp, KAUTH_ARG(kauth_id), | |
348 | NULL); | 363 | NULL); | |
349 | if (error != 0) | 364 | if (error != 0) | |
350 | goto err; | 365 | goto err; | |
351 | #ifdef QUOTA2 | 366 | #ifdef QUOTA2 | |
352 | if (ump->um_flags & UFS_QUOTA2) { | 367 | if (ump->um_flags & UFS_QUOTA2) { | |
353 | error = quota2_handle_cmd_delete(ump, qk); | 368 | error = quota2_handle_cmd_delete(ump, qk); | |
354 | } else | 369 | } else | |
355 | #endif | 370 | #endif | |
356 | panic("quota_handle_cmd_get: no support ?"); | 371 | panic("quota_handle_cmd_get: no support ?"); | |
357 | 372 | |||
358 | if (error && error != ENOENT) | 373 | if (error && error != ENOENT) | |
359 | goto err; | 374 | goto err; | |
360 | } | 375 | } | |
361 | 376 | |||
362 | return 0; | 377 | return 0; | |
363 | err: | 378 | err: | |
364 | return error; | 379 | return error; | |
365 | } | 380 | } | |
366 | 381 | |||
367 | static int | 382 | static int | |
368 | quota_handle_cmd_getall(struct mount *mp, struct lwp *l, | 383 | quota_handle_cmd_cursorget(struct mount *mp, struct lwp *l, | |
369 | struct vfs_quotactl_args *args) | 384 | struct vfs_quotactl_args *args) | |
370 | { | 385 | { | |
371 | struct ufsmount *ump = VFSTOUFS(mp); | 386 | struct ufsmount *ump = VFSTOUFS(mp); | |
372 | struct quotakcursor *cursor; | 387 | struct quotakcursor *cursor; | |
373 | struct quotakey *keys; | 388 | struct quotakey *keys; | |
374 | struct quotaval *vals; | 389 | struct quotaval *vals; | |
375 | unsigned maxnum; | 390 | unsigned maxnum; | |
376 | unsigned *ret; | 391 | unsigned *ret; | |
377 | int error; | 392 | int error; | |
378 | 393 | |||
379 | KASSERT(args->qc_type == QCT_GETALL); | 394 | KASSERT(args->qc_type == QCT_CURSORGET); | |
380 | cursor = args->u.getall.qc_cursor; | 395 | cursor = args->u.cursorget.qc_cursor; | |
381 | keys = args->u.getall.qc_keys; | 396 | keys = args->u.cursorget.qc_keys; | |
382 | vals = args->u.getall.qc_vals; | 397 | vals = args->u.cursorget.qc_vals; | |
383 | maxnum = args->u.getall.qc_maxnum; | 398 | maxnum = args->u.cursorget.qc_maxnum; | |
384 | ret = args->u.getall.qc_ret; | 399 | ret = args->u.cursorget.qc_ret; | |
385 | 400 | |||
386 | if ((ump->um_flags & UFS_QUOTA2) == 0) | 401 | if ((ump->um_flags & UFS_QUOTA2) == 0) | |
387 | return EOPNOTSUPP; | 402 | return EOPNOTSUPP; | |
388 | 403 | |||
389 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 404 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
390 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | 405 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | |
391 | if (error) | 406 | if (error) | |
392 | return error; | 407 | return error; | |
393 | 408 | |||
394 | #ifdef QUOTA2 | 409 | #ifdef QUOTA2 | |
395 | if (ump->um_flags & UFS_QUOTA2) { | 410 | if (ump->um_flags & UFS_QUOTA2) { | |
396 | error = quota2_handle_cmd_getall(ump, cursor, | 411 | error = quota2_handle_cmd_cursorget(ump, cursor, keys, vals, | |
397 | keys, vals, maxnum, ret); | 412 | maxnum, ret); | |
398 | } else | 413 | } else | |
399 | #endif | 414 | #endif | |
400 | panic("quota_handle_cmd_getall: no support ?"); | 415 | panic("quota_handle_cmd_cursorget: no support ?"); | |
401 | 416 | |||
402 | return error; | 417 | return error; | |
403 | } | 418 | } | |
404 | 419 | |||
405 | static int | 420 | static int | |
406 | quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l, | 421 | quota_handle_cmd_cursoropen(struct mount *mp, struct lwp *l, | |
407 | struct vfs_quotactl_args *args) | 422 | struct vfs_quotactl_args *args) | |
408 | { | 423 | { | |
409 | struct ufsmount *ump = VFSTOUFS(mp); | 424 | struct ufsmount *ump = VFSTOUFS(mp); | |
410 | struct quotakcursor *cursor; | 425 | struct quotakcursor *cursor; | |
411 | int error; | 426 | int error; | |
412 | 427 | |||
413 | KASSERT(args->qc_type == QCT_CURSOROPEN); | 428 | KASSERT(args->qc_type == QCT_CURSOROPEN); | |
414 | cursor = args->u.cursoropen.qc_cursor; | 429 | cursor = args->u.cursoropen.qc_cursor; | |
415 | 430 | |||
416 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 431 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
417 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | 432 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | |
418 | if (error) | 433 | if (error) | |
419 | return error; | 434 | return error; | |
420 | 435 | |||
421 | #ifdef QUOTA2 | 436 | #ifdef QUOTA2 | |
422 | if (ump->um_flags & UFS_QUOTA2) { | 437 | if (ump->um_flags & UFS_QUOTA2) { | |
423 | error = quota2_handle_cmd_cursoropen(ump, cursor); | 438 | error = quota2_handle_cmd_cursoropen(ump, cursor); | |
424 | } else | 439 | } else | |
425 | #endif | 440 | #endif | |
426 | error = EOPNOTSUPP; | 441 | error = EOPNOTSUPP; | |
427 | 442 | |||
428 | return error; | 443 | return error; | |
429 | } | 444 | } | |
430 | 445 | |||
431 | static int | 446 | static int | |
432 | quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l, | 447 | quota_handle_cmd_cursorclose(struct mount *mp, struct lwp *l, | |
433 | struct vfs_quotactl_args *args) | 448 | struct vfs_quotactl_args *args) | |
434 | { | 449 | { | |
435 | struct ufsmount *ump = VFSTOUFS(mp); | 450 | struct ufsmount *ump = VFSTOUFS(mp); | |
436 | struct quotakcursor *cursor; | 451 | struct quotakcursor *cursor; | |
437 | int error; | 452 | int error; | |
438 | 453 | |||
439 | KASSERT(args->qc_type == QCT_CURSORCLOSE); | 454 | KASSERT(args->qc_type == QCT_CURSORCLOSE); | |
440 | cursor = args->u.cursorclose.qc_cursor; | 455 | cursor = args->u.cursorclose.qc_cursor; | |
441 | 456 | |||
442 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 457 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
443 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | 458 | KAUTH_REQ_SYSTEM_FS_QUOTA_GET, mp, NULL, NULL); | |
444 | if (error) | 459 | if (error) | |
445 | return error; | 460 | return error; | |
446 | 461 | |||
447 | #ifdef QUOTA2 | 462 | #ifdef QUOTA2 | |
448 | if (ump->um_flags & UFS_QUOTA2) { | 463 | if (ump->um_flags & UFS_QUOTA2) { | |
449 | error = quota2_handle_cmd_cursorclose(ump, cursor); | 464 | error = quota2_handle_cmd_cursorclose(ump, cursor); | |
450 | } else | 465 | } else | |
451 | #endif | 466 | #endif | |
452 | error = EOPNOTSUPP; | 467 | error = EOPNOTSUPP; | |
453 | 468 | |||
454 | return error; | 469 | return error; | |
455 | } | 470 | } | |
456 | 471 | |||
457 | static int | 472 | static int | |
473 | quota_handle_cmd_cursorskipidtype(struct mount *mp, struct lwp *l, | |||
474 | struct vfs_quotactl_args *args) | |||
475 | { | |||
476 | struct ufsmount *ump = VFSTOUFS(mp); | |||
477 | struct quotakcursor *cursor; | |||
478 | int idtype; | |||
479 | int error; | |||
480 | ||||
481 | KASSERT(args->qc_type == QCT_CURSORSKIPIDTYPE); | |||
482 | cursor = args->u.cursorskipidtype.qc_cursor; | |||
483 | idtype = args->u.cursorskipidtype.qc_idtype; | |||
484 | ||||
485 | #ifdef QUOTA2 | |||
486 | if (ump->um_flags & UFS_QUOTA2) { | |||
487 | error = quota2_handle_cmd_cursorskipidtype(ump, cursor, idtype); | |||
488 | } else | |||
489 | #endif | |||
490 | error = EOPNOTSUPP; | |||
491 | ||||
492 | return error; | |||
493 | } | |||
494 | ||||
495 | static int | |||
496 | quota_handle_cmd_cursoratend(struct mount *mp, struct lwp *l, | |||
497 | struct vfs_quotactl_args *args) | |||
498 | { | |||
499 | struct ufsmount *ump = VFSTOUFS(mp); | |||
500 | struct quotakcursor *cursor; | |||
501 | int *ret; | |||
502 | int error; | |||
503 | ||||
504 | KASSERT(args->qc_type == QCT_CURSORATEND); | |||
505 | cursor = args->u.cursoratend.qc_cursor; | |||
506 | ret = args->u.cursoratend.qc_ret; | |||
507 | ||||
508 | #ifdef QUOTA2 | |||
509 | if (ump->um_flags & UFS_QUOTA2) { | |||
510 | error = quota2_handle_cmd_cursoratend(ump, cursor, ret); | |||
511 | } else | |||
512 | #endif | |||
513 | error = EOPNOTSUPP; | |||
514 | ||||
515 | return error; | |||
516 | } | |||
517 | ||||
518 | static int | |||
519 | quota_handle_cmd_cursorrewind(struct mount *mp, struct lwp *l, | |||
520 | struct vfs_quotactl_args *args) | |||
521 | { | |||
522 | struct ufsmount *ump = VFSTOUFS(mp); | |||
523 | struct quotakcursor *cursor; | |||
524 | int error; | |||
525 | ||||
526 | KASSERT(args->qc_type == QCT_CURSORREWIND); | |||
527 | cursor = args->u.cursorrewind.qc_cursor; | |||
528 | ||||
529 | #ifdef QUOTA2 | |||
530 | if (ump->um_flags & UFS_QUOTA2) { | |||
531 | error = quota2_handle_cmd_cursorrewind(ump, cursor); | |||
532 | } else | |||
533 | #endif | |||
534 | error = EOPNOTSUPP; | |||
535 | ||||
536 | return error; | |||
537 | } | |||
538 | ||||
539 | static int | |||
458 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, | 540 | quota_handle_cmd_quotaon(struct mount *mp, struct lwp *l, | |
459 | struct vfs_quotactl_args *args) | 541 | struct vfs_quotactl_args *args) | |
460 | { | 542 | { | |
461 | prop_dictionary_t data; | 543 | prop_dictionary_t data; | |
462 | struct ufsmount *ump = VFSTOUFS(mp); | 544 | struct ufsmount *ump = VFSTOUFS(mp); | |
463 | int error; | 545 | int error; | |
464 | const char *qfile; | 546 | const char *qfile; | |
465 | prop_dictionary_t cmddict; | 547 | prop_dictionary_t cmddict; | |
466 | int q2type; | 548 | int q2type; | |
467 | prop_array_t datas; | 549 | prop_array_t datas; | |
468 | 550 | |||
469 | KASSERT(args->qc_type == QCT_PROPLIB); | 551 | KASSERT(args->qc_type == QCT_PROPLIB); | |
470 | cmddict = args->u.proplib.qc_cmddict; | 552 | cmddict = args->u.proplib.qc_cmddict; | |
471 | q2type = args->u.proplib.qc_q2type; | 553 | q2type = args->u.proplib.qc_q2type; | |
472 | datas = args->u.proplib.qc_datas; | 554 | datas = args->u.proplib.qc_datas; | |
473 | 555 | |||
474 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 556 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
475 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 557 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
476 | 558 | |||
477 | if ((ump->um_flags & UFS_QUOTA2) != 0) | 559 | if ((ump->um_flags & UFS_QUOTA2) != 0) | |
478 | return EBUSY; | 560 | return EBUSY; | |
479 | 561 | |||
480 | if (prop_array_count(datas) != 1) | 562 | if (prop_array_count(datas) != 1) | |
481 | return EINVAL; | 563 | return EINVAL; | |
482 | 564 | |||
483 | data = prop_array_get(datas, 0); | 565 | data = prop_array_get(datas, 0); | |
484 | if (data == NULL) | 566 | if (data == NULL) | |
485 | return ENOMEM; | 567 | return ENOMEM; | |
486 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", | 568 | if (!prop_dictionary_get_cstring_nocopy(data, "quotafile", | |
487 | &qfile)) | 569 | &qfile)) | |
488 | return EINVAL; | 570 | return EINVAL; | |
489 | 571 | |||
490 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 572 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
491 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | 573 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | |
492 | if (error != 0) { | 574 | if (error != 0) { | |
493 | return error; | 575 | return error; | |
494 | } | 576 | } | |
495 | #ifdef QUOTA | 577 | #ifdef QUOTA | |
496 | error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); | 578 | error = quota1_handle_cmd_quotaon(l, ump, q2type, qfile); | |
497 | #else | 579 | #else | |
498 | error = EOPNOTSUPP; | 580 | error = EOPNOTSUPP; | |
499 | #endif | 581 | #endif | |
500 | 582 | |||
501 | return error; | 583 | return error; | |
502 | } | 584 | } | |
503 | 585 | |||
504 | static int | 586 | static int | |
505 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, | 587 | quota_handle_cmd_quotaoff(struct mount *mp, struct lwp *l, | |
506 | struct vfs_quotactl_args *args) | 588 | struct vfs_quotactl_args *args) | |
507 | { | 589 | { | |
508 | struct ufsmount *ump = VFSTOUFS(mp); | 590 | struct ufsmount *ump = VFSTOUFS(mp); | |
509 | int error; | 591 | int error; | |
510 | prop_dictionary_t cmddict; | 592 | prop_dictionary_t cmddict; | |
511 | int q2type; | 593 | int q2type; | |
512 | prop_array_t datas; | 594 | prop_array_t datas; | |
513 | 595 | |||
514 | KASSERT(args->qc_type == QCT_PROPLIB); | 596 | KASSERT(args->qc_type == QCT_PROPLIB); | |
515 | cmddict = args->u.proplib.qc_cmddict; | 597 | cmddict = args->u.proplib.qc_cmddict; | |
516 | q2type = args->u.proplib.qc_q2type; | 598 | q2type = args->u.proplib.qc_q2type; | |
517 | datas = args->u.proplib.qc_datas; | 599 | datas = args->u.proplib.qc_datas; | |
518 | 600 | |||
519 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | 601 | KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); | |
520 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | 602 | KASSERT(prop_object_type(datas) == PROP_TYPE_ARRAY); | |
521 | 603 | |||
522 | if ((ump->um_flags & UFS_QUOTA2) != 0) | 604 | if ((ump->um_flags & UFS_QUOTA2) != 0) | |
523 | return EOPNOTSUPP; | 605 | return EOPNOTSUPP; | |
524 | 606 | |||
525 | if (prop_array_count(datas) != 0) | 607 | if (prop_array_count(datas) != 0) | |
526 | return EINVAL; | 608 | return EINVAL; | |
527 | 609 | |||
528 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | 610 | error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FS_QUOTA, | |
529 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | 611 | KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF, mp, NULL, NULL); | |
530 | if (error != 0) { | 612 | if (error != 0) { | |
531 | return error; | 613 | return error; | |
532 | } | 614 | } | |
533 | #ifdef QUOTA | 615 | #ifdef QUOTA | |
534 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); | 616 | error = quota1_handle_cmd_quotaoff(l, ump, q2type); | |
535 | #else | 617 | #else | |
536 | error = EOPNOTSUPP; | 618 | error = EOPNOTSUPP; | |
537 | #endif | 619 | #endif | |
538 | 620 | |||
539 | return error; | 621 | return error; | |
540 | } | 622 | } | |
541 | 623 | |||
542 | /* | 624 | /* | |
543 | * Initialize the quota system. | 625 | * Initialize the quota system. | |
544 | */ | 626 | */ | |
545 | void | 627 | void | |
546 | dqinit(void) | 628 | dqinit(void) | |
547 | { | 629 | { | |
548 | 630 | |||
549 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | 631 | mutex_init(&dqlock, MUTEX_DEFAULT, IPL_NONE); | |
550 | cv_init(&dqcv, "quota"); | 632 | cv_init(&dqcv, "quota"); | |
551 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); | 633 | dqhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &dqhash); | |
552 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", | 634 | dquot_cache = pool_cache_init(sizeof(struct dquot), 0, 0, 0, "ufsdq", | |
553 | NULL, IPL_NONE, NULL, NULL, NULL); | 635 | NULL, IPL_NONE, NULL, NULL, NULL); | |
554 | } | 636 | } | |
555 | 637 | |||
556 | void | 638 | void | |
557 | dqreinit(void) | 639 | dqreinit(void) | |
558 | { | 640 | { | |
559 | struct dquot *dq; | 641 | struct dquot *dq; | |
560 | struct dqhashhead *oldhash, *hash; | 642 | struct dqhashhead *oldhash, *hash; | |
561 | struct vnode *dqvp; | 643 | struct vnode *dqvp; | |
562 | u_long oldmask, mask, hashval; | 644 | u_long oldmask, mask, hashval; | |
563 | int i; | 645 | int i; | |
564 | 646 | |||
565 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); | 647 | hash = hashinit(desiredvnodes, HASH_LIST, true, &mask); | |
566 | mutex_enter(&dqlock); | 648 | mutex_enter(&dqlock); | |
567 | oldhash = dqhashtbl; | 649 | oldhash = dqhashtbl; | |
568 | oldmask = dqhash; | 650 | oldmask = dqhash; | |
569 | dqhashtbl = hash; | 651 | dqhashtbl = hash; | |
570 | dqhash = mask; | 652 | dqhash = mask; | |
571 | for (i = 0; i <= oldmask; i++) { | 653 | for (i = 0; i <= oldmask; i++) { | |
572 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { | 654 | while ((dq = LIST_FIRST(&oldhash[i])) != NULL) { | |
573 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; | 655 | dqvp = dq->dq_ump->um_quotas[dq->dq_type]; | |
574 | LIST_REMOVE(dq, dq_hash); | 656 | LIST_REMOVE(dq, dq_hash); | |
575 | hashval = DQHASH(dqvp, dq->dq_id); | 657 | hashval = DQHASH(dqvp, dq->dq_id); | |
576 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); | 658 | LIST_INSERT_HEAD(&dqhashtbl[hashval], dq, dq_hash); | |
577 | } | 659 | } | |
578 | } | 660 | } | |
579 | mutex_exit(&dqlock); | 661 | mutex_exit(&dqlock); | |
580 | hashdone(oldhash, HASH_LIST, oldmask); | 662 | hashdone(oldhash, HASH_LIST, oldmask); | |
581 | } | 663 | } | |
582 | 664 | |||
583 | /* | 665 | /* | |
584 | * Free resources held by quota system. | 666 | * Free resources held by quota system. | |
585 | */ | 667 | */ | |
586 | void | 668 | void | |
587 | dqdone(void) | 669 | dqdone(void) | |
588 | { | 670 | { | |
589 | 671 | |||
590 | pool_cache_destroy(dquot_cache); | 672 | pool_cache_destroy(dquot_cache); | |
591 | hashdone(dqhashtbl, HASH_LIST, dqhash); | 673 | hashdone(dqhashtbl, HASH_LIST, dqhash); | |
592 | cv_destroy(&dqcv); | 674 | cv_destroy(&dqcv); | |
593 | mutex_destroy(&dqlock); | 675 | mutex_destroy(&dqlock); | |
594 | } | 676 | } | |
595 | 677 | |||
596 | /* | 678 | /* | |
597 | * Set up the quotas for an inode. | 679 | * Set up the quotas for an inode. | |
598 | * | 680 | * | |
599 | * This routine completely defines the semantics of quotas. | 681 | * This routine completely defines the semantics of quotas. | |
600 | * If other criterion want to be used to establish quotas, the | 682 | * If other criterion want to be used to establish quotas, the | |
601 | * MAXQUOTAS value in quotas.h should be increased, and the | 683 | * MAXQUOTAS value in quotas.h should be increased, and the | |
602 | * additional dquots set up here. | 684 | * additional dquots set up here. | |
603 | */ | 685 | */ | |
604 | int | 686 | int | |
605 | getinoquota(struct inode *ip) | 687 | getinoquota(struct inode *ip) | |
606 | { | 688 | { | |
607 | struct ufsmount *ump = ip->i_ump; | 689 | struct ufsmount *ump = ip->i_ump; | |
608 | struct vnode *vp = ITOV(ip); | 690 | struct vnode *vp = ITOV(ip); | |
609 | int i, error; | 691 | int i, error; | |
610 | u_int32_t ino_ids[MAXQUOTAS]; | 692 | u_int32_t ino_ids[MAXQUOTAS]; | |
611 | 693 | |||
612 | /* | 694 | /* | |
613 | * To avoid deadlocks never update quotas for quota files | 695 | * To avoid deadlocks never update quotas for quota files | |
614 | * on the same file system | 696 | * on the same file system | |
615 | */ | 697 | */ | |
616 | for (i = 0; i < MAXQUOTAS; i++) | 698 | for (i = 0; i < MAXQUOTAS; i++) | |
617 | if (vp == ump->um_quotas[i]) | 699 | if (vp == ump->um_quotas[i]) | |
618 | return 0; | 700 | return 0; | |
619 | 701 | |||
620 | ino_ids[USRQUOTA] = ip->i_uid; | 702 | ino_ids[USRQUOTA] = ip->i_uid; | |
621 | ino_ids[GRPQUOTA] = ip->i_gid; | 703 | ino_ids[GRPQUOTA] = ip->i_gid; | |
622 | for (i = 0; i < MAXQUOTAS; i++) { | 704 | for (i = 0; i < MAXQUOTAS; i++) { | |
623 | /* | 705 | /* | |
624 | * If the file id changed the quota needs update. | 706 | * If the file id changed the quota needs update. | |
625 | */ | 707 | */ | |
626 | if (ip->i_dquot[i] != NODQUOT && | 708 | if (ip->i_dquot[i] != NODQUOT && | |
627 | ip->i_dquot[i]->dq_id != ino_ids[i]) { | 709 | ip->i_dquot[i]->dq_id != ino_ids[i]) { | |
628 | dqrele(ITOV(ip), ip->i_dquot[i]); | 710 | dqrele(ITOV(ip), ip->i_dquot[i]); | |
629 | ip->i_dquot[i] = NODQUOT; | 711 | ip->i_dquot[i] = NODQUOT; | |
630 | } | 712 | } | |
631 | /* | 713 | /* | |
632 | * Set up the quota based on file id. | 714 | * Set up the quota based on file id. | |
633 | * ENODEV means that quotas are not enabled. | 715 | * ENODEV means that quotas are not enabled. | |
634 | */ | 716 | */ | |
635 | if (ip->i_dquot[i] == NODQUOT && | 717 | if (ip->i_dquot[i] == NODQUOT && | |
636 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && | 718 | (error = dqget(vp, ino_ids[i], ump, i, &ip->i_dquot[i])) && | |
637 | error != ENODEV) | 719 | error != ENODEV) | |
638 | return (error); | 720 | return (error); | |
639 | } | 721 | } | |
640 | return 0; | 722 | return 0; | |
641 | } | 723 | } | |
642 | 724 | |||
643 | /* | 725 | /* | |
644 | * Obtain a dquot structure for the specified identifier and quota file | 726 | * Obtain a dquot structure for the specified identifier and quota file | |
645 | * reading the information from the file if necessary. | 727 | * reading the information from the file if necessary. | |
646 | */ | 728 | */ | |
647 | int | 729 | int | |
648 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, | 730 | dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, | |
649 | struct dquot **dqp) | 731 | struct dquot **dqp) | |
650 | { | 732 | { | |
651 | struct dquot *dq, *ndq; | 733 | struct dquot *dq, *ndq; | |
652 | struct dqhashhead *dqh; | 734 | struct dqhashhead *dqh; | |
653 | struct vnode *dqvp; | 735 | struct vnode *dqvp; | |
654 | int error = 0; /* XXX gcc */ | 736 | int error = 0; /* XXX gcc */ | |
655 | 737 | |||
656 | /* Lock to see an up to date value for QTF_CLOSING. */ | 738 | /* Lock to see an up to date value for QTF_CLOSING. */ | |
657 | mutex_enter(&dqlock); | 739 | mutex_enter(&dqlock); | |
658 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { | 740 | if ((ump->um_flags & (UFS_QUOTA|UFS_QUOTA2)) == 0) { | |
659 | mutex_exit(&dqlock); | 741 | mutex_exit(&dqlock); | |
660 | *dqp = NODQUOT; | 742 | *dqp = NODQUOT; | |
661 | return (ENODEV); | 743 | return (ENODEV); | |
662 | } | 744 | } | |
663 | dqvp = ump->um_quotas[type]; | 745 | dqvp = ump->um_quotas[type]; | |
664 | #ifdef QUOTA | 746 | #ifdef QUOTA | |
665 | if (ump->um_flags & UFS_QUOTA) { | 747 | if (ump->um_flags & UFS_QUOTA) { | |
666 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { | 748 | if (dqvp == NULLVP || (ump->umq1_qflags[type] & QTF_CLOSING)) { | |
667 | mutex_exit(&dqlock); | 749 | mutex_exit(&dqlock); | |
668 | *dqp = NODQUOT; | 750 | *dqp = NODQUOT; | |
669 | return (ENODEV); | 751 | return (ENODEV); | |
670 | } | 752 | } | |
671 | } | 753 | } | |
672 | #endif | 754 | #endif | |
673 | #ifdef QUOTA2 | 755 | #ifdef QUOTA2 | |
674 | if (ump->um_flags & UFS_QUOTA2) { | 756 | if (ump->um_flags & UFS_QUOTA2) { | |
675 | if (dqvp == NULLVP) { | 757 | if (dqvp == NULLVP) { | |
676 | mutex_exit(&dqlock); | 758 | mutex_exit(&dqlock); | |
677 | *dqp = NODQUOT; | 759 | *dqp = NODQUOT; | |
678 | return (ENODEV); | 760 | return (ENODEV); | |
679 | } | 761 | } | |
680 | } | 762 | } | |
681 | #endif | 763 | #endif | |
682 | KASSERT(dqvp != vp); | 764 | KASSERT(dqvp != vp); | |
683 | /* | 765 | /* | |
684 | * Check the cache first. | 766 | * Check the cache first. | |
685 | */ | 767 | */ | |
686 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | 768 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | |
687 | LIST_FOREACH(dq, dqh, dq_hash) { | 769 | LIST_FOREACH(dq, dqh, dq_hash) { | |
688 | if (dq->dq_id != id || | 770 | if (dq->dq_id != id || | |
689 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | 771 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | |
690 | continue; | 772 | continue; | |
691 | KASSERT(dq->dq_cnt > 0); | 773 | KASSERT(dq->dq_cnt > 0); | |
692 | dqref(dq); | 774 | dqref(dq); | |
693 | mutex_exit(&dqlock); | 775 | mutex_exit(&dqlock); | |
694 | *dqp = dq; | 776 | *dqp = dq; | |
695 | return (0); | 777 | return (0); | |
696 | } | 778 | } | |
697 | /* | 779 | /* | |
698 | * Not in cache, allocate a new one. | 780 | * Not in cache, allocate a new one. | |
699 | */ | 781 | */ | |
700 | mutex_exit(&dqlock); | 782 | mutex_exit(&dqlock); | |
701 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); | 783 | ndq = pool_cache_get(dquot_cache, PR_WAITOK); | |
702 | /* | 784 | /* | |
703 | * Initialize the contents of the dquot structure. | 785 | * Initialize the contents of the dquot structure. | |
704 | */ | 786 | */ | |
705 | memset((char *)ndq, 0, sizeof *ndq); | 787 | memset((char *)ndq, 0, sizeof *ndq); | |
706 | ndq->dq_flags = 0; | 788 | ndq->dq_flags = 0; | |
707 | ndq->dq_id = id; | 789 | ndq->dq_id = id; | |
708 | ndq->dq_ump = ump; | 790 | ndq->dq_ump = ump; | |
709 | ndq->dq_type = type; | 791 | ndq->dq_type = type; | |
710 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); | 792 | mutex_init(&ndq->dq_interlock, MUTEX_DEFAULT, IPL_NONE); | |
711 | mutex_enter(&dqlock); | 793 | mutex_enter(&dqlock); | |
712 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | 794 | dqh = &dqhashtbl[DQHASH(dqvp, id)]; | |
713 | LIST_FOREACH(dq, dqh, dq_hash) { | 795 | LIST_FOREACH(dq, dqh, dq_hash) { | |
714 | if (dq->dq_id != id || | 796 | if (dq->dq_id != id || | |
715 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | 797 | dq->dq_ump->um_quotas[dq->dq_type] != dqvp) | |
716 | continue; | 798 | continue; | |
717 | /* | 799 | /* | |
718 | * Another thread beat us allocating this dquot. | 800 | * Another thread beat us allocating this dquot. | |
719 | */ | 801 | */ | |
720 | KASSERT(dq->dq_cnt > 0); | 802 | KASSERT(dq->dq_cnt > 0); | |
721 | dqref(dq); | 803 | dqref(dq); | |
722 | mutex_exit(&dqlock); | 804 | mutex_exit(&dqlock); | |
723 | mutex_destroy(&ndq->dq_interlock); | 805 | mutex_destroy(&ndq->dq_interlock); | |
724 | pool_cache_put(dquot_cache, ndq); | 806 | pool_cache_put(dquot_cache, ndq); | |
725 | *dqp = dq; | 807 | *dqp = dq; | |
726 | return 0; | 808 | return 0; | |
727 | } | 809 | } | |
728 | dq = ndq; | 810 | dq = ndq; | |
729 | LIST_INSERT_HEAD(dqh, dq, dq_hash); | 811 | LIST_INSERT_HEAD(dqh, dq, dq_hash); | |
730 | dqref(dq); | 812 | dqref(dq); | |
731 | mutex_enter(&dq->dq_interlock); | 813 | mutex_enter(&dq->dq_interlock); | |
732 | mutex_exit(&dqlock); | 814 | mutex_exit(&dqlock); | |
733 | #ifdef QUOTA | 815 | #ifdef QUOTA | |
734 | if (ump->um_flags & UFS_QUOTA) | 816 | if (ump->um_flags & UFS_QUOTA) | |
735 | error = dq1get(dqvp, id, ump, type, dq); | 817 | error = dq1get(dqvp, id, ump, type, dq); | |
736 | #endif | 818 | #endif | |
737 | #ifdef QUOTA2 | 819 | #ifdef QUOTA2 | |
738 | if (ump->um_flags & UFS_QUOTA2) | 820 | if (ump->um_flags & UFS_QUOTA2) | |
739 | error = dq2get(dqvp, id, ump, type, dq); | 821 | error = dq2get(dqvp, id, ump, type, dq); | |
740 | #endif | 822 | #endif | |
741 | /* | 823 | /* | |
742 | * I/O error in reading quota file, release | 824 | * I/O error in reading quota file, release | |
743 | * quota structure and reflect problem to caller. | 825 | * quota structure and reflect problem to caller. | |
744 | */ | 826 | */ | |
745 | if (error) { | 827 | if (error) { | |
746 | mutex_enter(&dqlock); | 828 | mutex_enter(&dqlock); | |
747 | LIST_REMOVE(dq, dq_hash); | 829 | LIST_REMOVE(dq, dq_hash); | |
748 | mutex_exit(&dqlock); | 830 | mutex_exit(&dqlock); | |
749 | mutex_exit(&dq->dq_interlock); | 831 | mutex_exit(&dq->dq_interlock); | |
750 | dqrele(vp, dq); | 832 | dqrele(vp, dq); | |
751 | *dqp = NODQUOT; | 833 | *dqp = NODQUOT; | |
752 | return (error); | 834 | return (error); | |
753 | } | 835 | } | |
754 | mutex_exit(&dq->dq_interlock); | 836 | mutex_exit(&dq->dq_interlock); | |
755 | *dqp = dq; | 837 | *dqp = dq; | |
756 | return (0); | 838 | return (0); | |
757 | } | 839 | } | |
758 | 840 | |||
759 | /* | 841 | /* | |
760 | * Obtain a reference to a dquot. | 842 | * Obtain a reference to a dquot. | |
761 | */ | 843 | */ | |
762 | void | 844 | void | |
763 | dqref(struct dquot *dq) | 845 | dqref(struct dquot *dq) | |
764 | { | 846 | { | |
765 | 847 | |||
766 | KASSERT(mutex_owned(&dqlock)); | 848 | KASSERT(mutex_owned(&dqlock)); | |
767 | dq->dq_cnt++; | 849 | dq->dq_cnt++; | |
768 | KASSERT(dq->dq_cnt > 0); | 850 | KASSERT(dq->dq_cnt > 0); | |
769 | } | 851 | } | |
770 | 852 | |||
771 | /* | 853 | /* | |
772 | * Release a reference to a dquot. | 854 | * Release a reference to a dquot. | |
773 | */ | 855 | */ | |
774 | void | 856 | void | |
775 | dqrele(struct vnode *vp, struct dquot *dq) | 857 | dqrele(struct vnode *vp, struct dquot *dq) | |
776 | { | 858 | { | |
777 | 859 | |||
778 | if (dq == NODQUOT) | 860 | if (dq == NODQUOT) | |
779 | return; | 861 | return; | |
780 | mutex_enter(&dq->dq_interlock); | 862 | mutex_enter(&dq->dq_interlock); | |
781 | for (;;) { | 863 | for (;;) { | |
782 | mutex_enter(&dqlock); | 864 | mutex_enter(&dqlock); | |
783 | if (dq->dq_cnt > 1) { | 865 | if (dq->dq_cnt > 1) { | |
784 | dq->dq_cnt--; | 866 | dq->dq_cnt--; | |
785 | mutex_exit(&dqlock); | 867 | mutex_exit(&dqlock); | |
786 | mutex_exit(&dq->dq_interlock); | 868 | mutex_exit(&dq->dq_interlock); | |
787 | return; | 869 | return; | |
788 | } | 870 | } | |
789 | if ((dq->dq_flags & DQ_MOD) == 0) | 871 | if ((dq->dq_flags & DQ_MOD) == 0) | |
790 | break; | 872 | break; | |
791 | mutex_exit(&dqlock); | 873 | mutex_exit(&dqlock); | |
792 | #ifdef QUOTA | 874 | #ifdef QUOTA | |
793 | if (dq->dq_ump->um_flags & UFS_QUOTA) | 875 | if (dq->dq_ump->um_flags & UFS_QUOTA) | |
794 | (void) dq1sync(vp, dq); | 876 | (void) dq1sync(vp, dq); | |
795 | #endif | 877 | #endif | |
796 | #ifdef QUOTA2 | 878 | #ifdef QUOTA2 | |
797 | if (dq->dq_ump->um_flags & UFS_QUOTA2) | 879 | if (dq->dq_ump->um_flags & UFS_QUOTA2) | |
798 | (void) dq2sync(vp, dq); | 880 | (void) dq2sync(vp, dq); | |
799 | #endif | 881 | #endif | |
800 | } | 882 | } | |
801 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); | 883 | KASSERT(dq->dq_cnt == 1 && (dq->dq_flags & DQ_MOD) == 0); | |
802 | LIST_REMOVE(dq, dq_hash); | 884 | LIST_REMOVE(dq, dq_hash); | |
803 | mutex_exit(&dqlock); | 885 | mutex_exit(&dqlock); | |
804 | mutex_exit(&dq->dq_interlock); | 886 | mutex_exit(&dq->dq_interlock); | |
805 | mutex_destroy(&dq->dq_interlock); | 887 | mutex_destroy(&dq->dq_interlock); | |
806 | pool_cache_put(dquot_cache, dq); | 888 | pool_cache_put(dquot_cache, dq); | |
807 | } | 889 | } | |
808 | 890 | |||
809 | int | 891 | int | |
810 | qsync(struct mount *mp) | 892 | qsync(struct mount *mp) | |
811 | { | 893 | { | |
812 | struct ufsmount *ump = VFSTOUFS(mp); | 894 | struct ufsmount *ump = VFSTOUFS(mp); | |
813 | #ifdef QUOTA | 895 | #ifdef QUOTA | |
814 | if (ump->um_flags & UFS_QUOTA) | 896 | if (ump->um_flags & UFS_QUOTA) | |
815 | return q1sync(mp); | 897 | return q1sync(mp); | |
816 | #endif | 898 | #endif | |
817 | #ifdef QUOTA2 | 899 | #ifdef QUOTA2 | |
818 | if (ump->um_flags & UFS_QUOTA2) | 900 | if (ump->um_flags & UFS_QUOTA2) | |
819 | return q2sync(mp); | 901 | return q2sync(mp); | |
820 | #endif | 902 | #endif | |
821 | return 0; | 903 | return 0; | |
822 | } | 904 | } | |
823 | 905 | |||
824 | #ifdef DIAGNOSTIC | 906 | #ifdef DIAGNOSTIC | |
825 | /* | 907 | /* | |
826 | * Check the hash chains for stray dquot's. | 908 | * Check the hash chains for stray dquot's. | |
827 | */ | 909 | */ | |
828 | void | 910 | void | |
829 | dqflush(struct vnode *vp) | 911 | dqflush(struct vnode *vp) | |
830 | { | 912 | { | |
831 | struct dquot *dq; | 913 | struct dquot *dq; | |
832 | int i; | 914 | int i; | |
833 | 915 | |||
834 | mutex_enter(&dqlock); | 916 | mutex_enter(&dqlock); | |
835 | for (i = 0; i <= dqhash; i++) | 917 | for (i = 0; i <= dqhash; i++) | |
836 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) | 918 | LIST_FOREACH(dq, &dqhashtbl[i], dq_hash) | |
837 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); | 919 | KASSERT(dq->dq_ump->um_quotas[dq->dq_type] != vp); | |
838 | mutex_exit(&dqlock); | 920 | mutex_exit(&dqlock); | |
839 | } | 921 | } | |
840 | #endif | 922 | #endif |
--- src/sys/ufs/ufs/ufs_quota.h 2012/01/29 07:08:58 1.19
+++ src/sys/ufs/ufs/ufs_quota.h 2012/01/29 07:09:52 1.20
@@ -1,140 +1,145 @@ | @@ -1,140 +1,145 @@ | |||
1 | /* $NetBSD: ufs_quota.h,v 1.19 2012/01/29 07:08:58 dholland Exp $ */ | 1 | /* $NetBSD: ufs_quota.h,v 1.20 2012/01/29 07:09:52 dholland Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | 4 | * Copyright (c) 1982, 1986, 1990, 1993, 1995 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to Berkeley by | 7 | * This code is derived from software contributed to Berkeley by | |
8 | * Robert Elz at The University of Melbourne. | 8 | * Robert Elz at The University of Melbourne. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. Neither the name of the University nor the names of its contributors | 18 | * 3. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | 32 | * SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | 34 | * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 | |
35 | */ | 35 | */ | |
36 | #include <ufs/ufs/quota1.h> | 36 | #include <ufs/ufs/quota1.h> | |
37 | #include <ufs/ufs/quota2.h> | 37 | #include <ufs/ufs/quota2.h> | |
38 | 38 | |||
39 | struct quotakcursor; /* from <sys/quotactl.h> */ | 39 | struct quotakcursor; /* from <sys/quotactl.h> */ | |
40 | 40 | |||
41 | 41 | |||
42 | /* link to this quota in the quota inode (for QUOTA2) */ | 42 | /* link to this quota in the quota inode (for QUOTA2) */ | |
43 | struct dq2_desc { | 43 | struct dq2_desc { | |
44 | uint64_t dq2_lblkno; /* logical disk block holding this quota */ | 44 | uint64_t dq2_lblkno; /* logical disk block holding this quota */ | |
45 | u_int dq2_blkoff; /* offset in disk block holding this quota */ | 45 | u_int dq2_blkoff; /* offset in disk block holding this quota */ | |
46 | }; | 46 | }; | |
47 | 47 | |||
48 | /* | 48 | /* | |
49 | * The following structure records disk usage for a user or group on a | 49 | * The following structure records disk usage for a user or group on a | |
50 | * filesystem. There is one allocated for each quota that exists on any | 50 | * filesystem. There is one allocated for each quota that exists on any | |
51 | * filesystem for the current user or group. A cache is kept of recently | 51 | * filesystem for the current user or group. A cache is kept of recently | |
52 | * used entries. | 52 | * used entries. | |
53 | * Field markings and the corresponding locks: | 53 | * Field markings and the corresponding locks: | |
54 | * h: dqlock | 54 | * h: dqlock | |
55 | * d: dq_interlock | 55 | * d: dq_interlock | |
56 | * | 56 | * | |
57 | * Lock order is: dq_interlock -> dqlock | 57 | * Lock order is: dq_interlock -> dqlock | |
58 | * dq_interlock -> dqvp | 58 | * dq_interlock -> dqvp | |
59 | */ | 59 | */ | |
60 | struct dquot { | 60 | struct dquot { | |
61 | LIST_ENTRY(dquot) dq_hash; /* h: hash list */ | 61 | LIST_ENTRY(dquot) dq_hash; /* h: hash list */ | |
62 | u_int16_t dq_flags; /* d: flags, see below */ | 62 | u_int16_t dq_flags; /* d: flags, see below */ | |
63 | u_int16_t dq_type; /* d: quota type of this dquot */ | 63 | u_int16_t dq_type; /* d: quota type of this dquot */ | |
64 | u_int32_t dq_cnt; /* h: count of active references */ | 64 | u_int32_t dq_cnt; /* h: count of active references */ | |
65 | u_int32_t dq_id; /* d: identifier this applies to */ | 65 | u_int32_t dq_id; /* d: identifier this applies to */ | |
66 | struct ufsmount *dq_ump; /* d: filesystem this is taken from */ | 66 | struct ufsmount *dq_ump; /* d: filesystem this is taken from */ | |
67 | kmutex_t dq_interlock; /* d: lock this dquot */ | 67 | kmutex_t dq_interlock; /* d: lock this dquot */ | |
68 | union { | 68 | union { | |
69 | struct dqblk dq1_dqb; /* d: actual usage & quotas */ | 69 | struct dqblk dq1_dqb; /* d: actual usage & quotas */ | |
70 | struct dq2_desc dq2_desc; /* d: pointer to quota data */ | 70 | struct dq2_desc dq2_desc; /* d: pointer to quota data */ | |
71 | } dq_un; | 71 | } dq_un; | |
72 | }; | 72 | }; | |
73 | 73 | |||
74 | /* | 74 | /* | |
75 | * Flag values. | 75 | * Flag values. | |
76 | */ | 76 | */ | |
77 | #define DQ_MOD 0x04 /* this quota modified since read */ | 77 | #define DQ_MOD 0x04 /* this quota modified since read */ | |
78 | #define DQ_FAKE 0x08 /* no limits here, just usage */ | 78 | #define DQ_FAKE 0x08 /* no limits here, just usage */ | |
79 | #define DQ_WARN(ltype) (0x10 << ltype) /* has been warned about "type" limit */ | 79 | #define DQ_WARN(ltype) (0x10 << ltype) /* has been warned about "type" limit */ | |
80 | /* | 80 | /* | |
81 | * Shorthand notation. | 81 | * Shorthand notation. | |
82 | */ | 82 | */ | |
83 | #define dq_bhardlimit dq_un.dq1_dqb.dqb_bhardlimit | 83 | #define dq_bhardlimit dq_un.dq1_dqb.dqb_bhardlimit | |
84 | #define dq_bsoftlimit dq_un.dq1_dqb.dqb_bsoftlimit | 84 | #define dq_bsoftlimit dq_un.dq1_dqb.dqb_bsoftlimit | |
85 | #define dq_curblocks dq_un.dq1_dqb.dqb_curblocks | 85 | #define dq_curblocks dq_un.dq1_dqb.dqb_curblocks | |
86 | #define dq_ihardlimit dq_un.dq1_dqb.dqb_ihardlimit | 86 | #define dq_ihardlimit dq_un.dq1_dqb.dqb_ihardlimit | |
87 | #define dq_isoftlimit dq_un.dq1_dqb.dqb_isoftlimit | 87 | #define dq_isoftlimit dq_un.dq1_dqb.dqb_isoftlimit | |
88 | #define dq_curinodes dq_un.dq1_dqb.dqb_curinodes | 88 | #define dq_curinodes dq_un.dq1_dqb.dqb_curinodes | |
89 | #define dq_btime dq_un.dq1_dqb.dqb_btime | 89 | #define dq_btime dq_un.dq1_dqb.dqb_btime | |
90 | #define dq_itime dq_un.dq1_dqb.dqb_itime | 90 | #define dq_itime dq_un.dq1_dqb.dqb_itime | |
91 | 91 | |||
92 | #define dq2_lblkno dq_un.dq2_desc.dq2_lblkno | 92 | #define dq2_lblkno dq_un.dq2_desc.dq2_lblkno | |
93 | #define dq2_blkoff dq_un.dq2_desc.dq2_blkoff | 93 | #define dq2_blkoff dq_un.dq2_desc.dq2_blkoff | |
94 | /* | 94 | /* | |
95 | * If the system has never checked for a quota for this file, then it is | 95 | * If the system has never checked for a quota for this file, then it is | |
96 | * set to NODQUOT. Once a write attempt is made the inode pointer is set | 96 | * set to NODQUOT. Once a write attempt is made the inode pointer is set | |
97 | * to reference a dquot structure. | 97 | * to reference a dquot structure. | |
98 | */ | 98 | */ | |
99 | #define NODQUOT NULL | 99 | #define NODQUOT NULL | |
100 | 100 | |||
101 | extern kmutex_t dqlock; | 101 | extern kmutex_t dqlock; | |
102 | extern kcondvar_t dqcv; | 102 | extern kcondvar_t dqcv; | |
103 | /* | 103 | /* | |
104 | * Quota name to error message mapping. | 104 | * Quota name to error message mapping. | |
105 | */ | 105 | */ | |
106 | const char *quotatypes[MAXQUOTAS]; | 106 | const char *quotatypes[MAXQUOTAS]; | |
107 | 107 | |||
108 | int getinoquota(struct inode *); | 108 | int getinoquota(struct inode *); | |
109 | int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **); | 109 | int dqget(struct vnode *, u_long, struct ufsmount *, int, struct dquot **); | |
110 | void dqref(struct dquot *); | 110 | void dqref(struct dquot *); | |
111 | void dqrele(struct vnode *, struct dquot *); | 111 | void dqrele(struct vnode *, struct dquot *); | |
112 | void dqflush(struct vnode *); | 112 | void dqflush(struct vnode *); | |
113 | 113 | |||
114 | int chkdq1(struct inode *, int64_t, kauth_cred_t, int); | 114 | int chkdq1(struct inode *, int64_t, kauth_cred_t, int); | |
115 | int chkiq1(struct inode *, int32_t, kauth_cred_t, int); | 115 | int chkiq1(struct inode *, int32_t, kauth_cred_t, int); | |
116 | int q1sync(struct mount *); | 116 | int q1sync(struct mount *); | |
117 | int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | 117 | int dq1get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | |
118 | int dq1sync(struct vnode *, struct dquot *); | 118 | int dq1sync(struct vnode *, struct dquot *); | |
119 | int quota1_handle_cmd_get(struct ufsmount *, const struct quotakey *, | 119 | int quota1_handle_cmd_get(struct ufsmount *, const struct quotakey *, | |
120 | struct quotaval *); | 120 | struct quotaval *); | |
121 | int quota1_handle_cmd_put(struct ufsmount *, const struct quotakey *, | 121 | int quota1_handle_cmd_put(struct ufsmount *, const struct quotakey *, | |
122 | const struct quotaval *); | 122 | const struct quotaval *); | |
123 | int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int, | 123 | int quota1_handle_cmd_quotaon(struct lwp *, struct ufsmount *, int, | |
124 | const char *); | 124 | const char *); | |
125 | int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int); | 125 | int quota1_handle_cmd_quotaoff(struct lwp *, struct ufsmount *, int); | |
126 | 126 | |||
127 | int chkdq2(struct inode *, int64_t, kauth_cred_t, int); | 127 | int chkdq2(struct inode *, int64_t, kauth_cred_t, int); | |
128 | int chkiq2(struct inode *, int32_t, kauth_cred_t, int); | 128 | int chkiq2(struct inode *, int32_t, kauth_cred_t, int); | |
129 | int quota2_handle_cmd_get(struct ufsmount *, const struct quotakey *, | 129 | int quota2_handle_cmd_get(struct ufsmount *, const struct quotakey *, | |
130 | struct quotaval *); | 130 | struct quotaval *); | |
131 | int quota2_handle_cmd_put(struct ufsmount *, const struct quotakey *, | 131 | int quota2_handle_cmd_put(struct ufsmount *, const struct quotakey *, | |
132 | const struct quotaval *); | 132 | const struct quotaval *); | |
133 | int quota2_handle_cmd_delete(struct ufsmount *, const struct quotakey *); | 133 | int quota2_handle_cmd_delete(struct ufsmount *, const struct quotakey *); | |
134 | int quota2_handle_cmd_getall(struct ufsmount *, struct quotakcursor *, | 134 | int quota2_handle_cmd_cursorget(struct ufsmount *, struct quotakcursor *, | |
135 | struct quotakey *, struct quotaval *, unsigned, unsigned *); | 135 | struct quotakey *, struct quotaval *, unsigned, unsigned *); | |
136 | int quota2_handle_cmd_cursoropen(struct ufsmount *, struct quotakcursor *); | 136 | int quota2_handle_cmd_cursoropen(struct ufsmount *, struct quotakcursor *); | |
137 | int quota2_handle_cmd_cursorclose(struct ufsmount *, struct quotakcursor *); | 137 | int quota2_handle_cmd_cursorclose(struct ufsmount *, struct quotakcursor *); | |
138 | int quota2_handle_cmd_cursorskipidtype(struct ufsmount *, struct quotakcursor *, | |||
139 | int); | |||
140 | int quota2_handle_cmd_cursoratend(struct ufsmount *, struct quotakcursor *, | |||
141 | int *); | |||
142 | int quota2_handle_cmd_cursorrewind(struct ufsmount *, struct quotakcursor *); | |||
138 | int q2sync(struct mount *); | 143 | int q2sync(struct mount *); | |
139 | int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | 144 | int dq2get(struct vnode *, u_long, struct ufsmount *, int, struct dquot *); | |
140 | int dq2sync(struct vnode *, struct dquot *); | 145 | int dq2sync(struct vnode *, struct dquot *); |
--- src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:08:58 1.25
+++ src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:09:52 1.26
@@ -1,1349 +1,1417 @@ | @@ -1,1349 +1,1417 @@ | |||
1 | /* $NetBSD: ufs_quota2.c,v 1.25 2012/01/29 07:08:58 dholland Exp $ */ | 1 | /* $NetBSD: ufs_quota2.c,v 1.26 2012/01/29 07:09:52 dholland Exp $ */ | |
2 | /*- | 2 | /*- | |
3 | * Copyright (c) 2010 Manuel Bouyer | 3 | * Copyright (c) 2010 Manuel Bouyer | |
4 | * All rights reserved. | 4 | * All rights reserved. | |
5 | * | 5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | 7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | 8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | 9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | 10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | 11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | 12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | 13 | * documentation and/or other materials provided with the distribution. | |
14 | * | 14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 15 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
16 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 16 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
17 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 17 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
18 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 18 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
19 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 19 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
25 | * POSSIBILITY OF SUCH DAMAGE. | 25 | * POSSIBILITY OF SUCH DAMAGE. | |
26 | */ | 26 | */ | |
27 | 27 | |||
28 | #include <sys/cdefs.h> | 28 | #include <sys/cdefs.h> | |
29 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.25 2012/01/29 07:08:58 dholland Exp $"); | 29 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.26 2012/01/29 07:09:52 dholland Exp $"); | |
30 | 30 | |||
31 | #include <sys/buf.h> | 31 | #include <sys/buf.h> | |
32 | #include <sys/param.h> | 32 | #include <sys/param.h> | |
33 | #include <sys/kernel.h> | 33 | #include <sys/kernel.h> | |
34 | #include <sys/systm.h> | 34 | #include <sys/systm.h> | |
35 | #include <sys/malloc.h> | 35 | #include <sys/malloc.h> | |
36 | #include <sys/namei.h> | 36 | #include <sys/namei.h> | |
37 | #include <sys/file.h> | 37 | #include <sys/file.h> | |
38 | #include <sys/proc.h> | 38 | #include <sys/proc.h> | |
39 | #include <sys/vnode.h> | 39 | #include <sys/vnode.h> | |
40 | #include <sys/mount.h> | 40 | #include <sys/mount.h> | |
41 | #include <sys/fstrans.h> | 41 | #include <sys/fstrans.h> | |
42 | #include <sys/kauth.h> | 42 | #include <sys/kauth.h> | |
43 | #include <sys/wapbl.h> | 43 | #include <sys/wapbl.h> | |
44 | #include <sys/quota.h> | 44 | #include <sys/quota.h> | |
45 | #include <sys/quotactl.h> | 45 | #include <sys/quotactl.h> | |
46 | 46 | |||
47 | #include <ufs/ufs/quota2.h> | 47 | #include <ufs/ufs/quota2.h> | |
48 | #include <ufs/ufs/inode.h> | 48 | #include <ufs/ufs/inode.h> | |
49 | #include <ufs/ufs/ufsmount.h> | 49 | #include <ufs/ufs/ufsmount.h> | |
50 | #include <ufs/ufs/ufs_bswap.h> | 50 | #include <ufs/ufs/ufs_bswap.h> | |
51 | #include <ufs/ufs/ufs_extern.h> | 51 | #include <ufs/ufs/ufs_extern.h> | |
52 | #include <ufs/ufs/ufs_quota.h> | 52 | #include <ufs/ufs/ufs_quota.h> | |
53 | #include <ufs/ufs/ufs_wapbl.h> | 53 | #include <ufs/ufs/ufs_wapbl.h> | |
54 | #include <quota/quotaprop.h> | 54 | #include <quota/quotaprop.h> | |
55 | 55 | |||
56 | /* | 56 | /* | |
57 | * LOCKING: | 57 | * LOCKING: | |
58 | * Data in the entries are protected by the associated struct dquot's | 58 | * Data in the entries are protected by the associated struct dquot's | |
59 | * dq_interlock (this means we can't read or change a quota entry without | 59 | * dq_interlock (this means we can't read or change a quota entry without | |
60 | * grabing a dquot for it). | 60 | * grabing a dquot for it). | |
61 | * The header and lists (including pointers in the data entries, and q2e_uid) | 61 | * The header and lists (including pointers in the data entries, and q2e_uid) | |
62 | * are protected by the global dqlock. | 62 | * are protected by the global dqlock. | |
63 | * the locking order is dq_interlock -> dqlock | 63 | * the locking order is dq_interlock -> dqlock | |
64 | */ | 64 | */ | |
65 | 65 | |||
66 | static int quota2_bwrite(struct mount *, struct buf *); | 66 | static int quota2_bwrite(struct mount *, struct buf *); | |
67 | static int getinoquota2(struct inode *, bool, bool, struct buf **, | 67 | static int getinoquota2(struct inode *, bool, bool, struct buf **, | |
68 | struct quota2_entry **); | 68 | struct quota2_entry **); | |
69 | static int getq2h(struct ufsmount *, int, struct buf **, | 69 | static int getq2h(struct ufsmount *, int, struct buf **, | |
70 | struct quota2_header **, int); | 70 | struct quota2_header **, int); | |
71 | static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **, | 71 | static int getq2e(struct ufsmount *, int, daddr_t, int, struct buf **, | |
72 | struct quota2_entry **, int); | 72 | struct quota2_entry **, int); | |
73 | static int quota2_walk_list(struct ufsmount *, struct buf *, int, | 73 | static int quota2_walk_list(struct ufsmount *, struct buf *, int, | |
74 | uint64_t *, int, void *, | 74 | uint64_t *, int, void *, | |
75 | int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, | 75 | int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, | |
76 | uint64_t, void *)); | 76 | uint64_t, void *)); | |
77 | 77 | |||
78 | #if 0 | 78 | #if 0 | |
79 | static prop_dictionary_t q2etoprop(struct quota2_entry *, int); | 79 | static prop_dictionary_t q2etoprop(struct quota2_entry *, int); | |
80 | #endif | 80 | #endif | |
81 | 81 | |||
82 | static const char *limnames[] = INITQLNAMES; | 82 | static const char *limnames[] = INITQLNAMES; | |
83 | 83 | |||
84 | static void | 84 | static void | |
85 | quota2_dict_update_q2e_limits(int objtype, const struct quotaval *val, | 85 | quota2_dict_update_q2e_limits(int objtype, const struct quotaval *val, | |
86 | struct quota2_entry *q2e) | 86 | struct quota2_entry *q2e) | |
87 | { | 87 | { | |
88 | /* make sure we can index q2e_val[] by the fs-independent objtype */ | 88 | /* make sure we can index q2e_val[] by the fs-independent objtype */ | |
89 | CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK); | 89 | CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK); | |
90 | CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE); | 90 | CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE); | |
91 | 91 | |||
92 | q2e->q2e_val[objtype].q2v_hardlimit = val->qv_hardlimit; | 92 | q2e->q2e_val[objtype].q2v_hardlimit = val->qv_hardlimit; | |
93 | q2e->q2e_val[objtype].q2v_softlimit = val->qv_softlimit; | 93 | q2e->q2e_val[objtype].q2v_softlimit = val->qv_softlimit; | |
94 | q2e->q2e_val[objtype].q2v_grace = val->qv_grace; | 94 | q2e->q2e_val[objtype].q2v_grace = val->qv_grace; | |
95 | } | 95 | } | |
96 | 96 | |||
97 | #if 0 | 97 | #if 0 | |
98 | static prop_dictionary_t | 98 | static prop_dictionary_t | |
99 | q2etoprop(struct quota2_entry *q2e, int def) | 99 | q2etoprop(struct quota2_entry *q2e, int def) | |
100 | { | 100 | { | |
101 | const char *val_names[] = INITQVNAMES_ALL; | 101 | const char *val_names[] = INITQVNAMES_ALL; | |
102 | prop_dictionary_t dict1 = prop_dictionary_create(); | 102 | prop_dictionary_t dict1 = prop_dictionary_create(); | |
103 | prop_dictionary_t dict2; | 103 | prop_dictionary_t dict2; | |
104 | int i; | 104 | int i; | |
105 | 105 | |||
106 | if (dict1 == NULL) | 106 | if (dict1 == NULL) | |
107 | return NULL; | 107 | return NULL; | |
108 | 108 | |||
109 | if (def) { | 109 | if (def) { | |
110 | if (!prop_dictionary_set_cstring_nocopy(dict1, "id", | 110 | if (!prop_dictionary_set_cstring_nocopy(dict1, "id", | |
111 | "default")) { | 111 | "default")) { | |
112 | goto err; | 112 | goto err; | |
113 | } | 113 | } | |
114 | } else { | 114 | } else { | |
115 | if (!prop_dictionary_set_uint32(dict1, "id", q2e->q2e_uid)) { | 115 | if (!prop_dictionary_set_uint32(dict1, "id", q2e->q2e_uid)) { | |
116 | goto err; | 116 | goto err; | |
117 | } | 117 | } | |
118 | } | 118 | } | |
119 | for (i = 0; i < N_QL; i++) { | 119 | for (i = 0; i < N_QL; i++) { | |
120 | dict2 = limits64toprop(&q2e->q2e_val[i].q2v_hardlimit, | 120 | dict2 = limits64toprop(&q2e->q2e_val[i].q2v_hardlimit, | |
121 | val_names, N_QV); | 121 | val_names, N_QV); | |
122 | if (dict2 == NULL) | 122 | if (dict2 == NULL) | |
123 | goto err; | 123 | goto err; | |
124 | if (!prop_dictionary_set_and_rel(dict1, limnames[i], dict2)) | 124 | if (!prop_dictionary_set_and_rel(dict1, limnames[i], dict2)) | |
125 | goto err; | 125 | goto err; | |
126 | } | 126 | } | |
127 | return dict1; | 127 | return dict1; | |
128 | 128 | |||
129 | err: | 129 | err: | |
130 | prop_object_release(dict1); | 130 | prop_object_release(dict1); | |
131 | return NULL; | 131 | return NULL; | |
132 | } | 132 | } | |
133 | #endif | 133 | #endif | |
134 | 134 | |||
135 | /* | 135 | /* | |
136 | * Convert internal representation to FS-independent representation. | 136 | * Convert internal representation to FS-independent representation. | |
137 | * (Note that while the two types are currently identical, the | 137 | * (Note that while the two types are currently identical, the | |
138 | * internal representation is an on-disk struct and the FS-independent | 138 | * internal representation is an on-disk struct and the FS-independent | |
139 | * representation is not, and they might diverge in the future.) | 139 | * representation is not, and they might diverge in the future.) | |
140 | */ | 140 | */ | |
141 | static void | 141 | static void | |
142 | q2val_to_quotaval(struct quota2_val *q2v, struct quotaval *qv) | 142 | q2val_to_quotaval(struct quota2_val *q2v, struct quotaval *qv) | |
143 | { | 143 | { | |
144 | qv->qv_softlimit = q2v->q2v_softlimit; | 144 | qv->qv_softlimit = q2v->q2v_softlimit; | |
145 | qv->qv_hardlimit = q2v->q2v_hardlimit; | 145 | qv->qv_hardlimit = q2v->q2v_hardlimit; | |
146 | qv->qv_usage = q2v->q2v_cur; | 146 | qv->qv_usage = q2v->q2v_cur; | |
147 | qv->qv_expiretime = q2v->q2v_time; | 147 | qv->qv_expiretime = q2v->q2v_time; | |
148 | qv->qv_grace = q2v->q2v_grace; | 148 | qv->qv_grace = q2v->q2v_grace; | |
149 | } | 149 | } | |
150 | 150 | |||
151 | /* | 151 | /* | |
152 | * Convert a quota2entry and default-flag to the FS-independent | 152 | * Convert a quota2entry and default-flag to the FS-independent | |
153 | * representation. | 153 | * representation. | |
154 | */ | 154 | */ | |
155 | static void | 155 | static void | |
156 | q2e_to_quotaval(struct quota2_entry *q2e, int def, | 156 | q2e_to_quotaval(struct quota2_entry *q2e, int def, | |
157 | id_t *id, int objtype, struct quotaval *ret) | 157 | id_t *id, int objtype, struct quotaval *ret) | |
158 | { | 158 | { | |
159 | if (def) { | 159 | if (def) { | |
160 | *id = QUOTA_DEFAULTID; | 160 | *id = QUOTA_DEFAULTID; | |
161 | } else { | 161 | } else { | |
162 | *id = q2e->q2e_uid; | 162 | *id = q2e->q2e_uid; | |
163 | } | 163 | } | |
164 | 164 | |||
165 | KASSERT(objtype >= 0 && objtype < N_QL); | 165 | KASSERT(objtype >= 0 && objtype < N_QL); | |
166 | q2val_to_quotaval(&q2e->q2e_val[objtype], ret); | 166 | q2val_to_quotaval(&q2e->q2e_val[objtype], ret); | |
167 | } | 167 | } | |
168 | 168 | |||
169 | 169 | |||
170 | static int | 170 | static int | |
171 | quota2_bwrite(struct mount *mp, struct buf *bp) | 171 | quota2_bwrite(struct mount *mp, struct buf *bp) | |
172 | { | 172 | { | |
173 | if (mp->mnt_flag & MNT_SYNCHRONOUS) | 173 | if (mp->mnt_flag & MNT_SYNCHRONOUS) | |
174 | return bwrite(bp); | 174 | return bwrite(bp); | |
175 | else { | 175 | else { | |
176 | bdwrite(bp); | 176 | bdwrite(bp); | |
177 | return 0; | 177 | return 0; | |
178 | } | 178 | } | |
179 | } | 179 | } | |
180 | 180 | |||
181 | static int | 181 | static int | |
182 | getq2h(struct ufsmount *ump, int type, | 182 | getq2h(struct ufsmount *ump, int type, | |
183 | struct buf **bpp, struct quota2_header **q2hp, int flags) | 183 | struct buf **bpp, struct quota2_header **q2hp, int flags) | |
184 | { | 184 | { | |
185 | #ifdef FFS_EI | 185 | #ifdef FFS_EI | |
186 | const int needswap = UFS_MPNEEDSWAP(ump); | 186 | const int needswap = UFS_MPNEEDSWAP(ump); | |
187 | #endif | 187 | #endif | |
188 | int error; | 188 | int error; | |
189 | struct buf *bp; | 189 | struct buf *bp; | |
190 | struct quota2_header *q2h; | 190 | struct quota2_header *q2h; | |
191 | 191 | |||
192 | KASSERT(mutex_owned(&dqlock)); | 192 | KASSERT(mutex_owned(&dqlock)); | |
193 | error = bread(ump->um_quotas[type], 0, ump->umq2_bsize, | 193 | error = bread(ump->um_quotas[type], 0, ump->umq2_bsize, | |
194 | ump->um_cred[type], flags, &bp); | 194 | ump->um_cred[type], flags, &bp); | |
195 | if (error) | 195 | if (error) | |
196 | return error; | 196 | return error; | |
197 | if (bp->b_resid != 0) | 197 | if (bp->b_resid != 0) | |
198 | panic("dq2get: %s quota file truncated", quotatypes[type]); | 198 | panic("dq2get: %s quota file truncated", quotatypes[type]); | |
199 | 199 | |||
200 | q2h = (void *)bp->b_data; | 200 | q2h = (void *)bp->b_data; | |
201 | if (ufs_rw32(q2h->q2h_magic_number, needswap) != Q2_HEAD_MAGIC || | 201 | if (ufs_rw32(q2h->q2h_magic_number, needswap) != Q2_HEAD_MAGIC || | |
202 | q2h->q2h_type != type) | 202 | q2h->q2h_type != type) | |
203 | panic("dq2get: corrupted %s quota header", quotatypes[type]); | 203 | panic("dq2get: corrupted %s quota header", quotatypes[type]); | |
204 | *bpp = bp; | 204 | *bpp = bp; | |
205 | *q2hp = q2h; | 205 | *q2hp = q2h; | |
206 | return 0; | 206 | return 0; | |
207 | } | 207 | } | |
208 | 208 | |||
209 | static int | 209 | static int | |
210 | getq2e(struct ufsmount *ump, int type, daddr_t lblkno, int blkoffset, | 210 | getq2e(struct ufsmount *ump, int type, daddr_t lblkno, int blkoffset, | |
211 | struct buf **bpp, struct quota2_entry **q2ep, int flags) | 211 | struct buf **bpp, struct quota2_entry **q2ep, int flags) | |
212 | { | 212 | { | |
213 | int error; | 213 | int error; | |
214 | struct buf *bp; | 214 | struct buf *bp; | |
215 | 215 | |||
216 | if (blkoffset & (sizeof(uint64_t) - 1)) { | 216 | if (blkoffset & (sizeof(uint64_t) - 1)) { | |
217 | panic("dq2get: %s quota file corrupted", | 217 | panic("dq2get: %s quota file corrupted", | |
218 | quotatypes[type]); | 218 | quotatypes[type]); | |
219 | } | 219 | } | |
220 | error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize, | 220 | error = bread(ump->um_quotas[type], lblkno, ump->umq2_bsize, | |
221 | ump->um_cred[type], flags, &bp); | 221 | ump->um_cred[type], flags, &bp); | |
222 | if (error) | 222 | if (error) | |
223 | return error; | 223 | return error; | |
224 | if (bp->b_resid != 0) { | 224 | if (bp->b_resid != 0) { | |
225 | panic("dq2get: %s quota file corrupted", | 225 | panic("dq2get: %s quota file corrupted", | |
226 | quotatypes[type]); | 226 | quotatypes[type]); | |
227 | } | 227 | } | |
228 | *q2ep = (void *)((char *)bp->b_data + blkoffset); | 228 | *q2ep = (void *)((char *)bp->b_data + blkoffset); | |
229 | *bpp = bp; | 229 | *bpp = bp; | |
230 | return 0; | 230 | return 0; | |
231 | } | 231 | } | |
232 | 232 | |||
233 | /* walk a quota entry list, calling the callback for each entry */ | 233 | /* walk a quota entry list, calling the callback for each entry */ | |
234 | #define Q2WL_ABORT 0x10000000 | 234 | #define Q2WL_ABORT 0x10000000 | |
235 | 235 | |||
236 | static int | 236 | static int | |
237 | quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type, | 237 | quota2_walk_list(struct ufsmount *ump, struct buf *hbp, int type, | |
238 | uint64_t *offp, int flags, void *a, | 238 | uint64_t *offp, int flags, void *a, | |
239 | int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *)) | 239 | int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *)) | |
240 | { | 240 | { | |
241 | #ifdef FFS_EI | 241 | #ifdef FFS_EI | |
242 | const int needswap = UFS_MPNEEDSWAP(ump); | 242 | const int needswap = UFS_MPNEEDSWAP(ump); | |
243 | #endif | 243 | #endif | |
244 | daddr_t off = ufs_rw64(*offp, needswap); | 244 | daddr_t off = ufs_rw64(*offp, needswap); | |
245 | struct buf *bp, *obp = hbp; | 245 | struct buf *bp, *obp = hbp; | |
246 | int ret = 0, ret2 = 0; | 246 | int ret = 0, ret2 = 0; | |
247 | struct quota2_entry *q2e; | 247 | struct quota2_entry *q2e; | |
248 | daddr_t lblkno, blkoff, olblkno = 0; | 248 | daddr_t lblkno, blkoff, olblkno = 0; | |
249 | 249 | |||
250 | KASSERT(mutex_owner(&dqlock)); | 250 | KASSERT(mutex_owner(&dqlock)); | |
251 | 251 | |||
252 | while (off != 0) { | 252 | while (off != 0) { | |
253 | lblkno = (off >> ump->um_mountp->mnt_fs_bshift); | 253 | lblkno = (off >> ump->um_mountp->mnt_fs_bshift); | |
254 | blkoff = (off & ump->umq2_bmask); | 254 | blkoff = (off & ump->umq2_bmask); | |
255 | if (lblkno == 0) { | 255 | if (lblkno == 0) { | |
256 | /* in the header block */ | 256 | /* in the header block */ | |
257 | bp = hbp; | 257 | bp = hbp; | |
258 | } else if (lblkno == olblkno) { | 258 | } else if (lblkno == olblkno) { | |
259 | /* still in the same buf */ | 259 | /* still in the same buf */ | |
260 | bp = obp; | 260 | bp = obp; | |
261 | } else { | 261 | } else { | |
262 | ret = bread(ump->um_quotas[type], lblkno, | 262 | ret = bread(ump->um_quotas[type], lblkno, | |
263 | ump->umq2_bsize, | 263 | ump->umq2_bsize, | |
264 | ump->um_cred[type], flags, &bp); | 264 | ump->um_cred[type], flags, &bp); | |
265 | if (ret) | 265 | if (ret) | |
266 | return ret; | 266 | return ret; | |
267 | if (bp->b_resid != 0) { | 267 | if (bp->b_resid != 0) { | |
268 | panic("quota2_walk_list: %s quota file corrupted", | 268 | panic("quota2_walk_list: %s quota file corrupted", | |
269 | quotatypes[type]); | 269 | quotatypes[type]); | |
270 | } | 270 | } | |
271 | } | 271 | } | |
272 | q2e = (void *)((char *)(bp->b_data) + blkoff); | 272 | q2e = (void *)((char *)(bp->b_data) + blkoff); | |
273 | ret = (*func)(ump, offp, q2e, off, a); | 273 | ret = (*func)(ump, offp, q2e, off, a); | |
274 | if (off != ufs_rw64(*offp, needswap)) { | 274 | if (off != ufs_rw64(*offp, needswap)) { | |
275 | /* callback changed parent's pointer, redo */ | 275 | /* callback changed parent's pointer, redo */ | |
276 | off = ufs_rw64(*offp, needswap); | 276 | off = ufs_rw64(*offp, needswap); | |
277 | if (bp != hbp && bp != obp) | 277 | if (bp != hbp && bp != obp) | |
278 | ret2 = bwrite(bp); | 278 | ret2 = bwrite(bp); | |
279 | } else { | 279 | } else { | |
280 | /* parent if now current */ | 280 | /* parent if now current */ | |
281 | if (obp != bp && obp != hbp) { | 281 | if (obp != bp && obp != hbp) { | |
282 | if (flags & B_MODIFY) | 282 | if (flags & B_MODIFY) | |
283 | ret2 = bwrite(obp); | 283 | ret2 = bwrite(obp); | |
284 | else | 284 | else | |
285 | brelse(obp, 0); | 285 | brelse(obp, 0); | |
286 | } | 286 | } | |
287 | obp = bp; | 287 | obp = bp; | |
288 | olblkno = lblkno; | 288 | olblkno = lblkno; | |
289 | offp = &(q2e->q2e_next); | 289 | offp = &(q2e->q2e_next); | |
290 | off = ufs_rw64(*offp, needswap); | 290 | off = ufs_rw64(*offp, needswap); | |
291 | } | 291 | } | |
292 | if (ret) | 292 | if (ret) | |
293 | break; | 293 | break; | |
294 | if (ret2) { | 294 | if (ret2) { | |
295 | ret = ret2; | 295 | ret = ret2; | |
296 | break; | 296 | break; | |
297 | } | 297 | } | |
298 | } | 298 | } | |
299 | if (obp != hbp) { | 299 | if (obp != hbp) { | |
300 | if (flags & B_MODIFY) | 300 | if (flags & B_MODIFY) | |
301 | ret2 = bwrite(obp); | 301 | ret2 = bwrite(obp); | |
302 | else | 302 | else | |
303 | brelse(obp, 0); | 303 | brelse(obp, 0); | |
304 | } | 304 | } | |
305 | if (ret & Q2WL_ABORT) | 305 | if (ret & Q2WL_ABORT) | |
306 | return 0; | 306 | return 0; | |
307 | if (ret == 0) | 307 | if (ret == 0) | |
308 | return ret2; | 308 | return ret2; | |
309 | return ret; | 309 | return ret; | |
310 | } | 310 | } | |
311 | 311 | |||
312 | int | 312 | int | |
313 | quota2_umount(struct mount *mp, int flags) | 313 | quota2_umount(struct mount *mp, int flags) | |
314 | { | 314 | { | |
315 | int i, error; | 315 | int i, error; | |
316 | struct ufsmount *ump = VFSTOUFS(mp); | 316 | struct ufsmount *ump = VFSTOUFS(mp); | |
317 | 317 | |||
318 | if ((ump->um_flags & UFS_QUOTA2) == 0) | 318 | if ((ump->um_flags & UFS_QUOTA2) == 0) | |
319 | return 0; | 319 | return 0; | |
320 | 320 | |||
321 | for (i = 0; i < MAXQUOTAS; i++) { | 321 | for (i = 0; i < MAXQUOTAS; i++) { | |
322 | if (ump->um_quotas[i] != NULLVP) { | 322 | if (ump->um_quotas[i] != NULLVP) { | |
323 | error = vn_close(ump->um_quotas[i], FREAD|FWRITE, | 323 | error = vn_close(ump->um_quotas[i], FREAD|FWRITE, | |
324 | ump->um_cred[i]); | 324 | ump->um_cred[i]); | |
325 | if (error) { | 325 | if (error) { | |
326 | printf("quota2_umount failed: close(%p) %d\n", | 326 | printf("quota2_umount failed: close(%p) %d\n", | |
327 | ump->um_quotas[i], error); | 327 | ump->um_quotas[i], error); | |
328 | return error; | 328 | return error; | |
329 | } | 329 | } | |
330 | } | 330 | } | |
331 | ump->um_quotas[i] = NULLVP; | 331 | ump->um_quotas[i] = NULLVP; | |
332 | } | 332 | } | |
333 | return 0; | 333 | return 0; | |
334 | } | 334 | } | |
335 | 335 | |||
336 | static int | 336 | static int | |
337 | quota2_q2ealloc(struct ufsmount *ump, int type, uid_t uid, struct dquot *dq, | 337 | quota2_q2ealloc(struct ufsmount *ump, int type, uid_t uid, struct dquot *dq, | |
338 | struct buf **bpp, struct quota2_entry **q2ep) | 338 | struct buf **bpp, struct quota2_entry **q2ep) | |
339 | { | 339 | { | |
340 | int error, error2; | 340 | int error, error2; | |
341 | struct buf *hbp, *bp; | 341 | struct buf *hbp, *bp; | |
342 | struct quota2_header *q2h; | 342 | struct quota2_header *q2h; | |
343 | struct quota2_entry *q2e; | 343 | struct quota2_entry *q2e; | |
344 | daddr_t offset; | 344 | daddr_t offset; | |
345 | u_long hash_mask; | 345 | u_long hash_mask; | |
346 | const int needswap = UFS_MPNEEDSWAP(ump); | 346 | const int needswap = UFS_MPNEEDSWAP(ump); | |
347 | 347 | |||
348 | KASSERT(mutex_owned(&dq->dq_interlock)); | 348 | KASSERT(mutex_owned(&dq->dq_interlock)); | |
349 | KASSERT(mutex_owned(&dqlock)); | 349 | KASSERT(mutex_owned(&dqlock)); | |
350 | error = getq2h(ump, type, &hbp, &q2h, B_MODIFY); | 350 | error = getq2h(ump, type, &hbp, &q2h, B_MODIFY); | |
351 | if (error) | 351 | if (error) | |
352 | return error; | 352 | return error; | |
353 | offset = ufs_rw64(q2h->q2h_free, needswap); | 353 | offset = ufs_rw64(q2h->q2h_free, needswap); | |
354 | if (offset == 0) { | 354 | if (offset == 0) { | |
355 | struct vnode *vp = ump->um_quotas[type]; | 355 | struct vnode *vp = ump->um_quotas[type]; | |
356 | struct inode *ip = VTOI(vp); | 356 | struct inode *ip = VTOI(vp); | |
357 | uint64_t size = ip->i_size; | 357 | uint64_t size = ip->i_size; | |
358 | /* need to alocate a new disk block */ | 358 | /* need to alocate a new disk block */ | |
359 | error = UFS_BALLOC(vp, size, ump->umq2_bsize, | 359 | error = UFS_BALLOC(vp, size, ump->umq2_bsize, | |
360 | ump->um_cred[type], B_CLRBUF | B_SYNC, &bp); | 360 | ump->um_cred[type], B_CLRBUF | B_SYNC, &bp); | |
361 | if (error) { | 361 | if (error) { | |
362 | brelse(hbp, 0); | 362 | brelse(hbp, 0); | |
363 | return error; | 363 | return error; | |
364 | } | 364 | } | |
365 | KASSERT((ip->i_size % ump->umq2_bsize) == 0); | 365 | KASSERT((ip->i_size % ump->umq2_bsize) == 0); | |
366 | ip->i_size += ump->umq2_bsize; | 366 | ip->i_size += ump->umq2_bsize; | |
367 | DIP_ASSIGN(ip, size, ip->i_size); | 367 | DIP_ASSIGN(ip, size, ip->i_size); | |
368 | ip->i_flag |= IN_CHANGE | IN_UPDATE; | 368 | ip->i_flag |= IN_CHANGE | IN_UPDATE; | |
369 | uvm_vnp_setsize(vp, ip->i_size); | 369 | uvm_vnp_setsize(vp, ip->i_size); | |
370 | quota2_addfreeq2e(q2h, bp->b_data, size, ump->umq2_bsize, | 370 | quota2_addfreeq2e(q2h, bp->b_data, size, ump->umq2_bsize, | |
371 | needswap); | 371 | needswap); | |
372 | error = bwrite(bp); | 372 | error = bwrite(bp); | |
373 | error2 = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT); | 373 | error2 = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT); | |
374 | if (error || error2) { | 374 | if (error || error2) { | |
375 | brelse(hbp, 0); | 375 | brelse(hbp, 0); | |
376 | if (error) | 376 | if (error) | |
377 | return error; | 377 | return error; | |
378 | return error2; | 378 | return error2; | |
379 | } | 379 | } | |
380 | offset = ufs_rw64(q2h->q2h_free, needswap); | 380 | offset = ufs_rw64(q2h->q2h_free, needswap); | |
381 | KASSERT(offset != 0); | 381 | KASSERT(offset != 0); | |
382 | } | 382 | } | |
383 | dq->dq2_lblkno = (offset >> ump->um_mountp->mnt_fs_bshift); | 383 | dq->dq2_lblkno = (offset >> ump->um_mountp->mnt_fs_bshift); | |
384 | dq->dq2_blkoff = (offset & ump->umq2_bmask); | 384 | dq->dq2_blkoff = (offset & ump->umq2_bmask); | |
385 | if (dq->dq2_lblkno == 0) { | 385 | if (dq->dq2_lblkno == 0) { | |
386 | bp = hbp; | 386 | bp = hbp; | |
387 | q2e = (void *)((char *)bp->b_data + dq->dq2_blkoff); | 387 | q2e = (void *)((char *)bp->b_data + dq->dq2_blkoff); | |
388 | } else { | 388 | } else { | |
389 | error = getq2e(ump, type, dq->dq2_lblkno, | 389 | error = getq2e(ump, type, dq->dq2_lblkno, | |
390 | dq->dq2_blkoff, &bp, &q2e, B_MODIFY); | 390 | dq->dq2_blkoff, &bp, &q2e, B_MODIFY); | |
391 | if (error) { | 391 | if (error) { | |
392 | brelse(hbp, 0); | 392 | brelse(hbp, 0); | |
393 | return error; | 393 | return error; | |
394 | } | 394 | } | |
395 | } | 395 | } | |
396 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | 396 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | |
397 | /* remove from free list */ | 397 | /* remove from free list */ | |
398 | q2h->q2h_free = q2e->q2e_next; | 398 | q2h->q2h_free = q2e->q2e_next; | |
399 | 399 | |||
400 | memcpy(q2e, &q2h->q2h_defentry, sizeof(*q2e)); | 400 | memcpy(q2e, &q2h->q2h_defentry, sizeof(*q2e)); | |
401 | q2e->q2e_uid = ufs_rw32(uid, needswap); | 401 | q2e->q2e_uid = ufs_rw32(uid, needswap); | |
402 | /* insert in hash list */ | 402 | /* insert in hash list */ | |
403 | q2e->q2e_next = q2h->q2h_entries[uid & hash_mask]; | 403 | q2e->q2e_next = q2h->q2h_entries[uid & hash_mask]; | |
404 | q2h->q2h_entries[uid & hash_mask] = ufs_rw64(offset, needswap); | 404 | q2h->q2h_entries[uid & hash_mask] = ufs_rw64(offset, needswap); | |
405 | if (hbp != bp) { | 405 | if (hbp != bp) { | |
406 | bwrite(hbp); | 406 | bwrite(hbp); | |
407 | } | 407 | } | |
408 | *q2ep = q2e; | 408 | *q2ep = q2e; | |
409 | *bpp = bp; | 409 | *bpp = bp; | |
410 | return 0; | 410 | return 0; | |
411 | } | 411 | } | |
412 | 412 | |||
413 | static int | 413 | static int | |
414 | getinoquota2(struct inode *ip, bool alloc, bool modify, struct buf **bpp, | 414 | getinoquota2(struct inode *ip, bool alloc, bool modify, struct buf **bpp, | |
415 | struct quota2_entry **q2ep) | 415 | struct quota2_entry **q2ep) | |
416 | { | 416 | { | |
417 | int error; | 417 | int error; | |
418 | int i; | 418 | int i; | |
419 | struct dquot *dq; | 419 | struct dquot *dq; | |
420 | struct ufsmount *ump = ip->i_ump; | 420 | struct ufsmount *ump = ip->i_ump; | |
421 | u_int32_t ino_ids[MAXQUOTAS]; | 421 | u_int32_t ino_ids[MAXQUOTAS]; | |
422 | 422 | |||
423 | error = getinoquota(ip); | 423 | error = getinoquota(ip); | |
424 | if (error) | 424 | if (error) | |
425 | return error; | 425 | return error; | |
426 | 426 | |||
427 | if (alloc) { | 427 | if (alloc) { | |
428 | UFS_WAPBL_JLOCK_ASSERT(ump->um_mountp); | 428 | UFS_WAPBL_JLOCK_ASSERT(ump->um_mountp); | |
429 | } | 429 | } | |
430 | ino_ids[USRQUOTA] = ip->i_uid; | 430 | ino_ids[USRQUOTA] = ip->i_uid; | |
431 | ino_ids[GRPQUOTA] = ip->i_gid; | 431 | ino_ids[GRPQUOTA] = ip->i_gid; | |
432 | /* first get the interlock for all dquot */ | 432 | /* first get the interlock for all dquot */ | |
433 | for (i = 0; i < MAXQUOTAS; i++) { | 433 | for (i = 0; i < MAXQUOTAS; i++) { | |
434 | dq = ip->i_dquot[i]; | 434 | dq = ip->i_dquot[i]; | |
435 | if (dq == NODQUOT) | 435 | if (dq == NODQUOT) | |
436 | continue; | 436 | continue; | |
437 | mutex_enter(&dq->dq_interlock); | 437 | mutex_enter(&dq->dq_interlock); | |
438 | } | 438 | } | |
439 | /* now get the corresponding quota entry */ | 439 | /* now get the corresponding quota entry */ | |
440 | for (i = 0; i < MAXQUOTAS; i++) { | 440 | for (i = 0; i < MAXQUOTAS; i++) { | |
441 | bpp[i] = NULL; | 441 | bpp[i] = NULL; | |
442 | q2ep[i] = NULL; | 442 | q2ep[i] = NULL; | |
443 | dq = ip->i_dquot[i]; | 443 | dq = ip->i_dquot[i]; | |
444 | if (dq == NODQUOT) | 444 | if (dq == NODQUOT) | |
445 | continue; | 445 | continue; | |
446 | if (__predict_false(ump->um_quotas[i] == NULL)) { | 446 | if (__predict_false(ump->um_quotas[i] == NULL)) { | |
447 | /* | 447 | /* | |
448 | * quotas have been turned off. This can happen | 448 | * quotas have been turned off. This can happen | |
449 | * at umount time. | 449 | * at umount time. | |
450 | */ | 450 | */ | |
451 | mutex_exit(&dq->dq_interlock); | 451 | mutex_exit(&dq->dq_interlock); | |
452 | dqrele(NULLVP, dq); | 452 | dqrele(NULLVP, dq); | |
453 | ip->i_dquot[i] = NULL; | 453 | ip->i_dquot[i] = NULL; | |
454 | continue; | 454 | continue; | |
455 | } | 455 | } | |
456 | 456 | |||
457 | if ((dq->dq2_lblkno | dq->dq2_blkoff) == 0) { | 457 | if ((dq->dq2_lblkno | dq->dq2_blkoff) == 0) { | |
458 | if (!alloc) { | 458 | if (!alloc) { | |
459 | continue; | 459 | continue; | |
460 | } | 460 | } | |
461 | /* need to alloc a new on-disk quot */ | 461 | /* need to alloc a new on-disk quot */ | |
462 | mutex_enter(&dqlock); | 462 | mutex_enter(&dqlock); | |
463 | error = quota2_q2ealloc(ump, i, ino_ids[i], dq, | 463 | error = quota2_q2ealloc(ump, i, ino_ids[i], dq, | |
464 | &bpp[i], &q2ep[i]); | 464 | &bpp[i], &q2ep[i]); | |
465 | mutex_exit(&dqlock); | 465 | mutex_exit(&dqlock); | |
466 | if (error) | 466 | if (error) | |
467 | return error; | 467 | return error; | |
468 | } else { | 468 | } else { | |
469 | error = getq2e(ump, i, dq->dq2_lblkno, | 469 | error = getq2e(ump, i, dq->dq2_lblkno, | |
470 | dq->dq2_blkoff, &bpp[i], &q2ep[i], | 470 | dq->dq2_blkoff, &bpp[i], &q2ep[i], | |
471 | modify ? B_MODIFY : 0); | 471 | modify ? B_MODIFY : 0); | |
472 | if (error) | 472 | if (error) | |
473 | return error; | 473 | return error; | |
474 | } | 474 | } | |
475 | } | 475 | } | |
476 | return 0; | 476 | return 0; | |
477 | } | 477 | } | |
478 | 478 | |||
479 | static int | 479 | static int | |
480 | quota2_check(struct inode *ip, int vtype, int64_t change, kauth_cred_t cred, | 480 | quota2_check(struct inode *ip, int vtype, int64_t change, kauth_cred_t cred, | |
481 | int flags) | 481 | int flags) | |
482 | { | 482 | { | |
483 | int error; | 483 | int error; | |
484 | struct buf *bp[MAXQUOTAS]; | 484 | struct buf *bp[MAXQUOTAS]; | |
485 | struct quota2_entry *q2e[MAXQUOTAS]; | 485 | struct quota2_entry *q2e[MAXQUOTAS]; | |
486 | struct quota2_val *q2vp; | 486 | struct quota2_val *q2vp; | |
487 | struct dquot *dq; | 487 | struct dquot *dq; | |
488 | uint64_t ncurblks; | 488 | uint64_t ncurblks; | |
489 | struct ufsmount *ump = ip->i_ump; | 489 | struct ufsmount *ump = ip->i_ump; | |
490 | struct mount *mp = ump->um_mountp; | 490 | struct mount *mp = ump->um_mountp; | |
491 | const int needswap = UFS_MPNEEDSWAP(ump); | 491 | const int needswap = UFS_MPNEEDSWAP(ump); | |
492 | int i; | 492 | int i; | |
493 | 493 | |||
494 | if ((error = getinoquota2(ip, change > 0, change != 0, bp, q2e)) != 0) | 494 | if ((error = getinoquota2(ip, change > 0, change != 0, bp, q2e)) != 0) | |
495 | return error; | 495 | return error; | |
496 | if (change == 0) { | 496 | if (change == 0) { | |
497 | for (i = 0; i < MAXQUOTAS; i++) { | 497 | for (i = 0; i < MAXQUOTAS; i++) { | |
498 | dq = ip->i_dquot[i]; | 498 | dq = ip->i_dquot[i]; | |
499 | if (dq == NODQUOT) | 499 | if (dq == NODQUOT) | |
500 | continue; | 500 | continue; | |
501 | if (bp[i]) | 501 | if (bp[i]) | |
502 | brelse(bp[i], 0); | 502 | brelse(bp[i], 0); | |
503 | mutex_exit(&dq->dq_interlock); | 503 | mutex_exit(&dq->dq_interlock); | |
504 | } | 504 | } | |
505 | return 0; | 505 | return 0; | |
506 | } | 506 | } | |
507 | if (change < 0) { | 507 | if (change < 0) { | |
508 | for (i = 0; i < MAXQUOTAS; i++) { | 508 | for (i = 0; i < MAXQUOTAS; i++) { | |
509 | dq = ip->i_dquot[i]; | 509 | dq = ip->i_dquot[i]; | |
510 | if (dq == NODQUOT) | 510 | if (dq == NODQUOT) | |
511 | continue; | 511 | continue; | |
512 | if (q2e[i] == NULL) { | 512 | if (q2e[i] == NULL) { | |
513 | mutex_exit(&dq->dq_interlock); | 513 | mutex_exit(&dq->dq_interlock); | |
514 | continue; | 514 | continue; | |
515 | } | 515 | } | |
516 | q2vp = &q2e[i]->q2e_val[vtype]; | 516 | q2vp = &q2e[i]->q2e_val[vtype]; | |
517 | ncurblks = ufs_rw64(q2vp->q2v_cur, needswap); | 517 | ncurblks = ufs_rw64(q2vp->q2v_cur, needswap); | |
518 | if (ncurblks < -change) | 518 | if (ncurblks < -change) | |
519 | ncurblks = 0; | 519 | ncurblks = 0; | |
520 | else | 520 | else | |
521 | ncurblks += change; | 521 | ncurblks += change; | |
522 | q2vp->q2v_cur = ufs_rw64(ncurblks, needswap); | 522 | q2vp->q2v_cur = ufs_rw64(ncurblks, needswap); | |
523 | quota2_bwrite(mp, bp[i]); | 523 | quota2_bwrite(mp, bp[i]); | |
524 | mutex_exit(&dq->dq_interlock); | 524 | mutex_exit(&dq->dq_interlock); | |
525 | } | 525 | } | |
526 | return 0; | 526 | return 0; | |
527 | } | 527 | } | |
528 | /* see if the allocation is allowed */ | 528 | /* see if the allocation is allowed */ | |
529 | for (i = 0; i < MAXQUOTAS; i++) { | 529 | for (i = 0; i < MAXQUOTAS; i++) { | |
530 | struct quota2_val q2v; | 530 | struct quota2_val q2v; | |
531 | int ql_stat; | 531 | int ql_stat; | |
532 | dq = ip->i_dquot[i]; | 532 | dq = ip->i_dquot[i]; | |
533 | if (dq == NODQUOT) | 533 | if (dq == NODQUOT) | |
534 | continue; | 534 | continue; | |
535 | KASSERT(q2e[i] != NULL); | 535 | KASSERT(q2e[i] != NULL); | |
536 | quota2_ufs_rwq2v(&q2e[i]->q2e_val[vtype], &q2v, needswap); | 536 | quota2_ufs_rwq2v(&q2e[i]->q2e_val[vtype], &q2v, needswap); | |
537 | ql_stat = quota2_check_limit(&q2v, change, time_second); | 537 | ql_stat = quota2_check_limit(&q2v, change, time_second); | |
538 | 538 | |||
539 | if ((flags & FORCE) == 0 && | 539 | if ((flags & FORCE) == 0 && | |
540 | kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA, | 540 | kauth_authorize_system(cred, KAUTH_SYSTEM_FS_QUOTA, | |
541 | KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, | 541 | KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT, | |
542 | KAUTH_ARG(i), KAUTH_ARG(vtype), NULL) != 0) { | 542 | KAUTH_ARG(i), KAUTH_ARG(vtype), NULL) != 0) { | |
543 | /* enforce this limit */ | 543 | /* enforce this limit */ | |
544 | switch(QL_STATUS(ql_stat)) { | 544 | switch(QL_STATUS(ql_stat)) { | |
545 | case QL_S_DENY_HARD: | 545 | case QL_S_DENY_HARD: | |
546 | if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { | 546 | if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { | |
547 | uprintf("\n%s: write failed, %s %s " | 547 | uprintf("\n%s: write failed, %s %s " | |
548 | "limit reached\n", | 548 | "limit reached\n", | |
549 | mp->mnt_stat.f_mntonname, | 549 | mp->mnt_stat.f_mntonname, | |
550 | quotatypes[i], limnames[vtype]); | 550 | quotatypes[i], limnames[vtype]); | |
551 | dq->dq_flags |= DQ_WARN(vtype); | 551 | dq->dq_flags |= DQ_WARN(vtype); | |
552 | } | 552 | } | |
553 | error = EDQUOT; | 553 | error = EDQUOT; | |
554 | break; | 554 | break; | |
555 | case QL_S_DENY_GRACE: | 555 | case QL_S_DENY_GRACE: | |
556 | if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { | 556 | if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { | |
557 | uprintf("\n%s: write failed, %s %s " | 557 | uprintf("\n%s: write failed, %s %s " | |
558 | "limit reached\n", | 558 | "limit reached\n", | |
559 | mp->mnt_stat.f_mntonname, | 559 | mp->mnt_stat.f_mntonname, | |
560 | quotatypes[i], limnames[vtype]); | 560 | quotatypes[i], limnames[vtype]); | |
561 | dq->dq_flags |= DQ_WARN(vtype); | 561 | dq->dq_flags |= DQ_WARN(vtype); | |
562 | } | 562 | } | |
563 | error = EDQUOT; | 563 | error = EDQUOT; | |
564 | break; | 564 | break; | |
565 | case QL_S_ALLOW_SOFT: | 565 | case QL_S_ALLOW_SOFT: | |
566 | if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { | 566 | if ((dq->dq_flags & DQ_WARN(vtype)) == 0) { | |
567 | uprintf("\n%s: warning, %s %s " | 567 | uprintf("\n%s: warning, %s %s " | |
568 | "quota exceeded\n", | 568 | "quota exceeded\n", | |
569 | mp->mnt_stat.f_mntonname, | 569 | mp->mnt_stat.f_mntonname, | |
570 | quotatypes[i], limnames[vtype]); | 570 | quotatypes[i], limnames[vtype]); | |
571 | dq->dq_flags |= DQ_WARN(vtype); | 571 | dq->dq_flags |= DQ_WARN(vtype); | |
572 | } | 572 | } | |
573 | break; | 573 | break; | |
574 | } | 574 | } | |
575 | } | 575 | } | |
576 | /* | 576 | /* | |
577 | * always do this; we don't know if the allocation will | 577 | * always do this; we don't know if the allocation will | |
578 | * succed or not in the end. if we don't do the allocation | 578 | * succed or not in the end. if we don't do the allocation | |
579 | * q2v_time will be ignored anyway | 579 | * q2v_time will be ignored anyway | |
580 | */ | 580 | */ | |
581 | if (ql_stat & QL_F_CROSS) { | 581 | if (ql_stat & QL_F_CROSS) { | |
582 | q2v.q2v_time = time_second + q2v.q2v_grace; | 582 | q2v.q2v_time = time_second + q2v.q2v_grace; | |
583 | quota2_ufs_rwq2v(&q2v, &q2e[i]->q2e_val[vtype], | 583 | quota2_ufs_rwq2v(&q2v, &q2e[i]->q2e_val[vtype], | |
584 | needswap); | 584 | needswap); | |
585 | } | 585 | } | |
586 | } | 586 | } | |
587 | 587 | |||
588 | /* now do the allocation if allowed */ | 588 | /* now do the allocation if allowed */ | |
589 | for (i = 0; i < MAXQUOTAS; i++) { | 589 | for (i = 0; i < MAXQUOTAS; i++) { | |
590 | dq = ip->i_dquot[i]; | 590 | dq = ip->i_dquot[i]; | |
591 | if (dq == NODQUOT) | 591 | if (dq == NODQUOT) | |
592 | continue; | 592 | continue; | |
593 | KASSERT(q2e[i] != NULL); | 593 | KASSERT(q2e[i] != NULL); | |
594 | if (error == 0) { | 594 | if (error == 0) { | |
595 | q2vp = &q2e[i]->q2e_val[vtype]; | 595 | q2vp = &q2e[i]->q2e_val[vtype]; | |
596 | ncurblks = ufs_rw64(q2vp->q2v_cur, needswap); | 596 | ncurblks = ufs_rw64(q2vp->q2v_cur, needswap); | |
597 | q2vp->q2v_cur = ufs_rw64(ncurblks + change, needswap); | 597 | q2vp->q2v_cur = ufs_rw64(ncurblks + change, needswap); | |
598 | quota2_bwrite(mp, bp[i]); | 598 | quota2_bwrite(mp, bp[i]); | |
599 | } else | 599 | } else | |
600 | brelse(bp[i], 0); | 600 | brelse(bp[i], 0); | |
601 | mutex_exit(&dq->dq_interlock); | 601 | mutex_exit(&dq->dq_interlock); | |
602 | } | 602 | } | |
603 | return error; | 603 | return error; | |
604 | } | 604 | } | |
605 | 605 | |||
606 | int | 606 | int | |
607 | chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | 607 | chkdq2(struct inode *ip, int64_t change, kauth_cred_t cred, int flags) | |
608 | { | 608 | { | |
609 | return quota2_check(ip, QL_BLOCK, change, cred, flags); | 609 | return quota2_check(ip, QL_BLOCK, change, cred, flags); | |
610 | } | 610 | } | |
611 | 611 | |||
612 | int | 612 | int | |
613 | chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | 613 | chkiq2(struct inode *ip, int32_t change, kauth_cred_t cred, int flags) | |
614 | { | 614 | { | |
615 | return quota2_check(ip, QL_FILE, change, cred, flags); | 615 | return quota2_check(ip, QL_FILE, change, cred, flags); | |
616 | } | 616 | } | |
617 | 617 | |||
618 | int | 618 | int | |
619 | quota2_handle_cmd_put(struct ufsmount *ump, const struct quotakey *key, | 619 | quota2_handle_cmd_put(struct ufsmount *ump, const struct quotakey *key, | |
620 | const struct quotaval *val) | 620 | const struct quotaval *val) | |
621 | { | 621 | { | |
622 | int error; | 622 | int error; | |
623 | struct dquot *dq; | 623 | struct dquot *dq; | |
624 | struct quota2_header *q2h; | 624 | struct quota2_header *q2h; | |
625 | struct quota2_entry q2e, *q2ep; | 625 | struct quota2_entry q2e, *q2ep; | |
626 | struct buf *bp; | 626 | struct buf *bp; | |
627 | const int needswap = UFS_MPNEEDSWAP(ump); | 627 | const int needswap = UFS_MPNEEDSWAP(ump); | |
628 | 628 | |||
629 | /* make sure we can index by the fs-independent idtype */ | 629 | /* make sure we can index by the fs-independent idtype */ | |
630 | CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA); | 630 | CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA); | |
631 | CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA); | 631 | CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA); | |
632 | 632 | |||
633 | if (ump->um_quotas[key->qk_idtype] == NULLVP) | 633 | if (ump->um_quotas[key->qk_idtype] == NULLVP) | |
634 | return ENODEV; | 634 | return ENODEV; | |
635 | error = UFS_WAPBL_BEGIN(ump->um_mountp); | 635 | error = UFS_WAPBL_BEGIN(ump->um_mountp); | |
636 | if (error) | 636 | if (error) | |
637 | return error; | 637 | return error; | |
638 | 638 | |||
639 | if (key->qk_id == QUOTA_DEFAULTID) { | 639 | if (key->qk_id == QUOTA_DEFAULTID) { | |
640 | mutex_enter(&dqlock); | 640 | mutex_enter(&dqlock); | |
641 | error = getq2h(ump, key->qk_idtype, &bp, &q2h, B_MODIFY); | 641 | error = getq2h(ump, key->qk_idtype, &bp, &q2h, B_MODIFY); | |
642 | if (error) { | 642 | if (error) { | |
643 | mutex_exit(&dqlock); | 643 | mutex_exit(&dqlock); | |
644 | goto out_wapbl; | 644 | goto out_wapbl; | |
645 | } | 645 | } | |
646 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | 646 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | |
647 | quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e); | 647 | quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e); | |
648 | quota2_ufs_rwq2e(&q2e, &q2h->q2h_defentry, needswap); | 648 | quota2_ufs_rwq2e(&q2e, &q2h->q2h_defentry, needswap); | |
649 | mutex_exit(&dqlock); | 649 | mutex_exit(&dqlock); | |
650 | quota2_bwrite(ump->um_mountp, bp); | 650 | quota2_bwrite(ump->um_mountp, bp); | |
651 | goto out_wapbl; | 651 | goto out_wapbl; | |
652 | } | 652 | } | |
653 | 653 | |||
654 | error = dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq); | 654 | error = dqget(NULLVP, key->qk_id, ump, key->qk_idtype, &dq); | |
655 | if (error) | 655 | if (error) | |
656 | goto out_wapbl; | 656 | goto out_wapbl; | |
657 | 657 | |||
658 | mutex_enter(&dq->dq_interlock); | 658 | mutex_enter(&dq->dq_interlock); | |
659 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | 659 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | |
660 | /* need to alloc a new on-disk quot */ | 660 | /* need to alloc a new on-disk quot */ | |
661 | mutex_enter(&dqlock); | 661 | mutex_enter(&dqlock); | |
662 | error = quota2_q2ealloc(ump, key->qk_idtype, key->qk_id, dq, | 662 | error = quota2_q2ealloc(ump, key->qk_idtype, key->qk_id, dq, | |
663 | &bp, &q2ep); | 663 | &bp, &q2ep); | |
664 | mutex_exit(&dqlock); | 664 | mutex_exit(&dqlock); | |
665 | } else { | 665 | } else { | |
666 | error = getq2e(ump, key->qk_idtype, dq->dq2_lblkno, | 666 | error = getq2e(ump, key->qk_idtype, dq->dq2_lblkno, | |
667 | dq->dq2_blkoff, &bp, &q2ep, B_MODIFY); | 667 | dq->dq2_blkoff, &bp, &q2ep, B_MODIFY); | |
668 | } | 668 | } | |
669 | if (error) | 669 | if (error) | |
670 | goto out_il; | 670 | goto out_il; | |
671 | 671 | |||
672 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | 672 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | |
673 | quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e); | 673 | quota2_dict_update_q2e_limits(key->qk_objtype, val, &q2e); | |
674 | quota2_ufs_rwq2e(&q2e, q2ep, needswap); | 674 | quota2_ufs_rwq2e(&q2e, q2ep, needswap); | |
675 | quota2_bwrite(ump->um_mountp, bp); | 675 | quota2_bwrite(ump->um_mountp, bp); | |
676 | 676 | |||
677 | out_il: | 677 | out_il: | |
678 | mutex_exit(&dq->dq_interlock); | 678 | mutex_exit(&dq->dq_interlock); | |
679 | dqrele(NULLVP, dq); | 679 | dqrele(NULLVP, dq); | |
680 | out_wapbl: | 680 | out_wapbl: | |
681 | UFS_WAPBL_END(ump->um_mountp); | 681 | UFS_WAPBL_END(ump->um_mountp); | |
682 | return error; | 682 | return error; | |
683 | } | 683 | } | |
684 | 684 | |||
685 | struct dq2clear_callback { | 685 | struct dq2clear_callback { | |
686 | uid_t id; | 686 | uid_t id; | |
687 | struct dquot *dq; | 687 | struct dquot *dq; | |
688 | struct quota2_header *q2h; | 688 | struct quota2_header *q2h; | |
689 | }; | 689 | }; | |
690 | 690 | |||
691 | static int | 691 | static int | |
692 | dq2clear_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, | 692 | dq2clear_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, | |
693 | uint64_t off, void *v) | 693 | uint64_t off, void *v) | |
694 | { | 694 | { | |
695 | struct dq2clear_callback *c = v; | 695 | struct dq2clear_callback *c = v; | |
696 | #ifdef FFS_EI | 696 | #ifdef FFS_EI | |
697 | const int needswap = UFS_MPNEEDSWAP(ump); | 697 | const int needswap = UFS_MPNEEDSWAP(ump); | |
698 | #endif | 698 | #endif | |
699 | uint64_t myoff; | 699 | uint64_t myoff; | |
700 | 700 | |||
701 | if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { | 701 | if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { | |
702 | KASSERT(mutex_owned(&c->dq->dq_interlock)); | 702 | KASSERT(mutex_owned(&c->dq->dq_interlock)); | |
703 | c->dq->dq2_lblkno = 0; | 703 | c->dq->dq2_lblkno = 0; | |
704 | c->dq->dq2_blkoff = 0; | 704 | c->dq->dq2_blkoff = 0; | |
705 | myoff = *offp; | 705 | myoff = *offp; | |
706 | /* remove from hash list */ | 706 | /* remove from hash list */ | |
707 | *offp = q2e->q2e_next; | 707 | *offp = q2e->q2e_next; | |
708 | /* add to free list */ | 708 | /* add to free list */ | |
709 | q2e->q2e_next = c->q2h->q2h_free; | 709 | q2e->q2e_next = c->q2h->q2h_free; | |
710 | c->q2h->q2h_free = myoff; | 710 | c->q2h->q2h_free = myoff; | |
711 | return Q2WL_ABORT; | 711 | return Q2WL_ABORT; | |
712 | } | 712 | } | |
713 | return 0; | 713 | return 0; | |
714 | } | 714 | } | |
715 | int | 715 | int | |
716 | quota2_handle_cmd_delete(struct ufsmount *ump, const struct quotakey *qk) | 716 | quota2_handle_cmd_delete(struct ufsmount *ump, const struct quotakey *qk) | |
717 | { | 717 | { | |
718 | int idtype; | 718 | int idtype; | |
719 | id_t id; | 719 | id_t id; | |
720 | int objtype; | 720 | int objtype; | |
721 | int error, i, canfree; | 721 | int error, i, canfree; | |
722 | struct dquot *dq; | 722 | struct dquot *dq; | |
723 | struct quota2_header *q2h; | 723 | struct quota2_header *q2h; | |
724 | struct quota2_entry q2e, *q2ep; | 724 | struct quota2_entry q2e, *q2ep; | |
725 | struct buf *hbp, *bp; | 725 | struct buf *hbp, *bp; | |
726 | u_long hash_mask; | 726 | u_long hash_mask; | |
727 | struct dq2clear_callback c; | 727 | struct dq2clear_callback c; | |
728 | 728 | |||
729 | idtype = qk->qk_idtype; | 729 | idtype = qk->qk_idtype; | |
730 | id = qk->qk_id; | 730 | id = qk->qk_id; | |
731 | objtype = qk->qk_objtype; | 731 | objtype = qk->qk_objtype; | |
732 | 732 | |||
733 | if (ump->um_quotas[idtype] == NULLVP) | 733 | if (ump->um_quotas[idtype] == NULLVP) | |
734 | return ENODEV; | 734 | return ENODEV; | |
735 | if (id == QUOTA_DEFAULTID) | 735 | if (id == QUOTA_DEFAULTID) | |
736 | return EOPNOTSUPP; | 736 | return EOPNOTSUPP; | |
737 | 737 | |||
738 | /* get the default entry before locking the entry's buffer */ | 738 | /* get the default entry before locking the entry's buffer */ | |
739 | mutex_enter(&dqlock); | 739 | mutex_enter(&dqlock); | |
740 | error = getq2h(ump, idtype, &hbp, &q2h, 0); | 740 | error = getq2h(ump, idtype, &hbp, &q2h, 0); | |
741 | if (error) { | 741 | if (error) { | |
742 | mutex_exit(&dqlock); | 742 | mutex_exit(&dqlock); | |
743 | return error; | 743 | return error; | |
744 | } | 744 | } | |
745 | /* we'll copy to another disk entry, so no need to swap */ | 745 | /* we'll copy to another disk entry, so no need to swap */ | |
746 | memcpy(&q2e, &q2h->q2h_defentry, sizeof(q2e)); | 746 | memcpy(&q2e, &q2h->q2h_defentry, sizeof(q2e)); | |
747 | mutex_exit(&dqlock); | 747 | mutex_exit(&dqlock); | |
748 | brelse(hbp, 0); | 748 | brelse(hbp, 0); | |
749 | 749 | |||
750 | error = dqget(NULLVP, id, ump, idtype, &dq); | 750 | error = dqget(NULLVP, id, ump, idtype, &dq); | |
751 | if (error) | 751 | if (error) | |
752 | return error; | 752 | return error; | |
753 | 753 | |||
754 | mutex_enter(&dq->dq_interlock); | 754 | mutex_enter(&dq->dq_interlock); | |
755 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | 755 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | |
756 | /* already clear, nothing to do */ | 756 | /* already clear, nothing to do */ | |
757 | error = ENOENT; | 757 | error = ENOENT; | |
758 | goto out_il; | 758 | goto out_il; | |
759 | } | 759 | } | |
760 | error = UFS_WAPBL_BEGIN(ump->um_mountp); | 760 | error = UFS_WAPBL_BEGIN(ump->um_mountp); | |
761 | if (error) | 761 | if (error) | |
762 | goto out_dq; | 762 | goto out_dq; | |
763 | 763 | |||
764 | error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, | 764 | error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, | |
765 | &bp, &q2ep, B_MODIFY); | 765 | &bp, &q2ep, B_MODIFY); | |
766 | if (error) | 766 | if (error) | |
767 | goto out_wapbl; | 767 | goto out_wapbl; | |
768 | 768 | |||
769 | /* make sure we can index by the objtype passed in */ | 769 | /* make sure we can index by the objtype passed in */ | |
770 | CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK); | 770 | CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK); | |
771 | CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE); | 771 | CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE); | |
772 | 772 | |||
773 | /* clear the requested objtype by copying from the default entry */ | 773 | /* clear the requested objtype by copying from the default entry */ | |
774 | q2ep->q2e_val[objtype].q2v_softlimit = | 774 | q2ep->q2e_val[objtype].q2v_softlimit = | |
775 | q2e.q2e_val[objtype].q2v_softlimit; | 775 | q2e.q2e_val[objtype].q2v_softlimit; | |
776 | q2ep->q2e_val[objtype].q2v_hardlimit = | 776 | q2ep->q2e_val[objtype].q2v_hardlimit = | |
777 | q2e.q2e_val[objtype].q2v_hardlimit; | 777 | q2e.q2e_val[objtype].q2v_hardlimit; | |
778 | q2ep->q2e_val[objtype].q2v_grace = | 778 | q2ep->q2e_val[objtype].q2v_grace = | |
779 | q2e.q2e_val[objtype].q2v_grace; | 779 | q2e.q2e_val[objtype].q2v_grace; | |
780 | q2ep->q2e_val[objtype].q2v_time = 0; | 780 | q2ep->q2e_val[objtype].q2v_time = 0; | |
781 | 781 | |||
782 | /* if this entry now contains no information, we can free it */ | 782 | /* if this entry now contains no information, we can free it */ | |
783 | canfree = 1; | 783 | canfree = 1; | |
784 | for (i = 0; i < N_QL; i++) { | 784 | for (i = 0; i < N_QL; i++) { | |
785 | if (q2ep->q2e_val[i].q2v_cur != 0 || | 785 | if (q2ep->q2e_val[i].q2v_cur != 0 || | |
786 | (q2ep->q2e_val[i].q2v_softlimit != | 786 | (q2ep->q2e_val[i].q2v_softlimit != | |
787 | q2e.q2e_val[i].q2v_softlimit) || | 787 | q2e.q2e_val[i].q2v_softlimit) || | |
788 | (q2ep->q2e_val[i].q2v_hardlimit != | 788 | (q2ep->q2e_val[i].q2v_hardlimit != | |
789 | q2e.q2e_val[i].q2v_hardlimit) || | 789 | q2e.q2e_val[i].q2v_hardlimit) || | |
790 | (q2ep->q2e_val[i].q2v_grace != | 790 | (q2ep->q2e_val[i].q2v_grace != | |
791 | q2e.q2e_val[i].q2v_grace)) { | 791 | q2e.q2e_val[i].q2v_grace)) { | |
792 | canfree = 0; | 792 | canfree = 0; | |
793 | break; | 793 | break; | |
794 | } | 794 | } | |
795 | /* note: do not need to check q2v_time */ | 795 | /* note: do not need to check q2v_time */ | |
796 | } | 796 | } | |
797 | 797 | |||
798 | if (canfree == 0) { | 798 | if (canfree == 0) { | |
799 | quota2_bwrite(ump->um_mountp, bp); | 799 | quota2_bwrite(ump->um_mountp, bp); | |
800 | goto out_wapbl; | 800 | goto out_wapbl; | |
801 | } | 801 | } | |
802 | /* we can free it. release bp so we can walk the list */ | 802 | /* we can free it. release bp so we can walk the list */ | |
803 | brelse(bp, 0); | 803 | brelse(bp, 0); | |
804 | mutex_enter(&dqlock); | 804 | mutex_enter(&dqlock); | |
805 | error = getq2h(ump, idtype, &hbp, &q2h, 0); | 805 | error = getq2h(ump, idtype, &hbp, &q2h, 0); | |
806 | if (error) | 806 | if (error) | |
807 | goto out_dqlock; | 807 | goto out_dqlock; | |
808 | 808 | |||
809 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | 809 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | |
810 | c.dq = dq; | 810 | c.dq = dq; | |
811 | c.id = id; | 811 | c.id = id; | |
812 | c.q2h = q2h; | 812 | c.q2h = q2h; | |
813 | error = quota2_walk_list(ump, hbp, idtype, | 813 | error = quota2_walk_list(ump, hbp, idtype, | |
814 | &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c, | 814 | &q2h->q2h_entries[id & hash_mask], B_MODIFY, &c, | |
815 | dq2clear_callback); | 815 | dq2clear_callback); | |
816 | 816 | |||
817 | bwrite(hbp); | 817 | bwrite(hbp); | |
818 | 818 | |||
819 | out_dqlock: | 819 | out_dqlock: | |
820 | mutex_exit(&dqlock); | 820 | mutex_exit(&dqlock); | |
821 | out_wapbl: | 821 | out_wapbl: | |
822 | UFS_WAPBL_END(ump->um_mountp); | 822 | UFS_WAPBL_END(ump->um_mountp); | |
823 | out_il: | 823 | out_il: | |
824 | mutex_exit(&dq->dq_interlock); | 824 | mutex_exit(&dq->dq_interlock); | |
825 | out_dq: | 825 | out_dq: | |
826 | dqrele(NULLVP, dq); | 826 | dqrele(NULLVP, dq); | |
827 | return error; | 827 | return error; | |
828 | } | 828 | } | |
829 | 829 | |||
830 | static int | 830 | static int | |
831 | quota2_result_add_q2e(struct ufsmount *ump, int idtype, | 831 | quota2_result_add_q2e(struct ufsmount *ump, int idtype, | |
832 | int id, struct quotakey *keys, struct quotaval *vals, unsigned pos, | 832 | int id, struct quotakey *keys, struct quotaval *vals, unsigned pos, | |
833 | int skipfirst, int skiplast) | 833 | int skipfirst, int skiplast) | |
834 | { | 834 | { | |
835 | struct dquot *dq; | 835 | struct dquot *dq; | |
836 | int error; | 836 | int error; | |
837 | struct quota2_entry *q2ep, q2e; | 837 | struct quota2_entry *q2ep, q2e; | |
838 | struct buf *bp; | 838 | struct buf *bp; | |
839 | const int needswap = UFS_MPNEEDSWAP(ump); | 839 | const int needswap = UFS_MPNEEDSWAP(ump); | |
840 | 840 | |||
841 | error = dqget(NULLVP, id, ump, idtype, &dq); | 841 | error = dqget(NULLVP, id, ump, idtype, &dq); | |
842 | if (error) | 842 | if (error) | |
843 | return error; | 843 | return error; | |
844 | 844 | |||
845 | mutex_enter(&dq->dq_interlock); | 845 | mutex_enter(&dq->dq_interlock); | |
846 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | 846 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | |
847 | mutex_exit(&dq->dq_interlock); | 847 | mutex_exit(&dq->dq_interlock); | |
848 | dqrele(NULLVP, dq); | 848 | dqrele(NULLVP, dq); | |
849 | return ENOENT; | 849 | return ENOENT; | |
850 | } | 850 | } | |
851 | error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, | 851 | error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, | |
852 | &bp, &q2ep, 0); | 852 | &bp, &q2ep, 0); | |
853 | if (error) { | 853 | if (error) { | |
854 | mutex_exit(&dq->dq_interlock); | 854 | mutex_exit(&dq->dq_interlock); | |
855 | dqrele(NULLVP, dq); | 855 | dqrele(NULLVP, dq); | |
856 | return error; | 856 | return error; | |
857 | } | 857 | } | |
858 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | 858 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | |
859 | brelse(bp, 0); | 859 | brelse(bp, 0); | |
860 | mutex_exit(&dq->dq_interlock); | 860 | mutex_exit(&dq->dq_interlock); | |
861 | dqrele(NULLVP, dq); | 861 | dqrele(NULLVP, dq); | |
862 | 862 | |||
863 | if (skipfirst == 0) { | 863 | if (skipfirst == 0) { | |
864 | keys[pos].qk_idtype = idtype; | 864 | keys[pos].qk_idtype = idtype; | |
865 | keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS; | 865 | keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS; | |
866 | q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id, | 866 | q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id, | |
867 | QL_BLOCK, &vals[pos]); | 867 | QL_BLOCK, &vals[pos]); | |
868 | pos++; | 868 | pos++; | |
869 | } | 869 | } | |
870 | 870 | |||
871 | if (skiplast == 0) { | 871 | if (skiplast == 0) { | |
872 | keys[pos].qk_idtype = idtype; | 872 | keys[pos].qk_idtype = idtype; | |
873 | keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES; | 873 | keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES; | |
874 | q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id, | 874 | q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id, | |
875 | QL_FILE, &vals[pos]); | 875 | QL_FILE, &vals[pos]); | |
876 | pos++; | 876 | pos++; | |
877 | } | 877 | } | |
878 | 878 | |||
879 | return 0; | 879 | return 0; | |
880 | } | 880 | } | |
881 | 881 | |||
882 | static int | 882 | static int | |
883 | quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, | 883 | quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, | |
884 | struct quotaval *ret) | 884 | struct quotaval *ret) | |
885 | { | 885 | { | |
886 | struct dquot *dq; | 886 | struct dquot *dq; | |
887 | int error; | 887 | int error; | |
888 | struct quota2_entry *q2ep, q2e; | 888 | struct quota2_entry *q2ep, q2e; | |
889 | struct buf *bp; | 889 | struct buf *bp; | |
890 | const int needswap = UFS_MPNEEDSWAP(ump); | 890 | const int needswap = UFS_MPNEEDSWAP(ump); | |
891 | id_t id2; | 891 | id_t id2; | |
892 | 892 | |||
893 | error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); | 893 | error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); | |
894 | if (error) | 894 | if (error) | |
895 | return error; | 895 | return error; | |
896 | 896 | |||
897 | mutex_enter(&dq->dq_interlock); | 897 | mutex_enter(&dq->dq_interlock); | |
898 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | 898 | if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { | |
899 | mutex_exit(&dq->dq_interlock); | 899 | mutex_exit(&dq->dq_interlock); | |
900 | dqrele(NULLVP, dq); | 900 | dqrele(NULLVP, dq); | |
901 | return ENOENT; | 901 | return ENOENT; | |
902 | } | 902 | } | |
903 | error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff, | 903 | error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff, | |
904 | &bp, &q2ep, 0); | 904 | &bp, &q2ep, 0); | |
905 | if (error) { | 905 | if (error) { | |
906 | mutex_exit(&dq->dq_interlock); | 906 | mutex_exit(&dq->dq_interlock); | |
907 | dqrele(NULLVP, dq); | 907 | dqrele(NULLVP, dq); | |
908 | return error; | 908 | return error; | |
909 | } | 909 | } | |
910 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | 910 | quota2_ufs_rwq2e(q2ep, &q2e, needswap); | |
911 | brelse(bp, 0); | 911 | brelse(bp, 0); | |
912 | mutex_exit(&dq->dq_interlock); | 912 | mutex_exit(&dq->dq_interlock); | |
913 | dqrele(NULLVP, dq); | 913 | dqrele(NULLVP, dq); | |
914 | 914 | |||
915 | q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret); | 915 | q2e_to_quotaval(&q2e, 0, &id2, qk->qk_objtype, ret); | |
916 | KASSERT(id2 == qk->qk_id); | 916 | KASSERT(id2 == qk->qk_id); | |
917 | return 0; | 917 | return 0; | |
918 | } | 918 | } | |
919 | 919 | |||
920 | int | 920 | int | |
921 | quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk, | 921 | quota2_handle_cmd_get(struct ufsmount *ump, const struct quotakey *qk, | |
922 | struct quotaval *ret) | 922 | struct quotaval *ret) | |
923 | { | 923 | { | |
924 | int error; | 924 | int error; | |
925 | struct quota2_header *q2h; | 925 | struct quota2_header *q2h; | |
926 | struct quota2_entry q2e; | 926 | struct quota2_entry q2e; | |
927 | struct buf *bp; | 927 | struct buf *bp; | |
928 | const int needswap = UFS_MPNEEDSWAP(ump); | 928 | const int needswap = UFS_MPNEEDSWAP(ump); | |
929 | id_t id2; | 929 | id_t id2; | |
930 | 930 | |||
931 | /* | 931 | /* | |
932 | * Make sure the FS-independent codes match the internal ones, | 932 | * Make sure the FS-independent codes match the internal ones, | |
933 | * so we can use the passed-in objtype without having to | 933 | * so we can use the passed-in objtype without having to | |
934 | * convert it explicitly to QL_BLOCK/QL_FILE. | 934 | * convert it explicitly to QL_BLOCK/QL_FILE. | |
935 | */ | 935 | */ | |
936 | CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS); | 936 | CTASSERT(QL_BLOCK == QUOTA_OBJTYPE_BLOCKS); | |
937 | CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES); | 937 | CTASSERT(QL_FILE == QUOTA_OBJTYPE_FILES); | |
938 | CTASSERT(N_QL == 2); | 938 | CTASSERT(N_QL == 2); | |
939 | 939 | |||
940 | if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) { | 940 | if (qk->qk_objtype < 0 || qk->qk_objtype >= N_QL) { | |
941 | return EINVAL; | 941 | return EINVAL; | |
942 | } | 942 | } | |
943 | 943 | |||
944 | if (ump->um_quotas[qk->qk_idtype] == NULLVP) | 944 | if (ump->um_quotas[qk->qk_idtype] == NULLVP) | |
945 | return ENODEV; | 945 | return ENODEV; | |
946 | if (qk->qk_id == QUOTA_DEFAULTID) { | 946 | if (qk->qk_id == QUOTA_DEFAULTID) { | |
947 | mutex_enter(&dqlock); | 947 | mutex_enter(&dqlock); | |
948 | error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); | 948 | error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); | |
949 | if (error) { | 949 | if (error) { | |
950 | mutex_exit(&dqlock); | 950 | mutex_exit(&dqlock); | |
951 | return error; | 951 | return error; | |
952 | } | 952 | } | |
953 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | 953 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | |
954 | mutex_exit(&dqlock); | 954 | mutex_exit(&dqlock); | |
955 | brelse(bp, 0); | 955 | brelse(bp, 0); | |
956 | q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, | 956 | q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, | |
957 | qk->qk_objtype, ret); | 957 | qk->qk_objtype, ret); | |
958 | (void)id2; | 958 | (void)id2; | |
959 | } else | 959 | } else | |
960 | error = quota2_fetch_q2e(ump, qk, ret); | 960 | error = quota2_fetch_q2e(ump, qk, ret); | |
961 | 961 | |||
962 | return error; | 962 | return error; | |
963 | } | 963 | } | |
964 | 964 | |||
965 | struct ufsq2_cursor { | 965 | struct ufsq2_cursor { | |
966 | uint32_t q2c_magic; /* magic number */ | 966 | uint32_t q2c_magic; /* magic number */ | |
967 | int q2c_hashsize; /* size of hash table at last go */ | 967 | int q2c_hashsize; /* size of hash table at last go */ | |
968 | 968 | |||
969 | int q2c_users_done; /* true if we've returned all user data */ | 969 | int q2c_users_done; /* true if we've returned all user data */ | |
970 | int q2c_groups_done; /* true if we've returned all group data */ | 970 | int q2c_groups_done; /* true if we've returned all group data */ | |
971 | int q2c_defaults_done; /* true if we've returned the default values */ | 971 | int q2c_defaults_done; /* true if we've returned the default values */ | |
972 | int q2c_hashpos; /* slot to start at in hash table */ | 972 | int q2c_hashpos; /* slot to start at in hash table */ | |
973 | int q2c_uidpos; /* number of ids we've handled */ | 973 | int q2c_uidpos; /* number of ids we've handled */ | |
974 | int q2c_blocks_done; /* true if we've returned the blocks value */ | 974 | int q2c_blocks_done; /* true if we've returned the blocks value */ | |
975 | }; | 975 | }; | |
976 | 976 | |||
977 | #define Q2C_MAGIC (0xbeebe111) | 977 | #define Q2C_MAGIC (0xbeebe111) | |
978 | 978 | |||
979 | #define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0]) | 979 | #define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0]) | |
980 | 980 | |||
981 | static int | 981 | static int | |
982 | q2cursor_check(struct ufsq2_cursor *cursor) | 982 | q2cursor_check(struct ufsq2_cursor *cursor) | |
983 | { | 983 | { | |
984 | if (cursor->q2c_magic != Q2C_MAGIC) { | 984 | if (cursor->q2c_magic != Q2C_MAGIC) { | |
985 | return EINVAL; | 985 | return EINVAL; | |
986 | } | 986 | } | |
987 | if (cursor->q2c_hashsize < 0) { | 987 | if (cursor->q2c_hashsize < 0) { | |
988 | return EINVAL; | 988 | return EINVAL; | |
989 | } | 989 | } | |
990 | 990 | |||
991 | if (cursor->q2c_users_done != 0 && cursor->q2c_users_done != 1) { | 991 | if (cursor->q2c_users_done != 0 && cursor->q2c_users_done != 1) { | |
992 | return EINVAL; | 992 | return EINVAL; | |
993 | } | 993 | } | |
994 | if (cursor->q2c_groups_done != 0 && cursor->q2c_groups_done != 1) { | 994 | if (cursor->q2c_groups_done != 0 && cursor->q2c_groups_done != 1) { | |
995 | return EINVAL; | 995 | return EINVAL; | |
996 | } | 996 | } | |
997 | if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) { | 997 | if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) { | |
998 | return EINVAL; | 998 | return EINVAL; | |
999 | } | 999 | } | |
1000 | if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) { | 1000 | if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) { | |
1001 | return EINVAL; | 1001 | return EINVAL; | |
1002 | } | 1002 | } | |
1003 | if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) { | 1003 | if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) { | |
1004 | return EINVAL; | 1004 | return EINVAL; | |
1005 | } | 1005 | } | |
1006 | return 0; | 1006 | return 0; | |
1007 | } | 1007 | } | |
1008 | 1008 | |||
1009 | struct getuids { | 1009 | struct getuids { | |
1010 | long nuids; /* number of uids in array */ | 1010 | long nuids; /* number of uids in array */ | |
1011 | long maxuids; /* number of uids allocated */ | 1011 | long maxuids; /* number of uids allocated */ | |
1012 | uid_t *uids; /* array of uids, dynamically allocated */ | 1012 | uid_t *uids; /* array of uids, dynamically allocated */ | |
1013 | long skip; | 1013 | long skip; | |
1014 | long seen; | 1014 | long seen; | |
1015 | long limit; | 1015 | long limit; | |
1016 | }; | 1016 | }; | |
1017 | 1017 | |||
1018 | static int | 1018 | static int | |
1019 | quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, | 1019 | quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, | |
1020 | struct quota2_entry *q2ep, uint64_t off, void *v) | 1020 | struct quota2_entry *q2ep, uint64_t off, void *v) | |
1021 | { | 1021 | { | |
1022 | struct getuids *gu = v; | 1022 | struct getuids *gu = v; | |
1023 | uid_t *newuids; | 1023 | uid_t *newuids; | |
1024 | long newmax; | 1024 | long newmax; | |
1025 | #ifdef FFS_EI | 1025 | #ifdef FFS_EI | |
1026 | const int needswap = UFS_MPNEEDSWAP(ump); | 1026 | const int needswap = UFS_MPNEEDSWAP(ump); | |
1027 | #endif | 1027 | #endif | |
1028 | 1028 | |||
1029 | if (gu->skip > 0) { | 1029 | if (gu->skip > 0) { | |
1030 | gu->skip--; | 1030 | gu->skip--; | |
1031 | return 0; | 1031 | return 0; | |
1032 | } | 1032 | } | |
1033 | if (gu->nuids == gu->maxuids) { | 1033 | if (gu->nuids == gu->maxuids) { | |
1034 | newmax = gu->maxuids + PAGE_SIZE / sizeof(uid_t); | 1034 | newmax = gu->maxuids + PAGE_SIZE / sizeof(uid_t); | |
1035 | newuids = realloc(gu->uids, newmax * sizeof(gu->uids[0]), | 1035 | newuids = realloc(gu->uids, newmax * sizeof(gu->uids[0]), | |
1036 | M_TEMP, M_WAITOK); | 1036 | M_TEMP, M_WAITOK); | |
1037 | if (newuids == NULL) { | 1037 | if (newuids == NULL) { | |
1038 | return ENOMEM; | 1038 | return ENOMEM; | |
1039 | } | 1039 | } | |
1040 | gu->uids = newuids; | 1040 | gu->uids = newuids; | |
1041 | gu->maxuids = newmax; | 1041 | gu->maxuids = newmax; | |
1042 | } | 1042 | } | |
1043 | gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); | 1043 | gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); | |
1044 | gu->nuids++; | 1044 | gu->nuids++; | |
1045 | gu->seen++; | 1045 | gu->seen++; | |
1046 | if (gu->nuids == gu->limit) { | 1046 | if (gu->nuids == gu->limit) { | |
1047 | return Q2WL_ABORT; | 1047 | return Q2WL_ABORT; | |
1048 | } | 1048 | } | |
1049 | return 0; | 1049 | return 0; | |
1050 | } | 1050 | } | |
1051 | 1051 | |||
1052 | int | 1052 | int | |
1053 | quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc, | 1053 | quota2_handle_cmd_cursorget(struct ufsmount *ump, struct quotakcursor *qkc, | |
1054 | struct quotakey *keys, struct quotaval *vals, unsigned maxreturn, | 1054 | struct quotakey *keys, struct quotaval *vals, unsigned maxreturn, | |
1055 | unsigned *ret) | 1055 | unsigned *ret) | |
1056 | { | 1056 | { | |
1057 | int error; | 1057 | int error; | |
1058 | struct ufsq2_cursor *cursor; | 1058 | struct ufsq2_cursor *cursor; | |
1059 | struct quota2_header *q2h; | 1059 | struct quota2_header *q2h; | |
1060 | struct quota2_entry q2e; | 1060 | struct quota2_entry q2e; | |
1061 | struct buf *hbp; | 1061 | struct buf *hbp; | |
1062 | uint64_t offset; | 1062 | uint64_t offset; | |
1063 | int idtype; | 1063 | int idtype; | |
1064 | int can_switch_idtype; | 1064 | int can_switch_idtype; | |
1065 | int i, j; | 1065 | int i, j; | |
1066 | int quota2_hash_size; | 1066 | int quota2_hash_size; | |
1067 | const int needswap = UFS_MPNEEDSWAP(ump); | 1067 | const int needswap = UFS_MPNEEDSWAP(ump); | |
1068 | struct getuids gu; | 1068 | struct getuids gu; | |
1069 | long excess; | 1069 | long excess; | |
1070 | id_t junkid; | 1070 | id_t junkid; | |
1071 | struct quotaval qv; | 1071 | struct quotaval qv; | |
1072 | unsigned num, maxnum; | 1072 | unsigned num, maxnum; | |
1073 | int skipfirst, skiplast; | 1073 | int skipfirst, skiplast; | |
1074 | int numreturn; | 1074 | int numreturn; | |
1075 | 1075 | |||
1076 | cursor = Q2CURSOR(qkc); | 1076 | cursor = Q2CURSOR(qkc); | |
1077 | error = q2cursor_check(cursor); | 1077 | error = q2cursor_check(cursor); | |
1078 | if (error) { | 1078 | if (error) { | |
1079 | return error; | 1079 | return error; | |
1080 | } | 1080 | } | |
1081 | 1081 | |||
1082 | CTASSERT(USRQUOTA == QUOTA_IDTYPE_USER); | 1082 | CTASSERT(USRQUOTA == QUOTA_IDTYPE_USER); | |
1083 | CTASSERT(GRPQUOTA == QUOTA_IDTYPE_GROUP); | 1083 | CTASSERT(GRPQUOTA == QUOTA_IDTYPE_GROUP); | |
1084 | 1084 | |||
1085 | if (cursor->q2c_users_done == 0 && | 1085 | if (cursor->q2c_users_done == 0 && | |
1086 | ump->um_quotas[USRQUOTA] == NULLVP) { | 1086 | ump->um_quotas[USRQUOTA] == NULLVP) { | |
1087 | cursor->q2c_users_done = 1; | 1087 | cursor->q2c_users_done = 1; | |
1088 | } | 1088 | } | |
1089 | if (cursor->q2c_groups_done == 0 && | 1089 | if (cursor->q2c_groups_done == 0 && | |
1090 | ump->um_quotas[GRPQUOTA] == NULLVP) { | 1090 | ump->um_quotas[GRPQUOTA] == NULLVP) { | |
1091 | cursor->q2c_groups_done = 1; | 1091 | cursor->q2c_groups_done = 1; | |
1092 | } | 1092 | } | |
1093 | 1093 | |||
1094 | restart: | 1094 | restart: | |
1095 | 1095 | |||
1096 | if (cursor->q2c_users_done == 0) { | 1096 | if (cursor->q2c_users_done == 0) { | |
1097 | idtype = QUOTA_IDTYPE_USER; | 1097 | idtype = QUOTA_IDTYPE_USER; | |
1098 | can_switch_idtype = 1; | 1098 | can_switch_idtype = 1; | |
1099 | } else if (cursor->q2c_groups_done == 0) { | 1099 | } else if (cursor->q2c_groups_done == 0) { | |
1100 | idtype = QUOTA_IDTYPE_GROUP; | 1100 | idtype = QUOTA_IDTYPE_GROUP; | |
1101 | can_switch_idtype = 0; | 1101 | can_switch_idtype = 0; | |
1102 | } else { | 1102 | } else { | |
1103 | /* nothing more to do, return 0 */ | 1103 | /* nothing more to do, return 0 */ | |
1104 | *ret = 0; | 1104 | *ret = 0; | |
1105 | return 0; | 1105 | return 0; | |
1106 | } | 1106 | } | |
1107 | 1107 | |||
1108 | KASSERT(ump->um_quotas[idtype] != NULLVP); | 1108 | KASSERT(ump->um_quotas[idtype] != NULLVP); | |
1109 | 1109 | |||
1110 | numreturn = 0; | 1110 | numreturn = 0; | |
1111 | 1111 | |||
1112 | mutex_enter(&dqlock); | 1112 | mutex_enter(&dqlock); | |
1113 | error = getq2h(ump, idtype, &hbp, &q2h, 0); | 1113 | error = getq2h(ump, idtype, &hbp, &q2h, 0); | |
1114 | if (error) { | 1114 | if (error) { | |
1115 | mutex_exit(&dqlock); | 1115 | mutex_exit(&dqlock); | |
1116 | return error; | 1116 | return error; | |
1117 | } | 1117 | } | |
1118 | 1118 | |||
1119 | if (cursor->q2c_defaults_done == 0) { | 1119 | if (cursor->q2c_defaults_done == 0) { | |
1120 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | 1120 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | |
1121 | if (cursor->q2c_blocks_done == 0) { | 1121 | if (cursor->q2c_blocks_done == 0) { | |
1122 | q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv); | 1122 | q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv); | |
1123 | keys[numreturn].qk_idtype = idtype; | 1123 | keys[numreturn].qk_idtype = idtype; | |
1124 | keys[numreturn].qk_id = QUOTA_DEFAULTID; | 1124 | keys[numreturn].qk_id = QUOTA_DEFAULTID; | |
1125 | keys[numreturn].qk_objtype = QUOTA_OBJTYPE_BLOCKS; | 1125 | keys[numreturn].qk_objtype = QUOTA_OBJTYPE_BLOCKS; | |
1126 | vals[numreturn++] = qv; | 1126 | vals[numreturn++] = qv; | |
1127 | cursor->q2c_blocks_done = 1; | 1127 | cursor->q2c_blocks_done = 1; | |
1128 | } | 1128 | } | |
1129 | if (cursor->q2c_blocks_done == 1) { | 1129 | if (cursor->q2c_blocks_done == 1) { | |
1130 | q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv); | 1130 | q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv); | |
1131 | keys[numreturn].qk_idtype = idtype; | 1131 | keys[numreturn].qk_idtype = idtype; | |
1132 | keys[numreturn].qk_id = QUOTA_DEFAULTID; | 1132 | keys[numreturn].qk_id = QUOTA_DEFAULTID; | |
1133 | keys[numreturn].qk_objtype = QUOTA_OBJTYPE_FILES; | 1133 | keys[numreturn].qk_objtype = QUOTA_OBJTYPE_FILES; | |
1134 | vals[numreturn++] = qv; | 1134 | vals[numreturn++] = qv; | |
1135 | cursor->q2c_blocks_done = 0; | 1135 | cursor->q2c_blocks_done = 0; | |
1136 | cursor->q2c_defaults_done = 1; | 1136 | cursor->q2c_defaults_done = 1; | |
1137 | } | 1137 | } | |
1138 | } | 1138 | } | |
1139 | 1139 | |||
1140 | /* | 1140 | /* | |
1141 | * we can't directly get entries as we can't walk the list | 1141 | * we can't directly get entries as we can't walk the list | |
1142 | * with qdlock and grab dq_interlock to read the entries | 1142 | * with qdlock and grab dq_interlock to read the entries | |
1143 | * at the same time. So just walk the lists to build a list of uid, | 1143 | * at the same time. So just walk the lists to build a list of uid, | |
1144 | * and then read entries for these uids | 1144 | * and then read entries for these uids | |
1145 | */ | 1145 | */ | |
1146 | memset(&gu, 0, sizeof(gu)); | 1146 | memset(&gu, 0, sizeof(gu)); | |
1147 | quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); | 1147 | quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); | |
1148 | 1148 | |||
1149 | /* if the table size has changed, make the caller start over */ | 1149 | /* if the table size has changed, make the caller start over */ | |
1150 | if (cursor->q2c_hashsize == 0) { | 1150 | if (cursor->q2c_hashsize == 0) { | |
1151 | cursor->q2c_hashsize = quota2_hash_size; | 1151 | cursor->q2c_hashsize = quota2_hash_size; | |
1152 | } else if (cursor->q2c_hashsize != quota2_hash_size) { | 1152 | } else if (cursor->q2c_hashsize != quota2_hash_size) { | |
1153 | error = EDEADLK; | 1153 | error = EDEADLK; | |
1154 | goto fail; | 1154 | goto fail; | |
1155 | } | 1155 | } | |
1156 | 1156 | |||
1157 | gu.skip = cursor->q2c_uidpos; | 1157 | gu.skip = cursor->q2c_uidpos; | |
1158 | gu.seen = 0; | 1158 | gu.seen = 0; | |
1159 | gu.limit = (maxreturn - numreturn) / 2; | 1159 | gu.limit = (maxreturn - numreturn) / 2; | |
1160 | if (gu.limit == 0 && (maxreturn - numreturn) > 0) { | 1160 | if (gu.limit == 0 && (maxreturn - numreturn) > 0) { | |
1161 | gu.limit = 1; | 1161 | gu.limit = 1; | |
1162 | } | 1162 | } | |
1163 | for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { | 1163 | for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { | |
1164 | offset = q2h->q2h_entries[i]; | 1164 | offset = q2h->q2h_entries[i]; | |
1165 | gu.seen = 0; | 1165 | gu.seen = 0; | |
1166 | error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, | 1166 | error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, | |
1167 | quota2_getuids_callback); | 1167 | quota2_getuids_callback); | |
1168 | if (error && error != Q2WL_ABORT) { | 1168 | if (error && error != Q2WL_ABORT) { | |
1169 | if (gu.uids != NULL) | 1169 | if (gu.uids != NULL) | |
1170 | free(gu.uids, M_TEMP); | 1170 | free(gu.uids, M_TEMP); | |
1171 | break; | 1171 | break; | |
1172 | } | 1172 | } | |
1173 | if (error == Q2WL_ABORT) { | 1173 | if (error == Q2WL_ABORT) { | |
1174 | /* got enough uids for now */ | 1174 | /* got enough uids for now */ | |
1175 | error = 0; | 1175 | error = 0; | |
1176 | } | 1176 | } | |
1177 | if (gu.nuids > gu.limit) { | 1177 | if (gu.nuids > gu.limit) { | |
1178 | excess = gu.nuids - gu.limit; | 1178 | excess = gu.nuids - gu.limit; | |
1179 | KASSERT(excess < gu.seen); | 1179 | KASSERT(excess < gu.seen); | |
1180 | gu.seen -= excess; | 1180 | gu.seen -= excess; | |
1181 | gu.nuids -= excess; | 1181 | gu.nuids -= excess; | |
1182 | } | 1182 | } | |
1183 | if (gu.nuids == gu.limit) { | 1183 | if (gu.nuids == gu.limit) { | |
1184 | break; | 1184 | break; | |
1185 | } | 1185 | } | |
1186 | } | 1186 | } | |
1187 | KASSERT(gu.nuids <= gu.limit); | 1187 | KASSERT(gu.nuids <= gu.limit); | |
1188 | cursor->q2c_hashpos = i; | 1188 | cursor->q2c_hashpos = i; | |
1189 | cursor->q2c_uidpos = gu.seen; | 1189 | cursor->q2c_uidpos = gu.seen; | |
1190 | 1190 | |||
1191 | fail: | 1191 | fail: | |
1192 | mutex_exit(&dqlock); | 1192 | mutex_exit(&dqlock); | |
1193 | brelse(hbp, 0); | 1193 | brelse(hbp, 0); | |
1194 | if (error) | 1194 | if (error) | |
1195 | return error; | 1195 | return error; | |
1196 | 1196 | |||
1197 | if (gu.nuids == 0) { | 1197 | if (gu.nuids == 0) { | |
1198 | if (idtype == QUOTA_IDTYPE_USER) | 1198 | if (idtype == QUOTA_IDTYPE_USER) | |
1199 | cursor->q2c_users_done = 1; | 1199 | cursor->q2c_users_done = 1; | |
1200 | else | 1200 | else | |
1201 | cursor->q2c_groups_done = 1; | 1201 | cursor->q2c_groups_done = 1; | |
1202 | if (can_switch_idtype) { | 1202 | if (can_switch_idtype) { | |
1203 | goto restart; | 1203 | goto restart; | |
1204 | } | 1204 | } | |
1205 | } | 1205 | } | |
1206 | 1206 | |||
1207 | maxnum = gu.nuids*2; | 1207 | maxnum = gu.nuids*2; | |
1208 | 1208 | |||
1209 | /* | 1209 | /* | |
1210 | * If we've already sent back the blocks value for the first id, | 1210 | * If we've already sent back the blocks value for the first id, | |
1211 | * don't send it again (skipfirst). | 1211 | * don't send it again (skipfirst). | |
1212 | * | 1212 | * | |
1213 | * If we have an odd number of available result slots and we | 1213 | * If we have an odd number of available result slots and we | |
1214 | * aren't going to skip the first result entry, we need to | 1214 | * aren't going to skip the first result entry, we need to | |
1215 | * leave off the last result entry (skiplast). | 1215 | * leave off the last result entry (skiplast). | |
1216 | */ | 1216 | */ | |
1217 | skipfirst = (cursor->q2c_blocks_done != 0); | 1217 | skipfirst = (cursor->q2c_blocks_done != 0); | |
1218 | skiplast = skipfirst == 0 && (maxreturn < maxnum); | 1218 | skiplast = skipfirst == 0 && (maxreturn < maxnum); | |
1219 | num = 0; | 1219 | num = 0; | |
1220 | for (j = 0; j < gu.nuids; j++) { | 1220 | for (j = 0; j < gu.nuids; j++) { | |
1221 | error = quota2_result_add_q2e(ump, idtype, | 1221 | error = quota2_result_add_q2e(ump, idtype, | |
1222 | gu.uids[j], keys, vals, numreturn + j*2, | 1222 | gu.uids[j], keys, vals, numreturn + j*2, | |
1223 | j == 0 && skipfirst, | 1223 | j == 0 && skipfirst, | |
1224 | j + 1 == gu.nuids && skiplast); | 1224 | j + 1 == gu.nuids && skiplast); | |
1225 | if (error == ENOENT) | 1225 | if (error == ENOENT) | |
1226 | continue; | 1226 | continue; | |
1227 | if (error) | 1227 | if (error) | |
1228 | break; | 1228 | break; | |
1229 | if ((j == 0 && skipfirst) || (j + 1 == gu.nuids && skiplast)) { | 1229 | if ((j == 0 && skipfirst) || (j + 1 == gu.nuids && skiplast)) { | |
1230 | num += 1; | 1230 | num += 1; | |
1231 | } else { | 1231 | } else { | |
1232 | num += 2; | 1232 | num += 2; | |
1233 | } | 1233 | } | |
1234 | } | 1234 | } | |
1235 | numreturn += num; | 1235 | numreturn += num; | |
1236 | *ret = numreturn; | 1236 | *ret = numreturn; | |
1237 | 1237 | |||
1238 | cursor->q2c_blocks_done = skiplast; | 1238 | cursor->q2c_blocks_done = skiplast; | |
1239 | 1239 | |||
1240 | if (gu.uids != NULL) | 1240 | if (gu.uids != NULL) | |
1241 | free(gu.uids, M_TEMP); | 1241 | free(gu.uids, M_TEMP); | |
1242 | return error; | 1242 | return error; | |
1243 | } | 1243 | } | |
1244 | 1244 | |||
1245 | int | 1245 | int | |
1246 | quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) | 1246 | quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) | |
1247 | { | 1247 | { | |
1248 | struct ufsq2_cursor *cursor; | 1248 | struct ufsq2_cursor *cursor; | |
1249 | 1249 | |||
1250 | CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); | 1250 | CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); | |
1251 | cursor = Q2CURSOR(qkc); | 1251 | cursor = Q2CURSOR(qkc); | |
1252 | 1252 | |||
1253 | cursor->q2c_magic = Q2C_MAGIC; | 1253 | cursor->q2c_magic = Q2C_MAGIC; | |
1254 | cursor->q2c_hashsize = 0; | 1254 | cursor->q2c_hashsize = 0; | |
1255 | 1255 | |||
1256 | cursor->q2c_users_done = 0; | 1256 | cursor->q2c_users_done = 0; | |
1257 | cursor->q2c_groups_done = 0; | 1257 | cursor->q2c_groups_done = 0; | |
1258 | cursor->q2c_defaults_done = 0; | 1258 | cursor->q2c_defaults_done = 0; | |
1259 | cursor->q2c_hashpos = 0; | 1259 | cursor->q2c_hashpos = 0; | |
1260 | cursor->q2c_uidpos = 0; | 1260 | cursor->q2c_uidpos = 0; | |
1261 | cursor->q2c_blocks_done = 0; | 1261 | cursor->q2c_blocks_done = 0; | |
1262 | return 0; | 1262 | return 0; | |
1263 | } | 1263 | } | |
1264 | 1264 | |||
1265 | int | 1265 | int | |
1266 | quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc) | 1266 | quota2_handle_cmd_cursorclose(struct ufsmount *ump, struct quotakcursor *qkc) | |
1267 | { | 1267 | { | |
1268 | struct ufsq2_cursor *cursor; | 1268 | struct ufsq2_cursor *cursor; | |
1269 | int error; | 1269 | int error; | |
1270 | 1270 | |||
1271 | cursor = Q2CURSOR(qkc); | 1271 | cursor = Q2CURSOR(qkc); | |
1272 | error = q2cursor_check(cursor); | 1272 | error = q2cursor_check(cursor); | |
1273 | if (error) { | 1273 | if (error) { | |
1274 | return error; | 1274 | return error; | |
1275 | } | 1275 | } | |
1276 | 1276 | |||
1277 | /* nothing to do */ | 1277 | /* nothing to do */ | |
1278 | 1278 | |||
1279 | return 0; | 1279 | return 0; | |
1280 | } | 1280 | } | |
1281 | 1281 | |||
1282 | int | 1282 | int | |
1283 | quota2_handle_cmd_cursorskipidtype(struct ufsmount *ump, | |||
1284 | struct quotakcursor *qkc, int idtype) | |||
1285 | { | |||
1286 | struct ufsq2_cursor *cursor; | |||
1287 | int error; | |||
1288 | ||||
1289 | cursor = Q2CURSOR(qkc); | |||
1290 | error = q2cursor_check(cursor); | |||
1291 | if (error) { | |||
1292 | return error; | |||
1293 | } | |||
1294 | ||||
1295 | switch (idtype) { | |||
1296 | case QUOTA_IDTYPE_USER: | |||
1297 | cursor->q2c_users_done = 1; | |||
1298 | break; | |||
1299 | case QUOTA_IDTYPE_GROUP: | |||
1300 | cursor->q2c_groups_done = 1; | |||
1301 | break; | |||
1302 | default: | |||
1303 | return EINVAL; | |||
1304 | } | |||
1305 | ||||
1306 | return 0; | |||
1307 | } | |||
1308 | ||||
1309 | int | |||
1310 | quota2_handle_cmd_cursoratend(struct ufsmount *ump, struct quotakcursor *qkc, | |||
1311 | int *ret) | |||
1312 | { | |||
1313 | struct ufsq2_cursor *cursor; | |||
1314 | int error; | |||
1315 | ||||
1316 | cursor = Q2CURSOR(qkc); | |||
1317 | error = q2cursor_check(cursor); | |||
1318 | if (error) { | |||
1319 | return error; | |||
1320 | } | |||
1321 | ||||
1322 | *ret = (cursor->q2c_users_done && cursor->q2c_groups_done); | |||
1323 | return 0; | |||
1324 | } | |||
1325 | ||||
1326 | int | |||
1327 | quota2_handle_cmd_cursorrewind(struct ufsmount *ump, struct quotakcursor *qkc) | |||
1328 | { | |||
1329 | struct ufsq2_cursor *cursor; | |||
1330 | int error; | |||
1331 | ||||
1332 | cursor = Q2CURSOR(qkc); | |||
1333 | error = q2cursor_check(cursor); | |||
1334 | if (error) { | |||
1335 | return error; | |||
1336 | } | |||
1337 | ||||
1338 | cursor->q2c_hashsize = 0; | |||
1339 | ||||
1340 | cursor->q2c_users_done = 0; | |||
1341 | cursor->q2c_groups_done = 0; | |||
1342 | cursor->q2c_defaults_done = 0; | |||
1343 | cursor->q2c_hashpos = 0; | |||
1344 | cursor->q2c_uidpos = 0; | |||
1345 | cursor->q2c_blocks_done = 0; | |||
1346 | ||||
1347 | return 0; | |||
1348 | } | |||
1349 | ||||
1350 | int | |||
1283 | q2sync(struct mount *mp) | 1351 | q2sync(struct mount *mp) | |
1284 | { | 1352 | { | |
1285 | return 0; | 1353 | return 0; | |
1286 | } | 1354 | } | |
1287 | 1355 | |||
1288 | struct dq2get_callback { | 1356 | struct dq2get_callback { | |
1289 | uid_t id; | 1357 | uid_t id; | |
1290 | struct dquot *dq; | 1358 | struct dquot *dq; | |
1291 | }; | 1359 | }; | |
1292 | 1360 | |||
1293 | static int | 1361 | static int | |
1294 | dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, | 1362 | dq2get_callback(struct ufsmount *ump, uint64_t *offp, struct quota2_entry *q2e, | |
1295 | uint64_t off, void *v) | 1363 | uint64_t off, void *v) | |
1296 | { | 1364 | { | |
1297 | struct dq2get_callback *c = v; | 1365 | struct dq2get_callback *c = v; | |
1298 | daddr_t lblkno; | 1366 | daddr_t lblkno; | |
1299 | int blkoff; | 1367 | int blkoff; | |
1300 | #ifdef FFS_EI | 1368 | #ifdef FFS_EI | |
1301 | const int needswap = UFS_MPNEEDSWAP(ump); | 1369 | const int needswap = UFS_MPNEEDSWAP(ump); | |
1302 | #endif | 1370 | #endif | |
1303 | 1371 | |||
1304 | if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { | 1372 | if (ufs_rw32(q2e->q2e_uid, needswap) == c->id) { | |
1305 | KASSERT(mutex_owned(&c->dq->dq_interlock)); | 1373 | KASSERT(mutex_owned(&c->dq->dq_interlock)); | |
1306 | lblkno = (off >> ump->um_mountp->mnt_fs_bshift); | 1374 | lblkno = (off >> ump->um_mountp->mnt_fs_bshift); | |
1307 | blkoff = (off & ump->umq2_bmask); | 1375 | blkoff = (off & ump->umq2_bmask); | |
1308 | c->dq->dq2_lblkno = lblkno; | 1376 | c->dq->dq2_lblkno = lblkno; | |
1309 | c->dq->dq2_blkoff = blkoff; | 1377 | c->dq->dq2_blkoff = blkoff; | |
1310 | return Q2WL_ABORT; | 1378 | return Q2WL_ABORT; | |
1311 | } | 1379 | } | |
1312 | return 0; | 1380 | return 0; | |
1313 | } | 1381 | } | |
1314 | 1382 | |||
1315 | int | 1383 | int | |
1316 | dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, | 1384 | dq2get(struct vnode *dqvp, u_long id, struct ufsmount *ump, int type, | |
1317 | struct dquot *dq) | 1385 | struct dquot *dq) | |
1318 | { | 1386 | { | |
1319 | struct buf *bp; | 1387 | struct buf *bp; | |
1320 | struct quota2_header *q2h; | 1388 | struct quota2_header *q2h; | |
1321 | int error; | 1389 | int error; | |
1322 | daddr_t offset; | 1390 | daddr_t offset; | |
1323 | u_long hash_mask; | 1391 | u_long hash_mask; | |
1324 | struct dq2get_callback c = { | 1392 | struct dq2get_callback c = { | |
1325 | .id = id, | 1393 | .id = id, | |
1326 | .dq = dq | 1394 | .dq = dq | |
1327 | }; | 1395 | }; | |
1328 | 1396 | |||
1329 | KASSERT(mutex_owned(&dq->dq_interlock)); | 1397 | KASSERT(mutex_owned(&dq->dq_interlock)); | |
1330 | mutex_enter(&dqlock); | 1398 | mutex_enter(&dqlock); | |
1331 | error = getq2h(ump, type, &bp, &q2h, 0); | 1399 | error = getq2h(ump, type, &bp, &q2h, 0); | |
1332 | if (error) | 1400 | if (error) | |
1333 | goto out_mutex; | 1401 | goto out_mutex; | |
1334 | /* look for our entry */ | 1402 | /* look for our entry */ | |
1335 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | 1403 | hash_mask = ((1 << q2h->q2h_hash_shift) - 1); | |
1336 | offset = q2h->q2h_entries[id & hash_mask]; | 1404 | offset = q2h->q2h_entries[id & hash_mask]; | |
1337 | error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, | 1405 | error = quota2_walk_list(ump, bp, type, &offset, 0, (void *)&c, | |
1338 | dq2get_callback); | 1406 | dq2get_callback); | |
1339 | brelse(bp, 0); | 1407 | brelse(bp, 0); | |
1340 | out_mutex: | 1408 | out_mutex: | |
1341 | mutex_exit(&dqlock); | 1409 | mutex_exit(&dqlock); | |
1342 | return error; | 1410 | return error; | |
1343 | } | 1411 | } | |
1344 | 1412 | |||
1345 | int | 1413 | int | |
1346 | dq2sync(struct vnode *vp, struct dquot *dq) | 1414 | dq2sync(struct vnode *vp, struct dquot *dq) | |
1347 | { | 1415 | { | |
1348 | return 0; | 1416 | return 0; | |
1349 | } | 1417 | } |