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:
parent
3f7016035a
commit
ba10361ab2
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 *);
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ∅
|
||||
}
|
||||
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--;
|
||||
|
|
|
@ -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 = #
|
||||
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);
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
Loading…
Reference in New Issue