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:
perseant 2000-05-16 04:55:58 +00:00
parent 6047a12c7b
commit e6c7065240
12 changed files with 560 additions and 828 deletions

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -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--;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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 {

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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 */
}
/*

View File

@ -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 */