#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/mntent.h>
#include <sys/fs/ufs_fs.h>
#include <sys/vnode.h>
#include <sys/fs/ufs_inode.h>
#include "fsck.h"
void
pass4(void)
{
fsck_ino_t inumber;
struct dinode *dp;
struct inodesc idesc;
int n, was_dir;
int need_rescan;
int scan_pass = 0;
do {
if (debug)
(void) printf("pass4 scan %d\n", scan_pass++);
need_rescan = 0;
for (inumber = UFSROOTINO; inumber <= lastino; inumber++) {
init_inodesc(&idesc);
idesc.id_type = ADDR;
idesc.id_func = pass4check;
idesc.id_number = inumber;
was_dir = (statemap[inumber] & DSTATE) == DSTATE;
switch (statemap[inumber] & ~(INORPHAN | INDELAYD
| INZLINK)) {
case FZLINK:
case DZLINK:
if (lncntp[inumber] == 0) {
clri(&idesc, "UNREF", CLRI_VERBOSE,
CLRI_NOP_OK);
if (was_dir &&
(statemap[inumber] == USTATE))
need_rescan = 1;
break;
}
case FSTATE:
case DFOUND:
case SSTATE:
n = lncntp[inumber];
if (n || (statemap[inumber] &
(INDELAYD | INZLINK))) {
adjust(&idesc, n);
if (was_dir &&
(statemap[inumber] == USTATE)) {
need_rescan = 1;
} else {
TRACK_LNCNTP(inumber,
lncntp[inumber] = 0);
}
}
break;
case DSTATE:
clri(&idesc, "UNREF", CLRI_VERBOSE,
CLRI_NOP_OK);
if (was_dir && (statemap[inumber] == USTATE))
need_rescan = 1;
break;
case DCLEAR:
dp = ginode(inumber);
if (dp->di_size == 0) {
clri(&idesc, "ZERO LENGTH",
CLRI_VERBOSE, CLRI_NOP_CORRUPT);
break;
}
case FCLEAR:
clri(&idesc, "BAD/DUP", CLRI_VERBOSE,
CLRI_NOP_CORRUPT);
break;
case SCLEAR:
clri(&idesc, "BAD", CLRI_VERBOSE,
CLRI_NOP_CORRUPT);
break;
case USTATE:
break;
default:
errexit("BAD STATE 0x%x FOR INODE I=%d",
(int)statemap[inumber], inumber);
}
}
} while (need_rescan);
}
int
pass4check(struct inodesc *idesc)
{
int fragnum, cg_frag;
int res = KEEPON;
daddr32_t blkno = idesc->id_blkno;
int cylno;
struct cg *cgp = &cgrp;
caddr_t err;
if ((idesc->id_truncto >= 0) && (idesc->id_lbn < idesc->id_truncto)) {
if (debug)
(void) printf(
"pass4check: skipping inode %d lbn %d with truncto %d\n",
idesc->id_number, idesc->id_lbn,
idesc->id_truncto);
return (KEEPON);
}
for (fragnum = 0; fragnum < idesc->id_numfrags; fragnum++) {
if (chkrange(blkno + fragnum, 1)) {
res = SKIP;
} else if (testbmap(blkno + fragnum)) {
cg_frag = blkno + fragnum;
if (!find_dup_ref(cg_frag, idesc->id_number,
idesc->id_lbn * sblock.fs_frag + fragnum,
DB_DECR)) {
if (debug)
(void) printf("p4c marking %d avail\n",
cg_frag);
clrbmap(cg_frag);
n_blks--;
cylno = dtog(&sblock, cg_frag);
(void) getblk(&cgblk, cgtod(&sblock, cylno),
(size_t)sblock.fs_cgsize);
err = cg_sanity(cgp, cylno);
if (err != NULL) {
pfatal("CG %d: %s\n", cylno, err);
free((void *)err);
if (reply("REPAIR") == 0)
errexit("Program terminated.");
fix_cg(cgp, cylno);
}
clrbit(cg_blksfree(cgp),
dtogd(&sblock, cg_frag));
cgdirty();
res |= ALTERED;
}
}
}
return (res);
}