Add working writing ability to fsck_lfs, including roll-forward, based on

a partial-segment writer ported from the kernel.
This commit is contained in:
perseant 2003-03-28 08:09:52 +00:00
parent 3f7016035a
commit ba10361ab2
26 changed files with 4701 additions and 2466 deletions

View File

@ -1,15 +1,15 @@
# $NetBSD: Makefile,v 1.5 2002/08/19 10:16:53 lukem Exp $
# $NetBSD: Makefile,v 1.6 2003/03/28 08:09:52 perseant Exp $
# @(#)Makefile 8.1 (Berkeley) 6/5/93
.include <bsd.own.mk>
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
SRCS+= pass0.c pass5.c
FSCK= ${NETBSDSRCDIR}/sbin/fsck
SRCS= bufcache.c dir.c fsutil.c inode.c lfs.c lfs_cksum.c main.c
SRCS+= pass0.c pass1.c pass2.c pass3.c pass4.c pass5.c pass6.c
SRCS+= segwrite.c setup.c utilities.c vars.c vnode.c
FSCK= ${NETBSDSRCDIR}/sbin/fsck
.PATH: ${NETBSDSRCDIR}/sys/ufs/lfs ${FSCK}
CPPFLAGS+=-I${FSCK} # -DVERBOSE_BLOCKMAP
CPPFLAGS+=-I${FSCK} # -DNDEBUG # -DVERBOSE_BLOCKMAP
.include <bsd.prog.mk>

316
sbin/fsck_lfs/bufcache.c Normal file
View File

@ -0,0 +1,316 @@
/* $NetBSD: bufcache.c,v 1.1 2003/03/28 08:09:52 perseant Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/buf.h>
#include <sys/queue.h>
#include <sys/mount.h>
#include <assert.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bufcache.h"
#include "vnode.h"
/*
* Definitions for the buffer free lists.
*/
#define BQUEUES 3 /* number of free buffer queues */
#define BQ_LOCKED 0 /* super-blocks &c */
#define BQ_LRU 1 /* lru, useful buffers */
#define BQ_AGE 2 /* rubbish */
TAILQ_HEAD(bqueues, ubuf) bufqueues[BQUEUES];
#define HASH_MAX 101
struct bufhash_struct bufhash[HASH_MAX];
int maxbufs = BUF_CACHE_SIZE;
int nbufs = 0;
int cachehits = 0;
int cachemisses = 0;
int hashmax = 0;
off_t locked_queue_bytes = 0;
/* Simple buffer hash function */
static int
vl_hash(struct uvnode * vp, daddr_t lbn)
{
return (int)((unsigned long) vp + lbn) % HASH_MAX;
}
/* Initialize buffer cache */
void
bufinit(void)
{
int i;
for (i = 0; i < BQUEUES; i++) {
TAILQ_INIT(&bufqueues[i]);
}
for (i = 0; i < HASH_MAX; i++)
LIST_INIT(&bufhash[HASH_MAX]);
}
/* Print statistics of buffer cache usage */
void
bufstats(void)
{
printf("buffer cache: %d hits %d misses (%2.2f%%); hash depth %d\n",
cachehits, cachemisses,
(cachehits * 100.0) / (cachehits + cachemisses),
hashmax);
}
/*
* Remove a buffer from the cache.
* Caller must remove the buffer from its free list.
*/
void
buf_destroy(struct ubuf * bp)
{
bp->b_flags |= B_NEEDCOMMIT;
LIST_REMOVE(bp, b_vnbufs);
LIST_REMOVE(bp, b_hash);
free(bp->b_data);
free(bp);
--nbufs;
}
/* Remove a buffer from its free list. */
void
bremfree(struct ubuf * bp)
{
struct bqueues *dp = NULL;
/*
* We only calculate the head of the freelist when removing
* the last element of the list as that is the only time that
* it is needed (e.g. to reset the tail pointer).
*
* NB: This makes an assumption about how tailq's are implemented.
*/
if (bp->b_flags & B_LOCKED)
locked_queue_bytes -= bp->b_bcount;
if (TAILQ_NEXT(bp, b_freelist) == NULL) {
for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++)
if (dp->tqh_last == &bp->b_freelist.tqe_next)
break;
if (dp == &bufqueues[BQUEUES])
errx(1, "bremfree: lost tail");
}
++bp->b_vp->v_usecount;
TAILQ_REMOVE(dp, bp, b_freelist);
}
/* Return a buffer if it is in the cache, otherwise return NULL. */
struct ubuf *
incore(struct uvnode * vp, int lbn)
{
struct ubuf *bp;
int hash, depth;
hash = vl_hash(vp, lbn);
/* XXX use a real hash instead. */
depth = 0;
LIST_FOREACH(bp, &bufhash[hash], b_hash) {
if (++depth > hashmax)
hashmax = depth;
if (bp->b_vp == vp && bp->b_lblkno == lbn) {
return bp;
}
}
return NULL;
}
/*
* Return a buffer of the given size, lbn and uvnode.
* If none is in core, make a new one.
*/
struct ubuf *
getblk(struct uvnode * vp, daddr_t lbn, int size)
{
struct ubuf *bp;
/*
* First check the buffer cache lists.
*/
if ((bp = incore(vp, lbn)) != NULL) {
assert(!(bp->b_flags & B_NEEDCOMMIT));
assert(!(bp->b_flags & B_BUSY));
assert(bp->b_bcount == size);
bp->b_flags |= B_BUSY;
bremfree(bp);
return bp;
}
/*
* Not on the list.
* Get a new block of the appropriate size and use that.
* If not enough space, free blocks from the AGE and LRU lists
* to make room.
*/
while (nbufs >= maxbufs) {
bp = TAILQ_FIRST(&bufqueues[BQ_AGE]);
if (bp)
TAILQ_REMOVE(&bufqueues[BQ_AGE], bp, b_freelist);
if (bp == NULL) {
bp = TAILQ_FIRST(&bufqueues[BQ_LRU]);
if (bp)
TAILQ_REMOVE(&bufqueues[BQ_AGE], bp,
b_freelist);
}
if (bp) {
if (bp->b_flags & B_DELWRI)
VOP_STRATEGY(bp);
buf_destroy(bp);
}
#ifdef DEBUG
else {
warnx("no free buffers, allocating more than %d",
maxbufs);
}
#endif
}
++nbufs;
bp = (struct ubuf *) malloc(sizeof(*bp));
memset(bp, 0, sizeof(*bp));
bp->b_data = malloc(size);
memset(bp->b_data, 0, size);
bp->b_vp = vp;
bp->b_blkno = bp->b_lblkno = lbn;
bp->b_bcount = size;
LIST_INSERT_HEAD(&bufhash[vl_hash(vp, lbn)], bp, b_hash);
LIST_INSERT_HEAD(&vp->v_cleanblkhd, bp, b_vnbufs);
bp->b_flags = B_BUSY;
return bp;
}
/* Write a buffer to disk according to its strategy routine. */
void
bwrite(struct ubuf * bp)
{
bp->b_flags &= ~(B_READ | B_DONE | B_DELWRI | B_LOCKED);
VOP_STRATEGY(bp);
bp->b_flags |= B_DONE;
reassignbuf(bp, bp->b_vp);
brelse(bp);
}
/* Put a buffer back on its free list, clear B_BUSY. */
void
brelse(struct ubuf * bp)
{
int age;
assert(!(bp->b_flags & B_NEEDCOMMIT));
assert(bp->b_flags & B_BUSY);
age = bp->b_flags & B_AGE;
bp->b_flags &= ~(B_BUSY | B_AGE);
if (bp->b_flags & B_INVAL) {
buf_destroy(bp);
return;
}
if (bp->b_flags & B_LOCKED) {
locked_queue_bytes += bp->b_bcount;
TAILQ_INSERT_TAIL(&bufqueues[BQ_LOCKED], bp, b_freelist);
} else if (age) {
TAILQ_INSERT_TAIL(&bufqueues[BQ_AGE], bp, b_freelist);
} else {
TAILQ_INSERT_TAIL(&bufqueues[BQ_LRU], bp, b_freelist);
}
--bp->b_vp->v_usecount;
}
/* Read the given block from disk, return it B_BUSY. */
int
bread(struct uvnode * vp, daddr_t lbn, int size, struct ucred * unused,
struct ubuf ** bpp)
{
struct ubuf *bp;
daddr_t daddr;
int error, count;
bp = getblk(vp, lbn, size);
*bpp = bp;
if (bp->b_flags & (B_DELWRI | B_DONE)) {
++cachehits;
return 0;
}
++cachemisses;
/*
* Not found. Need to find that block's location on disk,
* and load it in.
*/
daddr = -1;
error = VOP_BMAP(vp, lbn, &daddr);
bp->b_blkno = daddr;
if (daddr >= 0) {
count = pread(vp->v_fd, bp->b_data, bp->b_bcount,
dbtob((off_t) daddr));
if (count == bp->b_bcount) {
bp->b_flags |= B_DONE;
return 0;
}
return -1;
}
memset(bp->b_data, 0, bp->b_bcount);
return 0;
}
/* Move a buffer between dirty and clean block lists. */
void
reassignbuf(struct ubuf * bp, struct uvnode * vp)
{
LIST_REMOVE(bp, b_vnbufs);
if (bp->b_flags & B_DELWRI) {
LIST_INSERT_HEAD(&vp->v_dirtyblkhd, bp, b_vnbufs);
} else {
LIST_INSERT_HEAD(&vp->v_cleanblkhd, bp, b_vnbufs);
}
}

125
sbin/fsck_lfs/bufcache.h Normal file
View File

