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