diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 328dd1b..090e3ba 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3615,6 +3615,8 @@ vn_strategy(struct vnode *vp, struct bio *bio) vop_strategy(*vp->v_ops, vp, bio); } +static void vn_cache_strategy_callback(struct bio *bio); + int vn_cache_strategy(struct vnode *vp, struct bio *bio) { @@ -3660,11 +3662,12 @@ vn_cache_strategy(struct vnode *vp, struct bio *bio) } /* - * If we are good then issue the I/O using swap_pager_strategy() + * If we are good then issue the I/O using swap_pager_strategy(). */ if (i == bp->b_xio.xio_npages) { m = bp->b_xio.xio_pages[0]; nbio = push_bio(bio); + nbio->bio_done = vn_cache_strategy_callback; nbio->bio_offset = ptoa(m->pindex); KKASSERT(m->object == object); swap_pager_strategy(object, nbio); @@ -3674,6 +3677,21 @@ vn_cache_strategy(struct vnode *vp, struct bio *bio) } /* + * This is a bit of a hack but since the vn_cache_strategy() function can + * override a VFS's strategy function we must make sure that the bio, which + * is probably bio2, doesn't leak an unexpected offset value back to the + * filesystem. The filesystem (e.g. UFS) might otherwise assume that the + * bio went through its own file strategy function and the the bio2 offset + * is a cached disk offset when, in fact, it isn't. + */ +static void +vn_cache_strategy_callback(struct bio *bio) +{ + bio->bio_offset = NOOFFSET; + biodone(pop_bio(bio)); +} + +/* * bpdone: * * Finish I/O on a buffer after all BIOs have been processed.