pass5.c revision 253155
120253Sjoerg/*
220302Sjoerg * Copyright (c) 1980, 1986, 1993
320302Sjoerg *	The Regents of the University of California.  All rights reserved.
420253Sjoerg *
520253Sjoerg * Redistribution and use in source and binary forms, with or without
620253Sjoerg * modification, are permitted provided that the following conditions
720253Sjoerg * are met:
820253Sjoerg * 1. Redistributions of source code must retain the above copyright
920302Sjoerg *    notice, this list of conditions and the following disclaimer.
1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1120253Sjoerg *    notice, this list of conditions and the following disclaimer in the
1220253Sjoerg *    documentation and/or other materials provided with the distribution.
1320253Sjoerg * 4. Neither the name of the University nor the names of its contributors
1420302Sjoerg *    may be used to endorse or promote products derived from this software
1520253Sjoerg *    without specific prior written permission.
1620253Sjoerg *
1720302Sjoerg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1820253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1920253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2020253Sjoerg * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2120253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2220253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2320253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2420253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2544229Sdavidn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2620253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2720253Sjoerg * SUCH DAMAGE.
2830259Scharnier */
2930259Scharnier
3050479Speter#if 0
3130259Scharnier#ifndef lint
3230259Scharnierstatic const char sccsid[] = "@(#)pass5.c	8.9 (Berkeley) 4/28/95";
3330259Scharnier#endif /* not lint */
3430259Scharnier#endif
3520253Sjoerg#include <sys/cdefs.h>
3620253Sjoerg__FBSDID("$FreeBSD: stable/9/sbin/fsck_ffs/pass5.c 253155 2013-07-10 14:13:37Z des $");
3720253Sjoerg
3830259Scharnier#include <sys/param.h>
3920253Sjoerg#include <sys/sysctl.h>
4020555Sdavidn
4120555Sdavidn#include <ufs/ufs/dinode.h>
4220555Sdavidn#include <ufs/ffs/fs.h>
4330259Scharnier
4464918Sgreen#include <err.h>
4520253Sjoerg#include <inttypes.h>
4620253Sjoerg#include <limits.h>
4720253Sjoerg#include <string.h>
4823318Sache#include <libufs.h>
4922394Sdavidn
5052512Sdavidn#include "fsck.h"
5124214Sache
5244386Sdavidnstatic void check_maps(u_char *, u_char *, int, ufs2_daddr_t, const char *,
5320253Sjoerg			int *, int, int, int);
5420253Sjoergstatic void clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end);
5520253Sjoerg
5620253Sjoergvoid
5720253Sjoergpass5(void)
5820253Sjoerg{
5920253Sjoerg	int c, i, j, blk, frags, basesize, mapsize;
6020253Sjoerg	int inomapsize, blkmapsize;
6120253Sjoerg	struct fs *fs = &sblock;
6285145Sache	ufs2_daddr_t d, dbase, dmax, start;
6320253Sjoerg	int rewritecg = 0;
6420253Sjoerg	struct csum *cs;
6520253Sjoerg	struct csum_total cstotal;
6620253Sjoerg	struct inodesc idesc[3];
6720253Sjoerg	char buf[MAXBSIZE];
6820253Sjoerg	struct cg *cg, *newcg = (struct cg *)buf;
6920253Sjoerg	struct bufarea *cgbp;
7020253Sjoerg
7120253Sjoerg	inoinfo(WINO)->ino_state = USTATE;
7220253Sjoerg	memset(newcg, 0, (size_t)fs->fs_cgsize);
7320253Sjoerg	newcg->cg_niblk = fs->fs_ipg;
7420253Sjoerg	if (cvtlevel >= 3) {
7520253Sjoerg		if (fs->fs_maxcontig < 2 && fs->fs_contigsumsize > 0) {
7620253Sjoerg			if (preen)
7720253Sjoerg				pwarn("DELETING CLUSTERING MAPS\n");
7820253Sjoerg			if (preen || reply("DELETE CLUSTERING MAPS")) {
7920253Sjoerg				fs->fs_contigsumsize = 0;
8020253Sjoerg				rewritecg = 1;
81124382Siedowse				sbdirty();
8220253Sjoerg			}
8320253Sjoerg		}
8420253Sjoerg		if (fs->fs_maxcontig > 1) {
8520253Sjoerg			const char *doit = 0;
8620253Sjoerg
8720253Sjoerg			if (fs->fs_contigsumsize < 1) {
8820253Sjoerg				doit = "CREAT";
8920253Sjoerg			} else if (fs->fs_contigsumsize < fs->fs_maxcontig &&
9020253Sjoerg				   fs->fs_contigsumsize < FS_MAXCONTIG) {
9120253Sjoerg				doit = "EXPAND";
9220253Sjoerg			}
9320253Sjoerg			if (doit) {
9420253Sjoerg				i = fs->fs_contigsumsize;
9520253Sjoerg				fs->fs_contigsumsize =
9620253Sjoerg				    MIN(fs->fs_maxcontig, FS_MAXCONTIG);
9720253Sjoerg				if (CGSIZE(fs) > (u_int)fs->fs_bsize) {
9820253Sjoerg					pwarn("CANNOT %s CLUSTER MAPS\n", doit);
9952527Sdavidn					fs->fs_contigsumsize = i;
10020253Sjoerg				} else if (preen ||
10152512Sdavidn				    reply("CREATE CLUSTER MAPS")) {
10220253Sjoerg					if (preen)
10320253Sjoerg						pwarn("%sING CLUSTER MAPS\n",
10420253Sjoerg						    doit);
10520253Sjoerg					fs->fs_cgsize =
10620253Sjoerg					    fragroundup(fs, CGSIZE(fs));
10720253Sjoerg					rewritecg = 1;
10820747Sdavidn					sbdirty();
10982868Sdd				}
110167919Sle			}
111167919Sle		}
11220253Sjoerg	}
11320253Sjoerg	basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_firstfield);
11420253Sjoerg	if (sblock.fs_magic == FS_UFS2_MAGIC) {
11520253Sjoerg		newcg->cg_iusedoff = basesize;
11620253Sjoerg	} else {
11720253Sjoerg		/*
11820253Sjoerg		 * We reserve the space for the old rotation summary
11920253Sjoerg		 * tables for the benefit of old kernels, but do not
12020253Sjoerg		 * maintain them in modern kernels. In time, they can
12120253Sjoerg		 * go away.
12256000Sdavidn		 */
12320253Sjoerg		newcg->cg_old_btotoff = basesize;
12420253Sjoerg		newcg->cg_old_boff = newcg->cg_old_btotoff +
12556000Sdavidn		    fs->fs_old_cpg * sizeof(int32_t);
12656000Sdavidn		newcg->cg_iusedoff = newcg->cg_old_boff +
12756000Sdavidn		    fs->fs_old_cpg * fs->fs_old_nrpos * sizeof(u_int16_t);
12820253Sjoerg		memset(&newcg->cg_space[0], 0, newcg->cg_iusedoff - basesize);
12920253Sjoerg	}
13052512Sdavidn	inomapsize = howmany(fs->fs_ipg, CHAR_BIT);
13120253Sjoerg	newcg->cg_freeoff = newcg->cg_iusedoff + inomapsize;
13220267Sjoerg	blkmapsize = howmany(fs->fs_fpg, CHAR_BIT);
13320267Sjoerg	newcg->cg_nextfreeoff = newcg->cg_freeoff + blkmapsize;
13420267Sjoerg	if (fs->fs_contigsumsize > 0) {
13520267Sjoerg		newcg->cg_clustersumoff = newcg->cg_nextfreeoff -
13620267Sjoerg		    sizeof(u_int32_t);
13720267Sjoerg		newcg->cg_clustersumoff =
13820267Sjoerg		    roundup(newcg->cg_clustersumoff, sizeof(u_int32_t));
13920267Sjoerg		newcg->cg_clusteroff = newcg->cg_clustersumoff +
14020267Sjoerg		    (fs->fs_contigsumsize + 1) * sizeof(u_int32_t);
14120267Sjoerg		newcg->cg_nextfreeoff = newcg->cg_clusteroff +
14220267Sjoerg		    howmany(fragstoblks(fs, fs->fs_fpg), CHAR_BIT);
14320267Sjoerg	}
14420267Sjoerg	newcg->cg_magic = CG_MAGIC;
14520267Sjoerg	mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
14620253Sjoerg	memset(&idesc[0], 0, sizeof idesc);
14720253Sjoerg	for (i = 0; i < 3; i++)
14820253Sjoerg		idesc[i].id_type = ADDR;
14920253Sjoerg	memset(&cstotal, 0, sizeof(struct csum_total));
15020267Sjoerg	dmax = blknum(fs, fs->fs_size + fs->fs_frag - 1);
15120253Sjoerg	for (d = fs->fs_size; d < dmax; d++)
15221052Sdavidn		setbmap(d);
153167919Sle	for (c = 0; c < fs->fs_ncg; c++) {
154167919Sle		if (got_siginfo) {
155167919Sle			printf("%s: phase 5: cyl group %d of %d (%d%%)\n",
156167919Sle			    cdevname, c, sblock.fs_ncg,
157167919Sle			    c * 100 / sblock.fs_ncg);
158219408Sjkim			got_siginfo = 0;
159167919Sle		}
160168044Sle		if (got_sigalarm) {
161167919Sle			setproctitle("%s p5 %d%%", cdevname,
16221052Sdavidn			    c * 100 / sblock.fs_ncg);
16321052Sdavidn			got_sigalarm = 0;
16421052Sdavidn		}
16521052Sdavidn		cgbp = cgget(c);
166224535Sdelphij		cg = cgbp->b_un.b_cg;
16721052Sdavidn		if (!cg_chkmagic(cg))
16821052Sdavidn			pfatal("CG %d: BAD MAGIC NUMBER\n", c);
16921052Sdavidn		newcg->cg_time = cg->cg_time;
17021052Sdavidn		newcg->cg_old_time = cg->cg_old_time;
17121052Sdavidn		newcg->cg_unrefs = cg->cg_unrefs;
17221052Sdavidn		newcg->cg_cgx = c;
17330259Scharnier		dbase = cgbase(fs, c);
17421052Sdavidn		dmax = dbase + fs->fs_fpg;
17521052Sdavidn		if (dmax > fs->fs_size)
17621052Sdavidn			dmax = fs->fs_size;
17721052Sdavidn		newcg->cg_ndblk = dmax - dbase;
17821242Sdavidn		if (fs->fs_magic == FS_UFS1_MAGIC) {
17921242Sdavidn			if (c == fs->fs_ncg - 1)
18021242Sdavidn				newcg->cg_old_ncyl = howmany(newcg->cg_ndblk,
18121242Sdavidn				    fs->fs_fpg / fs->fs_old_cpg);
18221242Sdavidn			else
18321242Sdavidn				newcg->cg_old_ncyl = fs->fs_old_cpg;
18421242Sdavidn			newcg->cg_old_niblk = fs->fs_ipg;
18521242Sdavidn			newcg->cg_niblk = 0;
18621242Sdavidn		}
187219408Sjkim		if (fs->fs_contigsumsize > 0)
18821242Sdavidn			newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag;
189148584Spjd		newcg->cg_cs.cs_ndir = 0;
190148584Spjd		newcg->cg_cs.cs_nffree = 0;
191148584Spjd		newcg->cg_cs.cs_nbfree = 0;
192148584Spjd		newcg->cg_cs.cs_nifree = fs->fs_ipg;
193148584Spjd		if (cg->cg_rotor >= 0 && cg->cg_rotor < newcg->cg_ndblk)
19421242Sdavidn			newcg->cg_rotor = cg->cg_rotor;
19521242Sdavidn		else
19621242Sdavidn			newcg->cg_rotor = 0;
197130633Srobert		if (cg->cg_frotor >= 0 && cg->cg_frotor < newcg->cg_ndblk)
198130633Srobert			newcg->cg_frotor = cg->cg_frotor;
19921242Sdavidn		else
20021242Sdavidn			newcg->cg_frotor = 0;
20121242Sdavidn		if (cg->cg_irotor >= 0 && cg->cg_irotor < fs->fs_ipg)
20221242Sdavidn			newcg->cg_irotor = cg->cg_irotor;
203219408Sjkim		else
20421242Sdavidn			newcg->cg_irotor = 0;
20521242Sdavidn		if (fs->fs_magic == FS_UFS1_MAGIC) {
20621242Sdavidn			newcg->cg_initediblk = 0;
20730259Scharnier		} else {
20821242Sdavidn			if ((unsigned)cg->cg_initediblk > fs->fs_ipg)
20921242Sdavidn				newcg->cg_initediblk = fs->fs_ipg;
21021052Sdavidn			else
21121242Sdavidn				newcg->cg_initediblk = cg->cg_initediblk;
212219408Sjkim		}
21330259Scharnier		memset(&newcg->cg_frsum[0], 0, sizeof newcg->cg_frsum);
21421052Sdavidn		memset(cg_inosused(newcg), 0, (size_t)(mapsize));
21521052Sdavidn		j = fs->fs_ipg * c;
21621052Sdavidn		for (i = 0; i < inostathead[c].il_numalloced; j++, i++) {
21721052Sdavidn			switch (inoinfo(j)->ino_state) {
21830259Scharnier
21921052Sdavidn			case USTATE:
22021052Sdavidn				break;
22120253Sjoerg
22220253Sjoerg			case DSTATE:
22320253Sjoerg			case DCLEAR:
22421330Sdavidn			case DFOUND:
22521330Sdavidn			case DZLINK:
22621330Sdavidn				newcg->cg_cs.cs_ndir++;
22720253Sjoerg				/* FALLTHROUGH */
22820253Sjoerg
22920253Sjoerg			case FSTATE:
23020253Sjoerg			case FCLEAR:
23163596Sdavidn			case FZLINK:
23263596Sdavidn				newcg->cg_cs.cs_nifree--;
23363596Sdavidn				setbit(cg_inosused(newcg), i);
23463596Sdavidn				break;
23563596Sdavidn
23663596Sdavidn			default:
23763596Sdavidn				if (j < (int)ROOTINO)
23863596Sdavidn					break;
23920253Sjoerg				errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
24020253Sjoerg				    inoinfo(j)->ino_state, j);
24120253Sjoerg			}
24220679Sdavidn		}
24320253Sjoerg		if (c == 0)
24420253Sjoerg			for (i = 0; i < (int)ROOTINO; i++) {
24552527Sdavidn				setbit(cg_inosused(newcg), i);
24620253Sjoerg				newcg->cg_cs.cs_nifree--;
24720747Sdavidn			}
24844229Sdavidn		start = -1;
24961957Sache		for (i = 0, d = dbase;
25030259Scharnier		     d < dmax;
25120253Sjoerg		     d += fs->fs_frag, i += fs->fs_frag) {
25220747Sdavidn			frags = 0;
25320747Sdavidn			for (j = 0; j < fs->fs_frag; j++) {
25420253Sjoerg				if (testbmap(d + j)) {
25520747Sdavidn					if ((Eflag || Zflag) && start != -1) {
25620253Sjoerg						clear_blocks(start, d + j - 1);
25720253Sjoerg						start = -1;
25852527Sdavidn					}
25920253Sjoerg					continue;
26026088Sdavidn				}
26130259Scharnier				if (start == -1)
26220253Sjoerg					start = d + j;
26352527Sdavidn				setbit(cg_blksfree(newcg), i + j);
26420253Sjoerg				frags++;
26520253Sjoerg			}
26620253Sjoerg			if (frags == fs->fs_frag) {
26763600Sdavidn				newcg->cg_cs.cs_nbfree++;
26863600Sdavidn				if (fs->fs_contigsumsize > 0)
26920253Sjoerg					setbit(cg_clustersfree(newcg),
27020253Sjoerg					    i / fs->fs_frag);
27130259Scharnier			} else if (frags > 0) {
27220253Sjoerg				newcg->cg_cs.cs_nffree += frags;
27320253Sjoerg				blk = blkmap(fs, cg_blksfree(newcg), i);
27420253Sjoerg				ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
27520253Sjoerg			}
27620253Sjoerg		}
27720253Sjoerg		if ((Eflag || Zflag) && start != -1)
27820253Sjoerg			clear_blocks(start, d - 1);
27920253Sjoerg		if (fs->fs_contigsumsize > 0) {
28020253Sjoerg			int32_t *sump = cg_clustersum(newcg);
28120253Sjoerg			u_char *mapp = cg_clustersfree(newcg);
28220253Sjoerg			int map = *mapp++;
28320253Sjoerg			int bit = 1;
28420253Sjoerg			int run = 0;
28520253Sjoerg
28620253Sjoerg			for (i = 0; i < newcg->cg_nclusterblks; i++) {
28720267Sjoerg				if ((map & bit) != 0) {
28830259Scharnier					run++;
28920267Sjoerg				} else if (run != 0) {
29020253Sjoerg					if (run > fs->fs_contigsumsize)
29152527Sdavidn						run = fs->fs_contigsumsize;
29220253Sjoerg					sump[run]++;
29320267Sjoerg					run = 0;
29444386Sdavidn				}
29520253Sjoerg				if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) {
29644229Sdavidn					bit <<= 1;
29744229Sdavidn				} else {
29844386Sdavidn					map = *mapp++;
29944229Sdavidn					bit = 1;
30020267Sjoerg				}
30120253Sjoerg			}
30252527Sdavidn			if (run != 0) {
30320253Sjoerg				if (run > fs->fs_contigsumsize)
30444229Sdavidn					run = fs->fs_contigsumsize;
30520253Sjoerg				sump[run]++;
30620253Sjoerg			}
30720253Sjoerg		}
30820253Sjoerg		if (bkgrdflag != 0) {
30930259Scharnier			cstotal.cs_nffree += cg->cg_cs.cs_nffree;
31020253Sjoerg			cstotal.cs_nbfree += cg->cg_cs.cs_nbfree;
31120253Sjoerg			cstotal.cs_nifree += cg->cg_cs.cs_nifree;
31220253Sjoerg			cstotal.cs_ndir += cg->cg_cs.cs_ndir;
31320253Sjoerg		} else {
31420253Sjoerg			cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
31520253Sjoerg			cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
31643780Sdes			cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
31743780Sdes			cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
31843780Sdes		}
31920253Sjoerg		cs = &fs->fs_cs(fs, c);
32020253Sjoerg		if (cursnapshot == 0 &&
32120253Sjoerg		    memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 &&
32220253Sjoerg		    dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
32352527Sdavidn			memmove(cs, &newcg->cg_cs, sizeof *cs);
32420253Sjoerg			sbdirty();
32520253Sjoerg		}
32620253Sjoerg		if (rewritecg) {
32752512Sdavidn			memmove(cg, newcg, (size_t)fs->fs_cgsize);
32852512Sdavidn			dirty(cgbp);
32952527Sdavidn			continue;
33020253Sjoerg		}
33144229Sdavidn		if (cursnapshot == 0 &&
33220253Sjoerg		    memcmp(newcg, cg, basesize) != 0 &&
33320253Sjoerg		    dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
33420253Sjoerg			memmove(cg, newcg, (size_t)basesize);
33520253Sjoerg			dirty(cgbp);
33620253Sjoerg		}
33744386Sdavidn		if (bkgrdflag != 0 || usedsoftdep || debug)
33844386Sdavidn			update_maps(cg, newcg, bkgrdflag);
33944386Sdavidn		if (cursnapshot == 0 &&
34020253Sjoerg		    memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 &&
34120253Sjoerg		    dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
34230259Scharnier			memmove(cg_inosused(cg), cg_inosused(newcg),
34330259Scharnier			      (size_t)mapsize);
34420253Sjoerg			dirty(cgbp);
34552527Sdavidn		}
34620253Sjoerg	}
34720253Sjoerg	if (cursnapshot == 0 &&
34820253Sjoerg	    memcmp(&cstotal, &fs->fs_cstotal, sizeof cstotal) != 0
34920253Sjoerg	    && dofix(&idesc[0], "SUMMARY BLK COUNT(S) WRONG IN SUPERBLK")) {
35052512Sdavidn		memmove(&fs->fs_cstotal, &cstotal, sizeof cstotal);
35152512Sdavidn		fs->fs_ronly = 0;
35252512Sdavidn		fs->fs_fmod = 0;
35352512Sdavidn		sbdirty();
35452512Sdavidn	}
35552512Sdavidn
35652512Sdavidn	/*
35752512Sdavidn	 * When doing background fsck on a snapshot, figure out whether
35852512Sdavidn	 * the superblock summary is inaccurate and correct it when
35952512Sdavidn	 * necessary.
36052512Sdavidn	 */
36152512Sdavidn	if (cursnapshot != 0) {
36252512Sdavidn		cmd.size = 1;
36352512Sdavidn
36452512Sdavidn		cmd.value = cstotal.cs_ndir - fs->fs_cstotal.cs_ndir;
36552512Sdavidn		if (cmd.value != 0) {
36652512Sdavidn			if (debug)
36752512Sdavidn				printf("adjndir by %+" PRIi64 "\n", cmd.value);
36852527Sdavidn			if (bkgrdsumadj == 0 || sysctl(adjndir, MIBSIZE, 0, 0,
36952512Sdavidn			    &cmd, sizeof cmd) == -1)
37052512Sdavidn				rwerror("ADJUST NUMBER OF DIRECTORIES", cmd.value);
37152512Sdavidn		}
37252512Sdavidn
37352527Sdavidn		cmd.value = cstotal.cs_nbfree - fs->fs_cstotal.cs_nbfree;
37452527Sdavidn		if (cmd.value != 0) {
37552527Sdavidn			if (debug)
37652527Sdavidn				printf("adjnbfree by %+" PRIi64 "\n", cmd.value);
37752527Sdavidn			if (bkgrdsumadj == 0 || sysctl(adjnbfree, MIBSIZE, 0, 0,
37820253Sjoerg			    &cmd, sizeof cmd) == -1)
37920253Sjoerg				rwerror("ADJUST NUMBER OF FREE BLOCKS", cmd.value);
38020253Sjoerg		}
38120253Sjoerg
38220253Sjoerg		cmd.value = cstotal.cs_nifree - fs->fs_cstotal.cs_nifree;
38330259Scharnier		if (cmd.value != 0) {
38420253Sjoerg			if (debug)
38544229Sdavidn				printf("adjnifree by %+" PRIi64 "\n", cmd.value);
38644229Sdavidn			if (bkgrdsumadj == 0 || sysctl(adjnifree, MIBSIZE, 0, 0,
38785145Sache			    &cmd, sizeof cmd) == -1)
38844229Sdavidn				rwerror("ADJUST NUMBER OF FREE INODES", cmd.value);
38920747Sdavidn		}
39085145Sache
39120747Sdavidn		cmd.value = cstotal.cs_nffree - fs->fs_cstotal.cs_nffree;
39244229Sdavidn		if (cmd.value != 0) {
39344229Sdavidn			if (debug)
39444229Sdavidn				printf("adjnffree by %+" PRIi64 "\n", cmd.value);
39544229Sdavidn			if (bkgrdsumadj == 0 || sysctl(adjnffree, MIBSIZE, 0, 0,
39644229Sdavidn			    &cmd, sizeof cmd) == -1)
39744229Sdavidn				rwerror("ADJUST NUMBER OF FREE FRAGS", cmd.value);
39844229Sdavidn		}
39944229Sdavidn
40020253Sjoerg		cmd.value = cstotal.cs_numclusters - fs->fs_cstotal.cs_numclusters;
40120253Sjoerg		if (cmd.value != 0) {
40220253Sjoerg			if (debug)
40320253Sjoerg				printf("adjnumclusters by %+" PRIi64 "\n", cmd.value);
40420253Sjoerg			if (bkgrdsumadj == 0 || sysctl(adjnumclusters, MIBSIZE, 0, 0,
40520253Sjoerg			    &cmd, sizeof cmd) == -1)
406130633Srobert				rwerror("ADJUST NUMBER OF FREE CLUSTERS", cmd.value);
40720253Sjoerg		}
40852502Sdavidn	}
40952502Sdavidn}
41052502Sdavidn
41152502Sdavidn/*
41256000Sdavidn * Compare the original cylinder group inode and block bitmaps with the
41352502Sdavidn * updated cylinder group inode and block bitmaps. Free inodes and blocks
41452502Sdavidn * that have been added. Complain if any previously freed inodes blocks
41521330Sdavidn * are now allocated.
41652502Sdavidn */
41752502Sdavidnvoid
41852502Sdavidnupdate_maps(
41952502Sdavidn	struct cg *oldcg,	/* cylinder group of claimed allocations */
42052502Sdavidn	struct cg *newcg,	/* cylinder group of determined allocations */
42156000Sdavidn	int usesysctl)		/* 1 => use sysctl interface to update maps */
42252502Sdavidn{
42352502Sdavidn	int inomapsize, excessdirs;
42452502Sdavidn	struct fs *fs = &sblock;
42520253Sjoerg
42620253Sjoerg	inomapsize = howmany(fs->fs_ipg, CHAR_BIT);
42720253Sjoerg	excessdirs = oldcg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir;
42820253Sjoerg	if (excessdirs < 0) {
42944229Sdavidn		pfatal("LOST %d DIRECTORIES\n", -excessdirs);
43044229Sdavidn		excessdirs = 0;
43144229Sdavidn	}
43244229Sdavidn	if (excessdirs > 0)
43344229Sdavidn		check_maps(cg_inosused(newcg), cg_inosused(oldcg), inomapsize,
43420253Sjoerg		    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_ipg, "DIR", freedirs,
43544229Sdavidn		    0, excessdirs, usesysctl);
43644229Sdavidn	check_maps(cg_inosused(newcg), cg_inosused(oldcg), inomapsize,
43744229Sdavidn	    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_ipg, "FILE", freefiles,
43844229Sdavidn	    excessdirs, fs->fs_ipg, usesysctl);
43944229Sdavidn	check_maps(cg_blksfree(oldcg), cg_blksfree(newcg),
44020253Sjoerg	    howmany(fs->fs_fpg, CHAR_BIT),
44144229Sdavidn	    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_fpg, "FRAG",
44244229Sdavidn	    freeblks, 0, fs->fs_fpg, usesysctl);
44344229Sdavidn}
44444229Sdavidn
44544229Sdavidnstatic void
44644229Sdavidncheck_maps(
44744229Sdavidn	u_char *map1,	/* map of claimed allocations */
44844229Sdavidn	u_char *map2,	/* map of determined allocations */
44944229Sdavidn	int mapsize,	/* size of above two maps */
45044229Sdavidn	ufs2_daddr_t startvalue, /* resource value for first element in map */
45120253Sjoerg	const char *name,	/* name of resource found in maps */
45220253Sjoerg	int *opcode,	/* sysctl opcode to free resource */
45320267Sjoerg	int skip,	/* number of entries to skip before starting to free */
45420253Sjoerg	int limit,	/* limit on number of entries to free */
45544386Sdavidn	int usesysctl)	/* 1 => use sysctl interface to update maps */
45644386Sdavidn{
45744386Sdavidn#	define BUFSIZE 16
45820253Sjoerg	char buf[BUFSIZE];
45920253Sjoerg	long i, j, k, l, m, size;
46020253Sjoerg	ufs2_daddr_t n, astart, aend, ustart, uend;
46120253Sjoerg	void (*msg)(const char *fmt, ...);
46220253Sjoerg
46320253Sjoerg	if (usesysctl)
46430259Scharnier		msg = pfatal;
46520679Sdavidn	else
46652527Sdavidn		msg = pwarn;
46720253Sjoerg	astart = ustart = aend = uend = -1;
46852527Sdavidn	for (i = 0; i < mapsize; i++) {
46961957Sache		j = *map1++;
47020253Sjoerg		k = *map2++;
47152527Sdavidn		if (j == k)
47220253Sjoerg			continue;
47330259Scharnier		for (m = 0, l = 1; m < CHAR_BIT; m++, l <<= 1) {
47420253Sjoerg			if ((j & l) == (k & l))
47530259Scharnier				continue;
47620253Sjoerg			n = startvalue + i * CHAR_BIT + m;
47720253Sjoerg			if ((j & l) != 0) {
47852527Sdavidn				if (astart == -1) {
47952527Sdavidn					astart = aend = n;
48052527Sdavidn					continue;
48152527Sdavidn				}
48261762Sdavidn				if (aend + 1 == n) {
48352527Sdavidn					aend = n;
48452527Sdavidn					continue;
48552527Sdavidn				}
48620253Sjoerg				if (astart == aend)
48752527Sdavidn					(*msg)("ALLOCATED %s %" PRId64
48852527Sdavidn					    " MARKED FREE\n",
48952527Sdavidn					    name, astart);
49052527Sdavidn				else
49152527Sdavidn					(*msg)("%s %sS %" PRId64 "-%" PRId64
49252527Sdavidn					    " MARKED FREE\n",
49320253Sjoerg					    "ALLOCATED", name, astart, aend);
49420253Sjoerg				astart = aend = n;
49520253Sjoerg			} else {
49620253Sjoerg				if (ustart == -1) {
49720253Sjoerg					ustart = uend = n;
49830259Scharnier					continue;
49952527Sdavidn				}
50052527Sdavidn				if (uend + 1 == n) {
50152527Sdavidn					uend = n;
50252527Sdavidn					continue;
50320253Sjoerg				}
50420253Sjoerg				size = uend - ustart + 1;
50552527Sdavidn				if (size <= skip) {
50620267Sjoerg					skip -= size;
50752527Sdavidn					ustart = uend = n;
50852527Sdavidn					continue;
50952527Sdavidn				}
51052527Sdavidn				if (skip > 0) {
51152527Sdavidn					ustart += skip;
51252527Sdavidn					size -= skip;
51320253Sjoerg					skip = 0;
51420253Sjoerg				}
51520253Sjoerg				if (size > limit)
51620253Sjoerg					size = limit;
51720253Sjoerg				if (debug && size == 1)
51830259Scharnier					pwarn("%s %s %" PRId64
51952527Sdavidn					    " MARKED USED\n",
52052527Sdavidn					    "UNALLOCATED", name, ustart);
52152527Sdavidn				else if (debug)
52252527Sdavidn					pwarn("%s %sS %" PRId64 "-%" PRId64
52320253Sjoerg					    " MARKED USED\n",
52420253Sjoerg					    "UNALLOCATED", name, ustart,
52520253Sjoerg					    ustart + size - 1);
52652527Sdavidn				if (usesysctl != 0) {
52752527Sdavidn					cmd.value = ustart;
52852527Sdavidn					cmd.size = size;
52952527Sdavidn					if (sysctl(opcode, MIBSIZE, 0, 0,
53052527Sdavidn					    &cmd, sizeof cmd) == -1) {
53152527Sdavidn						snprintf(buf, BUFSIZE,
53252527Sdavidn						    "FREE %s", name);
53352527Sdavidn						rwerror(buf, cmd.value);
53452527Sdavidn					}
53520253Sjoerg				}
53652527Sdavidn				limit -= size;
53752527Sdavidn				if (limit <= 0)
53852527Sdavidn					return;
53952527Sdavidn				ustart = uend = n;
54052527Sdavidn			}
54152527Sdavidn		}
54252527Sdavidn	}
54352527Sdavidn	if (astart != -1) {
54452527Sdavidn		if (astart == aend)
54520747Sdavidn			(*msg)("ALLOCATED %s %" PRId64
546130629Srobert			    " MARKED FREE\n", name, astart);
547130629Srobert		else
54820747Sdavidn			(*msg)("ALLOCATED %sS %" PRId64 "-%" PRId64
54920747Sdavidn			    " MARKED FREE\n",
55030259Scharnier			    name, astart, aend);
55120747Sdavidn	}
55230259Scharnier	if (ustart != -1) {
55320747Sdavidn		size = uend - ustart + 1;
55420747Sdavidn		if (size <= skip)
555124382Siedowse			return;
556124382Siedowse		if (skip > 0) {
55764918Sgreen			ustart += skip;
55864918Sgreen			size -= skip;
55964918Sgreen		}
56064918Sgreen		if (size > limit)
56164918Sgreen			size = limit;
56264918Sgreen		if (debug) {
56364918Sgreen			if (size == 1)
56420267Sjoerg				pwarn("UNALLOCATED %s %" PRId64
56552527Sdavidn				    " MARKED USED\n",
56652527Sdavidn				    name, ustart);
56720267Sjoerg			else
56820253Sjoerg				pwarn("UNALLOCATED %sS %" PRId64 "-%" PRId64
56964918Sgreen				    " MARKED USED\n",
57052527Sdavidn				    name, ustart, ustart + size - 1);
57152527Sdavidn		}
57252527Sdavidn		if (usesysctl != 0) {
57352527Sdavidn			cmd.value = ustart;
57452527Sdavidn			cmd.size = size;
57520253Sjoerg			if (sysctl(opcode, MIBSIZE, 0, 0, &cmd,
57630259Scharnier			    sizeof cmd) == -1) {
57744229Sdavidn				snprintf(buf, BUFSIZE, "FREE %s", name);
57830259Scharnier				rwerror(buf, cmd.value);
57920253Sjoerg			}
58020253Sjoerg		}
58120253Sjoerg	}
58220253Sjoerg}
58320253Sjoerg
58420253Sjoergstatic void
58520253Sjoergclear_blocks(ufs2_daddr_t start, ufs2_daddr_t end)
58620253Sjoerg{
58720253Sjoerg
58820253Sjoerg	if (debug)
58920253Sjoerg		printf("Zero frags %jd to %jd\n", start, end);
59020253Sjoerg	if (Zflag)
59120253Sjoerg		blzero(fswritefd, fsbtodb(&sblock, start),
59264918Sgreen		    lfragtosize(&sblock, end - start + 1));
59364918Sgreen	if (Eflag)
59464918Sgreen		blerase(fswritefd, fsbtodb(&sblock, start),
59564918Sgreen		    lfragtosize(&sblock, end - start + 1));
59664918Sgreen}
59752527Sdavidn