17c478bd9Sstevel@tonic-gate /*
2*77a343abSabalfour * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
37c478bd9Sstevel@tonic-gate * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate */
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
77c478bd9Sstevel@tonic-gate /* All Rights Reserved */
87c478bd9Sstevel@tonic-gate
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
117c478bd9Sstevel@tonic-gate * All rights reserved.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
147c478bd9Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright
157c478bd9Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display
167c478bd9Sstevel@tonic-gate * the following acknowledgement: ``This product includes software
177c478bd9Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors''
187c478bd9Sstevel@tonic-gate * in the documentation or other materials provided with the distribution
197c478bd9Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this
207c478bd9Sstevel@tonic-gate * software. Neither the name of the University nor the names of its
217c478bd9Sstevel@tonic-gate * contributors may be used to endorse or promote products derived
227c478bd9Sstevel@tonic-gate * from this software without specific prior written permission.
237c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
247c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
257c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
297c478bd9Sstevel@tonic-gate
30355d6bb5Sswilcox #include <stdio.h>
31355d6bb5Sswilcox #include <stdlib.h>
32355d6bb5Sswilcox #include <unistd.h>
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
367c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
377c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
387c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
397c478bd9Sstevel@tonic-gate #include "fsck.h"
407c478bd9Sstevel@tonic-gate
41355d6bb5Sswilcox void
pass4(void)42355d6bb5Sswilcox pass4(void)
437c478bd9Sstevel@tonic-gate {
44355d6bb5Sswilcox fsck_ino_t inumber;
457c478bd9Sstevel@tonic-gate struct dinode *dp;
467c478bd9Sstevel@tonic-gate struct inodesc idesc;
47355d6bb5Sswilcox int n, was_dir;
48355d6bb5Sswilcox int need_rescan;
49355d6bb5Sswilcox int scan_pass = 0;
507c478bd9Sstevel@tonic-gate
51355d6bb5Sswilcox /*
52355d6bb5Sswilcox * If we clear a directory, it may have produced orphans which
53355d6bb5Sswilcox * we need to go pick up. So, do this until done. It can be
54355d6bb5Sswilcox * proven that the loop terminates because at most there can
55355d6bb5Sswilcox * be lastino directories, and we only rescan if we clear a
56355d6bb5Sswilcox * directory.
57355d6bb5Sswilcox */
58355d6bb5Sswilcox do {
59355d6bb5Sswilcox if (debug)
60355d6bb5Sswilcox (void) printf("pass4 scan %d\n", scan_pass++);
61355d6bb5Sswilcox
62355d6bb5Sswilcox need_rescan = 0;
63355d6bb5Sswilcox for (inumber = UFSROOTINO; inumber <= lastino; inumber++) {
64355d6bb5Sswilcox init_inodesc(&idesc);
657c478bd9Sstevel@tonic-gate idesc.id_type = ADDR;
667c478bd9Sstevel@tonic-gate idesc.id_func = pass4check;
677c478bd9Sstevel@tonic-gate idesc.id_number = inumber;
68355d6bb5Sswilcox
69355d6bb5Sswilcox was_dir = (statemap[inumber] & DSTATE) == DSTATE;
70355d6bb5Sswilcox
71355d6bb5Sswilcox switch (statemap[inumber] & ~(INORPHAN | INDELAYD
72355d6bb5Sswilcox | INZLINK)) {
73355d6bb5Sswilcox
74355d6bb5Sswilcox case FZLINK:
75355d6bb5Sswilcox case DZLINK:
76355d6bb5Sswilcox /*
77355d6bb5Sswilcox * INZLINK gets set if the inode claimed zero
78355d6bb5Sswilcox * links when we first looked at it in pass 1.
79355d6bb5Sswilcox * If lncntp[] also claims it has zero links,
80355d6bb5Sswilcox * it really is unreferenced. However, we
81355d6bb5Sswilcox * could have found a link to it during one of
82355d6bb5Sswilcox * the other passes, so we have to check the
83355d6bb5Sswilcox * final count in lncntp[].
84355d6bb5Sswilcox */
85355d6bb5Sswilcox if (lncntp[inumber] == 0) {
86355d6bb5Sswilcox clri(&idesc, "UNREF", CLRI_VERBOSE,
87355d6bb5Sswilcox CLRI_NOP_OK);
88355d6bb5Sswilcox if (was_dir &&
89355d6bb5Sswilcox (statemap[inumber] == USTATE))
90355d6bb5Sswilcox need_rescan = 1;
91355d6bb5Sswilcox break;
92355d6bb5Sswilcox }
93355d6bb5Sswilcox /* FALLTHROUGH */
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate case FSTATE:
967c478bd9Sstevel@tonic-gate case DFOUND:
97355d6bb5Sswilcox case SSTATE:
987c478bd9Sstevel@tonic-gate n = lncntp[inumber];
99355d6bb5Sswilcox if (n || (statemap[inumber] &
100355d6bb5Sswilcox (INDELAYD | INZLINK))) {
101355d6bb5Sswilcox /*
102355d6bb5Sswilcox * adjust() will clear the inode if
103355d6bb5Sswilcox * the link count goes to zero. If
104355d6bb5Sswilcox * it isn't cleared, we need to note
105355d6bb5Sswilcox * that we've adjusted the count
106355d6bb5Sswilcox * already, so we don't do it again
107355d6bb5Sswilcox * on a rescan.
108355d6bb5Sswilcox */
109355d6bb5Sswilcox adjust(&idesc, n);
110355d6bb5Sswilcox if (was_dir &&
111355d6bb5Sswilcox (statemap[inumber] == USTATE)) {
112355d6bb5Sswilcox need_rescan = 1;
113355d6bb5Sswilcox } else {
114355d6bb5Sswilcox TRACK_LNCNTP(inumber,
115355d6bb5Sswilcox lncntp[inumber] = 0);
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate break;
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate case DSTATE:
121355d6bb5Sswilcox clri(&idesc, "UNREF", CLRI_VERBOSE,
122355d6bb5Sswilcox CLRI_NOP_OK);
123355d6bb5Sswilcox if (was_dir && (statemap[inumber] == USTATE))
124355d6bb5Sswilcox need_rescan = 1;
1257c478bd9Sstevel@tonic-gate break;
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate case DCLEAR:
1287c478bd9Sstevel@tonic-gate dp = ginode(inumber);
1297c478bd9Sstevel@tonic-gate if (dp->di_size == 0) {
130355d6bb5Sswilcox clri(&idesc, "ZERO LENGTH",
131355d6bb5Sswilcox CLRI_VERBOSE, CLRI_NOP_CORRUPT);
1327c478bd9Sstevel@tonic-gate break;
1337c478bd9Sstevel@tonic-gate }
134355d6bb5Sswilcox /* FALLTHROUGH */
135355d6bb5Sswilcox
1367c478bd9Sstevel@tonic-gate case FCLEAR:
137355d6bb5Sswilcox clri(&idesc, "BAD/DUP", CLRI_VERBOSE,
138355d6bb5Sswilcox CLRI_NOP_CORRUPT);
1397c478bd9Sstevel@tonic-gate break;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate case SCLEAR:
142355d6bb5Sswilcox clri(&idesc, "BAD", CLRI_VERBOSE,
143355d6bb5Sswilcox CLRI_NOP_CORRUPT);
1447c478bd9Sstevel@tonic-gate break;
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate case USTATE:
1477c478bd9Sstevel@tonic-gate break;
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate default:
150355d6bb5Sswilcox errexit("BAD STATE 0x%x FOR INODE I=%d",
151355d6bb5Sswilcox (int)statemap[inumber], inumber);
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate }
154355d6bb5Sswilcox } while (need_rescan);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate
157355d6bb5Sswilcox int
pass4check(struct inodesc * idesc)158355d6bb5Sswilcox pass4check(struct inodesc *idesc)
1597c478bd9Sstevel@tonic-gate {
160355d6bb5Sswilcox int fragnum, cg_frag;
1617c478bd9Sstevel@tonic-gate int res = KEEPON;
1627c478bd9Sstevel@tonic-gate daddr32_t blkno = idesc->id_blkno;
163355d6bb5Sswilcox int cylno;
164355d6bb5Sswilcox struct cg *cgp = &cgrp;
165355d6bb5Sswilcox caddr_t err;
1667c478bd9Sstevel@tonic-gate
167355d6bb5Sswilcox if ((idesc->id_truncto >= 0) && (idesc->id_lbn < idesc->id_truncto)) {
168355d6bb5Sswilcox if (debug)
169355d6bb5Sswilcox (void) printf(
170355d6bb5Sswilcox "pass4check: skipping inode %d lbn %d with truncto %d\n",
171355d6bb5Sswilcox idesc->id_number, idesc->id_lbn,
172355d6bb5Sswilcox idesc->id_truncto);
173355d6bb5Sswilcox return (KEEPON);
1747c478bd9Sstevel@tonic-gate }
175355d6bb5Sswilcox
176355d6bb5Sswilcox for (fragnum = 0; fragnum < idesc->id_numfrags; fragnum++) {
177355d6bb5Sswilcox if (chkrange(blkno + fragnum, 1)) {
178355d6bb5Sswilcox res = SKIP;
179355d6bb5Sswilcox } else if (testbmap(blkno + fragnum)) {
180355d6bb5Sswilcox /*
181355d6bb5Sswilcox * The block's in use. Remove our reference
182355d6bb5Sswilcox * from it.
183355d6bb5Sswilcox *
184355d6bb5Sswilcox * If it wasn't a dup, or everybody's done with
185355d6bb5Sswilcox * it, then this is the last reference and it's
186355d6bb5Sswilcox * safe to actually deallocate the on-disk block.
187355d6bb5Sswilcox *
188355d6bb5Sswilcox * We depend on pass 5 resolving the on-disk bitmap
189355d6bb5Sswilcox * effects.
190355d6bb5Sswilcox */
191355d6bb5Sswilcox cg_frag = blkno + fragnum;
192355d6bb5Sswilcox if (!find_dup_ref(cg_frag, idesc->id_number,
193355d6bb5Sswilcox idesc->id_lbn * sblock.fs_frag + fragnum,
194355d6bb5Sswilcox DB_DECR)) {
195355d6bb5Sswilcox
196355d6bb5Sswilcox if (debug)
197355d6bb5Sswilcox (void) printf("p4c marking %d avail\n",
198355d6bb5Sswilcox cg_frag);
199355d6bb5Sswilcox clrbmap(cg_frag);
2007c478bd9Sstevel@tonic-gate n_blks--;
201355d6bb5Sswilcox
202355d6bb5Sswilcox /*
203355d6bb5Sswilcox * Do the same for the on-disk bitmap, so
204355d6bb5Sswilcox * that we don't need another pass to figure
205355d6bb5Sswilcox * out what's really being used. We'll let
206355d6bb5Sswilcox * pass5() work out the fragment/block
207355d6bb5Sswilcox * accounting.
208355d6bb5Sswilcox */
209355d6bb5Sswilcox cylno = dtog(&sblock, cg_frag);
210355d6bb5Sswilcox (void) getblk(&cgblk, cgtod(&sblock, cylno),
211355d6bb5Sswilcox (size_t)sblock.fs_cgsize);
212*77a343abSabalfour err = cg_sanity(cgp, cylno);
213355d6bb5Sswilcox if (err != NULL) {
214355d6bb5Sswilcox pfatal("CG %d: %s\n", cylno, err);
215355d6bb5Sswilcox free((void *)err);
216355d6bb5Sswilcox if (reply("REPAIR") == 0)
217355d6bb5Sswilcox errexit("Program terminated.");
218355d6bb5Sswilcox fix_cg(cgp, cylno);
219355d6bb5Sswilcox }
220355d6bb5Sswilcox clrbit(cg_blksfree(cgp),
221355d6bb5Sswilcox dtogd(&sblock, cg_frag));
222355d6bb5Sswilcox cgdirty();
223355d6bb5Sswilcox
224355d6bb5Sswilcox res |= ALTERED;
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate return (res);
2297c478bd9Sstevel@tonic-gate }
230