aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_cluster.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-09-02 04:04:23 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-09-02 18:36:33 +0000
commit5cc82c563eda97b70120f06e9635ab6c1c24fecd (patch)
tree91c61e433b80c07fca831ef1dd019ae5a92a55f5 /sys/kern/vfs_cluster.c
parent6352bbf7be9b312979a4110342ff4e18eb0fcfa4 (diff)
downloadsrc-5cc82c563eda97b70120f06e9635ab6c1c24fecd.tar.gz
src-5cc82c563eda97b70120f06e9635ab6c1c24fecd.zip
cluster_write(): do not access buffer after it is released
The issue was reported by Alexander Lochmann <alexander.lochmann@tu-dortmund.de>, who found the problem by performing lock analysis using LockDoc, see https://doi.org/10.1145/3302424.3303948. Reviewed by: mckusick Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D31780
Diffstat (limited to 'sys/kern/vfs_cluster.c')
-rw-r--r--sys/kern/vfs_cluster.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c
index 7ca67c390b91..d3b303f28f6b 100644
--- a/sys/kern/vfs_cluster.c
+++ b/sys/kern/vfs_cluster.c
@@ -646,7 +646,7 @@ void
cluster_write(struct vnode *vp, struct vn_clusterw *vnc, struct buf *bp,
u_quad_t filesize, int seqcount, int gbflags)
{
- daddr_t lbn;
+ daddr_t lbn, pbn;
int maxclen, cursize;
int lblocksize;
int async;
@@ -753,14 +753,16 @@ cluster_write(struct vnode *vp, struct vn_clusterw *vnc, struct buf *bp,
bp->b_blkno == bp->b_lblkno &&
(VOP_BMAP(vp, lbn, NULL, &bp->b_blkno, &maxclen,
NULL) != 0 || bp->b_blkno == -1)) {
+ pbn = bp->b_blkno;
bawrite(bp);
vnc->v_clen = 0;
- vnc->v_lasta = bp->b_blkno;
+ vnc->v_lasta = pbn;
vnc->v_cstart = lbn + 1;
vnc->v_lastw = lbn;
return;
}
vnc->v_clen = maxclen;
+ pbn = bp->b_blkno;
if (!async && maxclen == 0) { /* I/O not contiguous */
vnc->v_cstart = lbn + 1;
bawrite(bp);
@@ -774,6 +776,7 @@ cluster_write(struct vnode *vp, struct vn_clusterw *vnc, struct buf *bp,
* are operating sequentially, otherwise let the buf or
* update daemon handle it.
*/
+ pbn = bp->b_blkno;
bdwrite(bp);
if (seqcount > 1) {
cluster_wbuild_wb(vp, lblocksize, vnc->v_cstart,
@@ -785,15 +788,17 @@ cluster_write(struct vnode *vp, struct vn_clusterw *vnc, struct buf *bp,
/*
* We are low on memory, get it going NOW
*/
+ pbn = bp->b_blkno;
bawrite(bp);
} else {
/*
* In the middle of a cluster, so just delay the I/O for now.
*/
+ pbn = bp->b_blkno;
bdwrite(bp);
}
vnc->v_lastw = lbn;
- vnc->v_lasta = bp->b_blkno;
+ vnc->v_lasta = pbn;
}
/*