diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2021-09-02 04:04:23 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2021-09-02 18:36:33 +0000 |
commit | 5cc82c563eda97b70120f06e9635ab6c1c24fecd (patch) | |
tree | 91c61e433b80c07fca831ef1dd019ae5a92a55f5 /sys/kern/vfs_cluster.c | |
parent | 6352bbf7be9b312979a4110342ff4e18eb0fcfa4 (diff) | |
download | src-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.c | 11 |
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; } /* |