diff options
| author | perseant <perseant@NetBSD.org> | 2006-04-05 20:29:40 +0000 |
|---|---|---|
| committer | perseant <perseant@NetBSD.org> | 2006-04-05 20:29:40 +0000 |
| commit | 2c3f7b46baa3aa6207c6caa9490f84ab3fbbf998 (patch) | |
| tree | 21a48f83f5079acb59821f4c23d9010f991e3592 /libexec | |
| parent | 2ab52a9ec86b501e3418cf907c34fdcd56aaa914 (diff) | |
Handle the case of inode blocks misidentified by the segment headers
correctly, a problem reported by Kurt Schreiner; as well as similar
error cases (realloc returning NULL or no cleanable segments found).
Diffstat (limited to 'libexec')
| -rw-r--r-- | libexec/lfs_cleanerd/lfs_cleanerd.c | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/libexec/lfs_cleanerd/lfs_cleanerd.c b/libexec/lfs_cleanerd/lfs_cleanerd.c index 49e4e538ccd..4d42fb650cd 100644 --- a/libexec/lfs_cleanerd/lfs_cleanerd.c +++ b/libexec/lfs_cleanerd/lfs_cleanerd.c @@ -1,4 +1,4 @@ -/* $NetBSD: lfs_cleanerd.c,v 1.2 2006/04/01 23:48:56 christos Exp $ */ +/* $NetBSD: lfs_cleanerd.c,v 1.3 2006/04/05 20:29:40 perseant Exp $ */ /*- * Copyright (c) 2005 The NetBSD Foundation, Inc. @@ -354,7 +354,7 @@ parse_pseg(struct clfs *fs, daddr_t daddr, BLOCK_INFO **bipp, int *bic) { SEGSUM *ssp; IFILE *ifp; - BLOCK_INFO *bip; + BLOCK_INFO *bip, *nbip; int32_t *iaddrp, idaddr, odaddr; FINFO *fip; struct ubuf *ifbp; @@ -408,6 +408,17 @@ parse_pseg(struct clfs *fs, daddr_t daddr, BLOCK_INFO **bipp, int *bic) fic = inoc = 0; while (fic < ssp->ss_nfinfo || inoc < ssp->ss_ninos) { /* + * We must have either a file block or an inode block. + * If we don't have either one, it's an error. + */ + if (fic >= ssp->ss_nfinfo && *iaddrp != daddr) { + syslog(LOG_WARNING, "%s: bad pseg at %x (seg %d)", + fs->lfs_fsmnt, odaddr, dtosn(fs, odaddr)); + *bipp = bip; + return 0x0; + } + + /* * Note each inode from the inode blocks */ if (inoc < ssp->ss_ninos && *iaddrp == daddr) { @@ -433,8 +444,15 @@ parse_pseg(struct clfs *fs, daddr_t daddr, BLOCK_INFO **bipp, int *bic) * A current inode. Add it. */ ++*bic; - bip = (BLOCK_INFO *)realloc(bip, *bic * - sizeof(*bip)); + nbip = (BLOCK_INFO *)realloc(bip, *bic * + sizeof(*bip)); + if (nbip) + bip = nbip; + else { + --*bic; + *bipp = bip; + return 0x0; + } bip[*bic - 1].bi_inode = dip[i].di_inumber; bip[*bic - 1].bi_lbn = LFS_UNUSED_LBN; bip[*bic - 1].bi_daddr = daddr; @@ -506,8 +524,15 @@ parse_pseg(struct clfs *fs, daddr_t daddr, BLOCK_INFO **bipp, int *bic) } /* Add all the blocks from the finfos (current or not) */ - bip = (BLOCK_INFO *)realloc(bip, (*bic + fip->fi_nblocks) * - sizeof(*bip)); + nbip = (BLOCK_INFO *)realloc(bip, (*bic + fip->fi_nblocks) * + sizeof(*bip)); + if (nbip) + bip = nbip; + else { + *bipp = bip; + return 0x0; + } + for (i = 0; i < fip->fi_nblocks; i++) { bip[*bic + i].bi_inode = fip->fi_ino; bip[*bic + i].bi_lbn = fip->fi_blocks[i]; @@ -745,6 +770,9 @@ toss_old_blocks(struct clfs *fs, BLOCK_INFO **bipp, int *bic) int blkcnt; } */ lim; + if (bic == 0 || bip == NULL) + return; + /* * Kludge: Store the disk address in segcreate so we know which * ones to toss. @@ -1029,6 +1057,8 @@ clean_fs(struct clfs *fs, CLEANERINFO *cip) /* If there is nothing to do, try again later. */ if (bic == 0) { + dlog("%s: no blocks to clean in %d cleanable segments", + fs->lfs_fsmnt, (int)ngood); fd_release_all(fs->clfs_devvp); return 0; } @@ -1086,9 +1116,10 @@ clean_fs(struct clfs *fs, CLEANERINFO *cip) PRId64 " supporting Ifile = %" PRId64 " bytes to clean %d segs (%" PRId64 "%% recovery)", fs->lfs_fsmnt, (int64_t)nb, (int64_t)(extra - if_extra), - (int64_t)if_extra, (int64_t)(nb + extra), - ngood, (int64_t)(100 - (100 * (nb + extra)) / - (ngood * fs->lfs_ssize))); + (int64_t)if_extra, (int64_t)(nb + extra), ngood, + (ngood ? (int64_t)(100 - (100 * (nb + extra)) / + (ngood * fs->lfs_ssize)) : + (int64_t)0)); if (nb + extra >= ngood * fs->lfs_ssize) syslog(LOG_WARNING, "%s: cleaner not making forward progress", fs->lfs_fsmnt); |
