ext2fs_alloc.c revision 1.54 1 1.54 riastrad /* $NetBSD: ext2fs_alloc.c,v 1.54 2023/08/26 05:22:50 riastradh 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.54 riastrad __KERNEL_RCSID(0, "$NetBSD: ext2fs_alloc.c,v 1.54 2023/08/26 05:22:50 riastradh 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.10 toshii * contigously. 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.53 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.49 jdolecek /*
714 1.49 jdolecek * Compute group description csum. Structure data must be LE (not host).
715 1.49 jdolecek * Returned as LE (disk encoding).
716 1.49 jdolecek */
717 1.49 jdolecek static uint16_t
718 1.49 jdolecek ext2fs_cg_get_csum(struct m_ext2fs *fs, int cg, struct ext2_gd *gd)
719 1.49 jdolecek {
720 1.49 jdolecek uint16_t crc;
721 1.53 christos size_t cgsize = 1 << fs->e2fs_group_desc_shift;
722 1.49 jdolecek uint32_t cg_bswapped = h2fs32((uint32_t)cg);
723 1.49 jdolecek size_t off;
724 1.49 jdolecek
725 1.49 jdolecek if (!EXT2F_HAS_ROCOMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM))
726 1.49 jdolecek return 0;
727 1.49 jdolecek
728 1.49 jdolecek off = offsetof(struct ext2_gd, ext2bgd_checksum);
729 1.49 jdolecek
730 1.49 jdolecek crc = crc16(~0, (uint8_t *)fs->e2fs.e2fs_uuid, sizeof(fs->e2fs.e2fs_uuid));
731 1.49 jdolecek crc = crc16(crc, (uint8_t *)&cg_bswapped, sizeof(cg_bswapped));
732 1.49 jdolecek crc = crc16(crc, (uint8_t *)gd, off);
733 1.53 christos crc = crc16(crc, (uint8_t *)gd + off + 2, cgsize - (off + 2));
734 1.49 jdolecek
735 1.49 jdolecek return h2fs16(crc);
736 1.49 jdolecek }
737 1.49 jdolecek
738 1.49 jdolecek static void
739 1.49 jdolecek ext2fs_init_bb(struct m_ext2fs *fs, int cg, struct ext2_gd *gd, char *bbp)
740 1.49 jdolecek {
741 1.49 jdolecek int i;
742 1.49 jdolecek
743 1.49 jdolecek memset(bbp, 0, fs->e2fs_bsize);
744 1.49 jdolecek
745 1.49 jdolecek /*
746 1.49 jdolecek * No block was ever allocated on this cg before, so the only used
747 1.49 jdolecek * blocks are metadata blocks on start of the group. We could optimize
748 1.49 jdolecek * this to set by bytes, but since this is done once per the group
749 1.49 jdolecek * in lifetime of filesystem, it really is not worth it.
750 1.49 jdolecek */
751 1.49 jdolecek for(i=0; i < fs->e2fs.e2fs_bpg - fs2h16(gd->ext2bgd_nbfree); i++)
752 1.49 jdolecek setbit(bbp, i);
753 1.49 jdolecek }
754 1.49 jdolecek
755 1.49 jdolecek /*
756 1.49 jdolecek * Verify csum and initialize itable if not done already
757 1.49 jdolecek */
758 1.49 jdolecek int
759 1.49 jdolecek ext2fs_cg_verify_and_initialize(struct vnode *devvp, struct m_ext2fs *fs, int ronly)
760 1.49 jdolecek {
761 1.49 jdolecek struct ext2_gd *gd;
762 1.49 jdolecek ino_t ioff;
763 1.49 jdolecek size_t boff;
764 1.49 jdolecek struct buf *bp;
765 1.49 jdolecek int cg, i, error;
766 1.49 jdolecek
767 1.49 jdolecek if (!E2FS_HAS_GD_CSUM(fs))
768 1.49 jdolecek return 0;
769 1.49 jdolecek
770 1.53 christos for(cg = 0; cg < fs->e2fs_ncg; cg++) {
771 1.49 jdolecek gd = &fs->e2fs_gd[cg];
772 1.49 jdolecek
773 1.49 jdolecek /* Verify checksum */
774 1.53 christos uint16_t csum = ext2fs_cg_get_csum(fs, cg, gd);
775 1.53 christos if (gd->ext2bgd_checksum != csum) {
776 1.53 christos printf("%s: group %d invalid csum (%#x != %#x)\n",
777 1.53 christos __func__, cg, gd->ext2bgd_checksum, csum);
778 1.49 jdolecek return EINVAL;
779 1.49 jdolecek }
780 1.49 jdolecek
781 1.49 jdolecek /* if mounting read-write, zero itable if not already done */
782 1.53 christos if (ronly ||
783 1.53 christos (gd->ext2bgd_flags & h2fs16(E2FS_BG_INODE_ZEROED)) != 0)
784 1.49 jdolecek continue;
785 1.49 jdolecek
786 1.49 jdolecek /*
787 1.49 jdolecek * We are skipping already used inodes, zero rest of itable
788 1.49 jdolecek * blocks. First block to zero could be only partial wipe, all
789 1.49 jdolecek * others are wiped completely. This might take a while,
790 1.49 jdolecek * there could be many inode table blocks. We use
791 1.49 jdolecek * delayed writes, so this shouldn't block for very
792 1.49 jdolecek * long.
793 1.49 jdolecek */
794 1.49 jdolecek ioff = fs->e2fs.e2fs_ipg - fs2h16(gd->ext2bgd_itable_unused_lo);
795 1.49 jdolecek boff = (ioff % fs->e2fs_ipb) * EXT2_DINODE_SIZE(fs);
796 1.49 jdolecek
797 1.49 jdolecek for(i = ioff / fs->e2fs_ipb; i < fs->e2fs_itpg; i++) {
798 1.49 jdolecek if (boff) {
799 1.49 jdolecek /* partial wipe, must read old data */
800 1.53 christos error = bread(devvp, EXT2_FSBTODB64OFF(fs,
801 1.53 christos fs2h32(gd->ext2bgd_i_tables),
802 1.53 christos fs2h32(gd->ext2bgd_i_tables_hi), i),
803 1.53 christos (int)fs->e2fs_bsize, B_MODIFY, &bp);
804 1.49 jdolecek if (error) {
805 1.53 christos printf("%s: can't read itable block",
806 1.53 christos __func__);
807 1.49 jdolecek return error;
808 1.49 jdolecek }
809 1.53 christos memset((char *)bp->b_data + boff, 0,
810 1.53 christos fs->e2fs_bsize - boff);
811 1.49 jdolecek boff = 0;
812 1.49 jdolecek } else {
813 1.49 jdolecek /*
814 1.49 jdolecek * Complete wipe, don't need to read data. This
815 1.49 jdolecek * assumes nothing else is changing the data.
816 1.49 jdolecek */
817 1.53 christos bp = getblk(devvp, EXT2_FSBTODB64OFF(fs,
818 1.53 christos fs2h32(gd->ext2bgd_i_tables),
819 1.53 christos fs2h32(gd->ext2bgd_i_tables_hi), i),
820 1.53 christos (int)fs->e2fs_bsize, 0, 0);
821 1.49 jdolecek clrbuf(bp);
822 1.49 jdolecek }
823 1.54 riastrad
824 1.49 jdolecek bdwrite(bp);
825 1.49 jdolecek }
826 1.49 jdolecek
827 1.49 jdolecek gd->ext2bgd_flags |= h2fs16(E2FS_BG_INODE_ZEROED);
828 1.49 jdolecek gd->ext2bgd_checksum = ext2fs_cg_get_csum(fs, cg, gd);
829 1.49 jdolecek fs->e2fs_fmod = 1;
830 1.49 jdolecek }
831 1.49 jdolecek
832 1.49 jdolecek return 0;
833 1.49 jdolecek }
834