fsck_lfs can now write to the filesystem, allowing it to correct most
(though still not all) errors in a damaged lfs. Segment byte accounting is corrected in pass 5. "fsck_lfs -p" will do a partial roll-forward, verifying the checkpoint from the newer superblock. fscknames[] is updated so that fsck knows about fsck_lfs.
This commit is contained in:
parent
6047a12c7b
commit
e6c7065240
@ -1,16 +1,13 @@
|
||||
# $NetBSD: Makefile,v 1.1 1999/03/18 02:02:18 perseant Exp $
|
||||
# $NetBSD: Makefile,v 1.2 2000/05/16 04:55:59 perseant Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/5/93
|
||||
|
||||
PROG= fsck_lfs
|
||||
MAN= fsck_lfs.8
|
||||
SRCS= dir.c inode.c main.c pass1.c pass2.c pass3.c pass4.c \
|
||||
fsutil.c setup.c utilities.c lfs_cksum.c vars.c # lfs_subr.c
|
||||
SRCS+= pass0.c
|
||||
#SRCS+= pass1b.c pass5.c ffs_subr.c ffs_tables.c
|
||||
fsutil.c setup.c utilities.c lfs_cksum.c vars.c
|
||||
SRCS+= pass0.c pass5.c
|
||||
FSCK= ${.CURDIR}/../fsck
|
||||
.PATH: ${.CURDIR}/../../sys/ufs/lfs ${FSCK}
|
||||
CPPFLAGS+=-I${FSCK} #-I../../sys -I../../include -DVERBOSE_BLOCKMAP
|
||||
CFLAGS+=-g
|
||||
LDFLAGS+=-g
|
||||
CPPFLAGS+=-I${FSCK}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: fsck.h,v 1.3 2000/01/20 21:32:31 perseant Exp $ */
|
||||
/* $NetBSD: fsck.h,v 1.4 2000/05/16 04:55:59 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997
|
||||
@ -208,13 +208,15 @@ struct inoinfo {
|
||||
ino_t allocino __P((ino_t, int));
|
||||
int ino_to_fsba __P((struct lfs *, ino_t));
|
||||
struct bufarea *getfileblk __P((struct lfs *, struct dinode *, ino_t));
|
||||
struct bufarea *lfs_bginode __P((ino_t));
|
||||
struct dinode *ginode __P((ino_t));
|
||||
struct dinode *lfs_ginode __P((ino_t));
|
||||
struct dinode *lfs_difind __P((struct lfs *, ino_t, struct dinode *));
|
||||
struct ifile *lfs_ientry __P((ino_t));
|
||||
struct ifile *lfs_ientry __P((ino_t, struct bufarea **));
|
||||
struct inoinfo *getinoinfo __P((ino_t));
|
||||
void getblk __P((struct bufarea *, daddr_t, long));
|
||||
void getdblk __P((struct bufarea *, daddr_t, long));
|
||||
int check_summary(struct lfs *, SEGSUM *, daddr_t);
|
||||
SEGUSE *lfs_gseguse(int, struct bufarea **);
|
||||
daddr_t lfs_ino_daddr(ino_t);
|
||||
|
||||
#include "fsck_vars.h"
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: fsck_lfs.8,v 1.2 1999/03/19 17:29:44 perseant Exp $
|
||||
.\" $NetBSD: fsck_lfs.8,v 1.3 2000/05/16 04:55:59 perseant Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1989, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -102,8 +102,7 @@ The following flags are interpreted by
|
||||
.Bl -tag -width indent
|
||||
.It Fl b
|
||||
Use the block specified immediately after the flag as
|
||||
the super block for the filesystem. Block 32 is usually
|
||||
an alternative super block.
|
||||
the super block for the filesystem.
|
||||
.It Fl d
|
||||
Print debugging output.
|
||||
.\" .It Fl f
|
||||
@ -131,8 +130,9 @@ except for
|
||||
which is assumed to be affirmative;
|
||||
do not open the filesystem for writing.
|
||||
.It Fl p
|
||||
Specify ``preen'' mode. In fsck_lfs this currently does nothing, though
|
||||
in the future it will perform a roll-forward.
|
||||
Specify ``preen'' mode. Currently, in this mode
|
||||
.Nm fsck_lfs
|
||||
simply checks validity of the newer checkpoint.
|
||||
.It Fl y
|
||||
Assume a yes response to all questions asked by
|
||||
.Nm fsck_lfs ;
|
||||
@ -143,7 +143,7 @@ to continue after essentially unlimited trouble has been encountered.
|
||||
.Bl -enum -indent indent -compact
|
||||
Inconsistencies checked are as follows:
|
||||
.It
|
||||
Blocks claimed by more than one inode or the free map.
|
||||
Blocks claimed by more than one inode.
|
||||
.It
|
||||
Blocks claimed by an inode outside the range of the filesystem.
|
||||
.It
|
||||
@ -159,8 +159,6 @@ Partially truncated file.
|
||||
.It
|
||||
Bad inode format.
|
||||
.It
|
||||
Blocks not accounted for anywhere.
|
||||
.It
|
||||
Directory checks:
|
||||
.Bl -item -indent indent -compact
|
||||
.It
|
||||
@ -177,9 +175,7 @@ Super Block checks:
|
||||
.It
|
||||
More blocks for inodes than there are in the filesystem.
|
||||
.It
|
||||
Bad free block map format.
|
||||
.It
|
||||
Total free block and/or free inode count incorrect.
|
||||
Segment block counts incorrect, or ``clean'' segments containing live data.
|
||||
.El
|
||||
.El
|
||||
.Pp
|
||||
@ -205,7 +201,8 @@ are fully enumerated and explained in Appendix A of
|
||||
.Re
|
||||
.Sh BUGS
|
||||
.Nm Fsck_lfs
|
||||
cannot currently make any repairs, even a roll-forward.
|
||||
cannot currently perform a full roll-forward, or correct all of the
|
||||
errors that it can detect.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: inode.c,v 1.4 2000/01/20 21:32:31 perseant Exp $ */
|
||||
/* $NetBSD: inode.c,v 1.5 2000/05/16 04:55:59 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997, 1998
|
||||
@ -52,13 +52,13 @@
|
||||
#include "fsutil.h"
|
||||
#include "extern.h"
|
||||
|
||||
extern struct dinode **din_table;
|
||||
extern SEGUSE *seg_table;
|
||||
extern daddr_t *din_table;
|
||||
|
||||
static int iblock __P((struct inodesc *, long, u_int64_t));
|
||||
int blksreqd(struct lfs *, int);
|
||||
int lfs_maxino(void);
|
||||
SEGUSE *lfs_gseguse(int);
|
||||
SEGUSE *lfs_gseguse(int, struct bufarea **);
|
||||
/* static void dump_inoblk __P((struct lfs *, struct dinode *)); */
|
||||
|
||||
/* stolen from lfs_inode.c */
|
||||
@ -205,109 +205,123 @@ getfileblk(struct lfs *fs, struct dinode *idinode, ino_t lbn)
|
||||
return bp;
|
||||
}
|
||||
|
||||
int lfs_maxino(void)
|
||||
{
|
||||
#if 1
|
||||
struct dinode *idinode;
|
||||
|
||||
idinode = lfs_difind(&sblock,sblock.lfs_ifile,&ifblock);
|
||||
return ((idinode->di_size
|
||||
- (sblock.lfs_cleansz + sblock.lfs_segtabsz) * sblock.lfs_bsize)
|
||||
/ sblock.lfs_bsize) * sblock.lfs_ifpb - 1;
|
||||
#else
|
||||
return sblock.lfs_nfiles;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
static struct dinode *gidinode(void)
|
||||
{
|
||||
static struct dinode *idinode;
|
||||
|
||||
if(!idinode) { /* only need to do this once */
|
||||
idinode = lfs_difind(&sblock,sblock.lfs_ifile,&ifblock);
|
||||
if(din_table[LFS_IFILE_INUM]
|
||||
&& din_table[LFS_IFILE_INUM]->di_gen > idinode->di_gen) {
|
||||
printf("XXX replacing IFILE gen %d with gen %d\n",
|
||||
idinode->di_gen, din_table[LFS_IFILE_INUM]->di_gen);
|
||||
idinode = din_table[LFS_IFILE_INUM];
|
||||
}
|
||||
}
|
||||
return idinode;
|
||||
}
|
||||
|
||||
struct bufarea *
|
||||
lfs_bginode(ino_t ino)
|
||||
{
|
||||
ino_t blkno;
|
||||
|
||||
/* this is almost verbatim from lfs.h LFS_IENTRY */
|
||||
blkno = ino/sblock.lfs_ifpb + sblock.lfs_cleansz + sblock.lfs_segtabsz;
|
||||
|
||||
return getfileblk(&sblock,gidinode(),blkno);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ifile *
|
||||
lfs_ientry(ino_t ino)
|
||||
lfs_ientry(ino_t ino, struct bufarea **bpp)
|
||||
{
|
||||
struct ifile *ifp;
|
||||
struct bufarea *bp;
|
||||
|
||||
bp = lfs_bginode(ino);
|
||||
if(bp)
|
||||
*bpp = getfileblk(&sblock, lfs_ginode(LFS_IFILE_INUM),
|
||||
ino/sblock.lfs_ifpb + sblock.lfs_cleansz +
|
||||
sblock.lfs_segtabsz);
|
||||
if(*bpp)
|
||||
{
|
||||
ifp = (struct ifile *)malloc(sizeof(*ifp));
|
||||
*ifp = (((struct ifile *)(bp->b_un.b_buf))[ino%sblock.lfs_ifpb]);
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
|
||||
return ifp;
|
||||
ifp = (((struct ifile *)((*bpp)->b_un.b_buf)) +
|
||||
(ino%sblock.lfs_ifpb));
|
||||
return ifp;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SEGUSE *
|
||||
lfs_gseguse(int segnum)
|
||||
lfs_gseguse(int segnum, struct bufarea **bpp)
|
||||
{
|
||||
int blkno;
|
||||
struct bufarea *bp;
|
||||
|
||||
blkno = segnum/(sblock.lfs_bsize/sizeof(SEGUSE)) + sblock.lfs_cleansz;
|
||||
bp = getfileblk(&sblock,gidinode(),blkno);
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
return ((SEGUSE *)bp->b_un.b_buf) + segnum%(sblock.lfs_bsize/sizeof(SEGUSE));
|
||||
(*bpp) = getfileblk(&sblock,lfs_ginode(LFS_IFILE_INUM),blkno);
|
||||
return ((SEGUSE *)(*bpp)->b_un.b_buf) + segnum%(sblock.lfs_bsize/sizeof(SEGUSE));
|
||||
}
|
||||
|
||||
daddr_t
|
||||
lfs_ino_daddr(ino_t inumber)
|
||||
{
|
||||
daddr_t daddr;
|
||||
IFILE *ifp;
|
||||
struct bufarea *bp;
|
||||
|
||||
if(din_table[inumber]) {
|
||||
daddr = din_table[inumber];
|
||||
} else {
|
||||
if(inumber == LFS_IFILE_INUM)
|
||||
daddr = sblock.lfs_idaddr;
|
||||
else {
|
||||
ifp = lfs_ientry(inumber, &bp);
|
||||
if(ifp==NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if(ifp->if_daddr == LFS_UNUSED_DADDR) {
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
daddr = ifp->if_daddr;
|
||||
}
|
||||
|
||||
din_table[inumber] = daddr;
|
||||
seg_table[datosn(&sblock,daddr)].su_nbytes += DINODE_SIZE;
|
||||
}
|
||||
return daddr;
|
||||
}
|
||||
|
||||
struct dinode *
|
||||
lfs_ginode(ino_t inumber) {
|
||||
lfs_ginode(ino_t inumber)
|
||||
{
|
||||
struct ifile *ifp;
|
||||
struct dinode *din;
|
||||
struct bufarea *bp;
|
||||
daddr_t daddr;
|
||||
|
||||
if (inumber == LFS_IFILE_INUM)
|
||||
return gidinode();
|
||||
if (/* inumber < ROOTINO || */ inumber > maxino)
|
||||
errexit("bad inode number %d to lfs_ginode\n", inumber);
|
||||
/* printf("[lfs_ginode: looking up inode %ld]\n",inumber); */
|
||||
ifp = lfs_ientry(inumber);
|
||||
if(ifp==NULL
|
||||
|| ifp->if_daddr == LFS_UNUSED_DADDR
|
||||
|| ifp->if_daddr == UNASSIGNED) {
|
||||
return NULL;
|
||||
if (inumber > maxino)
|
||||
errexit("bad inode number %d to lfs_ginode\n", inumber);
|
||||
|
||||
#if 0
|
||||
if (inumber == LFS_IFILE_INUM) {
|
||||
daddr = sblock.lfs_idaddr;
|
||||
if(din_table[LFS_IFILE_INUM] == 0) {
|
||||
din_table[LFS_IFILE_INUM] = daddr;
|
||||
seg_table[datosn(&sblock,daddr)].su_nbytes += DINODE_SIZE;
|
||||
}
|
||||
return gidinode();
|
||||
}
|
||||
#endif
|
||||
|
||||
daddr = lfs_ino_daddr(inumber);
|
||||
if(daddr == 0)
|
||||
return NULL;
|
||||
|
||||
if(pbp)
|
||||
pbp->b_flags &= ~B_INUSE;
|
||||
if ( !(seg_table[datosn(&sblock,ifp->if_daddr)].su_flags & SEGUSE_DIRTY) )
|
||||
{
|
||||
printf("! INO %d: daddr 0x%x is in clean segment %d\n", inumber,
|
||||
ifp->if_daddr, datosn(&sblock,ifp->if_daddr));
|
||||
}
|
||||
pbp = getddblk(ifp->if_daddr,sblock.lfs_bsize);
|
||||
pbp->b_flags &= ~B_INUSE;
|
||||
|
||||
pbp = getddblk(daddr,sblock.lfs_bsize);
|
||||
din=lfs_difind(&sblock, inumber, pbp->b_un.b_dinode);
|
||||
|
||||
/* debug */
|
||||
if(din && din->di_inumber != inumber)
|
||||
printf("! lfs_ginode: got ino #%ld instead of %ld\n",
|
||||
(long)din->di_inumber, (long)inumber);
|
||||
free(ifp);
|
||||
if(din == NULL) {
|
||||
pfatal("INODE %d NOT FOUND\n", inumber);
|
||||
if(reply("free")) {
|
||||
ifp = lfs_ientry(inumber, &bp);
|
||||
ifp->if_daddr = LFS_UNUSED_DADDR;
|
||||
ifp->if_nextfree = sblock.lfs_free;
|
||||
sblock.lfs_free = inumber;
|
||||
sbdirty();
|
||||
dirty(bp);
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
}
|
||||
}
|
||||
|
||||
return din;
|
||||
}
|
||||
|
||||
@ -317,27 +331,25 @@ ino_to_fsba(struct lfs *fs, ino_t ino)
|
||||
{
|
||||
daddr_t daddr = LFS_UNUSED_DADDR;
|
||||
struct ifile *ifp;
|
||||
struct bufarea *bp;
|
||||
|
||||
/* Translate the inode number to a disk address. */
|
||||
if (ino == LFS_IFILE_INUM)
|
||||
daddr = fs->lfs_idaddr;
|
||||
else {
|
||||
/* LFS_IENTRY(ifp, fs, ino, bp); */
|
||||
ifp = lfs_ientry(ino);
|
||||
ifp = lfs_ientry(ino,&bp);
|
||||
if(ifp) {
|
||||
daddr = ifp->if_daddr;
|
||||
free(ifp);
|
||||
} else {
|
||||
pwarn("Can't locate inode #%ud\n",ino);
|
||||
}
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
}
|
||||
return daddr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check validity of held (direct) blocks in an inode.
|
||||
* Note that this does not check held indirect blocks (although it does
|
||||
* check that the first level of indirection is valid).
|
||||
*/
|
||||
int
|
||||
ckinode(dp, idesc)
|
||||
@ -530,10 +542,6 @@ chkrange(blk, cnt)
|
||||
printf("daddr 0x%x too large\n", blk);
|
||||
return (1);
|
||||
}
|
||||
if ( !(seg_table[datosn(&sblock,blk)].su_flags & SEGUSE_DIRTY) ) {
|
||||
printf("daddr 0x%x is in clean segment 0x%x\n", blk, datosn(&sblock,blk));
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -630,7 +638,6 @@ inocleanup()
|
||||
void
|
||||
inodirty()
|
||||
{
|
||||
|
||||
dirty(pbp);
|
||||
}
|
||||
|
||||
@ -641,6 +648,8 @@ clri(idesc, type, flag)
|
||||
int flag;
|
||||
{
|
||||
register struct dinode *dp;
|
||||
struct bufarea *bp;
|
||||
IFILE *ifp;
|
||||
|
||||
dp = ginode(idesc->id_number);
|
||||
if (flag == 1) {
|
||||
@ -656,6 +665,16 @@ clri(idesc, type, flag)
|
||||
clearinode(dp);
|
||||
statemap[idesc->id_number] = USTATE;
|
||||
inodirty();
|
||||
|
||||
/* Send cleared inode to the free list */
|
||||
|
||||
ifp = lfs_ientry(idesc->id_number, &bp);
|
||||
ifp->if_daddr = LFS_UNUSED_DADDR;
|
||||
ifp->if_nextfree = sblock.lfs_free;
|
||||
sblock.lfs_free = idesc->id_number;
|
||||
sbdirty();
|
||||
dirty(bp);
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -819,5 +838,6 @@ freeino(ino)
|
||||
clearinode(dp);
|
||||
inodirty();
|
||||
statemap[ino] = USTATE;
|
||||
|
||||
n_files--;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: main.c,v 1.3 2000/04/14 06:03:38 simonb Exp $ */
|
||||
/* $NetBSD: main.c,v 1.4 2000/05/16 04:55:59 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
@ -63,9 +63,6 @@ static int checkfilesys __P((const char *, char *, long, int));
|
||||
static int docheck __P((struct fstab *));
|
||||
#endif
|
||||
static void usage __P((void));
|
||||
#ifdef DEBUG_IFILE
|
||||
void cat_ifile(void);
|
||||
#endif
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
@ -74,11 +71,7 @@ main(argc, argv)
|
||||
{
|
||||
int ch;
|
||||
int ret = 0;
|
||||
#ifndef DEBUG_IFILE
|
||||
char *optstring = "b:C:dm:npy";
|
||||
#else
|
||||
char *optstring = "b:C:dim:npy";
|
||||
#endif
|
||||
|
||||
sync();
|
||||
skipclean = 1;
|
||||
@ -99,11 +92,6 @@ main(argc, argv)
|
||||
case 'e':
|
||||
exitonfail++;
|
||||
break;
|
||||
#ifdef DEBUG_IFILE
|
||||
case 'i':
|
||||
debug_ifile++;
|
||||
break;
|
||||
#endif
|
||||
case 'm':
|
||||
lfmode = argtoi('m', "mode", optarg, 8);
|
||||
if (lfmode &~ 07777)
|
||||
@ -117,14 +105,8 @@ main(argc, argv)
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
#if 1
|
||||
/* For an LFS filesystem, "preen" means "do nothing" */
|
||||
/* XXX should it instead mean "run in background"? */
|
||||
exit(0);
|
||||
#else
|
||||
preen++;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'y':
|
||||
yflag++;
|
||||
@ -135,7 +117,7 @@ main(argc, argv)
|
||||
usage();
|
||||
}
|
||||
}
|
||||
#ifndef NOTYET
|
||||
#if 0
|
||||
if(nflag==0) {
|
||||
errexit("fsck_lfs cannot write to the filesystem yet; the -n flag is required.\n");
|
||||
}
|
||||
@ -223,12 +205,7 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IFILE
|
||||
if(debug_ifile==0 && preen == 0)
|
||||
#else
|
||||
if(preen == 0)
|
||||
#endif
|
||||
{
|
||||
if(preen == 0) {
|
||||
printf("** Last Mounted on %s\n", sblock.lfs_fsmnt);
|
||||
if (hotroot())
|
||||
printf("** Root file system\n");
|
||||
@ -237,94 +214,56 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
/*
|
||||
* 0: check segment checksums, inode ranges
|
||||
*/
|
||||
#ifdef DEBUG_IFILE
|
||||
if (debug_ifile==0 && preen == 0) {
|
||||
#else
|
||||
if (preen == 0) {
|
||||
#endif
|
||||
printf("** Phase 0 - Check Segment Summaries\n");
|
||||
}
|
||||
if (preen == 0)
|
||||
printf("** Phase 0 - Check Segment Summaries and Inode Free List\n");
|
||||
pass0();
|
||||
#ifdef DEBUG_IFILE
|
||||
if(debug_ifile) {
|
||||
cat_ifile();
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* 1: scan inodes tallying blocks used
|
||||
*/
|
||||
if (preen == 0) {
|
||||
printf("** Phase 1 - Check Blocks and Sizes\n");
|
||||
}
|
||||
pass1();
|
||||
#if 0 /* FFS */
|
||||
/*
|
||||
* 1b: locate first references to duplicates, if any
|
||||
*/
|
||||
if (duplist) {
|
||||
if (preen)
|
||||
pfatal("INTERNAL ERROR: dups with -p");
|
||||
printf("** Phase 1b - Rescan For More DUPS\n");
|
||||
pass1b();
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* 2: traverse directories from root to mark all connected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 2 - Check Pathnames\n");
|
||||
pass2();
|
||||
|
||||
/*
|
||||
* 3: scan inodes looking for disconnected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 3 - Check Connectivity\n");
|
||||
pass3();
|
||||
if (preen==0) {
|
||||
/*
|
||||
* 1: scan inodes tallying blocks used
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 1 - Check Blocks and Sizes\n");
|
||||
pass1();
|
||||
|
||||
/*
|
||||
* 2: traverse directories from root to mark all connected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 2 - Check Pathnames\n");
|
||||
pass2();
|
||||
|
||||
/*
|
||||
* 3: scan inodes looking for disconnected directories
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 3 - Check Connectivity\n");
|
||||
pass3();
|
||||
|
||||
/*
|
||||
* 4: scan inodes looking for disconnected files; check reference counts
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 4 - Check Reference Counts\n");
|
||||
pass4();
|
||||
|
||||
|
||||
/*
|
||||
* 5: check segment byte totals and dirty flags
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 5 - Check Segment Block Accounting\n");
|
||||
pass5();
|
||||
|
||||
/*
|
||||
* print out summary statistics
|
||||
*/
|
||||
pwarn("%d files, %d used, %d free ",
|
||||
n_files, n_blks, n_ffree + sblock.lfs_frag * n_bfree);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
/*
|
||||
* 4: scan inodes looking for disconnected files; check reference counts
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 4 - Check Reference Counts\n");
|
||||
pass4();
|
||||
#if 0 /* FFS */
|
||||
/*
|
||||
* 5: check and repair resource counts in cylinder groups
|
||||
*/
|
||||
if (preen == 0)
|
||||
printf("** Phase 5 - Check Cyl groups\n");
|
||||
pass5();
|
||||
#endif
|
||||
/*
|
||||
* print out summary statistics
|
||||
*/
|
||||
#if 0 /* FFS-specific */
|
||||
n_ffree = sblock.lfs_cstotal.cs_nffree;
|
||||
n_bfree = sblock.lfs_cstotal.cs_nbfree;
|
||||
#endif
|
||||
pwarn("%d files, %d used, %d free ",
|
||||
n_files, n_blks, n_ffree + sblock.lfs_frag * n_bfree);
|
||||
#if 0 /* FFS */
|
||||
printf("(%d frags, %d blocks, %d.%d%% fragmentation)\n",
|
||||
n_ffree, n_bfree, (n_ffree * 100) / sblock.lfs_dsize,
|
||||
((n_ffree * 1000 + sblock.lfs_dsize / 2) / sblock.lfs_dsize) % 10);
|
||||
if (debug &&
|
||||
(n_files -= maxino - ROOTINO - sblock.lfs_cstotal.cs_nifree))
|
||||
printf("%d files missing\n", n_files);
|
||||
#else
|
||||
putchar('\n');
|
||||
#endif
|
||||
if (debug) {
|
||||
#if 0 /* FFS */
|
||||
n_blks += sblock.lfs_ncg *
|
||||
(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
|
||||
n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
|
||||
n_blks += howmany(sblock.lfs_cssize, sblock.lfs_fsize);
|
||||
if (n_blks -= maxfsblock - (n_ffree + sblock.lfs_frag * n_bfree))
|
||||
printf("%d blocks missing\n", n_blks);
|
||||
#endif
|
||||
if (duplist != NULL) {
|
||||
printf("The following duplicate blocks remain:");
|
||||
for (dp = duplist; dp; dp = dp->next)
|
||||
@ -342,20 +281,7 @@ checkfilesys(filesys, mntpt, auxdata, child)
|
||||
duplist = (struct dups *)0;
|
||||
muldup = (struct dups *)0;
|
||||
inocleanup();
|
||||
#if 0 /* no explicit dirty marker in LFS */
|
||||
if (fsmodified) {
|
||||
(void)time(&sblock.lfs_tstamp);
|
||||
sbdirty();
|
||||
}
|
||||
if (cvtlevel && sblk.b_dirty) {
|
||||
/*
|
||||
* Write out the duplicate super blocks
|
||||
*/
|
||||
for (cylno = 0; cylno < sblock.lfs_ncg; cylno++)
|
||||
bwrite(fswritefd, (char *)&sblock,
|
||||
fsbtodb(&sblock, cgsblock(&sblock, cylno)), LFS_SBPAD);
|
||||
}
|
||||
#endif
|
||||
|
||||
ckfini(1);
|
||||
free(blockmap);
|
||||
free(statemap);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: pass0.c,v 1.3 1999/07/03 19:55:03 kleink Exp $ */
|
||||
/* $NetBSD: pass0.c,v 1.4 2000/05/16 04:55:59 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Konrad E. Schroder.
|
||||
@ -55,12 +55,9 @@
|
||||
#define CKSEG_IGNORECLEAN 2
|
||||
|
||||
extern int fake_cleanseg;
|
||||
void check_segment(int, int, daddr_t, struct lfs *, int, int (*)(struct lfs *, SEGSUM *, int, int, daddr_t, daddr_t));
|
||||
static int check_summary(struct lfs *, SEGSUM *, int, int, daddr_t, daddr_t);
|
||||
SEGUSE *lfs_gseguse(int);
|
||||
void check_segment(int, int, daddr_t, struct lfs *, int,
|
||||
int (*)(struct lfs *, SEGSUM *, daddr_t));
|
||||
|
||||
struct dinode **din_table;
|
||||
SEGUSE *seg_table;
|
||||
/*
|
||||
* Pass 0. Check the LFS partial segments for valid checksums, correcting
|
||||
* if necessary. Also check for valid offsets for inode and finfo blocks.
|
||||
@ -72,39 +69,44 @@ SEGUSE *seg_table;
|
||||
|
||||
void pass0()
|
||||
{
|
||||
int i;
|
||||
daddr_t seg_addr;
|
||||
daddr_t daddr;
|
||||
IFILE *ifp;
|
||||
struct bufarea *bp;
|
||||
ino_t ino, lastino, nextino;
|
||||
|
||||
/*
|
||||
* Run through the Ifile, to count and load the inodes into
|
||||
* a dynamic inode table.
|
||||
* Check the inode free list for inuse inodes.
|
||||
*
|
||||
* XXX should also check for cycles or breaks in the list, and be able
|
||||
* to repair them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Check the segments
|
||||
*/
|
||||
|
||||
seg_addr = sblock.lfs_sboffs[0];
|
||||
for(i=0; i < sblock.lfs_nseg; i++)
|
||||
{
|
||||
seg_table[i] = *(lfs_gseguse(i));
|
||||
check_segment(fsreadfd, i, seg_addr, &sblock,
|
||||
CKSEG_IGNORECLEAN|CKSEG_VERBOSE, check_summary);
|
||||
seg_addr += (sblock.lfs_ssize << sblock.lfs_fsbtodb);
|
||||
lastino = 0;
|
||||
ino=sblock.lfs_free;
|
||||
while(ino) {
|
||||
ifp = lfs_ientry(ino,&bp);
|
||||
nextino = ifp->if_nextfree;
|
||||
daddr = ifp->if_daddr;
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
if(daddr) {
|
||||
printf("! Ino %d with daddr 0x%x is on the free list!\n",
|
||||
ino, daddr);
|
||||
if(preen || reply("FIX")==1) {
|
||||
if(lastino == 0) {
|
||||
sblock.lfs_free = nextino;
|
||||
sbdirty();
|
||||
} else {
|
||||
ifp = lfs_ientry(lastino,&bp);
|
||||
ifp->if_nextfree = nextino;
|
||||
++bp->b_dirty;
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
}
|
||||
ino = nextino;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
lastino = ino;
|
||||
ino = nextino;
|
||||
}
|
||||
#if 0
|
||||
/* check to see which inodes we didn't get */
|
||||
printf("Unavailable inodes: ");
|
||||
for(i=1;i<maxino;i++) /* XXX ino 0 is never present */
|
||||
if(din_table[i]==NULL)
|
||||
{
|
||||
struct ifile *ifp;
|
||||
|
||||
ifp = lfs_ientry(i);
|
||||
printf("(%d should be at daddr 0x%x)",i,ifp->if_daddr);
|
||||
}
|
||||
putchar('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dump_segsum(SEGSUM *sump, daddr_t addr)
|
||||
@ -121,21 +123,23 @@ static void dump_segsum(SEGSUM *sump, daddr_t addr)
|
||||
sump->ss_flags&SS_CONT?'c':'-');
|
||||
}
|
||||
|
||||
void check_segment(int fd, int segnum, daddr_t addr, struct lfs *fs, int flags, int (*func)(struct lfs *, SEGSUM *, int, int, daddr_t, daddr_t))
|
||||
void check_segment(int fd, int segnum, daddr_t addr, struct lfs *fs, int flags, int (*func)(struct lfs *, SEGSUM *, daddr_t))
|
||||
{
|
||||
struct lfs *sbp;
|
||||
SEGSUM *sump=NULL;
|
||||
SEGUSE su;
|
||||
SEGUSE *su;
|
||||
struct bufarea *bp = NULL;
|
||||
int psegnum=0, ninos=0;
|
||||
off_t sum_offset, db_ssize;
|
||||
int bc;
|
||||
int bc, su_flags, su_nsums, su_ninos;
|
||||
|
||||
db_ssize = sblock.lfs_ssize << sblock.lfs_fsbtodb;
|
||||
su = *(lfs_gseguse(segnum)); /* structure copy */
|
||||
|
||||
if(fake_cleanseg >= 0 && segnum == fake_cleanseg)
|
||||
seg_table[segnum].su_flags &= ~SEGUSE_DIRTY;
|
||||
su = lfs_gseguse(segnum, &bp);
|
||||
su_flags = su->su_flags;
|
||||
su_nsums = su->su_nsums;
|
||||
su_ninos = su->su_ninos;
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
|
||||
/* printf("Seg at 0x%x\n",addr); */
|
||||
if((flags & CKSEG_VERBOSE) && segnum*db_ssize + fs->lfs_sboffs[0] != addr)
|
||||
@ -145,7 +149,7 @@ void check_segment(int fd, int segnum, daddr_t addr, struct lfs *fs, int flags,
|
||||
sum_offset = ((off_t)addr << dbshift);
|
||||
|
||||
/* If this segment should have a superblock, look for one */
|
||||
if(su.su_flags & SEGUSE_SUPERBLOCK) {
|
||||
if(su_flags & SEGUSE_SUPERBLOCK) {
|
||||
bp = getddblk(sum_offset >> dbshift, LFS_SBPAD);
|
||||
sum_offset += LFS_SBPAD;
|
||||
|
||||
@ -166,11 +170,11 @@ void check_segment(int fd, int segnum, daddr_t addr, struct lfs *fs, int flags,
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
}
|
||||
/* XXX need to also check whether this one *should* be dirty */
|
||||
if((flags & CKSEG_IGNORECLEAN) && (su.su_flags & SEGUSE_DIRTY)==0)
|
||||
if((flags & CKSEG_IGNORECLEAN) && (su_flags & SEGUSE_DIRTY)==0)
|
||||
return;
|
||||
|
||||
while(1) {
|
||||
if(su.su_nsums <= psegnum)
|
||||
if(su_nsums <= psegnum)
|
||||
break;
|
||||
bp = getddblk(sum_offset >> dbshift, LFS_SUMMARY_SIZE);
|
||||
sump = (SEGSUM *)(bp->b_un.b_buf);
|
||||
@ -185,7 +189,7 @@ void check_segment(int fd, int segnum, daddr_t addr, struct lfs *fs, int flags,
|
||||
if(flags & CKSEG_VERBOSE) {
|
||||
/* Corrupt partial segment */
|
||||
pwarn("CORRUPT PARTIAL SEGMENT %d/%d OF SEGMENT %d AT BLK 0x%qx",
|
||||
psegnum, su.su_nsums, segnum,
|
||||
psegnum, su_nsums, segnum,
|
||||
(unsigned long long)sum_offset>>dbshift);
|
||||
if(db_ssize < (sum_offset>>dbshift) - addr)
|
||||
pwarn(" (+0x%qx/0x%qx)",
|
||||
@ -209,7 +213,7 @@ void check_segment(int fd, int segnum, daddr_t addr, struct lfs *fs, int flags,
|
||||
/*
|
||||
* Good partial segment
|
||||
*/
|
||||
bc = (*func)(&sblock, sump, segnum, psegnum, addr, (daddr_t)(sum_offset>>dbshift));
|
||||
bc = (*func)(&sblock, sump, (daddr_t)(sum_offset>>dbshift));
|
||||
if(bc) {
|
||||
sum_offset += LFS_SUMMARY_SIZE + bc;
|
||||
ninos += (sump->ss_ninos + INOPB(&sblock)-1)/INOPB(&sblock);
|
||||
@ -221,82 +225,97 @@ void check_segment(int fd, int segnum, daddr_t addr, struct lfs *fs, int flags,
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
}
|
||||
if(flags & CKSEG_VERBOSE) {
|
||||
if(ninos != su.su_ninos)
|
||||
if(ninos != su_ninos)
|
||||
pwarn("SEGMENT %d has %d ninos, not %d\n",
|
||||
segnum, ninos, su.su_ninos);
|
||||
if(psegnum != su.su_nsums)
|
||||
segnum, ninos, su_ninos);
|
||||
if(psegnum != su_nsums)
|
||||
pwarn("SEGMENT %d has %d summaries, not %d\n",
|
||||
segnum, psegnum, su.su_nsums);
|
||||
segnum, psegnum, su_nsums);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int check_summary(struct lfs *fs, SEGSUM *sp, int sn, int pn, daddr_t seg_addr, daddr_t pseg_addr)
|
||||
int check_summary(struct lfs *fs, SEGSUM *sp, daddr_t pseg_addr)
|
||||
{
|
||||
FINFO *fp;
|
||||
int bc; /* Bytes in partial segment */
|
||||
daddr_t *dp;
|
||||
struct dinode *ip;
|
||||
int nblocks;
|
||||
daddr_t seg_addr, *dp, *idp, daddr;
|
||||
struct bufarea *bp;
|
||||
int i, j, n;
|
||||
int i, j, k, datac, len;
|
||||
long sn;
|
||||
u_long *datap;
|
||||
u_int32_t ccksum;
|
||||
|
||||
sn = datosn(fs, pseg_addr);
|
||||
seg_addr = sntoda(fs, sn);
|
||||
|
||||
/* printf("Pseg at 0x%x, %d inos, %d finfos\n",addr>>dbshift,sp->ss_ninos,sp->ss_nfinfo); */
|
||||
/* We've already checked the sumsum, just do the data bounds and sum */
|
||||
bc = ((sp->ss_ninos + INOPB(fs) - 1) / INOPB(fs)) << fs->lfs_bshift;
|
||||
|
||||
/* 1. Count the blocks. */
|
||||
nblocks = ((sp->ss_ninos + INOPB(fs) - 1) / INOPB(fs));
|
||||
bc = nblocks << fs->lfs_bshift;
|
||||
|
||||
fp = (FINFO *)(sp + 1);
|
||||
for(i=0; i<sp->ss_nfinfo; i++) {
|
||||
nblocks += fp->fi_nblocks;
|
||||
bc += fp->fi_lastlength + ((fp->fi_nblocks-1) << fs->lfs_bshift);
|
||||
fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks);
|
||||
}
|
||||
datap = (u_long *)malloc(nblocks * sizeof(*datap));
|
||||
datac = 0;
|
||||
|
||||
dp = (daddr_t *)sp;
|
||||
dp += LFS_SUMMARY_SIZE / sizeof(daddr_t);
|
||||
dp--;
|
||||
i=0;
|
||||
#if 0
|
||||
if(sp->ss_ninos==0 && sp->ss_nfinfo==0) {
|
||||
pwarn("SEGMENT %d PSEG %d IS EMPTY\n",sn,pn);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
while(i<sp->ss_ninos)
|
||||
{
|
||||
if(*dp < seg_addr || *dp > seg_addr + (sblock.lfs_ssize<<dbshift))
|
||||
{
|
||||
printf("Disk address 0x%x but should be in 0x%x--0x%x\n",
|
||||
*dp, seg_addr, seg_addr+(sblock.lfs_ssize<<dbshift));
|
||||
}
|
||||
bp = getddblk(*dp, (1<<fs->lfs_bshift));
|
||||
ip = (struct dinode *)bp->b_un.b_buf;
|
||||
for(j=0; i<sp->ss_ninos && j<INOPB(fs); j++) {
|
||||
/* check range */
|
||||
if(ip[j].di_inumber < 0 || ip[j].di_inumber > maxino)
|
||||
{
|
||||
pwarn("BAD INUM %d IN SEGMENT %d PARTIAL %d\n",
|
||||
ip[j].di_inumber, sn, pn);
|
||||
/* XXX Allow to fix (zero) this */
|
||||
} else {
|
||||
/* take a record of the highest-generation of each inode */
|
||||
n = ip[j].di_inumber;
|
||||
#if 1
|
||||
if(din_table[n]==NULL || din_table[n]->di_gen < ip[j].di_gen) {
|
||||
if(!din_table[n])
|
||||
din_table[n] = (struct dinode *)
|
||||
malloc(sizeof(struct dinode));
|
||||
memcpy(din_table[n],&ip[j],sizeof(struct dinode));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
i++;
|
||||
}
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
dp--;
|
||||
}
|
||||
|
||||
idp = dp;
|
||||
daddr = pseg_addr + (LFS_SUMMARY_SIZE/dev_bsize);
|
||||
fp = (FINFO *)(sp + 1);
|
||||
for(i=0; i<sp->ss_nfinfo; i++) {
|
||||
bc += fp->fi_lastlength + ((fp->fi_nblocks-1) << fs->lfs_bshift);
|
||||
/* XXX for now, ignore mismatches between segments' FINFO and IFILE */
|
||||
dp = &(fp->fi_blocks[0]);
|
||||
for(j=0; j<fp->fi_nblocks; j++) {
|
||||
/* XXX check values against inodes' known block size */
|
||||
dp++;
|
||||
}
|
||||
fp = (FINFO *)dp;
|
||||
for(i=0, j=0; i<sp->ss_nfinfo || j<howmany(sp->ss_ninos,INOPB(fs)); i++) {
|
||||
/* printf("*idp=%x, daddr=%x\n", *idp, daddr); */
|
||||
if(i >= sp->ss_nfinfo && *idp != daddr) {
|
||||
pwarn("Not enough inode blocks in pseg at 0x%x: found %d, wanted %d\n",
|
||||
pseg_addr, j, howmany(sp->ss_ninos,INOPB(fs)));
|
||||
pwarn("*idp=%x, daddr=%x\n", *idp, daddr);
|
||||
break;
|
||||
}
|
||||
while(j < howmany(sp->ss_ninos,INOPB(fs)) && *idp == daddr) {
|
||||
bp = getddblk(daddr, (1<<fs->lfs_bshift));
|
||||
datap[datac++] = ((u_long *)(bp->b_un.b_buf))[0];
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
|
||||
++j;
|
||||
daddr += (1<<fs->lfs_bshift)/dev_bsize;
|
||||
--idp;
|
||||
}
|
||||
if(i < sp->ss_nfinfo) {
|
||||
for(k=0; k<fp->fi_nblocks; k++) {
|
||||
len = (k==fp->fi_nblocks - 1 ? fp->fi_lastlength
|
||||
: (1<<fs->lfs_bshift));
|
||||
bp = getddblk(daddr, len);
|
||||
datap[datac++] = ((u_long *)(bp->b_un.b_buf))[0];
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
daddr += len/dev_bsize;
|
||||
}
|
||||
fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks);
|
||||
}
|
||||
}
|
||||
|
||||
if(datac != nblocks) {
|
||||
pwarn("Partial segment at 0x%x expected %d blocks counted %d\n",
|
||||
pseg_addr, nblocks, datac);
|
||||
}
|
||||
|
||||
ccksum = cksum(datap, nblocks * sizeof(u_long));
|
||||
/* Check the data checksum */
|
||||
if (ccksum != sp->ss_datasum) {
|
||||
pwarn("Partial segment at 0x%x data checksum mismatch: got 0x%x, expected 0x%x\n",
|
||||
pseg_addr, sp->ss_datasum, ccksum);
|
||||
/* return 0; */
|
||||
}
|
||||
|
||||
return bc;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: pass1.c,v 1.4 2000/01/20 21:32:32 perseant Exp $ */
|
||||
/* $NetBSD: pass1.c,v 1.5 2000/05/16 04:55:59 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
@ -50,11 +50,13 @@
|
||||
#include "extern.h"
|
||||
#include "fsutil.h"
|
||||
|
||||
extern struct dinode **din_table;
|
||||
SEGUSE *seg_table;
|
||||
extern daddr_t *din_table;
|
||||
|
||||
static daddr_t badblk;
|
||||
static daddr_t dupblk;
|
||||
static void checkinode __P((ino_t, struct inodesc *));
|
||||
static int i_d_cmp(const void *, const void *);
|
||||
|
||||
static void bmapcheck(void)
|
||||
{
|
||||
@ -67,15 +69,39 @@ static void bmapcheck(void)
|
||||
raise(1);
|
||||
}
|
||||
|
||||
struct ino_daddr {
|
||||
ino_t ino;
|
||||
daddr_t daddr;
|
||||
};
|
||||
|
||||
static int
|
||||
i_d_cmp(const void *va, const void *vb)
|
||||
{
|
||||
struct ino_daddr *a, *b;
|
||||
|
||||
a = *((struct ino_daddr **)va);
|
||||
b = *((struct ino_daddr **)vb);
|
||||
|
||||
if (a->daddr == b->daddr) {
|
||||
return (a->ino - b->ino);
|
||||
}
|
||||
if (a->daddr > b->daddr) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
pass1()
|
||||
{
|
||||
ino_t inumber;
|
||||
int total_segments;
|
||||
int i, total_segments;
|
||||
struct inodesc idesc;
|
||||
struct dinode *idinode, *tinode;
|
||||
struct ifile *ifp;
|
||||
CLEANERINFO *cp;
|
||||
struct bufarea *bp;
|
||||
struct ino_daddr **dins;
|
||||
|
||||
idinode = lfs_difind(&sblock,sblock.lfs_ifile,&ifblock);
|
||||
|
||||
@ -102,18 +128,28 @@ pass1()
|
||||
inumber = 0;
|
||||
n_files = n_blks = 0;
|
||||
|
||||
/* find a value for numdirs */
|
||||
if (debug)
|
||||
printf("creating inode address table...\n");
|
||||
/* Sort by daddr */
|
||||
dins = (struct ino_daddr **)malloc((maxino+1) * sizeof(*dins));
|
||||
for(i=0;i<=maxino;i++) {
|
||||
dins[i] = malloc(sizeof(**dins));
|
||||
dins[i]->ino = i;
|
||||
dins[i]->daddr = lfs_ino_daddr(i);
|
||||
}
|
||||
qsort(dins, maxino+1, sizeof(*dins), i_d_cmp);
|
||||
|
||||
/* find a value for numdirs, fill in din_table */
|
||||
if (debug)
|
||||
printf("counting dirs...\n");
|
||||
numdirs=0;
|
||||
for(inumber=0; inumber < maxino; inumber++) {
|
||||
tinode = lfs_ginode(inumber);
|
||||
#if 0 /* debug */
|
||||
ifp = lfs_ientry(inumber);
|
||||
if(ifp)
|
||||
printf("Inode %lu has disk address %lx\n",
|
||||
inumber, ifp->if_daddr);
|
||||
#endif
|
||||
if(tinode && (tinode->di_mode & IFMT)==IFDIR)
|
||||
numdirs++;
|
||||
for(i=0; i <= maxino; i++) {
|
||||
inumber = dins[i]->ino;
|
||||
if(inumber == 0 || dins[i]->daddr == 0)
|
||||
continue;
|
||||
tinode = lfs_ginode(inumber);
|
||||
if(tinode && (tinode->di_mode & IFMT)==IFDIR)
|
||||
numdirs++;
|
||||
}
|
||||
|
||||
/* from setup.c */
|
||||
@ -130,19 +166,23 @@ pass1()
|
||||
}
|
||||
|
||||
/* resetinodebuf(); */
|
||||
|
||||
for(inumber=ROOTINO; inumber <= maxino; inumber++) {
|
||||
ifp = lfs_ientry(inumber);
|
||||
if(ifp && ifp->if_daddr != LFS_UNUSED_DADDR) {
|
||||
checkinode(inumber, &idesc);
|
||||
#if 1
|
||||
if(statemap[inumber]!=USTATE && din_table[inumber]==NULL) {
|
||||
pwarn("Inode %d not claimed by any segment (belongs to %d)\n",inumber,datosn(&sblock,ifp->if_daddr));
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
statemap[inumber] = USTATE;
|
||||
if (debug)
|
||||
printf("counting blocks...\n");
|
||||
for(i=0; i <= maxino; i++) {
|
||||
inumber = dins[i]->ino;
|
||||
if(inumber == 0 || dins[i]->daddr == 0)
|
||||
continue;
|
||||
ifp = lfs_ientry(inumber,&bp);
|
||||
if(ifp && ifp->if_daddr != LFS_UNUSED_DADDR) {
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
checkinode(inumber, &idesc);
|
||||
} else {
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
statemap[inumber] = USTATE;
|
||||
}
|
||||
free(dins[i]);
|
||||
}
|
||||
free(dins);
|
||||
|
||||
bmapcheck();
|
||||
/* freeinodebuf(); */
|
||||
@ -262,7 +302,7 @@ checkinode(inumber, idesc)
|
||||
if (debug)
|
||||
printf("bad indirect addr: %d\n",
|
||||
dp->di_ib[j]);
|
||||
goto unknown;
|
||||
/* goto unknown; */
|
||||
}
|
||||
if (ftypeok(dp) == 0)
|
||||
goto unknown;
|
||||
@ -337,6 +377,10 @@ pass1check(idesc)
|
||||
register struct dups *dlp;
|
||||
struct dups *new;
|
||||
|
||||
if (!testbmap(blkno)) {
|
||||
seg_table[datosn(&sblock,blkno)].su_nbytes += idesc->id_numfrags * sblock.lfs_fsize;
|
||||
}
|
||||
|
||||
if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
|
||||
blkerror(idesc->id_number, "BAD", blkno);
|
||||
if (badblk++ >= MAXBAD) {
|
||||
@ -357,10 +401,6 @@ pass1check(idesc)
|
||||
#ifndef VERBOSE_BLOCKMAP
|
||||
setbmap(blkno);
|
||||
#else
|
||||
#if 0
|
||||
if(idesc->id_number > 10000)
|
||||
printf("Oops, inum was %d\n", idesc->id_number);
|
||||
#endif
|
||||
setbmap(blkno,idesc->id_number);
|
||||
#endif
|
||||
} else {
|
||||
|
@ -1,101 +0,0 @@
|
||||
/* $NetBSD: pass1b.c,v 1.2 1999/07/03 19:55:03 kleink Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
#include "extern.h"
|
||||
|
||||
static int pass1bcheck __P((struct inodesc *));
|
||||
static struct dups *duphead;
|
||||
|
||||
void
|
||||
pass1b()
|
||||
{
|
||||
register int c, i;
|
||||
register struct dinode *dp;
|
||||
struct inodesc idesc;
|
||||
ino_t inumber;
|
||||
|
||||
memset(&idesc, 0, sizeof(struct inodesc));
|
||||
idesc.id_type = ADDR;
|
||||
idesc.id_func = pass1bcheck;
|
||||
duphead = duplist;
|
||||
inumber = 0;
|
||||
for (c = 0; c < sblock.fs_ncg; c++) {
|
||||
for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
|
||||
if (inumber < ROOTINO)
|
||||
continue;
|
||||
dp = ginode(inumber);
|
||||
if (dp == NULL)
|
||||
continue;
|
||||
idesc.id_number = inumber;
|
||||
if (statemap[inumber] != USTATE &&
|
||||
(ckinode(dp, &idesc) & STOP))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pass1bcheck(idesc)
|
||||
register struct inodesc *idesc;
|
||||
{
|
||||
register struct dups *dlp;
|
||||
int nfrags, res = KEEPON;
|
||||
daddr_t blkno = idesc->id_blkno;
|
||||
|
||||
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
|
||||
if (chkrange(blkno, 1))
|
||||
res = SKIP;
|
||||
for (dlp = duphead; dlp; dlp = dlp->next) {
|
||||
if (dlp->dup == blkno) {
|
||||
blkerror(idesc->id_number, "DUP", blkno);
|
||||
dlp->dup = duphead->dup;
|
||||
duphead->dup = blkno;
|
||||
duphead = duphead->next;
|
||||
}
|
||||
if (dlp == muldup)
|
||||
break;
|
||||
}
|
||||
if (muldup == 0 || duphead == muldup->next)
|
||||
return (STOP);
|
||||
}
|
||||
return (res);
|
||||
}
|
@ -1,333 +1,52 @@
|
||||
/* $NetBSD: pass5.c,v 1.2 1999/07/03 19:55:03 kleink Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)pass5.c 8.6 (Berkeley) 11/30/94";
|
||||
#else
|
||||
static char rcsid[] = "$NetBSD: pass5.c,v 1.2 1999/07/03 19:55:03 kleink Exp $";
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
/* $NetBSD: pass5.c,v 1.3 2000/05/16 04:55:59 perseant Exp $ */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <ufs/ufs/dinode.h>
|
||||
#include <ufs/ffs/fs.h>
|
||||
#include <ufs/ffs/ffs_extern.h>
|
||||
#include <string.h>
|
||||
#include <ufs/ufs/dir.h>
|
||||
#include <sys/mount.h>
|
||||
#include <ufs/lfs/lfs.h>
|
||||
|
||||
#include "fsutil.h"
|
||||
#include <string.h>
|
||||
#include "fsck.h"
|
||||
#include "extern.h"
|
||||
#include "fsutil.h"
|
||||
|
||||
extern SEGUSE *seg_table;
|
||||
|
||||
void
|
||||
pass5()
|
||||
{
|
||||
int c, blk, frags, basesize, sumsize, mapsize, savednrpos;
|
||||
register struct fs *fs = &sblock;
|
||||
register struct cg *cg = &cgrp;
|
||||
daddr_t dbase, dmax;
|
||||
register daddr_t d;
|
||||
register long i, j;
|
||||
struct csum *cs;
|
||||
struct csum cstotal;
|
||||
struct inodesc idesc[3];
|
||||
char buf[MAXBSIZE];
|
||||
register struct cg *newcg = (struct cg *)buf;
|
||||
struct ocg *ocg = (struct ocg *)buf;
|
||||
SEGUSE *su;
|
||||
struct bufarea *bp;
|
||||
int i;
|
||||
|
||||
statemap[WINO] = USTATE;
|
||||
memset(newcg, 0, (size_t)fs->fs_cgsize);
|
||||
newcg->cg_niblk = fs->fs_ipg;
|
||||
if (cvtlevel >= 3) {
|
||||
if (fs->fs_maxcontig < 2 && fs->fs_contigsumsize > 0) {
|
||||
if (preen)
|
||||
pwarn("DELETING CLUSTERING MAPS\n");
|
||||
if (preen || reply("DELETE CLUSTERING MAPS")) {
|
||||
fs->fs_contigsumsize = 0;
|
||||
doinglevel1 = 1;
|
||||
sbdirty();
|
||||
/*
|
||||
* Check segment holdings against actual holdings. Check for
|
||||
* "clean" segments that contain live data.
|
||||
*/
|
||||
for(i=0; i < sblock.lfs_nseg; i++) {
|
||||
su = lfs_gseguse(i, &bp);
|
||||
if (!(su->su_flags & SEGUSE_DIRTY) &&
|
||||
seg_table[i].su_nbytes>0)
|
||||
{
|
||||
pwarn("%d bytes contained in 'clean' segment %d\n",
|
||||
seg_table[i].su_nbytes, i);
|
||||
if(preen || reply("fix")) {
|
||||
su->su_flags |= SEGUSE_DIRTY;
|
||||
dirty(bp);
|
||||
}
|
||||
}
|
||||
if (fs->fs_maxcontig > 1) {
|
||||
char *doit = 0;
|
||||
|
||||
if (fs->fs_contigsumsize < 1) {
|
||||
doit = "CREAT";
|
||||
} else if (fs->fs_contigsumsize < fs->fs_maxcontig &&
|
||||
fs->fs_contigsumsize < FS_MAXCONTIG) {
|
||||
doit = "EXPAND";
|
||||
}
|
||||
if (doit) {
|
||||
i = fs->fs_contigsumsize;
|
||||
fs->fs_contigsumsize =
|
||||
MIN(fs->fs_maxcontig, FS_MAXCONTIG);
|
||||
if (CGSIZE(fs) > fs->fs_bsize) {
|
||||
pwarn("CANNOT %s CLUSTER MAPS\n", doit);
|
||||
fs->fs_contigsumsize = i;
|
||||
} else if (preen ||
|
||||
reply("CREATE CLUSTER MAPS")) {
|
||||
if (preen)
|
||||
pwarn("%sING CLUSTER MAPS\n",
|
||||
doit);
|
||||
fs->fs_cgsize =
|
||||
fragroundup(fs, CGSIZE(fs));
|
||||
doinglevel1 = 1;
|
||||
sbdirty();
|
||||
}
|
||||
if ((su->su_flags & SEGUSE_DIRTY) &&
|
||||
su->su_nbytes != seg_table[i].su_nbytes)
|
||||
{
|
||||
pwarn("segment %d claims %d bytes but has %d\n",
|
||||
i, su->su_nbytes, seg_table[i].su_nbytes);
|
||||
if(preen || reply("fix")) {
|
||||
su->su_nbytes = seg_table[i].su_nbytes;
|
||||
dirty(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch ((int)fs->fs_postblformat) {
|
||||
|
||||
case FS_42POSTBLFMT:
|
||||
basesize = (char *)(&ocg->cg_btot[0]) -
|
||||
(char *)(&ocg->cg_firstfield);
|
||||
sumsize = &ocg->cg_iused[0] - (u_int8_t *)(&ocg->cg_btot[0]);
|
||||
mapsize = &ocg->cg_free[howmany(fs->fs_fpg, NBBY)] -
|
||||
(u_char *)&ocg->cg_iused[0];
|
||||
ocg->cg_magic = CG_MAGIC;
|
||||
savednrpos = fs->fs_nrpos;
|
||||
fs->fs_nrpos = 8;
|
||||
break;
|
||||
|
||||
case FS_DYNAMICPOSTBLFMT:
|
||||
newcg->cg_btotoff =
|
||||
&newcg->cg_space[0] - (u_char *)(&newcg->cg_firstfield);
|
||||
newcg->cg_boff =
|
||||
newcg->cg_btotoff + fs->fs_cpg * sizeof(int32_t);
|
||||
newcg->cg_iusedoff = newcg->cg_boff +
|
||||
fs->fs_cpg * fs->fs_nrpos * sizeof(int16_t);
|
||||
newcg->cg_freeoff =
|
||||
newcg->cg_iusedoff + howmany(fs->fs_ipg, NBBY);
|
||||
if (fs->fs_contigsumsize <= 0) {
|
||||
newcg->cg_nextfreeoff = newcg->cg_freeoff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY);
|
||||
} else {
|
||||
newcg->cg_clustersumoff = newcg->cg_freeoff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY) -
|
||||
sizeof(int32_t);
|
||||
newcg->cg_clustersumoff =
|
||||
roundup(newcg->cg_clustersumoff, sizeof(int32_t));
|
||||
newcg->cg_clusteroff = newcg->cg_clustersumoff +
|
||||
(fs->fs_contigsumsize + 1) * sizeof(int32_t);
|
||||
newcg->cg_nextfreeoff = newcg->cg_clusteroff +
|
||||
howmany(fs->fs_cpg * fs->fs_spc / NSPB(fs), NBBY);
|
||||
}
|
||||
newcg->cg_magic = CG_MAGIC;
|
||||
basesize = &newcg->cg_space[0] -
|
||||
(u_char *)(&newcg->cg_firstfield);
|
||||
sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
|
||||
mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
|
||||
break;
|
||||
|
||||
default:
|
||||
errexit("UNKNOWN ROTATIONAL TABLE FORMAT %d\n",
|
||||
fs->fs_postblformat);
|
||||
}
|
||||
memset(&idesc[0], 0, sizeof idesc);
|
||||
for (i = 0; i < 3; i++) {
|
||||
idesc[i].id_type = ADDR;
|
||||
if (doinglevel2)
|
||||
idesc[i].id_fix = FIX;
|
||||
}
|
||||
memset(&cstotal, 0, sizeof(struct csum));
|
||||
j = blknum(fs, fs->fs_size + fs->fs_frag - 1);
|
||||
for (i = fs->fs_size; i < j; i++)
|
||||
setbmap(i);
|
||||
for (c = 0; c < fs->fs_ncg; c++) {
|
||||
getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize);
|
||||
if (!cg_chkmagic(cg))
|
||||
pfatal("CG %d: BAD MAGIC NUMBER\n", c);
|
||||
dbase = cgbase(fs, c);
|
||||
dmax = dbase + fs->fs_fpg;
|
||||
if (dmax > fs->fs_size)
|
||||
dmax = fs->fs_size;
|
||||
newcg->cg_time = cg->cg_time;
|
||||
newcg->cg_cgx = c;
|
||||
if (c == fs->fs_ncg - 1)
|
||||
newcg->cg_ncyl = fs->fs_ncyl % fs->fs_cpg;
|
||||
else
|
||||
newcg->cg_ncyl = fs->fs_cpg;
|
||||
newcg->cg_ndblk = dmax - dbase;
|
||||
if (fs->fs_contigsumsize > 0)
|
||||
newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag;
|
||||
newcg->cg_cs.cs_ndir = 0;
|
||||
newcg->cg_cs.cs_nffree = 0;
|
||||
newcg->cg_cs.cs_nbfree = 0;
|
||||
newcg->cg_cs.cs_nifree = fs->fs_ipg;
|
||||
if (cg->cg_rotor < newcg->cg_ndblk)
|
||||
newcg->cg_rotor = cg->cg_rotor;
|
||||
else
|
||||
newcg->cg_rotor = 0;
|
||||
if (cg->cg_frotor < newcg->cg_ndblk)
|
||||
newcg->cg_frotor = cg->cg_frotor;
|
||||
else
|
||||
newcg->cg_frotor = 0;
|
||||
if (cg->cg_irotor < newcg->cg_niblk)
|
||||
newcg->cg_irotor = cg->cg_irotor;
|
||||
else
|
||||
newcg->cg_irotor = 0;
|
||||
memset(&newcg->cg_frsum[0], 0, sizeof newcg->cg_frsum);
|
||||
memset(&cg_blktot(newcg)[0], 0,
|
||||
(size_t)(sumsize + mapsize));
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
ocg->cg_magic = CG_MAGIC;
|
||||
j = fs->fs_ipg * c;
|
||||
for (i = 0; i < fs->fs_ipg; j++, i++) {
|
||||
switch (statemap[j]) {
|
||||
|
||||
case USTATE:
|
||||
break;
|
||||
|
||||
case DSTATE:
|
||||
case DCLEAR:
|
||||
case DFOUND:
|
||||
newcg->cg_cs.cs_ndir++;
|
||||
/* fall through */
|
||||
|
||||
case FSTATE:
|
||||
case FCLEAR:
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
setbit(cg_inosused(newcg), i);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (j < ROOTINO)
|
||||
break;
|
||||
errexit("BAD STATE %d FOR INODE I=%ld",
|
||||
statemap[j], j);
|
||||
}
|
||||
}
|
||||
if (c == 0)
|
||||
for (i = 0; i < ROOTINO; i++) {
|
||||
setbit(cg_inosused(newcg), i);
|
||||
newcg->cg_cs.cs_nifree--;
|
||||
}
|
||||
for (i = 0, d = dbase;
|
||||
d < dmax;
|
||||
d += fs->fs_frag, i += fs->fs_frag) {
|
||||
frags = 0;
|
||||
for (j = 0; j < fs->fs_frag; j++) {
|
||||
if (testbmap(d + j))
|
||||
continue;
|
||||
setbit(cg_blksfree(newcg), i + j);
|
||||
frags++;
|
||||
}
|
||||
if (frags == fs->fs_frag) {
|
||||
newcg->cg_cs.cs_nbfree++;
|
||||
j = cbtocylno(fs, i);
|
||||
cg_blktot(newcg)[j]++;
|
||||
cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++;
|
||||
if (fs->fs_contigsumsize > 0)
|
||||
setbit(cg_clustersfree(newcg),
|
||||
i / fs->fs_frag);
|
||||
} else if (frags > 0) {
|
||||
newcg->cg_cs.cs_nffree += frags;
|
||||
blk = blkmap(fs, cg_blksfree(newcg), i);
|
||||
ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
|
||||
}
|
||||
}
|
||||
if (fs->fs_contigsumsize > 0) {
|
||||
int32_t *sump = cg_clustersum(newcg);
|
||||
u_char *mapp = cg_clustersfree(newcg);
|
||||
int map = *mapp++;
|
||||
int bit = 1;
|
||||
int run = 0;
|
||||
|
||||
for (i = 0; i < newcg->cg_nclusterblks; i++) {
|
||||
if ((map & bit) != 0) {
|
||||
run++;
|
||||
} else if (run != 0) {
|
||||
if (run > fs->fs_contigsumsize)
|
||||
run = fs->fs_contigsumsize;
|
||||
sump[run]++;
|
||||
run = 0;
|
||||
}
|
||||
if ((i & (NBBY - 1)) != (NBBY - 1)) {
|
||||
bit <<= 1;
|
||||
} else {
|
||||
map = *mapp++;
|
||||
bit = 1;
|
||||
}
|
||||
}
|
||||
if (run != 0) {
|
||||
if (run > fs->fs_contigsumsize)
|
||||
run = fs->fs_contigsumsize;
|
||||
sump[run]++;
|
||||
}
|
||||
}
|
||||
cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
|
||||
cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
|
||||
cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
|
||||
cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
|
||||
cs = &fs->fs_cs(fs, c);
|
||||
if (memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 &&
|
||||
dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
memcpy(cs, &newcg->cg_cs, sizeof *cs);
|
||||
sbdirty();
|
||||
}
|
||||
if (doinglevel1) {
|
||||
memcpy(cg, newcg, (size_t)fs->fs_cgsize);
|
||||
cgdirty();
|
||||
continue;
|
||||
}
|
||||
if (memcmp(cg_inosused(newcg),
|
||||
cg_inosused(cg), mapsize) != 0 &&
|
||||
dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
|
||||
memcpy(cg_inosused(cg), cg_inosused(newcg),
|
||||
(size_t)mapsize);
|
||||
cgdirty();
|
||||
}
|
||||
if ((memcmp(newcg, cg, basesize) != 0 ||
|
||||
memcmp(&cg_blktot(newcg)[0],
|
||||
&cg_blktot(cg)[0], sumsize) != 0) &&
|
||||
dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
|
||||
memcpy(cg, newcg, (size_t)basesize);
|
||||
memcpy(&cg_blktot(cg)[0],
|
||||
&cg_blktot(newcg)[0], (size_t)sumsize);
|
||||
cgdirty();
|
||||
}
|
||||
}
|
||||
if (fs->fs_postblformat == FS_42POSTBLFMT)
|
||||
fs->fs_nrpos = savednrpos;
|
||||
if (memcmp(&cstotal, &fs->fs_cstotal, sizeof *cs) != 0
|
||||
&& dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
|
||||
memcpy(&fs->fs_cstotal, &cstotal, sizeof *cs);
|
||||
fs->fs_ronly = 0;
|
||||
fs->fs_fmod = 0;
|
||||
sbdirty();
|
||||
bp->b_flags &= ~B_INUSE;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: setup.c,v 1.3 1999/07/03 19:55:03 kleink Exp $ */
|
||||
/* $NetBSD: setup.c,v 1.4 2000/05/16 04:55:59 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
@ -59,8 +59,8 @@
|
||||
#include "fsutil.h"
|
||||
|
||||
struct bufarea asblk;
|
||||
extern struct dinode **din_table;
|
||||
extern SEGUSE *seg_table;
|
||||
daddr_t *din_table;
|
||||
SEGUSE *seg_table;
|
||||
#define altsblock (*asblk.b_un.b_fs)
|
||||
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
|
||||
|
||||
@ -70,6 +70,8 @@ static struct disklabel *getdisklabel __P((const char *, int));
|
||||
static int readsb __P((int));
|
||||
int lfs_maxino(void);
|
||||
|
||||
static daddr_t try_verify(struct lfs *, struct lfs *);
|
||||
|
||||
#ifdef DKTYPENAMES
|
||||
int useless __P((void));
|
||||
|
||||
@ -83,6 +85,48 @@ useless(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static daddr_t
|
||||
try_verify(struct lfs *osb, struct lfs *nsb)
|
||||
{
|
||||
daddr_t daddr;
|
||||
SEGSUM *sp;
|
||||
char summary[LFS_SUMMARY_SIZE];
|
||||
int bc, flag;
|
||||
|
||||
daddr = osb->lfs_offset;
|
||||
while(daddr != nsb->lfs_offset) {
|
||||
flag = 0;
|
||||
oncemore:
|
||||
/* Read in summary block */
|
||||
bread(fsreadfd, summary, daddr, LFS_SUMMARY_SIZE);
|
||||
sp = (SEGSUM *)summary;
|
||||
|
||||
/*
|
||||
* Could be a superblock instead of a segment summary.
|
||||
* XXX should use gseguse, but right now we need to do more
|
||||
* setup before we can...fix this
|
||||
*/
|
||||
if(sp->ss_magic != SS_MAGIC ||
|
||||
sp->ss_sumsum != cksum(&sp->ss_datasum, LFS_SUMMARY_SIZE -
|
||||
sizeof(sp->ss_sumsum)))
|
||||
{
|
||||
if(flag==0) {
|
||||
daddr += LFS_SBPAD/dev_bsize;
|
||||
goto oncemore;
|
||||
}
|
||||
return 0x0;
|
||||
}
|
||||
bc = check_summary(osb, sp, daddr);
|
||||
if(bc==0)
|
||||
break;
|
||||
daddr += (LFS_SUMMARY_SIZE + bc) / dev_bsize;
|
||||
if(datosn(osb,daddr) != datosn(osb, daddr + (LFS_SUMMARY_SIZE+(1<<osb->lfs_bshift))/dev_bsize)) {
|
||||
daddr = ((SEGSUM *)summary)->ss_next;
|
||||
}
|
||||
}
|
||||
return daddr;
|
||||
}
|
||||
|
||||
int
|
||||
setup(dev)
|
||||
const char *dev;
|
||||
@ -94,10 +138,12 @@ setup(dev)
|
||||
off_t sizepb;
|
||||
#endif
|
||||
struct stat statb;
|
||||
daddr_t daddr;
|
||||
struct lfs proto;
|
||||
int doskipclean;
|
||||
u_int64_t maxfilesize;
|
||||
struct lfs *sb0;
|
||||
struct lfs *sb0, *sb1, *osb, *nsb;
|
||||
struct dinode *idinode;
|
||||
|
||||
havesb = 0;
|
||||
fswritefd = -1;
|
||||
@ -169,6 +215,9 @@ setup(dev)
|
||||
doskipclean = 0;
|
||||
pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
|
||||
}
|
||||
|
||||
bufinit();
|
||||
|
||||
if(bflag==0) {
|
||||
/*
|
||||
* Even if that superblock read in properly, it may not
|
||||
@ -177,26 +226,50 @@ setup(dev)
|
||||
* of the two is *less* recent. --ks
|
||||
*/
|
||||
sb0 = malloc(sizeof(*sb0));
|
||||
sb1 = malloc(sizeof(*sb1));
|
||||
memcpy(sb0,&sblock,sizeof(*sb0));
|
||||
bflag = sblock.lfs_sboffs[1];
|
||||
if(readsb(1)==0) {
|
||||
pwarn("COULDN'T READ ALT SUPERBLOCK AT BLK %d",bflag);
|
||||
if (reply("ASSUME PRIMARY SUPERBLOCK IS GOOD") == 0) {
|
||||
return (0);
|
||||
} else { /* use primary as good */
|
||||
memcpy(&sblock,sb0,sizeof(*sb0)); /* XXX cheating? */
|
||||
}
|
||||
} else {
|
||||
if(debug)
|
||||
pwarn("sb0 %d, sb1 %d\n",sb0->lfs_tstamp,sblock.lfs_tstamp);
|
||||
if(sblock.lfs_tstamp >= sb0->lfs_tstamp) {
|
||||
memcpy(&sblock,sb0,sizeof(*sb0)); /* XXX cheating? */
|
||||
bflag = sblock.lfs_sboffs[1];
|
||||
if(readsb(1)==0) {
|
||||
pwarn("COULDN'T READ ALT SUPERBLOCK AT BLK %d",bflag);
|
||||
if (reply("ASSUME PRIMARY SUPERBLOCK IS GOOD") == 0) {
|
||||
return (0);
|
||||
} else { /* use primary as good */
|
||||
memcpy(&sblock,sb0,sizeof(*sb0)); /* XXX cheating? */
|
||||
}
|
||||
} else {
|
||||
memcpy(sb1,&sblock,sizeof(*sb1));
|
||||
if(debug)
|
||||
pwarn("sb0 %d, sb1 %d\n",sb0->lfs_tstamp,sblock.lfs_tstamp);
|
||||
/*
|
||||
* Verify the checkpoint of the newer superblock,
|
||||
* if the timestamp of the two superblocks is
|
||||
* different. XXX use lfs_offset instead, discover
|
||||
* how to quickly discover "newness" based on that.
|
||||
*/
|
||||
if(sb0->lfs_tstamp != sb1->lfs_tstamp) {
|
||||
if(sb0->lfs_tstamp > sb1->lfs_tstamp) {
|
||||
osb = sb1;
|
||||
nsb = sb0;
|
||||
} else {
|
||||
pwarn("Using alt superblock, disk addr 0x%x\n",
|
||||
bflag);
|
||||
osb = sb0;
|
||||
nsb = sb1;
|
||||
}
|
||||
daddr = try_verify(osb, nsb);
|
||||
|
||||
if (debug)
|
||||
printf("done.\n");
|
||||
if (daddr == nsb->lfs_offset) {
|
||||
pwarn("Checkpoint verified, recovered %d seconds of data\n", nsb->lfs_tstamp - osb->lfs_tstamp);
|
||||
memcpy(&sblock,nsb,sizeof(*nsb));
|
||||
sbdirty();
|
||||
} else {
|
||||
pwarn("Checkpoint invalid, lost %d seconds of data\n", nsb->lfs_tstamp - osb->lfs_tstamp);
|
||||
memcpy(&sblock,osb,sizeof(*osb));
|
||||
}
|
||||
}
|
||||
}
|
||||
free(sb0);
|
||||
free(sb1);
|
||||
}
|
||||
if(debug) {
|
||||
printf("dev_bsize = %lu\n",dev_bsize);
|
||||
@ -233,11 +306,14 @@ setup(dev)
|
||||
printf("Couldn't read disk block %d\n",sblock.lfs_idaddr);
|
||||
exit(1);
|
||||
}
|
||||
maxino = lfs_maxino();
|
||||
idinode = lfs_difind(&sblock,sblock.lfs_ifile,&ifblock);
|
||||
maxino = ((idinode->di_size
|
||||
- (sblock.lfs_cleansz + sblock.lfs_segtabsz) * sblock.lfs_bsize)
|
||||
/ sblock.lfs_bsize) * sblock.lfs_ifpb - 1;
|
||||
#endif
|
||||
if (debug)
|
||||
printf("maxino=%d\n",maxino);
|
||||
din_table = (struct dinode **)malloc(maxino*sizeof(*din_table));
|
||||
din_table = (daddr_t *)malloc(maxino*sizeof(*din_table));
|
||||
memset(din_table,0,maxino*sizeof(*din_table));
|
||||
seg_table = (SEGUSE *)malloc(sblock.lfs_nseg * sizeof(SEGUSE));
|
||||
memset(seg_table,0,sblock.lfs_nseg * sizeof(SEGUSE));
|
||||
@ -367,7 +443,6 @@ u_quad_t maxtable[] = {
|
||||
(unsigned long)(maxino + 1) * sizeof(int16_t));
|
||||
goto badsblabel;
|
||||
}
|
||||
bufinit();
|
||||
return (1);
|
||||
|
||||
badsblabel:
|
||||
@ -531,24 +606,28 @@ calcsb(dev, devfd, fs)
|
||||
return (0);
|
||||
}
|
||||
lp = getdisklabel(dev, devfd);
|
||||
if (isdigit(*cp))
|
||||
pp = &lp->d_partitions[0];
|
||||
else
|
||||
pp = &lp->d_partitions[*cp - 'a'];
|
||||
if (pp->p_fstype != FS_BSDLFS) {
|
||||
pfatal("%s: NOT LABELED AS AN LFS FILE SYSTEM (%s)\n",
|
||||
dev, pp->p_fstype < FSMAXTYPES ?
|
||||
fstypenames[pp->p_fstype] : "unknown");
|
||||
return (0);
|
||||
if(lp==NULL) {
|
||||
dev_bsize = DEV_BSIZE;
|
||||
} else {
|
||||
if (isdigit(*cp))
|
||||
pp = &lp->d_partitions[0];
|
||||
else
|
||||
pp = &lp->d_partitions[*cp - 'a'];
|
||||
if (pp->p_fstype != FS_BSDLFS) {
|
||||
pfatal("%s: NOT LABELED AS AN LFS FILE SYSTEM (%s)\n",
|
||||
dev, pp->p_fstype < FSMAXTYPES ?
|
||||
fstypenames[pp->p_fstype] : "unknown");
|
||||
return (0);
|
||||
}
|
||||
memset(fs, 0, sizeof(struct lfs));
|
||||
fs->lfs_fsize = pp->p_fsize;
|
||||
fs->lfs_frag = pp->p_frag;
|
||||
fs->lfs_size = pp->p_size;
|
||||
fs->lfs_nspf = fs->lfs_fsize / lp->d_secsize;
|
||||
dev_bsize = lp->d_secsize;
|
||||
for (fs->lfs_fsbtodb = 0, i = fs->lfs_nspf; i > 1; i >>= 1)
|
||||
fs->lfs_fsbtodb++;
|
||||
}
|
||||
memset(fs, 0, sizeof(struct lfs));
|
||||
fs->lfs_fsize = pp->p_fsize;
|
||||
fs->lfs_frag = pp->p_frag;
|
||||
fs->lfs_size = pp->p_size;
|
||||
fs->lfs_nspf = fs->lfs_fsize / lp->d_secsize;
|
||||
dev_bsize = lp->d_secsize;
|
||||
for (fs->lfs_fsbtodb = 0, i = fs->lfs_nspf; i > 1; i >>= 1)
|
||||
fs->lfs_fsbtodb++;
|
||||
return (1);
|
||||
}
|
||||
|
||||
@ -563,7 +642,11 @@ getdisklabel(s, fd)
|
||||
if (s == NULL)
|
||||
return ((struct disklabel *)NULL);
|
||||
pwarn("ioctl (GCINFO): %s\n", strerror(errno));
|
||||
#if 0
|
||||
errexit("%s: can't read disk label\n", s);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
return (&lab);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: utilities.c,v 1.2 1999/07/03 19:55:03 kleink Exp $ */
|
||||
/* $NetBSD: utilities.c,v 1.3 2000/05/16 04:56:00 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
@ -266,12 +266,27 @@ ckfini(markclean)
|
||||
return;
|
||||
}
|
||||
flush(fswritefd, &sblk);
|
||||
if (havesb && sblk.b_bno != LFS_SBPAD / dev_bsize &&
|
||||
!preen && reply("UPDATE STANDARD SUPERBLOCK")) {
|
||||
sblk.b_bno = LFS_SBPAD / dev_bsize;
|
||||
if (havesb && sblk.b_bno != LFS_LABELPAD / dev_bsize &&
|
||||
sblk.b_bno != sblock.lfs_sboffs[0] &&
|
||||
!preen && reply("UPDATE STANDARD SUPERBLOCKS")) {
|
||||
sblk.b_bno = LFS_LABELPAD / dev_bsize;
|
||||
sbdirty();
|
||||
flush(fswritefd, &sblk);
|
||||
}
|
||||
if (havesb) {
|
||||
if(sblk.b_bno == LFS_LABELPAD / dev_bsize) {
|
||||
/* Do the first alternate */
|
||||
sblk.b_bno = sblock.lfs_sboffs[1];
|
||||
sbdirty();
|
||||
flush(fswritefd, &sblk);
|
||||
} else if(sblk.b_bno == sblock.lfs_sboffs[1]) {
|
||||
/* Do the primary */
|
||||
sblk.b_bno = LFS_LABELPAD / dev_bsize;
|
||||
sbdirty();
|
||||
flush(fswritefd, &sblk);
|
||||
}
|
||||
}
|
||||
|
||||
/* flush(fswritefd, &cgblk); */
|
||||
/* free(cgblk.b_un.b_buf); */
|
||||
for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
|
||||
@ -284,8 +299,7 @@ ckfini(markclean)
|
||||
if (bufhead.b_size != cnt)
|
||||
errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
|
||||
pbp = pdirbp = (struct bufarea *)0;
|
||||
#if 0 /* FFS */
|
||||
if (markclean && (sblock.lfs_clean & FS_ISCLEAN) == 0) {
|
||||
if (markclean && sblock.lfs_clean == 0) {
|
||||
/*
|
||||
* Mark the file system as clean, and sync the superblock.
|
||||
*/
|
||||
@ -294,12 +308,20 @@ ckfini(markclean)
|
||||
else if (!reply("MARK FILE SYSTEM CLEAN"))
|
||||
markclean = 0;
|
||||
if (markclean) {
|
||||
sblock.lfs_clean = FS_ISCLEAN;
|
||||
sblock.lfs_clean = 1;
|
||||
sbdirty();
|
||||
flush(fswritefd, &sblk);
|
||||
if(sblk.b_bno == LFS_LABELPAD / dev_bsize) {
|
||||
/* Do the first alternate */
|
||||
sblk.b_bno = sblock.lfs_sboffs[0];
|
||||
flush(fswritefd, &sblk);
|
||||
} else if(sblk.b_bno == sblock.lfs_sboffs[0]) {
|
||||
/* Do the primary */
|
||||
sblk.b_bno = LFS_LABELPAD / dev_bsize;
|
||||
flush(fswritefd, &sblk);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (debug)
|
||||
printf("cache missed %ld of %ld (%d%%)\n", diskreads,
|
||||
totalreads, (int)(diskreads * 100 / totalreads));
|
||||
@ -389,6 +411,13 @@ int
|
||||
allocblk(frags)
|
||||
long frags;
|
||||
{
|
||||
#if 1
|
||||
/*
|
||||
* XXX Can't allocate blocks right now because we would have to do
|
||||
* a full partial segment write.
|
||||
*/
|
||||
return 0;
|
||||
#else /* 0 */
|
||||
register int i, j, k;
|
||||
|
||||
if (frags <= 0 || frags > sblock.lfs_frag)
|
||||
@ -416,6 +445,7 @@ allocblk(frags)
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
#endif /* 0 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: disklabel.h,v 1.59 2000/05/03 18:28:46 jdolecek Exp $ */
|
||||
/* $NetBSD: disklabel.h,v 1.60 2000/05/16 04:55:58 perseant Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1987, 1988, 1993
|
||||
@ -283,7 +283,7 @@ static const char *const fscknames[] = {
|
||||
NULL, /* Eighth edition */
|
||||
"ffs", /* 4.2BSD */
|
||||
"msdos", /* MSDOS */
|
||||
NULL, /* 4.4LFS */
|
||||
"lfs", /* 4.4LFS */
|
||||
NULL, /* unknown */
|
||||
NULL, /* HPFS */
|
||||
NULL, /* ISO9660 */
|
||||
|
Loading…
Reference in New Issue
Block a user