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