xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/pass1.c (revision 7c478bd9)
1 /*
2  * Copyright 2003 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 <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/sysmacros.h>
33 #include <sys/mntent.h>
34 
35 #define	bcopy(f, t, n)    memcpy(t, f, n)
36 #define	bzero(s, n)	memset(s, 0, n)
37 #define	bcmp(s, d, n)	memcmp(s, d, n)
38 
39 #define	index(s, r)	strchr(s, r)
40 #define	rindex(s, r)	strrchr(s, r)
41 
42 #include <sys/fs/ufs_fs.h>
43 #include <sys/vnode.h>
44 #include <sys/fs/ufs_inode.h>
45 #include <sys/fs/ufs_log.h>
46 #include "fsck.h"
47 
48 /*
49  * for each large file ( size > MAXOFF_T) this global counter
50  * gets incremented here.
51  */
52 
53 extern uint_t largefile_count;
54 
55 static uint32_t badblk;
56 static uint32_t dupblk;
57 int pass1check();
58 struct dinode *getnextinode();
59 
60 pass1()
61 {
62 	uint_t c, i, j;
63 	struct dinode *dp;
64 	struct zlncnt *zlnp;
65 	int ndb, cgd;
66 	struct inodesc idesc;
67 	ino_t inumber, shadow, attrinode;
68 	ino_t maxinumber;
69 	int32_t	tmpblks;
70 
71 	/*
72 	 * Set file system reserved blocks in used block map.
73 	 */
74 	for (c = 0; c < sblock.fs_ncg; c++) {
75 		cgd = cgdmin(&sblock, c);
76 		if (c == 0) {
77 			i = cgbase(&sblock, c);
78 			cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
79 		} else
80 			i = cgsblock(&sblock, c);
81 		for (; i < cgd; i++)
82 			setbmap(i);
83 	}
84 	/*
85 	 * Record log blocks
86 	 */
87 	if (islog && islogok && sblock.fs_logbno) {
88 		struct bufarea *bp;
89 		extent_block_t *ebp;
90 		extent_t *ep;
91 		daddr32_t nfno, fno;
92 		int	i;
93 		int	j;
94 
95 		bp = getdatablk(logbtofrag(&sblock,
96 		    sblock.fs_logbno), sblock.fs_bsize);
97 		ebp = (void *)bp->b_un.b_buf;
98 		ep = &ebp->extents[0];
99 		for (i = 0; i < ebp->nextents; ++i, ++ep) {
100 			fno = logbtofrag(&sblock, ep->pbno);
101 			nfno = dbtofsb(&sblock, ep->nbno);
102 			for (j = 0; j < nfno; ++j, ++fno)
103 				setbmap(fno);
104 		}
105 		brelse(bp);
106 
107 		fno = logbtofrag(&sblock, sblock.fs_logbno);
108 		for (j = 0; j < sblock.fs_frag; ++j, ++fno)
109 			setbmap(fno);
110 	}
111 	/*
112 	 * Find all allocated blocks.
113 	 */
114 	bzero((char *)&idesc, sizeof (struct inodesc));
115 	idesc.id_type = ADDR;
116 	idesc.id_func = pass1check;
117 	inumber = 0;
118 	n_files = n_blks = 0;
119 	resetinodebuf();
120 	maxinumber = sblock.fs_ncg * sblock.fs_ipg;
121 	for (c = 0; c < sblock.fs_ncg; c++) {
122 		for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
123 			if (inumber < UFSROOTINO)
124 				continue;
125 			dp = getnextinode(inumber);
126 			if ((dp->di_mode & IFMT) == 0) {
127 				/* mode and type of file is not set */
128 				if (bcmp((char *)dp->di_db, (char *)zino.di_db,
129 					NDADDR * sizeof (daddr32_t)) ||
130 				    bcmp((char *)dp->di_ib, (char *)zino.di_ib,
131 					NIADDR * sizeof (daddr32_t)) ||
132 				    dp->di_mode || dp->di_size) {
133 					pfatal("PARTIALLY ALLOCATED INODE I=%u",
134 						inumber);
135 					if (reply("CLEAR") == 1) {
136 						dp = ginode(inumber);
137 						clearinode(dp);
138 						inodirty();
139 					}
140 				}
141 				statemap[inumber] = USTATE;
142 				continue;
143 			}
144 			lastino = inumber;
145 			if (dp->di_size > (u_offset_t)UFS_MAXOFFSET_T) {
146 				if (debug)
147 					printf("bad size %llu:",
148 							dp->di_size);
149 				goto unknown;
150 			}
151 			if (!preen && (dp->di_mode & IFMT) == IFMT &&
152 			    reply("BAD MODE: MAKE IT A FILE") == 1) {
153 				dp = ginode(inumber);
154 				dp->di_size = (u_offset_t)sblock.fs_fsize;
155 				dp->di_mode = IFREG|0600;
156 				inodirty();
157 			}
158 			/* number of blocks is a 32 bit value */
159 			ndb = howmany(dp->di_size,
160 						(u_offset_t)sblock.fs_bsize);
161 			if (ndb < 0) {
162 				if (debug)
163 					printf("bad size %llu ndb %d:",
164 					dp->di_size, ndb);
165 				goto unknown;
166 			}
167 			if (dp->di_blocks < 0) {
168 				if (debug) {
169 					printf("bad number of sectors %d: ",
170 					    dp->di_blocks);
171 				}
172 				dp = ginode(inumber);
173 				tmpblks = (int32_t)
174 				    ((dp->di_size + (512 - 1)) >> 9);
175 				dp->di_blocks = (int32_t)(ndb*16);
176 				inodirty();
177 				if (debug) {
178 					printf("new number of sectors "
179 					    "%d (0x%x,0x%x)\n", dp->di_blocks,
180 					    dp->di_blocks, tmpblks);
181 				}
182 
183 			}
184 			if ((dp->di_mode & IFMT) == IFBLK ||
185 			    (dp->di_mode & IFMT) == IFCHR) {
186 			    for (j = 0; j < NDADDR; j++) {
187 				if (dp->di_db[j] != 0 &&
188 				    &dp->di_db[j] != &dp->di_ordev) {
189 					if (debug) {
190 printf("special file contains value %d at indirect addr[%d] - should be 0\n",
191 						dp->di_db[j], j);
192 					}
193 					goto unknown;
194 				}
195 			    }
196 			} else {
197 			    for (j = ndb; j < NDADDR; j++)
198 				if (dp->di_db[j] != 0) {
199 					if (debug) {
200 			    printf("bad direct addr[%lld]: 0x%x mode:%o\n",
201 						j, dp->di_db[j], dp->di_mode);
202 					}
203 					goto unknown;
204 				}
205 			}
206 			for (j = 0, ndb -= NDADDR; ndb > 0; j++)
207 				ndb /= NINDIR(&sblock);
208 			for (; j < NIADDR; j++)
209 				if (dp->di_ib[j] != 0) {
210 					if (debug) {
211 					printf("bad indirect addr: %d\n",
212 							dp->di_ib[j]);
213 					}
214 					goto unknown;
215 				}
216 			if (ftypeok(dp) == 0) {
217 				printf("mode: %o\n", dp->di_mode);
218 				goto unknown;
219 			}
220 			n_files++;
221 			lncntp[inumber] = dp->di_nlink;
222 			/*
223 			 * if errorlocked then open deleted files will
224 			 * manifest as di_nlink <= 0 and di_mode != 0
225 			 * so skip them; they're ok.
226 			 */
227 			if (dp->di_nlink <= 0 &&
228 					!(errorlocked && dp->di_mode == 0)) {
229 				zlnp = (struct zlncnt *)malloc(sizeof (*zlnp));
230 				if (zlnp == NULL) {
231 					pfatal("LINK COUNT TABLE OVERFLOW");
232 					if (reply("CONTINUE") == 0)
233 						errexit("");
234 				} else {
235 					zlnp->zlncnt = inumber;
236 					zlnp->next = zlnhead;
237 					zlnhead = zlnp;
238 				}
239 			}
240 
241 			/*
242 			 * Check for holes in a directory inode.
243 			 *
244 			 * Handle holes in direct blocks here.
245 			 * Holes in indirect blocks for large directories
246 			 * (>NDADDR blocks) will be checked in ckinode().
247 			 */
248 
249 			idesc.id_llbna = 0;
250 			idesc.id_hasholes = 0;
251 			if ((((dp->di_mode & IFMT) == IFDIR) ||
252 			    ((dp->di_mode & IFMT) == IFATTRDIR)) &&
253 			    dp->di_size > 0) {
254 
255 				ndb = howmany(dp->di_size,
256 						(u_offset_t)sblock.fs_bsize);
257 				ndb = ndb < NDADDR ? ndb : NDADDR;
258 
259 				for (j = 0; j < ndb; j++) {
260 					if (dp->di_db[j] == 0) {
261 						pwarn("DIRECTORY I=%d "
262 						    "HAS HOLES",
263 						    inumber);
264 						if (preen)
265 							printf("(CORRECTED)\n");
266 						else if (reply("CORRECT") == 0)
267 							break;
268 						idesc.id_hasholes = 1;
269 						break;
270 					} else {
271 						idesc.id_llbna++;
272 					}
273 				}
274 
275 				if (idesc.id_hasholes) {
276 					dp = ginode(inumber);
277 
278 					/*
279 					 * Move the existing entries in the
280 					 * direct block list, down.
281 					 *
282 					 * Do this only if the hole is
283 					 * not in the first block, or else
284 					 * the "." & the ".." entries will be
285 					 * missing and cannot be fixed.
286 					 * Such directories will get cleared.
287 					 */
288 					for (; j > 0 && j < ndb; j++) {
289 						if (!dp->di_db[j])
290 							continue;
291 						dp->di_db[idesc.id_llbna++] =
292 							dp->di_db[j];
293 					}
294 					/*
295 					 * Clear out rest of the direct block
296 					 * entries as they could be non zero
297 					 * as a result of the above operation.
298 					 */
299 					for (j = idesc.id_llbna; j < NDADDR;
300 					    j++)
301 						dp->di_db[j] = 0;
302 					/*
303 					 * Clear out indirect blocks, if any.
304 					 * We don't move indirect blocks down
305 					 * into the direct blocks, as it gets
306 					 * complicated.
307 					 *
308 					 * These blocks have not been accounted
309 					 * for yet. All the resulting orphaned
310 					 * directory entries will be taken
311 					 * care of in this run of pass1() and
312 					 * hence we do not need another run of
313 					 * fsck(no need for setting dirholes)
314 					 */
315 					for (j = 0; j < NIADDR; j++)
316 						dp->di_ib[j] = 0;
317 
318 					/*
319 					 * update the inode size & blocks count
320 					 */
321 					dp->di_size = (idesc.id_llbna) *
322 						sblock.fs_bsize;
323 					dp->di_blocks = dp->di_size / DEV_BSIZE;
324 					inodirty();
325 				}
326 			}
327 			if (((dp->di_mode & IFMT) == IFDIR) ||
328 			    ((dp->di_mode & IFMT) == IFATTRDIR)) {
329 				if (dp->di_size == 0)
330 					statemap[inumber] = DCLEAR;
331 				else
332 					statemap[inumber] = DSTATE;
333 				cacheino(dp, inumber);
334 			} else if ((dp->di_mode & IFMT) == IFSHAD) {
335 				if (dp->di_size == 0)
336 					statemap[inumber] = SCLEAR;
337 				else
338 					statemap[inumber] = SSTATE;
339 				cacheacl(dp, inumber);
340 			} else
341 				statemap[inumber] = FSTATE;
342 			badblk = dupblk = 0;
343 			idesc.id_number = inumber;
344 			idesc.id_fix = DONTKNOW;
345 			if (dp->di_size > (u_offset_t)MAXOFF_T) {
346 				largefile_count++;
347 				if (debug)
348 					printf("largefile: size=%lld,"
349 					    "count=%d\n", dp->di_size,
350 					    largefile_count);
351 			}
352 			(void) ckinode(dp, &idesc);
353 
354 			/*
355 			 * Check if we have holes in the directory's indirect
356 			 * blocks. Update the size. This requires another
357 			 * pass1 run (fsck once again).
358 			 */
359 			ndb = howmany(dp->di_size,
360 						(u_offset_t)sblock.fs_bsize);
361 			if ((((dp->di_mode & IFMT) == IFDIR) ||
362 			    ((dp->di_mode & IFMT) == IFATTRDIR)) &&
363 			    idesc.id_hasholes && idesc.id_llbna >= NDADDR &&
364 			    idesc.id_llbna < ndb) {
365 
366 				pwarn("DIRECTORY I=%d HAS HOLES", inumber);
367 
368 				if (preen || reply("CORRECT") == 1) {
369 					/*
370 					 * update the size
371 					 */
372 					dp = ginode(inumber);
373 					dp->di_size = (idesc.id_llbna) *
374 						sblock.fs_bsize;
375 					/*
376 					 * Clear out indirect blocks in the
377 					 * inode beyond the new size.
378 					 *
379 					 * All the disk block pointers in the
380 					 * the indirect blocks past the hole
381 					 * will get cleared out by the pass1()
382 					 * run as part of the re-check.
383 					 */
384 					ndb = howmany(dp->di_size,
385 						(u_offset_t)sblock.fs_bsize);
386 					for (j = 0, ndb -= NDADDR; ndb > 0; j++)
387 						ndb /= NINDIR(&sblock);
388 					for (; j < NIADDR; j++)
389 						dp->di_ib[j] = 0;
390 
391 					inodirty();
392 					/*
393 					 * flag that we need to re-check this
394 					 * filesystem to recover the blocks we
395 					 * just orphaned.
396 					 */
397 					dirholes = 1;
398 				}
399 				if (preen)
400 					printf(" (CORRECTED)\n");
401 			}
402 
403 			idesc.id_entryno *= btodb(sblock.fs_fsize);
404 			if (dp->di_blocks != idesc.id_entryno) {
405 			pwarn("INCORRECT BLOCK COUNT I=%u (%d should be %d)",
406 			    inumber, (uint32_t)dp->di_blocks,
407 			    idesc.id_entryno);
408 				if (preen)
409 					printf(" (CORRECTED)\n");
410 				else if (reply("CORRECT") == 0)
411 					continue;
412 				dp = ginode(inumber);
413 				dp->di_blocks = idesc.id_entryno;
414 				inodirty();
415 			}
416 			if (((dp->di_mode & IFMT) == IFDIR) ||
417 			    ((dp->di_mode & IFMT) == IFATTRDIR))
418 				if (dp->di_blocks == 0)
419 					statemap[inumber] = DCLEAR;
420 			/*
421 			 * Check that the ACL is on a valid file type
422 			 */
423 			shadow = dp->di_shadow;
424 			if (shadow != 0) {
425 				if (acltypeok(dp) == 0) {
426 					pwarn("NON-ZERO ACL REFERENCE,  I=%ld",
427 					    inumber);
428 					if (preen)
429 						printf(" (CORRECTED)\n");
430 					else if (reply("CORRECT") == 0)
431 						continue;
432 					dp = ginode(inumber);
433 					dp->di_shadow = 0;
434 					inodirty();
435 				} else if ((shadow <= UFSROOTINO) ||
436 					(shadow > maxinumber)) {
437 				/*
438 				 * The shadow inode # must be realistic -
439 				 * either 0 or a real inode number.
440 				 */
441 					pwarn("BAD ACL REFERENCE I=%ld",
442 					    inumber);
443 					if (preen)
444 						printf(" (CORRECTED)\n");
445 					else if (reply("CORRECT") == 0)
446 						continue;
447 					dp = ginode(inumber);
448 					dp->di_shadow = 0;
449 					dp->di_mode &= IFMT;
450 					dp->di_smode = dp->di_mode;
451 					inodirty();
452 				} else {
453 					/*
454 					 * "register" this inode/shadow pair
455 					 */
456 					registershadowclient(shadow,
457 						inumber, &shadowclientinfo);
458 				}
459 			}
460 
461 			attrinode = dp->di_oeftflag;
462 			if (attrinode != 0) {
463 				if ((attrinode <= UFSROOTINO) ||
464 					(attrinode > maxinumber)) {
465 				/*
466 				 * The attrdir inode # must be realistic -
467 				 * either 0 or a real inode number.
468 				 */
469 					pwarn("BAD ATTRIBUTE REFERENCE I=%ld"
470 						" parent file/dir I=%ld",
471 					    attrinode, inumber);
472 					if (preen)
473 						printf(" (CORRECTED)\n");
474 					else if (reply("CORRECT") == 0)
475 						continue;
476 					dp = ginode(inumber);
477 					dp->di_oeftflag = 0;
478 					dp->di_mode &= IFMT;
479 					dp->di_smode = dp->di_mode;
480 					inodirty();
481 				} else {
482 					/*
483 					 * "register" this inode/shadow pair
484 					 */
485 					dp = ginode(attrinode);
486 					if ((dp->di_mode & IFMT) != IFATTRDIR) {
487 						pwarn("BAD ATTRIBUTE DIR I=%ld"
488 						    " parent file/dir I=%ld",
489 						    attrinode, inumber);
490 						if (preen)
491 							printf(
492 							    " (CORRECTED)\n");
493 						else if (reply("CORRECT") ==
494 								0)
495 							continue;
496 						dp = ginode(inumber);
497 						dp->di_oeftflag = 0;
498 						inodirty();
499 					} else {
500 						registershadowclient(attrinode,
501 							inumber,
502 							&attrclientinfo);
503 					}
504 				}
505 			}
506 			continue;
507 	unknown:
508 			pfatal("UNKNOWN FILE TYPE I=%u", inumber);
509 			if (((dp->di_mode & IFMT) == IFDIR) ||
510 			    ((dp->di_mode & IFMT) == IFATTRDIR)) {
511 				statemap[inumber] = DCLEAR;
512 				cacheino(dp, inumber);
513 			} else
514 				statemap[inumber] = FCLEAR;
515 			if (reply("CLEAR") == 1) {
516 				statemap[inumber] = USTATE;
517 				dp = ginode(inumber);
518 				clearinode(dp);
519 				inodirty();
520 			}
521 		}
522 	}
523 	freeinodebuf();
524 }
525 
526 pass1check(idesc)
527 	struct inodesc *idesc;
528 {
529 	int res = KEEPON;
530 	int anyout;
531 	int	nfrags;
532 	daddr32_t blkno = idesc->id_blkno;
533 	struct dups *dlp;
534 	struct dups *new;
535 
536 	if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
537 		blkerror(idesc->id_number, "BAD", blkno);
538 		if (++badblk >= MAXBAD) {
539 			pwarn("EXCESSIVE BAD BLKS I=%u",
540 				idesc->id_number);
541 			if (preen)
542 				printf(" (SKIPPING)\n");
543 			else if (reply("CONTINUE") == 0)
544 				errexit("");
545 			return (STOP);
546 		}
547 	}
548 	for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
549 		if (anyout && chkrange(blkno, 1)) {
550 			res = SKIP;
551 		} else if (!testbmap(blkno)) {
552 			n_blks++;
553 			setbmap(blkno);
554 		} else {
555 			blkerror(idesc->id_number, "DUP", blkno);
556 			if (++dupblk >= MAXDUP) {
557 				pwarn("EXCESSIVE DUP BLKS I=%u",
558 					idesc->id_number);
559 				if (preen)
560 					printf(" (SKIPPING)\n");
561 				else if (reply("CONTINUE") == 0)
562 					errexit("");
563 				return (STOP);
564 			}
565 			new = (struct dups *)malloc(sizeof (struct dups));
566 			if (new == NULL) {
567 				pfatal("DUP TABLE OVERFLOW.");
568 				if (reply("CONTINUE") == 0)
569 					errexit("");
570 				return (STOP);
571 			}
572 			new->dup = blkno;
573 			if (muldup == 0) {
574 				duplist = muldup = new;
575 				new->next = 0;
576 			} else {
577 				new->next = muldup->next;
578 				muldup->next = new;
579 			}
580 			for (dlp = duplist; dlp != muldup; dlp = dlp->next)
581 				if (dlp->dup == blkno)
582 					break;
583 			if (dlp == muldup && dlp->dup != blkno)
584 				muldup = new;
585 		}
586 		/*
587 		 * count the number of blocks found in id_entryno
588 		 */
589 		idesc->id_entryno++;
590 	}
591 	return (res);
592 }
593