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