From owner-svn-src-head@FreeBSD.ORG Sat Sep 11 13:06:06 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id ED1AA106566B; Sat, 11 Sep 2010 13:06:06 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id DCE898FC16; Sat, 11 Sep 2010 13:06:06 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o8BD66No097554; Sat, 11 Sep 2010 13:06:06 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o8BD66xa097549; Sat, 11 Sep 2010 13:06:06 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201009111306.o8BD66xa097549@svn.freebsd.org> From: Konstantin Belousov Date: Sat, 11 Sep 2010 13:06:06 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r212466 - in head/sys: kern sys X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 11 Sep 2010 13:06:07 -0000 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 *);