1/* $NetBSD: pass6.c,v 1.23 2010/02/16 23:20:30 mlelstv Exp $	 */
2
3/*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Konrad E. Schroder <perseant@hhhh.org>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/param.h>
34#include <sys/time.h>
35#include <sys/buf.h>
36#include <sys/mount.h>
37
38#include <ufs/ufs/ufsmount.h>
39#include <ufs/ufs/inode.h>
40#include <ufs/ufs/dir.h>
41#define vnode uvnode
42#include <ufs/lfs/lfs.h>
43#undef vnode
44
45#include <assert.h>
46#include <err.h>
47#include <signal.h>
48#include <string.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <util.h>
52
53#include "bufcache.h"
54#include "vnode.h"
55#include "lfs_user.h"
56#include "segwrite.h"
57
58#include "fsck.h"
59#include "extern.h"
60#include "fsutil.h"
61
62extern u_int32_t cksum(void *, size_t);
63extern u_int32_t lfs_sb_cksum(struct dlfs *);
64
65extern ufs_daddr_t badblk;
66extern SEGUSE *seg_table;
67
68static int nnewblocks;
69
70/*
71 * Our own copy of lfs_update_single so we can account in seg_table
72 * as well as the Ifile; and so we can add the blocks to their new
73 * segment.
74 *
75 * Change the given block's address to ndaddr, finding its previous
76 * location using ufs_bmaparray().
77 *
78 * Account for this change in the segment table.
79 */
80static void
81rfw_update_single(struct uvnode *vp, daddr_t lbn, ufs_daddr_t ndaddr, int size)
82{
83	SEGUSE *sup;
84	struct ubuf *bp;
85	struct indir a[NIADDR + 2], *ap;
86	struct inode *ip;
87	daddr_t daddr, ooff;
88	int num, error;
89	int i, osize = 0;
90	int frags, ofrags = 0;
91	u_int32_t oldsn, sn;
92
93	ip = VTOI(vp);
94	ip->i_flag |= IN_MODIFIED;
95
96	error = ufs_bmaparray(fs, vp, lbn, &daddr, a, &num);
97	if (error)
98		errx(1, "lfs_updatemeta: ufs_bmaparray returned %d"
99		     " looking up lbn %" PRId64 "\n", error, lbn);
100	if (daddr > 0)
101		daddr = dbtofsb(fs, daddr);
102
103	frags = numfrags(fs, size);
104	switch (num) {
105	case 0:
106		ooff = ip->i_ffs1_db[lbn];
107		if (ooff <= 0)
108			ip->i_ffs1_blocks += frags;
109		else {
110			/* possible fragment truncation or extension */
111			ofrags = numfrags(fs, ip->i_lfs_fragsize[lbn]);
112			ip->i_ffs1_blocks += (frags - ofrags);
113		}
114		ip->i_ffs1_db[lbn] = ndaddr;
115		break;
116	case 1:
117		ooff = ip->i_ffs1_ib[a[0].in_off];
118		if (ooff <= 0)
119			ip->i_ffs1_blocks += frags;
120		ip->i_ffs1_ib[a[0].in_off] = ndaddr;
121		break;
122	default:
123		ap = &a[num - 1];
124		if (bread(vp, ap->in_lbn, fs->lfs_bsize, NULL, 0, &bp))
125			errx(1, "lfs_updatemeta: bread bno %" PRId64,
126			    ap->in_lbn);
127
128		ooff = ((ufs_daddr_t *) bp->b_data)[ap->in_off];
129		if (ooff <= 0)
130			ip->i_ffs1_blocks += frags;
131		((ufs_daddr_t *) bp->b_data)[ap->in_off] = ndaddr;
132		(void) VOP_BWRITE(bp);
133	}
134
135	/*
136	 * Update segment usage information, based on old size
137	 * and location.
138	 */
139	if (daddr > 0) {
140		oldsn = dtosn(fs, daddr);
141		if (lbn >= 0 && lbn < NDADDR)
142			osize = ip->i_lfs_fragsize[lbn];
143		else
144			osize = fs->lfs_bsize;
145		LFS_SEGENTRY(sup, fs, oldsn, bp);
146		seg_table[oldsn].su_nbytes -= osize;
147		sup->su_nbytes -= osize;
148		if (!(bp->b_flags & B_GATHERED))
149			fs->lfs_flags |= LFS_IFDIRTY;
150		LFS_WRITESEGENTRY(sup, fs, oldsn, bp);
151		for (i = 0; i < btofsb(fs, osize); i++)
152			clrbmap(daddr + i);
153	}
154
155	/* If block is beyond EOF, update size */
156	if (lbn >= 0 && ip->i_ffs1_size <= (lbn << fs->lfs_bshift)) {
157		ip->i_ffs1_size = (lbn << fs->lfs_bshift) + 1;
158	}
159
160	/* If block frag size is too large for old EOF, update size */
161	if (lbn < NDADDR) {
162		off_t minsize;
163
164		minsize = (lbn << fs->lfs_bshift);
165		minsize += (size - fs->lfs_fsize) + 1;
166		if (ip->i_ffs1_size < minsize)
167			ip->i_ffs1_size = minsize;
168	}
169
170	/* Count for the user */
171	++nnewblocks;
172
173	/* Add block to its new segment */
174	sn = dtosn(fs, ndaddr);
175	LFS_SEGENTRY(sup, fs, sn, bp);
176	seg_table[sn].su_nbytes += size;
177	sup->su_nbytes += size;
178	if (!(bp->b_flags & B_GATHERED))
179		fs->lfs_flags |= LFS_IFDIRTY;
180	LFS_WRITESEGENTRY(sup, fs, sn, bp);
181	for (i = 0; i < btofsb(fs, size); i++)
182#ifndef VERBOSE_BLOCKMAP
183		setbmap(daddr + i);
184#else
185		setbmap(daddr + i, ip->i_number);
186#endif
187
188	/* Check bfree accounting as well */
189	if (daddr <= 0) {
190		fs->lfs_bfree -= btofsb(fs, size);
191	} else if (size != osize) {
192		fs->lfs_bfree -= (frags - ofrags);
193	}
194
195	/*
196	 * Now that this block has a new address, and its old
197	 * segment no longer owns it, we can forget about its
198	 * old size.
199	 */
200	if (lbn >= 0 && lbn < NDADDR)
201		ip->i_lfs_fragsize[lbn] = size;
202}
203
204/*
205 * Remove the vnode from the cache, including any blocks it
206 * may hold.  Account the blocks.  Finally account the removal
207 * of the inode from its segment.
208 */
209static void
210remove_ino(struct uvnode *vp, ino_t ino)
211{
212	IFILE *ifp;
213	SEGUSE *sup;
214	CLEANERINFO *cip;
215	struct ubuf *bp, *sbp, *cbp;
216	struct inodesc idesc;
217	ufs_daddr_t daddr;
218	int obfree;
219
220	if (debug)
221		pwarn("remove ino %d\n", (int)ino);
222
223	obfree = fs->lfs_bfree;
224	LFS_IENTRY(ifp, fs, ino, bp);
225	daddr = ifp->if_daddr;
226	if (daddr > 0) {
227		ifp->if_daddr = 0x0;
228
229		LFS_GET_HEADFREE(fs, cip, cbp, &(ifp->if_nextfree));
230		VOP_BWRITE(bp);
231		LFS_PUT_HEADFREE(fs, cip, cbp, ino);
232		sbdirty();
233
234		if (vp == NULL)
235			vp = lfs_raw_vget(fs, ino, fs->lfs_ivnode->v_fd, daddr);
236
237		LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
238		sup->su_nbytes -= DINODE1_SIZE;
239		VOP_BWRITE(sbp);
240		seg_table[dtosn(fs, daddr)].su_nbytes -= DINODE1_SIZE;
241	} else
242		brelse(bp, 0);
243
244	/* Do on-disk accounting */
245	if (vp) {
246		idesc.id_number = ino;
247		idesc.id_func = pass4check; /* Delete dinode and blocks */
248		idesc.id_type = ADDR;
249		idesc.id_lblkno = 0;
250		clri(&idesc, "unknown", 2); /* XXX magic number 2 */
251		/* vp has been destroyed */
252	}
253}
254
255/*
256 * Use FIP records to update blocks, if the generation number matches.
257 */
258static void
259pass6harvest(ufs_daddr_t daddr, FINFO *fip)
260{
261	struct uvnode *vp;
262	int i;
263	size_t size;
264
265	vp = vget(fs, fip->fi_ino);
266	if (vp && vp != fs->lfs_ivnode &&
267	    VTOI(vp)->i_ffs1_gen == fip->fi_version) {
268		for (i = 0; i < fip->fi_nblocks; i++) {
269			size = (i == fip->fi_nblocks - 1 ?
270				fip->fi_lastlength : fs->lfs_bsize);
271			if (debug)
272				pwarn("ino %lld lbn %lld -> 0x%lx\n",
273					(long long)fip->fi_ino,
274					(long long)fip->fi_blocks[i],
275					(long)daddr);
276			rfw_update_single(vp, fip->fi_blocks[i], daddr, size);
277			daddr += btofsb(fs, size);
278		}
279	}
280}
281
282/*
283 * Check validity of blocks on roll-forward inodes.
284 */
285int
286pass6check(struct inodesc * idesc)
287{
288	int i, sn, anyout, anynew;
289
290	/* Brand new blocks are always OK */
291	if (idesc->id_blkno == UNWRITTEN)
292		return KEEPON;
293
294	/* Check that the blocks do not lie within clean segments. */
295	anyout = anynew = 0;
296	for (i = 0; i < idesc->id_numfrags; i++) {
297		sn = dtosn(fs, idesc->id_blkno + i);
298		if (sn < 0 || sn >= fs->lfs_nseg ||
299		    (seg_table[sn].su_flags & SEGUSE_DIRTY) == 0) {
300			anyout = 1;
301			break;
302		}
303		if (seg_table[sn].su_flags & SEGUSE_ACTIVE) {
304			if (sn != dtosn(fs, fs->lfs_offset) ||
305			    idesc->id_blkno > fs->lfs_offset) {
306				++anynew;
307			}
308		}
309		if (!anynew) {
310			/* Clear so pass1check won't be surprised */
311			clrbmap(idesc->id_blkno + i);
312			seg_table[sn].su_nbytes -= fsbtob(fs, 1);
313		}
314	}
315	if (anyout) {
316		blkerror(idesc->id_number, "BAD", idesc->id_blkno);
317		if (badblk++ >= MAXBAD) {
318			pwarn("EXCESSIVE BAD BLKS I=%llu",
319			    (unsigned long long)idesc->id_number);
320			if (preen)
321				pwarn(" (SKIPPING)\n");
322			else if (reply("CONTINUE") == 0)
323				err(EEXIT, "%s", "");
324			return (STOP);
325		}
326	}
327
328	return pass1check(idesc);
329}
330
331static void
332account_indir(struct uvnode *vp, struct ufs1_dinode *dp, daddr_t ilbn, daddr_t daddr, int lvl)
333{
334	struct ubuf *bp;
335	int32_t *dap, *odap, *buf, *obuf;
336	daddr_t lbn;
337
338	if (lvl == 0)
339		lbn = -ilbn;
340	else
341		lbn = ilbn + 1;
342	bread(fs->lfs_devvp, fsbtodb(fs, daddr), fs->lfs_bsize, NULL, 0, &bp);
343	buf = emalloc(fs->lfs_bsize);
344	memcpy(buf, bp->b_data, fs->lfs_bsize);
345	brelse(bp, 0);
346
347	obuf = emalloc(fs->lfs_bsize);
348	if (vp) {
349		bread(vp, ilbn, fs->lfs_bsize, NULL, 0, &bp);
350		memcpy(obuf, bp->b_data, fs->lfs_bsize);
351		brelse(bp, 0);
352	} else
353		memset(obuf, 0, fs->lfs_bsize);
354
355	for (dap = buf, odap = obuf;
356	     dap < (int32_t *)((char *)buf + fs->lfs_bsize);
357	     ++dap, ++odap) {
358		if (*dap > 0 && *dap != *odap) {
359			rfw_update_single(vp, lbn, *dap, dblksize(fs, dp, lbn));
360			if (lvl > 0)
361				account_indir(vp, dp, lbn, *dap, lvl - 1);
362		}
363		if (lvl == 0)
364			++lbn;
365		else if (lvl == 1)
366			lbn -= NINDIR(fs);
367		else if (lvl == 2)
368			lbn -= NINDIR(fs) * NINDIR(fs);
369	}
370
371	free(obuf);
372	free(buf);
373}
374
375/*
376 * Account block changes between new found inode and existing inode.
377 */
378static void
379account_block_changes(struct ufs1_dinode *dp)
380{
381	int i;
382	daddr_t lbn, off, odaddr;
383	struct uvnode *vp;
384	struct inode *ip;
385
386	vp = vget(fs, dp->di_inumber);
387	ip = (vp ? VTOI(vp) : NULL);
388
389	/* Check direct block holdings between existing and new */
390	for (i = 0; i < NDADDR; i++) {
391		odaddr = (ip ? ip->i_ffs1_db[i] : 0x0);
392		if (dp->di_db[i] > 0 && dp->di_db[i] != odaddr)
393			rfw_update_single(vp, i, dp->di_db[i],
394					  dblksize(fs, dp, i));
395	}
396
397	/* Check indirect block holdings between existing and new */
398	off = 0;
399	for (i = 0; i < NIADDR; i++) {
400		odaddr = (ip ? ip->i_ffs1_ib[i] : 0x0);
401		if (dp->di_ib[i] > 0 && dp->di_ib[i] != odaddr) {
402			lbn = -(NDADDR + off + i);
403			rfw_update_single(vp, i, dp->di_ib[i], fs->lfs_bsize);
404			account_indir(vp, dp, lbn, dp->di_ib[i], i);
405		}
406		if (off == 0)
407			off = NINDIR(fs);
408		else
409			off *= NINDIR(fs);
410	}
411}
412
413/*
414 * Give a previously allocated inode a new address; do segment
415 * accounting if necessary.
416 *
417 * Caller has ensured that this inode is not on the free list, so no
418 * free list accounting is done.
419 */
420static void
421readdress_inode(struct ufs1_dinode *dp, ufs_daddr_t daddr)
422{
423	IFILE *ifp;
424	SEGUSE *sup;
425	struct ubuf *bp;
426	int sn;
427	ufs_daddr_t odaddr;
428	ino_t thisino = dp->di_inumber;
429	struct uvnode *vp;
430
431	/* Recursively check all block holdings, account changes */
432	account_block_changes(dp);
433
434	/* Move ifile pointer to this location */
435	LFS_IENTRY(ifp, fs, thisino, bp);
436	odaddr = ifp->if_daddr;
437	assert(odaddr != 0);
438	ifp->if_daddr = daddr;
439	VOP_BWRITE(bp);
440
441	if (debug)
442		pwarn("readdress ino %d from 0x%x to 0x%x mode %o nlink %d\n",
443			(int)dp->di_inumber,
444			(unsigned)odaddr,
445			(unsigned)daddr,
446			(int)dp->di_mode, (int)dp->di_nlink);
447
448	/* Copy over preexisting in-core inode, if any */
449	vp = vget(fs, thisino);
450	memcpy(VTOI(vp)->i_din.ffs1_din, dp, sizeof(*dp));
451
452	/* Finally account the inode itself */
453	sn = dtosn(fs, odaddr);
454	LFS_SEGENTRY(sup, fs, sn, bp);
455	sup->su_nbytes -= DINODE1_SIZE;
456	VOP_BWRITE(bp);
457	seg_table[sn].su_nbytes -= DINODE1_SIZE;
458
459	sn = dtosn(fs, daddr);
460	LFS_SEGENTRY(sup, fs, sn, bp);
461	sup->su_nbytes += DINODE1_SIZE;
462	VOP_BWRITE(bp);
463	seg_table[sn].su_nbytes += DINODE1_SIZE;
464}
465
466/*
467 * Allocate the given inode from the free list.
468 */
469static void
470alloc_inode(ino_t thisino, ufs_daddr_t daddr)
471{
472	ino_t ino, nextfree, oldhead;
473	IFILE *ifp;
474	SEGUSE *sup;
475	struct ubuf *bp, *cbp;
476	CLEANERINFO *cip;
477
478	if (debug)
479		pwarn("allocating ino %d at 0x%x\n", (int)thisino,
480			(unsigned)daddr);
481	while (thisino >= maxino) {
482		extend_ifile(fs);
483	}
484
485	LFS_IENTRY(ifp, fs, thisino, bp);
486	if (ifp->if_daddr != 0) {
487		pwarn("allocated inode %lld already allocated\n",
488			(long long)thisino);
489	}
490	nextfree = ifp->if_nextfree;
491	ifp->if_nextfree = 0;
492	ifp->if_daddr = daddr;
493	VOP_BWRITE(bp);
494
495	LFS_GET_HEADFREE(fs, cip, cbp, &oldhead);
496	if (oldhead == thisino) {
497		LFS_PUT_HEADFREE(fs, cip, cbp, nextfree);
498		sbdirty();
499		if (nextfree == 0) {
500			extend_ifile(fs);
501		}
502	} else {
503		/* Search the free list for this inode */
504		ino = oldhead;
505		while (ino) {
506			LFS_IENTRY(ifp, fs, ino, bp);
507			assert(ifp->if_nextfree != ino);
508			if (ifp->if_nextfree == thisino) {
509				ifp->if_nextfree = nextfree;
510				VOP_BWRITE(bp);
511				if (nextfree == 0)
512					LFS_PUT_TAILFREE(fs, cip, cbp, ino);
513				break;
514			} else
515				ino = ifp->if_nextfree;
516			brelse(bp, 0);
517		}
518	}
519
520	/* Account for new location */
521	LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), bp);
522	sup->su_nbytes += DINODE1_SIZE;
523	VOP_BWRITE(bp);
524	seg_table[dtosn(fs, daddr)].su_nbytes += DINODE1_SIZE;
525}
526
527/*
528 * Roll forward from the last verified checkpoint.
529 *
530 * Basic strategy:
531 *
532 * Run through the summaries finding the last valid partial segment.
533 * Note segment numbers as we go.  For each inode that we find, compare
534 * its generation number; if newer than old inode's (or if old inode is
535 * USTATE), change to that inode.  Recursively look at inode blocks that
536 * do not have their old disk addresses.  These addresses must lie in
537 * segments we have seen already in our roll forward.
538 *
539 * A second pass through the past-checkpoint area verifies the validity
540 * of these new blocks, as well as updating other blocks that do not
541 * have corresponding new inodes (but their generation number must match
542 * the old generation number).
543 */
544void
545pass6(void)
546{
547	ufs_daddr_t daddr, ibdaddr, odaddr, lastgood, nextseg, *idaddrp;
548	struct uvnode *vp, *devvp;
549	CLEANERINFO *cip;
550	SEGUSE *sup;
551	SEGSUM *sp;
552	struct ubuf *bp, *ibp, *sbp, *cbp;
553	struct ufs1_dinode *dp;
554	struct inodesc idesc;
555	int i, j, bc, hassuper;
556	int nnewfiles, ndelfiles, nmvfiles;
557	int sn, curseg;
558	char *ibbuf;
559	long lastserial;
560
561	devvp = fs->lfs_devvp;
562
563	/* If we can't roll forward because of created files, don't try */
564	if (no_roll_forward) {
565		if (debug)
566			pwarn("not rolling forward due to possible allocation conflict\n");
567		return;
568	}
569
570	/* Find last valid partial segment */
571	lastgood = try_verify(fs, devvp, 0, debug);
572	if (lastgood == fs->lfs_offset) {
573		if (debug)
574			pwarn("not rolling forward, nothing to recover\n");
575		return;
576	}
577
578	if (debug)
579		pwarn("could roll forward from 0x%" PRIx32 " to 0x%" PRIx32 "\n",
580			fs->lfs_offset, lastgood);
581
582	if (!preen && reply("ROLL FORWARD") == 0)
583		return;
584	/*
585	 * Pass 1: find inode blocks.  We ignore the Ifile inode but accept
586	 * changes to any other inode.
587	 */
588
589	ibbuf = emalloc(fs->lfs_ibsize);
590	nnewfiles = ndelfiles = nmvfiles = nnewblocks = 0;
591	daddr = fs->lfs_offset;
592	nextseg = fs->lfs_nextseg;
593	hassuper = 0;
594	lastserial = 0;
595	while (daddr != lastgood) {
596		seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE;
597		LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
598		sup->su_flags |= SEGUSE_DIRTY;
599		VOP_BWRITE(sbp);
600
601		/* Could be a superblock */
602		if (sntod(fs, dtosn(fs, daddr)) == daddr) {
603			if (daddr == fs->lfs_start) {
604				++hassuper;
605				daddr += btofsb(fs, LFS_LABELPAD);
606			}
607			for (i = 0; i < LFS_MAXNUMSB; i++) {
608				if (daddr == fs->lfs_sboffs[i]) {
609					++hassuper;
610					daddr += btofsb(fs, LFS_SBPAD);
611				}
612				if (daddr < fs->lfs_sboffs[i])
613					break;
614			}
615		}
616
617		/* Read in summary block */
618		bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, 0, &bp);
619		sp = (SEGSUM *)bp->b_data;
620		if (debug)
621			pwarn("sum at 0x%x: ninos=%d nfinfo=%d\n",
622				(unsigned)daddr, (int)sp->ss_ninos,
623				(int)sp->ss_nfinfo);
624
625		/* We have verified that this is a good summary. */
626		LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
627		++sup->su_nsums;
628		VOP_BWRITE(sbp);
629		fs->lfs_bfree -= btofsb(fs, fs->lfs_sumsize);
630		fs->lfs_dmeta += btofsb(fs, fs->lfs_sumsize);
631		sbdirty();
632		nextseg = sp->ss_next;
633		if (sntod(fs, dtosn(fs, daddr)) == daddr +
634		    hassuper * btofsb(fs, LFS_SBPAD) &&
635		    dtosn(fs, daddr) != dtosn(fs, fs->lfs_offset)) {
636			--fs->lfs_nclean;
637			sbdirty();
638		}
639
640		/* Find inodes, look at generation number. */
641		if (sp->ss_ninos) {
642			LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
643			sup->su_ninos += howmany(sp->ss_ninos, INOPB(fs));
644			VOP_BWRITE(sbp);
645			fs->lfs_dmeta += btofsb(fs, howmany(sp->ss_ninos,
646							    INOPB(fs)) *
647						fs->lfs_ibsize);
648		}
649		idaddrp = ((ufs_daddr_t *)((char *)bp->b_data + fs->lfs_sumsize));
650		for (i = 0; i < howmany(sp->ss_ninos, INOPB(fs)); i++) {
651			ino_t *inums;
652
653			inums = ecalloc(INOPB(fs) + 1, sizeof(*inums));
654			ibdaddr = *--idaddrp;
655			fs->lfs_bfree -= btofsb(fs, fs->lfs_ibsize);
656			sbdirty();
657			bread(devvp, fsbtodb(fs, ibdaddr), fs->lfs_ibsize,
658			      NOCRED, 0, &ibp);
659			memcpy(ibbuf, ibp->b_data, fs->lfs_ibsize);
660			brelse(ibp, 0);
661
662			j = 0;
663			for (dp = (struct ufs1_dinode *)ibbuf;
664			     dp < (struct ufs1_dinode *)ibbuf + INOPB(fs);
665			     ++dp) {
666				if (dp->di_u.inumber == 0 ||
667				    dp->di_u.inumber == fs->lfs_ifile)
668					continue;
669				/* Basic sanity checks */
670				if (dp->di_nlink < 0
671#if 0
672				    || dp->di_u.inumber < 0
673				    || dp->di_size < 0
674#endif
675				) {
676					pwarn("BAD INODE AT 0x%" PRIx32 "\n",
677						ibdaddr);
678					brelse(bp, 0);
679					free(inums);
680					goto out;
681				}
682
683				vp = vget(fs, dp->di_u.inumber);
684
685				/*
686				 * Four cases:
687				 * (1) Invalid inode (nlink == 0).
688				 *     If currently allocated, remove.
689				 */
690				if (dp->di_nlink == 0) {
691					remove_ino(vp, dp->di_u.inumber);
692					++ndelfiles;
693					continue;
694				}
695				/*
696				 * (2) New valid inode, previously free.
697				 *     Nothing to do except account
698				 *     the inode itself, done after the
699				 *     loop.
700				 */
701				if (vp == NULL) {
702					if (!(sp->ss_flags & SS_DIROP))
703						pfatal("NEW FILE IN NON-DIROP PARTIAL SEGMENT");
704					else {
705						inums[j++] = dp->di_u.inumber;
706						nnewfiles++;
707					}
708					continue;
709				}
710				/*
711				 * (3) Valid new version of previously
712				 *     allocated inode.  Delete old file
713				 *     and proceed as in (2).
714				 */
715				if (vp && VTOI(vp)->i_ffs1_gen < dp->di_gen) {
716					remove_ino(vp, dp->di_u.inumber);
717					if (!(sp->ss_flags & SS_DIROP))
718						pfatal("NEW FILE VERSION IN NON-DIROP PARTIAL SEGMENT");
719					else {
720						inums[j++] = dp->di_u.inumber;
721						ndelfiles++;
722						nnewfiles++;
723					}
724					continue;
725				}
726				/*
727				 * (4) Same version of previously
728				 *     allocated inode.  Move inode to
729				 *     this location, account inode change
730				 *     only.  We'll pick up any new
731				 *     blocks when we do the block pass.
732				 */
733				if (vp && VTOI(vp)->i_ffs1_gen == dp->di_gen) {
734					nmvfiles++;
735					readdress_inode(dp, ibdaddr);
736
737					/* Update with new info */
738					VTOD(vp)->di_mode = dp->di_mode;
739					VTOD(vp)->di_nlink = dp->di_nlink;
740					/* XXX size is important */
741					VTOD(vp)->di_size = dp->di_size;
742					VTOD(vp)->di_atime = dp->di_atime;
743					VTOD(vp)->di_atimensec = dp->di_atimensec;
744					VTOD(vp)->di_mtime = dp->di_mtime;
745					VTOD(vp)->di_mtimensec = dp->di_mtimensec;
746					VTOD(vp)->di_ctime = dp->di_ctime;
747					VTOD(vp)->di_ctimensec = dp->di_ctimensec;
748					VTOD(vp)->di_flags = dp->di_flags;
749					VTOD(vp)->di_uid = dp->di_uid;
750					VTOD(vp)->di_gid = dp->di_gid;
751					inodirty(VTOI(vp));
752				}
753			}
754			for (j = 0; inums[j]; j++) {
755				alloc_inode(inums[j], ibdaddr);
756				vp = lfs_raw_vget(fs, inums[j],
757					      devvp->v_fd, ibdaddr);
758				/* We'll get the blocks later */
759				if (debug)
760					pwarn("alloc ino %d nlink %d\n",
761						(int)inums[j], VTOD(vp)->di_nlink);
762				memset(VTOD(vp)->di_db, 0, (NDADDR + NIADDR) *
763				       sizeof(ufs_daddr_t));
764				VTOD(vp)->di_blocks = 0;
765
766				vp->v_uflag |= VU_DIROP;
767				inodirty(VTOI(vp));
768			}
769			free(inums);
770		}
771
772		bc = check_summary(fs, sp, daddr, debug, devvp, NULL);
773		if (bc == 0) {
774			pwarn("unexpected bad seg ptr at 0x%x with serial=%d\n",
775				(int)daddr, (int)sp->ss_serial);
776			brelse(bp, 0);
777			break;
778		} else {
779			if (debug)
780				pwarn("good seg ptr at 0x%x with serial=%d\n",
781					(int)daddr, (int)sp->ss_serial);
782			lastserial = sp->ss_serial;
783		}
784		odaddr = daddr;
785		daddr += btofsb(fs, fs->lfs_sumsize + bc);
786		if (dtosn(fs, odaddr) != dtosn(fs, daddr) ||
787		    dtosn(fs, daddr) != dtosn(fs, daddr +
788			btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize) - 1)) {
789			daddr = ((SEGSUM *)bp->b_data)->ss_next;
790		}
791		brelse(bp, 0);
792	}
793
794    out:
795	free(ibbuf);
796
797	/* Set serial here, just to be sure (XXX should be right already) */
798	fs->lfs_serial = lastserial + 1;
799
800	/*
801	 * Check our new vnodes.  Any blocks must lie in segments that
802	 * we've seen before (SEGUSE_DIRTY or SEGUSE_RFW); and the rest
803	 * of the pass 1 checks as well.
804	 */
805	memset(&idesc, 0, sizeof(struct inodesc));
806	idesc.id_type = ADDR;
807	idesc.id_func = pass6check;
808	idesc.id_lblkno = 0;
809	LIST_FOREACH(vp, &vnodelist, v_mntvnodes) {
810		if ((vp->v_uflag & VU_DIROP) == 0)
811			--n_files; /* Don't double count */
812		checkinode(VTOI(vp)->i_number, &idesc);
813	}
814
815	/*
816	 * Second pass.  Run through FINFO entries looking for blocks
817	 * with the same generation number as files we've seen before.
818	 * If they have it, pretend like we just wrote them.  We don't
819	 * do the pretend-write, though, if we've already seen them
820	 * (the accounting would have been done for us already).
821	 */
822	daddr = fs->lfs_offset;
823	while (daddr != lastgood) {
824		if (!(seg_table[dtosn(fs, daddr)].su_flags & SEGUSE_DIRTY)) {
825			seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY;
826			LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
827			sup->su_flags |= SEGUSE_DIRTY;
828			VOP_BWRITE(sbp);
829		}
830
831		/* Could be a superblock */
832		if (sntod(fs, dtosn(fs, daddr)) == daddr) {
833			if (daddr == fs->lfs_start)
834				daddr += btofsb(fs, LFS_LABELPAD);
835			for (i = 0; i < LFS_MAXNUMSB; i++) {
836				if (daddr == fs->lfs_sboffs[i]) {
837					daddr += btofsb(fs, LFS_SBPAD);
838				}
839				if (daddr < fs->lfs_sboffs[i])
840					break;
841			}
842		}
843
844		/* Read in summary block */
845		bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, 0, &bp);
846		sp = (SEGSUM *)bp->b_data;
847		bc = check_summary(fs, sp, daddr, debug, devvp, pass6harvest);
848		if (bc == 0) {
849			pwarn("unexpected bad seg ptr [2] at 0x%x with serial=%d\n",
850				(int)daddr, (int)sp->ss_serial);
851			brelse(bp, 0);
852			break;
853		}
854		odaddr = daddr;
855		daddr += btofsb(fs, fs->lfs_sumsize + bc);
856		fs->lfs_avail -= btofsb(fs, fs->lfs_sumsize + bc);
857		if (dtosn(fs, odaddr) != dtosn(fs, daddr) ||
858		    dtosn(fs, daddr) != dtosn(fs, daddr +
859			btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize) - 1)) {
860			fs->lfs_avail -= sntod(fs, dtosn(fs, daddr) + 1) - daddr;
861			daddr = ((SEGSUM *)bp->b_data)->ss_next;
862		}
863		LFS_CLEANERINFO(cip, fs, cbp);
864		LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0);
865		bp->b_flags |= B_AGE;
866		brelse(bp, 0);
867	}
868
869	/* Final address could also be a superblock */
870	if (sntod(fs, dtosn(fs, lastgood)) == lastgood) {
871		if (lastgood == fs->lfs_start)
872			lastgood += btofsb(fs, LFS_LABELPAD);
873		for (i = 0; i < LFS_MAXNUMSB; i++) {
874			if (lastgood == fs->lfs_sboffs[i])
875				lastgood += btofsb(fs, LFS_SBPAD);
876			if (lastgood < fs->lfs_sboffs[i])
877				break;
878		}
879	}
880
881	/* Update offset to point at correct location */
882	fs->lfs_offset = lastgood;
883	fs->lfs_curseg = sntod(fs, dtosn(fs, lastgood));
884	for (sn = curseg = dtosn(fs, fs->lfs_curseg);;) {
885		sn = (sn + 1) % fs->lfs_nseg;
886		if (sn == curseg)
887			errx(1, "no clean segments");
888		LFS_SEGENTRY(sup, fs, sn, bp);
889		if ((sup->su_flags & SEGUSE_DIRTY) == 0) {
890			sup->su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE;
891			VOP_BWRITE(bp);
892			break;
893		}
894		brelse(bp, 0);
895	}
896	fs->lfs_nextseg = sntod(fs, sn);
897
898	if (preen) {
899		if (ndelfiles)
900			pwarn("roll forward deleted %d file%s\n", ndelfiles,
901				(ndelfiles > 1 ? "s" : ""));
902		if (nnewfiles)
903			pwarn("roll forward added %d file%s\n", nnewfiles,
904				(nnewfiles > 1 ? "s" : ""));
905		if (nmvfiles)
906			pwarn("roll forward relocated %d inode%s\n", nmvfiles,
907				(nmvfiles > 1 ? "s" : ""));
908		if (nnewblocks)
909			pwarn("roll forward verified %d data block%s\n", nnewblocks,
910				(nnewblocks > 1 ? "s" : ""));
911		if (ndelfiles == 0 && nnewfiles == 0 && nmvfiles == 0 &&
912		    nnewblocks == 0)
913			pwarn("roll forward produced nothing new\n");
914	}
915
916	if (!preen) {
917		/* Run pass 5 again (it's quick anyway). */
918		pwarn("** Phase 6b - Recheck Segment Block Accounting\n");
919		pass5();
920	}
921
922	/* Likewise for pass 0 */
923	if (!preen)
924		pwarn("** Phase 6c - Recheck Inode Free List\n");
925	pass0();
926}
927