10Sstevel@tonic-gate /*
2*3219Sabalfour * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
70Sstevel@tonic-gate /* All Rights Reserved */
80Sstevel@tonic-gate
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
110Sstevel@tonic-gate * All rights reserved.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
140Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright
150Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display
160Sstevel@tonic-gate * the following acknowledgement: ``This product includes software
170Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors''
180Sstevel@tonic-gate * in the documentation or other materials provided with the distribution
190Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this
200Sstevel@tonic-gate * software. Neither the name of the University nor the names of its
210Sstevel@tonic-gate * contributors may be used to endorse or promote products derived
220Sstevel@tonic-gate * from this software without specific prior written permission.
230Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
240Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
250Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
290Sstevel@tonic-gate
30392Sswilcox #include <stdio.h>
31392Sswilcox #include <stdlib.h>
32392Sswilcox #include <unistd.h>
330Sstevel@tonic-gate #include <sys/param.h>
340Sstevel@tonic-gate #include <sys/types.h>
350Sstevel@tonic-gate #include <sys/mntent.h>
360Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
390Sstevel@tonic-gate #include "fsck.h"
400Sstevel@tonic-gate
41392Sswilcox void
pass4(void)42392Sswilcox pass4(void)
430Sstevel@tonic-gate {
44392Sswilcox fsck_ino_t inumber;
450Sstevel@tonic-gate struct dinode *dp;
460Sstevel@tonic-gate struct inodesc idesc;
47392Sswilcox int n, was_dir;
48392Sswilcox int need_rescan;
49392Sswilcox int scan_pass = 0;
500Sstevel@tonic-gate
51392Sswilcox /*
52392Sswilcox * If we clear a directory, it may have produced orphans which
53392Sswilcox * we need to go pick up. So, do this until done. It can be
54392Sswilcox * proven that the loop terminates because at most there can
55392Sswilcox * be lastino directories, and we only rescan if we clear a
56392Sswilcox * directory.
57392Sswilcox */
58392Sswilcox do {
59392Sswilcox if (debug)
60392Sswilcox (void) printf("pass4 scan %d\n", scan_pass++);
61392Sswilcox
62392Sswilcox need_rescan = 0;
63392Sswilcox for (inumber = UFSROOTINO; inumber <= lastino; inumber++) {
64392Sswilcox init_inodesc(&idesc);
65392Sswilcox idesc.id_type = ADDR;
66392Sswilcox idesc.id_func = pass4check;
67392Sswilcox idesc.id_number = inumber;
68392Sswilcox
69392Sswilcox was_dir = (statemap[inumber] & DSTATE) == DSTATE;
700Sstevel@tonic-gate
71392Sswilcox switch (statemap[inumber] & ~(INORPHAN | INDELAYD
72392Sswilcox | INZLINK)) {
73392Sswilcox
74392Sswilcox case FZLINK:
75392Sswilcox case DZLINK:
76392Sswilcox /*
77392Sswilcox * INZLINK gets set if the inode claimed zero
78392Sswilcox * links when we first looked at it in pass 1.
79392Sswilcox * If lncntp[] also claims it has zero links,
80392Sswilcox * it really is unreferenced. However, we
81392Sswilcox * could have found a link to it during one of
82392Sswilcox * the other passes, so we have to check the
83392Sswilcox * final count in lncntp[].
84392Sswilcox */
85392Sswilcox if (lncntp[inumber] == 0) {
86392Sswilcox clri(&idesc, "UNREF", CLRI_VERBOSE,
87392Sswilcox CLRI_NOP_OK);
88392Sswilcox if (was_dir &&
89392Sswilcox (statemap[inumber] == USTATE))
90392Sswilcox need_rescan = 1;
91392Sswilcox break;
92392Sswilcox }
93392Sswilcox /* FALLTHROUGH */
940Sstevel@tonic-gate
95392Sswilcox case FSTATE:
96392Sswilcox case DFOUND:
97392Sswilcox case SSTATE:
98392Sswilcox n = lncntp[inumber];
99392Sswilcox if (n || (statemap[inumber] &
100392Sswilcox (INDELAYD | INZLINK))) {
101392Sswilcox /*
102392Sswilcox * adjust() will clear the inode if
103392Sswilcox * the link count goes to zero. If
104392Sswilcox * it isn't cleared, we need to note
105392Sswilcox * that we've adjusted the count
106392Sswilcox * already, so we don't do it again
107392Sswilcox * on a rescan.
108392Sswilcox */
109392Sswilcox adjust(&idesc, n);
110392Sswilcox if (was_dir &&
111392Sswilcox (statemap[inumber] == USTATE)) {
112392Sswilcox need_rescan = 1;
113392Sswilcox } else {
114392Sswilcox TRACK_LNCNTP(inumber,
115392Sswilcox lncntp[inumber] = 0);
116392Sswilcox }
117392Sswilcox }
118392Sswilcox break;
1190Sstevel@tonic-gate
120392Sswilcox case DSTATE:
121392Sswilcox clri(&idesc, "UNREF", CLRI_VERBOSE,
122392Sswilcox CLRI_NOP_OK);
123392Sswilcox if (was_dir && (statemap[inumber] == USTATE))
124392Sswilcox need_rescan = 1;
1250Sstevel@tonic-gate break;
126392Sswilcox
127392Sswilcox case DCLEAR:
128392Sswilcox dp = ginode(inumber);
129392Sswilcox if (dp->di_size == 0) {
130392Sswilcox clri(&idesc, "ZERO LENGTH",
131392Sswilcox CLRI_VERBOSE, CLRI_NOP_CORRUPT);
132392Sswilcox break;
133392Sswilcox }
134392Sswilcox /* FALLTHROUGH */
135392Sswilcox
136392Sswilcox case FCLEAR:
137392Sswilcox clri(&idesc, "BAD/DUP", CLRI_VERBOSE,
138392Sswilcox CLRI_NOP_CORRUPT);
139392Sswilcox break;
140392Sswilcox
141392Sswilcox case SCLEAR:
142392Sswilcox clri(&idesc, "BAD", CLRI_VERBOSE,
143392Sswilcox CLRI_NOP_CORRUPT);
144392Sswilcox break;
145392Sswilcox
146392Sswilcox case USTATE:
147392Sswilcox break;
148392Sswilcox
149392Sswilcox default:
150392Sswilcox errexit("BAD STATE 0x%x FOR INODE I=%d",
151392Sswilcox (int)statemap[inumber], inumber);
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate }
154392Sswilcox } while (need_rescan);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
157392Sswilcox int
pass4check(struct inodesc * idesc)158392Sswilcox pass4check(struct inodesc *idesc)
1590Sstevel@tonic-gate {
160392Sswilcox int fragnum, cg_frag;
1610Sstevel@tonic-gate int res = KEEPON;
1620Sstevel@tonic-gate daddr32_t blkno = idesc->id_blkno;
163392Sswilcox int cylno;
164392Sswilcox struct cg *cgp = &cgrp;
165392Sswilcox caddr_t err;
1660Sstevel@tonic-gate
167392Sswilcox if ((idesc->id_truncto >= 0) && (idesc->id_lbn < idesc->id_truncto)) {
168392Sswilcox if (debug)
169392Sswilcox (void) printf(
170392Sswilcox "pass4check: skipping inode %d lbn %d with truncto %d\n",
171392Sswilcox idesc->id_number, idesc->id_lbn,
172392Sswilcox idesc->id_truncto);
173392Sswilcox return (KEEPON);
174392Sswilcox }
175392Sswilcox
176392Sswilcox for (fragnum = 0; fragnum < idesc->id_numfrags; fragnum++) {
177392Sswilcox if (chkrange(blkno + fragnum, 1)) {
1780Sstevel@tonic-gate res = SKIP;
179392Sswilcox } else if (testbmap(blkno + fragnum)) {
180392Sswilcox /*
181392Sswilcox * The block's in use. Remove our reference
182392Sswilcox * from it.
183392Sswilcox *
184392Sswilcox * If it wasn't a dup, or everybody's done with
185392Sswilcox * it, then this is the last reference and it's
186392Sswilcox * safe to actually deallocate the on-disk block.
187392Sswilcox *
188392Sswilcox * We depend on pass 5 resolving the on-disk bitmap
189392Sswilcox * effects.
190392Sswilcox */
191392Sswilcox cg_frag = blkno + fragnum;
192392Sswilcox if (!find_dup_ref(cg_frag, idesc->id_number,
193392Sswilcox idesc->id_lbn * sblock.fs_frag + fragnum,
194392Sswilcox DB_DECR)) {
195392Sswilcox
196392Sswilcox if (debug)
197392Sswilcox (void) printf("p4c marking %d avail\n",
198392Sswilcox cg_frag);
199392Sswilcox clrbmap(cg_frag);
2000Sstevel@tonic-gate n_blks--;
201392Sswilcox
202392Sswilcox /*
203392Sswilcox * Do the same for the on-disk bitmap, so
204392Sswilcox * that we don't need another pass to figure
205392Sswilcox * out what's really being used. We'll let
206392Sswilcox * pass5() work out the fragment/block
207392Sswilcox * accounting.
208392Sswilcox */
209392Sswilcox cylno = dtog(&sblock, cg_frag);
210392Sswilcox (void) getblk(&cgblk, cgtod(&sblock, cylno),
211392Sswilcox (size_t)sblock.fs_cgsize);
212*3219Sabalfour err = cg_sanity(cgp, cylno);
213392Sswilcox if (err != NULL) {
214392Sswilcox pfatal("CG %d: %s\n", cylno, err);
215392Sswilcox free((void *)err);
216392Sswilcox if (reply("REPAIR") == 0)
217392Sswilcox errexit("Program terminated.");
218392Sswilcox fix_cg(cgp, cylno);
219392Sswilcox }
220392Sswilcox clrbit(cg_blksfree(cgp),
221392Sswilcox dtogd(&sblock, cg_frag));
222392Sswilcox cgdirty();
223392Sswilcox
224392Sswilcox res |= ALTERED;
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate return (res);
2290Sstevel@tonic-gate }
230