1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1980, 1986, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#if 0
33#ifndef lint
34static const char sccsid[] = "@(#)pass5.c	8.9 (Berkeley) 4/28/95";
35#endif /* not lint */
36#endif
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD$");
39
40#include <sys/param.h>
41#include <sys/sysctl.h>
42
43#include <ufs/ufs/dinode.h>
44#include <ufs/ffs/fs.h>
45
46#include <err.h>
47#include <inttypes.h>
48#include <limits.h>
49#include <string.h>
50#include <libufs.h>
51
52#include "fsck.h"
53
54static void check_maps(u_char *, u_char *, int, ufs2_daddr_t, const char *,
55			int *, int, int, int);
56static void clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end);
57
58void
59pass5(void)
60{
61	int c, i, j, blk, frags, basesize, mapsize;
62	int inomapsize, blkmapsize;
63	struct fs *fs = &sblock;
64	ufs2_daddr_t d, dbase, dmax, start;
65	int rewritecg = 0;
66	ino_t inum;
67	struct csum *cs;
68	struct csum_total cstotal;
69	struct inodesc idesc[3];
70	char buf[MAXBSIZE];
71	struct cg *cg, *newcg = (struct cg *)buf;
72	struct bufarea *cgbp;
73
74	inoinfo(UFS_WINO)->ino_state = USTATE;
75	memset(newcg, 0, (size_t)fs->fs_cgsize);
76	newcg->cg_niblk = fs->fs_ipg;
77	/* check to see if we are to add a cylinder group check hash */
78	if ((ckhashadd & CK_CYLGRP) != 0) {
79		fs->fs_metackhash |= CK_CYLGRP;
80		rewritecg = 1;
81		sbdirty();
82	}
83	if (cvtlevel >= 3) {
84		if (fs->fs_maxcontig < 2 && fs->fs_contigsumsize > 0) {
85			if (preen)
86				pwarn("DELETING CLUSTERING MAPS\n");
87			if (preen || reply("DELETE CLUSTERING MAPS")) {
88				fs->fs_contigsumsize = 0;
89				rewritecg = 1;
90				sbdirty();
91			}
92		}
93		if (fs->fs_maxcontig > 1) {
94			const char *doit = NULL;
95
96			if (fs->fs_contigsumsize < 1) {
97				doit = "CREAT";
98			} else if (fs->fs_contigsumsize < fs->fs_maxcontig &&
99				   fs->fs_contigsumsize < FS_MAXCONTIG) {
100				doit = "EXPAND";
101			}
102			if (doit) {
103				i = fs->fs_contigsumsize;
104				fs->fs_contigsumsize =
105				    MIN(fs->fs_maxcontig, FS_MAXCONTIG);
106				if (CGSIZE(fs) > (u_int)fs->fs_bsize) {
107					pwarn("CANNOT %s CLUSTER MAPS\n", doit);
108					fs->fs_contigsumsize = i;
109				} else if (preen ||
110				    reply("CREATE CLUSTER MAPS")) {
111					if (preen)
112						pwarn("%sING CLUSTER MAPS\n",
113						    doit);
114					fs->fs_cgsize =
115					    fragroundup(fs, CGSIZE(fs));
116					rewritecg = 1;
117					sbdirty();
118				}
119			}
120		}
121	}
122	basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_firstfield);
123	if (sblock.fs_magic == FS_UFS2_MAGIC) {
124		newcg->cg_iusedoff = basesize;
125	} else {
126		/*
127		 * We reserve the space for the old rotation summary
128		 * tables for the benefit of old kernels, but do not
129		 * maintain them in modern kernels. In time, they can
130		 * go away.
131		 */
132		newcg->cg_old_btotoff = basesize;
133		newcg->cg_old_boff = newcg->cg_old_btotoff +
134		    fs->fs_old_cpg * sizeof(int32_t);
135		newcg->cg_iusedoff = newcg->cg_old_boff +
136		    fs->fs_old_cpg * fs->fs_old_nrpos * sizeof(u_int16_t);
137		memset(&newcg->cg_space[0], 0, newcg->cg_iusedoff - basesize);
138	}
139	inomapsize = howmany(fs->fs_ipg, CHAR_BIT);
140	newcg->cg_freeoff = newcg->cg_iusedoff + inomapsize;
141	blkmapsize = howmany(fs->fs_fpg, CHAR_BIT);
142	newcg->cg_nextfreeoff = newcg->cg_freeoff + blkmapsize;
143	if (fs->fs_contigsumsize > 0) {
144		newcg->cg_clustersumoff = newcg->cg_nextfreeoff -
145		    sizeof(u_int32_t);
146		newcg->cg_clustersumoff =
147		    roundup(newcg->cg_clustersumoff, sizeof(u_int32_t));
148		newcg->cg_clusteroff = newcg->cg_clustersumoff +
149		    (fs->fs_contigsumsize + 1) * sizeof(u_int32_t);
150		newcg->cg_nextfreeoff = newcg->cg_clusteroff +
151		    howmany(fragstoblks(fs, fs->fs_fpg), CHAR_BIT);
152	}
153	newcg->cg_magic = CG_MAGIC;
154	mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
155	memset(&idesc[0], 0, sizeof idesc);
156	for (i = 0; i < 3; i++)
157		idesc[i].id_type = ADDR;
158	memset(&cstotal, 0, sizeof(struct csum_total));
159	dmax = blknum(fs, fs->fs_size + fs->fs_frag - 1);
160	for (d = fs->fs_size; d < dmax; d++)
161		setbmap(d);
162	for (c = 0; c < fs->fs_ncg; c++) {
163		if (got_siginfo) {
164			printf("%s: phase 5: cyl group %d of %d (%d%%)\n",
165			    cdevname, c, sblock.fs_ncg,
166			    c * 100 / sblock.fs_ncg);
167			got_siginfo = 0;
168		}
169		if (got_sigalarm) {
170			setproctitle("%s p5 %d%%", cdevname,
171			    c * 100 / sblock.fs_ncg);
172			got_sigalarm = 0;
173		}
174		cgbp = cglookup(c);
175		cg = cgbp->b_un.b_cg;
176		if (!cg_chkmagic(cg))
177			pfatal("CG %d: BAD MAGIC NUMBER\n", c);
178		/*
179		 * If we have a cylinder group check hash and are not adding
180		 * it for the first time, verify that it is good.
181		 */
182		if ((fs->fs_metackhash & CK_CYLGRP) != 0 &&
183		    (ckhashadd & CK_CYLGRP) == 0) {
184			uint32_t ckhash, thishash;
185
186			ckhash = cg->cg_ckhash;
187			cg->cg_ckhash = 0;
188			thishash = calculate_crc32c(~0L, cg, fs->fs_cgsize);
189			if (ckhash != thishash)
190				pwarn("CG %d: BAD CHECK-HASH %#x vs %#x\n",
191				    c, ckhash, thishash);
192			cg->cg_ckhash = ckhash;
193		}
194		newcg->cg_time = cg->cg_time;
195		newcg->cg_old_time = cg->cg_old_time;
196		newcg->cg_unrefs = cg->cg_unrefs;
197		newcg->cg_cgx = c;
198		dbase = cgbase(fs, c);
199		dmax = dbase + fs->fs_fpg;
200		if (dmax > fs->fs_size)
201			dmax = fs->fs_size;
202		newcg->cg_ndblk = dmax - dbase;
203		if (fs->fs_magic == FS_UFS1_MAGIC) {
204			if (c == fs->fs_ncg - 1)
205				newcg->cg_old_ncyl = howmany(newcg->cg_ndblk,
206				    fs->fs_fpg / fs->fs_old_cpg);
207			else
208				newcg->cg_old_ncyl = fs->fs_old_cpg;
209			newcg->cg_old_niblk = fs->fs_ipg;
210			newcg->cg_niblk = 0;
211		}
212		if (fs->fs_contigsumsize > 0)
213			newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag;
214		newcg->cg_cs.cs_ndir = 0;
215		newcg->cg_cs.cs_nffree = 0;
216		newcg->cg_cs.cs_nbfree = 0;
217		newcg->cg_cs.cs_nifree = fs->fs_ipg;
218		if (cg->cg_rotor >= 0 && cg->cg_rotor < newcg->cg_ndblk)
219			newcg->cg_rotor = cg->cg_rotor;
220		else
221			newcg->cg_rotor = 0;
222		if (cg->cg_frotor >= 0 && cg->cg_frotor < newcg->cg_ndblk)
223			newcg->cg_frotor = cg->cg_frotor;
224		else
225			newcg->cg_frotor = 0;
226		if (cg->cg_irotor >= 0 && cg->cg_irotor < fs->fs_ipg)
227			newcg->cg_irotor = cg->cg_irotor;
228		else
229			newcg->cg_irotor = 0;
230		if (fs->fs_magic == FS_UFS1_MAGIC) {
231			newcg->cg_initediblk = 0;
232		} else {
233			if ((unsigned)cg->cg_initediblk > fs->fs_ipg)
234				newcg->cg_initediblk = fs->fs_ipg;
235			else
236				newcg->cg_initediblk = cg->cg_initediblk;
237		}
238		memset(&newcg->cg_frsum[0], 0, sizeof newcg->cg_frsum);
239		memset(cg_inosused(newcg), 0, (size_t)(mapsize));
240		inum = fs->fs_ipg * c;
241		for (i = 0; i < inostathead[c].il_numalloced; inum++, i++) {
242			switch (inoinfo(inum)->ino_state) {
243
244			case USTATE:
245				break;
246
247			case DSTATE:
248			case DCLEAR:
249			case DFOUND:
250			case DZLINK:
251				newcg->cg_cs.cs_ndir++;
252				/* FALLTHROUGH */
253
254			case FSTATE:
255			case FCLEAR:
256			case FZLINK:
257				newcg->cg_cs.cs_nifree--;
258				setbit(cg_inosused(newcg), i);
259				break;
260
261			default:
262				if (inum < UFS_ROOTINO)
263					break;
264				errx(EEXIT, "BAD STATE %d FOR INODE I=%ju",
265				    inoinfo(inum)->ino_state, (uintmax_t)inum);
266			}
267		}
268		if (c == 0)
269			for (i = 0; i < (int)UFS_ROOTINO; i++) {
270				setbit(cg_inosused(newcg), i);
271				newcg->cg_cs.cs_nifree--;
272			}
273		start = -1;
274		for (i = 0, d = dbase;
275		     d < dmax;
276		     d += fs->fs_frag, i += fs->fs_frag) {
277			frags = 0;
278			for (j = 0; j < fs->fs_frag; j++) {
279				if (testbmap(d + j)) {
280					if ((Eflag || Zflag) && start != -1) {
281						clear_blocks(start, d + j - 1);
282						start = -1;
283					}
284					continue;
285				}
286				if (start == -1)
287					start = d + j;
288				setbit(cg_blksfree(newcg), i + j);
289				frags++;
290			}
291			if (frags == fs->fs_frag) {
292				newcg->cg_cs.cs_nbfree++;
293				if (fs->fs_contigsumsize > 0)
294					setbit(cg_clustersfree(newcg),
295					    i / fs->fs_frag);
296			} else if (frags > 0) {
297				newcg->cg_cs.cs_nffree += frags;
298				blk = blkmap(fs, cg_blksfree(newcg), i);
299				ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
300			}
301		}
302		if ((Eflag || Zflag) && start != -1)
303			clear_blocks(start, d - 1);
304		if (fs->fs_contigsumsize > 0) {
305			int32_t *sump = cg_clustersum(newcg);
306			u_char *mapp = cg_clustersfree(newcg);
307			int map = *mapp++;
308			int bit = 1;
309			int run = 0;
310
311			for (i = 0; i < newcg->cg_nclusterblks; i++) {
312				if ((map & bit) != 0) {
313					run++;
314				} else if (run != 0) {
315					if (run > fs->fs_contigsumsize)
316						run = fs->fs_contigsumsize;
317					sump[run]++;
318					run = 0;
319				}
320				if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) {
321					bit <<= 1;
322				} else {
323					map = *mapp++;
324					bit = 1;
325				}
326			}
327			if (run != 0) {
328				if (run > fs->fs_contigsumsize)
329					run = fs->fs_contigsumsize;
330				sump[run]++;
331			}
332		}
333		if ((fs->fs_metackhash & CK_CYLGRP) != 0) {
334			newcg->cg_ckhash = 0;
335			newcg->cg_ckhash =
336			    calculate_crc32c(~0L, (void *)newcg, fs->fs_cgsize);
337		}
338
339		if (bkgrdflag != 0) {
340			cstotal.cs_nffree += cg->cg_cs.cs_nffree;
341			cstotal.cs_nbfree += cg->cg_cs.cs_nbfree;
342			cstotal.cs_nifree += cg->cg_cs.cs_nifree;
343			cstotal.cs_ndir += cg->cg_cs.cs_ndir;
344		} else {
345			cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
346			cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
347			cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
348			cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
349		}
350		cs = &fs->fs_cs(fs, c);
351		if (cursnapshot == 0 &&
352		    memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 &&
353		    dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
354			memmove(cs, &newcg->cg_cs, sizeof *cs);
355			sbdirty();
356		}
357		if (rewritecg) {
358			memmove(cg, newcg, (size_t)fs->fs_cgsize);
359			dirty(cgbp);
360			continue;
361		}
362		if (cursnapshot == 0 &&
363		    memcmp(newcg, cg, basesize) != 0 &&
364		    dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
365			memmove(cg, newcg, (size_t)basesize);
366			dirty(cgbp);
367		}
368		if (bkgrdflag != 0 || usedsoftdep || debug)
369			update_maps(cg, newcg, bkgrdflag);
370		if (cursnapshot == 0 &&
371		    memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 &&
372		    dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
373			memmove(cg_inosused(cg), cg_inosused(newcg),
374			      (size_t)mapsize);
375			dirty(cgbp);
376		}
377	}
378	if (cursnapshot == 0 &&
379	    memcmp(&cstotal, &fs->fs_cstotal, sizeof cstotal) != 0
380	    && dofix(&idesc[0], "SUMMARY BLK COUNT(S) WRONG IN SUPERBLK")) {
381		memmove(&fs->fs_cstotal, &cstotal, sizeof cstotal);
382		fs->fs_ronly = 0;
383		fs->fs_fmod = 0;
384		sbdirty();
385	}
386
387	/*
388	 * When doing background fsck on a snapshot, figure out whether
389	 * the superblock summary is inaccurate and correct it when
390	 * necessary.
391	 */
392	if (cursnapshot != 0) {
393		cmd.size = 1;
394
395		cmd.value = cstotal.cs_ndir - fs->fs_cstotal.cs_ndir;
396		if (cmd.value != 0) {
397			if (debug)
398				printf("adjndir by %+" PRIi64 "\n", cmd.value);
399			if (bkgrdsumadj == 0 || sysctl(adjndir, MIBSIZE, 0, 0,
400			    &cmd, sizeof cmd) == -1)
401				rwerror("ADJUST NUMBER OF DIRECTORIES", cmd.value);
402		}
403
404		cmd.value = cstotal.cs_nbfree - fs->fs_cstotal.cs_nbfree;
405		if (cmd.value != 0) {
406			if (debug)
407				printf("adjnbfree by %+" PRIi64 "\n", cmd.value);
408			if (bkgrdsumadj == 0 || sysctl(adjnbfree, MIBSIZE, 0, 0,
409			    &cmd, sizeof cmd) == -1)
410				rwerror("ADJUST NUMBER OF FREE BLOCKS", cmd.value);
411		}
412
413		cmd.value = cstotal.cs_nifree - fs->fs_cstotal.cs_nifree;
414		if (cmd.value != 0) {
415			if (debug)
416				printf("adjnifree by %+" PRIi64 "\n", cmd.value);
417			if (bkgrdsumadj == 0 || sysctl(adjnifree, MIBSIZE, 0, 0,
418			    &cmd, sizeof cmd) == -1)
419				rwerror("ADJUST NUMBER OF FREE INODES", cmd.value);
420		}
421
422		cmd.value = cstotal.cs_nffree - fs->fs_cstotal.cs_nffree;
423		if (cmd.value != 0) {
424			if (debug)
425				printf("adjnffree by %+" PRIi64 "\n", cmd.value);
426			if (bkgrdsumadj == 0 || sysctl(adjnffree, MIBSIZE, 0, 0,
427			    &cmd, sizeof cmd) == -1)
428				rwerror("ADJUST NUMBER OF FREE FRAGS", cmd.value);
429		}
430
431		cmd.value = cstotal.cs_numclusters - fs->fs_cstotal.cs_numclusters;
432		if (cmd.value != 0) {
433			if (debug)
434				printf("adjnumclusters by %+" PRIi64 "\n", cmd.value);
435			if (bkgrdsumadj == 0 || sysctl(adjnumclusters, MIBSIZE, 0, 0,
436			    &cmd, sizeof cmd) == -1)
437				rwerror("ADJUST NUMBER OF FREE CLUSTERS", cmd.value);
438		}
439	}
440}
441
442/*
443 * Compare the original cylinder group inode and block bitmaps with the
444 * updated cylinder group inode and block bitmaps. Free inodes and blocks
445 * that have been added. Complain if any previously freed inodes blocks
446 * are now allocated.
447 */
448void
449update_maps(
450	struct cg *oldcg,	/* cylinder group of claimed allocations */
451	struct cg *newcg,	/* cylinder group of determined allocations */
452	int usesysctl)		/* 1 => use sysctl interface to update maps */
453{
454	int inomapsize, excessdirs;
455	struct fs *fs = &sblock;
456
457	inomapsize = howmany(fs->fs_ipg, CHAR_BIT);
458	excessdirs = oldcg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir;
459	if (excessdirs < 0) {
460		pfatal("LOST %d DIRECTORIES\n", -excessdirs);
461		excessdirs = 0;
462	}
463	if (excessdirs > 0)
464		check_maps(cg_inosused(newcg), cg_inosused(oldcg), inomapsize,
465		    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_ipg, "DIR", freedirs,
466		    0, excessdirs, usesysctl);
467	check_maps(cg_inosused(newcg), cg_inosused(oldcg), inomapsize,
468	    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_ipg, "FILE", freefiles,
469	    excessdirs, fs->fs_ipg, usesysctl);
470	check_maps(cg_blksfree(oldcg), cg_blksfree(newcg),
471	    howmany(fs->fs_fpg, CHAR_BIT),
472	    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_fpg, "FRAG",
473	    freeblks, 0, fs->fs_fpg, usesysctl);
474}
475
476static void
477check_maps(
478	u_char *map1,	/* map of claimed allocations */
479	u_char *map2,	/* map of determined allocations */
480	int mapsize,	/* size of above two maps */
481	ufs2_daddr_t startvalue, /* resource value for first element in map */
482	const char *name,	/* name of resource found in maps */
483	int *opcode,	/* sysctl opcode to free resource */
484	int skip,	/* number of entries to skip before starting to free */
485	int limit,	/* limit on number of entries to free */
486	int usesysctl)	/* 1 => use sysctl interface to update maps */
487{
488#	define BUFSIZE 16
489	char buf[BUFSIZE];
490	long i, j, k, l, m, size;
491	ufs2_daddr_t n, astart, aend, ustart, uend;
492	void (*msg)(const char *fmt, ...);
493
494	if (usesysctl)
495		msg = pfatal;
496	else
497		msg = pwarn;
498	astart = ustart = aend = uend = -1;
499	for (i = 0; i < mapsize; i++) {
500		j = *map1++;
501		k = *map2++;
502		if (j == k)
503			continue;
504		for (m = 0, l = 1; m < CHAR_BIT; m++, l <<= 1) {
505			if ((j & l) == (k & l))
506				continue;
507			n = startvalue + i * CHAR_BIT + m;
508			if ((j & l) != 0) {
509				if (astart == -1) {
510					astart = aend = n;
511					continue;
512				}
513				if (aend + 1 == n) {
514					aend = n;
515					continue;
516				}
517				if (astart == aend)
518					(*msg)("ALLOCATED %s %" PRId64
519					    " MARKED FREE\n",
520					    name, astart);
521				else
522					(*msg)("%s %sS %" PRId64 "-%" PRId64
523					    " MARKED FREE\n",
524					    "ALLOCATED", name, astart, aend);
525				astart = aend = n;
526			} else {
527				if (ustart == -1) {
528					ustart = uend = n;
529					continue;
530				}
531				if (uend + 1 == n) {
532					uend = n;
533					continue;
534				}
535				size = uend - ustart + 1;
536				if (size <= skip) {
537					skip -= size;
538					ustart = uend = n;
539					continue;
540				}
541				if (skip > 0) {
542					ustart += skip;
543					size -= skip;
544					skip = 0;
545				}
546				if (size > limit)
547					size = limit;
548				if (debug && size == 1)
549					pwarn("%s %s %" PRId64
550					    " MARKED USED\n",
551					    "UNALLOCATED", name, ustart);
552				else if (debug)
553					pwarn("%s %sS %" PRId64 "-%" PRId64
554					    " MARKED USED\n",
555					    "UNALLOCATED", name, ustart,
556					    ustart + size - 1);
557				if (usesysctl != 0) {
558					cmd.value = ustart;
559					cmd.size = size;
560					if (sysctl(opcode, MIBSIZE, 0, 0,
561					    &cmd, sizeof cmd) == -1) {
562						snprintf(buf, BUFSIZE,
563						    "FREE %s", name);
564						rwerror(buf, cmd.value);
565					}
566				}
567				limit -= size;
568				if (limit <= 0)
569					return;
570				ustart = uend = n;
571			}
572		}
573	}
574	if (astart != -1) {
575		if (astart == aend)
576			(*msg)("ALLOCATED %s %" PRId64
577			    " MARKED FREE\n", name, astart);
578		else
579			(*msg)("ALLOCATED %sS %" PRId64 "-%" PRId64
580			    " MARKED FREE\n",
581			    name, astart, aend);
582	}
583	if (ustart != -1) {
584		size = uend - ustart + 1;
585		if (size <= skip)
586			return;
587		if (skip > 0) {
588			ustart += skip;
589			size -= skip;
590		}
591		if (size > limit)
592			size = limit;
593		if (debug) {
594			if (size == 1)
595				pwarn("UNALLOCATED %s %" PRId64
596				    " MARKED USED\n",
597				    name, ustart);
598			else
599				pwarn("UNALLOCATED %sS %" PRId64 "-%" PRId64
600				    " MARKED USED\n",
601				    name, ustart, ustart + size - 1);
602		}
603		if (usesysctl != 0) {
604			cmd.value = ustart;
605			cmd.size = size;
606			if (sysctl(opcode, MIBSIZE, 0, 0, &cmd,
607			    sizeof cmd) == -1) {
608				snprintf(buf, BUFSIZE, "FREE %s", name);
609				rwerror(buf, cmd.value);
610			}
611		}
612	}
613}
614
615static void
616clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end)
617{
618
619	if (debug)
620		printf("Zero frags %jd to %jd\n", start, end);
621	if (Zflag)
622		blzero(fswritefd, fsbtodb(&sblock, start),
623		    lfragtosize(&sblock, end - start + 1));
624	if (Eflag)
625		blerase(fswritefd, fsbtodb(&sblock, start),
626		    lfragtosize(&sblock, end - start + 1));
627}
628