svn commit: r212466 - in head/sys: kern sys

Konstantin Belousov kib at FreeBSD.org
Sat Sep 11 13:06:07 UTC 2010


Author: kib
Date: Sat Sep 11 13:06:06 2010
New Revision: 212466
URL: http://svn.freebsd.org/changeset/base/212466

Log:
  Protect mnt_syncer with the sync_mtx. This prevents a (rare) vnode leak
  when mount and update are executed in parallel.
  
  Encapsulate syncer vnode deallocation into the helper function
  vfs_deallocate_syncvnode(), to not externalize sync_mtx from vfs_subr.c.
  
  Found and reviewed by:	jh (previous version of the patch)
  Tested by:	pho
  MFC after:	3 weeks

Modified:
  head/sys/kern/vfs_mount.c
  head/sys/kern/vfs_subr.c
  head/sys/sys/mount.h

Modified: head/sys/kern/vfs_mount.c
==============================================================================
--- head/sys/kern/vfs_mount.c	Sat Sep 11 12:58:31 2010	(r212465)
+++ head/sys/kern/vfs_mount.c	Sat Sep 11 13:06:06 2010	(r212466)
@@ -1031,14 +1031,10 @@ vfs_domount_update(
 	 */
 	mp->mnt_optnew = NULL;
 
-	if ((mp->mnt_flag & MNT_RDONLY) == 0) {
-		if (mp->mnt_syncer == NULL)
-			vfs_allocate_syncvnode(mp);
-	} else {
-		if (mp->mnt_syncer != NULL)
-			vrele(mp->mnt_syncer);
-		mp->mnt_syncer = NULL;
-	}
+	if ((mp->mnt_flag & MNT_RDONLY) == 0)
+		vfs_allocate_syncvnode(mp);
+	else
+		vfs_deallocate_syncvnode(mp);
 end:
 	vfs_unbusy(mp);
 	VI_LOCK(vp);
@@ -1318,8 +1314,7 @@ dounmount(mp, flags, td)
 	mp->mnt_kern_flag &= ~MNTK_ASYNC;
 	MNT_IUNLOCK(mp);
 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
-	if (mp->mnt_syncer != NULL)
-		vrele(mp->mnt_syncer);
+	vfs_deallocate_syncvnode(mp);
 	/*
 	 * For forced unmounts, move process cdir/rdir refs on the fs root
 	 * vnode to the covered vnode.  For non-forced unmounts we want
@@ -1358,7 +1353,7 @@ dounmount(mp, flags, td)
 		}
 		MNT_ILOCK(mp);
 		mp->mnt_kern_flag &= ~MNTK_NOINSMNTQ;
-		if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) {
+		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
 			MNT_IUNLOCK(mp);
 			vfs_allocate_syncvnode(mp);
 			MNT_ILOCK(mp);

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c	Sat Sep 11 12:58:31 2010	(r212465)
+++ head/sys/kern/vfs_subr.c	Sat Sep 11 13:06:06 2010	(r212466)
@@ -3405,9 +3405,31 @@ vfs_allocate_syncvnode(struct mount *mp)
 	/* XXX - vn_syncer_add_to_worklist() also grabs and drops sync_mtx. */
 	mtx_lock(&sync_mtx);
 	sync_vnode_count++;
+	if (mp->mnt_syncer == NULL) {
+		mp->mnt_syncer = vp;
+		vp = NULL;
+	}
 	mtx_unlock(&sync_mtx);
 	BO_UNLOCK(bo);
-	mp->mnt_syncer = vp;
+	if (vp != NULL) {
+		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+		vgone(vp);
+		vput(vp);
+	}
+}
+
+void
+vfs_deallocate_syncvnode(struct mount *mp)
+{
+	struct vnode *vp;
+
+	mtx_lock(&sync_mtx);
+	vp = mp->mnt_syncer;
+	if (vp != NULL)
+		mp->mnt_syncer = NULL;
+	mtx_unlock(&sync_mtx);
+	if (vp != NULL)
+		vrele(vp);
 }
 
 /*
@@ -3488,15 +3510,16 @@ sync_reclaim(struct vop_reclaim_args *ap
 
 	bo = &vp->v_bufobj;
 	BO_LOCK(bo);
-	vp->v_mount->mnt_syncer = NULL;
+	mtx_lock(&sync_mtx);
+	if (vp->v_mount->mnt_syncer == vp)
+		vp->v_mount->mnt_syncer = NULL;
 	if (bo->bo_flag & BO_ONWORKLST) {
-		mtx_lock(&sync_mtx);
 		LIST_REMOVE(bo, bo_synclist);
 		syncer_worklist_len--;
 		sync_vnode_count--;
-		mtx_unlock(&sync_mtx);
 		bo->bo_flag &= ~BO_ONWORKLST;
 	}
+	mtx_unlock(&sync_mtx);
 	BO_UNLOCK(bo);
 
 	return (0);

Modified: head/sys/sys/mount.h
==============================================================================
--- head/sys/sys/mount.h	Sat Sep 11 12:58:31 2010	(r212465)
+++ head/sys/sys/mount.h	Sat Sep 11 13:06:06 2010	(r212466)
@@ -731,6 +731,7 @@ int	vfs_busy(struct mount *, int);
 int	vfs_export			 /* process mount export info */
 	    (struct mount *, struct export_args *);
 void	vfs_allocate_syncvnode(struct mount *);
+void	vfs_deallocate_syncvnode(struct mount *);
 int	vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions);
 void	vfs_getnewfsid(struct mount *);
 struct cdev *vfs_getrootfsid(struct mount *);


More information about the svn-src-head mailing list