Date: Wed, 23 Feb 2000 22:55:06 -0800 From: Alfred Perlstein <bright@wintelcom.net> To: Matthew Dillon <dillon@apollo.backplane.com> Cc: Ian Dowse <iedowse@maths.tcd.ie>, mckusick@freebsd.org, current@freebsd.org Subject: Re: ffs_blkfree: freeing free block (was Re: Panic (pmap)) Message-ID: <20000223225505.A21720@fw.wintelcom.net> In-Reply-To: <200002240556.VAA34592@apollo.backplane.com>; from dillon@apollo.backplane.com on Wed, Feb 23, 2000 at 09:56:35PM -0800 References: <200002232235.aa22335@salmon.maths.tcd.ie> <200002240227.SAA33299@apollo.backplane.com> <200002240556.VAA34592@apollo.backplane.com>
next in thread | previous in thread | raw e-mail | index | archive | help
Er, shouldn't you guys let Kirk know, not only is he "MAINTAINER", but
pretty much mostly "CREATOR" :)
Kirk, another issue with running out of space in FFS seems to have
come up:
* Matthew Dillon <dillon@apollo.backplane.com> [000223 18:57] wrote:
> :Ian Dowse <iedowse@maths.tcd.ie> wrote:
> :I think I've found it. Here's an easy way to repeat the problem to
> :start with:
> :
> : mount_mfs -T fd1440 none /mnt
> : cd /mnt
> : dd if=/dev/zero bs=4k of=test seek=1036 count=1
> : dd if=/dev/zero bs=4k of=test1 count=1
> : dd if=/dev/zero bs=4k of=test2
> : rm test1
> : dd if=/dev/zero bs=4k of=test seek=8000 count=1
> : echo > test
> :
> :It looks as if the problem is in ffs_balloc(), and occurs as follows:
> : - ffs_balloc() is asked to allocate a doubly indirect block.
> : - The first-level indirection block already exists
> : - The second-level indirection block does not exist, but is
> : successfully allocated.
> : - This block is linked into the first-level indirection block by
> : the line:
> :
> : bap[indirs[i - 1].in_off] = nb;
> :
> : - Allocation of the data block fails.
> : - All allocated blocks are then released, but there is still
> : a link in the first-level indirection block to what is
> : now a free block.
> :
> :The fix should be relatively straightforward - either the code should
> :avoid linking new indirection blocks until all allocations succeed,
> :or it should back out the changes on failure.
> :
> :Ian
>
> Great detective work! The 'allocib' variable is used to unwind the
> 'first' new indirect block allocation, but it is *only* initialized
> for the Level 0 block. So the unwinding only works when the Level 0
> indirect block had to be allocated. When the Level 0 indirect block
> is valid and a deeper level indirect block had to be allocated,
> allocib is not initialized and the association is not unwound even
> though the deeper indirect block is freed when the data block allocation
> fails.
>
> Unfortunately, we can't simply initialize 'allocib' here, because it
> would point into the middle of a buffer. The fix is thus not entirely
> trivial.
>
> This is what I think we need to do, but THIS PATCH IS NOT TESTED AND
> COULD BE COMPLETELY WRONG. Any filesystem gurus out there who can look
> at this and tell me if it's correct?
[patch snipped, Matt just re-issued a fixed version]
* Matthew Dillon <dillon@apollo.backplane.com> [000223 22:26] wrote:
>
> Oops, here's a new version of my patch. This one survives Ian's test
> script. I was improperly blowing away an 'error' field.
>
> -Matt
>
> Index: ffs_balloc.c
> ===================================================================
> RCS file: /home/ncvs/src/sys/ufs/ffs/ffs_balloc.c,v
> retrieving revision 1.25
> diff -u -r1.25 ffs_balloc.c
> --- ffs_balloc.c 2000/01/11 08:27:00 1.25
> +++ ffs_balloc.c 2000/02/24 05:44:59
> @@ -77,6 +77,7 @@
> ufs_daddr_t newb, *bap, pref;
> int deallocated, osize, nsize, num, i, error;
> ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
> + int unwindidx = -1;
> struct proc *p = curproc; /* XXX */
>
> vp = ap->a_vp;
> @@ -272,6 +273,8 @@
> }
> }
> bap[indirs[i - 1].in_off] = nb;
> + if (allocib == NULL && unwindidx < 0)
> + unwindidx = i - 1;
> /*
> * If required, write synchronously, otherwise use
> * delayed write.
> @@ -349,8 +352,28 @@
> 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", error);
> + brelse(bp);
> + } else {
> + bap = (ufs_daddr_t *)bp->b_data;
> + bap[indirs[unwindidx].in_off] = 0;
> + if (flags & B_SYNC) {
> + bwrite(bp);
> + } else {
> + if (bp->b_bufsize == fs->fs_bsize)
> + bp->b_flags |= B_CLUSTEROK;
> + bdwrite(bp);
> + }
> + }
> + }
> if (deallocated) {
> #ifdef QUOTA
> /*
>
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20000223225505.A21720>
