From e6c70652400eca73a3e262912cb2cd16c0b7a38e Mon Sep 17 00:00:00 2001 From: perseant Date: Tue, 16 May 2000 04:55:58 +0000 Subject: [PATCH] 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. --- sbin/fsck_lfs/Makefile | 11 +- sbin/fsck_lfs/fsck.h | 8 +- sbin/fsck_lfs/fsck_lfs.8 | 21 +-- sbin/fsck_lfs/inode.c | 184 +++++++++++--------- sbin/fsck_lfs/main.c | 174 ++++++------------- sbin/fsck_lfs/pass0.c | 227 +++++++++++++------------ sbin/fsck_lfs/pass1.c | 102 +++++++---- sbin/fsck_lfs/pass1b.c | 101 ----------- sbin/fsck_lfs/pass5.c | 349 ++++---------------------------------- sbin/fsck_lfs/setup.c | 161 +++++++++++++----- sbin/fsck_lfs/utilities.c | 46 ++++- sys/sys/disklabel.h | 4 +- 12 files changed, 560 insertions(+), 828 deletions(-) delete mode 100644 sbin/fsck_lfs/pass1b.c diff --git a/sbin/fsck_lfs/Makefile b/sbin/fsck_lfs/Makefile index 17d1856a4ed3..7e28cb91709d 100644 --- a/sbin/fsck_lfs/Makefile +++ b/sbin/fsck_lfs/Makefile @@ -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 diff --git a/sbin/fsck_lfs/fsck.h b/sbin/fsck_lfs/fsck.h index 74746231af00..70372b28573e 100644 --- a/sbin/fsck_lfs/fsck.h +++ b/sbin/fsck_lfs/fsck.h @@ -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" diff --git a/sbin/fsck_lfs/fsck_lfs.8 b/sbin/fsck_lfs/fsck_lfs.8 index 92d9e536e1c7..ee7570aa7b47 100644 --- a/sbin/fsck_lfs/fsck_lfs.8 +++ b/sbin/fsck_lfs/fsck_lfs.8 @@ -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 diff --git a/sbin/fsck_lfs/inode.c b/sbin/fsck_lfs/inode.c index 394b2bc85531..c1449ea55266 100644 --- a/sbin/fsck_lfs/inode.c +++ b/sbin/fsck_lfs/inode.c @@ -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--; } diff --git a/sbin/fsck_lfs/main.c b/sbin/fsck_lfs/main.c index 1194d159c083..07e8d06d5c9a 100644 --- a/sbin/fsck_lfs/main.c +++ b/sbin/fsck_lfs/main.c @@ -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); diff --git a/sbin/fsck_lfs/pass0.c b/sbin/fsck_lfs/pass0.c index 627382841c65..9829cf7fbb86 100644 --- a/sbin/fsck_lfs/pass0.c +++ b/sbin/fsck_lfs/pass0.c @@ -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;iif_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; iss_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(iss_ninos) - { - if(*dp < seg_addr || *dp > seg_addr + (sblock.lfs_ssize<lfs_bshift)); - ip = (struct dinode *)bp->b_un.b_buf; - for(j=0; iss_ninos && j 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; iss_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; jfi_nblocks; j++) { - /* XXX check values against inodes' known block size */ - dp++; - } - fp = (FINFO *)dp; + for(i=0, j=0; iss_nfinfo || jss_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<lfs_bshift)); + datap[datac++] = ((u_long *)(bp->b_un.b_buf))[0]; + bp->b_flags &= ~B_INUSE; + + ++j; + daddr += (1<lfs_bshift)/dev_bsize; + --idp; + } + if(i < sp->ss_nfinfo) { + for(k=0; kfi_nblocks; k++) { + len = (k==fp->fi_nblocks - 1 ? fp->fi_lastlength + : (1<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; } diff --git a/sbin/fsck_lfs/pass1.c b/sbin/fsck_lfs/pass1.c index 6b4eb62d187e..c2b24560e1d6 100644 --- a/sbin/fsck_lfs/pass1.c +++ b/sbin/fsck_lfs/pass1.c @@ -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 { diff --git a/sbin/fsck_lfs/pass1b.c b/sbin/fsck_lfs/pass1b.c deleted file mode 100644 index 820123e5fa2f..000000000000 --- a/sbin/fsck_lfs/pass1b.c +++ /dev/null @@ -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 -#include -#include -#include - -#include -#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); -} diff --git a/sbin/fsck_lfs/pass5.c b/sbin/fsck_lfs/pass5.c index f4529198e8e1..83735a6b972c 100644 --- a/sbin/fsck_lfs/pass5.c +++ b/sbin/fsck_lfs/pass5.c @@ -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 #include #include -#include -#include -#include +#include +#include +#include -#include "fsutil.h" +#include #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; } } diff --git a/sbin/fsck_lfs/setup.c b/sbin/fsck_lfs/setup.c index 046e4229cfbe..a4e16c7748eb 100644 --- a/sbin/fsck_lfs/setup.c +++ b/sbin/fsck_lfs/setup.c @@ -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<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); } diff --git a/sbin/fsck_lfs/utilities.c b/sbin/fsck_lfs/utilities.c index a3d49e70cda5..536f358b8d5a 100644 --- a/sbin/fsck_lfs/utilities.c +++ b/sbin/fsck_lfs/utilities.c @@ -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 */ } /* diff --git a/sys/sys/disklabel.h b/sys/sys/disklabel.h index 774b29f161b9..ca9f4d58432d 100644 --- a/sys/sys/disklabel.h +++ b/sys/sys/disklabel.h @@ -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 */