ext2fs_alloc.c revision 1.57 1 1.57 msaitoh /* $NetBSD: ext2fs_alloc.c,v 1.57 2024/05/13 00:24:19 msaitoh Exp $ */
2 1.1 bouyer
3 1.1 bouyer /*
4 1.1 bouyer * Copyright (c) 1982, 1986, 1989, 1993
5 1.1 bouyer * The Regents of the University of California. All rights reserved.
6 1.1 bouyer *
7 1.1 bouyer * Redistribution and use in source and binary forms, with or without
8 1.1 bouyer * modification, are permitted provided that the following conditions
9 1.1 bouyer * are met:
10 1.1 bouyer * 1. Redistributions of source code must retain the above copyright
11 1.1 bouyer * notice, this list of conditions and the following disclaimer.
12 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 bouyer * notice, this list of conditions and the following disclaimer in the
14 1.1 bouyer * documentation and/or other materials provided with the distribution.
15 1.20 agc * 3. Neither the name of the University nor the names of its contributors
16 1.20 agc * may be used to endorse or promote products derived from this software
17 1.20 agc * without specific prior written permission.
18 1.20 agc *
19 1.20 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 1.20 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.20 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.20 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 1.20 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.20 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.20 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.20 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.20 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.20 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.20 agc * SUCH DAMAGE.
30 1.20 agc *
31 1.20 agc * @(#)ffs_alloc.c 8.11 (Berkeley) 10/27/94
32 1.20 agc * Modified for ext2fs by Manuel Bouyer.
33 1.20 agc */
34 1.20 agc
35 1.20 agc /*
36 1.20 agc * Copyright (c) 1997 Manuel Bouyer.
37 1.20 agc *
38 1.20 agc * Redistribution and use in source and binary forms, with or without
39 1.20 agc * modification, are permitted provided that the following conditions
40 1.20 agc * are met:
41 1.20 agc * 1. Redistributions of source code must retain the above copyright
42 1.20 agc * notice, this list of conditions and the following disclaimer.
43 1.20 agc * 2. Redistributions in binary form must reproduce the above copyright
44 1.20 agc * notice, this list of conditions and the following disclaimer in the
45 1.20 agc * documentation and/or other materials provided with the distribution.
46 1.1 bouyer *
47 1.22 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 1.22 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 1.22 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 1.22 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 1.22 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 1.22 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 1.22 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 1.22 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 1.22 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 1.22 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 1.1 bouyer *
58 1.1 bouyer * @(#)ffs_alloc.c 8.11 (Berkeley) 10/27/94
59 1.1 bouyer * Modified for ext2fs by Manuel Bouyer.
60 1.1 bouyer */
61 1.13 lukem
62 1.13 lukem #include <sys/cdefs.h>
63 1.57 msaitoh __KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.57 2024/05/13 00:24:19 msaitoh Exp $");
64 1.1 bouyer
65 1.1 bouyer #include <sys/param.h>
66 1.1 bouyer #include <sys/systm.h>
67 1.1 bouyer #include <sys/buf.h>
68 1.1 bouyer #include <sys/proc.h>
69 1.1 bouyer #include <sys/vnode.h>
70 1.1 bouyer #include <sys/mount.h>
71 1.1 bouyer #include <sys/kernel.h>
72 1.1 bouyer #include <sys/syslog.h>
73 1.29 elad #include <sys/kauth.h>
74 1.1 bouyer
75 1.49 jdolecek #include <lib/libkern/crc16.h>
76 1.49 jdolecek
77 1.1 bouyer #include <ufs/ufs/inode.h>
78 1.1 bouyer #include <ufs/ufs/ufs_extern.h>
79 1.27 yamt #include <ufs/ufs/ufsmount.h>
80 1.1 bouyer
81 1.1 bouyer #include <ufs/ext2fs/ext2fs.h>
82 1.1 bouyer #include <ufs/ext2fs/ext2fs_extern.h>
83 1.1 bouyer
84 1.1 bouyer u_long ext2gennumber;
85 1.1 bouyer
86 1.26 xtraeme static daddr_t ext2fs_alloccg(struct inode *, int, daddr_t, int);
87 1.26 xtraeme static u_long ext2fs_dirpref(struct m_ext2fs *);
88 1.26 xtraeme static void ext2fs_fserr(struct m_ext2fs *, u_int, const char *);
89 1.26 xtraeme static u_long ext2fs_hashalloc(struct inode *, int, long, int,
90 1.40 tsutsui daddr_t (*)(struct inode *, int, daddr_t, int));
91 1.26 xtraeme static daddr_t ext2fs_nodealloccg(struct inode *, int, daddr_t, int);
92 1.26 xtraeme static daddr_t ext2fs_mapsearch(struct m_ext2fs *, char *, daddr_t);
93 1.53 christos static __inline void ext2fs_cg_update(struct m_ext2fs *, int,
94 1.53 christos struct ext2_gd *, int, int, int, daddr_t);
95 1.53 christos static uint16_t ext2fs_cg_get_csum(struct m_ext2fs *, int, struct ext2_gd *);
96 1.53 christos static void ext2fs_init_bb(struct m_ext2fs *, int, struct ext2_gd *,
97 1.53 christos char *);
98 1.1 bouyer
99 1.1 bouyer /*
100 1.1 bouyer * Allocate a block in the file system.
101 1.23 perry *
102 1.1 bouyer * A preference may be optionally specified. If a preference is given
103 1.1 bouyer * the following hierarchy is used to allocate a block:
104 1.1 bouyer * 1) allocate the requested block.
105 1.1 bouyer * 2) allocate a rotationally optimal block in the same cylinder.
106 1.1 bouyer * 3) allocate a block in the same cylinder group.
107 1.1 bouyer * 4) quadradically rehash into other cylinder groups, until an
108 1.1 bouyer * available block is located.
109 1.11 wiz * If no block preference is given the following hierarchy is used
110 1.1 bouyer * to allocate a block:
111 1.1 bouyer * 1) allocate a block in the cylinder group that contains the
112 1.1 bouyer * inode for the file.
113 1.1 bouyer * 2) quadradically rehash into other cylinder groups, until an
114 1.1 bouyer * available block is located.
115 1.1 bouyer */
116 1.1 bouyer int
117 1.32 christos ext2fs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref,
118 1.31 christos kauth_cred_t cred, daddr_t *bnp)
119 1.1 bouyer {
120 1.7 augustss struct m_ext2fs *fs;
121 1.15 fvdl daddr_t bno;
122 1.1 bouyer int cg;
123 1.23 perry
124 1.1 bouyer *bnp = 0;
125 1.1 bouyer fs = ip->i_e2fs;
126 1.1 bouyer #ifdef DIAGNOSTIC
127 1.1 bouyer if (cred == NOCRED)
128 1.14 provos panic("ext2fs_alloc: missing credential");
129 1.1 bouyer #endif /* DIAGNOSTIC */
130 1.1 bouyer if (fs->e2fs.e2fs_fbcount == 0)
131 1.1 bouyer goto nospace;
132 1.39 elad if (kauth_authorize_system(cred, KAUTH_SYSTEM_FS_RESERVEDSPACE, 0, NULL,
133 1.39 elad NULL, NULL) != 0 &&
134 1.34 elad freespace(fs) <= 0)
135 1.1 bouyer goto nospace;
136 1.1 bouyer if (bpref >= fs->e2fs.e2fs_bcount)
137 1.1 bouyer bpref = 0;
138 1.1 bouyer if (bpref == 0)
139 1.1 bouyer cg = ino_to_cg(fs, ip->i_number);
140 1.1 bouyer else
141 1.1 bouyer cg = dtog(fs, bpref);
142 1.15 fvdl bno = (daddr_t)ext2fs_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
143 1.40 tsutsui ext2fs_alloccg);
144 1.1 bouyer if (bno > 0) {
145 1.43 jakllsch ext2fs_setnblock(ip, ext2fs_nblock(ip) + btodb(fs->e2fs_bsize));
146 1.1 bouyer ip->i_flag |= IN_CHANGE | IN_UPDATE;
147 1.1 bouyer *bnp = bno;
148 1.48 christos return 0;
149 1.1 bouyer }
150 1.1 bouyer nospace:
151 1.29 elad ext2fs_fserr(fs, kauth_cred_geteuid(cred), "file system full");
152 1.1 bouyer uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt);
153 1.48 christos return ENOSPC;
154 1.1 bouyer }
155 1.1 bouyer
156 1.1 bouyer /*
157 1.1 bouyer * Allocate an inode in the file system.
158 1.23 perry *
159 1.1 bouyer * If allocating a directory, use ext2fs_dirpref to select the inode.
160 1.1 bouyer * If allocating in a directory, the following hierarchy is followed:
161 1.1 bouyer * 1) allocate the preferred inode.
162 1.1 bouyer * 2) allocate an inode in the same cylinder group.
163 1.1 bouyer * 3) quadradically rehash into other cylinder groups, until an
164 1.1 bouyer * available inode is located.
165 1.11 wiz * If no inode preference is given the following hierarchy is used
166 1.1 bouyer * to allocate an inode:
167 1.1 bouyer * 1) allocate an inode in cylinder group 0.
168 1.1 bouyer * 2) quadradically rehash into other cylinder groups, until an
169 1.1 bouyer * available inode is located.
170 1.1 bouyer */
171 1.1 bouyer int
172 1.52 hannken ext2fs_valloc(struct vnode *pvp, int mode, kauth_cred_t cred, ino_t *inop)
173 1.1 bouyer {
174 1.7 augustss struct inode *pip;
175 1.7 augustss struct m_ext2fs *fs;
176 1.1 bouyer ino_t ino, ipref;
177 1.52 hannken int cg;
178 1.23 perry
179 1.1 bouyer pip = VTOI(pvp);
180 1.1 bouyer fs = pip->i_e2fs;
181 1.1 bouyer if (fs->e2fs.e2fs_ficount == 0)
182 1.1 bouyer goto noinodes;
183 1.1 bouyer
184 1.1 bouyer if ((mode & IFMT) == IFDIR)
185 1.1 bouyer cg = ext2fs_dirpref(fs);
186 1.1 bouyer else
187 1.1 bouyer cg = ino_to_cg(fs, pip->i_number);
188 1.1 bouyer ipref = cg * fs->e2fs.e2fs_ipg + 1;
189 1.1 bouyer ino = (ino_t)ext2fs_hashalloc(pip, cg, (long)ipref, mode, ext2fs_nodealloccg);
190 1.1 bouyer if (ino == 0)
191 1.1 bouyer goto noinodes;
192 1.49 jdolecek
193 1.52 hannken *inop = ino;
194 1.52 hannken return 0;
195 1.1 bouyer
196 1.1 bouyer noinodes:
197 1.29 elad ext2fs_fserr(fs, kauth_cred_geteuid(cred), "out of inodes");
198 1.1 bouyer uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt);
199 1.48 christos return ENOSPC;
200 1.1 bouyer }
201 1.1 bouyer
202 1.1 bouyer /*
203 1.1 bouyer * Find a cylinder to place a directory.
204 1.1 bouyer *
205 1.1 bouyer * The policy implemented by this algorithm is to select from
206 1.1 bouyer * among those cylinder groups with above the average number of
207 1.1 bouyer * free inodes, the one with the smallest number of directories.
208 1.1 bouyer */
209 1.1 bouyer static u_long
210 1.26 xtraeme ext2fs_dirpref(struct m_ext2fs *fs)
211 1.1 bouyer {
212 1.1 bouyer int cg, maxspace, mincg, avgifree;
213 1.1 bouyer
214 1.1 bouyer avgifree = fs->e2fs.e2fs_ficount / fs->e2fs_ncg;
215 1.1 bouyer maxspace = 0;
216 1.1 bouyer mincg = -1;
217 1.53 christos for (cg = 0; cg < fs->e2fs_ncg; cg++) {
218 1.53 christos uint32_t nifree =
219 1.53 christos (fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree_hi) << 16)
220 1.53 christos | fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree);
221 1.53 christos if (nifree < avgifree) {
222 1.53 christos continue;
223 1.53 christos }
224 1.53 christos uint32_t nbfree =
225 1.53 christos (fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree_hi) << 16)
226 1.53 christos | fs2h16(fs->e2fs_gd[cg].ext2bgd_nbfree);
227 1.53 christos if (mincg == -1 || nbfree > maxspace) {
228 1.53 christos mincg = cg;
229 1.53 christos maxspace = nbfree;
230 1.1 bouyer }
231 1.53 christos }
232 1.1 bouyer return mincg;
233 1.1 bouyer }
234 1.1 bouyer
235 1.1 bouyer /*
236 1.1 bouyer * Select the desired position for the next block in a file. The file is
237 1.1 bouyer * logically divided into sections. The first section is composed of the
238 1.1 bouyer * direct blocks. Each additional section contains fs_maxbpg blocks.
239 1.23 perry *
240 1.1 bouyer * If no blocks have been allocated in the first section, the policy is to
241 1.1 bouyer * request a block in the same cylinder group as the inode that describes
242 1.1 bouyer * the file. Otherwise, the policy is to try to allocate the blocks
243 1.57 msaitoh * contiguously. The two fields of the ext2 inode extension (see
244 1.1 bouyer * ufs/ufs/inode.h) help this.
245 1.1 bouyer */
246 1.15 fvdl daddr_t
247 1.26 xtraeme ext2fs_blkpref(struct inode *ip, daddr_t lbn, int indx,
248 1.26 xtraeme int32_t *bap /* XXX ondisk32 */)
249 1.1 bouyer {
250 1.7 augustss struct m_ext2fs *fs;
251 1.7 augustss int cg, i;
252 1.1 bouyer
253 1.1 bouyer fs = ip->i_e2fs;
254 1.1 bouyer /*
255 1.1 bouyer * if we are doing contigous lbn allocation, try to alloc blocks
256 1.1 bouyer * contigously on disk
257 1.1 bouyer */
258 1.1 bouyer
259 1.1 bouyer if ( ip->i_e2fs_last_blk && lbn == ip->i_e2fs_last_lblk + 1) {
260 1.1 bouyer return ip->i_e2fs_last_blk + 1;
261 1.1 bouyer }
262 1.1 bouyer
263 1.1 bouyer /*
264 1.1 bouyer * bap, if provided, gives us a list of blocks to which we want to
265 1.1 bouyer * stay close
266 1.1 bouyer */
267 1.1 bouyer
268 1.1 bouyer if (bap) {
269 1.1 bouyer for (i = indx; i >= 0 ; i--) {
270 1.1 bouyer if (bap[i]) {
271 1.2 bouyer return fs2h32(bap[i]) + 1;
272 1.1 bouyer }
273 1.1 bouyer }
274 1.1 bouyer }
275 1.1 bouyer
276 1.1 bouyer /* fall back to the first block of the cylinder containing the inode */
277 1.1 bouyer
278 1.1 bouyer cg = ino_to_cg(fs, ip->i_number);
279 1.1 bouyer return fs->e2fs.e2fs_bpg * cg + fs->e2fs.e2fs_first_dblock + 1;
280 1.1 bouyer }
281 1.1 bouyer
282 1.1 bouyer /*
283 1.1 bouyer * Implement the cylinder overflow algorithm.
284 1.1 bouyer *
285 1.1 bouyer * The policy implemented by this algorithm is:
286 1.1 bouyer * 1) allocate the block in its requested cylinder group.
287 1.1 bouyer * 2) quadradically rehash on the cylinder group number.
288 1.1 bouyer * 3) brute force search for a free block.
289 1.1 bouyer */
290 1.1 bouyer static u_long
291 1.26 xtraeme ext2fs_hashalloc(struct inode *ip, int cg, long pref, int size,
292 1.26 xtraeme daddr_t (*allocator)(struct inode *, int, daddr_t, int))
293 1.1 bouyer {
294 1.7 augustss struct m_ext2fs *fs;
295 1.1 bouyer long result;
296 1.1 bouyer int i, icg = cg;
297 1.1 bouyer
298 1.1 bouyer fs = ip->i_e2fs;
299 1.1 bouyer /*
300 1.1 bouyer * 1: preferred cylinder group
301 1.1 bouyer */
302 1.1 bouyer result = (*allocator)(ip, cg, pref, size);
303 1.1 bouyer if (result)
304 1.48 christos return result;
305 1.1 bouyer /*
306 1.1 bouyer * 2: quadratic rehash
307 1.1 bouyer */
308 1.1 bouyer for (i = 1; i < fs->e2fs_ncg; i *= 2) {
309 1.1 bouyer cg += i;
310 1.1 bouyer if (cg >= fs->e2fs_ncg)
311 1.1 bouyer cg -= fs->e2fs_ncg;
312 1.1 bouyer result = (*allocator)(ip, cg, 0, size);
313 1.1 bouyer if (result)
314 1.48 christos return result;
315 1.1 bouyer }
316 1.1 bouyer /*
317 1.1 bouyer * 3: brute force search
318 1.1 bouyer * Note that we start at i == 2, since 0 was checked initially,
319 1.1 bouyer * and 1 is always checked in the quadratic rehash.
320 1.1 bouyer */
321 1.1 bouyer cg = (icg + 2) % fs->e2fs_ncg;
322 1.1 bouyer for (i = 2; i < fs->e2fs_ncg; i++) {
323 1.1 bouyer result = (*allocator)(ip, cg, 0, size);
324 1.1 bouyer if (result)
325 1.48 christos return result;
326 1.1 bouyer cg++;
327 1.1 bouyer if (cg == fs->e2fs_ncg)
328 1.1 bouyer cg = 0;
329 1.1 bouyer }
330 1.48 christos return 0;
331 1.1 bouyer }
332 1.1 bouyer
333 1.1 bouyer /*
334 1.1 bouyer * Determine whether a block can be allocated.
335 1.1 bouyer *
336 1.1 bouyer * Check to see if a block of the appropriate size is available,
337 1.1 bouyer * and if it is, allocate it.
338 1.1 bouyer */
339 1.1 bouyer
340 1.15 fvdl static daddr_t
341 1.32 christos ext2fs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
342 1.1 bouyer {
343 1.7 augustss struct m_ext2fs *fs;
344 1.7 augustss char *bbp;
345 1.1 bouyer struct buf *bp;
346 1.1 bouyer int error, bno, start, end, loc;
347 1.1 bouyer
348 1.1 bouyer fs = ip->i_e2fs;
349 1.53 christos if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0 &&
350 1.53 christos fs->e2fs_gd[cg].ext2bgd_nbfree_hi == 0)
351 1.48 christos return 0;
352 1.53 christos error = bread(ip->i_devvp, EXT2_FSBTODB64(fs,
353 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap),
354 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap_hi)),
355 1.46 maxv (int)fs->e2fs_bsize, B_MODIFY, &bp);
356 1.1 bouyer if (error) {
357 1.48 christos return 0;
358 1.1 bouyer }
359 1.1 bouyer bbp = (char *)bp->b_data;
360 1.1 bouyer
361 1.1 bouyer if (dtog(fs, bpref) != cg)
362 1.1 bouyer bpref = 0;
363 1.49 jdolecek
364 1.49 jdolecek /* initialize block bitmap now if uninit */
365 1.49 jdolecek if (__predict_false(E2FS_HAS_GD_CSUM(fs) &&
366 1.49 jdolecek (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)))) {
367 1.49 jdolecek ext2fs_init_bb(fs, cg, &fs->e2fs_gd[cg], bbp);
368 1.49 jdolecek fs->e2fs_gd[cg].ext2bgd_flags &= h2fs16(~E2FS_BG_BLOCK_UNINIT);
369 1.49 jdolecek }
370 1.49 jdolecek
371 1.1 bouyer if (bpref != 0) {
372 1.1 bouyer bpref = dtogd(fs, bpref);
373 1.1 bouyer /*
374 1.1 bouyer * if the requested block is available, use it
375 1.1 bouyer */
376 1.1 bouyer if (isclr(bbp, bpref)) {
377 1.1 bouyer bno = bpref;
378 1.1 bouyer goto gotit;
379 1.1 bouyer }
380 1.1 bouyer }
381 1.1 bouyer /*
382 1.1 bouyer * no blocks in the requested cylinder, so take next
383 1.1 bouyer * available one in this cylinder group.
384 1.1 bouyer * first try to get 8 contigous blocks, then fall back to a single
385 1.1 bouyer * block.
386 1.1 bouyer */
387 1.1 bouyer if (bpref)
388 1.1 bouyer start = dtogd(fs, bpref) / NBBY;
389 1.1 bouyer else
390 1.1 bouyer start = 0;
391 1.1 bouyer end = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
392 1.1 bouyer for (loc = start; loc < end; loc++) {
393 1.1 bouyer if (bbp[loc] == 0) {
394 1.1 bouyer bno = loc * NBBY;
395 1.1 bouyer goto gotit;
396 1.1 bouyer }
397 1.1 bouyer }
398 1.1 bouyer for (loc = 0; loc < start; loc++) {
399 1.1 bouyer if (bbp[loc] == 0) {
400 1.1 bouyer bno = loc * NBBY;
401 1.1 bouyer goto gotit;
402 1.1 bouyer }
403 1.1 bouyer }
404 1.1 bouyer
405 1.1 bouyer bno = ext2fs_mapsearch(fs, bbp, bpref);
406 1.50 jdolecek #if 0
407 1.51 jdolecek /*
408 1.51 jdolecek * XXX jdolecek mapsearch actually never fails, it panics instead.
409 1.51 jdolecek * If re-enabling, make sure to brele() before returning.
410 1.51 jdolecek */
411 1.1 bouyer if (bno < 0)
412 1.48 christos return 0;
413 1.50 jdolecek #endif
414 1.1 bouyer gotit:
415 1.1 bouyer #ifdef DIAGNOSTIC
416 1.15 fvdl if (isset(bbp, (daddr_t)bno)) {
417 1.53 christos printf("%s: cg=%d bno=%d fs=%s\n", __func__,
418 1.53 christos cg, bno, fs->e2fs_fsmnt);
419 1.2 bouyer panic("ext2fs_alloccg: dup alloc");
420 1.1 bouyer }
421 1.1 bouyer #endif
422 1.15 fvdl setbit(bbp, (daddr_t)bno);
423 1.1 bouyer fs->e2fs.e2fs_fbcount--;
424 1.49 jdolecek ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], -1, 0, 0, 0);
425 1.1 bouyer fs->e2fs_fmod = 1;
426 1.1 bouyer bdwrite(bp);
427 1.48 christos return cg * fs->e2fs.e2fs_fpg + fs->e2fs.e2fs_first_dblock + bno;
428 1.1 bouyer }
429 1.1 bouyer
430 1.1 bouyer /*
431 1.1 bouyer * Determine whether an inode can be allocated.
432 1.1 bouyer *
433 1.1 bouyer * Check to see if an inode is available, and if it is,
434 1.1 bouyer * allocate it using the following policy:
435 1.1 bouyer * 1) allocate the requested inode.
436 1.1 bouyer * 2) allocate the next available inode after the requested
437 1.1 bouyer * inode in the specified cylinder group.
438 1.1 bouyer */
439 1.15 fvdl static daddr_t
440 1.26 xtraeme ext2fs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
441 1.1 bouyer {
442 1.7 augustss struct m_ext2fs *fs;
443 1.7 augustss char *ibp;
444 1.1 bouyer struct buf *bp;
445 1.1 bouyer int error, start, len, loc, map, i;
446 1.1 bouyer
447 1.1 bouyer ipref--; /* to avoid a lot of (ipref -1) */
448 1.33 chs if (ipref == -1)
449 1.33 chs ipref = 0;
450 1.1 bouyer fs = ip->i_e2fs;
451 1.56 christos if (fs->e2fs_gd[cg].ext2bgd_nifree == 0 &&
452 1.53 christos fs->e2fs_gd[cg].ext2bgd_nifree_hi == 0)
453 1.48 christos return 0;
454 1.53 christos error = bread(ip->i_devvp, EXT2_FSBTODB64(fs,
455 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap),
456 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap_hi)),
457 1.46 maxv (int)fs->e2fs_bsize, B_MODIFY, &bp);
458 1.1 bouyer if (error) {
459 1.48 christos return 0;
460 1.1 bouyer }
461 1.1 bouyer ibp = (char *)bp->b_data;
462 1.49 jdolecek
463 1.49 jdolecek KASSERT(!E2FS_HAS_GD_CSUM(fs) || (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0);
464 1.49 jdolecek
465 1.49 jdolecek /* initialize inode bitmap now if uninit */
466 1.49 jdolecek if (__predict_false(E2FS_HAS_GD_CSUM(fs) &&
467 1.49 jdolecek (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)))) {
468 1.49 jdolecek KASSERT(fs2h16(fs->e2fs_gd[cg].ext2bgd_nifree) == fs->e2fs.e2fs_ipg);
469 1.49 jdolecek memset(ibp, 0, fs->e2fs_bsize);
470 1.49 jdolecek fs->e2fs_gd[cg].ext2bgd_flags &= h2fs16(~E2FS_BG_INODE_UNINIT);
471 1.49 jdolecek }
472 1.49 jdolecek
473 1.1 bouyer if (ipref) {
474 1.1 bouyer ipref %= fs->e2fs.e2fs_ipg;
475 1.1 bouyer if (isclr(ibp, ipref))
476 1.1 bouyer goto gotit;
477 1.1 bouyer }
478 1.1 bouyer start = ipref / NBBY;
479 1.1 bouyer len = howmany(fs->e2fs.e2fs_ipg - ipref, NBBY);
480 1.1 bouyer loc = skpc(0xff, len, &ibp[start]);
481 1.1 bouyer if (loc == 0) {
482 1.1 bouyer len = start + 1;
483 1.1 bouyer start = 0;
484 1.1 bouyer loc = skpc(0xff, len, &ibp[0]);
485 1.1 bouyer if (loc == 0) {
486 1.53 christos printf("%s: cg = %d, ipref = %lld, fs = %s\n", __func__,
487 1.53 christos cg, (long long)ipref, fs->e2fs_fsmnt);
488 1.53 christos panic("%s: map corrupted", __func__);
489 1.1 bouyer /* NOTREACHED */
490 1.1 bouyer }
491 1.1 bouyer }
492 1.1 bouyer i = start + len - loc;
493 1.42 rmind map = ibp[i] ^ 0xff;
494 1.42 rmind if (map == 0) {
495 1.53 christos printf("%s: fs = %s\n", __func__, fs->e2fs_fsmnt);
496 1.53 christos panic("%s: inode not in map", __func__);
497 1.1 bouyer }
498 1.42 rmind ipref = i * NBBY + ffs(map) - 1;
499 1.1 bouyer gotit:
500 1.1 bouyer setbit(ibp, ipref);
501 1.1 bouyer fs->e2fs.e2fs_ficount--;
502 1.49 jdolecek ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg],
503 1.49 jdolecek 0, -1, ((mode & IFMT) == IFDIR) ? 1 : 0, ipref);
504 1.1 bouyer fs->e2fs_fmod = 1;
505 1.1 bouyer bdwrite(bp);
506 1.48 christos return cg * fs->e2fs.e2fs_ipg + ipref + 1;
507 1.1 bouyer }
508 1.1 bouyer
509 1.1 bouyer /*
510 1.1 bouyer * Free a block.
511 1.1 bouyer *
512 1.1 bouyer * The specified block is placed back in the
513 1.1 bouyer * free map.
514 1.1 bouyer */
515 1.1 bouyer void
516 1.26 xtraeme ext2fs_blkfree(struct inode *ip, daddr_t bno)
517 1.1 bouyer {
518 1.7 augustss struct m_ext2fs *fs;
519 1.7 augustss char *bbp;
520 1.1 bouyer struct buf *bp;
521 1.1 bouyer int error, cg;
522 1.1 bouyer
523 1.1 bouyer fs = ip->i_e2fs;
524 1.1 bouyer cg = dtog(fs, bno);
525 1.49 jdolecek
526 1.53 christos KASSERT(!E2FS_HAS_GD_CSUM(fs) ||
527 1.53 christos (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_BLOCK_UNINIT)) == 0);
528 1.49 jdolecek
529 1.1 bouyer if ((u_int)bno >= fs->e2fs.e2fs_bcount) {
530 1.53 christos printf("%s: bad block %jd, ino %ju\n",
531 1.53 christos __func__, (intmax_t)bno, (uintmax_t)ip->i_number);
532 1.37 mrg ext2fs_fserr(fs, ip->i_uid, "bad block");
533 1.1 bouyer return;
534 1.1 bouyer }
535 1.53 christos error = bread(ip->i_devvp, EXT2_FSBTODB64(fs,
536 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap),
537 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_b_bitmap_hi)),
538 1.53 christos (int)fs->e2fs_bsize, B_MODIFY, &bp);
539 1.1 bouyer if (error) {
540 1.1 bouyer return;
541 1.1 bouyer }
542 1.1 bouyer bbp = (char *)bp->b_data;
543 1.1 bouyer bno = dtogd(fs, bno);
544 1.1 bouyer if (isclr(bbp, bno)) {
545 1.53 christos printf("%s: dev = %#jx, block = %jd, fs = %s\n", __func__,
546 1.53 christos (uintmax_t)ip->i_dev, (intmax_t)bno,
547 1.38 christos fs->e2fs_fsmnt);
548 1.53 christos panic("%s: freeing free block", __func__);
549 1.1 bouyer }
550 1.1 bouyer clrbit(bbp, bno);
551 1.1 bouyer fs->e2fs.e2fs_fbcount++;
552 1.49 jdolecek ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg], 1, 0, 0, 0);
553 1.1 bouyer fs->e2fs_fmod = 1;
554 1.1 bouyer bdwrite(bp);
555 1.1 bouyer }
556 1.1 bouyer
557 1.1 bouyer /*
558 1.1 bouyer * Free an inode.
559 1.1 bouyer *
560 1.1 bouyer * The specified inode is placed back in the free map.
561 1.1 bouyer */
562 1.1 bouyer int
563 1.27 yamt ext2fs_vfree(struct vnode *pvp, ino_t ino, int mode)
564 1.1 bouyer {
565 1.7 augustss struct m_ext2fs *fs;
566 1.7 augustss char *ibp;
567 1.7 augustss struct inode *pip;
568 1.1 bouyer struct buf *bp;
569 1.1 bouyer int error, cg;
570 1.1 bouyer
571 1.27 yamt pip = VTOI(pvp);
572 1.1 bouyer fs = pip->i_e2fs;
573 1.49 jdolecek
574 1.33 chs if ((u_int)ino > fs->e2fs.e2fs_icount || (u_int)ino < EXT2_FIRSTINO)
575 1.53 christos panic("%s: range: dev = %#jx, ino = %ju, fs = %s",
576 1.53 christos __func__, (uintmax_t)pip->i_dev, (uintmax_t)ino,
577 1.38 christos fs->e2fs_fsmnt);
578 1.49 jdolecek
579 1.1 bouyer cg = ino_to_cg(fs, ino);
580 1.49 jdolecek
581 1.53 christos KASSERT(!E2FS_HAS_GD_CSUM(fs) ||
582 1.53 christos (fs->e2fs_gd[cg].ext2bgd_flags & h2fs16(E2FS_BG_INODE_UNINIT)) == 0);
583 1.49 jdolecek
584 1.53 christos error = bread(pip->i_devvp, EXT2_FSBTODB64(fs,
585 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap),
586 1.53 christos fs2h32(fs->e2fs_gd[cg].ext2bgd_i_bitmap_hi)),
587 1.53 christos (int)fs->e2fs_bsize, B_MODIFY, &bp);
588 1.1 bouyer if (error) {
589 1.48 christos return 0;
590 1.1 bouyer }
591 1.1 bouyer ibp = (char *)bp->b_data;
592 1.1 bouyer ino = (ino - 1) % fs->e2fs.e2fs_ipg;
593 1.1 bouyer if (isclr(ibp, ino)) {
594 1.53 christos printf("%s: dev = %#jx, ino = %ju, fs = %s\n", __func__,
595 1.53 christos (uintmax_t)pip->i_dev,
596 1.53 christos (uintmax_t)ino, fs->e2fs_fsmnt);
597 1.1 bouyer if (fs->e2fs_ronly == 0)
598 1.53 christos panic("%s: freeing free inode", __func__);
599 1.1 bouyer }
600 1.1 bouyer clrbit(ibp, ino);
601 1.1 bouyer fs->e2fs.e2fs_ficount++;
602 1.49 jdolecek ext2fs_cg_update(fs, cg, &fs->e2fs_gd[cg],
603 1.49 jdolecek 0, 1, ((mode & IFMT) == IFDIR) ? -1 : 0, 0);
604 1.1 bouyer fs->e2fs_fmod = 1;
605 1.1 bouyer bdwrite(bp);
606 1.48 christos return 0;
607 1.1 bouyer }
608 1.1 bouyer
609 1.1 bouyer /*
610 1.1 bouyer * Find a block in the specified cylinder group.
611 1.1 bouyer *
612 1.1 bouyer * It is a panic if a request is made to find a block if none are
613 1.1 bouyer * available.
614 1.1 bouyer */
615 1.1 bouyer
616 1.15 fvdl static daddr_t
617 1.26 xtraeme ext2fs_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref)
618 1.1 bouyer {
619 1.1 bouyer int start, len, loc, i, map;
620 1.1 bouyer
621 1.1 bouyer /*
622 1.1 bouyer * find the fragment by searching through the free block
623 1.1 bouyer * map for an appropriate bit pattern
624 1.1 bouyer */
625 1.1 bouyer if (bpref)
626 1.1 bouyer start = dtogd(fs, bpref) / NBBY;
627 1.1 bouyer else
628 1.1 bouyer start = 0;
629 1.1 bouyer len = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
630 1.1 bouyer loc = skpc(0xff, len, &bbp[start]);
631 1.1 bouyer if (loc == 0) {
632 1.1 bouyer len = start + 1;
633 1.1 bouyer start = 0;
634 1.1 bouyer loc = skpc(0xff, len, &bbp[start]);
635 1.1 bouyer if (loc == 0) {
636 1.53 christos printf("%s: start = %d, len = %d, fs = %s\n",
637 1.53 christos __func__, start, len, fs->e2fs_fsmnt);
638 1.53 christos panic("%s: map corrupted", __func__);
639 1.1 bouyer /* NOTREACHED */
640 1.1 bouyer }
641 1.1 bouyer }
642 1.1 bouyer i = start + len - loc;
643 1.42 rmind map = bbp[i] ^ 0xff;
644 1.42 rmind if (map == 0) {
645 1.53 christos printf("%s: fs = %s\n", __func__, fs->e2fs_fsmnt);
646 1.53 christos panic("%s: block not in map", __func__);
647 1.42 rmind }
648 1.42 rmind return i * NBBY + ffs(map) - 1;
649 1.1 bouyer }
650 1.1 bouyer
651 1.1 bouyer /*
652 1.1 bouyer * Fserr prints the name of a file system with an error diagnostic.
653 1.23 perry *
654 1.1 bouyer * The form of the error message is:
655 1.1 bouyer * fs: error message
656 1.1 bouyer */
657 1.1 bouyer static void
658 1.26 xtraeme ext2fs_fserr(struct m_ext2fs *fs, u_int uid, const char *cp)
659 1.1 bouyer {
660 1.1 bouyer
661 1.1 bouyer log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->e2fs_fsmnt, cp);
662 1.1 bouyer }
663 1.49 jdolecek
664 1.49 jdolecek static __inline void
665 1.49 jdolecek ext2fs_cg_update(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, int nbfree, int nifree, int ndirs, daddr_t ioff)
666 1.49 jdolecek {
667 1.49 jdolecek if (nifree) {
668 1.53 christos uint32_t ext2bgd_nifree = fs2h16(gd->ext2bgd_nifree) |
669 1.53 christos (fs2h16(gd->ext2bgd_nifree_hi) << 16);
670 1.54 riastrad ext2bgd_nifree += nifree;
671 1.53 christos gd->ext2bgd_nifree = h2fs16(ext2bgd_nifree);
672 1.53 christos gd->ext2bgd_nifree_hi = h2fs16(ext2bgd_nifree >> 16);
673 1.49 jdolecek /*
674 1.49 jdolecek * If we allocated inode on bigger offset than what was
675 1.49 jdolecek * ever used before, bump the itable_unused count. This
676 1.49 jdolecek * member only ever grows, and is used only for initialization
677 1.49 jdolecek * !INODE_ZEROED groups with used inodes. Of course, by the
678 1.49 jdolecek * time we get here the itables are already zeroed, but
679 1.49 jdolecek * e2fstools fsck.ext4 still checks this.
680 1.49 jdolecek */
681 1.53 christos if (E2FS_HAS_GD_CSUM(fs) && nifree < 0 &&
682 1.53 christos (ioff + 1) >= (fs->e2fs.e2fs_ipg -
683 1.53 christos fs2h16(gd->ext2bgd_itable_unused_lo))) {
684 1.53 christos gd->ext2bgd_itable_unused_lo =
685 1.53 christos h2fs16(fs->e2fs.e2fs_ipg - (ioff + 1));
686 1.49 jdolecek }
687 1.49 jdolecek
688 1.53 christos KASSERT(!E2FS_HAS_GD_CSUM(fs) ||
689 1.53 christos gd->ext2bgd_itable_unused_lo <= ext2bgd_nifree);
690 1.49 jdolecek }
691 1.49 jdolecek
692 1.49 jdolecek
693 1.53 christos if (nbfree) {
694 1.53 christos uint32_t ext2bgd_nbfree = fs2h16(gd->ext2bgd_nbfree)
695 1.53 christos | (fs2h16(gd->ext2bgd_nbfree_hi) << 16);
696 1.53 christos ext2bgd_nbfree += nbfree;
697 1.53 christos gd->ext2bgd_nbfree = h2fs16(ext2bgd_nbfree);
698 1.53 christos gd->ext2bgd_nbfree_hi = h2fs16(ext2bgd_nbfree >> 16);
699 1.53 christos }
700 1.53 christos
701 1.53 christos if (ndirs) {
702 1.53 christos uint32_t ext2bgd_ndirs = fs2h16(gd->ext2bgd_ndirs)
703 1.53 christos | (fs2h16(gd->ext2bgd_ndirs_hi) << 16);
704 1.53 christos ext2bgd_ndirs += ndirs;
705 1.53 christos gd->ext2bgd_ndirs = h2fs16(ext2bgd_ndirs);
706 1.53 christos gd->ext2bgd_ndirs_hi = h2fs16(ext2bgd_ndirs >> 16);
707 1.53 christos }
708 1.49 jdolecek
709 1.49 jdolecek if (E2FS_HAS_GD_CSUM(fs))
710 1.49 jdolecek gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd);
711 1.49 jdolecek }
712 1.49 jdolecek
713 1.55 christos static const uint32_t ext2fs_crc32c_table[256] = {
714 1.55 christos 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
715 1.55 christos 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
716 1.55 christos 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
717 1.55 christos 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
718 1.55 christos 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
719 1.55 christos 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
720 1.55 christos 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
721 1.55 christos 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
722 1.55 christos 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
723 1.55 christos 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
724 1.55 christos 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
725 1.55 christos 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
726 1.55 christos 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
727 1.55 christos 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
728 1.55 christos 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
729 1.55 christos 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
730 1.55 christos 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
731 1.55 christos 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
732 1.55 christos 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
733 1.55 christos 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
734 1.55 christos 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
735 1.55 christos 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
736 1.55 christos 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
737 1.55 christos 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
738 1.55 christos 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
739 1.55 christos 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
740 1.55 christos 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
741 1.55 christos 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
742 1.55 christos 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
743 1.55 christos 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
744 1.55 christos 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
745 1.55 christos 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
746 1.55 christos 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
747 1.55 christos 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
748 1.55 christos 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
749 1.55 christos 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
750 1.55 christos 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
751 1.55 christos 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
752 1.55 christos 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
753 1.55 christos 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
754 1.55 christos 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
755 1.55 christos 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
756 1.55 christos 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
757 1.55 christos 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
758 1.55 christos 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
759 1.55 christos 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
760 1.55 christos 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
761 1.55 christos 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
762 1.55 christos 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
763 1.55 christos 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
764 1.55 christos 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
765 1.55 christos 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
766 1.55 christos 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
767 1.55 christos 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
768 1.55 christos 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
769 1.55 christos 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
770 1.55 christos 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
771 1.55 christos 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
772 1.55 christos 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
773 1.55 christos 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
774 1.55 christos 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
775 1.55 christos 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
776 1.55 christos 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
777 1.55 christos 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
778 1.55 christos };
779 1.55 christos
780 1.55 christos static uint32_t
781 1.55 christos ext2fs_crc32c(uint32_t last, const void *vbuf, size_t len)
782 1.55 christos {
783 1.55 christos uint32_t crc = last;
784 1.55 christos const uint8_t *buf = vbuf;
785 1.55 christos
786 1.55 christos while (len--)
787 1.55 christos crc = ext2fs_crc32c_table[(crc ^ *buf++) & 0xff] ^ (crc >> 8);
788 1.55 christos
789 1.55 christos return crc;
790 1.55 christos }
791 1.55 christos
792 1.49 jdolecek /*
793 1.49 jdolecek * Compute group description csum. Structure data must be LE (not host).
794 1.49 jdolecek * Returned as LE (disk encoding).
795 1.49 jdolecek */
796 1.49 jdolecek static uint16_t
797 1.49 jdolecek ext2fs_cg_get_csum(struct m_ext2fs *fs, int cg, struct ext2_gd *gd)
798 1.49 jdolecek {
799 1.49 jdolecek uint16_t crc;
800 1.53 christos size_t cgsize = 1 << fs->e2fs_group_desc_shift;
801 1.49 jdolecek uint32_t cg_bswapped = h2fs32((uint32_t)cg);
802 1.49 jdolecek size_t off;
803 1.49 jdolecek
804 1.55 christos if (EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) {
805 1.55 christos uint32_t crc32;
806 1.55 christos uint8_t dummy[2] = {0, 0};
807 1.55 christos
808 1.55 christos off = offsetof(struct ext2_gd, ext2bgd_checksum);
809 1.55 christos
810 1.55 christos crc32 = ext2fs_crc32c(~0, fs->e2fs.e2fs_uuid,
811 1.55 christos sizeof(fs->e2fs.e2fs_uuid));
812 1.55 christos crc32 = ext2fs_crc32c(crc32, &cg_bswapped, sizeof(cg_bswapped));
813 1.55 christos crc32 = ext2fs_crc32c(crc32, gd, off);
814 1.55 christos crc32 = ext2fs_crc32c(crc32, dummy, 2);
815 1.55 christos crc32 = ext2fs_crc32c(crc32, gd + off + 2, cgsize - (off + 2));
816 1.55 christos
817 1.55 christos return h2fs16(crc32 & 0xffff);
818 1.55 christos }
819 1.55 christos
820 1.49 jdolecek if (!EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM))
821 1.49 jdolecek return 0;
822 1.49 jdolecek
823 1.49 jdolecek off = offsetof(struct ext2_gd, ext2bgd_checksum);
824 1.49 jdolecek
825 1.55 christos crc = crc16(~0, (uint8_t *)fs->e2fs.e2fs_uuid,
826 1.55 christos sizeof(fs->e2fs.e2fs_uuid));
827 1.49 jdolecek crc = crc16(crc, (uint8_t *)&cg_bswapped, sizeof(cg_bswapped));
828 1.49 jdolecek crc = crc16(crc, (uint8_t *)gd, off);
829 1.53 christos crc = crc16(crc, (uint8_t *)gd + off + 2, cgsize - (off + 2));
830 1.49 jdolecek
831 1.49 jdolecek return h2fs16(crc);
832 1.49 jdolecek }
833 1.49 jdolecek
834 1.49 jdolecek static void
835 1.49 jdolecek ext2fs_init_bb(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, char *bbp)
836 1.49 jdolecek {
837 1.49 jdolecek int i;
838 1.49 jdolecek
839 1.49 jdolecek memset(bbp, 0, fs->e2fs_bsize);
840 1.49 jdolecek
841 1.49 jdolecek /*
842 1.49 jdolecek * No block was ever allocated on this cg before, so the only used
843 1.49 jdolecek * blocks are metadata blocks on start of the group. We could optimize
844 1.49 jdolecek * this to set by bytes, but since this is done once per the group
845 1.49 jdolecek * in lifetime of filesystem, it really is not worth it.
846 1.49 jdolecek */
847 1.49 jdolecek for(i=0; i < fs->e2fs.e2fs_bpg - fs2h16(gd->ext2bgd_nbfree); i++)
848 1.49 jdolecek setbit(bbp, i);
849 1.49 jdolecek }
850 1.49 jdolecek
851 1.49 jdolecek /*
852 1.49 jdolecek * Verify csum and initialize itable if not done already
853 1.49 jdolecek */
854 1.49 jdolecek int
855 1.49 jdolecek ext2fs_cg_verify_and_initialize(struct vnode *devvp, struct m_ext2fs *fs, int ronly)
856 1.49 jdolecek {
857 1.49 jdolecek struct ext2_gd *gd;
858 1.49 jdolecek ino_t ioff;
859 1.49 jdolecek size_t boff;
860 1.49 jdolecek struct buf *bp;
861 1.49 jdolecek int cg, i, error;
862 1.49 jdolecek
863 1.49 jdolecek if (!E2FS_HAS_GD_CSUM(fs))
864 1.49 jdolecek return 0;
865 1.49 jdolecek
866 1.53 christos for(cg = 0; cg < fs->e2fs_ncg; cg++) {
867 1.49 jdolecek gd = &fs->e2fs_gd[cg];
868 1.49 jdolecek
869 1.49 jdolecek /* Verify checksum */
870 1.53 christos uint16_t csum = ext2fs_cg_get_csum(fs, cg, gd);
871 1.53 christos if (gd->ext2bgd_checksum != csum) {
872 1.53 christos printf("%s: group %d invalid csum (%#x != %#x)\n",
873 1.53 christos __func__, cg, gd->ext2bgd_checksum, csum);
874 1.49 jdolecek return EINVAL;
875 1.49 jdolecek }
876 1.49 jdolecek
877 1.49 jdolecek /* if mounting read-write, zero itable if not already done */
878 1.53 christos if (ronly ||
879 1.53 christos (gd->ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0)
880 1.49 jdolecek continue;
881 1.49 jdolecek
882 1.49 jdolecek /*
883 1.49 jdolecek * We are skipping already used inodes, zero rest of itable
884 1.49 jdolecek * blocks. First block to zero could be only partial wipe, all
885 1.49 jdolecek * others are wiped completely. This might take a while,
886 1.49 jdolecek * there could be many inode table blocks. We use
887 1.49 jdolecek * delayed writes, so this shouldn't block for very
888 1.49 jdolecek * long.
889 1.49 jdolecek */
890 1.49 jdolecek ioff = fs->e2fs.e2fs_ipg - fs2h16(gd->ext2bgd_itable_unused_lo);
891 1.49 jdolecek boff = (ioff % fs->e2fs_ipb) * EXT2_DINODE_SIZE(fs);
892 1.49 jdolecek
893 1.49 jdolecek for(i = ioff / fs->e2fs_ipb; i < fs->e2fs_itpg; i++) {
894 1.49 jdolecek if (boff) {
895 1.49 jdolecek /* partial wipe, must read old data */
896 1.53 christos error = bread(devvp, EXT2_FSBTODB64OFF(fs,
897 1.53 christos fs2h32(gd->ext2bgd_i_tables),
898 1.53 christos fs2h32(gd->ext2bgd_i_tables_hi), i),
899 1.53 christos (int)fs->e2fs_bsize, B_MODIFY, &bp);
900 1.49 jdolecek if (error) {
901 1.53 christos printf("%s: can't read itable block",
902 1.53 christos __func__);
903 1.49 jdolecek return error;
904 1.49 jdolecek }
905 1.53 christos memset((char *)bp->b_data + boff, 0,
906 1.53 christos fs->e2fs_bsize - boff);
907 1.49 jdolecek boff = 0;
908 1.49 jdolecek } else {
909 1.49 jdolecek /*
910 1.49 jdolecek * Complete wipe, don't need to read data. This
911 1.49 jdolecek * assumes nothing else is changing the data.
912 1.49 jdolecek */
913 1.53 christos bp = getblk(devvp, EXT2_FSBTODB64OFF(fs,
914 1.53 christos fs2h32(gd->ext2bgd_i_tables),
915 1.53 christos fs2h32(gd->ext2bgd_i_tables_hi), i),
916 1.53 christos (int)fs->e2fs_bsize, 0, 0);
917 1.49 jdolecek clrbuf(bp);
918 1.49 jdolecek }
919 1.54 riastrad
920 1.49 jdolecek bdwrite(bp);
921 1.49 jdolecek }
922 1.49 jdolecek
923 1.49 jdolecek gd->ext2bgd_flags |= h2fs16(E2FS_BG_INODE_ZEROED);
924 1.49 jdolecek gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd);
925 1.49 jdolecek fs->e2fs_fmod = 1;
926 1.49 jdolecek }
927 1.49 jdolecek
928 1.49 jdolecek return 0;
929 1.49 jdolecek }
930