xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/pass4.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved  	*/
8 
9 /*
10  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that: (1) source distributions retain this entire copyright
15  * notice and comment, and (2) distributions including binaries display
16  * the following acknowledgement:  ``This product includes software
17  * developed by the University of California, Berkeley and its contributors''
18  * in the documentation or other materials provided with the distribution
19  * and in all advertising materials mentioning features or use of this
20  * software. Neither the name of the University nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/mntent.h>
36 #include <sys/fs/ufs_fs.h>
37 #include <sys/vnode.h>
38 #include <sys/fs/ufs_inode.h>
39 #include "fsck.h"
40 
41 void
42 pass4(void)
43 {
44 	fsck_ino_t inumber;
45 	struct dinode *dp;
46 	struct inodesc idesc;
47 	int n, was_dir;
48 	int need_rescan;
49 	int scan_pass = 0;
50 
51 	/*
52 	 * If we clear a directory, it may have produced orphans which
53 	 * we need to go pick up.  So, do this until done.  It can be
54 	 * proven that the loop terminates because at most there can
55 	 * be lastino directories, and we only rescan if we clear a
56 	 * directory.
57 	 */
58 	do {
59 		if (debug)
60 			(void) printf("pass4 scan %d\n", scan_pass++);
61 
62 		need_rescan = 0;
63 		for (inumber = UFSROOTINO; inumber <= lastino; inumber++) {
64 			init_inodesc(&idesc);
65 			idesc.id_type = ADDR;
66 			idesc.id_func = pass4check;
67 			idesc.id_number = inumber;
68 
69 			was_dir = (statemap[inumber] & DSTATE) == DSTATE;
70 
71 			switch (statemap[inumber] & ~(INORPHAN | INDELAYD
72 			    | INZLINK)) {
73 
74 			case FZLINK:
75 			case DZLINK:
76 				/*
77 				 * INZLINK gets set if the inode claimed zero
78 				 * links when we first looked at it in pass 1.
79 				 * If lncntp[] also claims it has zero links,
80 				 * it really is unreferenced.  However, we
81 				 * could have found a link to it during one of
82 				 * the other passes, so we have to check the
83 				 * final count in lncntp[].
84 				 */
85 				if (lncntp[inumber] == 0) {
86 					clri(&idesc, "UNREF", CLRI_VERBOSE,
87 					    CLRI_NOP_OK);
88 					if (was_dir &&
89 					    (statemap[inumber] == USTATE))
90 						need_rescan = 1;
91 					break;
92 				}
93 				/* FALLTHROUGH */
94 
95 			case FSTATE:
96 			case DFOUND:
97 			case SSTATE:
98 				n = lncntp[inumber];
99 				if (n || (statemap[inumber] &
100 				    (INDELAYD | INZLINK))) {
101 					/*
102 					 * adjust() will clear the inode if
103 					 * the link count goes to zero.  If
104 					 * it isn't cleared, we need to note
105 					 * that we've adjusted the count
106 					 * already, so we don't do it again
107 					 * on a rescan.
108 					 */
109 					adjust(&idesc, n);
110 					if (was_dir &&
111 					    (statemap[inumber] == USTATE)) {
112 						need_rescan = 1;
113 					} else {
114 						TRACK_LNCNTP(inumber,
115 						    lncntp[inumber] = 0);
116 					}
117 				}
118 				break;
119 
120 			case DSTATE:
121 				clri(&idesc, "UNREF", CLRI_VERBOSE,
122 				    CLRI_NOP_OK);
123 				if (was_dir && (statemap[inumber] == USTATE))
124 					need_rescan = 1;
125 				break;
126 
127 			case DCLEAR:
128 				dp = ginode(inumber);
129 				if (dp->di_size == 0) {
130 					clri(&idesc, "ZERO LENGTH",
131 					    CLRI_VERBOSE, CLRI_NOP_CORRUPT);
132 					break;
133 				}
134 				/* FALLTHROUGH */
135 
136 			case FCLEAR:
137 				clri(&idesc, "BAD/DUP", CLRI_VERBOSE,
138 				    CLRI_NOP_CORRUPT);
139 				break;
140 
141 			case SCLEAR:
142 				clri(&idesc, "BAD", CLRI_VERBOSE,
143 				    CLRI_NOP_CORRUPT);
144 				break;
145 
146 			case USTATE:
147 				break;
148 
149 			default:
150 				errexit("BAD STATE 0x%x FOR INODE I=%d",
151 					(int)statemap[inumber], inumber);
152 			}
153 		}
154 	} while (need_rescan);
155 }
156 
157 int
158 pass4check(struct inodesc *idesc)
159 {
160 	int fragnum, cg_frag;
161 	int res = KEEPON;
162 	daddr32_t blkno = idesc->id_blkno;
163 	int cylno;
164 	struct cg *cgp = &cgrp;
165 	caddr_t err;
166 
167 	if ((idesc->id_truncto >= 0) && (idesc->id_lbn < idesc->id_truncto)) {
168 		if (debug)
169 			(void) printf(
170 		    "pass4check: skipping inode %d lbn %d with truncto %d\n",
171 			    idesc->id_number, idesc->id_lbn,
172 			    idesc->id_truncto);
173 		return (KEEPON);
174 	}
175 
176 	for (fragnum = 0; fragnum < idesc->id_numfrags; fragnum++) {
177 		if (chkrange(blkno + fragnum, 1)) {
178 			res = SKIP;
179 		} else if (testbmap(blkno + fragnum)) {
180 			/*
181 			 * The block's in use.  Remove our reference
182 			 * from it.
183 			 *
184 			 * If it wasn't a dup, or everybody's done with
185 			 * it, then this is the last reference and it's
186 			 * safe to actually deallocate the on-disk block.
187 			 *
188 			 * We depend on pass 5 resolving the on-disk bitmap
189 			 * effects.
190 			 */
191 			cg_frag = blkno + fragnum;
192 			if (!find_dup_ref(cg_frag, idesc->id_number,
193 			    idesc->id_lbn * sblock.fs_frag + fragnum,
194 			    DB_DECR)) {
195 
196 				if (debug)
197 					(void) printf("p4c marking %d avail\n",
198 					    cg_frag);
199 				clrbmap(cg_frag);
200 				n_blks--;
201 
202 				/*
203 				 * Do the same for the on-disk bitmap, so
204 				 * that we don't need another pass to figure
205 				 * out what's really being used.  We'll let
206 				 * pass5() work out the fragment/block
207 				 * accounting.
208 				 */
209 				cylno = dtog(&sblock, cg_frag);
210 				(void) getblk(&cgblk, cgtod(&sblock, cylno),
211 				    (size_t)sblock.fs_cgsize);
212 				err = cg_sanity(cgp, cylno);
213 				if (err != NULL) {
214 					pfatal("CG %d: %s\n", cylno, err);
215 					free((void *)err);
216 					if (reply("REPAIR") == 0)
217 						errexit("Program terminated.");
218 					fix_cg(cgp, cylno);
219 				}
220 				clrbit(cg_blksfree(cgp),
221 				    dtogd(&sblock, cg_frag));
222 				cgdirty();
223 
224 				res |= ALTERED;
225 			}
226 		}
227 	}
228 	return (res);
229 }
230