--- a/sys/kern/vfs_cluster.c +++ b/sys/kern/vfs_cluster.c @@ -1245,6 +1245,7 @@ { struct vnode *vp; off_t loffset; + off_t phys_offset; int maxclen, cursize; int async; cluster_cache_t dummy; @@ -1258,6 +1259,12 @@ loffset = bp->b_loffset; KASSERT(bp->b_loffset != NOOFFSET, ("cluster_write: no buffer offset")); + /* + * Snapshot the physical offset: bdwrite()/bawrite() below release + * the buffer, so bp must not be dereferenced afterwards (use + * phys_offset for the post-release v_lasta updates). + */ + phys_offset = bp->b_bio2.bio_offset; cc = cluster_getcache(&dummy, vp, loffset); @@ -1311,6 +1318,7 @@ bp, blksize); endbp = &buflist->bs_children [buflist->bs_nchildren - 1]; + phys_offset = bp->b_bio2.bio_offset; if (VOP_REALLOCBLKS(vp, buflist)) { /* * Failed, push the previous cluster @@ -1342,7 +1350,7 @@ bdwrite(*bpp); kfree(buflist, M_SEGMENT); cc->v_lastw = loffset + blksize; - cc->v_lasta = bp->b_bio2.bio_offset + + cc->v_lasta = phys_offset + blksize; cluster_putcache(cc); return; @@ -1360,9 +1368,10 @@ (bp->b_bio2.bio_offset == NOOFFSET) && (VOP_BMAP(vp, loffset, &bp->b_bio2.bio_offset, &maxclen, NULL, BUF_CMD_WRITE) || bp->b_bio2.bio_offset == NOOFFSET)) { + phys_offset = bp->b_bio2.bio_offset; bdwrite(bp); cc->v_clen = 0; - cc->v_lasta = bp->b_bio2.bio_offset + blksize; + cc->v_lasta = phys_offset + blksize; cc->v_cstart = loffset; cc->v_lastw = loffset + blksize; cluster_putcache(cc); @@ -1406,7 +1415,7 @@ bdwrite(bp); } cc->v_lastw = loffset + blksize; - cc->v_lasta = bp->b_bio2.bio_offset + blksize; + cc->v_lasta = phys_offset + blksize; cluster_putcache(cc); }