@ -0,0 +1,125 @@
/* $NetBSD: bufcache.h,v 1.1 2003/03/28 08:09:52 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
*
* @(#)buf.h 8.9 (Berkeley) 3/30/95
*/
#define BUF_CACHE_SIZE 1000
/*
* The buffer header describes an I/O operation.
*/
struct ubuf {
LIST_ENTRY(ubuf) b_hash; /* Hash chain. */
LIST_ENTRY(ubuf) b_vnbufs; /* Buffer's associated vnode. */
TAILQ_ENTRY(ubuf) b_freelist; /* Free list position if not active. */
volatile long b_flags; /* B_* flags. */
long b_bcount; /* Valid bytes in buffer. */
#undef b_data
char *b_data; /* Data in buffer */
daddr_t b_lblkno; /* Logical block number. */
daddr_t b_blkno; /* Underlying physical block number */
struct uvnode *b_vp; /* File vnode. */
};
#define b_bufsize b_bcount
/*
* These flags are kept in b_flags.
*/
#define B_AGE 0x00000001 /* Move to age queue when I/O done. */
#define B_NEEDCOMMIT 0x00000002 /* Needs committing to stable storage */
#define B_BUSY 0x00000010 /* I/O in progress. */
#define B_DELWRI 0x00000080 /* Delay I/O until buffer reused. */
#define B_DONE 0x00000200 /* I/O completed. */
#define B_ERROR 0x00000800 /* I/O error occurred. */
#define B_GATHERED 0x00001000 /* LFS: already in a segment. */
#define B_INVAL 0x00002000 /* Does not contain valid info. */
#define B_LOCKED 0x00004000 /* Locked in core (not reusable). */
#define B_READ 0x00100000 /* Read buffer. */
LIST_HEAD(bufhash_struct, ubuf);
void bufinit(void);
void bufstats(void);
void buf_destroy(struct ubuf *);
void bremfree(struct ubuf *);
struct ubuf *incore(struct uvnode *, int);
struct ubuf *getblk(struct uvnode *, daddr_t, int);
void bwrite(struct ubuf *);
void brelse(struct ubuf *);
int bread(struct uvnode *, daddr_t, int, struct ucred *, struct ubuf **);
void reassignbuf(struct ubuf *, struct uvnode *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: dir.c,v 1.7 2002/05/23 04:05:11 perseant Exp $ */
/* $NetBSD: dir.c,v 1.8 2003/03/28 08:09:52 perseant Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -33,24 +33,32 @@
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <sys/mount.h> /* XXX */
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/lfs/lfs.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fsck.h"
#include "fsutil.h"
#include "extern.h"
char *lfname = "lost+found";
int lfmode = 01700;
char *lfname = "lost+found";
int lfmode = 01700;
struct dirtemplate emptydir = {0, DIRBLKSIZ};
struct dirtemplate dirhead = {
0, 12, DT_DIR, 1, ".",
@ -61,13 +69,12 @@ struct odirtemplate odirhead = {
0, DIRBLKSIZ - 12, 2, ".."
};
static int expanddir(struct dinode *, char *);
static void freedir(ino_t, ino_t);
static struct direct *fsck_readdir(struct inodesc *);
static struct bufarea *getdirblk(daddr_t, long);
static int lftempname(char *, ino_t);
static int mkentry(struct inodesc *);
static int chgino(struct inodesc *);
static int expanddir(struct uvnode *, struct dinode *, char *);
static void freedir(ino_t, ino_t);
static struct direct *fsck_readdir(struct uvnode *, struct inodesc *);
static int lftempname(char *, ino_t);
static int mkentry(struct inodesc *);
static int chgino(struct inodesc *);
/*
* Propagate connected state through the tree.
@ -75,7 +82,7 @@ static int chgino(struct inodesc *);
void
propagate()
{
register struct inoinfo **inpp, *inp, *pinp;
struct inoinfo **inpp, *inp, *pinp;
struct inoinfo **inpend;
/*
@ -109,55 +116,38 @@ propagate()
* Scan each entry in a directory block.
*/
int
dirscan(struct inodesc * idesc)
dirscan(struct inodesc *idesc)
{
register struct direct *dp;
register struct bufarea *bp;
int dsize, n;
long blksiz;
char dbuf[DIRBLKSIZ];
struct direct *dp;
struct ubuf *bp;
int dsize, n;
long blksiz;
char dbuf[DIRBLKSIZ];
struct uvnode *vp;
if (idesc->id_type != DATA)
errexit("wrong type to dirscan %d\n", idesc->id_type);
if (idesc->id_entryno == 0 &&
(idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
blksiz = idesc->id_numfrags * sblock.lfs_fsize;
if (chkrange(idesc->id_blkno, fragstofsb(&sblock, idesc->id_numfrags))) {
blksiz = idesc->id_numfrags * fs->lfs_fsize;
if (chkrange(idesc->id_blkno, fragstofsb(fs, idesc->id_numfrags))) {
idesc->id_filesize -= blksiz;
return (SKIP);
}
idesc->id_loc = 0;
for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
vp = vget(fs, idesc->id_number);
for (dp = fsck_readdir(vp, idesc); dp != NULL;
dp = fsck_readdir(vp, idesc)) {
dsize = dp->d_reclen;
memcpy(dbuf, dp, (size_t)dsize);
# if (BYTE_ORDER == LITTLE_ENDIAN)
if (!newinofmt) {
struct direct *tdp = (struct direct *)dbuf;
u_char tmp;
tmp = tdp->d_namlen;
tdp->d_namlen = tdp->d_type;
tdp->d_type = tmp;
}
# endif
idesc->id_dirp = (struct direct *)dbuf;
if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
# if (BYTE_ORDER == LITTLE_ENDIAN)
if (!newinofmt && !doinglevel2) {
struct direct *tdp;
u_char tmp;
tdp = (struct direct *)dbuf;
tmp = tdp->d_namlen;
tdp->d_namlen = tdp->d_type;
tdp->d_type = tmp;
}
# endif
bp = getdirblk(idesc->id_blkno, blksiz);
memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
(size_t)dsize);
dirty(bp);
memcpy(dbuf, dp, (size_t) dsize);
idesc->id_dirp = (struct direct *) dbuf;
if ((n = (*idesc->id_func) (idesc)) & ALTERED) {
bread(vp, idesc->id_lblkno, blksiz, NOCRED, &bp);
memcpy(bp->b_data + idesc->id_loc - dsize, dbuf,
(size_t) dsize);
VOP_BWRITE(bp);
sbdirty();
}
if (n & STOP)
@ -170,59 +160,71 @@ dirscan(struct inodesc * idesc)
* get next entry in a directory.
*/
static struct direct *
fsck_readdir(struct inodesc * idesc)
fsck_readdir(struct uvnode *vp, struct inodesc *idesc)
{
register struct direct *dp, *ndp;
register struct bufarea *bp;
long size, blksiz, fix, dploc;
struct direct *dp, *ndp;
struct ubuf *bp;
long size, blksiz, fix, dploc;
blksiz = idesc->id_numfrags * sblock.lfs_fsize;
bp = getdirblk(idesc->id_blkno, blksiz);
blksiz = idesc->id_numfrags * fs->lfs_fsize;
bread(vp, idesc->id_lblkno, blksiz, NOCRED, &bp);
if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
idesc->id_loc < blksiz) {
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
dp = (struct direct *) (bp->b_data + idesc->id_loc);
if (dircheck(idesc, dp))
goto dpok;
brelse(bp);
if (idesc->id_fix == IGNORE)
return (0);
fix = dofix(idesc, "DIRECTORY CORRUPTED");
bp = getdirblk(idesc->id_blkno, blksiz);
dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
bread(vp, idesc->id_blkno, blksiz, NOCRED, &bp);
dp = (struct direct *) (bp->b_data + idesc->id_loc);
dp->d_reclen = DIRBLKSIZ;
dp->d_ino = 0;
dp->d_type = 0;
dp->d_namlen = 0;
dp->d_name[0] = '\0';
if (fix)
dirty(bp);
VOP_BWRITE(bp);
else
brelse(bp);
idesc->id_loc += DIRBLKSIZ;
idesc->id_filesize -= DIRBLKSIZ;
return (dp);
}
dpok:
if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) {
brelse(bp);
return NULL;
}
dploc = idesc->id_loc;
dp = (struct direct *)(bp->b_un.b_buf + dploc);
dp = (struct direct *) (bp->b_data + dploc);
idesc->id_loc += dp->d_reclen;
idesc->id_filesize -= dp->d_reclen;
if ((idesc->id_loc % DIRBLKSIZ) == 0)
return (dp);
ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
if ((idesc->id_loc % DIRBLKSIZ) == 0) {
brelse(bp);
return dp;
}
ndp = (struct direct *) (bp->b_data + idesc->id_loc);
if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
dircheck(idesc, ndp) == 0) {
brelse(bp);
size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
idesc->id_loc += size;
idesc->id_filesize -= size;
if (idesc->id_fix == IGNORE)
return (0);
return 0;
fix = dofix(idesc, "DIRECTORY CORRUPTED");
bp = getdirblk(idesc->id_blkno, blksiz);
dp = (struct direct *)(bp->b_un.b_buf + dploc);
bread(vp, idesc->id_blkno, blksiz, NOCRED, &bp);
dp = (struct direct *) (bp->b_data + dploc);
dp->d_reclen += size;
if (fix)
dirty(bp);
}
VOP_BWRITE(bp);
else
brelse(bp);
} else
brelse(bp);
return (dp);
}
@ -231,12 +233,12 @@ dpok:
* This is a superset of the checks made in the kernel.
*/
int
dircheck(struct inodesc * idesc, struct direct * dp)
dircheck(struct inodesc *idesc, struct direct *dp)
{
register int size;
register char *cp;
u_char namlen, type;
int spaceleft;
int size;
char *cp;
u_char namlen, type;
int spaceleft;
spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
if (dp->d_ino >= maxino ||
@ -245,28 +247,18 @@ dircheck(struct inodesc * idesc, struct direct * dp)
(dp->d_reclen & 0x3) != 0) {
pwarn("ino too large, reclen=0, reclen>space, or reclen&3!=0\n");
pwarn("dp->d_ino = 0x%x\tdp->d_reclen = 0x%x\n",
dp->d_ino, dp->d_reclen);
dp->d_ino, dp->d_reclen);
pwarn("maxino = 0x%x\tspaceleft = 0x%x\n", maxino, spaceleft);
return (0);
}
if (dp->d_ino == 0)
return (1);
size = DIRSIZ(!newinofmt, dp, 0);
# if (BYTE_ORDER == LITTLE_ENDIAN)
if (!newinofmt) {
type = dp->d_namlen;
namlen = dp->d_type;
} else {
namlen = dp->d_namlen;
type = dp->d_type;
}
# else
namlen = dp->d_namlen;
type = dp->d_type;
# endif
size = DIRSIZ(0, dp, 0);
namlen = dp->d_namlen;
type = dp->d_type;
if (dp->d_reclen < size ||
idesc->id_filesize < size ||
/* namlen > MAXNAMLEN || */
/* namlen > MAXNAMLEN || */
type > 15) {
printf("reclen<size, filesize<size, namlen too large, or type>15\n");
return (0);
@ -293,8 +285,9 @@ direrror(ino_t ino, char *errmesg)
void
fileerror(ino_t cwd, ino_t ino, char *errmesg)
{
register struct dinode *dp;
char pathbuf[MAXPATHLEN + 1];
char pathbuf[MAXPATHLEN + 1];
struct uvnode *vp;
struct inode *ip;
pwarn("%s ", errmesg);
pinode(ino);
@ -304,33 +297,37 @@ fileerror(ino_t cwd, ino_t ino, char *errmesg)
pfatal("NAME=%s\n", pathbuf);
return;
}
dp = ginode(ino);
if (dp == NULL)
vp = vget(fs, ino);
ip = VTOI(vp);
if (vp == NULL)
pfatal("INO is NULL\n");
else {
if (ftypeok(dp))
if (ftypeok(VTOD(vp)))
pfatal("%s=%s\n",
(dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
(ip->i_ffs_mode & IFMT) == IFDIR ?
"DIR" : "FILE", pathbuf);
else
pfatal("NAME=%s\n", pathbuf);
}
}
void
adjust(struct inodesc * idesc, short lcnt)
adjust(struct inodesc *idesc, short lcnt)
{
register struct dinode *dp;
struct uvnode *vp;
struct dinode *dp;
dp = ginode(idesc->id_number);
vp = vget(fs, idesc->id_number);
dp = VTOD(vp);
if (dp->di_nlink == lcnt) {
if (linkup(idesc->id_number, (ino_t)0) == 0)
if (linkup(idesc->id_number, (ino_t) 0) == 0)
clri(idesc, "UNREF", 0);
} else {
pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));
((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));
pinode(idesc->id_number);
printf(" COUNT %d SHOULD BE %d",
dp->di_nlink, dp->di_nlink - lcnt);
dp->di_nlink, dp->di_nlink - lcnt);
if (preen) {
if (lcnt < 0) {
printf("\n");
@ -340,17 +337,17 @@ adjust(struct inodesc * idesc, short lcnt)
}
if (preen || reply("ADJUST") == 1) {
dp->di_nlink -= lcnt;
inodirty();
inodirty(VTOI(vp));
}
}
}
static int
mkentry(struct inodesc * idesc)
mkentry(struct inodesc *idesc)
{
register struct direct *dirp = idesc->id_dirp;
struct direct newent;
int newlen, oldlen;
struct direct *dirp = idesc->id_dirp;
struct direct newent;
int newlen, oldlen;
newent.d_namlen = strlen(idesc->id_name);
newlen = DIRSIZ(0, &newent, 0);
@ -362,59 +359,40 @@ mkentry(struct inodesc * idesc)
return (KEEPON);
newent.d_reclen = dirp->d_reclen - oldlen;
dirp->d_reclen = oldlen;
dirp = (struct direct *)(((char *)dirp) + oldlen);
dirp = (struct direct *) (((char *) dirp) + oldlen);
dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
dirp->d_reclen = newent.d_reclen;
if (newinofmt)
dirp->d_type = typemap[idesc->id_parent];
else
dirp->d_type = 0;
dirp->d_type = typemap[idesc->id_parent];
dirp->d_namlen = newent.d_namlen;
memcpy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
# if (BYTE_ORDER == LITTLE_ENDIAN)
/*
* If the entry was split, dirscan()will only reverse the byte
* order of the original entry, and not the new one, before
* writing it back out. So, we reverse the byte order here if
* necessary.
*/
if (oldlen != 0 && !newinofmt && !doinglevel2) {
u_char tmp;
tmp = dirp->d_namlen;
dirp->d_namlen = dirp->d_type;
dirp->d_type = tmp;
}
# endif
memcpy(dirp->d_name, idesc->id_name, (size_t) dirp->d_namlen + 1);
return (ALTERED | STOP);
}
static int
chgino(struct inodesc * idesc)
chgino(struct inodesc *idesc)
{
register struct direct *dirp = idesc->id_dirp;
struct direct *dirp = idesc->id_dirp;
if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
if (memcmp(dirp->d_name, idesc->id_name, (int) dirp->d_namlen + 1))
return (KEEPON);
dirp->d_ino = idesc->id_parent;
if (newinofmt)
dirp->d_type = typemap[idesc->id_parent];
else
dirp->d_type = 0;
dirp->d_type = typemap[idesc->id_parent];
return (ALTERED | STOP);
}
int
linkup(ino_t orphan, ino_t parentdir)
{
register struct dinode *dp;
int lostdir;
ino_t oldlfdir;
struct inodesc idesc;
char tempname[BUFSIZ];
struct dinode *dp;
int lostdir;
ino_t oldlfdir;
struct inodesc idesc;
char tempname[BUFSIZ];
struct uvnode *vp;
memset(&idesc, 0, sizeof(struct inodesc));
dp = ginode(orphan);
vp = vget(fs, orphan);
dp = VTOD(vp);
lostdir = (dp->di_mode & IFMT) == IFDIR;
pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
pinode(orphan);
@ -435,7 +413,7 @@ linkup(ino_t orphan, ino_t parentdir)
} else {
pwarn("NO lost+found DIRECTORY");
if (preen || reply("CREATE")) {
lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
lfdir = allocdir(ROOTINO, (ino_t) 0, lfmode);
if (lfdir != 0) {
if (makeentry(ROOTINO, lfdir, lfname) != 0) {
if (preen)
@ -455,13 +433,14 @@ linkup(ino_t orphan, ino_t parentdir)
return (0);
}
}
dp = ginode(lfdir);
vp = vget(fs, lfdir);
dp = VTOD(vp);
if ((dp->di_mode & IFMT) != IFDIR) {
pfatal("lost+found IS NOT A DIRECTORY");
if (reply("REALLOCATE") == 0)
return (0);
oldlfdir = lfdir;
if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) {
if ((lfdir = allocdir(ROOTINO, (ino_t) 0, lfmode)) == 0) {
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
return (0);
}
@ -469,19 +448,20 @@ linkup(ino_t orphan, ino_t parentdir)
pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
return (0);
}
inodirty();
inodirty(VTOI(vp));
idesc.id_type = ADDR;
idesc.id_func = pass4check;
idesc.id_number = oldlfdir;
adjust(&idesc, lncntp[oldlfdir] + 1);
lncntp[oldlfdir] = 0;
dp = ginode(lfdir);
vp = vget(fs, lfdir);
dp = VTOD(vp);
}
if (statemap[lfdir] != DFOUND) {
pfatal("SORRY. NO lost+found DIRECTORY\n\n");
return (0);
}
(void)lftempname(tempname, orphan);
(void) lftempname(tempname, orphan);
if (makeentry(lfdir, orphan, tempname) == 0) {
pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
printf("\n\n");
@ -490,14 +470,14 @@ linkup(ino_t orphan, ino_t parentdir)
lncntp[orphan]--;
if (lostdir) {
if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
parentdir != (ino_t)-1)
(void)makeentry(orphan, lfdir, "..");
dp = ginode(lfdir);
dp->di_nlink++;
inodirty();
parentdir != (ino_t) - 1)
(void) makeentry(orphan, lfdir, "..");
vp = vget(fs, lfdir);
VTOI(vp)->i_ffs_nlink++;
inodirty(VTOI(vp));
lncntp[lfdir]++;
pwarn("DIR I=%u CONNECTED. ", orphan);
if (parentdir != (ino_t)-1)
if (parentdir != (ino_t) - 1)
printf("PARENT WAS I=%u\n", parentdir);
if (preen == 0)
printf("\n");
@ -511,7 +491,7 @@ linkup(ino_t orphan, ino_t parentdir)
int
changeino(ino_t dir, char *name, ino_t newnum)
{
struct inodesc idesc;
struct inodesc idesc;
memset(&idesc, 0, sizeof(struct inodesc));
idesc.id_type = DATA;
@ -520,6 +500,7 @@ changeino(ino_t dir, char *name, ino_t newnum)
idesc.id_fix = DONTKNOW;
idesc.id_name = name;
idesc.id_parent = newnum; /* new value for name */
return (ckinode(ginode(dir), &idesc));
}
@ -529,9 +510,10 @@ changeino(ino_t dir, char *name, ino_t newnum)
int
makeentry(ino_t parent, ino_t ino, char *name)
{
struct dinode *dp;
struct inodesc idesc;
char pathbuf[MAXPATHLEN + 1];
struct dinode *dp;
struct inodesc idesc;
char pathbuf[MAXPATHLEN + 1];
struct uvnode *vp;
if (parent < ROOTINO || parent >= maxino ||
ino < ROOTINO || ino >= maxino)
@ -543,16 +525,18 @@ makeentry(ino_t parent, ino_t ino, char *name)
idesc.id_parent = ino; /* this is the inode to enter */
idesc.id_fix = DONTKNOW;
idesc.id_name = name;
dp = ginode(parent);
vp = vget(fs, parent);
dp = VTOD(vp);
if (dp->di_size % DIRBLKSIZ) {
dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
inodirty();
inodirty(VTOI(vp));
}
if ((ckinode(dp, &idesc) & ALTERED) != 0)
return (1);
getpathname(pathbuf, parent, parent);
dp = ginode(parent);
if (expanddir(dp, pathbuf) == 0)
vp = vget(fs, parent);
dp = VTOD(vp);
if (expanddir(vp, dp, pathbuf) == 0)
return (0);
return (ckinode(dp, &idesc) & ALTERED);
}
@ -561,54 +545,54 @@ makeentry(ino_t parent, ino_t ino, char *name)
* Attempt to expand the size of a directory
*/
static int
expanddir(struct dinode * dp, char *name)
expanddir(struct uvnode *vp, struct dinode *dp, char *name)
{
daddr_t lastbn, newblk;
register struct bufarea *bp;
char *cp, firstblk[DIRBLKSIZ];
daddr_t lastbn, newblk;
struct ubuf *bp;
char *cp, firstblk[DIRBLKSIZ];
lastbn = lblkno(&sblock, dp->di_size);
lastbn = lblkno(fs, dp->di_size);
if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)
return (0);
if ((newblk = allocblk(sblock.lfs_frag)) == 0)
return (0);
dp->di_db[lastbn + 1] = dp->di_db[lastbn];
dp->di_db[lastbn] = newblk;
dp->di_size += sblock.lfs_bsize;
dp->di_blocks += btofsb(&sblock, sblock.lfs_bsize);
bp = getdirblk(dp->di_db[lastbn + 1],
(long)dblksize(&sblock, dp, lastbn + 1));
if (bp->b_errs)
dp->di_db[lastbn] = 0;
bp = getblk(vp, lastbn, fs->lfs_bsize);
VOP_BWRITE(bp);
dp->di_size += fs->lfs_bsize;
dp->di_blocks += btofsb(fs, fs->lfs_bsize);
bread(vp, dp->di_db[lastbn + 1],
(long) dblksize(fs, dp, lastbn + 1), NOCRED, &bp);
if (bp->b_flags & B_ERROR)
goto bad;
memcpy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
bp = getdirblk(newblk, sblock.lfs_bsize);
if (bp->b_errs)
memcpy(firstblk, bp->b_data, DIRBLKSIZ);
bread(vp, newblk, fs->lfs_bsize, NOCRED, &bp);
if (bp->b_flags & B_ERROR)
goto bad;
memcpy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
cp < &bp->b_un.b_buf[sblock.lfs_bsize];
cp += DIRBLKSIZ)
memcpy(bp->b_data, firstblk, DIRBLKSIZ);
for (cp = &bp->b_data[DIRBLKSIZ];
cp < &bp->b_data[fs->lfs_bsize];
cp += DIRBLKSIZ)
memcpy(cp, &emptydir, sizeof emptydir);
dirty(bp);
bp = getdirblk(dp->di_db[lastbn + 1],
(long)dblksize(&sblock, dp, lastbn + 1));
if (bp->b_errs)
VOP_BWRITE(bp);
bread(vp, dp->di_db[lastbn + 1],
(long) dblksize(fs, dp, lastbn + 1), NOCRED, &bp);
if (bp->b_flags & B_ERROR)
goto bad;
memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir);
memcpy(bp->b_data, &emptydir, sizeof emptydir);
pwarn("NO SPACE LEFT IN %s", name);
if (preen)
printf(" (EXPANDED)\n");
else if (reply("EXPAND") == 0)
goto bad;
dirty(bp);
inodirty();
VOP_BWRITE(bp);
inodirty(VTOI(vp));
return (1);
bad:
dp->di_db[lastbn] = dp->di_db[lastbn + 1];
dp->di_db[lastbn + 1] = 0;
dp->di_size -= sblock.lfs_bsize;
dp->di_blocks -= btofsb(&sblock, sblock.lfs_bsize);
freeblk(newblk, sblock.lfs_frag);
dp->di_size -= fs->lfs_bsize;
dp->di_blocks -= btofsb(fs, fs->lfs_bsize);
freeblk(newblk, fs->lfs_frag);
return (0);
}
@ -618,33 +602,33 @@ bad:
int
allocdir(ino_t parent, ino_t request, int mode)
{
ino_t ino;
char *cp;
struct dinode *dp;
register struct bufarea *bp;
ino_t ino;
char *cp;
struct dinode *dp;
struct ubuf *bp;
struct dirtemplate *dirp;
struct uvnode *vp;
ino = allocino(request, IFDIR | mode);
if (newinofmt)
dirp = &dirhead;
else
dirp = (struct dirtemplate *) & odirhead;
dirp = &dirhead;
dirp->dot_ino = ino;
dirp->dotdot_ino = parent;
dp = ginode(ino);
bp = getdirblk(dp->di_db[0], sblock.lfs_fsize);
if (bp->b_errs) {
vp = vget(fs, ino);
dp = VTOD(vp);
bread(vp, dp->di_db[0], fs->lfs_fsize, NOCRED, &bp);
if (bp->b_flags & B_ERROR) {
brelse(bp);
freeino(ino);
return (0);
}
memcpy(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
cp < &bp->b_un.b_buf[sblock.lfs_fsize];
cp += DIRBLKSIZ)
memcpy(bp->b_data, dirp, sizeof(struct dirtemplate));
for (cp = &bp->b_data[DIRBLKSIZ];
cp < &bp->b_data[fs->lfs_fsize];
cp += DIRBLKSIZ)
memcpy(cp, &emptydir, sizeof emptydir);
dirty(bp);
VOP_BWRITE(bp);
dp->di_nlink = 2;
inodirty();
inodirty(VTOI(vp));
if (ino == ROOTINO) {
lncntp[ino] = dp->di_nlink;
cacheino(dp, ino);
@ -660,9 +644,10 @@ allocdir(ino_t parent, ino_t request, int mode)
lncntp[ino] = dp->di_nlink;
lncntp[parent]++;
}
dp = ginode(parent);
vp = vget(fs, parent);
dp = VTOD(vp);
dp->di_nlink++;
inodirty();
inodirty(VTOI(vp));
return (ino);
}
@ -672,12 +657,12 @@ allocdir(ino_t parent, ino_t request, int mode)
static void
freedir(ino_t ino, ino_t parent)
{
struct dinode *dp;
struct uvnode *vp;
if (ino != parent) {
dp = ginode(parent);
dp->di_nlink--;
inodirty();
vp = vget(fs, parent);
VTOI(vp)->i_ffs_nlink--;
inodirty(VTOI(vp));
}
freeino(ino);
}
@ -688,9 +673,9 @@ freedir(ino_t ino, ino_t parent)
static int
lftempname(char *bufp, ino_t ino)
{
register ino_t in;
register char *cp;
int namlen;
ino_t in;
char *cp;
int namlen;
cp = bufp + 2;
for (in = maxino; in > 0; in /= 10)
@ -705,18 +690,3 @@ lftempname(char *bufp, ino_t ino)
*cp = '#';
return (namlen);
}
/*
* Get a directory block.
* Ensure that it is held until another is requested.
*/
static struct bufarea *
getdirblk(daddr_t blkno, long size)
{
if (pdirbp != 0)
pdirbp->b_flags &= ~B_INUSE;
/* pdirbp = getdatablk(blkno, size); */
pdirbp = getddblk(blkno, size);
return (pdirbp);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: extern.h,v 1.3 2000/05/23 01:48:52 perseant Exp $ */
/* $NetBSD: extern.h,v 1.4 2003/03/28 08:09:53 perseant Exp $ */
/*
* Copyright (c) 1994 James A. Jegers
@ -24,52 +24,52 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
void adjust(struct inodesc *, short);
int allocblk(long);
int allocdir(ino_t, ino_t, int);
void blkerror(ino_t, char *, daddr_t);
int bread(int, char *, daddr_t, long);
void bufinit(void);
void bwrite(int, char *, daddr_t, long);
void cacheino(struct dinode *, ino_t);
int changeino(ino_t, char *, ino_t);
void adjust(struct inodesc *, short);
int allocblk(long);
int allocdir(ino_t, ino_t, int);
void blkerror(ino_t, char *, daddr_t);
void cacheino(struct dinode *, ino_t);
int changeino(ino_t, char *, ino_t);
struct fstab;
int chkrange(daddr_t, int);
void ckfini(int);
int ckinode(struct dinode *, struct inodesc *);
void clri(struct inodesc *, char *, int);
int dircheck(struct inodesc *, struct direct *);
void direrror(ino_t, char *);
int dirscan(struct inodesc *);
int dofix(struct inodesc *, char *);
void fileerror(ino_t, ino_t, char *);
int findino(struct inodesc *);
int findname(struct inodesc *);
void flush(int, struct bufarea *);
void freeblk(daddr_t, long);
void freeino(ino_t);
void freeinodebuf(void);
int ftypeok(struct dinode *);
void getpathname(char *, ino_t, ino_t);
void inocleanup(void);
void inodirty(void);
int linkup(ino_t, ino_t);
int makeentry(ino_t, ino_t, char *);
void pass0(void);
void pass1(void);
void pass1b(void);
void pass2(void);
void pass3(void);
void pass4(void);
int pass1check(struct inodesc *);
int pass4check(struct inodesc *);
void pass5(void);
void pinode(ino_t);
void propagate(void);
int reply(char *);
void resetinodebuf(void);
int setup(const char *);
struct dinode *getnextinode(ino_t);
void catch(int);
void catchquit(int);
void voidquit(int);
void checkinode(ino_t, struct inodesc *);
int chkrange(daddr_t, int);
void ckfini(int);
int ckinode(struct dinode *, struct inodesc *);
void clri(struct inodesc *, char *, int);
int dircheck(struct inodesc *, struct direct *);
void direrror(ino_t, char *);
int dirscan(struct inodesc *);
int dofix(struct inodesc *, char *);
void fileerror(ino_t, ino_t, char *);
int findino(struct inodesc *);
int findname(struct inodesc *);
void flush(int, struct ubufarea *);
void freeblk(daddr_t, long);
void freeino(ino_t);
void freeinodebuf(void);
int ftypeok(struct dinode *);
void getpathname(char *, ino_t, ino_t);
void inocleanup(void);
void inodirty(struct inode *);
int linkup(ino_t, ino_t);
int makeentry(ino_t, ino_t, char *);
void pass0(void);
void pass1(void);
void pass1b(void);
void pass2(void);
void pass3(void);
void pass4(void);
int pass1check(struct inodesc *);
int pass4check(struct inodesc *);
void pass5(void);
void pass6(void);
int pass6check(struct inodesc *);
void pinode(ino_t);
void propagate(void);
int reply(char *);
void resetinodebuf(void);
int setup(const char *);
struct dinode *getnextinode(ino_t);
void catch(int);
void catchquit(int);
void voidquit(int);

View File

@ -1,4 +1,4 @@
/* $NetBSD: fsck.h,v 1.7 2003/01/24 21:55:09 fvdl Exp $ */
/* $NetBSD: fsck.h,v 1.8 2003/03/28 08:09:53 perseant Exp $ */
/*
* Copyright (c) 1997
@ -63,24 +63,23 @@
/*
* buffer cache structure.
*/
struct bufarea {
struct bufarea *b_next; /* free list queue */
struct bufarea *b_prev; /* free list queue */
daddr_t b_bno;
int b_size;
int b_errs;
int b_flags;
struct ubufarea {
struct ubufarea *b_next; /* free list queue */
struct ubufarea *b_prev; /* free list queue */
daddr_t b_bno;
int b_size;
int b_errs;
int b_flags;
union {
char *b_buf; /* buffer space */
char *b_buf; /* buffer space */
/* XXX ondisk32 */
int32_t *b_indir; /* indirect block */
struct lfs *b_fs; /* super block */
struct cg *b_cg; /* cylinder group */
struct dinode *b_dinode; /* inode block */
} b_un;
char b_dirty;
int32_t *b_indir; /* indirect block */
struct lfs *b_fs; /* super block */
struct cg *b_cg;/* cylinder group */
struct dinode *b_dinode; /* inode block */
} b_un;
char b_dirty;
};
#define B_INUSE 1
#define MINBUFS 5 /* minimum number of buffers required */
@ -91,38 +90,25 @@ struct bufarea {
(bp)->b_bno = (daddr_t)-1; \
(bp)->b_flags = 0;
#define sblock (*sblk.b_un.b_fs)
#define ifblock (*iblk.b_un.b_dinode)
#define sbdirty() do { \
sblk.b_dirty = 1; \
sblock.lfs_dlfs.dlfs_cksum = lfs_sb_cksum(&(sblock.lfs_dlfs)); \
} while(0)
enum fixstate {
DONTKNOW, NOFIX, FIX, IGNORE
};
struct inodesc {
enum fixstate id_fix; /* policy on fixing errors */
int (*id_func)(struct inodesc *); /* function to be
* applied to blocks of inode */
ino_t id_number; /* inode number described */
ino_t id_parent; /* for DATA nodes, their parent */
daddr_t id_blkno; /* current block number being
* examined */
daddr_t id_lblkno; /* current logical block number */
int id_numfrags; /* number of frags contained in block */
quad_t id_filesize; /* for DATA nodes, the size of the
* directory */
int id_loc; /* for DATA nodes, current location
* in dir */
int id_entryno; /* for DATA nodes, current entry
* number */
struct direct *id_dirp; /* for DATA nodes, ptr to current
* entry */
char *id_name; /* for DATA nodes, name to find or
* enter */
char id_type; /* type of descriptor, DATA or ADDR */
enum fixstate id_fix; /* policy on fixing errors */
int (*id_func) (struct inodesc *); /* function to be applied to
* blocks of inode */
ino_t id_number; /* inode number described */
ino_t id_parent; /* for DATA nodes, their parent */
daddr_t id_blkno; /* current block number being examined */
daddr_t id_lblkno; /* current logical block number */
int id_numfrags; /* number of frags contained in block */
quad_t id_filesize; /* for DATA nodes, the size of the directory */
int id_loc; /* for DATA nodes, current location in dir */
int id_entryno; /* for DATA nodes, current entry number */
struct direct *id_dirp; /* for DATA nodes, ptr to current entry */
char *id_name; /* for DATA nodes, name to find or enter */
char id_type; /* type of descriptor, DATA or ADDR */
};
/* file types */
#define DATA 1
@ -150,33 +136,30 @@ struct inodesc {
* duplist muldup
*/
struct dups {
struct dups *next;
daddr_t dup;
struct dups *next;
daddr_t dup;
};
/*
* Linked list of inodes with zero link counts.
*/
struct zlncnt {
struct zlncnt *next;
ino_t zlncnt;
struct zlncnt *next;
ino_t zlncnt;
};
/*
* Inode cache data structures.
*/
struct inoinfo {
struct inoinfo *i_nexthash; /* next entry in hash chain */
struct inoinfo *i_child, *i_sibling, *i_parentp;
ino_t i_number; /* inode number of this entry */
ino_t i_parent; /* inode number of parent */
ino_t i_dotdot; /* inode number of `..' */
size_t i_isize; /* size of inode */
u_int i_numblks; /* size of block array in bytes */
ino_t i_number; /* inode number of this entry */
ino_t i_parent; /* inode number of parent */
ino_t i_dotdot; /* inode number of `..' */
size_t i_isize; /* size of inode */
u_int i_numblks; /* size of block array in bytes */
/* XXX ondisk32 */
int32_t i_blks[1]; /* actually longer */
} **inphead, **inpsort;
int32_t i_blks[1]; /* actually longer */
} **inphead, **inpsort;
#define clearinode(dp) (*(dp) = zino)
#ifndef VERBOSE_BLOCKMAP
@ -195,18 +178,10 @@ struct inoinfo {
#define ALTERED 0x08
#define FOUND 0x10
ino_t allocino(ino_t, int);
int ino_to_fsba(struct lfs *, ino_t);
struct bufarea *getfileblk(struct lfs *, struct dinode *, ino_t);
struct dinode *ginode(ino_t);
struct dinode *lfs_ginode(ino_t);
struct dinode *lfs_difind(struct lfs *, ino_t, struct dinode *);
struct ifile *lfs_ientry(ino_t, struct bufarea **);
ino_t allocino(ino_t, int);
int ino_to_fsba(struct lfs *, ino_t);
struct dinode *ginode(ino_t);
struct inoinfo *getinoinfo(ino_t);
void getblk(struct bufarea *, daddr_t, long);
void getdblk(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);
daddr_t lfs_ino_daddr(ino_t);
#include "fsck_vars.h"

View File

@ -1,4 +1,4 @@
.\" $NetBSD: fsck_lfs.8,v 1.12 2003/02/25 10:34:57 wiz Exp $
.\" $NetBSD: fsck_lfs.8,v 1.13 2003/03/28 08:09:53 perseant Exp $
.\"
.\" Copyright (c) 1980, 1989, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -135,7 +135,7 @@ do not open the filesystem for writing.
Specify ``preen'' mode.
Currently, in this mode
.Nm
simply checks validity of the newer checkpoint.
rolls forward from the older checkpoint, and performs no other action.
.It Fl y
Assume a yes response to all questions asked by
.Nm ;
@ -177,6 +177,12 @@ Super Block checks:
.Bl -item -offset indent -compact
.It
More blocks for inodes than there are in the filesystem.
.El
.It
Index File checks:
.Bl -item -offset indent -compact
.It
``In use'' inodes on free list, or free inodes not on free list.
.It
Segment block counts incorrect, or ``clean'' segments containing live data.
.El
@ -219,7 +225,3 @@ program was taken from
.Xr fsck_ffs 8 ;
what was not was written by
.An Konrad Schroder Aq perseant@hhhh.org .
.Sh BUGS
.Nm
cannot currently perform a full roll-forward, or correct all of the
errors that it can detect.

View File

@ -1,4 +1,4 @@
/* $NetBSD: fsck_vars.h,v 1.5 2003/01/24 21:55:09 fvdl Exp $ */
/* $NetBSD: fsck_vars.h,v 1.6 2003/03/28 08:09:53 perseant Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -35,62 +35,47 @@
* @(#)fsck.h 8.1 (Berkeley) 6/5/93
*/
extern struct bufarea bufhead; /* head of list of other blks in filesys */
extern struct bufarea sblk; /* file system superblock */
extern struct bufarea iblk; /* ifile on-disk inode block */
extern struct bufarea *pdirbp; /* current directory contents */
extern struct bufarea *pbp; /* current inode block */
extern struct bufarea *getddblk(daddr_t, long);
extern struct bufarea *getdatablk(daddr_t, long);
extern int iinooff; /* ifile inode offset in block of inodes */
extern struct dups *duplist; /* head of dup list */
extern struct dups *muldup; /* end of unique duplicate dup block numbers */
extern struct zlncnt *zlnhead; /* head of zero link count list */
extern struct lfs *fs;
extern daddr_t idaddr; /* inode block containing ifile inode */
extern long numdirs, listmax, inplast;
extern daddr_t idaddr; /* inode block containing ifile inode */
extern long numdirs, listmax, inplast;
extern long dev_bsize; /* computed value of DEV_BSIZE */
extern long secsize; /* actual disk sector size */
extern char nflag; /* assume a no response */
extern char yflag; /* assume a yes response */
extern int bflag; /* location of alternate super block */
extern int debug; /* output debugging info */
#ifdef DEBUG_IFILE
extern int debug_ifile; /* cat ifile and exit */
#endif
extern int exitonfail;
extern int cvtlevel; /* convert to newer file system format */
extern int doinglevel1; /* converting to new cylinder group format */
extern int doinglevel2; /* converting to new inode format */
extern int newinofmt; /* filesystem has new inode format */
extern int preen; /* just fix normal inconsistencies */
extern char havesb; /* superblock has been read */
extern char skipclean; /* skip clean file systems if preening */
extern int fsmodified; /* 1 => write done to file system */
extern int fsreadfd; /* file descriptor for reading file system */
extern int fswritefd; /* file descriptor for writing file system */
extern int rerun; /* rerun fsck. Only used in non-preen mode */
extern long dev_bsize; /* computed value of DEV_BSIZE */
extern long secsize; /* actual disk sector size */
extern char nflag; /* assume a no response */
extern char yflag; /* assume a yes response */
extern int bflag; /* location of alternate super block */
extern int debug; /* output debugging info */
extern int exitonfail;
extern int preen; /* just fix normal inconsistencies */
extern char havesb; /* superblock has been read */
extern char skipclean; /* skip clean file systems if preening */
extern int fsmodified; /* 1 => write done to file system */
extern int fsreadfd; /* file descriptor for reading file system */
extern int fswritefd; /* file descriptor for writing file system */
extern int rerun; /* rerun fsck. Only used in non-preen mode */
extern daddr_t maxfsblock; /* number of blocks in the file system */
extern daddr_t maxfsblock; /* number of blocks in the file system */
#ifndef VERBOSE_BLOCKMAP
extern char *blockmap; /* ptr to primary blk allocation map */
extern char *blockmap; /* ptr to primary blk allocation map */
#else
extern ino_t *blockmap; /* ptr to primary blk allocation map */
extern ino_t *blockmap; /* ptr to primary blk allocation map */
#endif
extern ino_t maxino; /* number of inodes in file system */
extern ino_t lastino; /* last inode in use */
extern char *statemap; /* ptr to inode state table */
extern char *typemap; /* ptr to inode type table */
extern ino_t maxino; /* number of inodes in file system */
extern ino_t lastino; /* last inode in use */
extern char *statemap; /* ptr to inode state table */
extern char *typemap; /* ptr to inode type table */
extern int16_t *lncntp; /* ptr to link count table */
extern ino_t lfdir; /* lost & found directory inode number */
extern char *lfname; /* lost & found directory name */
extern int lfmode; /* lost & found directory creation mode */
extern ino_t lfdir; /* lost & found directory inode number */
extern char *lfname; /* lost & found directory name */
extern int lfmode; /* lost & found directory creation mode */
extern daddr_t n_blks; /* number of blocks in use */
extern ino_t n_files; /* number of files in use */
extern daddr_t n_blks; /* number of blocks in use */
extern ino_t n_files; /* number of files in use */
extern struct dinode zino;

View File

@ -1,4 +1,4 @@
/* $NetBSD: inode.c,v 1.15 2003/02/17 23:48:09 perseant Exp $ */
/* $NetBSD: inode.c,v 1.16 2003/03/28 08:09:53 perseant Exp $ */
/*
* Copyright (c) 1997, 1998
@ -35,13 +35,19 @@
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#include <sys/mount.h> /* XXX */
#define vnode uvnode
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#undef vnode
#include <err.h>
#ifndef SMALL
#include <pwd.h>
#endif
@ -49,351 +55,58 @@
#include <stdlib.h>
#include <string.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fsck.h"
#include "fsutil.h"
#include "extern.h"
extern SEGUSE *seg_table;
extern daddr_t *din_table;
extern SEGUSE *seg_table;
extern ufs_daddr_t *din_table;
static int iblock(struct inodesc *, long, u_int64_t);
int blksreqd(struct lfs *, int);
int lfs_maxino(void);
/* static void dump_inoblk (struct lfs *, struct dinode *); */
/* stolen from lfs_inode.c */
/* Search a block for a specific dinode. */
struct dinode *
lfs_difind(struct lfs * fs, ino_t ino, struct dinode * dip)
{
struct dinode *ldip, *fin;
#ifdef LFS_IFILE_FRAG_ADDRESSING
if (fs->lfs_version == 1)
fin = dip + INOPB(fs);
else
fin = dip + INOPF(fs);
#else
fin = dip + INOPB(fs);
#endif
for (ldip = dip; ldip < fin; ++ldip) {
if (ldip->di_inumber == ino)
return ldip;
}
/* printf("lfs_difind: dinode %u not found\n", ino); */
return NULL;
}
static int iblock(struct inodesc *, long, u_int64_t);
int blksreqd(struct lfs *, int);
int lfs_maxino(void);
/*
* Calculate the number of blocks required to be able to address data block
* blkno (counting, of course, indirect blocks). blkno must >=0.
* Get a dinode of a given inum.
* XXX combine this function with vget.
*/
int
blksreqd(struct lfs * fs, int blkno)
{
long n = blkno;
if (blkno < NDADDR)
return blkno;
n -= NDADDR;
if (n < NINDIR(fs))
return blkno + 1;
n -= NINDIR(fs);
if (n < NINDIR(fs) * NINDIR(fs))
return blkno + 2 + n / NINDIR(fs) + 1;
n -= NINDIR(fs) * NINDIR(fs);
return blkno + 2 + NINDIR(fs) + n / (NINDIR(fs) * NINDIR(fs)) + 1;
}
#define BASE_SINDIR (NDADDR)
#define BASE_DINDIR (NDADDR+NINDIR(fs))
#define BASE_TINDIR (NDADDR+NINDIR(fs)+NINDIR(fs)*NINDIR(fs))
#define D_UNITS (NINDIR(fs))
#define T_UNITS (NINDIR(fs)*NINDIR(fs))
daddr_t lfs_bmap(struct lfs *, struct dinode *, daddr_t);
daddr_t
lfs_bmap(struct lfs * fs, struct dinode * idinode, daddr_t lbn)
{
daddr_t residue, up, off = 0;
struct bufarea *bp;
if (lbn > 0 && lbn > (idinode->di_size - 1) / dev_bsize) {
return UNASSIGNED;
}
/*
* Indirect blocks: if it is a first-level indirect, pull its
* address from the inode; otherwise, call ourselves to find the
* address of the parent indirect block, and load that to find
* the desired address.
*/
if (lbn < 0) {
lbn *= -1;
if (lbn == NDADDR) {
/* printf("lbn %d: single indir base\n", -lbn); */
return idinode->di_ib[0]; /* single indirect */
} else if (lbn == BASE_DINDIR + 1) {
/* printf("lbn %d: double indir base\n", -lbn); */
return idinode->di_ib[1]; /* double indirect */
} else if (lbn == BASE_TINDIR + 2) {
/* printf("lbn %d: triple indir base\n", -lbn); */
return idinode->di_ib[2]; /* triple indirect */
}
/*
* Find the immediate parent. This is essentially finding the
* residue of modulus, and then rounding accordingly.
*/
residue = (lbn - NDADDR) % NINDIR(fs);
if (residue == 1) {
/* Double indirect. Parent is the triple. */
up = idinode->di_ib[2];
off = (lbn - 2 - BASE_TINDIR) / (NINDIR(fs) * NINDIR(fs));
if (up == UNASSIGNED || up == LFS_UNUSED_DADDR)
return UNASSIGNED;
/* printf("lbn %d: parent is the triple\n", -lbn); */
bp = getddblk(up, sblock.lfs_bsize);
bp->b_flags &= ~B_INUSE;
return (daddr_t)(((int32_t *)(bp->b_un.b_buf))[off]);
} else { /* residue == 0 */
/* Single indirect. Two cases. */
if (lbn < BASE_TINDIR) {
/* Parent is the double, simple */
up = -(BASE_DINDIR) - 1;
off = (lbn - BASE_DINDIR) / D_UNITS;
/*
* printf("lbn %d: parent is %d/%d\n", -lbn,
* up,off);
*/
} else {
/* Ancestor is the triple, more complex */
up = ((lbn - BASE_TINDIR) / T_UNITS)
* T_UNITS + BASE_TINDIR + 1;
off = (lbn / D_UNITS) - (up / D_UNITS);
up = -up;
/*
* printf("lbn %d: parent is %d/%d\n", -lbn,
* up,off);
*/
}
}
} else {
/* Direct block. Its parent must be a single indirect. */
if (lbn < NDADDR)
return idinode->di_db[lbn];
else {
/* Parent is an indirect block. */
up = -(((lbn - NDADDR) / D_UNITS) * D_UNITS + NDADDR);
off = (lbn - NDADDR) % D_UNITS;
/* printf("lbn %d: parent is %d/%d\n", lbn,up,off); */
}
}
up = lfs_bmap(fs, idinode, up);
if (up == UNASSIGNED || up == LFS_UNUSED_DADDR)
return UNASSIGNED;
bp = getddblk(up, sblock.lfs_bsize);
bp->b_flags &= ~B_INUSE;
/* XXX ondisk32 */
return (daddr_t)(((int32_t *)(bp->b_un.b_buf))[off]);
}
/*
* This is kind of gross. We use this to find the nth block
* from a file whose inode has disk address idaddr. In practice
* we will only use this to find blocks of the ifile.
*/
static struct bufarea empty;
struct bufarea *
getfileblk(struct lfs * fs, struct dinode * idinode, ino_t lbn)
{
struct bufarea *bp;
daddr_t blkno;
static char empty_buf[65536];
empty.b_un.b_buf = &(empty_buf[0]);
blkno = lfs_bmap(fs, idinode, lbn);
if (blkno == UNASSIGNED || blkno == LFS_UNUSED_DADDR) {
printf("Warning: ifile lbn %d unassigned!\n", lbn);
return &empty;
}
bp = getddblk(blkno, sblock.lfs_bsize);
return bp;
}
#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);
}
return idinode;
}
#endif
struct ifile *
lfs_ientry(ino_t ino, struct bufarea ** bpp)
struct dinode *
ginode(ino_t ino)
{
struct uvnode *vp;
struct ubuf *bp;
IFILE *ifp;
*bpp = getfileblk(&sblock, lfs_ginode(LFS_IFILE_INUM),
ino / sblock.lfs_ifpb + sblock.lfs_cleansz +
sblock.lfs_segtabsz);
if (*bpp == &empty) {
printf("Warning: ino %d ientry in unassigned block\n", ino);
}
if (*bpp) {
if (sblock.lfs_version > 1) {
ifp = (((IFILE *)((*bpp)->b_un.b_buf)) +
(ino % sblock.lfs_ifpb));
} else {
ifp = (IFILE *)(((IFILE_V1 *)
((*bpp)->b_un.b_buf)) +
(ino % sblock.lfs_ifpb));
}
return ifp;
} else
return NULL;
}
SEGUSE *
lfs_gseguse(int segnum, struct bufarea ** bpp)
{
int blkno;
struct bufarea *bp;
blkno = segnum / sblock.lfs_sepb + sblock.lfs_cleansz;
(*bpp) = bp = getfileblk(&sblock, lfs_ginode(LFS_IFILE_INUM), blkno);
if (sblock.lfs_version == 1)
return (SEGUSE *)((SEGUSE_V1 *)(bp->b_un.b_buf) +
segnum % sblock.lfs_sepb);
else
return (SEGUSE *)(bp->b_un.b_buf) + segnum % sblock.lfs_sepb;
}
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 = 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[dtosn(&sblock, daddr)].su_nbytes += DINODE_SIZE;
}
return daddr;
}
struct dinode *
lfs_ginode(ino_t inumber)
{
struct ifile *ifp;
struct dinode *din;
struct bufarea *bp;
daddr_t daddr;
if (inumber >= maxino)
errexit("bad inode number %d to lfs_ginode\n", inumber);
#if 0
if (inumber == LFS_IFILE_INUM) {
daddr = idaddr;
if (din_table[LFS_IFILE_INUM] == 0) {
din_table[LFS_IFILE_INUM] = daddr;
seg_table[dtosn(&sblock, daddr)].su_nbytes += DINODE_SIZE;
}
return gidinode();
}
#endif
daddr = lfs_ino_daddr(inumber);
if (daddr == 0)
vp = vget(fs, ino);
if (vp == NULL)
return NULL;
if (pbp)
pbp->b_flags &= ~B_INUSE;
if (sblock.lfs_version == 1)
pbp = getddblk(daddr, sblock.lfs_bsize);
else
pbp = getddblk(daddr, sblock.lfs_fsize);
din = lfs_difind(&sblock, inumber, pbp->b_un.b_dinode);
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_freehd;
sblock.lfs_freehd = inumber;
sbdirty();
dirty(bp);
bp->b_flags &= ~B_INUSE;
}
if (din_table[ino] == 0x0) {
LFS_IENTRY(ifp, fs, ino, bp);
din_table[ino] = ifp->if_daddr;
seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes += DINODE_SIZE;
brelse(bp);
}
return din;
}
/* imported from lfs_vfsops.c */
int
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 {
ifp = lfs_ientry(ino, &bp);
if (ifp) {
daddr = ifp->if_daddr;
} else {
pwarn("Can't locate inode #%ud\n", ino);
}
bp->b_flags &= ~B_INUSE;
}
return daddr;
return &(VTOI(vp)->i_din.ffs_din);
}
/*
* Check validity of held (direct) blocks in an inode.
* Check validity of held blocks in an inode, recursing through all blocks.
*/
int
ckinode(struct dinode *dp, struct inodesc *idesc)
{
/* XXX ondisk32 */
register int32_t *ap;
long ret, n, ndb, offset;
struct dinode dino;
u_int64_t remsize, sizepb;
mode_t mode;
char pathbuf[MAXPATHLEN + 1];
ufs_daddr_t *ap, lbn;
long ret, n, ndb, offset;
struct dinode dino;
u_int64_t remsize, sizepb;
mode_t mode;
char pathbuf[MAXPATHLEN + 1];
struct uvnode *vp, *thisvp;
if (idesc->id_fix != IGNORE)
idesc->id_fix = DONTKNOW;
@ -401,34 +114,42 @@ ckinode(struct dinode *dp, struct inodesc *idesc)
idesc->id_filesize = dp->di_size;
mode = dp->di_mode & IFMT;
if (mode == IFBLK || mode == IFCHR ||
(mode == IFLNK && (dp->di_size < sblock.lfs_maxsymlinklen ||
(sblock.lfs_maxsymlinklen == 0 &&
dp->di_blocks == 0))))
(mode == IFLNK && (dp->di_size < fs->lfs_maxsymlinklen ||
(fs->lfs_maxsymlinklen == 0 &&
dp->di_blocks == 0))))
return (KEEPON);
dino = *dp;
ndb = howmany(dino.di_size, sblock.lfs_bsize);
ndb = howmany(dino.di_size, fs->lfs_bsize);
for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) {
thisvp = vget(fs, dino.di_u.inumber);
for (lbn = 0; lbn < NDADDR; lbn++) {
ap = dino.di_db + lbn;
if (thisvp)
idesc->id_numfrags =
numfrags(&sblock, fragroundup(&sblock, offset));
} else
idesc->id_numfrags = sblock.lfs_frag;
numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]);
else {
if (--ndb == 0 && (offset = blkoff(fs, dino.di_size)) != 0) {
idesc->id_numfrags =
numfrags(fs, fragroundup(fs, offset));
} else
idesc->id_numfrags = fs->lfs_frag;
}
if (*ap == 0) {
if (idesc->id_type == DATA && ndb >= 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
vp = vget(fs, idesc->id_number);
dp = VTOD(vp);
dp->di_size = (ap - &dino.di_db[0]) *
sblock.lfs_bsize;
fs->lfs_bsize;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
inodirty(VTOI(vp));
}
}
continue;
@ -436,16 +157,16 @@ ckinode(struct dinode *dp, struct inodesc *idesc)
idesc->id_blkno = *ap;
idesc->id_lblkno = ap - &dino.di_db[0];
if (idesc->id_type == ADDR) {
ret = (*idesc->id_func)(idesc);
ret = (*idesc->id_func) (idesc);
} else
ret = dirscan(idesc);
idesc->id_lblkno = 0;
if (ret & STOP)
return (ret);
}
idesc->id_numfrags = sblock.lfs_frag;
remsize = dino.di_size - sblock.lfs_bsize * NDADDR;
sizepb = sblock.lfs_bsize;
idesc->id_numfrags = fs->lfs_frag;
remsize = dino.di_size - fs->lfs_bsize * NDADDR;
sizepb = fs->lfs_bsize;
for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
if (*ap) {
idesc->id_blkno = *ap;
@ -456,107 +177,117 @@ ckinode(struct dinode *dp, struct inodesc *idesc)
if (idesc->id_type == DATA && remsize > 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
vp = vget(fs, idesc->id_number);
dp = VTOD(vp);
dp->di_size -= remsize;
remsize = 0;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
inodirty(VTOI(vp));
break;
}
}
}
sizepb *= NINDIR(&sblock);
sizepb *= NINDIR(fs);
remsize -= sizepb;
}
return (KEEPON);
}
static int
iblock(struct inodesc * idesc, long ilevel, u_int64_t isize)
iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
{
/* XXX ondisk32 */
int32_t *ap, *aplim;
struct bufarea *bp;
int i, n, (*func)(struct inodesc *), nif;
u_int64_t sizepb;
char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ];
struct dinode *dp;
ufs_daddr_t *ap, *aplim;
struct ubuf *bp;
int i, n, (*func) (struct inodesc *), nif;
u_int64_t sizepb;
char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ];
struct uvnode *devvp, *vp;
int diddirty = 0;
if (idesc->id_type == ADDR) {
func = idesc->id_func;
n = (*func)(idesc);
n = (*func) (idesc);
if ((n & KEEPON) == 0)
return (n);
} else
func = dirscan;
if (chkrange(idesc->id_blkno, fragstofsb(&sblock, idesc->id_numfrags)))
if (chkrange(idesc->id_blkno, fragstofsb(fs, idesc->id_numfrags)))
return (SKIP);
bp = getddblk(idesc->id_blkno, sblock.lfs_bsize);
devvp = fs->lfs_unlockvp;
bread(devvp, fsbtodb(fs, idesc->id_blkno), fs->lfs_bsize, NOCRED, &bp);
ilevel--;
for (sizepb = sblock.lfs_bsize, i = 0; i < ilevel; i++)
sizepb *= NINDIR(&sblock);
if (isize > sizepb * NINDIR(&sblock))
nif = NINDIR(&sblock);
for (sizepb = fs->lfs_bsize, i = 0; i < ilevel; i++)
sizepb *= NINDIR(fs);
if (isize > sizepb * NINDIR(fs))
nif = NINDIR(fs);
else
nif = howmany(isize, sizepb);
if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
if (idesc->id_func == pass1check && nif < NINDIR(fs)) {
aplim = ((ufs_daddr_t *) bp->b_data) + NINDIR(fs);
for (ap = ((ufs_daddr_t *) bp->b_data) + nif; ap < aplim; ap++) {
if (*ap == 0)
continue;
(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%u",
idesc->id_number);
(void) sprintf(buf, "PARTIALLY TRUNCATED INODE I=%u",
idesc->id_number);
if (dofix(idesc, buf)) {
*ap = 0;
dirty(bp);
++diddirty;
}
}
flush(fswritefd, bp);
}
aplim = &bp->b_un.b_indir[nif];
for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
aplim = ((ufs_daddr_t *) bp->b_data) + nif;
for (ap = ((ufs_daddr_t *) bp->b_data); ap < aplim; ap++) {
if (*ap) {
idesc->id_blkno = *ap;
if (ilevel == 0)
n = (*func)(idesc);
n = (*func) (idesc);
else
n = iblock(idesc, ilevel, isize);
if (n & STOP) {
bp->b_flags &= ~B_INUSE;
if (diddirty)
VOP_BWRITE(bp);
else
brelse(bp);
return (n);
}
} else {
if (idesc->id_type == DATA && isize > 0) {
/* An empty block in a directory XXX */
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
idesc->id_number);
pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
pathbuf);
pathbuf);
if (reply("ADJUST LENGTH") == 1) {
dp = ginode(idesc->id_number);
dp->di_size -= isize;
vp = vget(fs, idesc->id_number);
VTOI(vp)->i_ffs_size -= isize;
isize = 0;
printf(
"YOU MUST RERUN FSCK AFTERWARDS\n");
"YOU MUST RERUN FSCK AFTERWARDS\n");
rerun = 1;
inodirty();
bp->b_flags &= ~B_INUSE;
inodirty(VTOI(vp));
if (diddirty)
VOP_BWRITE(bp);
else
brelse(bp);
return (STOP);
}
}
}
isize -= sizepb;
}
bp->b_flags &= ~B_INUSE;
if (diddirty)
VOP_BWRITE(bp);
else
brelse(bp);
return (KEEPON);
}
/*
* Check that a block in a legal block number.
* Return 0 if in range, 1 if out of range.
@ -564,13 +295,13 @@ iblock(struct inodesc * idesc, long ilevel, u_int64_t isize)
int
chkrange(daddr_t blk, int cnt)
{
if (blk < sntod(&sblock, 0)) {
if (blk < sntod(fs, 0)) {
return (1);
}
if (blk > maxfsblock) {
return (1);
}
if (blk + cnt < sntod(&sblock, 0)) {
if (blk + cnt < sntod(fs, 0)) {
return (1);
}
if (blk + cnt > maxfsblock) {
@ -578,16 +309,6 @@ chkrange(daddr_t blk, int cnt)
}
return (0);
}
/*
* General purpose interface for reading inodes.
*/
struct dinode *
ginode(ino_t inumber)
{
return lfs_ginode(inumber);
}
/*
* Routines to maintain information about directory inodes.
* This is built during the first pass and used during the
@ -596,18 +317,17 @@ ginode(ino_t inumber)
* Enter inodes into the cache.
*/
void
cacheino(struct dinode *dp, ino_t inumber)
cacheino(struct dinode * dp, ino_t inumber)
{
register struct inoinfo *inp;
struct inoinfo *inp;
struct inoinfo **inpp;
unsigned int blks;
unsigned int blks;
blks = howmany(dp->di_size, sblock.lfs_bsize);
blks = howmany(dp->di_size, fs->lfs_bsize);
if (blks > NDADDR)
blks = NDADDR + NIADDR;
/* XXX ondisk32 */
inp = (struct inoinfo *)
malloc(sizeof(*inp) + (blks - 1) * sizeof(int32_t));
malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
if (inp == NULL)
return;
inpp = &inphead[inumber % numdirs];
@ -617,19 +337,19 @@ cacheino(struct dinode *dp, ino_t inumber)
if (inumber == ROOTINO)
inp->i_parent = ROOTINO;
else
inp->i_parent = (ino_t)0;
inp->i_dotdot = (ino_t)0;
inp->i_parent = (ino_t) 0;
inp->i_dotdot = (ino_t) 0;
inp->i_number = inumber;
inp->i_isize = dp->di_size;
/* XXX ondisk32 */
inp->i_numblks = blks * sizeof(int32_t);
memcpy(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
inp->i_numblks = blks * sizeof(ufs_daddr_t);
memcpy(&inp->i_blks[0], &dp->di_db[0], (size_t) inp->i_numblks);
if (inplast == listmax) {
listmax += 100;
inpsort = (struct inoinfo **)realloc((char *) inpsort,
(unsigned)listmax * sizeof(struct inoinfo *));
inpsort = (struct inoinfo **) realloc((char *) inpsort,
(unsigned) listmax * sizeof(struct inoinfo *));
if (inpsort == NULL)
errexit("cannot increase directory list\n");
err(8, "cannot increase directory list\n");
}
inpsort[inplast++] = inp;
}
@ -647,8 +367,8 @@ getinoinfo(ino_t inumber)
continue;
return (inp);
}
errexit("cannot find inode %d\n", inumber);
return ((struct inoinfo *)0);
err(8, "cannot find inode %d\n", inumber);
return ((struct inoinfo *) 0);
}
/*
@ -662,65 +382,64 @@ inocleanup()
if (inphead == NULL)
return;
for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
free((char *)(*inpp));
free((char *)inphead);
free((char *)inpsort);
free((char *) (*inpp));
free((char *) inphead);
free((char *) inpsort);
inphead = inpsort = NULL;
}
void
inodirty()
inodirty(struct inode *ip)
{
dirty(pbp);
ip->i_flag |= IN_MODIFIED;
}
void
clri(struct inodesc *idesc, char *type, int flag)
clri(struct inodesc * idesc, char *type, int flag)
{
register struct dinode *dp;
struct bufarea *bp;
IFILE *ifp;
struct ubuf *bp;
IFILE *ifp;
struct uvnode *vp;
dp = ginode(idesc->id_number);
vp = vget(fs, idesc->id_number);
if (flag == 1) {
pwarn("%s %s", type,
(dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
(VTOI(vp)->i_ffs_mode & IFMT) == IFDIR ? "DIR" : "FILE");
pinode(idesc->id_number);
}
if (preen || reply("CLEAR") == 1) {
if (preen)
if (flag == 2 || preen || reply("CLEAR") == 1) {
if (preen && flag != 2)
printf(" (CLEARED)\n");
n_files--;
(void)ckinode(dp, idesc);
clearinode(dp);
(void) ckinode(VTOD(vp), idesc);
clearinode(VTOD(vp));
statemap[idesc->id_number] = USTATE;
inodirty();
inodirty(VTOI(vp));
/* Send cleared inode to the free list */
ifp = lfs_ientry(idesc->id_number, &bp);
LFS_IENTRY(ifp, fs, idesc->id_number, bp);
ifp->if_daddr = LFS_UNUSED_DADDR;
ifp->if_nextfree = sblock.lfs_freehd;
sblock.lfs_freehd = idesc->id_number;
ifp->if_nextfree = fs->lfs_freehd;
fs->lfs_freehd = idesc->id_number;
sbdirty();
dirty(bp);
bp->b_flags &= ~B_INUSE;
VOP_BWRITE(bp);
}
}
int
findname(struct inodesc *idesc)
findname(struct inodesc * idesc)
{
register struct direct *dirp = idesc->id_dirp;
if (dirp->d_ino != idesc->id_parent)
return (KEEPON);
memcpy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
memcpy(idesc->id_name, dirp->d_name, (size_t) dirp->d_namlen + 1);
return (STOP | FOUND);
}
int
findino(struct inodesc *idesc)
findino(struct inodesc * idesc)
{
register struct direct *dirp = idesc->id_dirp;
@ -738,9 +457,9 @@ void
pinode(ino_t ino)
{
register struct dinode *dp;
register char *p;
struct passwd *pw;
time_t t;
register char *p;
struct passwd *pw;
time_t t;
printf(" I=%u ", ino);
if (ino < ROOTINO || ino >= maxino)
@ -749,15 +468,15 @@ pinode(ino_t ino)
if (dp) {
printf(" OWNER=");
#ifndef SMALL
if ((pw = getpwuid((int)dp->di_uid)) != 0)
if ((pw = getpwuid((int) dp->di_uid)) != 0)
printf("%s ", pw->pw_name);
else
#endif
printf("%u ", (unsigned)dp->di_uid);
printf("%u ", (unsigned) dp->di_uid);
printf("MODE=%o\n", dp->di_mode);
if (preen)
printf("%s: ", cdevname());
printf("SIZE=%llu ", (unsigned long long)dp->di_size);
printf("SIZE=%llu ", (unsigned long long) dp->di_size);
t = dp->di_mtime;
p = ctime(&t);
printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
@ -768,7 +487,7 @@ void
blkerror(ino_t ino, char *type, daddr_t blk)
{
pfatal("%lld %s I=%u", (long long)blk, type, ino);
pfatal("%lld %s I=%u", (long long) blk, type, ino);
printf("\n");
if (exitonfail)
exit(1);
@ -787,20 +506,21 @@ blkerror(ino_t ino, char *type, daddr_t blk)
return;
default:
errexit("BAD STATE %d TO BLKERR\n", statemap[ino]);
err(8, "BAD STATE %d TO BLKERR\n", statemap[ino]);
/* NOTREACHED */
}
}
/*
* allocate an unused inode
*/
ino_t
allocino(ino_t request, int type)
{
register ino_t ino;
register struct dinode *dp;
time_t t;
ino_t ino;
struct dinode *dp;
time_t t;
struct uvnode *vp;
struct ubuf *bp;
if (request == 0)
request = ROOTINO;
@ -822,42 +542,38 @@ allocino(ino_t request, int type)
default:
return (0);
}
dp = ginode(ino);
dp->di_db[0] = allocblk((long)1);
if (dp->di_db[0] == 0) {
statemap[ino] = USTATE;
return (0);
}
vp = vget(fs, ino);
dp = &(VTOI(vp)->i_din.ffs_din);
bp = getblk(vp, 0, fs->lfs_fsize);
VOP_BWRITE(bp);
dp->di_mode = type;
(void)time(&t);
(void) time(&t);
dp->di_atime = t;
dp->di_mtime = dp->di_ctime = dp->di_atime;
dp->di_size = sblock.lfs_fsize;
dp->di_blocks = btofsb(&sblock, sblock.lfs_fsize);
dp->di_size = fs->lfs_fsize;
dp->di_blocks = btofsb(fs, fs->lfs_fsize);
n_files++;
inodirty();
if (newinofmt)
typemap[ino] = IFTODT(type);
inodirty(VTOI(vp));
typemap[ino] = IFTODT(type);
return (ino);
}
/*
* deallocate an inode
*/
void
freeino(ino_t ino)
{
struct inodesc idesc;
struct dinode *dp;
struct inodesc idesc;
struct uvnode *vp;
memset(&idesc, 0, sizeof(struct inodesc));
idesc.id_type = ADDR;
idesc.id_func = pass4check;
idesc.id_number = ino;
dp = ginode(ino);
(void)ckinode(dp, &idesc);
clearinode(dp);
inodirty();
vp = vget(fs, ino);
(void) ckinode(VTOD(vp), &idesc);
clearinode(&VTOI(vp)->i_din.ffs_din);
inodirty(VTOI(vp));
statemap[ino] = USTATE;
n_files--;

779
sbin/fsck_lfs/lfs.c Normal file
View File

@ -0,0 +1,779 @@
/* $NetBSD: lfs.c,v 1.1 2003/03/28 08:09:53 perseant Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Copyright (c) 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
*
* @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#define vnode uvnode
#include <ufs/lfs/lfs.h>
#undef vnode
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "segwrite.h"
#define panic call_panic
extern u_int32_t cksum(void *, size_t);
extern u_int32_t lfs_sb_cksum(struct dlfs *);
extern struct uvnodelst vnodelist;
extern struct uvnodelst getvnodelist;
extern int nvnodes;
int fsdirty = 0;
void (*panic_func)(int, const char *, va_list) = my_vpanic;
/*
* LFS buffer and uvnode operations
*/
int
lfs_vop_strategy(struct ubuf * bp)
{
int count;
if (bp->b_flags & B_READ) {
count = pread(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
dbtob(bp->b_blkno));
if (count == bp->b_bcount)
bp->b_flags |= B_DONE;
} else {
count = pwrite(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
dbtob(bp->b_blkno));
if (count == 0) {
perror("pwrite");
return -1;
}
bp->b_flags &= ~B_DELWRI;
reassignbuf(bp, bp->b_vp);
}
return 0;
}
int
lfs_vop_bwrite(struct ubuf * bp)
{
struct lfs *fs;
fs = bp->b_vp->v_fs;
if (!(bp->b_flags & B_DELWRI)) {
fs->lfs_avail -= btofsb(fs, bp->b_bcount);
}
bp->b_flags |= B_DELWRI | B_LOCKED;
reassignbuf(bp, bp->b_vp);
brelse(bp);
return 0;
}
/*
* ufs_bmaparray does the bmap conversion, and if requested returns the
* array of logical blocks which must be traversed to get to a block.
* Each entry contains the offset into that block that gets you to the
* next block and the disk address of the block (if it is assigned).
*/
int
ufs_bmaparray(struct lfs * fs, struct uvnode * vp, daddr_t bn, daddr_t * bnp, struct indir * ap, int *nump)
{
struct inode *ip;
struct ubuf *bp;
struct indir a[NIADDR + 1], *xap;
daddr_t daddr;
daddr_t metalbn;
int error, num;
ip = VTOI(vp);
if (bn >= 0 && bn < NDADDR) {
if (nump != NULL)
*nump = 0;
*bnp = fsbtodb(fs, ip->i_ffs_db[bn]);
if (*bnp == 0)
*bnp = -1;
return (0);
}
xap = ap == NULL ? a : ap;
if (!nump)
nump = &num;
if ((error = ufs_getlbns(fs, vp, bn, xap, nump)) != 0)
return (error);
num = *nump;
/* Get disk address out of indirect block array */
daddr = ip->i_ffs_ib[xap->in_off];
for (bp = NULL, ++xap; --num; ++xap) {
/* Exit the loop if there is no disk address assigned yet and
* the indirect block isn't in the cache, or if we were
* looking for an indirect block and we've found it. */
metalbn = xap->in_lbn;
if ((daddr == 0 && !incore(vp, metalbn)) || metalbn == bn)
break;
/*
* If we get here, we've either got the block in the cache
* or we have a disk address for it, go fetch it.
*/
if (bp)
brelse(bp);
xap->in_exists = 1;
bp = getblk(vp, metalbn, fs->lfs_bsize);
if (!(bp->b_flags & (B_DONE | B_DELWRI))) {
bp->b_blkno = fsbtodb(fs, daddr);
bp->b_flags |= B_READ;
VOP_STRATEGY(bp);
}
daddr = ((ufs_daddr_t *) bp->b_data)[xap->in_off];
}
if (bp)
brelse(bp);
daddr = fsbtodb(fs, (ufs_daddr_t) daddr);
*bnp = daddr == 0 ? -1 : daddr;
return (0);
}
/*
* Create an array of logical block number/offset pairs which represent the
* path of indirect blocks required to access a data block. The first "pair"
* contains the logical block number of the appropriate single, double or
* triple indirect block and the offset into the inode indirect block array.
* Note, the logical block number of the inode single/double/triple indirect
* block appears twice in the array, once with the offset into the i_ffs_ib and
* once with the offset into the page itself.
*/
int
ufs_getlbns(struct lfs * fs, struct uvnode * vp, daddr_t bn, struct indir * ap, int *nump)
{
daddr_t metalbn, realbn;
int64_t blockcnt;
int lbc;
int i, numlevels, off;
int lognindir, indir;
if (nump)
*nump = 0;
numlevels = 0;
realbn = bn;
if (bn < 0)
bn = -bn;
lognindir = -1;
for (indir = fs->lfs_nindir; indir; indir >>= 1)
++lognindir;
/* Determine the number of levels of indirection. After this loop is
* done, blockcnt indicates the number of data blocks possible at the
* given level of indirection, and NIADDR - i is the number of levels
* of indirection needed to locate the requested block. */
bn -= NDADDR;
for (lbc = 0, i = NIADDR;; i--, bn -= blockcnt) {
if (i == 0)
return (EFBIG);
lbc += lognindir;
blockcnt = (int64_t) 1 << lbc;
if (bn < blockcnt)
break;
}
/* Calculate the address of the first meta-block. */
if (realbn >= 0)
metalbn = -(realbn - bn + NIADDR - i);
else
metalbn = -(-realbn - bn + NIADDR - i);
/* At each iteration, off is the offset into the bap array which is an
* array of disk addresses at the current level of indirection. The
* logical block number and the offset in that block are stored into
* the argument array. */
ap->in_lbn = metalbn;
ap->in_off = off = NIADDR - i;
ap->in_exists = 0;
ap++;
for (++numlevels; i <= NIADDR; i++) {
/* If searching for a meta-data block, quit when found. */
if (metalbn == realbn)
break;
lbc -= lognindir;
blockcnt = (int64_t) 1 << lbc;
off = (bn >> lbc) & (fs->lfs_nindir - 1);
++numlevels;
ap->in_lbn = metalbn;
ap->in_off = off;
ap->in_exists = 0;
++ap;
metalbn -= -1 + (off << lbc);
}
if (nump)
*nump = numlevels;
return (0);
}
int
lfs_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp)
{
return ufs_bmaparray(vp->v_fs, vp, lbn, daddrp, NULL, NULL);
}
/* Search a block for a specific dinode. */
struct dinode *
lfs_ifind(struct lfs * fs, ino_t ino, struct ubuf * bp)
{
struct dinode *dip = (struct dinode *) bp->b_data;
struct dinode *ldip, *fin;
fin = dip + INOPB(fs);
/*
* Read the inode block backwards, since later versions of the
* inode will supercede earlier ones. Though it is unlikely, it is
* possible that the same inode will appear in the same inode block.
*/
for (ldip = fin - 1; ldip >= dip; --ldip)
if (ldip->di_inumber == ino)
return (ldip);
return NULL;
}
/*
* lfs_raw_vget makes us a new vnode from the inode at the given disk address.
* XXX it currently loses atime information.
*/
struct uvnode *
lfs_raw_vget(struct lfs * fs, ino_t ino, int fd, ufs_daddr_t daddr)
{
struct uvnode *vp;
struct inode *ip;
struct dinode *dip;
struct ubuf *bp;
int i;
vp = (struct uvnode *) malloc(sizeof(*vp));
memset(vp, 0, sizeof(*vp));
vp->v_fd = fd;
vp->v_fs = fs;
vp->v_usecount = 0;
vp->v_strategy_op = lfs_vop_strategy;
vp->v_bwrite_op = lfs_vop_bwrite;
vp->v_bmap_op = lfs_vop_bmap;
++nvnodes;
LIST_INSERT_HEAD(&getvnodelist, vp, v_getvnodes);
LIST_INSERT_HEAD(&vnodelist, vp, v_mntvnodes);
vp->v_data = ip = (struct inode *) malloc(sizeof(*ip));
memset(ip, 0, sizeof(*ip));
/* Initialize the inode -- from lfs_vcreate. */
ip->inode_ext.lfs = malloc(sizeof(struct lfs_inode_ext));
memset(ip->inode_ext.lfs, 0, sizeof(struct lfs_inode_ext));
vp->v_data = ip;
/* ip->i_vnode = vp; */
ip->i_number = ino;
ip->i_lockf = 0;
ip->i_diroff = 0;
ip->i_ffs_mode = 0;
ip->i_ffs_size = 0;
ip->i_ffs_blocks = 0;
ip->i_lfs_effnblks = 0;
ip->i_flag = 0;
/* Load inode block and find inode */
bread(fs->lfs_unlockvp, fsbtodb(fs, daddr), fs->lfs_ibsize, NULL, &bp);
bp->b_flags |= B_AGE;
dip = lfs_ifind(fs, ino, bp);
if (dip == NULL) {
brelse(bp);
free(vp);
return NULL;
}
memcpy(&ip->i_din.ffs_din, dip, sizeof(*dip));
brelse(bp);
ip->i_number = ino;
/* ip->i_devvp = fs->lfs_unlockvp; */
ip->i_lfs = fs;
ip->i_ffs_effnlink = ip->i_ffs_nlink;
ip->i_lfs_effnblks = ip->i_ffs_blocks;
ip->i_lfs_osize = ip->i_ffs_size;
#if 0
if (fs->lfs_version > 1) {
ip->i_ffs_atime = ts.tv_sec;
ip->i_ffs_atimensec = ts.tv_nsec;
}
#endif
memset(ip->i_lfs_fragsize, 0, NDADDR * sizeof(*ip->i_lfs_fragsize));
for (i = 0; i < NDADDR; i++)
if (ip->i_ffs_db[i] != 0)
ip->i_lfs_fragsize[i] = blksize(fs, ip, i);
return vp;
}
static struct uvnode *
lfs_vget(void *vfs, ino_t ino)
{
struct lfs *fs = (struct lfs *)vfs;
ufs_daddr_t daddr;
struct ubuf *bp;
IFILE *ifp;
LFS_IENTRY(ifp, fs, ino, bp);
daddr = ifp->if_daddr;
brelse(bp);
if (daddr == 0)
return NULL;
return lfs_raw_vget(fs, ino, fs->lfs_ivnode->v_fd, daddr);
}
/* Check superblock magic number and checksum */
static int
check_sb(struct lfs *fs)
{
u_int32_t checksum;
if (fs->lfs_magic != LFS_MAGIC) {
printf("Superblock magic number (0x%lx) does not match "
"expected 0x%lx\n", (unsigned long) fs->lfs_magic,
(unsigned long) LFS_MAGIC);
return 1;
}
/* checksum */
checksum = lfs_sb_cksum(&(fs->lfs_dlfs));
if (fs->lfs_cksum != checksum) {
printf("Superblock checksum (%lx) does not match computed checksum (%lx)\n",
(unsigned long) fs->lfs_cksum, (unsigned long) checksum);
return 1;
}
return 0;
}
/* Initialize LFS library; load superblocks and choose which to use. */
struct lfs *
lfs_init(int devfd, daddr_t sblkno, daddr_t idaddr, int debug)
{
struct uvnode *devvp;
struct ubuf *bp;
int tryalt;
struct lfs *fs, *altfs;
int error;
vfs_init();
devvp = (struct uvnode *) malloc(sizeof(*devvp));
devvp->v_fs = NULL;
devvp->v_fd = devfd;
devvp->v_strategy_op = raw_vop_strategy;
devvp->v_bwrite_op = raw_vop_bwrite;
devvp->v_bmap_op = raw_vop_bmap;
tryalt = 0;
if (sblkno == 0) {
sblkno = btodb(LFS_LABELPAD);
tryalt = 1;
} else if (debug) {
printf("No -b flag given, not attempting to verify checkpoint\n");
}
error = bread(devvp, sblkno, LFS_SBPAD, NOCRED, &bp);
fs = (struct lfs *) malloc(sizeof(*fs));
*fs = *((struct lfs *) bp->b_data);
fs->lfs_unlockvp = devvp;
bp->b_flags |= B_INVAL;
brelse(bp);
if (tryalt) {
error = bread(devvp, fsbtodb(fs, fs->lfs_sboffs[1]),
LFS_SBPAD, NOCRED, &bp);
altfs = (struct lfs *) malloc(sizeof(*fs));
*altfs = *((struct lfs *) bp->b_data);
altfs->lfs_unlockvp = devvp;
bp->b_flags |= B_INVAL;
brelse(bp);
if (check_sb(fs)) {
if (debug)
printf("Primary superblock is no good, using first alternate\n");
free(fs);
fs = altfs;
} else {
/* If both superblocks check out, try verification */
if (check_sb(altfs)) {
if (debug)
printf("First alternate superblock is no good, using primary\n");
free(altfs);
} else {
if (lfs_verify(fs, altfs, devvp, debug) == fs) {
free(altfs);
} else {
free(fs);
fs = altfs;
}
}
}
}
if (check_sb(fs)) {
free(fs);
return NULL;
}
/* Compatibility */
if (fs->lfs_version < 2) {
fs->lfs_sumsize = LFS_V1_SUMMARY_SIZE;
fs->lfs_ibsize = fs->lfs_bsize;
fs->lfs_start = fs->lfs_sboffs[0];
fs->lfs_tstamp = fs->lfs_otstamp;
fs->lfs_fsbtodb = 0;
}
fs->lfs_suflags = (u_int32_t **) malloc(2 * sizeof(u_int32_t *));
fs->lfs_suflags[0] = (u_int32_t *) malloc(fs->lfs_nseg * sizeof(u_int32_t));
fs->lfs_suflags[1] = (u_int32_t *) malloc(fs->lfs_nseg * sizeof(u_int32_t));
if (idaddr == 0)
idaddr = fs->lfs_idaddr;
fs->lfs_ivnode = lfs_raw_vget(fs, fs->lfs_ifile, devvp->v_fd, idaddr);
register_vget((void *)fs, lfs_vget);
return fs;
}
/*
* Check partial segment validity between fs->lfs_offset and the given goal.
* If goal == 0, just keep on going until the segments stop making sense.
* Return the address of the first partial segment that failed.
*/
ufs_daddr_t
try_verify(struct lfs *osb, struct uvnode *devvp, ufs_daddr_t goal, int debug)
{
ufs_daddr_t daddr, odaddr;
SEGSUM *sp;
int bc, flag;
struct ubuf *bp;
ufs_daddr_t nodirop_daddr;
u_int64_t serial;
daddr = osb->lfs_offset;
nodirop_daddr = daddr;
serial = osb->lfs_serial;
while (daddr != goal) {
flag = 0;
oncemore:
/* Read in summary block */
bread(devvp, fsbtodb(osb, daddr), osb->lfs_sumsize, NULL, &bp);
sp = (SEGSUM *)bp->b_data;
/*
* 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_ident != osb->lfs_ident ||
sp->ss_serial < serial ||
sp->ss_sumsum != cksum(&sp->ss_datasum, osb->lfs_sumsize -
sizeof(sp->ss_sumsum))) {
brelse(bp);
if (flag == 0) {
flag = 1;
daddr += btofsb(osb, LFS_SBPAD);
goto oncemore;
}
break;
}
++serial;
bc = check_summary(osb, sp, daddr, debug, devvp, NULL);
if (bc == 0) {
brelse(bp);
break;
}
assert (bc > 0);
odaddr = daddr;
daddr += btofsb(osb, osb->lfs_sumsize + bc);
if (dtosn(osb, odaddr) != dtosn(osb, daddr) ||
dtosn(osb, daddr) != dtosn(osb, daddr +
btofsb(osb, osb->lfs_sumsize + osb->lfs_bsize))) {
daddr = sp->ss_next;
}
if (!(sp->ss_flags & SS_CONT))
nodirop_daddr = daddr;
brelse(bp);
}
if (goal == 0)
return nodirop_daddr;
else
return daddr;
}
/* Use try_verify to check whether the newer superblock is valid. */
struct lfs *
lfs_verify(struct lfs *sb0, struct lfs *sb1, struct uvnode *devvp, int debug)
{
ufs_daddr_t daddr;
struct lfs *osb, *nsb;
/*
* Verify the checkpoint of the newer superblock,
* if the timestamp/serial number of the two superblocks is
* different.
*/
if (debug)
printf("sb0 %lld, sb1 %lld\n", (long long) sb0->lfs_serial,
(long long) sb1->lfs_serial);
if ((sb0->lfs_version == 1 &&
sb0->lfs_otstamp != sb1->lfs_otstamp) ||
(sb0->lfs_version > 1 &&
sb0->lfs_serial != sb1->lfs_serial)) {
if (sb0->lfs_version == 1) {
if (sb0->lfs_otstamp > sb1->lfs_otstamp) {
osb = sb1;
nsb = sb0;
} else {
osb = sb0;
nsb = sb1;
}
} else {
if (sb0->lfs_serial > sb1->lfs_serial) {
osb = sb1;
nsb = sb0;
} else {
osb = sb0;
nsb = sb1;
}
}
if (debug) {
printf("Attempting to verify newer checkpoint...");
fflush(stdout);
}
daddr = try_verify(osb, devvp, nsb->lfs_offset, debug);
if (debug)
printf("done.\n");
if (daddr == nsb->lfs_offset) {
warnx("** Newer checkpoint verified, recovered %lld seconds of data\n",
(long long) nsb->lfs_tstamp - (long long) osb->lfs_tstamp);
sbdirty();
} else {
warnx("** Newer checkpoint invalid, lost %lld seconds of data\n", (long long) nsb->lfs_tstamp - (long long) osb->lfs_tstamp);
}
return (daddr == nsb->lfs_offset ? nsb : osb);
}
/* Nothing to check */
return osb;
}
/* Verify a partial-segment summary; return the number of bytes on disk. */
int
check_summary(struct lfs *fs, SEGSUM *sp, ufs_daddr_t pseg_addr, int debug,
struct uvnode *devvp, void (func(ufs_daddr_t, FINFO *)))
{
FINFO *fp;
int bc; /* Bytes in partial segment */
int nblocks;
ufs_daddr_t seg_addr, daddr;
ufs_daddr_t *dp, *idp;
struct ubuf *bp;
int i, j, k, datac, len;
long sn;
u_int32_t *datap;
u_int32_t ccksum;
sn = dtosn(fs, pseg_addr);
seg_addr = sntod(fs, sn);
/* We've already checked the sumsum, just do the data bounds and sum */
/* Count the blocks. */
nblocks = howmany(sp->ss_ninos, INOPB(fs));
bc = nblocks << (fs->lfs_version > 1 ? fs->lfs_ffshift : fs->lfs_bshift);
assert(bc >= 0);
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);
assert(bc >= 0);
fp = (FINFO *) (fp->fi_blocks + fp->fi_nblocks);
}
datap = (u_int32_t *) malloc(nblocks * sizeof(*datap));
datac = 0;
dp = (ufs_daddr_t *) sp;
dp += fs->lfs_sumsize / sizeof(ufs_daddr_t);
dp--;
idp = dp;
daddr = pseg_addr + btofsb(fs, fs->lfs_sumsize);
fp = (FINFO *) (sp + 1);
for (i = 0, j = 0;
i < sp->ss_nfinfo || j < howmany(sp->ss_ninos, INOPB(fs)); i++) {
if (i >= sp->ss_nfinfo && *idp != daddr) {
warnx("Not enough inode blocks in pseg at 0x" PRIx32
": found %d, wanted %d\n",
pseg_addr, j, howmany(sp->ss_ninos, INOPB(fs)));
if (debug)
warnx("*idp=%x, daddr=%" PRIx32 "\n", *idp,
daddr);
break;
}
while (j < howmany(sp->ss_ninos, INOPB(fs)) && *idp == daddr) {
bread(devvp, fsbtodb(fs, daddr), fs->lfs_ibsize, NOCRED, &bp);
datap[datac++] = ((u_int32_t *) (bp->b_data))[0];
brelse(bp);
++j;
daddr += btofsb(fs, fs->lfs_ibsize);
--idp;
}
if (i < sp->ss_nfinfo) {
if (func)
func(daddr, fp);
for (k = 0; k < fp->fi_nblocks; k++) {
len = (k == fp->fi_nblocks - 1 ?
fp->fi_lastlength
: fs->lfs_bsize);
bread(devvp, fsbtodb(fs, daddr), len, NOCRED, &bp);
datap[datac++] = ((u_int32_t *) (bp->b_data))[0];
brelse(bp);
daddr += btofsb(fs, len);
}
fp = (FINFO *) (fp->fi_blocks + fp->fi_nblocks);
}
}
if (datac != nblocks) {
warnx("Partial segment at 0x%llx expected %d blocks counted %d\n",
(long long) pseg_addr, nblocks, datac);
}
ccksum = cksum(datap, nblocks * sizeof(u_int32_t));
/* Check the data checksum */
if (ccksum != sp->ss_datasum) {
warnx("Partial segment at 0x%" PRIx32 " data checksum"
" mismatch: given 0x%x, computed 0x%x\n",
pseg_addr, sp->ss_datasum, ccksum);
free(datap);
return 0;
}
free(datap);
assert(bc >= 0);
return bc;
}
/* print message and exit */
void
my_vpanic(int fatal, const char *fmt, va_list ap)
{
(void) vprintf(fmt, ap);
exit(8);
}
void
call_panic(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
panic_func(1, fmt, ap);
va_end(ap);
}

76
sbin/fsck_lfs/lfs.h Normal file
View File

@ -0,0 +1,76 @@
/* $NetBSD: lfs.h,v 1.1 2003/03/28 08:09:53 perseant Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <stdarg.h>
struct lfs;
struct segsum;
struct finfo;
/*
* Structure used to pass around logical block paths generated by
* ufs_getlbns and used by truncate and bmap code.
*/
struct indir {
daddr_t in_lbn; /* Logical block number. */
int in_off; /* Offset in buffer. */
int in_exists; /* Flag if the block exists. */
};
typedef int32_t ufs_daddr_t;
/* Convert between inode pointers and vnode pointers. */
#define VTOI(vp) ((struct inode *)(vp)->v_data)
#define VTOD(vp) (&VTOI(vp)->i_din.ffs_din)
#define sbdirty() ++fsdirty
extern int fsdirty;
extern struct uvnodelst vnodelist;
int lfs_vop_strategy(struct ubuf *);
int lfs_vop_bwrite(struct ubuf *);
int lfs_vop_bmap(struct uvnode *, daddr_t, daddr_t *);
struct uvnode *lfs_raw_vget(struct lfs *, ino_t, int, ufs_daddr_t);
struct lfs *lfs_init(int, daddr_t, daddr_t, int);
struct lfs *lfs_verify(struct lfs *, struct lfs *, struct uvnode *, int);
int check_summary(struct lfs *, struct segsum *, ufs_daddr_t, int, struct uvnode *, void (*)(ufs_daddr_t, struct finfo *));
ufs_daddr_t try_verify(struct lfs *, struct uvnode *, ufs_daddr_t, int);
struct dinode *lfs_ifind(struct lfs *, ino_t, struct ubuf *);
void call_panic(const char *, ...);
void my_vpanic(int, const char *, va_list);

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.12 2003/01/28 05:17:13 mrg Exp $ */
/* $NetBSD: main.c,v 1.13 2003/03/28 08:09:53 perseant Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -40,7 +40,9 @@
#include <sys/mount.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/lfs/lfs.h>
#include <fstab.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@ -52,39 +54,34 @@
#include "extern.h"
#include "fsutil.h"
int returntosingle;
int fake_cleanseg = -1;
int returntosingle;
int main(int, char *[]);
int main(int, char *[]);
static int argtoi(int, char *, char *, int);
static int checkfilesys(const char *, char *, long, int);
#if 0
static int docheck(struct fstab *);
#endif
static void usage(void);
static int argtoi(int, char *, char *, int);
static int checkfilesys(const char *, char *, long, int);
static void usage(void);
extern void (*panic_func)(int, const char *, va_list);
int
main(int argc, char **argv)
{
int ch;
int ret = 0;
char *optstring = "b:C:dfi:m:npy";
int ch;
int ret = 0;
char *optstring = "b:dfi:m:npy";
sync();
skipclean = 1;
exitonfail = 0;
idaddr = 0x0;
panic_func = vmsg;
while ((ch = getopt(argc, argv, optstring)) != -1) {
switch (ch) {
case 'b':
skipclean = 0;
bflag = argtoi('b', "number", optarg, 10);
bflag = argtoi('b', "number", optarg, 0);
printf("Alternate super block location: %d\n", bflag);
break;
case 'C':
fake_cleanseg = atoi(optarg);
break;
case 'd':
debug++;
break;
@ -100,7 +97,7 @@ main(int argc, char **argv)
case 'm':
lfmode = argtoi('m', "mode", optarg, 8);
if (lfmode & ~07777)
errexit("bad mode to -m: %o\n", lfmode);
err(1, "bad mode to -m: %o\n", lfmode);
printf("** lost+found creation mode %o\n", lfmode);
break;
@ -122,11 +119,6 @@ main(int argc, char **argv)
usage();
}
}
#if 0
if (nflag == 0) {
errexit("fsck_lfs cannot write to the filesystem yet; the -n flag is required.\n");
}
#endif
argc -= optind;
argv += optind;
@ -135,12 +127,12 @@ main(int argc, char **argv)
usage();
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
(void)signal(SIGINT, catch);
(void) signal(SIGINT, catch);
if (preen)
(void)signal(SIGQUIT, catchquit);
(void) signal(SIGQUIT, catchquit);
while (argc-- > 0)
(void)checkfilesys(blockcheck(*argv++), 0, 0L, 0);
(void) checkfilesys(blockcheck(*argv++), 0, 0L, 0);
if (returntosingle)
ret = 2;
@ -151,46 +143,28 @@ main(int argc, char **argv)
static int
argtoi(int flag, char *req, char *str, int base)
{
char *cp;
int ret;
char *cp;
int ret;
ret = (int)strtol(str, &cp, base);
ret = (int) strtol(str, &cp, base);
if (cp == str || *cp)
errexit("-%c flag requires a %s\n", flag, req);
err(1, "-%c flag requires a %s\n", flag, req);
return (ret);
}
#if 0
/*
* Determine whether a filesystem should be checked.
*/
static int
docheck(struct fstab * fsp)
{
if ((strcmp(fsp->fs_vfstype, "ufs") &&
strcmp(fsp->fs_vfstype, "ffs")) ||
(strcmp(fsp->fs_type, FSTAB_RW) &&
strcmp(fsp->fs_type, FSTAB_RO)) ||
fsp->fs_passno == 0)
return (0);
return (1);
}
#endif
/*
* Check the specified filesystem.
*/
/* ARGSUSED */
static int
checkfilesys(const char *filesys, char *mntpt, long auxdata, int child)
{
daddr_t n_ffree = 0, n_bfree = 0;
struct dups *dp;
struct zlncnt *zlnp;
struct dups *dp;
struct zlncnt *zlnp;
if (preen && child)
(void)signal(SIGQUIT, voidquit);
(void) signal(SIGQUIT, voidquit);
setcdevname(filesys, preen);
if (debug && preen)
pwarn("starting\n");
@ -202,105 +176,107 @@ checkfilesys(const char *filesys, char *mntpt, long auxdata, int child)
return (0);
}
/*
* For LFS, "preen" means "roll forward". We don't check anything
* else.
*/
if (preen == 0) {
printf("** Last Mounted on %s\n", sblock.lfs_fsmnt);
printf("** Last Mounted on %s\n", fs->lfs_fsmnt);
if (hotroot())
printf("** Root file system\n");
}
/*
* 0: check segment checksums, inode ranges
*/
if (preen == 0)
/*
* 0: check segment checksums, inode ranges
*/
printf("** Phase 0 - Check Segment Summaries and Inode Free List\n");
if (idaddr != sblock.lfs_idaddr)
pwarn("-i given, skipping free list check\n");
else
pass0();
if (idaddr)
pwarn("-i given, skipping free list check\n");
else
pass0();
if (preen == 0) {
/*
* 1: scan inodes tallying blocks used
*/
if (preen == 0)
printf("** Phase 1 - Check Blocks and Sizes\n");
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");
printf("** Phase 2 - Check Pathnames\n");
pass2();
/*
* 3: scan inodes looking for disconnected directories
*/
if (preen == 0)
printf("** Phase 3 - Check Connectivity\n");
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");
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");
printf("** Phase 5 - Check Segment Block Accounting\n");
pass5();
/*
* print out summary statistics
*/
pwarn("%d files, %lld used, %lld free ",
n_files, (long long)n_blks,
(long long)(n_ffree + sblock.lfs_frag * n_bfree));
putchar('\n');
}
if (debug) {
if (duplist != NULL) {
printf("The following duplicate blocks remain:");
for (dp = duplist; dp; dp = dp->next)
printf(" %lld,", (long long)dp->dup);
printf("\n");
}
if (zlnhead != NULL) {
printf("The following zero link count inodes remain:");
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
printf(" %u,", zlnp->zlncnt);
printf("\n");
if (debug) {
if (duplist != NULL) {
printf("The following duplicate blocks remain:");
for (dp = duplist; dp; dp = dp->next)
printf(" %lld,", (long long) dp->dup);
printf("\n");
}
if (zlnhead != NULL) {
printf("The following zero link count inodes remain:");
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
printf(" %u,", zlnp->zlncnt);
printf("\n");
}
}
}
zlnhead = (struct zlncnt *)0;
duplist = (struct dups *)0;
muldup = (struct dups *)0;
if (!rerun) {
if (!preen)
printf("** Phase 6 - Roll Forward\n");
pass6();
}
zlnhead = (struct zlncnt *) 0;
duplist = (struct dups *) 0;
muldup = (struct dups *) 0;
inocleanup();
/*
* print out summary statistics
*/
pwarn("%d files, %lld used, %lld free\n",
n_files, (long long) n_blks,
(long long) fs->lfs_bfree);
ckfini(1);
free(blockmap);
free(statemap);
free((char *)lncntp);
if (!fsmodified)
if (!fsmodified) {
return (0);
}
if (!preen)
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
if (rerun)
printf("\n***** PLEASE RERUN FSCK *****\n");
if (hotroot()) {
struct statfs stfs_buf;
struct statfs stfs_buf;
/*
* We modified the root. Do a mount update on
* it, unless it is read-write, so we can continue.
*/
if (statfs("/", &stfs_buf) == 0) {
long flags = stfs_buf.f_flags;
long flags = stfs_buf.f_flags;
struct ufs_args args;
int ret;
int ret;
if (flags & MNT_RDONLY) {
args.fspec = 0;
@ -324,8 +300,8 @@ static void
usage()
{
(void)fprintf(stderr,
"Usage: %s [-dnpy] [-b block] [-m mode] filesystem ...\n",
getprogname());
(void) fprintf(stderr,
"Usage: %s [-dnpy] [-b block] [-m mode] filesystem ...\n",
getprogname());
exit(1);
}

View File

@ -1,7 +1,41 @@
/* $NetBSD: pass0.c,v 1.13 2003/02/17 23:48:09 perseant Exp $ */
/* $NetBSD: pass0.c,v 1.14 2003/03/28 08:09:53 perseant Exp $ */
/*
* Copyright (c) 1998 Konrad E. Schroder.
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*-
* Copyright (c) 1980, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
@ -34,30 +68,31 @@
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#define vnode uvnode
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#undef vnode
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fsck.h"
#include "extern.h"
#include "fsutil.h"
/* Flags for check_segment */
#define CKSEG_VERBOSE 1
#define CKSEG_IGNORECLEAN 2
extern int fake_cleanseg;
void
check_segment(int, int, daddr_t, struct lfs *, int,
int (*)(struct lfs *, SEGSUM *, daddr_t));
extern int fake_cleanseg;
/*
* Pass 0. Check the LFS partial segments for valid checksums, correcting
@ -68,60 +103,58 @@ check_segment(int, int, daddr_t, struct lfs *, int,
* finfo blocks, for one thing.
*/
#define dbshift (sblock.lfs_bshift - sblock.lfs_blktodb)
#define dbshift (fs->lfs_bshift - fs->lfs_blktodb)
void
pass0()
{
daddr_t daddr;
IFILE *ifp;
struct bufarea *bp;
ino_t ino, plastino, nextino, *visited;
daddr_t daddr;
IFILE *ifp;
struct ubuf *bp;
ino_t ino, plastino, nextino, *visited;
/*
* Check the inode free list for inuse inodes, and cycles.
* Make sure that all free inodes are in fact on the list.
*/
visited = (ino_t *)malloc(maxino * sizeof(ino_t));
visited = (ino_t *) malloc(maxino * sizeof(ino_t));
memset(visited, 0, maxino * sizeof(ino_t));
plastino = 0;
ino = sblock.lfs_freehd;
ino = fs->lfs_freehd;
while (ino) {
if (ino >= maxino) {
printf("! Ino %d out of range (last was %d)\n", ino,
plastino);
plastino);
break;
}
if (visited[ino]) {
pwarn("! Ino %d already found on the free list!\n",
ino);
ino);
if (preen || reply("FIX") == 1) {
/* plastino can't be zero */
ifp = lfs_ientry(plastino, &bp);
LFS_IENTRY(ifp, fs, plastino, bp);
ifp->if_nextfree = 0;
dirty(bp);
bp->b_flags &= ~B_INUSE;
VOP_BWRITE(bp);
}
break;
}
++visited[ino];
ifp = lfs_ientry(ino, &bp);
LFS_IENTRY(ifp, fs, ino, bp);
nextino = ifp->if_nextfree;
daddr = ifp->if_daddr;
bp->b_flags &= ~B_INUSE;
brelse(bp);
if (daddr) {
pwarn("! Ino %d with daddr 0x%llx is on the free list!\n",
ino, (long long)daddr);
ino, (long long) daddr);
if (preen || reply("FIX") == 1) {
if (plastino == 0) {
sblock.lfs_freehd = nextino;
fs->lfs_freehd = nextino;
sbdirty();
} else {
ifp = lfs_ientry(plastino, &bp);
LFS_IENTRY(ifp, fs, plastino, bp);
ifp->if_nextfree = nextino;
dirty(bp);
bp->b_flags &= ~B_INUSE;
VOP_BWRITE(bp);
}
ino = nextino;
continue;
@ -133,244 +166,22 @@ pass0()
/*
* Make sure all free inodes were found on the list
*/
for (ino = ROOTINO+1; ino < maxino; ++ino) {
for (ino = ROOTINO + 1; ino < maxino; ++ino) {
if (visited[ino])
continue;
ifp = lfs_ientry(ino, &bp);
LFS_IENTRY(ifp, fs, ino, bp);
if (ifp->if_daddr) {
bp->b_flags &= ~B_INUSE;
brelse(bp);
continue;
}
pwarn("! Ino %d free, but not on the free list\n", ino);
if (preen || reply("FIX") == 1) {
ifp->if_nextfree = sblock.lfs_freehd;
sblock.lfs_freehd = ino;
ifp->if_nextfree = fs->lfs_freehd;
fs->lfs_freehd = ino;
sbdirty();
dirty(bp);
}
bp->b_flags &= ~B_INUSE;
VOP_BWRITE(bp);
} else
brelse(bp);
}
}
static void
dump_segsum(SEGSUM * sump, daddr_t addr)
{
printf("Dump partial summary block 0x%llx\n", (long long)addr);
printf("\tsumsum: %x (%d)\n", sump->ss_sumsum, sump->ss_sumsum);
printf("\tdatasum: %x (%d)\n", sump->ss_datasum, sump->ss_datasum);
printf("\tnext: %x (%d)\n", sump->ss_next, sump->ss_next);
printf("\tcreate: %llx (%lld)\n", (long long)sump->ss_create,
(long long)sump->ss_create);
printf("\tnfinfo: %x (%d)\n", sump->ss_nfinfo, sump->ss_nfinfo);
printf("\tninos: %x (%d)\n", sump->ss_ninos, sump->ss_ninos);
printf("\tflags: %c%c\n",
sump->ss_flags & SS_DIROP ? 'd' : '-',
sump->ss_flags & SS_CONT ? 'c' : '-');
}
/* XXX Don't use... broken. -JO */
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;
struct bufarea *bp = NULL;
int psegnum = 0, ninos = 0;
off_t sum_offset, db_ssize;
int bc, su_flags, su_nsums, su_ninos;
db_ssize = segtod(&sblock, 1);
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)
pwarn("WARNING: segment begins at 0x%llx, should be 0x%llx\n",
(long long unsigned)addr,
(long long unsigned)(segnum * db_ssize + fs->lfs_sboffs[0]));
sum_offset = ((off_t)addr << dbshift);
/* If this segment should have a superblock, look for one */
if (su_flags & SEGUSE_SUPERBLOCK) {
bp = getddblk(sum_offset >> dbshift, LFS_SBPAD);
sum_offset += LFS_SBPAD;
/* check for a superblock -- XXX this is crude */
sbp = (struct lfs *)(bp->b_un.b_buf);
if (sbp->lfs_magic == LFS_MAGIC) {
#if 0
if (sblock.lfs_tstamp == sbp->lfs_tstamp &&
memcmp(sbp, &sblock, sizeof(*sbp)) &&
(flags & CKSEG_VERBOSE))
pwarn("SUPERBLOCK MISMATCH SEGMENT %d\n", segnum);
#endif
} else {
if (flags & CKSEG_VERBOSE)
pwarn("SEGMENT %d SUPERBLOCK INVALID\n", segnum);
/* XXX allow to fix */
}
bp->b_flags &= ~B_INUSE;
}
/* XXX need to also check whether this one *should* be dirty */
if ((flags & CKSEG_IGNORECLEAN) && (su_flags & SEGUSE_DIRTY) == 0)
return;
while (1) {
if (su_nsums <= psegnum)
break;
bp = getddblk(sum_offset >> dbshift, sblock.lfs_sumsize);
sump = (SEGSUM *)(bp->b_un.b_buf);
if (sump->ss_magic != SS_MAGIC) {
if (flags & CKSEG_VERBOSE)
printf("PARTIAL SEGMENT %d SEGMENT %d BAD PARTIAL SEGMENT MAGIC (0x%x should be 0x%x)\n",
psegnum, segnum, sump->ss_magic, SS_MAGIC);
bp->b_flags &= ~B_INUSE;
break;
}
if (sump->ss_sumsum != cksum(&sump->ss_datasum, sblock.lfs_sumsize - sizeof(sump->ss_sumsum))) {
if (flags & CKSEG_VERBOSE) {
/* Corrupt partial segment */
pwarn("CORRUPT PARTIAL SEGMENT %d/%d OF SEGMENT %d AT BLK 0x%llx",
psegnum, su_nsums, segnum,
(unsigned long long)sum_offset >> dbshift);
if (db_ssize < (sum_offset >> dbshift) - addr)
pwarn(" (+0x%llx/0x%llx)",
(unsigned long long)(((sum_offset >> dbshift) - addr) -
db_ssize),
(unsigned long long)db_ssize);
else
pwarn(" (-0x%llx/0x%llx)",
(unsigned long long)(db_ssize -
((sum_offset >> dbshift) - addr)),
(unsigned long long)db_ssize);
pwarn("\n");
dump_segsum(sump, sum_offset >> dbshift);
}
/* XXX fix it maybe */
bp->b_flags &= ~B_INUSE;
break; /* XXX could be throwing away data, but if
* this segsum is invalid, how to know where
* the next summary begins? */
}
/*
* Good partial segment
*/
bc = (*func)(&sblock, sump, (daddr_t)(sum_offset >> dbshift));
if (bc) {
sum_offset += sblock.lfs_sumsize + bc;
ninos += (sump->ss_ninos + INOPB(&sblock) - 1)
/ INOPB(&sblock);
psegnum++;
} else {
bp->b_flags &= ~B_INUSE;
break;
}
bp->b_flags &= ~B_INUSE;
}
if (flags & CKSEG_VERBOSE) {
if (ninos != su_ninos)
pwarn("SEGMENT %d has %d ninos, not %d\n",
segnum, ninos, su_ninos);
if (psegnum != su_nsums)
pwarn("SEGMENT %d has %d summaries, not %d\n",
segnum, psegnum, su_nsums);
}
return;
}
int
check_summary(struct lfs * fs, SEGSUM * sp, daddr_t pseg_addr)
{
FINFO *fp;
int bc; /* Bytes in partial segment */
int nblocks;
daddr_t seg_addr, daddr;
/* XXX ondisk32 */
int32_t *dp, *idp;
struct bufarea *bp;
int i, j, k, datac, len;
long sn;
u_long *datap;
u_int32_t ccksum;
sn = dtosn(fs, pseg_addr);
seg_addr = sntod(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 */
/* 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;
/* XXX ondisk32 */
dp = (int32_t *)sp;
dp += sblock.lfs_sumsize / sizeof(int32_t);
dp--;
idp = dp;
daddr = pseg_addr + btofsb(&sblock, sblock.lfs_sumsize);
fp = (FINFO *)(sp + 1);
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%llx: found %d, wanted %d\n",
(long long)pseg_addr, j, howmany(sp->ss_ninos, INOPB(fs)));
pwarn("*idp=%x, daddr=%llx\n", *idp, (long long)daddr);
break;
}
/* XXX ondisk32 */
while (j < howmany(sp->ss_ninos, INOPB(fs)) && *idp == daddr) {
bp = getddblk(daddr, fs->lfs_ibsize);
datap[datac++] = ((u_long *)(bp->b_un.b_buf))[0];
bp->b_flags &= ~B_INUSE;
++j;
daddr += btofsb(&sblock, fs->lfs_ibsize);
--idp;
}
if (i < sp->ss_nfinfo) {
for (k = 0; k < fp->fi_nblocks; k++) {
len = (k == fp->fi_nblocks - 1 ? fp->fi_lastlength
: fs->lfs_bsize);
bp = getddblk(daddr, len);
datap[datac++] = ((u_long *)(bp->b_un.b_buf))[0];
bp->b_flags &= ~B_INUSE;
daddr += btofsb(&sblock, len);
}
fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks);
}
}
if (datac != nblocks) {
pwarn("Partial segment at 0x%llx expected %d blocks counted %d\n",
(long long)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%llx data checksum mismatch: got 0x%x, expected 0x%x\n",
(long long)pseg_addr, sp->ss_datasum, ccksum);
/* return 0; */
}
return bc;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: pass1.c,v 1.13 2003/01/24 21:55:10 fvdl Exp $ */
/* $NetBSD: pass1.c,v 1.14 2003/03/28 08:09:54 perseant Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -35,32 +35,40 @@
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <sys/mount.h>
#include <ufs/lfs/lfs.h>
#include <sys/buf.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#define vnode uvnode
#include <ufs/lfs/lfs.h>
#undef vnode
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fsck.h"
#include "extern.h"
#include "fsutil.h"
SEGUSE *seg_table;
extern daddr_t *din_table;
SEGUSE *seg_table;
extern ufs_daddr_t *din_table;
static daddr_t badblk;
static daddr_t dupblk;
static void checkinode(ino_t, struct inodesc *);
static int i_d_cmp(const void *, const void *);
ufs_daddr_t badblk;
static ufs_daddr_t dupblk;
static int i_d_cmp(const void *, const void *);
struct ino_daddr {
ino_t ino;
daddr_t daddr;
ino_t ino;
ufs_daddr_t daddr;
};
static int
@ -68,8 +76,8 @@ i_d_cmp(const void *va, const void *vb)
{
struct ino_daddr *a, *b;
a = *((struct ino_daddr **)va);
b = *((struct ino_daddr **)vb);
a = *((struct ino_daddr **) va);
b = *((struct ino_daddr **) vb);
if (a->daddr == b->daddr) {
return (a->ino - b->ino);
@ -83,29 +91,14 @@ i_d_cmp(const void *va, const void *vb)
void
pass1()
{
ino_t inumber;
int i;
struct inodesc idesc;
struct dinode *idinode, *tinode;
struct ifile *ifp;
CLEANERINFO *cp;
struct bufarea *bp;
ino_t inumber;
int i;
struct inodesc idesc;
struct dinode *tinode;
struct ifile *ifp;
struct ubuf *bp;
struct ino_daddr **dins;
idinode = lfs_difind(&sblock, sblock.lfs_ifile, &ifblock);
/*
* We now have the ifile's inode block in core. Read out the
* number of segments.
*/
#if 1
if (pbp != 0)
pbp->b_flags &= ~B_INUSE;
pbp = getddblk(idinode->di_db[0], sblock.lfs_bsize);
cp = (CLEANERINFO *)(pbp->b_un.b_buf);
#endif
/*
* Find all allocated blocks, initialize numdirs.
*/
@ -117,13 +110,19 @@ pass1()
n_files = n_blks = 0;
if (debug)
printf("creating inode address table...\n");
printf("creating sorted inode address table...\n");
/* Sort by daddr */
dins = (struct ino_daddr **)malloc(maxino * sizeof(*dins));
dins = (struct ino_daddr **) malloc(maxino * sizeof(*dins));
for (i = 0; i < maxino; i++) {
dins[i] = malloc(sizeof(**dins));
dins[i]->ino = i;
dins[i]->daddr = lfs_ino_daddr(i);
if (i == fs->lfs_ifile)
dins[i]->daddr = fs->lfs_idaddr;
else {
LFS_IENTRY(ifp, fs, i, bp);
dins[i]->daddr = ifp->if_daddr;
brelse(bp);
}
}
qsort(dins, maxino, sizeof(*dins), i_d_cmp);
@ -135,7 +134,7 @@ pass1()
inumber = dins[i]->ino;
if (inumber == 0 || dins[i]->daddr == 0)
continue;
tinode = lfs_ginode(inumber);
tinode = ginode(inumber);
if (tinode && (tinode->di_mode & IFMT) == IFDIR)
numdirs++;
}
@ -143,50 +142,45 @@ pass1()
/* from setup.c */
inplast = 0;
listmax = numdirs + 10;
inpsort = (struct inoinfo **)calloc((unsigned) listmax,
sizeof(struct inoinfo *));
inphead = (struct inoinfo **)calloc((unsigned) numdirs,
sizeof(struct inoinfo *));
inpsort = (struct inoinfo **) calloc((unsigned) listmax,
sizeof(struct inoinfo *));
inphead = (struct inoinfo **) calloc((unsigned) numdirs,
sizeof(struct inoinfo *));
if (inpsort == NULL || inphead == NULL) {
printf("cannot alloc %lu bytes for inphead\n",
(unsigned long)numdirs * sizeof(struct inoinfo *));
(unsigned long) numdirs * sizeof(struct inoinfo *));
exit(1);
}
/* resetinodebuf(); */
if (debug)
printf("counting blocks...\n");
for (i = 0; i < maxino; i++) {
inumber = dins[i]->ino;
if (inumber == 0 || dins[i]->daddr == 0) {
statemap[inumber] = USTATE;
continue;
}
ifp = lfs_ientry(inumber, &bp);
if (ifp && ifp->if_daddr != LFS_UNUSED_DADDR) {
bp->b_flags &= ~B_INUSE;
if (dins[i]->daddr != LFS_UNUSED_DADDR) {
checkinode(inumber, &idesc);
} else {
bp->b_flags &= ~B_INUSE;
statemap[inumber] = USTATE;
}
free(dins[i]);
}
free(dins);
/* freeinodebuf(); */
}
static void
void
checkinode(ino_t inumber, struct inodesc * idesc)
{
register struct dinode *dp;
struct zlncnt *zlnp;
int ndb, j;
mode_t mode;
char *symbuf;
struct dinode *dp;
struct uvnode *vp;
struct zlncnt *zlnp;
int ndb, j;
mode_t mode;
/* dp = getnextinode(inumber); */
dp = lfs_ginode(inumber);
vp = vget(fs, inumber);
dp = VTOD(vp);
if (dp == NULL) {
/* pwarn("Could not find inode %ld\n",(long)inumber); */
@ -197,82 +191,56 @@ checkinode(ino_t inumber, struct inodesc * idesc)
/* XXX - LFS doesn't have this particular problem (?) */
if (mode == 0) {
/* XXX ondisk32 */
if (memcmp(dp->di_db, zino.di_db, NDADDR * sizeof(int32_t)) ||
memcmp(dp->di_ib, zino.di_ib, NIADDR * sizeof(int32_t)) ||
if (memcmp(dp->di_db, zino.di_db, NDADDR * sizeof(ufs_daddr_t)) ||
memcmp(dp->di_ib, zino.di_ib, NIADDR * sizeof(ufs_daddr_t)) ||
dp->di_mode || dp->di_size) {
pwarn("mode=o%o, ifmt=o%o\n", dp->di_mode, mode);
pfatal("PARTIALLY ALLOCATED INODE I=%u", inumber);
if (reply("CLEAR") == 1) {
dp = ginode(inumber);
vp = vget(fs, inumber);
dp = VTOD(vp);
clearinode(dp);
inodirty();
inodirty(VTOI(vp));
}
}
statemap[inumber] = USTATE;
return;
}
lastino = inumber;
if ( /* dp->di_size < 0 || */
dp->di_size + sblock.lfs_bsize - 1 < dp->di_size) {
if (dp->di_size < 0 || dp->di_size + fs->lfs_bsize - 1 < dp->di_size) {
if (debug)
printf("bad size %llu:",
(unsigned long long)dp->di_size);
(unsigned long long) dp->di_size);
goto unknown;
}
if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
dp = ginode(inumber);
dp->di_size = sblock.lfs_fsize;
vp = vget(fs, inumber);
dp = VTOD(vp);
dp->di_size = fs->lfs_fsize;
dp->di_mode = IFREG | 0600;
inodirty();
inodirty(VTOI(vp));
}
ndb = howmany(dp->di_size, sblock.lfs_bsize);
ndb = howmany(dp->di_size, fs->lfs_bsize);
if (ndb < 0) {
if (debug)
printf("bad size %llu ndb %d:",
(unsigned long long)dp->di_size, ndb);
(unsigned long long) dp->di_size, ndb);
goto unknown;
}
if (mode == IFBLK || mode == IFCHR)
ndb++;
if (mode == IFLNK) {
/*
* Note that the old fastlink format always had di_blocks set
* to 0. Other than that we no longer use the `spare' field
* (which is now the extended uid)for sanity checking, the
* new format is the same as the old. We simply ignore the
* conversion altogether. - mycroft, 19MAY1994
*/
if (doinglevel2 &&
dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
dp->di_blocks != 0) {
symbuf = alloca(secsize);
if (bread(fsreadfd, symbuf,
fsbtodb(&sblock, dp->di_db[0]),
(long)secsize) != 0)
errexit("cannot read symlink\n");
if (debug) {
symbuf[dp->di_size] = 0;
printf("convert symlink %d(%s)of size %lld\n",
inumber, symbuf, (long long)dp->di_size);
}
dp = ginode(inumber);
memcpy(dp->di_shortlink, symbuf, (long)dp->di_size);
dp->di_blocks = 0;
inodirty();
}
/*
* Fake ndb value so direct/indirect block checks below
* will detect any garbage after symlink string.
*/
if (dp->di_size < sblock.lfs_maxsymlinklen ||
(sblock.lfs_maxsymlinklen == 0 && dp->di_blocks == 0)) {
/* XXX ondisk32 */
ndb = howmany(dp->di_size, sizeof(int32_t));
if (dp->di_size < fs->lfs_maxsymlinklen ||
(fs->lfs_maxsymlinklen == 0 && dp->di_blocks == 0)) {
ndb = howmany(dp->di_size, sizeof(ufs_daddr_t));
if (ndb > NDADDR) {
j = ndb - NDADDR;
for (ndb = 1; j > 1; j--)
ndb *= NINDIR(&sblock);
ndb *= NINDIR(fs);
ndb += NDADDR;
}
}
@ -284,12 +252,12 @@ checkinode(ino_t inumber, struct inodesc * idesc)
goto unknown;
}
for (j = 0, ndb -= NDADDR; ndb > 0; j++)
ndb /= NINDIR(&sblock);
ndb /= NINDIR(fs);
for (; j < NIADDR; j++)
if (dp->di_ib[j] != 0) {
if (debug)
printf("bad indirect addr: %d\n",
dp->di_ib[j]);
dp->di_ib[j]);
/* goto unknown; */
}
if (ftypeok(dp) == 0)
@ -297,11 +265,11 @@ checkinode(ino_t inumber, struct inodesc * idesc)
n_files++;
lncntp[inumber] = dp->di_nlink;
if (dp->di_nlink <= 0) {
zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
zlnp = (struct zlncnt *) malloc(sizeof *zlnp);
if (zlnp == NULL) {
pfatal("LINK COUNT TABLE OVERFLOW");
if (reply("CONTINUE") == 0)
errexit("%s", "");
err(8, "%s", "");
} else {
zlnp->zlncnt = inumber;
zlnp->next = zlnhead;
@ -317,30 +285,18 @@ checkinode(ino_t inumber, struct inodesc * idesc)
} else
statemap[inumber] = FSTATE;
typemap[inumber] = IFTODT(mode);
#if 0 /* FFS */
if (doinglevel2 &&
(dp->di_ouid != (u_short) - 1 || dp->di_ogid != (u_short) - 1)) {
dp = ginode(inumber);
dp->di_uid = dp->di_ouid;
dp->di_ouid = -1;
dp->di_gid = dp->di_ogid;
dp->di_ogid = -1;
inodirty();
}
#endif
badblk = dupblk = 0;
idesc->id_number = inumber;
(void)ckinode(dp, idesc);
(void) ckinode(VTOD(vp), idesc);
if (dp->di_blocks != idesc->id_entryno) {
pwarn("INCORRECT BLOCK COUNT I=%u (%d should be %d)",
inumber, dp->di_blocks, idesc->id_entryno);
inumber, dp->di_blocks, idesc->id_entryno);
if (preen)
printf(" (CORRECTED)\n");
else if (reply("CORRECT") == 0)
return;
dp = ginode(inumber);
dp->di_blocks = idesc->id_entryno;
inodirty();
VTOI(vp)->i_ffs_blocks = idesc->id_entryno;
inodirty(VTOI(vp));
}
return;
unknown:
@ -348,36 +304,37 @@ unknown:
statemap[inumber] = FCLEAR;
if (reply("CLEAR") == 1) {
statemap[inumber] = USTATE;
dp = ginode(inumber);
vp = vget(fs, inumber);
dp = VTOD(vp);
clearinode(dp);
inodirty();
inodirty(VTOI(vp));
}
}
int
pass1check(struct inodesc * idesc)
pass1check(struct inodesc *idesc)
{
int res = KEEPON;
int anyout, ndblks;
daddr_t blkno = idesc->id_blkno;
int res = KEEPON;
int anyout, ndblks;
daddr_t blkno = idesc->id_blkno;
register struct dups *dlp;
struct dups *new;
struct dups *new;
if ((anyout = chkrange(blkno, fragstofsb(&sblock, idesc->id_numfrags))) != 0) {
if ((anyout = chkrange(blkno, fragstofsb(fs, idesc->id_numfrags))) != 0) {
blkerror(idesc->id_number, "BAD", blkno);
if (badblk++ >= MAXBAD) {
pwarn("EXCESSIVE BAD BLKS I=%u",
idesc->id_number);
idesc->id_number);
if (preen)
printf(" (SKIPPING)\n");
else if (reply("CONTINUE") == 0)
errexit("%s", "");
err(8, "%s", "");
return (STOP);
}
} else if (!testbmap(blkno)) {
seg_table[dtosn(&sblock, blkno)].su_nbytes += idesc->id_numfrags * sblock.lfs_fsize;
seg_table[dtosn(fs, blkno)].su_nbytes += idesc->id_numfrags * fs->lfs_fsize;
}
for (ndblks = fragstofsb(&sblock, idesc->id_numfrags); ndblks > 0; blkno++, ndblks--) {
for (ndblks = fragstofsb(fs, idesc->id_numfrags); ndblks > 0; blkno++, ndblks--) {
if (anyout && chkrange(blkno, 1)) {
res = SKIP;
} else if (!testbmap(blkno)) {
@ -391,22 +348,22 @@ pass1check(struct inodesc * idesc)
blkerror(idesc->id_number, "DUP", blkno);
#ifdef VERBOSE_BLOCKMAP
pwarn("(lbn %d: Holder is %d)\n", idesc->id_lblkno,
testbmap(blkno));
testbmap(blkno));
#endif
if (dupblk++ >= MAXDUP) {
pwarn("EXCESSIVE DUP BLKS I=%u",
idesc->id_number);
idesc->id_number);
if (preen)
printf(" (SKIPPING)\n");
else if (reply("CONTINUE") == 0)
errexit("%s", "");
err(8, "%s", "");
return (STOP);
}
new = (struct dups *)malloc(sizeof(struct dups));
new = (struct dups *) malloc(sizeof(struct dups));
if (new == NULL) {
pfatal("DUP TABLE OVERFLOW.");
if (reply("CONTINUE") == 0)
errexit("%s", "");
err(8, "%s", "");
return (STOP);
}
new->dup = blkno;

View File

@ -1,4 +1,4 @@
/* $NetBSD: pass2.c,v 1.6 2001/09/25 00:03:25 wiz Exp $ */
/* $NetBSD: pass2.c,v 1.7 2003/03/28 08:09:54 perseant Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -33,44 +33,53 @@
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#include <ufs/lfs/lfs.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fsck.h"
#include "fsutil.h"
#include "extern.h"
#define MINDIRSIZE (sizeof (struct dirtemplate))
static int pass2check(struct inodesc *);
static int blksort(const void *, const void *);
static int pass2check(struct inodesc *);
static int blksort(const void *, const void *);
void
pass2()
{
register struct dinode *dp;
register struct inoinfo **inpp, *inp;
struct dinode *dp;
struct uvnode *vp;
struct inoinfo **inpp, *inp;
struct inoinfo **inpend;
struct inodesc curino;
struct dinode dino;
char pathbuf[MAXPATHLEN + 1];
struct inodesc curino;
struct dinode dino;
char pathbuf[MAXPATHLEN + 1];
switch (statemap[ROOTINO]) {
case USTATE:
pfatal("ROOT INODE UNALLOCATED");
if (reply("ALLOCATE") == 0)
errexit("%s", "");
err(8, "%s", "");
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
errexit("CANNOT ALLOCATE ROOT INODE\n");
err(8, "CANNOT ALLOCATE ROOT INODE\n");
break;
case DCLEAR:
@ -78,11 +87,11 @@ pass2()
if (reply("REALLOCATE")) {
freeino(ROOTINO);
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
errexit("CANNOT ALLOCATE ROOT INODE\n");
err(8, "CANNOT ALLOCATE ROOT INODE\n");
break;
}
if (reply("CONTINUE") == 0)
errexit("%s", "");
err(8, "%s", "");
break;
case FSTATE:
@ -91,31 +100,30 @@ pass2()
if (reply("REALLOCATE")) {
freeino(ROOTINO);
if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
errexit("CANNOT ALLOCATE ROOT INODE\n");
err(8, "CANNOT ALLOCATE ROOT INODE\n");
break;
}
if (reply("FIX") == 0)
errexit("%s", "");
dp = ginode(ROOTINO);
err(8, "%s", "");
vp = vget(fs, ROOTINO);
dp = VTOD(vp);
dp->di_mode &= ~IFMT;
dp->di_mode |= IFDIR;
inodirty();
inodirty(VTOI(vp));
break;
case DSTATE:
break;
default:
errexit("BAD STATE %d FOR ROOT INODE\n", statemap[ROOTINO]);
}
if (newinofmt) {
statemap[WINO] = FSTATE;
typemap[WINO] = DT_WHT;
err(8, "BAD STATE %d FOR ROOT INODE\n", statemap[ROOTINO]);
}
statemap[WINO] = FSTATE;
typemap[WINO] = DT_WHT;
/*
* Sort the directory list into disk block order.
*/
qsort((char *)inpsort, (size_t) inplast, sizeof *inpsort, blksort);
qsort((char *) inpsort, (size_t) inplast, sizeof *inpsort, blksort);
/*
* Check the integrity of each directory.
*/
@ -131,35 +139,32 @@ pass2()
direrror(inp->i_number, "DIRECTORY TOO SHORT");
inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
if (reply("FIX") == 1) {
dp = ginode(inp->i_number);
vp = vget(fs, inp->i_number);
dp = VTOD(vp);
dp->di_size = inp->i_isize;
inodirty();
inodirty(VTOI(vp));
}
} else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
getpathname(pathbuf, inp->i_number, inp->i_number);
pwarn("DIRECTORY %s: LENGTH %lu NOT MULTIPLE OF %d",
pathbuf, (unsigned long)inp->i_isize, DIRBLKSIZ);
pathbuf, (unsigned long) inp->i_isize, DIRBLKSIZ);
if (preen)
printf(" (ADJUSTED)\n");
inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
if (preen || reply("ADJUST") == 1) {
dp = ginode(inp->i_number);
vp = vget(fs, inp->i_number);
dp = VTOD(vp);
dp->di_size = inp->i_isize;
inodirty();
inodirty(VTOI(vp));
}
}
memset(&dino, 0, sizeof(struct dinode));
dino.di_mode = IFDIR;
dino.di_size = inp->i_isize;
memcpy(&dino.di_db[0], &inp->i_blks[0], (size_t)inp->i_numblks);
memcpy(&dino.di_db[0], &inp->i_blks[0], (size_t) inp->i_numblks);
curino.id_number = inp->i_number;
curino.id_parent = inp->i_parent;
#if 0
printf("checking %ld against %ld\n",
(long)dino.di_inumber,
(long)inp->i_number);
#endif
(void)ckinode(&dino, &curino);
(void) ckinode(&dino, &curino);
}
/*
* Now that the parents of all directories have been found,
@ -170,25 +175,25 @@ pass2()
if (inp->i_parent == 0 || inp->i_isize == 0)
continue;
if (inp->i_dotdot == inp->i_parent ||
inp->i_dotdot == (ino_t)-1)
inp->i_dotdot == (ino_t) - 1)
continue;
if (inp->i_dotdot == 0) {
inp->i_dotdot = inp->i_parent;
fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
if (reply("FIX") == 0)
continue;
(void)makeentry(inp->i_number, inp->i_parent, "..");
(void) makeentry(inp->i_number, inp->i_parent, "..");
lncntp[inp->i_parent]--;
continue;
}
fileerror(inp->i_parent, inp->i_number,
"BAD INODE NUMBER FOR '..'");
"BAD INODE NUMBER FOR '..'");
if (reply("FIX") == 0)
continue;
lncntp[inp->i_dotdot]++;
lncntp[inp->i_parent]--;
inp->i_dotdot = inp->i_parent;
(void)changeino(inp->i_number, "..", inp->i_parent);
(void) changeino(inp->i_number, "..", inp->i_parent);
}
/*
* Mark all the directories that can be found from the root.
@ -201,20 +206,13 @@ pass2check(struct inodesc * idesc)
{
register struct direct *dirp = idesc->id_dirp;
register struct inoinfo *inp;
int n, entrysize, ret = 0;
struct dinode *dp;
char *errmsg;
struct direct proto;
char namebuf[MAXPATHLEN + 1];
char pathbuf[MAXPATHLEN + 1];
int n, entrysize, ret = 0;
struct dinode *dp;
char *errmsg;
struct direct proto;
char namebuf[MAXPATHLEN + 1];
char pathbuf[MAXPATHLEN + 1];
/*
* If converting, set directory entry type.
*/
if (doinglevel2 && dirp->d_ino > 0 && dirp->d_ino < maxino) {
dirp->d_type = typemap[dirp->d_ino];
ret |= ALTERED;
}
/*
* check for "."
*/
@ -227,7 +225,7 @@ pass2check(struct inodesc * idesc)
if (reply("FIX") == 1)
ret |= ALTERED;
}
if (newinofmt && dirp->d_type != DT_DIR) {
if (dirp->d_type != DT_DIR) {
direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
dirp->d_type = DT_DIR;
if (reply("FIX") == 1)
@ -237,40 +235,28 @@ pass2check(struct inodesc * idesc)
}
direrror(idesc->id_number, "MISSING '.'");
proto.d_ino = idesc->id_number;
if (newinofmt)
proto.d_type = DT_DIR;
else
proto.d_type = 0;
proto.d_type = DT_DIR;
proto.d_namlen = 1;
(void)strcpy(proto.d_name, ".");
# if BYTE_ORDER == LITTLE_ENDIAN
if (!newinofmt) {
u_char tmp;
tmp = proto.d_type;
proto.d_type = proto.d_namlen;
proto.d_namlen = tmp;
}
# endif
(void) strcpy(proto.d_name, ".");
entrysize = DIRSIZ(0, &proto, 0);
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
dirp->d_name);
dirp->d_name);
} else if (dirp->d_reclen < entrysize) {
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
} else if (dirp->d_reclen < 2 * entrysize) {
proto.d_reclen = dirp->d_reclen;
memcpy(dirp, &proto, (size_t)entrysize);
memcpy(dirp, &proto, (size_t) entrysize);
if (reply("FIX") == 1)
ret |= ALTERED;
} else {
n = dirp->d_reclen - entrysize;
proto.d_reclen = entrysize;
memcpy(dirp, &proto, (size_t)entrysize);
memcpy(dirp, &proto, (size_t) entrysize);
idesc->id_entryno++;
lncntp[dirp->d_ino]--;
dirp = (struct direct *)((char *)(dirp) + entrysize);
memset(dirp, 0, (size_t)n);
dirp = (struct direct *) ((char *) (dirp) + entrysize);
memset(dirp, 0, (size_t) n);
dirp->d_reclen = n;
if (reply("FIX") == 1)
ret |= ALTERED;
@ -280,21 +266,9 @@ chk1:
goto chk2;
inp = getinoinfo(idesc->id_number);
proto.d_ino = inp->i_parent;
if (newinofmt)
proto.d_type = DT_DIR;
else
proto.d_type = 0;
proto.d_type = DT_DIR;
proto.d_namlen = 2;
(void)strcpy(proto.d_name, "..");
# if BYTE_ORDER == LITTLE_ENDIAN
if (!newinofmt) {
u_char tmp;
tmp = proto.d_type;
proto.d_type = proto.d_namlen;
proto.d_namlen = tmp;
}
# endif
(void) strcpy(proto.d_name, "..");
entrysize = DIRSIZ(0, &proto, 0);
if (idesc->id_entryno == 0) {
n = DIRSIZ(0, dirp, 0);
@ -304,13 +278,13 @@ chk1:
dirp->d_reclen = n;
idesc->id_entryno++;
lncntp[dirp->d_ino]--;
dirp = (struct direct *)((char *)(dirp) + n);
memset(dirp, 0, (size_t)proto.d_reclen);
dirp = (struct direct *) ((char *) (dirp) + n);
memset(dirp, 0, (size_t) proto.d_reclen);
dirp->d_reclen = proto.d_reclen;
}
if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
inp->i_dotdot = dirp->d_ino;
if (newinofmt && dirp->d_type != DT_DIR) {
if (dirp->d_type != DT_DIR) {
direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
dirp->d_type = DT_DIR;
if (reply("FIX") == 1)
@ -321,12 +295,12 @@ chk1:
if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
dirp->d_name);
inp->i_dotdot = (ino_t)-1;
dirp->d_name);
inp->i_dotdot = (ino_t) - 1;
} else if (dirp->d_reclen < entrysize) {
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
inp->i_dotdot = (ino_t)-1;
inp->i_dotdot = (ino_t) - 1;
} else if (inp->i_parent != 0) {
/*
* We know the parent, so fix now.
@ -334,7 +308,7 @@ chk1:
inp->i_dotdot = inp->i_parent;
fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
proto.d_reclen = dirp->d_reclen;
memcpy(dirp, &proto, (size_t)entrysize);
memcpy(dirp, &proto, (size_t) entrysize);
if (reply("FIX") == 1)
ret |= ALTERED;
}
@ -369,17 +343,16 @@ chk2:
fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
n = reply("REMOVE");
} else if (dirp->d_ino == LFS_IFILE_INUM &&
idesc->id_number == ROOTINO) {
idesc->id_number == ROOTINO) {
if (dirp->d_type != DT_REG) {
fileerror(idesc->id_number, dirp->d_ino,
"BAD TYPE FOR IFILE");
"BAD TYPE FOR IFILE");
dirp->d_type = DT_REG;
if (reply("FIX") == 1)
ret |= ALTERED;
}
} else if (newinofmt &&
((dirp->d_ino == WINO && (dirp->d_type != DT_WHT)) ||
(dirp->d_ino != WINO && dirp->d_type == DT_WHT))) {
} else if (((dirp->d_ino == WINO && (dirp->d_type != DT_WHT)) ||
(dirp->d_ino != WINO && dirp->d_type == DT_WHT))) {
fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
dirp->d_ino = WINO;
dirp->d_type = DT_WHT;
@ -412,7 +385,7 @@ again:
break;
dp = ginode(dirp->d_ino);
statemap[dirp->d_ino] =
(dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
(dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
lncntp[dirp->d_ino] = dp->di_nlink;
goto again;
@ -421,11 +394,11 @@ again:
inp = getinoinfo(dirp->d_ino);
if (inp->i_parent != 0 && idesc->id_entryno > 2) {
getpathname(pathbuf, idesc->id_number,
idesc->id_number);
idesc->id_number);
getpathname(namebuf, dirp->d_ino, dirp->d_ino);
pwarn("%s %s %s\n", pathbuf,
"IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
namebuf);
"IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
namebuf);
if (preen)
printf(" (IGNORED)\n");
else if ((n = reply("REMOVE")) == 1)
@ -436,9 +409,9 @@ again:
/* fall through */
case FSTATE:
if (newinofmt && dirp->d_type != typemap[dirp->d_ino]) {
if (dirp->d_type != typemap[dirp->d_ino]) {
fileerror(idesc->id_number, dirp->d_ino,
"BAD TYPE VALUE");
"BAD TYPE VALUE");
dirp->d_type = typemap[dirp->d_ino];
if (reply("FIX") == 1)
ret |= ALTERED;
@ -447,8 +420,8 @@ again:
break;
default:
/* errexit */ pwarn("BAD STATE %d FOR INODE I=%d",
statemap[dirp->d_ino], dirp->d_ino);
err(8, "BAD STATE %d FOR INODE I=%d",
statemap[dirp->d_ino], dirp->d_ino);
}
}
if (n == 0)
@ -456,13 +429,12 @@ again:
dirp->d_ino = 0;
return (ret | KEEPON | ALTERED);
}
/*
* Routine to sort disk blocks.
*/
static int
blksort(const void *inpp1, const void *inpp2)
{
return ((*(struct inoinfo **)inpp1)->i_blks[0] -
(*(struct inoinfo **)inpp2)->i_blks[0]);
return ((*(struct inoinfo **) inpp1)->i_blks[0] -
(*(struct inoinfo **) inpp2)->i_blks[0]);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: pass3.c,v 1.3 2000/05/23 01:48:54 perseant Exp $ */
/* $NetBSD: pass3.c,v 1.4 2003/03/28 08:09:54 perseant Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -45,13 +45,13 @@ void
pass3()
{
register struct inoinfo **inpp, *inp;
ino_t orphan;
int loopcnt;
ino_t orphan;
int loopcnt;
for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) {
inp = *inpp;
if (inp->i_number == ROOTINO ||
!(inp->i_parent == 0 || statemap[inp->i_number] == DSTATE))
!(inp->i_parent == 0 || statemap[inp->i_number] == DSTATE))
continue;
if (statemap[inp->i_number] == DCLEAR)
continue;
@ -63,7 +63,7 @@ pass3()
break;
inp = getinoinfo(inp->i_parent);
}
(void)linkup(orphan, inp->i_dotdot);
(void) linkup(orphan, inp->i_dotdot);
inp->i_parent = inp->i_dotdot = lfdir;
lncntp[lfdir]--;
statemap[orphan] = DFOUND;

View File

@ -1,4 +1,4 @@
/* $NetBSD: pass4.c,v 1.5 2001/09/25 00:03:25 wiz Exp $ */
/* $NetBSD: pass4.c,v 1.6 2003/03/28 08:09:54 perseant Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -35,24 +35,36 @@
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <sys/mount.h>
#include <ufs/ufs/inode.h>
#define vnode uvnode
#define buf ubuf
#define panic call_panic
#include <ufs/lfs/lfs.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fsutil.h"
#include "fsck.h"
#include "extern.h"
extern SEGUSE *seg_table;
void
pass4()
{
register ino_t inumber;
register ino_t inumber;
register struct zlncnt *zlnp;
struct dinode *dp;
struct inodesc idesc;
int n;
struct dinode *dp;
struct inodesc idesc;
int n;
memset(&idesc, 0, sizeof(struct inodesc));
idesc.id_type = ADDR;
@ -65,14 +77,14 @@ pass4()
case DFOUND:
n = lncntp[inumber];
if (n)
adjust(&idesc, (short)n);
adjust(&idesc, (short) n);
else {
for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
if (zlnp->zlncnt == inumber) {
zlnp->zlncnt = zlnhead->zlncnt;
zlnp = zlnhead;
zlnhead = zlnhead->next;
free((char *)zlnp);
free((char *) zlnp);
clri(&idesc, "UNREF", 1);
break;
}
@ -98,8 +110,8 @@ pass4()
break;
default:
errexit("BAD STATE %d FOR INODE I=%d\n",
statemap[inumber], inumber);
err(8, "BAD STATE %d FOR INODE I=%d\n",
statemap[inumber], inumber);
}
}
}
@ -108,10 +120,13 @@ int
pass4check(struct inodesc * idesc)
{
register struct dups *dlp;
int ndblks, res = KEEPON;
daddr_t blkno = idesc->id_blkno;
int ndblks, res = KEEPON;
daddr_t blkno = idesc->id_blkno;
SEGUSE *sup;
struct ubuf *bp;
int sn;
for (ndblks = fragstodb(&sblock, idesc->id_numfrags); ndblks > 0; blkno++, ndblks--) {
for (ndblks = fragstofsb(fs, idesc->id_numfrags); ndblks > 0; blkno++, ndblks--) {
if (chkrange(blkno, 1)) {
res = SKIP;
} else if (testbmap(blkno)) {
@ -121,11 +136,17 @@ pass4check(struct inodesc * idesc)
dlp->dup = duplist->dup;
dlp = duplist;
duplist = duplist->next;
free((char *)dlp);
free((char *) dlp);
break;
}
if (dlp == 0) {
sn = dtosn(fs, blkno);
clrbmap(blkno);
LFS_SEGENTRY(sup, fs, sn, bp);
sup->su_nbytes -= fsbtob(fs, 1);
VOP_BWRITE(bp);
seg_table[sn].su_nbytes -= fsbtob(fs, 1);
++fs->lfs_bfree;
n_blks--;
}
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: pass5.c,v 1.11 2003/02/23 04:32:05 perseant Exp $ */
/* $NetBSD: pass5.c,v 1.12 2003/03/28 08:09:54 perseant Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* Copyright (c) 2000, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -36,33 +36,45 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#define vnode uvnode
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#undef vnode
#include <string.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fsck.h"
#include "extern.h"
#include "fsutil.h"
extern SEGUSE *seg_table;
extern SEGUSE *seg_table;
extern off_t locked_queue_bytes;
void
pass5()
{
SEGUSE *su;
struct bufarea *bp;
int i;
unsigned long bb; /* total number of used blocks (lower bound) */
unsigned long ubb; /* upper bound number of used blocks */
unsigned long avail; /* blocks available for writing */
unsigned long dmeta; /* blocks in segsums and inodes */
int nclean; /* clean segments */
size_t labelskew;
SEGUSE *su;
struct ubuf *bp, *cbp;
int i;
unsigned long bb; /* total number of used blocks (lower bound) */
unsigned long ubb; /* upper bound number of used blocks */
unsigned long avail; /* blocks available for writing */
unsigned long dmeta; /* blocks in segsums and inodes */
int nclean; /* clean segments */
size_t labelskew;
int diddirty;
/*
* Check segment holdings against actual holdings. Check for
@ -72,97 +84,108 @@ pass5()
avail = 0;
bb = ubb = 0;
dmeta = 0;
for (i = 0; i < sblock.lfs_nseg; i++) {
su = lfs_gseguse(i, &bp);
for (i = 0; i < fs->lfs_nseg; i++) {
diddirty = 0;
LFS_SEGENTRY(su, fs, 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")) {
seg_table[i].su_nbytes, i);
if (preen || reply("dirty segment")) {
su->su_flags |= SEGUSE_DIRTY;
dirty(bp);
++diddirty;
}
}
if ((su->su_flags & SEGUSE_DIRTY) &&
su->su_nbytes != seg_table[i].su_nbytes) {
pwarn("segment %d claims %d bytes but has %d",
i, su->su_nbytes, seg_table[i].su_nbytes);
if (su->su_nbytes > seg_table[i].su_nbytes)
i, su->su_nbytes, seg_table[i].su_nbytes);
if ((int32_t)su->su_nbytes >
(int32_t)seg_table[i].su_nbytes)
pwarn(" (high by %d)\n", su->su_nbytes -
seg_table[i].su_nbytes);
seg_table[i].su_nbytes);
else
pwarn(" (low by %d)\n", - su->su_nbytes +
seg_table[i].su_nbytes);
pwarn(" (low by %d)\n", -su->su_nbytes +
seg_table[i].su_nbytes);
if (preen || reply("fix")) {
su->su_nbytes = seg_table[i].su_nbytes;
dirty(bp);
++diddirty;
}
}
if (su->su_flags & SEGUSE_DIRTY) {
bb += btofsb(&sblock, su->su_nbytes +
su->su_nsums * sblock.lfs_sumsize);
ubb += btofsb(&sblock, su->su_nbytes +
su->su_nsums * sblock.lfs_sumsize +
su->su_ninos * sblock.lfs_ibsize);
dmeta += btofsb(&sblock,
sblock.lfs_sumsize * su->su_nsums);
dmeta += btofsb(&sblock,
sblock.lfs_ibsize * su->su_ninos);
bb += btofsb(fs, su->su_nbytes +
su->su_nsums * fs->lfs_sumsize);
ubb += btofsb(fs, su->su_nbytes +
su->su_nsums * fs->lfs_sumsize +
su->su_ninos * fs->lfs_ibsize);
dmeta += btofsb(fs,
fs->lfs_sumsize * su->su_nsums);
dmeta += btofsb(fs,
fs->lfs_ibsize * su->su_ninos);
} else {
nclean++;
avail += segtod(&sblock, 1);
avail += segtod(fs, 1);
if (su->su_flags & SEGUSE_SUPERBLOCK)
avail -= btofsb(&sblock, LFS_SBPAD);
if (i == 0 && sblock.lfs_version > 1 &&
sblock.lfs_start < btofsb(&sblock, LFS_LABELPAD))
avail -= btofsb(&sblock, LFS_LABELPAD) -
sblock.lfs_start;
avail -= btofsb(fs, LFS_SBPAD);
if (i == 0 && fs->lfs_version > 1 &&
fs->lfs_start < btofsb(fs, LFS_LABELPAD))
avail -= btofsb(fs, LFS_LABELPAD) -
fs->lfs_start;
}
bp->b_flags &= ~B_INUSE;
if (diddirty)
VOP_BWRITE(bp);
else
brelse(bp);
}
/* Also may be available bytes in current seg */
i = dtosn(&sblock, sblock.lfs_offset);
avail += sntod(&sblock, i + 1) - sblock.lfs_offset;
/* But do not count minfreesegs */
avail -= segtod(&sblock, (sblock.lfs_minfreeseg -
(sblock.lfs_minfreeseg / 2)));
if (dmeta != sblock.lfs_dmeta) {
pwarn("dmeta given as %d, should be %ld\n", sblock.lfs_dmeta,
dmeta);
if (preen || reply("fix")) {
sblock.lfs_dmeta = dmeta;
sbdirty();
}
}
if (avail != sblock.lfs_avail) {
pwarn("avail given as %d, should be %ld\n", sblock.lfs_avail,
avail);
/* Also may be available bytes in current seg */
i = dtosn(fs, fs->lfs_offset);
avail += sntod(fs, i + 1) - fs->lfs_offset;
/* But do not count minfreesegs */
avail -= segtod(fs, (fs->lfs_minfreeseg -
(fs->lfs_minfreeseg / 2)));
/* Note we may have bytes to write yet */
avail -= btofsb(fs, locked_queue_bytes);
if (dmeta != fs->lfs_dmeta) {
pwarn("dmeta given as %d, should be %ld\n", fs->lfs_dmeta,
dmeta);
if (preen || reply("fix")) {
sblock.lfs_avail = avail;
fs->lfs_dmeta = dmeta;
sbdirty();
}
}
if (nclean != sblock.lfs_nclean) {
pwarn("nclean given as %d, should be %d\n", sblock.lfs_nclean,
nclean);
if (avail != fs->lfs_avail &&
!(fsdirty && (cbp->b_flags & B_DELWRI) && avail +
btofsb(fs, fs->lfs_bsize) != fs->lfs_avail)) {
pwarn("avail given as %d, should be %ld\n", fs->lfs_avail,
avail);
if (preen || reply("fix")) {
sblock.lfs_nclean = nclean;
fs->lfs_avail = avail;
sbdirty();
}
}
if (nclean != fs->lfs_nclean) {
pwarn("nclean given as %d, should be %d\n", fs->lfs_nclean,
nclean);
if (preen || reply("fix")) {
fs->lfs_nclean = nclean;
sbdirty();
}
}
labelskew = 0;
if (sblock.lfs_version > 1 &&
sblock.lfs_start < btofsb(&sblock, LFS_LABELPAD))
labelskew = btofsb(&sblock, LFS_LABELPAD);
if (sblock.lfs_bfree > sblock.lfs_dsize - bb - labelskew ||
sblock.lfs_bfree < sblock.lfs_dsize - ubb - labelskew) {
if (fs->lfs_version > 1 &&
fs->lfs_start < btofsb(fs, LFS_LABELPAD))
labelskew = btofsb(fs, LFS_LABELPAD);
if (fs->lfs_bfree > fs->lfs_dsize - bb - labelskew ||
fs->lfs_bfree < fs->lfs_dsize - ubb - labelskew) {
pwarn("bfree given as %d, should be between %ld and %ld\n",
sblock.lfs_bfree, sblock.lfs_dsize - ubb - labelskew,
sblock.lfs_dsize - bb - labelskew);
fs->lfs_bfree, fs->lfs_dsize - ubb - labelskew,
fs->lfs_dsize - bb - labelskew);
if (preen || reply("fix")) {
sblock.lfs_bfree = sblock.lfs_dsize - labelskew -
(ubb + bb) / 2;
fs->lfs_bfree = fs->lfs_dsize - labelskew -
(ubb + bb) / 2;
sbdirty();
}
}

724
sbin/fsck_lfs/pass6.c Normal file
View File

@ -0,0 +1,724 @@
/* $NetBSD: pass6.c,v 1.1 2003/03/28 08:09:54 perseant Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/dir.h>
#define vnode uvnode
#include <ufs/lfs/lfs.h>
#undef vnode
#include <assert.h>
#include <err.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "segwrite.h"
#include "fsck.h"
#include "extern.h"
#include "fsutil.h"
extern u_int32_t cksum(void *, size_t);
extern u_int32_t lfs_sb_cksum(struct dlfs *);
extern ufs_daddr_t badblk;
extern SEGUSE *seg_table;
/*
* Our own copy of lfs_update_single so we can account in seg_table
* as well as the Ifile; and so we can add the blocks to their new
* segment.
*
* Change the given block's address to ndaddr, finding its previous
* location using ufs_bmaparray().
*
* Account for this change in the segment table.
*/
static void
rfw_update_single(struct uvnode *vp, daddr_t lbn, ufs_daddr_t ndaddr, int size)
{
SEGUSE *sup;
struct ubuf *bp;
struct indir a[NIADDR + 2], *ap;
struct inode *ip;
daddr_t daddr, ooff;
int num, error;
int i, bb, osize, obb;
u_int32_t oldsn, sn;
ip = VTOI(vp);
error = ufs_bmaparray(fs, vp, lbn, &daddr, a, &num);
if (error)
errx(1, "lfs_updatemeta: ufs_bmaparray returned %d"
" looking up lbn %" PRId64 "\n", error, lbn);
if (daddr > 0)
daddr = dbtofsb(fs, daddr);
bb = fragstofsb(fs, numfrags(fs, size));
switch (num) {
case 0:
ooff = ip->i_ffs_db[lbn];
if (ooff <= 0)
ip->i_ffs_blocks += bb;
else {
/* possible fragment truncation or extension */
obb = btofsb(fs, ip->i_lfs_fragsize[lbn]);
ip->i_ffs_blocks += (bb - obb);
}
ip->i_ffs_db[lbn] = ndaddr;
break;
case 1:
ooff = ip->i_ffs_ib[a[0].in_off];
if (ooff <= 0)
ip->i_ffs_blocks += bb;
ip->i_ffs_ib[a[0].in_off] = ndaddr;
break;
default:
ap = &a[num - 1];
if (bread(vp, ap->in_lbn, fs->lfs_bsize, NULL, &bp))
errx(1, "lfs_updatemeta: bread bno %" PRId64,
ap->in_lbn);
ooff = ((ufs_daddr_t *) bp->b_data)[ap->in_off];
if (ooff <= 0)
ip->i_ffs_blocks += bb;
((ufs_daddr_t *) bp->b_data)[ap->in_off] = ndaddr;
(void) VOP_BWRITE(bp);
}
/*
* Update segment usage information, based on old size
* and location.
*/
if (daddr > 0) {
oldsn = dtosn(fs, daddr);
if (lbn >= 0 && lbn < NDADDR)
osize = ip->i_lfs_fragsize[lbn];
else
osize = fs->lfs_bsize;
LFS_SEGENTRY(sup, fs, oldsn, bp);
seg_table[oldsn].su_nbytes -= osize;
sup->su_nbytes -= osize;
if (!(bp->b_flags & B_GATHERED))
fs->lfs_flags |= LFS_IFDIRTY;
LFS_WRITESEGENTRY(sup, fs, oldsn, bp);
for (i = 0; i < btofsb(fs, osize); i++)
clrbmap(daddr + i);
}
/* Add block to its new segment */
sn = dtosn(fs, ndaddr);
LFS_SEGENTRY(sup, fs, sn, bp);
seg_table[sn].su_nbytes += size;
sup->su_nbytes += size;
if (!(bp->b_flags & B_GATHERED))
fs->lfs_flags |= LFS_IFDIRTY;
LFS_WRITESEGENTRY(sup, fs, sn, bp);
for (i = 0; i < btofsb(fs, size); i++)
setbmap(daddr + i);
/* Check bfree accounting as well */
if (daddr < 0) {
fs->lfs_bfree -= btofsb(fs, size);
} else if (size != osize) {
fs->lfs_bfree -= (bb - obb);
}
/*
* Now that this block has a new address, and its old
* segment no longer owns it, we can forget about its
* old size.
*/
if (lbn >= 0 && lbn < NDADDR)
ip->i_lfs_fragsize[lbn] = size;
}
/*
* Remove the vnode from the cache, including any blocks it
* may hold. Account the blocks. Finally account the removal
* of the inode from its segment.
*/
static void
remove_ino(struct uvnode *vp, ino_t ino)
{
IFILE *ifp;
SEGUSE *sup;
struct ubuf *bp, *sbp;
struct inodesc idesc;
ufs_daddr_t daddr;
int obfree;
obfree = fs->lfs_bfree;
LFS_IENTRY(ifp, fs, ino, bp);
daddr = ifp->if_daddr;
brelse(bp);
if (vp == NULL && daddr > 0) {
vp = lfs_raw_vget(fs, ino, fs->lfs_ivnode->v_fd, daddr);
}
if (daddr > 0) {
LFS_SEGENTRY(sup, fs, dtosn(fs, ifp->if_daddr), sbp);
sup->su_nbytes -= DINODE_SIZE;
VOP_BWRITE(sbp);
seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes -= DINODE_SIZE;
}
/* Do on-disk accounting */
if (vp) {
idesc.id_number = ino;
idesc.id_func = pass4check; /* Delete dinode and blocks */
idesc.id_type = ADDR;
idesc.id_lblkno = 0;
clri(&idesc, "unknown", 2); /* XXX magic number 2 */
/* Get rid of this vnode for good */
vnode_destroy(vp);
}
}
/*
* Use FIP records to update blocks, if the generation number matches.
*/
static void
pass6harvest(ufs_daddr_t daddr, FINFO *fip)
{
struct uvnode *vp;
int i;
size_t size;
vp = vget(fs, fip->fi_ino);
if (vp && vp != fs->lfs_ivnode &&
VTOI(vp)->i_ffs_gen == fip->fi_version) {
for (i = 0; i < fip->fi_nblocks; i++) {
size = (i == fip->fi_nblocks - 1 ?
fip->fi_lastlength : fs->lfs_bsize);
rfw_update_single(vp, fip->fi_blocks[i], daddr, size);
daddr += btofsb(fs, size);
}
}
}
/*
* Check validity of blocks on roll-forward inodes.
*/
int
pass6check(struct inodesc * idesc)
{
int i, sn, anyout, anynew;
/* Check that the blocks do not lie within clean segments. */
anyout = anynew = 0;
for (i = 0; i < fragstofsb(fs, idesc->id_numfrags); i++) {
sn = dtosn(fs, idesc->id_blkno + i);
if (sn < 0 || sn >= fs->lfs_nseg ||
(seg_table[sn].su_flags & SEGUSE_DIRTY) == 0) {
anyout = 1;
break;
}
if (seg_table[sn].su_flags & SEGUSE_ACTIVE) {
if (sn != dtosn(fs, fs->lfs_offset) ||
idesc->id_blkno > fs->lfs_offset) {
++anynew;
}
}
if (!anynew) {
/* Clear so pass1check won't be surprised */
clrbmap(idesc->id_blkno + i);
seg_table[sn].su_nbytes -= fsbtob(fs, 1);
}
}
if (anyout) {
blkerror(idesc->id_number, "BAD", idesc->id_blkno);
if (badblk++ >= MAXBAD) {
pwarn("EXCESSIVE BAD BLKS I=%u",
idesc->id_number);
if (preen)
pwarn(" (SKIPPING)\n");
else if (reply("CONTINUE") == 0)
err(8, "%s", "");
return (STOP);
}
}
return pass1check(idesc);
}
/*
* Add a new block to the Ifile, to accommodate future file creations.
*/
static int
extend_ifile(void)
{
struct uvnode *vp;
struct inode *ip;
IFILE *ifp;
IFILE_V1 *ifp_v1;
struct ubuf *bp, *cbp;
daddr_t i, blkno, max;
ino_t oldlast;
CLEANERINFO *cip;
vp = fs->lfs_ivnode;
ip = VTOI(vp);
blkno = lblkno(fs, ip->i_ffs_size);
bp = getblk(vp, blkno, fs->lfs_bsize); /* XXX VOP_BALLOC() */
ip->i_ffs_size += fs->lfs_bsize;
i = (blkno - fs->lfs_segtabsz - fs->lfs_cleansz) *
fs->lfs_ifpb;
LFS_GET_HEADFREE(fs, cip, cbp, &oldlast);
LFS_PUT_HEADFREE(fs, cip, cbp, i);
max = i + fs->lfs_ifpb;
maxino = max;
fs->lfs_bfree -= btofsb(fs, fs->lfs_bsize);
if (fs->lfs_version == 1) {
for (ifp_v1 = (IFILE_V1 *)bp->b_data; i < max; ++ifp_v1) {
ifp_v1->if_version = 1;
ifp_v1->if_daddr = LFS_UNUSED_DADDR;
ifp_v1->if_nextfree = ++i;
}
ifp_v1--;
ifp_v1->if_nextfree = oldlast;
} else {
for (ifp = (IFILE *)bp->b_data; i < max; ++ifp) {
ifp->if_version = 1;
ifp->if_daddr = LFS_UNUSED_DADDR;
ifp->if_nextfree = ++i;
}
ifp--;
ifp->if_nextfree = oldlast;
}
LFS_PUT_TAILFREE(fs, cip, cbp, max - 1);
LFS_BWRITE_LOG(bp);
return 0;
}
/*
* Give a previously allocated inode a new address; do segment
* accounting if necessary.
*
* Caller has ensured that this inode is not on the free list, so no
* free list accounting is done.
*/
static void
readdress_inode(ino_t thisino, ufs_daddr_t daddr)
{
IFILE *ifp;
SEGUSE *sup;
struct ubuf *bp;
int sn;
ufs_daddr_t odaddr;
LFS_IENTRY(ifp, fs, thisino, bp);
odaddr = ifp->if_daddr;
ifp->if_daddr = daddr;
VOP_BWRITE(bp);
sn = dtosn(fs, odaddr);
LFS_SEGENTRY(sup, fs, sn, bp);
sup->su_nbytes -= DINODE_SIZE;
VOP_BWRITE(bp);
seg_table[sn].su_nbytes -= DINODE_SIZE;
sn = dtosn(fs, daddr);
LFS_SEGENTRY(sup, fs, sn, bp);
sup->su_nbytes += DINODE_SIZE;
VOP_BWRITE(bp);
seg_table[sn].su_nbytes += DINODE_SIZE;
}
/*
* Allocate the given inode from the free list.
*/
static void
alloc_inode(ino_t thisino, ufs_daddr_t daddr)
{
ino_t ino, nextfree;
IFILE *ifp;
SEGUSE *sup;
struct ubuf *bp;
LFS_IENTRY(ifp, fs, thisino, bp);
nextfree = ifp->if_nextfree;
ifp->if_nextfree = 0;
ifp->if_daddr = daddr;
VOP_BWRITE(bp);
while (thisino > (lblkno(fs, VTOI(fs->lfs_ivnode)->i_ffs_size) -
fs->lfs_segtabsz - fs->lfs_cleansz + 1) *
fs->lfs_ifpb) {
extend_ifile();
}
if (fs->lfs_freehd == thisino) {
fs->lfs_freehd = nextfree;
sbdirty();
if (nextfree == 0) {
extend_ifile();
}
} else {
ino = fs->lfs_freehd;
while (ino) {
LFS_IENTRY(ifp, fs, ino, bp);
assert(ifp->if_nextfree != ino);
if (ifp->if_nextfree == thisino) {
ifp->if_nextfree = nextfree;
VOP_BWRITE(bp);
break;
} else
ino = ifp->if_nextfree;
brelse(bp);
}
}
/* Account for new location */
LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), bp);
sup->su_nbytes += DINODE_SIZE;
VOP_BWRITE(bp);
seg_table[dtosn(fs, daddr)].su_nbytes += DINODE_SIZE;
}
/*
* Roll forward from the last verified checkpoint.
*
* Basic strategy:
*
* Run through the summaries finding the last valid partial segment.
* Note segment numbers as we go. For each inode that we find, compare
* its generation number; if newer than old inode's (or if old inode is
* USTATE), change to that inode. Recursively look at inode blocks that
* do not have their old disk addresses. These addresses must lie in
* segments we have seen already in our roll forward.
*
* A second pass through the past-checkpoint area verifies the validity
* of these new blocks, as well as updating other blocks that do not
* have corresponding new inodes (but their generation number must match
* the old generation number).
*/
void
pass6(void)
{
ufs_daddr_t daddr, ibdaddr, odaddr, lastgood, nextseg, *idaddrp;
struct uvnode *vp, *devvp;
CLEANERINFO *cip;
SEGUSE *sup;
SEGSUM *sp;
struct ubuf *bp, *ibp, *sbp, *cbp;
struct dinode *dp;
struct inodesc idesc;
int i, j, bc;
ufs_daddr_t hassuper;
devvp = fs->lfs_unlockvp;
/* Find last valid partial segment */
lastgood = try_verify(fs, devvp, 0, debug);
if (lastgood == fs->lfs_offset) {
if (debug)
pwarn("not rolling forward, nothing to recover\n");
return;
}
if (!preen && reply("roll forward") == 0)
return;
if (debug)
pwarn("rolling forward between %" PRIx32 " and %" PRIx32 "\n",
fs->lfs_offset, lastgood);
/*
* Pass 1: find inode blocks. We ignore the Ifile inode but accept
* changes to any other inode.
*/
daddr = fs->lfs_offset;
nextseg = fs->lfs_nextseg;
while (daddr != lastgood) {
seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY | SEGUSE_ACTIVE;
LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
sup->su_flags |= SEGUSE_DIRTY;
VOP_BWRITE(sbp);
hassuper = 0;
oncemore:
/* Read in summary block */
bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, &bp);
sp = (SEGSUM *)bp->b_data;
/* Could be a superblock instead of a segment summary. */
if (sntod(fs, dtosn(fs, daddr)) == daddr &&
(sp->ss_magic != SS_MAGIC ||
sp->ss_sumsum != cksum(&sp->ss_datasum, fs->lfs_sumsize -
sizeof(sp->ss_sumsum)))) {
brelse(bp);
daddr += btofsb(fs, LFS_SBPAD);
hassuper = 1;
goto oncemore;
}
/* We have verified that this is a good summary. */
LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
++sup->su_nsums;
VOP_BWRITE(sbp);
fs->lfs_bfree -= btofsb(fs, fs->lfs_sumsize);
fs->lfs_dmeta += btofsb(fs, fs->lfs_sumsize);
sbdirty();
nextseg = sp->ss_next;
if (sntod(fs, dtosn(fs, daddr)) == daddr +
hassuper * btofsb(fs, LFS_SBPAD) &&
dtosn(fs, daddr) != dtosn(fs, fs->lfs_offset)) {
--fs->lfs_nclean;
sbdirty();
}
/* Find inodes, look at generation number. */
if (sp->ss_ninos) {
LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
sup->su_ninos += howmany(sp->ss_ninos, INOPB(fs));
VOP_BWRITE(sbp);
fs->lfs_dmeta += btofsb(fs, howmany(sp->ss_ninos,
INOPB(fs)) *
fs->lfs_ibsize);
}
idaddrp = ((ufs_daddr_t *)((char *)bp->b_data + fs->lfs_sumsize));
for (i = 0; i < howmany(sp->ss_ninos, INOPB(fs)); i++) {
ino_t inums[INOPB(fs) + 1];
for (j = 0; j < INOPB(fs) + 1; j++)
inums[j] = 0;
ibdaddr = *--idaddrp;
fs->lfs_bfree -= btofsb(fs, fs->lfs_ibsize);
sbdirty();
bread(devvp, fsbtodb(fs, ibdaddr), fs->lfs_ibsize,
NOCRED, &ibp);
j = 0;
for (dp = (struct dinode *)ibp->b_data;
dp < (struct dinode *)ibp->b_data + INOPB(fs);
++dp) {
if (dp->di_u.inumber == 0 ||
dp->di_u.inumber == fs->lfs_ifile)
continue;
/* Basic sanity checks */
if (dp->di_nlink < 0 ||
dp->di_u.inumber < 0 ||
dp->di_size < 0) {
pwarn("bad inode at %" PRIx32 "\n",
ibdaddr);
brelse(ibp);
brelse(bp);
goto out;
}
vp = vget(fs, dp->di_u.inumber);
/*
* Four cases:
* (1) Invalid inode (nlink == 0).
* If currently allocated, remove.
*/
if (dp->di_nlink == 0) {
remove_ino(vp, dp->di_u.inumber);
continue;
}
/*
* (2) New valid inode, previously free.
* Nothing to do except account
* the inode itself, done after the
* loop.
*/
if (vp == NULL) {
inums[j++] = dp->di_u.inumber;
continue;
}
/*
* (3) Valid new version of previously
* allocated inode. Delete old file
* and proceed as in (2).
*/
if (vp && VTOI(vp)->i_ffs_gen < dp->di_gen) {
remove_ino(vp, dp->di_u.inumber);
inums[j++] = dp->di_u.inumber;
continue;
}
/*
* (4) Same version of previously
* allocated inode. Move inode to
* this location, account inode change
* only. We'll pick up any new
* blocks when we do the block pass.
*/
if (vp && VTOI(vp)->i_ffs_gen == dp->di_gen) {
readdress_inode(dp->di_u.inumber, ibdaddr);
/* Update with new info */
VTOD(vp)->di_mode = dp->di_mode;
VTOD(vp)->di_nlink = dp->di_nlink;
/* XXX size is important */
VTOD(vp)->di_size = dp->di_size;
VTOD(vp)->di_atime = dp->di_atime;
VTOD(vp)->di_atimensec = dp->di_atimensec;
VTOD(vp)->di_mtime = dp->di_mtime;
VTOD(vp)->di_mtimensec = dp->di_mtimensec;
VTOD(vp)->di_ctime = dp->di_ctime;
VTOD(vp)->di_ctimensec = dp->di_ctimensec;
VTOD(vp)->di_flags = dp->di_flags;
VTOD(vp)->di_uid = dp->di_uid;
VTOD(vp)->di_gid = dp->di_gid;
inodirty(VTOI(vp));
}
}
brelse(ibp);
for (j = 0; inums[j]; j++) {
alloc_inode(inums[j], ibdaddr);
vp = lfs_raw_vget(fs, inums[j],
devvp->v_fd, ibdaddr);
/* We'll get the blocks later */
memset(VTOD(vp)->di_db, 0, (NDADDR + NIADDR) *
sizeof(ufs_daddr_t));
VTOD(vp)->di_blocks = 0;
vp->v_flag |= VDIROP;
inodirty(VTOI(vp));
}
}
bc = check_summary(fs, sp, daddr, debug, devvp, NULL);
if (bc == 0) {
brelse(bp);
break;
}
odaddr = daddr;
daddr += btofsb(fs, fs->lfs_sumsize + bc);
if (dtosn(fs, odaddr) != dtosn(fs, daddr) ||
dtosn(fs, daddr) != dtosn(fs, daddr +
btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize))) {
daddr = ((SEGSUM *)bp->b_data)->ss_next;
}
brelse(bp);
}
out:
/*
* Check our new vnodes. Any blocks must lie in segments that
* we've seen before (SEGUSE_DIRTY or SEGUSE_RFW); and the rest
* of the pass 1 checks as well.
*/
memset(&idesc, 0, sizeof(struct inodesc));
idesc.id_type = ADDR;
idesc.id_func = pass6check;
idesc.id_lblkno = 0;
LIST_FOREACH(vp, &vnodelist, v_mntvnodes) {
checkinode(VTOI(vp)->i_number, &idesc);
}
/*
* Second pass. Run through FINFO entries looking for blocks
* with the same generation number as files we've seen before.
* If they have it, pretend like we just wrote them. We don't
* do the pretend-write, though, if we've already seen them
* (the accounting would have been done for us already).
*/
daddr = fs->lfs_offset;
while (daddr != lastgood) {
if (!(seg_table[dtosn(fs, daddr)].su_flags & SEGUSE_DIRTY)) {
seg_table[dtosn(fs, daddr)].su_flags |= SEGUSE_DIRTY;
LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), sbp);
sup->su_flags |= SEGUSE_DIRTY;
VOP_BWRITE(sbp);
}
oncemore2:
/* Read in summary block */
bread(devvp, fsbtodb(fs, daddr), fs->lfs_sumsize, NULL, &bp);
sp = (SEGSUM *)bp->b_data;
/* Could be a superblock instead of a segment summary. */
if (sntod(fs, dtosn(fs, daddr)) == daddr &&
(sp->ss_magic != SS_MAGIC ||
sp->ss_sumsum != cksum(&sp->ss_datasum, fs->lfs_sumsize -
sizeof(sp->ss_sumsum)))) {
brelse(bp);
daddr += btofsb(fs, LFS_SBPAD);
goto oncemore2;
}
bc = check_summary(fs, sp, daddr, debug, devvp, pass6harvest);
if (bc == 0) {
brelse(bp);
break;
}
odaddr = daddr;
daddr += btofsb(fs, fs->lfs_sumsize + bc);
fs->lfs_avail -= btofsb(fs, fs->lfs_sumsize + bc);
if (dtosn(fs, odaddr) != dtosn(fs, daddr) ||
dtosn(fs, daddr) != dtosn(fs, daddr +
btofsb(fs, fs->lfs_sumsize + fs->lfs_bsize))) {
fs->lfs_avail -= sntod(fs, dtosn(fs, daddr) + 1) - daddr;
daddr = ((SEGSUM *)bp->b_data)->ss_next;
}
LFS_CLEANERINFO(cip, fs, cbp);
LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0);
bp->b_flags |= B_AGE;
brelse(bp);
}
/* Update offset to point at correct location */
fs->lfs_offset = lastgood;
fs->lfs_curseg = sntod(fs, dtosn(fs, lastgood));
fs->lfs_nextseg = nextseg;
if (!preen) {
/* Run pass 5 again (it's quick anyway). */
pwarn("** Phase 6b - Recheck Segment Block Accounting\n");
pass5();
}
}

