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