xref: /freebsd/sbin/fsck_ffs/pass5.c (revision a3c15a4445062c80fef96dfeab1a10fb3f4f2194)
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 #define	IN_RTLD			/* So we pickup the P_OSREL defines */
39 #include <sys/param.h>
40 #include <sys/sysctl.h>
41 
42 #include <ufs/ufs/dinode.h>
43 #include <ufs/ffs/fs.h>
44 
45 #include <err.h>
46 #include <inttypes.h>
47 #include <limits.h>
48 #include <string.h>
49 #include <libufs.h>
50 
51 #include "fsck.h"
52 
53 static void check_maps(u_char *, u_char *, int, ufs2_daddr_t, const char *,
54 			int *, int, int, int);
55 static void clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end);
56 
57 void
58 pass5(void)
59 {
60 	int c, i, j, blk, frags, basesize, mapsize;
61 	int inomapsize, blkmapsize;
62 	struct fs *fs = &sblock;
63 	ufs2_daddr_t d, dbase, dmax, start;
64 	int rewritecg = 0;
65 	struct csum *cs;
66 	struct csum_total cstotal;
67 	struct inodesc idesc[3];
68 	char buf[MAXBSIZE];
69 	struct cg *cg, *newcg = (struct cg *)buf;
70 	struct bufarea *cgbp;
71 
72 	inoinfo(UFS_WINO)->ino_state = USTATE;
73 	memset(newcg, 0, (size_t)fs->fs_cgsize);
74 	newcg->cg_niblk = fs->fs_ipg;
75 	if (preen == 0 && yflag == 0 && fs->fs_magic == FS_UFS2_MAGIC &&
76 	    fswritefd != -1 && (fs->fs_metackhash & CK_CYLGRP) == 0 &&
77 	    getosreldate() >= P_OSREL_CK_CLYGRP &&
78 	    reply("ADD CYLINDER GROUP CHECKSUM PROTECTION") != 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 = cgget(c);
175 		cg = cgbp->b_un.b_cg;
176 		if (!cg_chkmagic(cg))
177 			pfatal("CG %d: BAD MAGIC NUMBER\n", c);
178 		newcg->cg_time = cg->cg_time;
179 		newcg->cg_old_time = cg->cg_old_time;
180 		newcg->cg_unrefs = cg->cg_unrefs;
181 		newcg->cg_cgx = c;
182 		dbase = cgbase(fs, c);
183 		dmax = dbase + fs->fs_fpg;
184 		if (dmax > fs->fs_size)
185 			dmax = fs->fs_size;
186 		newcg->cg_ndblk = dmax - dbase;
187 		if (fs->fs_magic == FS_UFS1_MAGIC) {
188 			if (c == fs->fs_ncg - 1)
189 				newcg->cg_old_ncyl = howmany(newcg->cg_ndblk,
190 				    fs->fs_fpg / fs->fs_old_cpg);
191 			else
192 				newcg->cg_old_ncyl = fs->fs_old_cpg;
193 			newcg->cg_old_niblk = fs->fs_ipg;
194 			newcg->cg_niblk = 0;
195 		}
196 		if (fs->fs_contigsumsize > 0)
197 			newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag;
198 		newcg->cg_cs.cs_ndir = 0;
199 		newcg->cg_cs.cs_nffree = 0;
200 		newcg->cg_cs.cs_nbfree = 0;
201 		newcg->cg_cs.cs_nifree = fs->fs_ipg;
202 		if (cg->cg_rotor >= 0 && cg->cg_rotor < newcg->cg_ndblk)
203 			newcg->cg_rotor = cg->cg_rotor;
204 		else
205 			newcg->cg_rotor = 0;
206 		if (cg->cg_frotor >= 0 && cg->cg_frotor < newcg->cg_ndblk)
207 			newcg->cg_frotor = cg->cg_frotor;
208 		else
209 			newcg->cg_frotor = 0;
210 		if (cg->cg_irotor >= 0 && cg->cg_irotor < fs->fs_ipg)
211 			newcg->cg_irotor = cg->cg_irotor;
212 		else
213 			newcg->cg_irotor = 0;
214 		if (fs->fs_magic == FS_UFS1_MAGIC) {
215 			newcg->cg_initediblk = 0;
216 		} else {
217 			if ((unsigned)cg->cg_initediblk > fs->fs_ipg)
218 				newcg->cg_initediblk = fs->fs_ipg;
219 			else
220 				newcg->cg_initediblk = cg->cg_initediblk;
221 		}
222 		memset(&newcg->cg_frsum[0], 0, sizeof newcg->cg_frsum);
223 		memset(cg_inosused(newcg), 0, (size_t)(mapsize));
224 		j = fs->fs_ipg * c;
225 		for (i = 0; i < inostathead[c].il_numalloced; j++, i++) {
226 			switch (inoinfo(j)->ino_state) {
227 
228 			case USTATE:
229 				break;
230 
231 			case DSTATE:
232 			case DCLEAR:
233 			case DFOUND:
234 			case DZLINK:
235 				newcg->cg_cs.cs_ndir++;
236 				/* FALLTHROUGH */
237 
238 			case FSTATE:
239 			case FCLEAR:
240 			case FZLINK:
241 				newcg->cg_cs.cs_nifree--;
242 				setbit(cg_inosused(newcg), i);
243 				break;
244 
245 			default:
246 				if (j < (int)UFS_ROOTINO)
247 					break;
248 				errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
249 				    inoinfo(j)->ino_state, j);
250 			}
251 		}
252 		if (c == 0)
253 			for (i = 0; i < (int)UFS_ROOTINO; i++) {
254 				setbit(cg_inosused(newcg), i);
255 				newcg->cg_cs.cs_nifree--;
256 			}
257 		start = -1;
258 		for (i = 0, d = dbase;
259 		     d < dmax;
260 		     d += fs->fs_frag, i += fs->fs_frag) {
261 			frags = 0;
262 			for (j = 0; j < fs->fs_frag; j++) {
263 				if (testbmap(d + j)) {
264 					if ((Eflag || Zflag) && start != -1) {
265 						clear_blocks(start, d + j - 1);
266 						start = -1;
267 					}
268 					continue;
269 				}
270 				if (start == -1)
271 					start = d + j;
272 				setbit(cg_blksfree(newcg), i + j);
273 				frags++;
274 			}
275 			if (frags == fs->fs_frag) {
276 				newcg->cg_cs.cs_nbfree++;
277 				if (fs->fs_contigsumsize > 0)
278 					setbit(cg_clustersfree(newcg),
279 					    i / fs->fs_frag);
280 			} else if (frags > 0) {
281 				newcg->cg_cs.cs_nffree += frags;
282 				blk = blkmap(fs, cg_blksfree(newcg), i);
283 				ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
284 			}
285 		}
286 		if ((Eflag || Zflag) && start != -1)
287 			clear_blocks(start, d - 1);
288 		if (fs->fs_contigsumsize > 0) {
289 			int32_t *sump = cg_clustersum(newcg);
290 			u_char *mapp = cg_clustersfree(newcg);
291 			int map = *mapp++;
292 			int bit = 1;
293 			int run = 0;
294 
295 			for (i = 0; i < newcg->cg_nclusterblks; i++) {
296 				if ((map & bit) != 0) {
297 					run++;
298 				} else if (run != 0) {
299 					if (run > fs->fs_contigsumsize)
300 						run = fs->fs_contigsumsize;
301 					sump[run]++;
302 					run = 0;
303 				}
304 				if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) {
305 					bit <<= 1;
306 				} else {
307 					map = *mapp++;
308 					bit = 1;
309 				}
310 			}
311 			if (run != 0) {
312 				if (run > fs->fs_contigsumsize)
313 					run = fs->fs_contigsumsize;
314 				sump[run]++;
315 			}
316 		}
317 		if ((fs->fs_metackhash & CK_CYLGRP) != 0) {
318 			newcg->cg_ckhash = 0;
319 			newcg->cg_ckhash =
320 			    calculate_crc32c(~0L, (void *)newcg, fs->fs_cgsize);
321 		}
322 
323 		if (bkgrdflag != 0) {
324 			cstotal.cs_nffree += cg->cg_cs.cs_nffree;
325 			cstotal.cs_nbfree += cg->cg_cs.cs_nbfree;
326 			cstotal.cs_nifree += cg->cg_cs.cs_nifree;
327 			cstotal.cs_ndir += cg->cg_cs.cs_ndir;
328 		} else {
329 			cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
330 			cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
331 			cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
332 			cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
333 		}
334 		cs = &fs->fs_cs(fs, c);
335 		if (cursnapshot == 0 &&
336 		    memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 &&
337 		    dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
338 			memmove(cs, &newcg->cg_cs, sizeof *cs);
339 			sbdirty();
340 		}
341 		if (rewritecg) {
342 			memmove(cg, newcg, (size_t)fs->fs_cgsize);
343 			dirty(cgbp);
344 			continue;
345 		}
346 		if (cursnapshot == 0 &&
347 		    memcmp(newcg, cg, basesize) != 0 &&
348 		    dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
349 			memmove(cg, newcg, (size_t)basesize);
350 			dirty(cgbp);
351 		}
352 		if (bkgrdflag != 0 || usedsoftdep || debug)
353 			update_maps(cg, newcg, bkgrdflag);
354 		if (cursnapshot == 0 &&
355 		    memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 &&
356 		    dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
357 			memmove(cg_inosused(cg), cg_inosused(newcg),
358 			      (size_t)mapsize);
359 			dirty(cgbp);
360 		}
361 	}
362 	if (cursnapshot == 0 &&
363 	    memcmp(&cstotal, &fs->fs_cstotal, sizeof cstotal) != 0
364 	    && dofix(&idesc[0], "SUMMARY BLK COUNT(S) WRONG IN SUPERBLK")) {
365 		memmove(&fs->fs_cstotal, &cstotal, sizeof cstotal);
366 		fs->fs_ronly = 0;
367 		fs->fs_fmod = 0;
368 		sbdirty();
369 	}
370 
371 	/*
372 	 * When doing background fsck on a snapshot, figure out whether
373 	 * the superblock summary is inaccurate and correct it when
374 	 * necessary.
375 	 */
376 	if (cursnapshot != 0) {
377 		cmd.size = 1;
378 
379 		cmd.value = cstotal.cs_ndir - fs->fs_cstotal.cs_ndir;
380 		if (cmd.value != 0) {
381 			if (debug)
382 				printf("adjndir by %+" PRIi64 "\n", cmd.value);
383 			if (bkgrdsumadj == 0 || sysctl(adjndir, MIBSIZE, 0, 0,
384 			    &cmd, sizeof cmd) == -1)
385 				rwerror("ADJUST NUMBER OF DIRECTORIES", cmd.value);
386 		}
387 
388 		cmd.value = cstotal.cs_nbfree - fs->fs_cstotal.cs_nbfree;
389 		if (cmd.value != 0) {
390 			if (debug)
391 				printf("adjnbfree by %+" PRIi64 "\n", cmd.value);
392 			if (bkgrdsumadj == 0 || sysctl(adjnbfree, MIBSIZE, 0, 0,
393 			    &cmd, sizeof cmd) == -1)
394 				rwerror("ADJUST NUMBER OF FREE BLOCKS", cmd.value);
395 		}
396 
397 		cmd.value = cstotal.cs_nifree - fs->fs_cstotal.cs_nifree;
398 		if (cmd.value != 0) {
399 			if (debug)
400 				printf("adjnifree by %+" PRIi64 "\n", cmd.value);
401 			if (bkgrdsumadj == 0 || sysctl(adjnifree, MIBSIZE, 0, 0,
402 			    &cmd, sizeof cmd) == -1)
403 				rwerror("ADJUST NUMBER OF FREE INODES", cmd.value);
404 		}
405 
406 		cmd.value = cstotal.cs_nffree - fs->fs_cstotal.cs_nffree;
407 		if (cmd.value != 0) {
408 			if (debug)
409 				printf("adjnffree by %+" PRIi64 "\n", cmd.value);
410 			if (bkgrdsumadj == 0 || sysctl(adjnffree, MIBSIZE, 0, 0,
411 			    &cmd, sizeof cmd) == -1)
412 				rwerror("ADJUST NUMBER OF FREE FRAGS", cmd.value);
413 		}
414 
415 		cmd.value = cstotal.cs_numclusters - fs->fs_cstotal.cs_numclusters;
416 		if (cmd.value != 0) {
417 			if (debug)
418 				printf("adjnumclusters by %+" PRIi64 "\n", cmd.value);
419 			if (bkgrdsumadj == 0 || sysctl(adjnumclusters, MIBSIZE, 0, 0,
420 			    &cmd, sizeof cmd) == -1)
421 				rwerror("ADJUST NUMBER OF FREE CLUSTERS", cmd.value);
422 		}
423 	}
424 }
425 
426 /*
427  * Compare the original cylinder group inode and block bitmaps with the
428  * updated cylinder group inode and block bitmaps. Free inodes and blocks
429  * that have been added. Complain if any previously freed inodes blocks
430  * are now allocated.
431  */
432 void
433 update_maps(
434 	struct cg *oldcg,	/* cylinder group of claimed allocations */
435 	struct cg *newcg,	/* cylinder group of determined allocations */
436 	int usesysctl)		/* 1 => use sysctl interface to update maps */
437 {
438 	int inomapsize, excessdirs;
439 	struct fs *fs = &sblock;
440 
441 	inomapsize = howmany(fs->fs_ipg, CHAR_BIT);
442 	excessdirs = oldcg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir;
443 	if (excessdirs < 0) {
444 		pfatal("LOST %d DIRECTORIES\n", -excessdirs);
445 		excessdirs = 0;
446 	}
447 	if (excessdirs > 0)
448 		check_maps(cg_inosused(newcg), cg_inosused(oldcg), inomapsize,
449 		    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_ipg, "DIR", freedirs,
450 		    0, excessdirs, usesysctl);
451 	check_maps(cg_inosused(newcg), cg_inosused(oldcg), inomapsize,
452 	    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_ipg, "FILE", freefiles,
453 	    excessdirs, fs->fs_ipg, usesysctl);
454 	check_maps(cg_blksfree(oldcg), cg_blksfree(newcg),
455 	    howmany(fs->fs_fpg, CHAR_BIT),
456 	    oldcg->cg_cgx * (ufs2_daddr_t)fs->fs_fpg, "FRAG",
457 	    freeblks, 0, fs->fs_fpg, usesysctl);
458 }
459 
460 static void
461 check_maps(
462 	u_char *map1,	/* map of claimed allocations */
463 	u_char *map2,	/* map of determined allocations */
464 	int mapsize,	/* size of above two maps */
465 	ufs2_daddr_t startvalue, /* resource value for first element in map */
466 	const char *name,	/* name of resource found in maps */
467 	int *opcode,	/* sysctl opcode to free resource */
468 	int skip,	/* number of entries to skip before starting to free */
469 	int limit,	/* limit on number of entries to free */
470 	int usesysctl)	/* 1 => use sysctl interface to update maps */
471 {
472 #	define BUFSIZE 16
473 	char buf[BUFSIZE];
474 	long i, j, k, l, m, size;
475 	ufs2_daddr_t n, astart, aend, ustart, uend;
476 	void (*msg)(const char *fmt, ...);
477 
478 	if (usesysctl)
479 		msg = pfatal;
480 	else
481 		msg = pwarn;
482 	astart = ustart = aend = uend = -1;
483 	for (i = 0; i < mapsize; i++) {
484 		j = *map1++;
485 		k = *map2++;
486 		if (j == k)
487 			continue;
488 		for (m = 0, l = 1; m < CHAR_BIT; m++, l <<= 1) {
489 			if ((j & l) == (k & l))
490 				continue;
491 			n = startvalue + i * CHAR_BIT + m;
492 			if ((j & l) != 0) {
493 				if (astart == -1) {
494 					astart = aend = n;
495 					continue;
496 				}
497 				if (aend + 1 == n) {
498 					aend = n;
499 					continue;
500 				}
501 				if (astart == aend)
502 					(*msg)("ALLOCATED %s %" PRId64
503 					    " MARKED FREE\n",
504 					    name, astart);
505 				else
506 					(*msg)("%s %sS %" PRId64 "-%" PRId64
507 					    " MARKED FREE\n",
508 					    "ALLOCATED", name, astart, aend);
509 				astart = aend = n;
510 			} else {
511 				if (ustart == -1) {
512 					ustart = uend = n;
513 					continue;
514 				}
515 				if (uend + 1 == n) {
516 					uend = n;
517 					continue;
518 				}
519 				size = uend - ustart + 1;
520 				if (size <= skip) {
521 					skip -= size;
522 					ustart = uend = n;
523 					continue;
524 				}
525 				if (skip > 0) {
526 					ustart += skip;
527 					size -= skip;
528 					skip = 0;
529 				}
530 				if (size > limit)
531 					size = limit;
532 				if (debug && size == 1)
533 					pwarn("%s %s %" PRId64
534 					    " MARKED USED\n",
535 					    "UNALLOCATED", name, ustart);
536 				else if (debug)
537 					pwarn("%s %sS %" PRId64 "-%" PRId64
538 					    " MARKED USED\n",
539 					    "UNALLOCATED", name, ustart,
540 					    ustart + size - 1);
541 				if (usesysctl != 0) {
542 					cmd.value = ustart;
543 					cmd.size = size;
544 					if (sysctl(opcode, MIBSIZE, 0, 0,
545 					    &cmd, sizeof cmd) == -1) {
546 						snprintf(buf, BUFSIZE,
547 						    "FREE %s", name);
548 						rwerror(buf, cmd.value);
549 					}
550 				}
551 				limit -= size;
552 				if (limit <= 0)
553 					return;
554 				ustart = uend = n;
555 			}
556 		}
557 	}
558 	if (astart != -1) {
559 		if (astart == aend)
560 			(*msg)("ALLOCATED %s %" PRId64
561 			    " MARKED FREE\n", name, astart);
562 		else
563 			(*msg)("ALLOCATED %sS %" PRId64 "-%" PRId64
564 			    " MARKED FREE\n",
565 			    name, astart, aend);
566 	}
567 	if (ustart != -1) {
568 		size = uend - ustart + 1;
569 		if (size <= skip)
570 			return;
571 		if (skip > 0) {
572 			ustart += skip;
573 			size -= skip;
574 		}
575 		if (size > limit)
576 			size = limit;
577 		if (debug) {
578 			if (size == 1)
579 				pwarn("UNALLOCATED %s %" PRId64
580 				    " MARKED USED\n",
581 				    name, ustart);
582 			else
583 				pwarn("UNALLOCATED %sS %" PRId64 "-%" PRId64
584 				    " MARKED USED\n",
585 				    name, ustart, ustart + size - 1);
586 		}
587 		if (usesysctl != 0) {
588 			cmd.value = ustart;
589 			cmd.size = size;
590 			if (sysctl(opcode, MIBSIZE, 0, 0, &cmd,
591 			    sizeof cmd) == -1) {
592 				snprintf(buf, BUFSIZE, "FREE %s", name);
593 				rwerror(buf, cmd.value);
594 			}
595 		}
596 	}
597 }
598 
599 static void
600 clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end)
601 {
602 
603 	if (debug)
604 		printf("Zero frags %jd to %jd\n", start, end);
605 	if (Zflag)
606 		blzero(fswritefd, fsbtodb(&sblock, start),
607 		    lfragtosize(&sblock, end - start + 1));
608 	if (Eflag)
609 		blerase(fswritefd, fsbtodb(&sblock, start),
610 		    lfragtosize(&sblock, end - start + 1));
611 }
612