xref: /freebsd/sbin/fsck_ffs/gjournal.c (revision 9336e0699bda8a301cd2bfa37106b6ec5e32012e)
1 /*-
2  * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Copyright (c) 1982, 1986, 1989, 1993
27  *	The Regents of the University of California.  All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions
31  * are met:
32  * 1. Redistributions of source code must retain the above copyright
33  *    notice, this list of conditions and the following disclaimer.
34  * 2. Redistributions in binary form must reproduce the above copyright
35  *    notice, this list of conditions and the following disclaimer in the
36  *    documentation and/or other materials provided with the distribution.
37  * 4. Neither the name of the University nor the names of its contributors
38  *    may be used to endorse or promote products derived from this software
39  *    without specific prior written permission.
40  *
41  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  */
53 
54 #include <sys/cdefs.h>
55 __FBSDID("$FreeBSD$");
56 
57 #include <sys/param.h>
58 #include <sys/disklabel.h>
59 #include <sys/mount.h>
60 #include <sys/stat.h>
61 
62 #include <ufs/ufs/ufsmount.h>
63 #include <ufs/ufs/dinode.h>
64 #include <ufs/ffs/fs.h>
65 
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <stdint.h>
69 #include <libufs.h>
70 #include <strings.h>
71 #include <err.h>
72 #include <assert.h>
73 
74 #include "fsck.h"
75 
76 struct cgchain {
77 	union {
78 		struct cg cgcu_cg;
79 		char cgcu_buf[MAXBSIZE];
80 	} cgc_union;
81 	int	cgc_busy;
82 	int	cgc_dirty;
83 	LIST_ENTRY(cgchain) cgc_next;
84 };
85 #define cgc_cg	cgc_union.cgcu_cg
86 
87 #define	MAX_CACHED_CGS	1024
88 static unsigned ncgs = 0;
89 static LIST_HEAD(, cgchain) cglist = LIST_HEAD_INITIALIZER(&cglist);
90 
91 static const char *devnam;
92 static struct uufsd *disk = NULL;
93 static struct fs *fs = NULL;
94 struct ufs2_dinode ufs2_zino;
95 
96 static void putcgs(void);
97 
98 /*
99  * Write current block of inodes.
100  */
101 static int
102 putino(struct uufsd *disk, ino_t inode)
103 {
104 	caddr_t inoblock;
105 	struct fs *fs;
106 	ssize_t ret;
107 
108 	fs = &disk->d_fs;
109 	inoblock = disk->d_inoblock;
110 
111 	assert(inoblock != NULL);
112 	assert(inode >= disk->d_inomin && inode <= disk->d_inomax);
113 	ret = bwrite(disk, fsbtodb(fs, ino_to_fsba(fs, inode)), inoblock,
114 	    fs->fs_bsize);
115 
116 	return (ret == -1 ? -1 : 0);
117 }
118 
119 /*
120  * Return cylinder group from the cache or load it if it is not in the
121  * cache yet.
122  * Don't cache more than MAX_CACHED_CGS cylinder groups.
123  */
124 static struct cgchain *
125 getcg(int cg)
126 {
127 	struct cgchain *cgc;
128 
129 	assert(disk != NULL && fs != NULL);
130 	LIST_FOREACH(cgc, &cglist, cgc_next) {
131 		if (cgc->cgc_cg.cg_cgx == cg) {
132 			//printf("%s: Found cg=%d\n", __func__, cg);
133 			return (cgc);
134 		}
135 	}
136 	/*
137 	 * Our cache is full? Let's clean it up.
138 	 */
139 	if (ncgs >= MAX_CACHED_CGS) {
140 		//printf("%s: Flushing CGs.\n", __func__);
141 		putcgs();
142 	}
143 	cgc = malloc(sizeof(*cgc));
144 	if (cgc == NULL) {
145 		/*
146 		 * Cannot allocate memory?
147 		 * Let's put all currently loaded and not busy cylinder groups
148 		 * on disk and try again.
149 		 */
150 		//printf("%s: No memory, flushing CGs.\n", __func__);
151 		putcgs();
152 		cgc = malloc(sizeof(*cgc));
153 		if (cgc == NULL)
154 			err(1, "malloc(%zu)", sizeof(*cgc));
155 	}
156 	if (cgread1(disk, cg) == -1)
157 		err(1, "cgread1(%d)", cg);
158 	bcopy(&disk->d_cg, &cgc->cgc_cg, sizeof(cgc->cgc_union));
159 	cgc->cgc_busy = 0;
160 	cgc->cgc_dirty = 0;
161 	LIST_INSERT_HEAD(&cglist, cgc, cgc_next);
162 	ncgs++;
163 	//printf("%s: Read cg=%d\n", __func__, cg);
164 	return (cgc);
165 }
166 
167 /*
168  * Mark cylinder group as dirty - it will be written back on putcgs().
169  */
170 static void
171 dirtycg(struct cgchain *cgc)
172 {
173 
174 	cgc->cgc_dirty = 1;
175 }
176 
177 /*
178  * Mark cylinder group as busy - it will not be freed on putcgs().
179  */
180 static void
181 busycg(struct cgchain *cgc)
182 {
183 
184 	cgc->cgc_busy = 1;
185 }
186 
187 /*
188  * Unmark the given cylinder group as busy.
189  */
190 static void
191 unbusycg(struct cgchain *cgc)
192 {
193 
194 	cgc->cgc_busy = 0;
195 }
196 
197 /*
198  * Write back all dirty cylinder groups.
199  * Free all non-busy cylinder groups.
200  */
201 static void
202 putcgs(void)
203 {
204 	struct cgchain *cgc, *cgc2;
205 
206 	assert(disk != NULL && fs != NULL);
207 	LIST_FOREACH_SAFE(cgc, &cglist, cgc_next, cgc2) {
208 		if (cgc->cgc_busy)
209 			continue;
210 		LIST_REMOVE(cgc, cgc_next);
211 		ncgs--;
212 		if (cgc->cgc_dirty) {
213 			bcopy(&cgc->cgc_cg, &disk->d_cg,
214 			    sizeof(cgc->cgc_union));
215 			if (cgwrite1(disk, cgc->cgc_cg.cg_cgx) == -1)
216 				err(1, "cgwrite1(%d)", cgc->cgc_cg.cg_cgx);
217 			//printf("%s: Wrote cg=%d\n", __func__,
218 			//    cgc->cgc_cg.cg_cgx);
219 		}
220 		free(cgc);
221 	}
222 }
223 
224 #if 0
225 /*
226  * Free all non-busy cylinder groups without storing the dirty ones.
227  */
228 static void
229 cancelcgs(void)
230 {
231 	struct cgchain *cgc;
232 
233 	assert(disk != NULL && fs != NULL);
234 	while ((cgc = LIST_FIRST(&cglist)) != NULL) {
235 		if (cgc->cgc_busy)
236 			continue;
237 		LIST_REMOVE(cgc, cgc_next);
238 		//printf("%s: Canceled cg=%d\n", __func__, cgc->cgc_cg.cg_cgx);
239 		free(cgc);
240 	}
241 }
242 #endif
243 
244 /*
245  * Open the given provider, load statistics.
246  */
247 static void
248 getdisk(void)
249 {
250 	int i;
251 
252 	if (disk != NULL)
253 		return;
254 	disk = malloc(sizeof(*disk));
255 	if (disk == NULL)
256 		err(1, "malloc(%zu)", sizeof(*disk));
257 	if (ufs_disk_fillout(disk, devnam) == -1) {
258 		err(1, "ufs_disk_fillout(%s) failed: %s", devnam,
259 		    disk->d_error);
260 	}
261 	fs = &disk->d_fs;
262 	fs->fs_csp = malloc((size_t)fs->fs_cssize);
263 	if (fs->fs_csp == NULL)
264 		err(1, "malloc(%zu)", (size_t)fs->fs_cssize);
265 	bzero(fs->fs_csp, (size_t)fs->fs_cssize);
266 	for (i = 0; i < fs->fs_cssize; i += fs->fs_bsize) {
267 		if (bread(disk, fsbtodb(fs, fs->fs_csaddr + numfrags(fs, i)),
268 		    (void *)(((char *)fs->fs_csp) + i),
269 		    (size_t)(fs->fs_cssize - i < fs->fs_bsize ? fs->fs_cssize - i : fs->fs_bsize)) == -1) {
270 			err(1, "bread: %s", disk->d_error);
271 		}
272 	}
273 	if (fs->fs_contigsumsize > 0) {
274 		fs->fs_maxcluster = malloc(fs->fs_ncg * sizeof(int32_t));
275 		if (fs->fs_maxcluster == NULL)
276 			err(1, "malloc(%zu)", fs->fs_ncg * sizeof(int32_t));
277 		for (i = 0; i < fs->fs_ncg; i++)
278 			fs->fs_maxcluster[i] = fs->fs_contigsumsize;
279 	}
280 }
281 
282 /*
283  * Mark file system as clean, write the super-block back, close the disk.
284  */
285 static void
286 closedisk(void)
287 {
288 
289 	free(fs->fs_csp);
290 	if (fs->fs_contigsumsize > 0) {
291 		free(fs->fs_maxcluster);
292 		fs->fs_maxcluster = NULL;
293 	}
294 	fs->fs_clean = 1;
295 	if (sbwrite(disk, 0) == -1)
296 		err(1, "sbwrite(%s)", devnam);
297 	if (ufs_disk_close(disk) == -1)
298 		err(1, "ufs_disk_close(%s)", devnam);
299 	free(disk);
300 	disk = NULL;
301 	fs = NULL;
302 }
303 
304 /*
305  * Write the statistics back, call closedisk().
306  */
307 static void
308 putdisk(void)
309 {
310 	int i;
311 
312 	assert(disk != NULL && fs != NULL);
313 	for (i = 0; i < fs->fs_cssize; i += fs->fs_bsize) {
314 		if (bwrite(disk, fsbtodb(fs, fs->fs_csaddr + numfrags(fs, i)),
315 		    (void *)(((char *)fs->fs_csp) + i),
316 		    (size_t)(fs->fs_cssize - i < fs->fs_bsize ? fs->fs_cssize - i : fs->fs_bsize)) == -1) {
317 			err(1, "bwrite: %s", disk->d_error);
318 		}
319 	}
320 	closedisk();
321 }
322 
323 #if 0
324 /*
325  * Free memory, close the disk, but don't write anything back.
326  */
327 static void
328 canceldisk(void)
329 {
330 	int i;
331 
332 	assert(disk != NULL && fs != NULL);
333 	free(fs->fs_csp);
334 	if (fs->fs_contigsumsize > 0)
335 		free(fs->fs_maxcluster);
336 	if (ufs_disk_close(disk) == -1)
337 		err(1, "ufs_disk_close(%s)", devnam);
338 	free(disk);
339 	disk = NULL;
340 	fs = NULL;
341 }
342 #endif
343 
344 static int
345 isblock(unsigned char *cp, ufs1_daddr_t h)
346 {
347 	unsigned char mask;
348 
349 	switch ((int)fs->fs_frag) {
350 	case 8:
351 		return (cp[h] == 0xff);
352 	case 4:
353 		mask = 0x0f << ((h & 0x1) << 2);
354 		return ((cp[h >> 1] & mask) == mask);
355 	case 2:
356 		mask = 0x03 << ((h & 0x3) << 1);
357 		return ((cp[h >> 2] & mask) == mask);
358 	case 1:
359 		mask = 0x01 << (h & 0x7);
360 		return ((cp[h >> 3] & mask) == mask);
361 	default:
362 		assert(!"isblock: invalid number of fragments");
363 	}
364 	return (0);
365 }
366 
367 /*
368  * put a block into the map
369  */
370 static void
371 setblock(unsigned char *cp, ufs1_daddr_t h)
372 {
373 
374 	switch ((int)fs->fs_frag) {
375 	case 8:
376 		cp[h] = 0xff;
377 		return;
378 	case 4:
379 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
380 		return;
381 	case 2:
382 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
383 		return;
384 	case 1:
385 		cp[h >> 3] |= (0x01 << (h & 0x7));
386 		return;
387 	default:
388 		assert(!"setblock: invalid number of fragments");
389 	}
390 }
391 
392 /*
393  * check if a block is free
394  */
395 static int
396 isfreeblock(u_char *cp, ufs1_daddr_t h)
397 {
398 
399 	switch ((int)fs->fs_frag) {
400 	case 8:
401 		return (cp[h] == 0);
402 	case 4:
403 		return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
404 	case 2:
405 		return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
406 	case 1:
407 		return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
408 	default:
409 		assert(!"isfreeblock: invalid number of fragments");
410 	}
411 	return (0);
412 }
413 
414 /*
415  * Update the frsum fields to reflect addition or deletion
416  * of some frags.
417  */
418 void
419 fragacct(int fragmap, int32_t fraglist[], int cnt)
420 {
421 	int inblk;
422 	int field, subfield;
423 	int siz, pos;
424 
425 	inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
426 	fragmap <<= 1;
427 	for (siz = 1; siz < fs->fs_frag; siz++) {
428 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
429 			continue;
430 		field = around[siz];
431 		subfield = inside[siz];
432 		for (pos = siz; pos <= fs->fs_frag; pos++) {
433 			if ((fragmap & field) == subfield) {
434 				fraglist[siz] += cnt;
435 				pos += siz;
436 				field <<= siz;
437 				subfield <<= siz;
438 			}
439 			field <<= 1;
440 			subfield <<= 1;
441 		}
442 	}
443 }
444 
445 static void
446 clusteracct(struct cg *cgp, ufs1_daddr_t blkno)
447 {
448 	int32_t *sump;
449 	int32_t *lp;
450 	u_char *freemapp, *mapp;
451 	int i, start, end, forw, back, map, bit;
452 
453 	if (fs->fs_contigsumsize <= 0)
454 		return;
455 	freemapp = cg_clustersfree(cgp);
456 	sump = cg_clustersum(cgp);
457 	/*
458 	 * Clear the actual block.
459 	 */
460 	setbit(freemapp, blkno);
461 	/*
462 	 * Find the size of the cluster going forward.
463 	 */
464 	start = blkno + 1;
465 	end = start + fs->fs_contigsumsize;
466 	if (end >= cgp->cg_nclusterblks)
467 		end = cgp->cg_nclusterblks;
468 	mapp = &freemapp[start / NBBY];
469 	map = *mapp++;
470 	bit = 1 << (start % NBBY);
471 	for (i = start; i < end; i++) {
472 		if ((map & bit) == 0)
473 			break;
474 		if ((i & (NBBY - 1)) != (NBBY - 1)) {
475 			bit <<= 1;
476 		} else {
477 			map = *mapp++;
478 			bit = 1;
479 		}
480 	}
481 	forw = i - start;
482 	/*
483 	 * Find the size of the cluster going backward.
484 	 */
485 	start = blkno - 1;
486 	end = start - fs->fs_contigsumsize;
487 	if (end < 0)
488 		end = -1;
489 	mapp = &freemapp[start / NBBY];
490 	map = *mapp--;
491 	bit = 1 << (start % NBBY);
492 	for (i = start; i > end; i--) {
493 		if ((map & bit) == 0)
494 			break;
495 		if ((i & (NBBY - 1)) != 0) {
496 			bit >>= 1;
497 		} else {
498 			map = *mapp--;
499 			bit = 1 << (NBBY - 1);
500 		}
501 	}
502 	back = start - i;
503 	/*
504 	 * Account for old cluster and the possibly new forward and
505 	 * back clusters.
506 	 */
507 	i = back + forw + 1;
508 	if (i > fs->fs_contigsumsize)
509 		i = fs->fs_contigsumsize;
510 	sump[i]++;
511 	if (back > 0)
512 		sump[back]--;
513 	if (forw > 0)
514 		sump[forw]--;
515 	/*
516 	 * Update cluster summary information.
517 	 */
518 	lp = &sump[fs->fs_contigsumsize];
519 	for (i = fs->fs_contigsumsize; i > 0; i--)
520 		if (*lp-- > 0)
521 			break;
522 	fs->fs_maxcluster[cgp->cg_cgx] = i;
523 }
524 
525 static void
526 blkfree(ufs2_daddr_t bno, long size)
527 {
528 	struct cgchain *cgc;
529 	struct cg *cgp;
530 	ufs1_daddr_t fragno, cgbno;
531 	int i, cg, blk, frags, bbase;
532 	u_int8_t *blksfree;
533 
534 	cg = dtog(fs, bno);
535 	cgc = getcg(cg);
536 	dirtycg(cgc);
537 	cgp = &cgc->cgc_cg;
538 	cgbno = dtogd(fs, bno);
539 	blksfree = cg_blksfree(cgp);
540 	if (size == fs->fs_bsize) {
541 		fragno = fragstoblks(fs, cgbno);
542 		if (!isfreeblock(blksfree, fragno))
543 			assert(!"blkfree: freeing free block");
544 		setblock(blksfree, fragno);
545 		clusteracct(cgp, fragno);
546 		cgp->cg_cs.cs_nbfree++;
547 		fs->fs_cstotal.cs_nbfree++;
548 		fs->fs_cs(fs, cg).cs_nbfree++;
549 	} else {
550 		bbase = cgbno - fragnum(fs, cgbno);
551 		/*
552 		 * decrement the counts associated with the old frags
553 		 */
554 		blk = blkmap(fs, blksfree, bbase);
555 		fragacct(blk, cgp->cg_frsum, -1);
556 		/*
557 		 * deallocate the fragment
558 		 */
559 		frags = numfrags(fs, size);
560 		for (i = 0; i < frags; i++) {
561 			if (isset(blksfree, cgbno + i))
562 				assert(!"blkfree: freeing free frag");
563 			setbit(blksfree, cgbno + i);
564 		}
565 		cgp->cg_cs.cs_nffree += i;
566 		fs->fs_cstotal.cs_nffree += i;
567 		fs->fs_cs(fs, cg).cs_nffree += i;
568 		/*
569 		 * add back in counts associated with the new frags
570 		 */
571 		blk = blkmap(fs, blksfree, bbase);
572 		fragacct(blk, cgp->cg_frsum, 1);
573 		/*
574 		 * if a complete block has been reassembled, account for it
575 		 */
576 		fragno = fragstoblks(fs, bbase);
577 		if (isblock(blksfree, fragno)) {
578 			cgp->cg_cs.cs_nffree -= fs->fs_frag;
579 			fs->fs_cstotal.cs_nffree -= fs->fs_frag;
580 			fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
581 			clusteracct(cgp, fragno);
582 			cgp->cg_cs.cs_nbfree++;
583 			fs->fs_cstotal.cs_nbfree++;
584 			fs->fs_cs(fs, cg).cs_nbfree++;
585 		}
586 	}
587 }
588 
589 /*
590  * Recursively free all indirect blocks.
591  */
592 static void
593 freeindir(ufs2_daddr_t blk, int level)
594 {
595 	char sblks[MAXBSIZE];
596 	ufs2_daddr_t *blks;
597 	int i;
598 
599 	if (bread(disk, fsbtodb(fs, blk), (void *)&sblks, (size_t)fs->fs_bsize) == -1)
600 		err(1, "bread: %s", disk->d_error);
601 	blks = (ufs2_daddr_t *)&sblks;
602 	for (i = 0; i < howmany(fs->fs_bsize, sizeof(ufs2_daddr_t)); i++) {
603 		if (blks[i] == 0)
604 			break;
605 		if (level == 0)
606 			blkfree(blks[i], fs->fs_bsize);
607 		else
608 			freeindir(blks[i], level - 1);
609 	}
610 	blkfree(blk, fs->fs_bsize);
611 }
612 
613 #define	dblksize(fs, dino, lbn) \
614 	((dino)->di_size >= smalllblktosize(fs, (lbn) + 1) \
615 	    ? (fs)->fs_bsize \
616 	    : fragroundup(fs, blkoff(fs, (dino)->di_size)))
617 
618 /*
619  * Free all blocks associated with the given inode.
620  */
621 static void
622 clear_inode(struct ufs2_dinode *dino)
623 {
624 	ufs2_daddr_t bn;
625 	int extblocks, i, level;
626 	off_t osize;
627 	long bsize;
628 
629 	extblocks = 0;
630 	if (fs->fs_magic == FS_UFS2_MAGIC && dino->di_extsize > 0)
631 		extblocks = btodb(fragroundup(fs, dino->di_extsize));
632 	/* deallocate external attributes blocks */
633 	if (extblocks > 0) {
634 		osize = dino->di_extsize;
635 		dino->di_blocks -= extblocks;
636 		dino->di_extsize = 0;
637 		for (i = 0; i < NXADDR; i++) {
638 			if (dino->di_extb[i] == 0)
639 				continue;
640 			blkfree(dino->di_extb[i], sblksize(fs, osize, i));
641 		}
642 	}
643 #define	SINGLE	0	/* index of single indirect block */
644 #define	DOUBLE	1	/* index of double indirect block */
645 #define	TRIPLE	2	/* index of triple indirect block */
646 	/* deallocate indirect blocks */
647 	for (level = SINGLE; level <= TRIPLE; level++) {
648 		if (dino->di_ib[level] == 0)
649 			break;
650 		freeindir(dino->di_ib[level], level);
651 	}
652 	/* deallocate direct blocks and fragments */
653 	for (i = 0; i < NDADDR; i++) {
654 		bn = dino->di_db[i];
655 		if (bn == 0)
656 			continue;
657 		bsize = dblksize(fs, dino, i);
658 		blkfree(bn, bsize);
659 	}
660 }
661 
662 void
663 gjournal_check(const char *filesys)
664 {
665 	struct ufs2_dinode *dino;
666 	void *p;
667 	struct cgchain *cgc;
668 	struct cg *cgp;
669 	uint8_t *inosused, *blksfree;
670 	ino_t cino, ino;
671 	int cg, mode;
672 
673 	devnam = filesys;
674 	getdisk();
675 	/* Are there any unreferenced inodes in this cylinder group? */
676 	if (fs->fs_unrefs == 0) {
677 		//printf("No unreferenced inodes.\n");
678 		closedisk();
679 		return;
680 	}
681 
682 	for (cg = 0; cg < fs->fs_ncg; cg++) {
683 		/* Show progress if requested. */
684 		if (got_siginfo) {
685 			printf("%s: phase j: cyl group %d of %d (%d%%)\n",
686 			    cdevname, cg, fs->fs_ncg, cg * 100 / fs->fs_ncg);
687 			got_siginfo = 0;
688 		}
689 		if (got_sigalarm) {
690 			setproctitle("%s pj %d%%", cdevname,
691 			     cg * 100 / fs->fs_ncg);
692 			got_sigalarm = 0;
693 		}
694 		cgc = getcg(cg);
695 		cgp = &cgc->cgc_cg;
696 		/* Are there any unreferenced inodes in this cylinder group? */
697 		if (cgp->cg_unrefs == 0)
698 			continue;
699 		//printf("Analizing cylinder group %d (count=%d)\n", cg, cgp->cg_unrefs);
700 		/*
701 		 * We are going to modify this cylinder group, so we want it to
702 		 * be written back.
703 		 */
704 		dirtycg(cgc);
705 		/* We don't want it to be freed in the meantime. */
706 		busycg(cgc);
707 		inosused = cg_inosused(cgp);
708 		blksfree = cg_blksfree(cgp);
709 		/*
710 		 * Now go through the list of all inodes in this cylinder group
711 		 * to find unreferenced ones.
712 		 */
713 		for (cino = 0; cino < fs->fs_ipg; cino++) {
714 			ino = fs->fs_ipg * cg + cino;
715 			/* Unallocated? Skip it. */
716 			if (isclr(inosused, cino))
717 				continue;
718 			if (getino(disk, &p, ino, &mode) == -1)
719 				err(1, "getino(cg=%d ino=%d)", cg, ino);
720 			dino = p;
721 			/* Not a regular file nor directory? Skip it. */
722 			if (!S_ISREG(dino->di_mode) && !S_ISDIR(dino->di_mode))
723 				continue;
724 			/* Has reference(s)? Skip it. */
725 			if (dino->di_nlink > 0)
726 				continue;
727 			//printf("Clearing inode=%d (size=%jd)\n", ino, (intmax_t)dino->di_size);
728 			/* Free inode's blocks. */
729 			clear_inode(dino);
730 			/* Deallocate it. */
731 			clrbit(inosused, cino);
732 			/* Update position of last used inode. */
733 			if (ino < cgp->cg_irotor)
734 				cgp->cg_irotor = ino;
735 			/* Update statistics. */
736 			cgp->cg_cs.cs_nifree++;
737 			fs->fs_cs(fs, cg).cs_nifree++;
738 			fs->fs_cstotal.cs_nifree++;
739 			cgp->cg_unrefs--;
740 			fs->fs_unrefs--;
741 			/* If this is directory, update related statistics. */
742 			if (S_ISDIR(dino->di_mode)) {
743 				cgp->cg_cs.cs_ndir--;
744 				fs->fs_cs(fs, cg).cs_ndir--;
745 				fs->fs_cstotal.cs_ndir--;
746 			}
747 			/* Zero-fill the inode. */
748 			*dino = ufs2_zino;
749 			/* Write the inode back. */
750 			if (putino(disk, ino) == -1)
751 				err(1, "putino(cg=%d ino=%d)", cg, ino);
752 			if (cgp->cg_unrefs == 0) {
753 				//printf("No more unreferenced inodes in cg=%d.\n", cg);
754 				break;
755 			}
756 		}
757 		/*
758 		 * We don't need this cylinder group anymore, so feel free to
759 		 * free it if needed.
760 		 */
761 		unbusycg(cgc);
762 		/*
763 		 * If there are no more unreferenced inodes, there is no need to
764 		 * check other cylinder groups.
765 		 */
766 		if (fs->fs_unrefs == 0) {
767 			//printf("No more unreferenced inodes (cg=%d/%d).\n", cg,
768 			//    fs->fs_ncg);
769 			break;
770 		}
771 	}
772 	/* Write back modified cylinder groups. */
773 	putcgs();
774 	/* Write back updated statistics and super-block. */
775 	putdisk();
776 }
777