1163849Spjd/*-
2163849Spjd * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3163849Spjd * All rights reserved.
4163849Spjd *
5163849Spjd * Redistribution and use in source and binary forms, with or without
6163849Spjd * modification, are permitted provided that the following conditions
7163849Spjd * are met:
8163849Spjd * 1. Redistributions of source code must retain the above copyright
9163849Spjd *    notice, this list of conditions and the following disclaimer.
10163849Spjd * 2. Redistributions in binary form must reproduce the above copyright
11163849Spjd *    notice, this list of conditions and the following disclaimer in the
12163849Spjd *    documentation and/or other materials provided with the distribution.
13163849Spjd *
14163849Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15163849Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16163849Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17163849Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18163849Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19163849Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20163849Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21163849Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22163849Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23163849Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24163849Spjd * SUCH DAMAGE.
25163849Spjd *
26163849Spjd * Copyright (c) 1982, 1986, 1989, 1993
27163849Spjd *	The Regents of the University of California.  All rights reserved.
28163849Spjd *
29163849Spjd * Redistribution and use in source and binary forms, with or without
30163849Spjd * modification, are permitted provided that the following conditions
31163849Spjd * are met:
32163849Spjd * 1. Redistributions of source code must retain the above copyright
33163849Spjd *    notice, this list of conditions and the following disclaimer.
34163849Spjd * 2. Redistributions in binary form must reproduce the above copyright
35163849Spjd *    notice, this list of conditions and the following disclaimer in the
36163849Spjd *    documentation and/or other materials provided with the distribution.
37163849Spjd * 4. Neither the name of the University nor the names of its contributors
38163849Spjd *    may be used to endorse or promote products derived from this software
39163849Spjd *    without specific prior written permission.
40163849Spjd *
41163849Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
42163849Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43163849Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44163849Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
45163849Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46163849Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47163849Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48163849Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49163849Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50163849Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51163849Spjd * SUCH DAMAGE.
52163849Spjd */
53163849Spjd
54163849Spjd#include <sys/cdefs.h>
55163849Spjd__FBSDID("$FreeBSD$");
56163849Spjd
57163849Spjd#include <sys/param.h>
58163849Spjd#include <sys/disklabel.h>
59163849Spjd#include <sys/mount.h>
60163849Spjd#include <sys/stat.h>
61163849Spjd
62163849Spjd#include <ufs/ufs/ufsmount.h>
63163849Spjd#include <ufs/ufs/dinode.h>
64163849Spjd#include <ufs/ffs/fs.h>
65163849Spjd
66163849Spjd#include <stdio.h>
67163849Spjd#include <stdlib.h>
68163849Spjd#include <stdint.h>
69163849Spjd#include <libufs.h>
70163849Spjd#include <strings.h>
71163849Spjd#include <err.h>
72163849Spjd#include <assert.h>
73163849Spjd
74163849Spjd#include "fsck.h"
75163849Spjd
76163849Spjdstruct cgchain {
77163849Spjd	union {
78163849Spjd		struct cg cgcu_cg;
79163849Spjd		char cgcu_buf[MAXBSIZE];
80163849Spjd	} cgc_union;
81163849Spjd	int	cgc_busy;
82163849Spjd	int	cgc_dirty;
83163849Spjd	LIST_ENTRY(cgchain) cgc_next;
84163849Spjd};
85163849Spjd#define cgc_cg	cgc_union.cgcu_cg
86163849Spjd
87163849Spjd#define	MAX_CACHED_CGS	1024
88163849Spjdstatic unsigned ncgs = 0;
89201145Santoinestatic LIST_HEAD(, cgchain) cglist = LIST_HEAD_INITIALIZER(cglist);
90163849Spjd
91163849Spjdstatic const char *devnam;
92163849Spjdstatic struct uufsd *disk = NULL;
93163849Spjdstatic struct fs *fs = NULL;
94163849Spjdstruct ufs2_dinode ufs2_zino;
95163849Spjd
96163849Spjdstatic void putcgs(void);
97163849Spjd
98163849Spjd/*
99163849Spjd * Return cylinder group from the cache or load it if it is not in the
100163849Spjd * cache yet.
101163849Spjd * Don't cache more than MAX_CACHED_CGS cylinder groups.
102163849Spjd */
103163849Spjdstatic struct cgchain *
104163849Spjdgetcg(int cg)
105163849Spjd{
106163849Spjd	struct cgchain *cgc;
107163849Spjd
108163849Spjd	assert(disk != NULL && fs != NULL);
109163849Spjd	LIST_FOREACH(cgc, &cglist, cgc_next) {
110163849Spjd		if (cgc->cgc_cg.cg_cgx == cg) {
111163849Spjd			//printf("%s: Found cg=%d\n", __func__, cg);
112163849Spjd			return (cgc);
113163849Spjd		}
114163849Spjd	}
115163849Spjd	/*
116163849Spjd	 * Our cache is full? Let's clean it up.
117163849Spjd	 */
118163849Spjd	if (ncgs >= MAX_CACHED_CGS) {
119163849Spjd		//printf("%s: Flushing CGs.\n", __func__);
120163849Spjd		putcgs();
121163849Spjd	}
122163849Spjd	cgc = malloc(sizeof(*cgc));
123163849Spjd	if (cgc == NULL) {
124163849Spjd		/*
125163849Spjd		 * Cannot allocate memory?
126163849Spjd		 * Let's put all currently loaded and not busy cylinder groups
127163849Spjd		 * on disk and try again.
128163849Spjd		 */
129163849Spjd		//printf("%s: No memory, flushing CGs.\n", __func__);
130163849Spjd		putcgs();
131163849Spjd		cgc = malloc(sizeof(*cgc));
132163849Spjd		if (cgc == NULL)
133163849Spjd			err(1, "malloc(%zu)", sizeof(*cgc));
134163849Spjd	}
135163849Spjd	if (cgread1(disk, cg) == -1)
136163849Spjd		err(1, "cgread1(%d)", cg);
137163849Spjd	bcopy(&disk->d_cg, &cgc->cgc_cg, sizeof(cgc->cgc_union));
138163849Spjd	cgc->cgc_busy = 0;
139163849Spjd	cgc->cgc_dirty = 0;
140163849Spjd	LIST_INSERT_HEAD(&cglist, cgc, cgc_next);
141163849Spjd	ncgs++;
142163849Spjd	//printf("%s: Read cg=%d\n", __func__, cg);
143163849Spjd	return (cgc);
144163849Spjd}
145163849Spjd
146163849Spjd/*
147163849Spjd * Mark cylinder group as dirty - it will be written back on putcgs().
148163849Spjd */
149163849Spjdstatic void
150163849Spjddirtycg(struct cgchain *cgc)
151163849Spjd{
152163849Spjd
153163849Spjd	cgc->cgc_dirty = 1;
154163849Spjd}
155163849Spjd
156163849Spjd/*
157163849Spjd * Mark cylinder group as busy - it will not be freed on putcgs().
158163849Spjd */
159163849Spjdstatic void
160163849Spjdbusycg(struct cgchain *cgc)
161163849Spjd{
162163849Spjd
163163849Spjd	cgc->cgc_busy = 1;
164163849Spjd}
165163849Spjd
166163849Spjd/*
167163849Spjd * Unmark the given cylinder group as busy.
168163849Spjd */
169163849Spjdstatic void
170163849Spjdunbusycg(struct cgchain *cgc)
171163849Spjd{
172163849Spjd
173163849Spjd	cgc->cgc_busy = 0;
174163849Spjd}
175163849Spjd
176163849Spjd/*
177163849Spjd * Write back all dirty cylinder groups.
178163849Spjd * Free all non-busy cylinder groups.
179163849Spjd */
180163849Spjdstatic void
181163849Spjdputcgs(void)
182163849Spjd{
183163849Spjd	struct cgchain *cgc, *cgc2;
184163849Spjd
185163849Spjd	assert(disk != NULL && fs != NULL);
186163849Spjd	LIST_FOREACH_SAFE(cgc, &cglist, cgc_next, cgc2) {
187163849Spjd		if (cgc->cgc_busy)
188163849Spjd			continue;
189163849Spjd		LIST_REMOVE(cgc, cgc_next);
190163849Spjd		ncgs--;
191163849Spjd		if (cgc->cgc_dirty) {
192163849Spjd			bcopy(&cgc->cgc_cg, &disk->d_cg,
193163849Spjd			    sizeof(cgc->cgc_union));
194163849Spjd			if (cgwrite1(disk, cgc->cgc_cg.cg_cgx) == -1)
195163849Spjd				err(1, "cgwrite1(%d)", cgc->cgc_cg.cg_cgx);
196163849Spjd			//printf("%s: Wrote cg=%d\n", __func__,
197163849Spjd			//    cgc->cgc_cg.cg_cgx);
198163849Spjd		}
199163849Spjd		free(cgc);
200163849Spjd	}
201163849Spjd}
202163849Spjd
203163849Spjd#if 0
204163849Spjd/*
205163849Spjd * Free all non-busy cylinder groups without storing the dirty ones.
206163849Spjd */
207163849Spjdstatic void
208163849Spjdcancelcgs(void)
209163849Spjd{
210163849Spjd	struct cgchain *cgc;
211163849Spjd
212163849Spjd	assert(disk != NULL && fs != NULL);
213163849Spjd	while ((cgc = LIST_FIRST(&cglist)) != NULL) {
214163849Spjd		if (cgc->cgc_busy)
215163849Spjd			continue;
216163849Spjd		LIST_REMOVE(cgc, cgc_next);
217163849Spjd		//printf("%s: Canceled cg=%d\n", __func__, cgc->cgc_cg.cg_cgx);
218163849Spjd		free(cgc);
219163849Spjd	}
220163849Spjd}
221163849Spjd#endif
222163849Spjd
223163849Spjd/*
224207141Sjeff * Open the given provider, load superblock.
225163849Spjd */
226163849Spjdstatic void
227207141Sjeffopendisk(void)
228163849Spjd{
229163849Spjd	if (disk != NULL)
230163849Spjd		return;
231163849Spjd	disk = malloc(sizeof(*disk));
232163849Spjd	if (disk == NULL)
233163849Spjd		err(1, "malloc(%zu)", sizeof(*disk));
234163849Spjd	if (ufs_disk_fillout(disk, devnam) == -1) {
235163849Spjd		err(1, "ufs_disk_fillout(%s) failed: %s", devnam,
236163849Spjd		    disk->d_error);
237163849Spjd	}
238163849Spjd	fs = &disk->d_fs;
239163849Spjd}
240163849Spjd
241163849Spjd/*
242163849Spjd * Mark file system as clean, write the super-block back, close the disk.
243163849Spjd */
244163849Spjdstatic void
245163849Spjdclosedisk(void)
246163849Spjd{
247163849Spjd
248163849Spjd	fs->fs_clean = 1;
249163849Spjd	if (sbwrite(disk, 0) == -1)
250163849Spjd		err(1, "sbwrite(%s)", devnam);
251163849Spjd	if (ufs_disk_close(disk) == -1)
252163849Spjd		err(1, "ufs_disk_close(%s)", devnam);
253163849Spjd	free(disk);
254163849Spjd	disk = NULL;
255163849Spjd	fs = NULL;
256163849Spjd}
257163849Spjd
258163849Spjdstatic void
259163849Spjdblkfree(ufs2_daddr_t bno, long size)
260163849Spjd{
261163849Spjd	struct cgchain *cgc;
262163849Spjd	struct cg *cgp;
263163849Spjd	ufs1_daddr_t fragno, cgbno;
264163849Spjd	int i, cg, blk, frags, bbase;
265163849Spjd	u_int8_t *blksfree;
266163849Spjd
267163849Spjd	cg = dtog(fs, bno);
268163849Spjd	cgc = getcg(cg);
269163849Spjd	dirtycg(cgc);
270163849Spjd	cgp = &cgc->cgc_cg;
271163849Spjd	cgbno = dtogd(fs, bno);
272163849Spjd	blksfree = cg_blksfree(cgp);
273163849Spjd	if (size == fs->fs_bsize) {
274163849Spjd		fragno = fragstoblks(fs, cgbno);
275207141Sjeff		if (!ffs_isfreeblock(fs, blksfree, fragno))
276163849Spjd			assert(!"blkfree: freeing free block");
277207141Sjeff		ffs_setblock(fs, blksfree, fragno);
278207141Sjeff		ffs_clusteracct(fs, cgp, fragno, 1);
279163849Spjd		cgp->cg_cs.cs_nbfree++;
280163849Spjd		fs->fs_cstotal.cs_nbfree++;
281163849Spjd		fs->fs_cs(fs, cg).cs_nbfree++;
282163849Spjd	} else {
283163849Spjd		bbase = cgbno - fragnum(fs, cgbno);
284163849Spjd		/*
285163849Spjd		 * decrement the counts associated with the old frags
286163849Spjd		 */
287163849Spjd		blk = blkmap(fs, blksfree, bbase);
288207141Sjeff		ffs_fragacct(fs, blk, cgp->cg_frsum, -1);
289163849Spjd		/*
290163849Spjd		 * deallocate the fragment
291163849Spjd		 */
292163849Spjd		frags = numfrags(fs, size);
293163849Spjd		for (i = 0; i < frags; i++) {
294163849Spjd			if (isset(blksfree, cgbno + i))
295163849Spjd				assert(!"blkfree: freeing free frag");
296163849Spjd			setbit(blksfree, cgbno + i);
297163849Spjd		}
298163849Spjd		cgp->cg_cs.cs_nffree += i;
299163849Spjd		fs->fs_cstotal.cs_nffree += i;
300163849Spjd		fs->fs_cs(fs, cg).cs_nffree += i;
301163849Spjd		/*
302163849Spjd		 * add back in counts associated with the new frags
303163849Spjd		 */
304163849Spjd		blk = blkmap(fs, blksfree, bbase);
305207141Sjeff		ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
306163849Spjd		/*
307163849Spjd		 * if a complete block has been reassembled, account for it
308163849Spjd		 */
309163849Spjd		fragno = fragstoblks(fs, bbase);
310207141Sjeff		if (ffs_isblock(fs, blksfree, fragno)) {
311163849Spjd			cgp->cg_cs.cs_nffree -= fs->fs_frag;
312163849Spjd			fs->fs_cstotal.cs_nffree -= fs->fs_frag;
313163849Spjd			fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
314207141Sjeff			ffs_clusteracct(fs, cgp, fragno, 1);
315163849Spjd			cgp->cg_cs.cs_nbfree++;
316163849Spjd			fs->fs_cstotal.cs_nbfree++;
317163849Spjd			fs->fs_cs(fs, cg).cs_nbfree++;
318163849Spjd		}
319163849Spjd	}
320163849Spjd}
321163849Spjd
322163849Spjd/*
323163849Spjd * Recursively free all indirect blocks.
324163849Spjd */
325163849Spjdstatic void
326163849Spjdfreeindir(ufs2_daddr_t blk, int level)
327163849Spjd{
328163849Spjd	char sblks[MAXBSIZE];
329163849Spjd	ufs2_daddr_t *blks;
330163849Spjd	int i;
331163849Spjd
332163849Spjd	if (bread(disk, fsbtodb(fs, blk), (void *)&sblks, (size_t)fs->fs_bsize) == -1)
333163849Spjd		err(1, "bread: %s", disk->d_error);
334163849Spjd	blks = (ufs2_daddr_t *)&sblks;
335207141Sjeff	for (i = 0; i < NINDIR(fs); i++) {
336163849Spjd		if (blks[i] == 0)
337163849Spjd			break;
338163849Spjd		if (level == 0)
339163849Spjd			blkfree(blks[i], fs->fs_bsize);
340163849Spjd		else
341163849Spjd			freeindir(blks[i], level - 1);
342163849Spjd	}
343163849Spjd	blkfree(blk, fs->fs_bsize);
344163849Spjd}
345163849Spjd
346163849Spjd#define	dblksize(fs, dino, lbn) \
347163849Spjd	((dino)->di_size >= smalllblktosize(fs, (lbn) + 1) \
348163849Spjd	    ? (fs)->fs_bsize \
349163849Spjd	    : fragroundup(fs, blkoff(fs, (dino)->di_size)))
350163849Spjd
351163849Spjd/*
352163849Spjd * Free all blocks associated with the given inode.
353163849Spjd */
354163849Spjdstatic void
355163849Spjdclear_inode(struct ufs2_dinode *dino)
356163849Spjd{
357163849Spjd	ufs2_daddr_t bn;
358163849Spjd	int extblocks, i, level;
359163849Spjd	off_t osize;
360163849Spjd	long bsize;
361163849Spjd
362163849Spjd	extblocks = 0;
363163849Spjd	if (fs->fs_magic == FS_UFS2_MAGIC && dino->di_extsize > 0)
364163849Spjd		extblocks = btodb(fragroundup(fs, dino->di_extsize));
365163849Spjd	/* deallocate external attributes blocks */
366163849Spjd	if (extblocks > 0) {
367163849Spjd		osize = dino->di_extsize;
368163849Spjd		dino->di_blocks -= extblocks;
369163849Spjd		dino->di_extsize = 0;
370163849Spjd		for (i = 0; i < NXADDR; i++) {
371163849Spjd			if (dino->di_extb[i] == 0)
372163849Spjd				continue;
373163849Spjd			blkfree(dino->di_extb[i], sblksize(fs, osize, i));
374163849Spjd		}
375163849Spjd	}
376163849Spjd#define	SINGLE	0	/* index of single indirect block */
377163849Spjd#define	DOUBLE	1	/* index of double indirect block */
378163849Spjd#define	TRIPLE	2	/* index of triple indirect block */
379163849Spjd	/* deallocate indirect blocks */
380163849Spjd	for (level = SINGLE; level <= TRIPLE; level++) {
381163849Spjd		if (dino->di_ib[level] == 0)
382163849Spjd			break;
383163849Spjd		freeindir(dino->di_ib[level], level);
384163849Spjd	}
385163849Spjd	/* deallocate direct blocks and fragments */
386163849Spjd	for (i = 0; i < NDADDR; i++) {
387163849Spjd		bn = dino->di_db[i];
388163849Spjd		if (bn == 0)
389163849Spjd			continue;
390163849Spjd		bsize = dblksize(fs, dino, i);
391163849Spjd		blkfree(bn, bsize);
392163849Spjd	}
393163849Spjd}
394163849Spjd
395163849Spjdvoid
396163849Spjdgjournal_check(const char *filesys)
397163849Spjd{
398163849Spjd	struct ufs2_dinode *dino;
399163866Sru	void *p;
400163849Spjd	struct cgchain *cgc;
401163849Spjd	struct cg *cgp;
402231812Seadler	uint8_t *inosused;
403163849Spjd	ino_t cino, ino;
404163849Spjd	int cg, mode;
405163849Spjd
406163849Spjd	devnam = filesys;
407207141Sjeff	opendisk();
408193372Spjd	/* Are there any unreferenced inodes in this file system? */
409163849Spjd	if (fs->fs_unrefs == 0) {
410163849Spjd		//printf("No unreferenced inodes.\n");
411163849Spjd		closedisk();
412163849Spjd		return;
413163849Spjd	}
414163849Spjd
415163849Spjd	for (cg = 0; cg < fs->fs_ncg; cg++) {
416163849Spjd		/* Show progress if requested. */
417163849Spjd		if (got_siginfo) {
418163849Spjd			printf("%s: phase j: cyl group %d of %d (%d%%)\n",
419163849Spjd			    cdevname, cg, fs->fs_ncg, cg * 100 / fs->fs_ncg);
420163849Spjd			got_siginfo = 0;
421163849Spjd		}
422163849Spjd		if (got_sigalarm) {
423163849Spjd			setproctitle("%s pj %d%%", cdevname,
424163849Spjd			     cg * 100 / fs->fs_ncg);
425163849Spjd			got_sigalarm = 0;
426163849Spjd		}
427163849Spjd		cgc = getcg(cg);
428163849Spjd		cgp = &cgc->cgc_cg;
429163849Spjd		/* Are there any unreferenced inodes in this cylinder group? */
430163849Spjd		if (cgp->cg_unrefs == 0)
431163849Spjd			continue;
432163849Spjd		//printf("Analizing cylinder group %d (count=%d)\n", cg, cgp->cg_unrefs);
433163849Spjd		/*
434163849Spjd		 * We are going to modify this cylinder group, so we want it to
435163849Spjd		 * be written back.
436163849Spjd		 */
437163849Spjd		dirtycg(cgc);
438163849Spjd		/* We don't want it to be freed in the meantime. */
439163849Spjd		busycg(cgc);
440163849Spjd		inosused = cg_inosused(cgp);
441163849Spjd		/*
442163849Spjd		 * Now go through the list of all inodes in this cylinder group
443163849Spjd		 * to find unreferenced ones.
444163849Spjd		 */
445163849Spjd		for (cino = 0; cino < fs->fs_ipg; cino++) {
446163849Spjd			ino = fs->fs_ipg * cg + cino;
447163849Spjd			/* Unallocated? Skip it. */
448163849Spjd			if (isclr(inosused, cino))
449163849Spjd				continue;
450163866Sru			if (getino(disk, &p, ino, &mode) == -1)
451163849Spjd				err(1, "getino(cg=%d ino=%d)", cg, ino);
452163866Sru			dino = p;
453163849Spjd			/* Not a regular file nor directory? Skip it. */
454163849Spjd			if (!S_ISREG(dino->di_mode) && !S_ISDIR(dino->di_mode))
455163849Spjd				continue;
456163849Spjd			/* Has reference(s)? Skip it. */
457163849Spjd			if (dino->di_nlink > 0)
458163849Spjd				continue;
459163849Spjd			//printf("Clearing inode=%d (size=%jd)\n", ino, (intmax_t)dino->di_size);
460163849Spjd			/* Free inode's blocks. */
461163849Spjd			clear_inode(dino);
462163849Spjd			/* Deallocate it. */
463163849Spjd			clrbit(inosused, cino);
464163849Spjd			/* Update position of last used inode. */
465163849Spjd			if (ino < cgp->cg_irotor)
466163849Spjd				cgp->cg_irotor = ino;
467163849Spjd			/* Update statistics. */
468163849Spjd			cgp->cg_cs.cs_nifree++;
469163849Spjd			fs->fs_cs(fs, cg).cs_nifree++;
470163849Spjd			fs->fs_cstotal.cs_nifree++;
471163849Spjd			cgp->cg_unrefs--;
472163849Spjd			fs->fs_unrefs--;
473163849Spjd			/* If this is directory, update related statistics. */
474163849Spjd			if (S_ISDIR(dino->di_mode)) {
475163849Spjd				cgp->cg_cs.cs_ndir--;
476163849Spjd				fs->fs_cs(fs, cg).cs_ndir--;
477163849Spjd				fs->fs_cstotal.cs_ndir--;
478163849Spjd			}
479163849Spjd			/* Zero-fill the inode. */
480163849Spjd			*dino = ufs2_zino;
481163849Spjd			/* Write the inode back. */
482207141Sjeff			if (putino(disk) == -1)
483163849Spjd				err(1, "putino(cg=%d ino=%d)", cg, ino);
484163849Spjd			if (cgp->cg_unrefs == 0) {
485163849Spjd				//printf("No more unreferenced inodes in cg=%d.\n", cg);
486163849Spjd				break;
487163849Spjd			}
488163849Spjd		}
489163849Spjd		/*
490163849Spjd		 * We don't need this cylinder group anymore, so feel free to
491163849Spjd		 * free it if needed.
492163849Spjd		 */
493163849Spjd		unbusycg(cgc);
494163849Spjd		/*
495163849Spjd		 * If there are no more unreferenced inodes, there is no need to
496163849Spjd		 * check other cylinder groups.
497163849Spjd		 */
498163849Spjd		if (fs->fs_unrefs == 0) {
499163849Spjd			//printf("No more unreferenced inodes (cg=%d/%d).\n", cg,
500163849Spjd			//    fs->fs_ncg);
501163849Spjd			break;
502163849Spjd		}
503163849Spjd	}
504163849Spjd	/* Write back modified cylinder groups. */
505163849Spjd	putcgs();
506163849Spjd	/* Write back updated statistics and super-block. */
507207141Sjeff	closedisk();
508163849Spjd}
509