xref: /onnv-gate/usr/src/cmd/fs.d/ufs/fsck/pass4.c (revision 3219:e626dd5cb7ec)
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