1016
sbin/fsck_lfs/segwrite.c Normal file

File diff suppressed because it is too large Load Diff

76
sbin/fsck_lfs/segwrite.h Normal file
View File

@ -0,0 +1,76 @@
/* $NetBSD: segwrite.h,v 1.1 2003/03/28 08:09:54 perseant Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Determine if it's OK to start a partial in this segment, or if we need
* to go on to a new segment.
*/
#define LFS_PARTIAL_FITS(fs) \
((fs)->lfs_fsbpseg - ((fs)->lfs_offset - (fs)->lfs_curseg) > \
fragstofsb((fs), (fs)->lfs_frag))
/* op values to lfs_writevnodes */
#define VN_REG 0
#define VN_DIROP 1
int lfs_segwrite(struct lfs *, int);
void lfs_writefile(struct lfs *, struct segment *, struct uvnode *);
int lfs_writeinode(struct lfs *, struct segment *, struct inode *);
int lfs_gatherblock(struct segment *, struct ubuf *);
int lfs_gather(struct lfs *, struct segment *, struct uvnode *,
int (*match) (struct lfs *, struct ubuf *));
void lfs_update_single(struct lfs *, struct segment *, daddr_t, int32_t, int);
void lfs_updatemeta(struct segment *);
int lfs_initseg(struct lfs *);
void lfs_newseg(struct lfs *);
int lfs_writeseg(struct lfs *, struct segment *);
void lfs_writesuper(struct lfs *, ufs_daddr_t);
int lfs_match_data(struct lfs *, struct ubuf *);
int lfs_match_indir(struct lfs *, struct ubuf *);
int lfs_match_dindir(struct lfs *, struct ubuf *);
int lfs_match_tindir(struct lfs *, struct ubuf *);
void lfs_shellsort(struct ubuf **, int32_t *, int, int);
int ufs_getlbns(struct lfs *, struct uvnode *, daddr_t, struct indir *, int *);
int ufs_bmaparray(struct lfs *, struct uvnode *, daddr_t, daddr_t *, struct indir *, int *);
int lfs_seglock(struct lfs *, unsigned long);
void lfs_segunlock(struct lfs *);
int lfs_writevnodes(struct lfs *, struct segment *, int);
void lfs_writesuper(struct lfs *, ufs_daddr_t);

