1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-16 10:20:30 +00:00

The ffs_balloc() routines, whan allocating the indirect blocks for

the inode, do the rollback in case the allocation failed (due to
insufficient free space or quota limits). But, the code does leaves the
buffers corresponding to the inoirect blocks on the vnode bufobj list.
This causes several assertion failures (for instance, "ffs_truncate3"
in ffs_truncate()) to fail, and could result in the indirect block
aliasing problem, like writing the context of such blocks to random
disk location.

Remove the buffers from the bufobj properly.

Reported and tested by:	Peter Holm
Reviewed by:	tegge
MFC after:	3 weeks
This commit is contained in:
Konstantin Belousov 2007-12-29 13:31:27 +00:00
parent ee4f10a0e0
commit e7627b2c62
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=174973

View File

@ -102,6 +102,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
ufs2_daddr_t newb;
ufs1_daddr_t *bap, pref;
ufs1_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
ufs2_daddr_t *lbns_remfree, lbns[NIADDR + 1];
int unwindidx = -1;
ip = VTOI(vp);
@ -231,6 +232,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
nb = dp->di_ib[indirs[0].in_off];
allocib = NULL;
allocblk = allociblk;
lbns_remfree = lbns;
if (nb == 0) {
UFS_LOCK(ump);
pref = ffs_blkpref_ufs1(ip, lbn, 0, (ufs1_daddr_t *)0);
@ -239,6 +241,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
return (error);
nb = newb;
*allocblk++ = nb;
*lbns_remfree++ = indirs[1].in_lbn;
bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0);
bp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(bp);
@ -289,6 +292,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
}
nb = newb;
*allocblk++ = nb;
*lbns_remfree++ = indirs[i].in_lbn;
nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(nbp);
@ -342,6 +346,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
}
nb = newb;
*allocblk++ = nb;
*lbns_remfree++ = lbn;
nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
if (flags & BA_CLRBUF)
@ -403,7 +408,22 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
* have an error to return to the user.
*/
(void) ffs_syncvnode(vp, MNT_WAIT);
for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
for (deallocated = 0, blkp = allociblk, lbns_remfree = lbns;
blkp < allocblk; blkp++, lbns_remfree++) {
/*
* We shall not leave the freed blocks on the vnode
* buffer object lists.
*/
bp = getblk(vp, *lbns_remfree, fs->fs_bsize, 0, 0, GB_NOCREAT);
if (bp != NULL) {
bp->b_flags |= (B_INVAL | B_RELBUF);
bp->b_flags &= ~B_ASYNC;
brelse(bp);
}
/*
* After the buffer is invalidated, free the block.
*/
ffs_blkfree(ump, fs, ip->i_devvp, *blkp, fs->fs_bsize,
ip->i_number);
deallocated += fs->fs_bsize;
@ -464,6 +484,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
struct indir indirs[NIADDR + 2];
ufs2_daddr_t nb, newb, *bap, pref;
ufs2_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
ufs2_daddr_t *lbns_remfree, lbns[NIADDR + 1];
int deallocated, osize, nsize, num, i, error;
int unwindidx = -1;
@ -703,6 +724,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
nb = dp->di_ib[indirs[0].in_off];
allocib = NULL;
allocblk = allociblk;
lbns_remfree = lbns;
if (nb == 0) {
UFS_LOCK(ump);
pref = ffs_blkpref_ufs2(ip, lbn, 0, (ufs2_daddr_t *)0);
@ -711,6 +733,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
return (error);
nb = newb;
*allocblk++ = nb;
*lbns_remfree++ = indirs[1].in_lbn;
bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0);
bp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(bp);
@ -761,6 +784,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
}
nb = newb;
*allocblk++ = nb;
*lbns_remfree++ = indirs[i].in_lbn;
nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(nbp);
@ -814,6 +838,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
}
nb = newb;
*allocblk++ = nb;
*lbns_remfree++ = lbn;
nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, 0);
nbp->b_blkno = fsbtodb(fs, nb);
if (flags & BA_CLRBUF)
@ -881,7 +906,22 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
* have an error to return to the user.
*/
(void) ffs_syncvnode(vp, MNT_WAIT);
for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
for (deallocated = 0, blkp = allociblk, lbns_remfree = lbns;
blkp < allocblk; blkp++, lbns_remfree++) {
/*
* We shall not leave the freed blocks on the vnode
* buffer object lists.
*/
bp = getblk(vp, *lbns_remfree, fs->fs_bsize, 0, 0, GB_NOCREAT);
if (bp != NULL) {
bp->b_flags |= (B_INVAL | B_RELBUF);
bp->b_flags &= ~B_ASYNC;
brelse(bp);
}
/*
* After the buffer is invalidated, free the block.
*/
ffs_blkfree(ump, fs, ip->i_devvp, *blkp, fs->fs_bsize,
ip->i_number);
deallocated += fs->fs_bsize;