diff options
author | kib <kib@FreeBSD.org> | 2009-06-30 10:07:33 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-06-30 10:07:33 +0000 |
commit | 4cf230ed170cd555457f98b62de976144a223f57 (patch) | |
tree | 858f72c2462938f06e39eb61e94b258b98685aee /sys/ufs | |
parent | c424611d793944a4fe03022da72a5ecc34649c72 (diff) | |
download | FreeBSD-src-4cf230ed170cd555457f98b62de976144a223f57.zip FreeBSD-src-4cf230ed170cd555457f98b62de976144a223f57.tar.gz |
For SU mounts, softdep_fsync() might drop vnode lock, allowing other
threads to put dirty buffers on the vnode bufobj list. For regular files
and synchronous fsync requests, check for the condition and restart the
fsync vop if a new dirty buffer arrived.
Tested by: pho
Approved by: re (kensmith)
MFC after: 1 month
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 1abb994..a6a4c05 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -180,15 +180,36 @@ struct vop_vector ffs_fifoops2 = { static int ffs_fsync(struct vop_fsync_args *ap) { + struct vnode *vp; + struct bufobj *bo; int error; - error = ffs_syncvnode(ap->a_vp, ap->a_waitfor); + vp = ap->a_vp; + bo = &vp->v_bufobj; +retry: + error = ffs_syncvnode(vp, ap->a_waitfor); if (error) return (error); if (ap->a_waitfor == MNT_WAIT && - (ap->a_vp->v_mount->mnt_flag & MNT_SOFTDEP)) - error = softdep_fsync(ap->a_vp); - return (error); + (vp->v_mount->mnt_flag & MNT_SOFTDEP)) { + error = softdep_fsync(vp); + if (error) + return (error); + + /* + * The softdep_fsync() function may drop vp lock, + * allowing for dirty buffers to reappear on the + * bo_dirty list. Recheck and resync as needed. + */ + BO_LOCK(bo); + if (vp->v_type == VREG && (bo->bo_numoutput > 0 || + bo->bo_dirty.bv_cnt > 0)) { + BO_UNLOCK(bo); + goto retry; + } + BO_UNLOCK(bo); + } + return (0); } int |