Home | History | Annotate | Line # | Download | only in fsck_lfs
pass0.c revision 1.4
      1 /*	$NetBSD: pass0.c,v 1.4 2000/05/16 04:55:59 perseant Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998 Konrad E. Schroder.
      5  * Copyright (c) 1980, 1986, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #include <sys/param.h>
     38 #include <sys/time.h>
     39 #include <ufs/ufs/dinode.h>
     40 #include <ufs/ufs/dir.h>
     41 #include <sys/mount.h>
     42 #include <ufs/lfs/lfs.h>
     43 #include <ufs/lfs/lfs_extern.h>
     44 
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <string.h>
     48 
     49 #include "fsck.h"
     50 #include "extern.h"
     51 #include "fsutil.h"
     52 
     53 /* Flags for check_segment */
     54 #define CKSEG_VERBOSE     1
     55 #define CKSEG_IGNORECLEAN 2
     56 
     57 extern int fake_cleanseg;
     58 void check_segment(int, int, daddr_t, struct lfs *, int,
     59 		   int (*)(struct lfs *, SEGSUM *, daddr_t));
     60 
     61 /*
     62  * Pass 0.  Check the LFS partial segments for valid checksums, correcting
     63  * if necessary.  Also check for valid offsets for inode and finfo blocks.
     64  */
     65 /* XXX more could be done here---consistency between inode-held blocks and
     66    finfo blocks, for one thing. */
     67 
     68 #define dbshift (sblock.lfs_bshift - sblock.lfs_fsbtodb)
     69 
     70 void pass0()
     71 {
     72     daddr_t daddr;
     73     IFILE *ifp;
     74     struct bufarea *bp;
     75     ino_t ino, lastino, nextino;
     76 
     77     /*
     78      * Check the inode free list for inuse inodes.
     79      *
     80      * XXX should also check for cycles or breaks in the list, and be able
     81      * to repair them.
     82      */
     83     lastino = 0;
     84     ino=sblock.lfs_free;
     85     while(ino) {
     86 	    ifp = lfs_ientry(ino,&bp);
     87 	    nextino = ifp->if_nextfree;
     88 	    daddr = ifp->if_daddr;
     89 	    bp->b_flags &= ~B_INUSE;
     90 	    if(daddr) {
     91 		    printf("! Ino %d with daddr 0x%x is on the free list!\n",
     92 			   ino, daddr);
     93 		    if(preen || reply("FIX")==1) {
     94 			    if(lastino == 0) {
     95 				    sblock.lfs_free = nextino;
     96 				    sbdirty();
     97 			    } else {
     98 				    ifp = lfs_ientry(lastino,&bp);
     99 				    ifp->if_nextfree = nextino;
    100 				    ++bp->b_dirty;
    101 				    bp->b_flags &= ~B_INUSE;
    102 			    }
    103 			    ino = nextino;
    104 			    continue;
    105 		    }
    106 	    }
    107 	    lastino = ino;
    108 	    ino = nextino;
    109     }
    110 }
    111 
    112 static void dump_segsum(SEGSUM *sump, daddr_t addr)
    113 {
    114     printf("Dump partial summary block 0x%x\n",addr);
    115     printf("\tsumsum:  %x (%d)\n",sump->ss_sumsum,sump->ss_sumsum);
    116     printf("\tdatasum: %x (%d)\n",sump->ss_datasum,sump->ss_datasum);
    117     printf("\tnext:    %x (%d)\n",sump->ss_next,sump->ss_next);
    118     printf("\tcreate:  %x (%d)\n",sump->ss_create,sump->ss_create);
    119     printf("\tnfinfo:  %x (%d)\n",sump->ss_nfinfo,sump->ss_nfinfo);
    120     printf("\tninos:   %x (%d)\n",sump->ss_ninos,sump->ss_ninos);
    121     printf("\tflags:   %c%c\n",
    122            sump->ss_flags&SS_DIROP?'d':'-',
    123            sump->ss_flags&SS_CONT?'c':'-');
    124 }
    125 
    126 void check_segment(int fd, int segnum, daddr_t addr, struct lfs *fs, int flags, int (*func)(struct lfs *, SEGSUM *, daddr_t))
    127 {
    128     struct lfs *sbp;
    129     SEGSUM *sump=NULL;
    130     SEGUSE *su;
    131     struct bufarea *bp = NULL;
    132     int psegnum=0, ninos=0;
    133     off_t sum_offset, db_ssize;
    134     int bc, su_flags, su_nsums, su_ninos;
    135 
    136     db_ssize = sblock.lfs_ssize << sblock.lfs_fsbtodb;
    137 
    138     su = lfs_gseguse(segnum, &bp);
    139     su_flags = su->su_flags;
    140     su_nsums = su->su_nsums;
    141     su_ninos = su->su_ninos;
    142     bp->b_flags &= ~B_INUSE;
    143 
    144     /* printf("Seg at 0x%x\n",addr); */
    145     if((flags & CKSEG_VERBOSE) && segnum*db_ssize + fs->lfs_sboffs[0] != addr)
    146         pwarn("WARNING: segment begins at 0x%qx, should be 0x%qx\n",
    147               (long long unsigned)addr,
    148 			  (long long unsigned)(segnum*db_ssize + fs->lfs_sboffs[0]));
    149     sum_offset = ((off_t)addr << dbshift);
    150 
    151     /* If this segment should have a superblock, look for one */
    152     if(su_flags & SEGUSE_SUPERBLOCK) {
    153         bp = getddblk(sum_offset >> dbshift, LFS_SBPAD);
    154         sum_offset += LFS_SBPAD;
    155 
    156         /* check for a superblock -- XXX this is crude */
    157         sbp = (struct lfs *)(bp->b_un.b_buf);
    158         if(sbp->lfs_magic==LFS_MAGIC) {
    159 #if 0
    160             if(sblock.lfs_tstamp == sbp->lfs_tstamp
    161                && memcmp(sbp,&sblock,sizeof(*sbp))
    162 	       && (flags & CKSEG_VERBOSE))
    163                 pwarn("SUPERBLOCK MISMATCH SEGMENT %d\n", segnum);
    164 #endif
    165         } else {
    166 		if(flags & CKSEG_VERBOSE)
    167 			pwarn("SEGMENT %d SUPERBLOCK INVALID\n",segnum);
    168 		/* XXX allow to fix */
    169         }
    170         bp->b_flags &= ~B_INUSE;
    171     }
    172     /* XXX need to also check whether this one *should* be dirty */
    173     if((flags & CKSEG_IGNORECLEAN) && (su_flags & SEGUSE_DIRTY)==0)
    174         return;
    175 
    176     while(1) {
    177         if(su_nsums <= psegnum)
    178             break;
    179         bp = getddblk(sum_offset >> dbshift, LFS_SUMMARY_SIZE);
    180         sump = (SEGSUM *)(bp->b_un.b_buf);
    181 	if (sump->ss_magic != SS_MAGIC) {
    182 		if(flags & CKSEG_VERBOSE)
    183 			printf("PARTIAL SEGMENT %d SEGMENT %d BAD PARTIAL SEGMENT MAGIC (0x%x should be 0x%x)\n",
    184 			       psegnum, segnum, sump->ss_magic, SS_MAGIC);
    185                 bp->b_flags &= ~B_INUSE;
    186 		break;
    187 	}
    188         if(sump->ss_sumsum != cksum(&sump->ss_datasum, LFS_SUMMARY_SIZE - sizeof(sump->ss_sumsum))) {
    189 		if(flags & CKSEG_VERBOSE) {
    190 			/* Corrupt partial segment */
    191 			pwarn("CORRUPT PARTIAL SEGMENT %d/%d OF SEGMENT %d AT BLK 0x%qx",
    192 			      psegnum, su_nsums, segnum,
    193 				  (unsigned long long)sum_offset>>dbshift);
    194 			if(db_ssize < (sum_offset>>dbshift) - addr)
    195 				pwarn(" (+0x%qx/0x%qx)",
    196 				      (unsigned long long)(((sum_offset>>dbshift) - addr) -
    197 										   db_ssize),
    198 				      (unsigned long long)db_ssize);
    199 			else
    200 				pwarn(" (-0x%qx/0x%qx)",
    201 				      (unsigned long long)(db_ssize -
    202 										   ((sum_offset>>dbshift) - addr)),
    203 				      (unsigned long long)db_ssize);
    204 			pwarn("\n");
    205 			dump_segsum(sump,sum_offset>>dbshift);
    206 		}
    207 		/* XXX fix it maybe */
    208 		bp->b_flags &= ~B_INUSE;
    209 		break; /* XXX could be throwing away data, but if this segsum
    210 			* is invalid, how to know where the next summary
    211 			* begins? */
    212         }
    213 	/*
    214 	 * Good partial segment
    215 	 */
    216 	bc = (*func)(&sblock, sump, (daddr_t)(sum_offset>>dbshift));
    217 	if(bc) {
    218                 sum_offset += LFS_SUMMARY_SIZE + bc;
    219                 ninos += (sump->ss_ninos + INOPB(&sblock)-1)/INOPB(&sblock);
    220                 psegnum++;
    221 	} else {
    222                 bp->b_flags &= ~B_INUSE;
    223                 break;
    224 	}
    225         bp->b_flags &= ~B_INUSE;
    226     }
    227     if(flags & CKSEG_VERBOSE) {
    228 	    if(ninos != su_ninos)
    229 		    pwarn("SEGMENT %d has %d ninos, not %d\n",
    230 			  segnum, ninos, su_ninos);
    231 	    if(psegnum != su_nsums)
    232 		    pwarn("SEGMENT %d has %d summaries, not %d\n",
    233 			  segnum, psegnum, su_nsums);
    234     }
    235 
    236     return;
    237 }
    238 
    239 int check_summary(struct lfs *fs, SEGSUM *sp, daddr_t pseg_addr)
    240 {
    241     FINFO *fp;
    242     int bc; /* Bytes in partial segment */
    243     int nblocks;
    244     daddr_t seg_addr, *dp, *idp, daddr;
    245     struct bufarea *bp;
    246     int i, j, k, datac, len;
    247     long sn;
    248     u_long *datap;
    249     u_int32_t ccksum;
    250 
    251     sn = datosn(fs, pseg_addr);
    252     seg_addr = sntoda(fs, sn);
    253 
    254     /* printf("Pseg at 0x%x, %d inos, %d finfos\n",addr>>dbshift,sp->ss_ninos,sp->ss_nfinfo); */
    255     /* We've already checked the sumsum, just do the data bounds and sum */
    256 
    257     /* 1. Count the blocks. */
    258     nblocks = ((sp->ss_ninos + INOPB(fs) - 1) / INOPB(fs));
    259     bc = nblocks << fs->lfs_bshift;
    260 
    261     fp = (FINFO *)(sp + 1);
    262     for(i=0; i<sp->ss_nfinfo; i++) {
    263 	    nblocks += fp->fi_nblocks;
    264 	    bc +=  fp->fi_lastlength + ((fp->fi_nblocks-1) << fs->lfs_bshift);
    265 	    fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks);
    266     }
    267     datap = (u_long *)malloc(nblocks * sizeof(*datap));
    268     datac = 0;
    269 
    270     dp = (daddr_t *)sp;
    271     dp += LFS_SUMMARY_SIZE / sizeof(daddr_t);
    272     dp--;
    273 
    274     idp = dp;
    275     daddr = pseg_addr + (LFS_SUMMARY_SIZE/dev_bsize);
    276     fp = (FINFO *)(sp + 1);
    277     for(i=0, j=0; i<sp->ss_nfinfo || j<howmany(sp->ss_ninos,INOPB(fs)); i++) {
    278 	    /* printf("*idp=%x, daddr=%x\n", *idp, daddr); */
    279 	    if(i >= sp->ss_nfinfo && *idp != daddr) {
    280 		    pwarn("Not enough inode blocks in pseg at 0x%x: found %d, wanted %d\n",
    281 			  pseg_addr, j, howmany(sp->ss_ninos,INOPB(fs)));
    282 		    pwarn("*idp=%x, daddr=%x\n", *idp, daddr);
    283 		    break;
    284 	    }
    285 	    while(j < howmany(sp->ss_ninos,INOPB(fs)) && *idp == daddr) {
    286 		    bp = getddblk(daddr, (1<<fs->lfs_bshift));
    287 		    datap[datac++] = ((u_long *)(bp->b_un.b_buf))[0];
    288 		    bp->b_flags &= ~B_INUSE;
    289 
    290 		    ++j;
    291 		    daddr += (1<<fs->lfs_bshift)/dev_bsize;
    292 		    --idp;
    293 	    }
    294 	    if(i < sp->ss_nfinfo) {
    295 		    for(k=0; k<fp->fi_nblocks; k++) {
    296 			    len = (k==fp->fi_nblocks - 1 ? fp->fi_lastlength
    297 				   : (1<<fs->lfs_bshift));
    298 			    bp = getddblk(daddr, len);
    299 			    datap[datac++] = ((u_long *)(bp->b_un.b_buf))[0];
    300 			    bp->b_flags &= ~B_INUSE;
    301 			    daddr += len/dev_bsize;
    302 		    }
    303 		    fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks);
    304 	    }
    305     }
    306 
    307     if(datac != nblocks) {
    308 	    pwarn("Partial segment at 0x%x expected %d blocks counted %d\n",
    309 		  pseg_addr, nblocks, datac);
    310     }
    311 
    312     ccksum = cksum(datap, nblocks * sizeof(u_long));
    313     /* Check the data checksum */
    314     if (ccksum != sp->ss_datasum) {
    315 	    pwarn("Partial segment at 0x%x data checksum mismatch: got 0x%x, expected 0x%x\n",
    316 		  pseg_addr, sp->ss_datasum, ccksum);
    317 	    /* return 0; */
    318     }
    319 
    320     return bc;
    321 }
    322