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