summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2000-04-20 14:41:58 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2000-04-20 14:41:58 +0000
commit098dc6e2a80f813d39e1a527414b322d88bd8ec0 (patch)
treeabfebc2d7be2821b7ecf7104bf62e9867863abd2 /sys
parentba6b056376adedc82f4ac0f41b5eed2fa3f30c75 (diff)
Fix a problem that occurs when the filesystem fills up.
When the filesystem is able to allocate an indirect block but not the data block, it incorrectly unwinds the indirect block leaving a dangling pointer to a free block. This is said to fix the "freeing free block" panics people were seeing. From FreeBSD.
Diffstat (limited to 'sys')
-rw-r--r--sys/ufs/ffs/ffs_balloc.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c
index a3cea28c3e1..76f91db1644 100644
--- a/sys/ufs/ffs/ffs_balloc.c
+++ b/sys/ufs/ffs/ffs_balloc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_balloc.c,v 1.9 1999/05/27 20:36:21 art Exp $ */
+/* $OpenBSD: ffs_balloc.c,v 1.10 2000/04/20 14:41:57 art Exp $ */
/* $NetBSD: ffs_balloc.c,v 1.3 1996/02/09 22:22:21 christos Exp $ */
/*
@@ -88,6 +88,7 @@ ffs_balloc(v)
daddr_t newb, *bap, pref;
int deallocated, osize, nsize, num, i, error;
daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR+1];
+ int unwindidx = -1;
vp = ap->a_vp;
ip = VTOI(vp);
@@ -292,6 +293,8 @@ ffs_balloc(v)
}
}
bap[indirs[i - 1].in_off] = nb;
+ if (allocib == NULL && unwindidx < 0)
+ unwindidx = i - 1;
/*
* If required, write synchronously, otherwise use
* delayed write.
@@ -358,8 +361,23 @@ fail:
ffs_blkfree(ip, *blkp, fs->fs_bsize);
deallocated += fs->fs_bsize;
}
- if (allocib != NULL)
+ if (allocib != NULL) {
*allocib = 0;
+ } else if (unwindidx >= 0) {
+ int r;
+
+ r = bread(vp, indirs[unwindidx].in_lbn,
+ (int)fs->fs_bsize, NOCRED, &bp);
+ if (r)
+ panic("Could not unwind indirect block, error %d", r);
+ bap = (ufs_daddr_t *)bp->b_data;
+ bap[indirs[unwindidx].in_off] = 0;
+ if (flags & B_SYNC) {
+ bwrite(bp);
+ } else {
+ bdwrite(bp);
+ }
+ }
if (deallocated) {
#ifdef QUOTA
/*
@@ -370,6 +388,6 @@ fail:
ip->i_ffs_blocks -= btodb(deallocated);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
}
- return (error);
+ return (error);
}