diff options
author | mckusick <mckusick@FreeBSD.org> | 2000-01-11 08:27:00 +0000 |
---|---|---|
committer | mckusick <mckusick@FreeBSD.org> | 2000-01-11 08:27:00 +0000 |
commit | 2ba5b4600717eb20d7ab4e58602e9aa3842eabf2 (patch) | |
tree | 879e9bc8facd7df06d1f694f028a7b634910a4ed /sys | |
parent | e935a650e228be8c7b681a89e3cd11f73af461d1 (diff) | |
download | FreeBSD-src-2ba5b4600717eb20d7ab4e58602e9aa3842eabf2.zip FreeBSD-src-2ba5b4600717eb20d7ab4e58602e9aa3842eabf2.tar.gz |
The only known cause of this panic is running out of disk space.
The problem occurs when an indirect block and a data block are
being allocated at the same time. For example when the 13th block
of the file is written, the filesystem needs to allocate the first
indirect block and a data block. If the indirect block allocation
succeeds, but the data block allocation fails, the error code
dellocates the indirect block as it has nothing at which to point.
Unfortunately, it does not deallocate the indirect block's associated
dependencies which then fail when they find the block unexpectedly
gone (ptr == 0 instead of its expected value). The fix is to fsync
the file before doing the block rollback, as the fsync will flush
out all of the dependencies. Once the rollback is done the file
must be fsync'ed again so that the soft updates code does not find
unexpected changes. This approach is much slower than writing the
code to back out the extraneous dependencies, but running out of
disk space is not expected to be a common occurence, so just getting
it right is the main criterion.
PR: kern/15063
Submitted by: Assar Westerlund <assar@stacken.kth.se>
Diffstat (limited to 'sys')
-rw-r--r-- | sys/ufs/ffs/ffs_balloc.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c index ebd630f..a40915d 100644 --- a/sys/ufs/ffs/ffs_balloc.c +++ b/sys/ufs/ffs/ffs_balloc.c @@ -56,7 +56,7 @@ int ffs_balloc(ap) struct vop_balloc_args /* { - struct inode *a_ip; + struct vnode *a_vp; ufs_daddr_t a_lbn; int a_size; struct ucred *a_cred; @@ -64,8 +64,8 @@ ffs_balloc(ap) struct buf *a_bpp; } */ *ap; { - register struct inode *ip; - register ufs_daddr_t lbn; + struct inode *ip; + ufs_daddr_t lbn; int size; struct ucred *cred; int flags; @@ -77,6 +77,7 @@ ffs_balloc(ap) ufs_daddr_t newb, *bap, pref; int deallocated, osize, nsize, num, i, error; ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; + struct proc *p = curproc; /* XXX */ vp = ap->a_vp; ip = VTOI(vp); @@ -335,7 +336,15 @@ fail: /* * If we have failed part way through block allocation, we * have to deallocate any indirect blocks that we have allocated. + * We have to fsync the file before we start to get rid of all + * of its dependencies so that we do not leave them dangling. + * We have to sync it at the end so that the soft updates code + * does not find any untracked changes. Although this is really + * slow, running out of disk space is not expected to be a common + * occurence. The error return from fsync is ignored as we already + * have an error to return to the user. */ + (void) VOP_FSYNC(vp, cred, MNT_WAIT, p); for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { ffs_blkfree(ip, *blkp, fs->fs_bsize); deallocated += fs->fs_bsize; @@ -352,5 +361,6 @@ fail: ip->i_blocks -= btodb(deallocated); ip->i_flag |= IN_CHANGE | IN_UPDATE; } + (void) VOP_FSYNC(vp, cred, MNT_WAIT, p); return (error); } |