gjournal.c revision 201145
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: head/sbin/fsck_ffs/gjournal.c 201145 2009-12-28 22:56:30Z antoine $");
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
76struct 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
88static unsigned ncgs = 0;
89static LIST_HEAD(, cgchain) cglist = LIST_HEAD_INITIALIZER(cglist);
90
91static const char *devnam;
92static struct uufsd *disk = NULL;
93static struct fs *fs = NULL;
94struct ufs2_dinode ufs2_zino;
95
96static void putcgs(void);
97
98/*
99 * Write current block of inodes.
100 */
101static int
102putino(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 */
124static struct cgchain *
125getcg(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 */
170static void
171dirtycg(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 */
180static void
181busycg(struct cgchain *cgc)
182{
183
184	cgc->cgc_busy = 1;
185}
186
187/*
188 * Unmark the given cylinder group as busy.
189 */
190static void
191unbusycg(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 */
201static void
202putcgs(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 */
228static void
229cancelcgs(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 */
247static void
248getdisk(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 */
285static void
286closedisk(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 */
307static void
308putdisk(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 */
327static void
328canceldisk(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
344static int
345isblock(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 */
370static void
371setblock(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 */
395static int
396isfreeblock(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 */
418void
419fragacct(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
445static void
446clusteracct(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
525static void
526blkfree(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 */
592static void
593freeindir(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 */
621static void
622clear_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
662void
663gjournal_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 file system? */
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