xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/pass4.c (revision 2a8bcb4e)
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 
28355d6bb5Sswilcox #include <stdio.h>
29355d6bb5Sswilcox #include <stdlib.h>
30355d6bb5Sswilcox #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <sys/param.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
347c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
357c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
367c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
377c478bd9Sstevel@tonic-gate #include "fsck.h"
387c478bd9Sstevel@tonic-gate 
39355d6bb5Sswilcox void
pass4(void)40355d6bb5Sswilcox pass4(void)
417c478bd9Sstevel@tonic-gate {
42355d6bb5Sswilcox 	fsck_ino_t inumber;
437c478bd9Sstevel@tonic-gate 	struct dinode *dp;
447c478bd9Sstevel@tonic-gate 	struct inodesc idesc;
45355d6bb5Sswilcox 	int n, was_dir;
46355d6bb5Sswilcox 	int need_rescan;
47355d6bb5Sswilcox 	int scan_pass = 0;
48355d6bb5Sswilcox 
49355d6bb5Sswilcox 	/*
50355d6bb5Sswilcox 	 * If we clear a directory, it may have produced orphans which
51355d6bb5Sswilcox 	 * we need to go pick up.  So, do this until done.  It can be
52355d6bb5Sswilcox 	 * proven that the loop terminates because at most there can
53355d6bb5Sswilcox 	 * be lastino directories, and we only rescan if we clear a
54355d6bb5Sswilcox 	 * directory.
55355d6bb5Sswilcox 	 */
56355d6bb5Sswilcox 	do {
57355d6bb5Sswilcox 		if (debug)
58355d6bb5Sswilcox 			(void) printf("pass4 scan %d\n", scan_pass++);
59355d6bb5Sswilcox 
60355d6bb5Sswilcox 		need_rescan = 0;
61355d6bb5Sswilcox 		for (inumber = UFSROOTINO; inumber <= lastino; inumber++) {
62355d6bb5Sswilcox 			init_inodesc(&idesc);
63355d6bb5Sswilcox 			idesc.id_type = ADDR;
64355d6bb5Sswilcox 			idesc.id_func = pass4check;
65355d6bb5Sswilcox 			idesc.id_number = inumber;
66355d6bb5Sswilcox 
67355d6bb5Sswilcox 			was_dir = (statemap[inumber] & DSTATE) == DSTATE;
68355d6bb5Sswilcox 
69355d6bb5Sswilcox 			switch (statemap[inumber] & ~(INORPHAN | INDELAYD
70355d6bb5Sswilcox 			    | INZLINK)) {
71355d6bb5Sswilcox 
72355d6bb5Sswilcox 			case FZLINK:
73355d6bb5Sswilcox 			case DZLINK:
74355d6bb5Sswilcox 				/*
75355d6bb5Sswilcox 				 * INZLINK gets set if the inode claimed zero
76355d6bb5Sswilcox 				 * links when we first looked at it in pass 1.
77355d6bb5Sswilcox 				 * If lncntp[] also claims it has zero links,
78355d6bb5Sswilcox 				 * it really is unreferenced.  However, we
79355d6bb5Sswilcox 				 * could have found a link to it during one of
80355d6bb5Sswilcox 				 * the other passes, so we have to check the
81355d6bb5Sswilcox 				 * final count in lncntp[].
82355d6bb5Sswilcox 				 */
83355d6bb5Sswilcox 				if (lncntp[inumber] == 0) {
84355d6bb5Sswilcox 					clri(&idesc, "UNREF", CLRI_VERBOSE,
85355d6bb5Sswilcox 					    CLRI_NOP_OK);
86355d6bb5Sswilcox 					if (was_dir &&
87355d6bb5Sswilcox 					    (statemap[inumber] == USTATE))
88355d6bb5Sswilcox 						need_rescan = 1;
89355d6bb5Sswilcox 					break;
90355d6bb5Sswilcox 				}
91355d6bb5Sswilcox 				/* FALLTHROUGH */
92355d6bb5Sswilcox 
93355d6bb5Sswilcox 			case FSTATE:
94355d6bb5Sswilcox 			case DFOUND:
95355d6bb5Sswilcox 			case SSTATE:
96355d6bb5Sswilcox 				n = lncntp[inumber];
97355d6bb5Sswilcox 				if (n || (statemap[inumber] &
98355d6bb5Sswilcox 				    (INDELAYD | INZLINK))) {
99355d6bb5Sswilcox 					/*
100355d6bb5Sswilcox 					 * adjust() will clear the inode if
101355d6bb5Sswilcox 					 * the link count goes to zero.  If
102355d6bb5Sswilcox 					 * it isn't cleared, we need to note
103355d6bb5Sswilcox 					 * that we've adjusted the count
104355d6bb5Sswilcox 					 * already, so we don't do it again
105355d6bb5Sswilcox 					 * on a rescan.
106355d6bb5Sswilcox 					 */
107355d6bb5Sswilcox 					adjust(&idesc, n);
108355d6bb5Sswilcox 					if (was_dir &&
109355d6bb5Sswilcox 					    (statemap[inumber] == USTATE)) {
110355d6bb5Sswilcox 						need_rescan = 1;
111355d6bb5Sswilcox 					} else {
112355d6bb5Sswilcox 						TRACK_LNCNTP(inumber,
113355d6bb5Sswilcox 						    lncntp[inumber] = 0);
1147c478bd9Sstevel@tonic-gate 					}
115355d6bb5Sswilcox 				}
116355d6bb5Sswilcox 				break;
117355d6bb5Sswilcox 
118355d6bb5Sswilcox 			case DSTATE:
119355d6bb5Sswilcox 				clri(&idesc, "UNREF", CLRI_VERBOSE,
120355d6bb5Sswilcox 				    CLRI_NOP_OK);
121355d6bb5Sswilcox 				if (was_dir && (statemap[inumber] == USTATE))
122355d6bb5Sswilcox 					need_rescan = 1;
123355d6bb5Sswilcox 				break;
124355d6bb5Sswilcox 
125355d6bb5Sswilcox 			case DCLEAR:
126355d6bb5Sswilcox 				dp = ginode(inumber);
127355d6bb5Sswilcox 				if (dp->di_size == 0) {
128355d6bb5Sswilcox 					clri(&idesc, "ZERO LENGTH",
129355d6bb5Sswilcox 					    CLRI_VERBOSE, CLRI_NOP_CORRUPT);
130355d6bb5Sswilcox 					break;
131355d6bb5Sswilcox 				}
132355d6bb5Sswilcox 				/* FALLTHROUGH */
133355d6bb5Sswilcox 
134355d6bb5Sswilcox 			case FCLEAR:
135355d6bb5Sswilcox 				clri(&idesc, "BAD/DUP", CLRI_VERBOSE,
136355d6bb5Sswilcox 				    CLRI_NOP_CORRUPT);
1377c478bd9Sstevel@tonic-gate 				break;
1387c478bd9Sstevel@tonic-gate 
139355d6bb5Sswilcox 			case SCLEAR:
140355d6bb5Sswilcox 				clri(&idesc, "BAD", CLRI_VERBOSE,
141355d6bb5Sswilcox 				    CLRI_NOP_CORRUPT);
142355d6bb5Sswilcox 				break;
1437c478bd9Sstevel@tonic-gate 
144355d6bb5Sswilcox 			case USTATE:
145355d6bb5Sswilcox 				break;
1467c478bd9Sstevel@tonic-gate 
147355d6bb5Sswilcox 			default:
148355d6bb5Sswilcox 				errexit("BAD STATE 0x%x FOR INODE I=%d",
149355d6bb5Sswilcox 					(int)statemap[inumber], inumber);
150355d6bb5Sswilcox 			}
1517c478bd9Sstevel@tonic-gate 		}
152355d6bb5Sswilcox 	} while (need_rescan);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
155355d6bb5Sswilcox int
pass4check(struct inodesc * idesc)156355d6bb5Sswilcox pass4check(struct inodesc *idesc)
1577c478bd9Sstevel@tonic-gate {
158355d6bb5Sswilcox 	int fragnum, cg_frag;
1597c478bd9Sstevel@tonic-gate 	int res = KEEPON;
1607c478bd9Sstevel@tonic-gate 	daddr32_t blkno = idesc->id_blkno;
161355d6bb5Sswilcox 	int cylno;
162355d6bb5Sswilcox 	struct cg *cgp = &cgrp;
163355d6bb5Sswilcox 	caddr_t err;
164355d6bb5Sswilcox 
165355d6bb5Sswilcox 	if ((idesc->id_truncto >= 0) && (idesc->id_lbn < idesc->id_truncto)) {
166355d6bb5Sswilcox 		if (debug)
167355d6bb5Sswilcox 			(void) printf(
168355d6bb5Sswilcox 		    "pass4check: skipping inode %d lbn %d with truncto %d\n",
169355d6bb5Sswilcox 			    idesc->id_number, idesc->id_lbn,
170355d6bb5Sswilcox 			    idesc->id_truncto);
171355d6bb5Sswilcox 		return (KEEPON);
172355d6bb5Sswilcox 	}
1737c478bd9Sstevel@tonic-gate 
174355d6bb5Sswilcox 	for (fragnum = 0; fragnum < idesc->id_numfrags; fragnum++) {
175355d6bb5Sswilcox 		if (chkrange(blkno + fragnum, 1)) {
1767c478bd9Sstevel@tonic-gate 			res = SKIP;
177355d6bb5Sswilcox 		} else if (testbmap(blkno + fragnum)) {
178355d6bb5Sswilcox 			/*
179355d6bb5Sswilcox 			 * The block's in use.  Remove our reference
180355d6bb5Sswilcox 			 * from it.
181355d6bb5Sswilcox 			 *
182355d6bb5Sswilcox 			 * If it wasn't a dup, or everybody's done with
183355d6bb5Sswilcox 			 * it, then this is the last reference and it's
184355d6bb5Sswilcox 			 * safe to actually deallocate the on-disk block.
185355d6bb5Sswilcox 			 *
186355d6bb5Sswilcox 			 * We depend on pass 5 resolving the on-disk bitmap
187355d6bb5Sswilcox 			 * effects.
188355d6bb5Sswilcox 			 */
189355d6bb5Sswilcox 			cg_frag = blkno + fragnum;
190355d6bb5Sswilcox 			if (!find_dup_ref(cg_frag, idesc->id_number,
191355d6bb5Sswilcox 			    idesc->id_lbn * sblock.fs_frag + fragnum,
192355d6bb5Sswilcox 			    DB_DECR)) {
193355d6bb5Sswilcox 
194355d6bb5Sswilcox 				if (debug)
195355d6bb5Sswilcox 					(void) printf("p4c marking %d avail\n",
196355d6bb5Sswilcox 					    cg_frag);
197355d6bb5Sswilcox 				clrbmap(cg_frag);
1987c478bd9Sstevel@tonic-gate 				n_blks--;
199355d6bb5Sswilcox 
200355d6bb5Sswilcox 				/*
201355d6bb5Sswilcox 				 * Do the same for the on-disk bitmap, so
202355d6bb5Sswilcox 				 * that we don't need another pass to figure
203355d6bb5Sswilcox 				 * out what's really being used.  We'll let
204355d6bb5Sswilcox 				 * pass5() work out the fragment/block
205355d6bb5Sswilcox 				 * accounting.
206355d6bb5Sswilcox 				 */
207355d6bb5Sswilcox 				cylno = dtog(&sblock, cg_frag);
208355d6bb5Sswilcox 				(void) getblk(&cgblk, cgtod(&sblock, cylno),
209355d6bb5Sswilcox 				    (size_t)sblock.fs_cgsize);
210*77a343abSabalfour 				err = cg_sanity(cgp, cylno);
211355d6bb5Sswilcox 				if (err != NULL) {
212355d6bb5Sswilcox 					pfatal("CG %d: %s\n", cylno, err);
213355d6bb5Sswilcox 					free((void *)err);
214355d6bb5Sswilcox 					if (reply("REPAIR") == 0)
215355d6bb5Sswilcox 						errexit("Program terminated.");
216355d6bb5Sswilcox 					fix_cg(cgp, cylno);
217355d6bb5Sswilcox 				}
218355d6bb5Sswilcox 				clrbit(cg_blksfree(cgp),
219355d6bb5Sswilcox 				    dtogd(&sblock, cg_frag));
220355d6bb5Sswilcox 				cgdirty();
221355d6bb5Sswilcox 
222355d6bb5Sswilcox 				res |= ALTERED;
2237c478bd9Sstevel@tonic-gate 			}
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 	return (res);
2277c478bd9Sstevel@tonic-gate }
228