summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorperseant <perseant@NetBSD.org>2006-04-05 20:29:40 +0000
committerperseant <perseant@NetBSD.org>2006-04-05 20:29:40 +0000
commit2c3f7b46baa3aa6207c6caa9490f84ab3fbbf998 (patch)
tree21a48f83f5079acb59821f4c23d9010f991e3592 /libexec
parent2ab52a9ec86b501e3418cf907c34fdcd56aaa914 (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.c49
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);