View File

@ -1,5 +1,40 @@
/* $NetBSD: setup.c,v 1.12 2003/01/24 21:55:10 fvdl Exp $ */
/* $NetBSD: setup.c,v 1.13 2003/03/28 08:09:55 perseant Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Copyright (c) 1980, 1986, 1993
* The Regents of the University of California. All rights reserved.
@ -35,18 +70,22 @@
/* #define DKTYPENAMES */
#define FSTYPENAMES
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/disklabel.h>
#include <sys/file.h>
#include <ufs/ufs/dinode.h>
#include <sys/mount.h> /* XXX ufs/lfs/lfs.h should include this for
* us */
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#define vnode uvnode
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#undef vnode
#include <ctype.h>
#include <err.h>
@ -55,121 +94,68 @@
#include <stdlib.h>
#include <string.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "fsck.h"
#include "extern.h"
#include "fsutil.h"
struct bufarea asblk;
daddr_t *din_table;
SEGUSE *seg_table;
#define altsblock (*asblk.b_un.b_fs)
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
void badsb(int, char *);
int calcsb(const char *, int, struct lfs *);
static struct disklabel *getdisklabel(const char *, int);
static int readsb(int);
int lfs_maxino(void);
u_quad_t maxtable[] = {
/* 1 */ -1,
/* 2 */ -1,
/* 4 */ -1,
/* 8 */ -1,
/* 16 */ -1,
/* 32 */ -1,
/* 64 */ -1,
/* 128 */ -1,
/* 256 */ -1,
/* 512 */ NDADDR + 128 + 128 * 128 + 128 * 128 * 128,
/* 1024 */ NDADDR + 256 + 256 * 256 + 256 * 256 * 256,
/* 2048 */ NDADDR + 512 + 512 * 512 + 512 * 512 * 512,
/* 4096 */ NDADDR + 1024 + 1024 * 1024 + 1024 * 1024 * 1024,
/* 8192 */ 1 << 31,
/* 16 K */ 1 << 31,
/* 32 K */ 1 << 31,
};
static daddr_t try_verify(struct lfs *, struct lfs *);
static struct disklabel *getdisklabel(const char *, int);
ufs_daddr_t *din_table;
SEGUSE *seg_table;
#ifdef DKTYPENAMES
int useless(void);
int useless(void);
int
useless(void)
{
char **foo = (char **)dktypenames;
char **bar = (char **)fscknames;
char **foo = (char **) dktypenames;
char **bar = (char **) fscknames;
return foo - bar;
}
#endif
static daddr_t
try_verify(struct lfs * osb, struct lfs * nsb)
{
daddr_t daddr, odaddr;
SEGSUM *sp;
char *summary;
int bc, flag;
daddr = osb->lfs_offset;
summary = malloc(osb->lfs_sumsize);
while (daddr != nsb->lfs_offset) {
flag = 0;
oncemore:
/* Read in summary block */
bread(fsreadfd, summary, fsbtodb(osb, daddr), osb->lfs_sumsize);
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, osb->lfs_sumsize -
sizeof(sp->ss_sumsum))) {
if (flag == 0) {
flag = 1;
daddr += btofsb(osb, LFS_SBPAD);
goto oncemore;
}
return 0x0;
}
bc = check_summary(osb, sp, daddr);
if (bc == 0)
break;
odaddr = daddr;
daddr += btofsb(osb, osb->lfs_sumsize + bc);
if (dtosn(osb, odaddr) != dtosn(osb, daddr) ||
dtosn(osb, daddr) != dtosn(osb, daddr +
btofsb(osb, osb->lfs_sumsize + osb->lfs_bsize))) {
daddr = ((SEGSUM *)summary)->ss_next;
}
}
return daddr;
}
u_quad_t maxtable[] = {
/* 1 */ -1,
/* 2 */ -1,
/* 4 */ -1,
/* 8 */ -1,
/* 16 */ -1,
/* 32 */ -1,
/* 64 */ -1,
/* 128 */ -1,
/* 256 */ -1,
/* 512 */ NDADDR + 128 + 128 * 128 + 128 * 128 * 128,
/* 1024 */ NDADDR + 256 + 256 * 256 + 256 * 256 * 256,
/* 2048 */ NDADDR + 512 + 512 * 512 + 512 * 512 * 512,
/* 4096 */ NDADDR + 1024 + 1024 * 1024 + 1024 * 1024 * 1024,
/* 8192 */ 1 << 31,
/* 16 K */ 1 << 31,
/* 32 K */ 1 << 31,
};
int
setup(const char *dev)
{
long bmapsize;
long bmapsize;
struct disklabel *lp;
#if 0
long i;
off_t sizepb;
#endif
struct stat statb;
daddr_t daddr;
struct lfs proto;
int doskipclean;
u_int64_t maxfilesize;
struct lfs *sb0, *sb1, *osb, *nsb;
struct dinode *idinode;
struct stat statb;
int doskipclean;
u_int64_t maxfilesize;
int open_flags;
struct uvnode *ivp;
struct ubuf *bp;
int i;
SEGUSE *sup;
havesb = 0;
fswritefd = -1;
doskipclean = skipclean;
if (stat(dev, &statb) < 0) {
printf("Can't stat %s: %s\n", dev, strerror(errno));
@ -180,14 +166,18 @@ setup(const char *dev)
if (reply("CONTINUE") == 0)
return (0);
}
if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
if (nflag)
open_flags = O_RDONLY;
else
open_flags = O_RDWR;
if ((fsreadfd = open(dev, open_flags)) < 0) {
printf("Can't open %s: %s\n", dev, strerror(errno));
return (0);
}
if (preen == 0)
printf("** %s", dev);
if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) {
fswritefd = -1;
if (nflag) {
if (preen)
pfatal("NO WRITE ACCESS");
printf(" (NO WRITE)");
@ -196,281 +186,169 @@ setup(const char *dev)
printf("\n");
fsmodified = 0;
lfdir = 0;
initbarea(&sblk);
initbarea(&asblk);
sblk.b_un.b_buf = malloc(LFS_SBPAD);
asblk.b_un.b_buf = malloc(LFS_SBPAD);
if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
errexit("cannot allocate space for superblock\n");
bufinit();
fs = lfs_init(fsreadfd, bflag, idaddr, debug);
if (fs == NULL) {
if (preen)
printf("%s: ", cdevname());
pfatal("BAD SUPER BLOCK\n");
}
if ((lp = getdisklabel((char *) NULL, fsreadfd)) != NULL)
dev_bsize = secsize = lp->d_secsize;
else
dev_bsize = secsize = DEV_BSIZE;
/*
* Read in the superblock, looking for alternates if necessary
*/
if (readsb(1) == 0) {
if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
return (0);
if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
return (0);
#if 0 /* XXX find the LFS way to do this */
for (cg = 0; cg < proto.lfs_ncg; cg++) {
bflag = fsbtodb(&proto, cgsblock(&proto, cg));
if (readsb(0) != 0)
break;
#if 0
if (fs->lfs_pflags & LFS_PF_CLEAN) {
if (doskipclean) {
pwarn("%sile system is clean; not checking\n",
preen ? "f" : "** F");
return (-1);
}
if (cg >= proto.lfs_ncg) {
printf("%s %s\n%s %s\n%s %s\n",
"SEARCH FOR ALTERNATE SUPER-BLOCK",
"FAILED. YOU MUST USE THE",
"-b OPTION TO FSCK_FFS TO SPECIFY THE",
"LOCATION OF AN ALTERNATE",
"SUPER-BLOCK TO SUPPLY NEEDED",
"INFORMATION; SEE fsck_ffs(8).");
return (0);
}
#else
pwarn("XXX Can't look for alternate superblocks yet\n");
return (0);
if (!preen)
pwarn("** File system is already clean\n");
}
#endif
doskipclean = 0;
pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
}
bufinit();
if (bflag == 0x0 && idaddr == 0x0) {
/*
* If we read a proper superblock, but its address was not
* lfs_sboffs[0], we're holding a fake primary superblock,
* and need to read the real one.
*/
if (sblock.lfs_sboffs[0] != dbtofsb(&sblock,
LFS_LABELPAD / dev_bsize))
{
if (debug)
pwarn("Getting 'real' primary superblock from 0x%x\n",
fsbtodb(&sblock, sblock.lfs_sboffs[0]));
bflag = fsbtodb(&sblock, sblock.lfs_sboffs[0]);
readsb(1);
bflag = 0;
}
/*
* Even if that superblock read in properly, it may not
* be guaranteed to point to a complete checkpoint.
* Read in the second superblock too, and take whichever
* of the two is *less* recent. --ks
*/
sb0 = malloc(sizeof(*sb0));
sb1 = malloc(sizeof(*sb1));
memcpy(sb0, &sblock, sizeof(*sb0));
bflag = fsbtodb(&sblock, 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) {
if (sb0->lfs_version > 1) {
pwarn("sb0 sn=%lld, sb1 sn=%lld\n",
(long long)sb0->lfs_serial,
(long long)sblock.lfs_serial);
} else {
pwarn("sb0 %lld, sb1 %lld\n",
(long long)sb0->lfs_otstamp,
(long long)sblock.lfs_otstamp);
}
}
/*
* 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_version == 1 &&
sb0->lfs_otstamp != sb1->lfs_otstamp) ||
(sb0->lfs_version > 1 &&
sb0->lfs_serial != sb1->lfs_serial)) {
if (sb0->lfs_version == 1) {
if (sb0->lfs_otstamp > sb1->lfs_otstamp) {
osb = sb1;
nsb = sb0;
} else {
osb = sb0;
nsb = sb1;
}
} else {
if (sb0->lfs_serial > sb1->lfs_serial) {
osb = sb1;
nsb = sb0;
} else {
osb = sb0;
nsb = sb1;
}
}
daddr = try_verify(osb, nsb);
if (debug)
printf("done.\n");
if (daddr == nsb->lfs_offset) {
pwarn("Checkpoint verified, recovered %lld seconds of data\n",
(long long)nsb->lfs_tstamp - (long long)osb->lfs_tstamp);
memcpy(&sblock, nsb, sizeof(*nsb));
sbdirty();
} else {
pwarn("Checkpoint invalid, lost %lld seconds of data\n", (long long)nsb->lfs_tstamp - (long long)osb->lfs_tstamp);
memcpy(&sblock, osb, sizeof(*osb));
}
}
}
free(sb0);
free(sb1);
}
if (idaddr == 0x0)
idaddr = sblock.lfs_idaddr;
if (debug) {
printf("dev_bsize = %lu\n", dev_bsize);
printf("lfs_bsize = %lu\n", (unsigned long)sblock.lfs_bsize);
printf("lfs_fsize = %lu\n", (unsigned long)sblock.lfs_fsize);
printf("lfs_frag = %lu\n", (unsigned long)sblock.lfs_frag);
printf("INOPB(fs) = %lu\n", (unsigned long)INOPB(&sblock));
if (sblock.lfs_version > 1)
printf("INOPF(fs) = %lu\n",
(unsigned long)INOPF(&sblock));
/* printf("fsbtodb(fs,1) = %lu\n",fsbtodb(&sblock,1)); */
printf("lfs_bsize = %lu\n", (unsigned long) fs->lfs_bsize);
printf("lfs_fsize = %lu\n", (unsigned long) fs->lfs_fsize);
printf("lfs_frag = %lu\n", (unsigned long) fs->lfs_frag);
printf("lfs_inopb = %lu\n", (unsigned long) fs->lfs_inopb);
}
/* Compatibility */
if (sblock.lfs_version == 1) {
sblock.lfs_sumsize = LFS_V1_SUMMARY_SIZE;
sblock.lfs_ibsize = sblock.lfs_bsize;
sblock.lfs_start = sblock.lfs_sboffs[0];
sblock.lfs_fsbtodb = 0;
}
initbarea(&iblk);
iblk.b_un.b_buf = malloc(sblock.lfs_ibsize);
if (bread(fsreadfd, (char *)iblk.b_un.b_buf, fsbtodb(&sblock, idaddr),
(long)sblock.lfs_ibsize) != 0) {
printf("Couldn't read disk block %lld\n", (long long)idaddr);
exit(1);
}
idinode = lfs_difind(&sblock, sblock.lfs_ifile, &ifblock);
if (idinode == NULL) {
printf("Ifile inode not found at daddr 0x%llx\n",
(unsigned long long)idaddr);
exit(1);
/* XXX find it in the segment summaries */
}
maxino = ((idinode->di_size
- (sblock.lfs_cleansz + sblock.lfs_segtabsz) * sblock.lfs_bsize)
/ sblock.lfs_bsize) * sblock.lfs_ifpb;
if (debug)
printf("maxino = %d\n", maxino);
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));
if (sblock.lfs_version == 1)
maxfsblock = sblock.lfs_size * (sblock.lfs_bsize / dev_bsize);
else
maxfsblock = sblock.lfs_size;
maxfilesize = maxtable[sblock.lfs_bshift] << sblock.lfs_bshift;
if ((sblock.lfs_minfree < 0 || sblock.lfs_minfree > 99)) {
if (fs->lfs_version == 1)
maxfsblock = fs->lfs_size * (fs->lfs_bsize / dev_bsize);
else
maxfsblock = fs->lfs_size;
maxfilesize = maxtable[fs->lfs_bshift] << fs->lfs_bshift;
if ((fs->lfs_minfree < 0 || fs->lfs_minfree > 99)) {
pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK",
sblock.lfs_minfree);
fs->lfs_minfree);
if (reply("SET TO DEFAULT") == 1) {
sblock.lfs_minfree = 10;
fs->lfs_minfree = 10;
sbdirty();
}
}
if (sblock.lfs_bmask != sblock.lfs_bsize - 1) {
if (fs->lfs_bmask != fs->lfs_bsize - 1) {
pwarn("INCORRECT BMASK=%x IN SUPERBLOCK (should be %x)",
(unsigned int)sblock.lfs_bmask,
(unsigned int)sblock.lfs_bsize - 1);
sblock.lfs_bmask = sblock.lfs_bsize - 1;
(unsigned int) fs->lfs_bmask,
(unsigned int) fs->lfs_bsize - 1);
fs->lfs_bmask = fs->lfs_bsize - 1;
if (preen)
printf(" (FIXED)\n");
if (preen || reply("FIX") == 1) {
sbdirty();
dirty(&asblk);
}
}
#if 0 /* FFS-specific checks */
if (sblock.lfs_fmask != ~(sblock.lfs_fsize - 1)) {
pwarn("INCORRECT FMASK=%x IN SUPERBLOCK",
sblock.lfs_fmask);
sblock.lfs_fmask = ~(sblock.lfs_fsize - 1);
if (fs->lfs_ffmask != fs->lfs_fsize - 1) {
pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK",
fs->lfs_ffmask);
fs->lfs_ffmask = fs->lfs_fsize - 1;
if (preen)
printf(" (FIXED)\n");
if (preen || reply("FIX") == 1) {
sbdirty();
dirty(&asblk);
}
}
#endif
if (sblock.lfs_maxfilesize != maxfilesize) {
if (fs->lfs_fbmask != (1 << fs->lfs_fbshift) - 1) {
pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK",
fs->lfs_ffmask);
fs->lfs_fbmask = (1 << fs->lfs_fbshift) - 1;
if (preen)
printf(" (FIXED)\n");
if (preen || reply("FIX") == 1) {
sbdirty();
}
}
if (fs->lfs_maxfilesize != maxfilesize) {
pwarn(
"INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK (should be %llu)",
(unsigned long long)sblock.lfs_maxfilesize,
(unsigned long long)maxfilesize);
sblock.lfs_maxfilesize = maxfilesize;
(unsigned long long) fs->lfs_maxfilesize,
(unsigned long long) maxfilesize);
fs->lfs_maxfilesize = maxfilesize;
if (preen)
printf(" (FIXED)\n");
if (preen || reply("FIX") == 1) {
sbdirty();
dirty(&asblk);
}
}
if (sblock.lfs_maxsymlinklen != MAXSYMLINKLEN) {
if (fs->lfs_maxsymlinklen != MAXSYMLINKLEN) {
pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK",
sblock.lfs_maxsymlinklen);
sblock.lfs_maxsymlinklen = MAXSYMLINKLEN;
fs->lfs_maxsymlinklen);
fs->lfs_maxsymlinklen = MAXSYMLINKLEN;
if (preen)
printf(" (FIXED)\n");
if (preen || reply("FIX") == 1) {
sbdirty();
dirty(&asblk);
}
}
newinofmt = 1;
/*
* Read in the Ifile; we'll be using it a lot.
* XXX If the Ifile is corrupted we are in bad shape. We need to
* XXX run through the segment headers of the entire disk to
* XXX reconstruct the inode table, then pretend all segments are
* XXX dirty while we do the rest.
*/
ivp = fs->lfs_ivnode;
maxino = ((VTOI(ivp)->i_ffs_size - (fs->lfs_cleansz + fs->lfs_segtabsz)
* fs->lfs_bsize) / fs->lfs_bsize) * fs->lfs_ifpb;
if (debug)
printf("maxino = %d\n", maxino);
for (i = 0; i < VTOI(ivp)->i_ffs_size; i += fs->lfs_bsize) {
bread(ivp, i >> fs->lfs_bshift, fs->lfs_bsize, NOCRED, &bp);
/* XXX check B_ERROR */
brelse(bp);
}
/*
* allocate and initialize the necessary maps
*/
din_table = (ufs_daddr_t *) malloc(maxino * sizeof(*din_table));
memset(din_table, 0, maxino * sizeof(*din_table));
seg_table = (SEGUSE *) malloc(fs->lfs_nseg * sizeof(SEGUSE));
memset(seg_table, 0, fs->lfs_nseg * sizeof(SEGUSE));
/* Get segment flags */
for (i = 0; i < fs->lfs_nseg; i++) {
LFS_SEGENTRY(sup, fs, i, bp);
seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE;
brelse(bp);
}
/* Initialize Ifile entry */
din_table[fs->lfs_ifile] = fs->lfs_idaddr;
seg_table[dtosn(fs, fs->lfs_idaddr)].su_nbytes += DINODE_SIZE;
#ifndef VERBOSE_BLOCKMAP
bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
blockmap = calloc((unsigned)bmapsize, sizeof(char));
blockmap = calloc((unsigned) bmapsize, sizeof(char));
#else
bmapsize = maxfsblock * sizeof(ino_t);
blockmap = (ino_t *)calloc(maxfsblock, sizeof(ino_t));
blockmap = (ino_t *) calloc(maxfsblock, sizeof(ino_t));
#endif
if (blockmap == NULL) {
printf("cannot alloc %u bytes for blockmap\n",
(unsigned)bmapsize);
(unsigned) bmapsize);
goto badsblabel;
}
statemap = calloc((unsigned)maxino, sizeof(char));
statemap = calloc((unsigned) maxino, sizeof(char));
if (statemap == NULL) {
printf("cannot alloc %u bytes for statemap\n",
(unsigned)maxino);
(unsigned) maxino);
goto badsblabel;
}
typemap = calloc((unsigned)maxino, sizeof(char));
typemap = calloc((unsigned) maxino, sizeof(char));
if (typemap == NULL) {
printf("cannot alloc %u bytes for typemap\n",
(unsigned)maxino);
(unsigned) maxino);
goto badsblabel;
}
lncntp = (int16_t *)calloc((unsigned)maxino, sizeof(int16_t));
lncntp = (int16_t *) calloc((unsigned) maxino, sizeof(int16_t));
if (lncntp == NULL) {
printf("cannot alloc %lu bytes for lncntp\n",
(unsigned long)maxino * sizeof(int16_t));
(unsigned long) maxino * sizeof(int16_t));
goto badsblabel;
}
return (1);
@ -480,190 +358,6 @@ badsblabel:
return (0);
}
/*
* Read in the LFS super block and its summary info.
*/
static int
readsb(int listerr)
{
daddr_t super = bflag ? bflag : LFS_LABELPAD / dev_bsize;
u_int32_t checksum;
if (bread(fsreadfd, (char *) &sblock, super, (long) LFS_SBPAD) != 0)
return (0);
sblk.b_bno = super;
sblk.b_size = LFS_SBPAD;
/*
* run a few consistency checks of the super block
*/
if (sblock.lfs_magic != LFS_MAGIC) {
badsb(listerr, "MAGIC NUMBER WRONG");
return (0);
}
/* checksum */
checksum = lfs_sb_cksum(&(sblock.lfs_dlfs));
if (sblock.lfs_cksum != checksum) {
printf("Superblock checksum (%lu) does not match computed checksum (%lu)\n",
(unsigned long)sblock.lfs_cksum, (unsigned long) checksum);
}
#if 0 /* XXX - replace these checks with
* appropriate LFS sanity checks */
if (sblock.lfs_ncg < 1) {
badsb(listerr, "NCG OUT OF RANGE");
return (0);
}
if (sblock.lfs_cpg < 1) {
badsb(listerr, "CPG OUT OF RANGE");
return (0);
}
if (sblock.lfs_ncg * sblock.lfs_cpg < sblock.lfs_ncyl ||
(sblock.lfs_ncg - 1) * sblock.lfs_cpg >= sblock.lfs_ncyl) {
badsb(listerr, "NCYL LESS THAN NCG*CPG");
return (0);
}
if (sblock.lfs_sbsize > SBSIZE) {
badsb(listerr, "SIZE PREPOSTEROUSLY LARGE");
return (0);
}
#endif
/*
* Compute block size that the filesystem is based on,
* according to fsbtodb, and adjust superblock block number
* so we can tell if this is an alternate later.
*/
super *= dev_bsize;
#if 0
dev_bsize = sblock.lfs_bsize / fsbtodb(&sblock, 1);
#endif
sblk.b_bno = super / dev_bsize;
if (bflag) {
havesb = 1;
return (1);
}
#if 0 /* XXX - for now skip the alt. superblock
* test as well */
/*
* Set all possible fields that could differ, then do check
* of whole super block against an alternate super block.
* When an alternate super-block is specified this check is skipped.
*/
getblk(&asblk, cgsblock(&sblock, sblock.lfs_ncg - 1), sblock.lfs_sbsize);
if (asblk.b_errs)
return (0);
altsblock.lfs_firstfield = sblock.lfs_firstfield;
altsblock.lfs_fscktime = sblock.lfs_fscktime;
altsblock.lfs_time = sblock.lfs_time;
altsblock.lfs_cstotal = sblock.lfs_cstotal;
altsblock.lfs_cgrotor = sblock.lfs_cgrotor;
altsblock.lfs_fmod = sblock.lfs_fmod;
altsblock.lfs_clean = sblock.lfs_clean;
altsblock.lfs_ronly = sblock.lfs_ronly;
altsblock.lfs_flags = sblock.lfs_flags;
altsblock.lfs_maxcontig = sblock.lfs_maxcontig;
altsblock.lfs_minfree = sblock.lfs_minfree;
altsblock.lfs_optim = sblock.lfs_optim;
altsblock.lfs_rotdelay = sblock.lfs_rotdelay;
altsblock.lfs_maxbpg = sblock.lfs_maxbpg;
memcpy(altsblock.lfs_csp, sblock.lfs_csp,
sizeof sblock.lfs_csp);
altsblock.lfs_maxcluster = sblock.lfs_maxcluster;
memcpy(altsblock.lfs_fsmnt, sblock.lfs_fsmnt,
sizeof sblock.lfs_fsmnt);
memcpy(altsblock.lfs_sparecon, sblock.lfs_sparecon,
sizeof sblock.lfs_sparecon);
/*
* The following should not have to be copied.
*/
altsblock.lfs_fsbtodb = sblock.lfs_fsbtodb;
altsblock.lfs_interleave = sblock.lfs_interleave;
altsblock.lfs_npsect = sblock.lfs_npsect;
altsblock.lfs_nrpos = sblock.lfs_nrpos;
altsblock.lfs_state = sblock.lfs_state;
altsblock.lfs_qbmask = sblock.lfs_qbmask;
altsblock.lfs_qfmask = sblock.lfs_qfmask;
altsblock.lfs_state = sblock.lfs_state;
altsblock.lfs_maxfilesize = sblock.lfs_maxfilesize;
if (memcmp(&sblock, &altsblock, (int)sblock.lfs_sbsize)) {
if (debug) {
long *nlp, *olp, *endlp;
printf("superblock mismatches\n");
nlp = (long *) &altsblock;
olp = (long *) &sblock;
endlp = olp + (sblock.lfs_sbsize / sizeof *olp);
for (; olp < endlp; olp++, nlp++) {
if (*olp == *nlp)
continue;
printf("offset %d, original %ld, alternate %ld\n",
olp - (long *) &sblock, *olp, *nlp);
}
}
badsb(listerr,
"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
return (0);
}
#endif
havesb = 1;
return (1);
}
void
badsb(int listerr, char *s)
{
if (!listerr)
return;
if (preen)
printf("%s: ", cdevname());
pfatal("BAD SUPER BLOCK: %s\n", s);
}
/*
* Calculate a prototype superblock based on information in the disk label.
* When done the cgsblock macro can be calculated and the fs_ncg field
* can be used. Do NOT attempt to use other macros without verifying that
* their needed information is available!
*/
int
calcsb(const char *dev, int devfd, struct lfs * fs)
{
register struct disklabel *lp;
register struct partition *pp;
register char *cp;
int i;
cp = strchr(dev, '\0') - 1;
if ((cp == (char *) -1 || (*cp < 'a' || *cp > 'h')) && !isdigit(*cp)) {
pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev);
return (0);
}
lp = getdisklabel(dev, devfd);
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++;
}
return (1);
}
static struct disklabel *
getdisklabel(const char *s, int fd)
{
@ -673,11 +367,7 @@ getdisklabel(const char *s, int 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.10 2003/01/24 21:55:10 fvdl Exp $ */
/* $NetBSD: utilities.c,v 1.11 2003/03/28 08:09:55 perseant Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -35,11 +35,13 @@
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <sys/mount.h>
#include <ufs/lfs/lfs.h>
#include <ufs/lfs/lfs_extern.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -48,33 +50,37 @@
#include <signal.h>
#include "bufcache.h"
#include "vnode.h"
#include "lfs.h"
#include "segwrite.h"
#include "fsutil.h"
#include "fsck.h"
#include "extern.h"
long diskreads, totalreads; /* Disk cache statistics */
long diskreads, totalreads; /* Disk cache statistics */
static void rwerror(char *, daddr_t);
extern int returntosingle;
extern int returntosingle;
extern off_t locked_queue_bytes;
int
ftypeok(struct dinode * dp)
{
switch (dp->di_mode & IFMT) {
case IFDIR:
case IFREG:
case IFBLK:
case IFCHR:
case IFLNK:
case IFSOCK:
case IFIFO:
case IFDIR:
case IFREG:
case IFBLK:
case IFCHR:
case IFLNK:
case IFSOCK:
case IFIFO:
return (1);
default:
if (debug)
printf("bad file type 0%o\n", dp->di_mode);
pwarn("bad file type 0%o\n", dp->di_mode);
return (0);
}
}
@ -82,14 +88,14 @@ ftypeok(struct dinode * dp)
int
reply(char *question)
{
int persevere;
char c;
int persevere;
char c;
if (preen)
pfatal("INTERNAL ERROR: GOT TO reply()");
err(1, "INTERNAL ERROR: GOT TO reply()");
persevere = !strcmp(question, "CONTINUE");
printf("\n");
if (!persevere && (nflag || fswritefd < 0)) {
if (!persevere && nflag) {
printf("%s? no\n\n", question);
return (0);
}
@ -99,7 +105,7 @@ reply(char *question)
}
do {
printf("%s? [yn] ", question);
(void)fflush(stdout);
(void) fflush(stdout);
c = getc(stdin);
while (c != '\n' && getc(stdin) != '\n')
if (feof(stdin))
@ -111,183 +117,30 @@ reply(char *question)
return (0);
}
/*
* Malloc buffers and set up cache.
*/
void
bufinit()
{
register struct bufarea *bp;
long bufcnt, i;
char *bufp;
pbp = pdirbp = (struct bufarea *)0;
bufp = malloc((unsigned int)sblock.lfs_bsize);
if (bufp == 0)
errexit("cannot allocate buffer pool\n");
/* cgblk.b_un.b_buf = bufp; */
/* initbarea(&cgblk); */
bufhead.b_next = bufhead.b_prev = &bufhead;
bufcnt = MAXBUFSPACE / sblock.lfs_bsize;
if (bufcnt < MINBUFS)
bufcnt = MINBUFS;
for (i = 0; i < bufcnt; i++) {
bp = (struct bufarea *)malloc(sizeof(struct bufarea));
bufp = malloc((unsigned int)sblock.lfs_bsize);
if (bp == NULL || bufp == NULL) {
if (i >= MINBUFS)
break;
errexit("cannot allocate buffer pool\n");
}
bp->b_un.b_buf = bufp;
bp->b_prev = &bufhead;
bp->b_next = bufhead.b_next;
bufhead.b_next->b_prev = bp;
bufhead.b_next = bp;
initbarea(bp);
}
bufhead.b_size = i; /* save number of buffers */
}
/*
* Manage a cache of directory blocks.
*/
struct bufarea *
getddblk(daddr_t blkno, long size)
{
register struct bufarea *bp;
for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
if (bp->b_bno == blkno) {
if (bp->b_size <= size)
getdblk(bp, blkno, size);
goto foundit;
}
for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
if ((bp->b_flags & B_INUSE) == 0)
break;
if (bp == &bufhead)
errexit("deadlocked buffer pool\n");
getdblk(bp, blkno, size);
/* fall through */
foundit:
totalreads++;
bp->b_prev->b_next = bp->b_next;
bp->b_next->b_prev = bp->b_prev;
bp->b_prev = &bufhead;
bp->b_next = bufhead.b_next;
bufhead.b_next->b_prev = bp;
bufhead.b_next = bp;
bp->b_flags |= B_INUSE;
return (bp);
}
struct bufarea *
getdatablk(daddr_t blkno, long size)
{
return getddblk(blkno, size);
}
void
getdblk(struct bufarea * bp, daddr_t blk, long size)
{
if (bp->b_bno != blk) {
flush(fswritefd, bp);
diskreads++;
bp->b_errs = bread(fsreadfd, bp->b_un.b_buf,
fsbtodb(&sblock, blk), size);
bp->b_bno = blk;
bp->b_size = size;
}
}
void
getblk(struct bufarea * bp, daddr_t blk, long size)
{
getdblk(bp, blk, size);
}
void
flush(int fd, struct bufarea * bp)
{
if (!bp->b_dirty)
return;
if (bp->b_errs != 0)
pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n",
(bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
(long long)bp->b_bno);
bp->b_dirty = 0;
bp->b_errs = 0;
bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
if (bp != &sblk)
return;
#if 0 /* XXX - FFS */
for (i = 0, j = 0; i < sblock.lfs_cssize; i += sblock.lfs_bsize, j++) {
bwrite(fswritefd, (char *)sblock.lfs_csp[j],
fsbtodb(&sblock, sblock.lfs_csaddr + j * sblock.lfs_frag),
sblock.lfs_cssize - i < sblock.lfs_bsize ?
sblock.lfs_cssize - i : sblock.lfs_bsize);
}
#endif
}
static void
rwerror(char *mesg, daddr_t blk)
write_superblocks(void)
{
if (preen == 0)
printf("\n");
pfatal("CANNOT %s: BLK %lld", mesg, (long long)blk);
if (reply("CONTINUE") == 0)
errexit("Program terminated\n");
lfs_writesuper(fs, fs->lfs_sboffs[0]);
lfs_writesuper(fs, fs->lfs_sboffs[1]);
fsmodified = 1;
}
void
ckfini(int markclean)
{
register struct bufarea *bp, *nbp;
int cnt = 0;
if (fswritefd < 0) {
(void)close(fsreadfd);
return;
}
flush(fswritefd, &sblk);
if (havesb && sblk.b_bno != sblock.lfs_sboffs[0] &&
sblk.b_bno != sblock.lfs_sboffs[1] &&
!preen && reply("UPDATE STANDARD SUPERBLOCKS")) {
sblk.b_bno = fsbtodb(&sblock, sblock.lfs_sboffs[0]);
sbdirty();
flush(fswritefd, &sblk);
}
if (havesb) {
if (sblk.b_bno == fsbtodb(&sblock, sblock.lfs_sboffs[0])) {
/* Do the first alternate */
sblk.b_bno = fsbtodb(&sblock, sblock.lfs_sboffs[1]);
sbdirty();
flush(fswritefd, &sblk);
} else if (sblk.b_bno ==
fsbtodb(&sblock, sblock.lfs_sboffs[1])) {
/* Do the primary */
sblk.b_bno = LFS_LABELPAD / dev_bsize;
sbdirty();
flush(fswritefd, &sblk);
if (!nflag && locked_queue_bytes > 0) {
if (preen || reply("WRITE CHANGES TO DISK") == 1) {
lfs_segwrite(fs, SEGM_CKP);
fsdirty = 0;
fsmodified = 1;
}
}
/* flush(fswritefd, &cgblk); */
/* free(cgblk.b_un.b_buf); */
for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
cnt++;
flush(fswritefd, bp);
nbp = bp->b_prev;
free(bp->b_un.b_buf);
free((char *)bp);
if (fsdirty && !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
sbdirty();
write_superblocks();
}
if (bufhead.b_size != cnt)
errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
pbp = pdirbp = (struct bufarea *)0;
if (markclean && !(sblock.lfs_pflags & LFS_PF_CLEAN)) {
if (markclean && (fs->lfs_pflags & LFS_PF_CLEAN) == 0) {
/*
* Mark the file system as clean, and sync the superblock.
*/
@ -296,169 +149,48 @@ ckfini(int markclean)
else if (!reply("MARK FILE SYSTEM CLEAN"))
markclean = 0;
if (markclean) {
sblock.lfs_pflags |= LFS_PF_CLEAN;
fs->lfs_pflags |= LFS_PF_CLEAN;
sbdirty();
flush(fswritefd, &sblk);
if (sblk.b_bno == LFS_LABELPAD / dev_bsize) {
/* Do the first alternate */
sblk.b_bno = fsbtodb(&sblock,
sblock.lfs_sboffs[0]);
flush(fswritefd, &sblk);
} else if (sblk.b_bno == fsbtodb(&sblock,
sblock.lfs_sboffs[0])) {
/* Do the primary */
sblk.b_bno = LFS_LABELPAD / dev_bsize;
flush(fswritefd, &sblk);
}
write_superblocks();
if (!preen)
printf(
"\n***** FILE SYSTEM MARKED CLEAN *****\n");
}
}
if (debug)
printf("cache missed %ld of %ld (%d%%)\n", diskreads,
totalreads, (int)(diskreads * 100 / totalreads));
(void)close(fsreadfd);
(void)close(fswritefd);
bufstats();
(void) close(fsreadfd);
}
int
bread(int fd, char *buf, daddr_t blk, long size)
{
char *cp;
int i, errs;
off_t offset;
offset = blk;
offset *= dev_bsize;
if (lseek(fd, offset, 0) < 0) {
rwerror("SEEK", blk);
} else if (read(fd, buf, (int)size) == size)
return (0);
rwerror("READ", blk);
if (lseek(fd, offset, 0) < 0)
rwerror("SEEK", blk);
errs = 0;
memset(buf, 0, (size_t)size);
printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
if (read(fd, cp, (int)secsize) != secsize) {
(void)lseek(fd, offset + i + secsize, 0);
if (secsize != dev_bsize && dev_bsize != 1)
printf(" %lld (%lld),",
(long long)((blk*dev_bsize + i) / secsize),
(long long)(blk + i / dev_bsize));
else
printf(" %lld,",
(long long)(blk + i / dev_bsize));
errs++;
}
}
printf("\n");
return (errs);
}
void
bwrite(int fd, char *buf, daddr_t blk, long size)
{
int i;
char *cp;
off_t offset;
if (fd < 0)
return;
offset = blk;
offset *= dev_bsize;
if (lseek(fd, offset, 0) < 0)
rwerror("SEEK", blk);
else if (write(fd, buf, (int)size) == size) {
fsmodified = 1;
return;
}
rwerror("WRITE", blk);
if (lseek(fd, offset, 0) < 0)
rwerror("SEEK", blk);
printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
(void)lseek(fd, offset + i + dev_bsize, 0);
printf(" %lld,", (long long)(blk + i / dev_bsize));
}
printf("\n");
return;
}
/*
* allocate a data block with the specified number of fragments
*/
int
allocblk(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)
return (0);
for (i = 0; i < maxfsblock - sblock.lfs_frag; i += sblock.lfs_frag) {
for (j = 0; j <= sblock.lfs_frag - frags; j++) {
if (testbmap(i + j))
continue;
for (k = 1; k < frags; k++)
if (testbmap(i + j + k))
break;
if (k < frags) {
j += k;
continue;
}
for (k = 0; k < frags; k++) {
#ifndef VERBOSE_BLOCKMAP
setbmap(i + j + k);
#else
setbmap(i + j + k, -1);
#endif
}
n_blks += frags;
return (i + j);
}
}
return (0);
#endif /* 0 */
}
/*
* Free a previously allocated block
*/
void
freeblk(daddr_t blkno, long frags)
{
struct inodesc idesc;
struct inodesc idesc;
idesc.id_blkno = blkno;
idesc.id_numfrags = frags;
(void)pass4check(&idesc);
(void) pass4check(&idesc);
}
/*
* Find a pathname
*/
void
getpathname(char *namebuf, ino_t curdir, ino_t ino)
{
int len;
register char *cp;
struct inodesc idesc;
static int busy = 0;
int len;
register char *cp;
struct inodesc idesc;
static int busy = 0;
if (curdir == ino && ino == ROOTINO) {
(void)strcpy(namebuf, "/");
(void) strcpy(namebuf, "/");
return;
}
if (busy ||
(statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
(void)strcpy(namebuf, "?");
(void) strcpy(namebuf, "?");
return;
}
busy = 1;
@ -486,7 +218,7 @@ namelookup:
break;
len = strlen(namebuf);
cp -= len;
memcpy(cp, namebuf, (size_t)len);
memcpy(cp, namebuf, (size_t) len);
*--cp = '/';
if (cp < &namebuf[MAXNAMLEN])
break;
@ -495,17 +227,15 @@ namelookup:
busy = 0;
if (ino != ROOTINO)
*--cp = '?';
memcpy(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
memcpy(namebuf, cp, (size_t) (&namebuf[MAXPATHLEN] - cp));
}
void
catch(int n)
{
if (!doinglevel2)
ckfini(0);
ckfini(0);
exit(12);
}
/*
* When preening, allow a single quit to signal
* a special exit after filesystem checks complete
@ -516,9 +246,8 @@ catchquit(int n)
{
printf("returning to single-user after filesystem check\n");
returntosingle = 1;
(void)signal(SIGQUIT, SIG_DFL);
(void) signal(SIGQUIT, SIG_DFL);
}
/*
* Ignore a single quit signal; wait and flush just in case.
* Used by child processes in preen.
@ -528,10 +257,9 @@ voidquit(int n)
{
sleep(1);
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGQUIT, SIG_DFL);
(void) signal(SIGQUIT, SIG_IGN);
(void) signal(SIGQUIT, SIG_DFL);
}
/*
* determine whether an inode should be fixed.
*/
@ -541,7 +269,7 @@ dofix(struct inodesc * idesc, char *msg)
switch (idesc->id_fix) {
case DONTKNOW:
case DONTKNOW:
if (idesc->id_type == DATA)
direrror(idesc->id_number, msg);
else
@ -566,7 +294,7 @@ dofix(struct inodesc * idesc, char *msg)
return (0);
default:
errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
err(8, "UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
}
/* NOTREACHED */
}

View File

@ -1,4 +1,39 @@
/* $NetBSD: vars.c,v 1.6 2003/01/24 21:55:10 fvdl Exp $ */
/* $NetBSD: vars.c,v 1.7 2003/03/28 08:09:55 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
@ -9,60 +44,47 @@
#include "fsck.h"
/* variables previously of file scope (from fsck.h) */
struct bufarea bufhead; /* head of list of other blks in filesys */
struct bufarea sblk; /* file system superblock */
struct bufarea iblk; /* ifile on-disk inode block */
struct bufarea *pdirbp; /* current directory contents */
struct bufarea *pbp; /* current inode block */
int iinooff; /* ifile inode offset in block of inodes */
struct dups *duplist; /* head of dup list */
struct dups *muldup; /* end of unique duplicate dup block numbers */
struct dups *duplist; /* head of dup list */
struct dups *muldup; /* end of unique duplicate dup block numbers */
struct zlncnt *zlnhead; /* head of zero link count list */
struct zlncnt *zlnhead; /* head of zero link count list */
struct lfs *fs;
daddr_t idaddr; /* inode block containing ifile inode */
long numdirs, listmax, inplast;
daddr_t idaddr; /* inode block containing ifile inode */
long numdirs, listmax, inplast;
long dev_bsize; /* computed value of DEV_BSIZE */
long secsize; /* actual disk sector size */
char nflag; /* assume a no response */
char yflag; /* assume a yes response */
int bflag; /* location of alternate super block */
int debug; /* output debugging info */
#ifdef DEBUG_IFILE
int debug_ifile; /* cat the ifile and exit */
#endif
int cvtlevel; /* convert to newer file system format */
int doinglevel1; /* converting to new cylinder group format */
int doinglevel2; /* converting to new inode format */
int exitonfail;
int newinofmt; /* filesystem has new inode format */
int preen; /* just fix normal inconsistencies */
char havesb; /* superblock has been read */
char skipclean; /* skip clean file systems if preening */
int fsmodified; /* 1 => write done to file system */
int fsreadfd; /* file descriptor for reading file system */
int fswritefd; /* file descriptor for writing file system */
int rerun; /* rerun fsck. Only used in non-preen mode */
long dev_bsize; /* computed value of DEV_BSIZE */
long secsize; /* actual disk sector size */
char nflag; /* assume a no response */
char yflag; /* assume a yes response */
int bflag; /* location of alternate super block */
int debug; /* output debugging info */
int exitonfail;
int preen; /* just fix normal inconsistencies */
char havesb; /* superblock has been read */
char skipclean; /* skip clean file systems if preening */
int fsmodified; /* 1 => write done to file system */
int fsreadfd; /* file descriptor for reading file system */
int rerun; /* rerun fsck. Only used in non-preen mode */
daddr_t maxfsblock; /* number of blocks in the file system */
daddr_t maxfsblock; /* number of blocks in the file system */
#ifndef VERBOSE_BLOCKMAP
char *blockmap; /* ptr to primary blk allocation map */
char *blockmap; /* ptr to primary blk allocation map */
#else
ino_t *blockmap;
ino_t *blockmap;
#endif
ino_t maxino; /* number of inodes in file system */
ino_t lastino; /* last inode in use */
char *statemap; /* ptr to inode state table */
char *typemap; /* ptr to inode type table */
int16_t *lncntp; /* ptr to link count table */
ino_t maxino; /* number of inodes in file system */
ino_t lastino; /* last inode in use */
char *statemap; /* ptr to inode state table */
char *typemap; /* ptr to inode type table */
int16_t *lncntp; /* ptr to link count table */
ino_t lfdir; /* lost & found directory inode number */
char *lfname; /* lost & found directory name */
int lfmode; /* lost & found directory creation mode */
ino_t lfdir; /* lost & found directory inode number */
char *lfname; /* lost & found directory name */
int lfmode; /* lost & found directory creation mode */
daddr_t n_blks; /* number of blocks in use */
ino_t n_files; /* number of files in use */
daddr_t n_blks; /* number of blocks in use */
ino_t n_files; /* number of files in use */
struct dinode zino;
struct dinode zino;

194
sbin/fsck_lfs/vnode.c Normal file
View File

@ -0,0 +1,194 @@
/* $NetBSD: vnode.c,v 1.1 2003/03/28 08:09:55 perseant Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <sys/queue.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#define vnode uvnode
#include <ufs/lfs/lfs.h>
#undef vnode
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bufcache.h"
#include "vnode.h"
struct uvnodelst vnodelist;
struct uvnodelst getvnodelist;
struct vgrlst vgrlist;
int nvnodes;
/* Convert between inode pointers and vnode pointers. */
#ifndef VTOI
#define VTOI(vp) ((struct inode *)(vp)->v_data)
#endif
/*
* Raw device uvnode ops
*/
int
raw_vop_strategy(struct ubuf * bp)
{
if (bp->b_flags & B_READ) {
return pread(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
dbtob(bp->b_blkno));
} else {
return pwrite(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
dbtob(bp->b_blkno));
}
}
int
raw_vop_bwrite(struct ubuf * bp)
{
bp->b_flags &= ~(B_READ | B_DELWRI | B_DONE | B_ERROR);
raw_vop_strategy(bp);
brelse(bp);
return 0;
}
int
raw_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp)
{
*daddrp = lbn;
return 0;
}
/* Register a fs-specific vget function */
void
register_vget(void *fs, struct uvnode *func(void *, ino_t))
{
struct vget_reg *vgr;
vgr = (struct vget_reg *)malloc(sizeof(*vgr));
vgr->vgr_fs = fs;
vgr->vgr_func = func;
LIST_INSERT_HEAD(&vgrlist, vgr, vgr_list);
}
static struct uvnode *
VFS_VGET(void *fs, ino_t ino)
{
struct vget_reg *vgr;
LIST_FOREACH(vgr, &vgrlist, vgr_list) {
if (vgr->vgr_fs == fs)
return vgr->vgr_func(fs, ino);
}
return NULL;
}
void
vnode_destroy(struct uvnode *tossvp)
{
struct ubuf *bp;
--nvnodes;
LIST_REMOVE(tossvp, v_getvnodes);
LIST_REMOVE(tossvp, v_mntvnodes);
LIST_FOREACH(bp, &tossvp->v_dirtyblkhd, b_vnbufs) {
bremfree(bp);
buf_destroy(bp);
}
LIST_FOREACH(bp, &tossvp->v_cleanblkhd, b_vnbufs) {
bremfree(bp);
buf_destroy(bp);
}
free(VTOI(tossvp)->inode_ext.lfs);
memset(VTOI(tossvp), 0, sizeof(struct inode));
free(tossvp->v_data);
memset(tossvp, 0, sizeof(*tossvp));
free(tossvp);
}
/*
* Find a vnode in the cache; if not present, get it from the
* filesystem-specific vget routine.
*/
struct uvnode *
vget(void *fs, ino_t ino)
{
struct uvnode *vp, *tossvp;
/* Look in the uvnode cache */
tossvp = NULL;
LIST_FOREACH(vp, &getvnodelist, v_getvnodes) {
if (vp->v_fs != fs)
continue;
if (VTOI(vp)->i_number == ino) {
LIST_REMOVE(vp, v_getvnodes);
LIST_INSERT_HEAD(&getvnodelist, vp, v_getvnodes);
break;
}
if (LIST_EMPTY(&vp->v_dirtyblkhd) &&
vp->v_usecount == 0 &&
!(vp->v_flag & VDIROP))
tossvp = vp;
}
/* Don't let vnode list grow arbitrarily */
if (nvnodes > VNODE_CACHE_SIZE && tossvp) {
vnode_destroy(tossvp);
}
if (vp)
return vp;
return VFS_VGET(fs, ino);
}
void
vfs_init(void)
{
nvnodes = 0;
LIST_INIT(&vnodelist);
LIST_INIT(&getvnodelist);
LIST_INIT(&vgrlist);
}

81
sbin/fsck_lfs/vnode.h Normal file
View File

@ -0,0 +1,81 @@
/* $NetBSD: vnode.h,v 1.1 2003/03/28 08:09:55 perseant Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Konrad E. Schroder <perseant@hhhh.org>.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#define VNODE_CACHE_SIZE 1000
LIST_HEAD(ubuflists, ubuf);
LIST_HEAD(uvnodelst, uvnode);
LIST_HEAD(vgrlst, vget_reg);
struct uvnode {
int v_fd;
int (*v_strategy_op) (struct ubuf *);
int (*v_bwrite_op) (struct ubuf *);
int (*v_bmap_op) (struct uvnode *, daddr_t, daddr_t *);
#define VDIROP 0x1000 /* vnode is involved in a directory op */
#define VDIRTY 0x8000 /* vnode is dirty */
u_int32_t v_flag;
void *v_fs;
void *v_data;
#undef v_usecount
int v_usecount;
struct ubuflists v_cleanblkhd; /* clean blocklist head */
struct ubuflists v_dirtyblkhd; /* dirty blocklist head */
LIST_ENTRY(uvnode) v_mntvnodes;
LIST_ENTRY(uvnode) v_getvnodes;
};
struct vget_reg {
void *vgr_fs;
struct uvnode *(*vgr_func) (void *, ino_t);
LIST_ENTRY(vget_reg) vgr_list;
};
#define VOP_STRATEGY(bp) ((bp)->b_vp->v_strategy_op(bp))
#define VOP_BWRITE(bp) ((bp)->b_vp->v_bwrite_op(bp))
#define VOP_BMAP(vp, lbn, daddrp) ((vp)->v_bmap_op((vp), (lbn), (daddrp)))
extern int fsdirty;
extern struct uvnodelst vnodelist;
int raw_vop_strategy(struct ubuf *);
int raw_vop_bwrite(struct ubuf *);
int raw_vop_bmap(struct uvnode *, daddr_t, daddr_t *);
void vnode_destroy(struct uvnode *);
struct uvnode *vget(void *, ino_t);
void register_vget(void *, struct uvnode *(void *, ino_t));
void vfs_init(void);