summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-06-30 10:07:33 +0000
committerkib <kib@FreeBSD.org>2009-06-30 10:07:33 +0000
commit4cf230ed170cd555457f98b62de976144a223f57 (patch)
tree858f72c2462938f06e39eb61e94b258b98685aee /sys/ufs
parentc424611d793944a4fe03022da72a5ecc34649c72 (diff)
downloadFreeBSD-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.c29
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
OpenPOWER on IntegriCloud