From owner-svn-src-all@freebsd.org Wed Jun 15 15:56:04 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B4D8AA451C3; Wed, 15 Jun 2016 15:56:04 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6A9E41B71; Wed, 15 Jun 2016 15:56:04 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u5FFu39s032258; Wed, 15 Jun 2016 15:56:03 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u5FFu3pt032257; Wed, 15 Jun 2016 15:56:03 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201606151556.u5FFu3pt032257@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Wed, 15 Jun 2016 15:56:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r301929 - head/sys/kern X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Jun 2016 15:56:04 -0000 Author: kib Date: Wed Jun 15 15:56:03 2016 New Revision: 301929 URL: https://svnweb.freebsd.org/changeset/base/301929 Log: Do not assume that we own the use reference on the covered vnode until we set MNTK_UNMOUNT flag on the mp. Otherwise parallel unmount which wins race with us could dereference the covered vnode, and we are left with the locked freed memory. Reported and tested by: pho Sponsored by: The FreeBSD Foundation Approved by: re (gjb) MFC after: 1 week Modified: head/sys/kern/vfs_mount.c Modified: head/sys/kern/vfs_mount.c ============================================================================== --- head/sys/kern/vfs_mount.c Wed Jun 15 15:55:14 2016 (r301928) +++ head/sys/kern/vfs_mount.c Wed Jun 15 15:56:03 2016 (r301929) @@ -1220,7 +1220,6 @@ dounmount(struct mount *mp, int flags, s VI_LOCK(coveredvp); vholdl(coveredvp); vn_lock(coveredvp, LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY); - vdrop(coveredvp); /* * Check for mp being unmounted while waiting for the * covered vnode lock. @@ -1228,18 +1227,22 @@ dounmount(struct mount *mp, int flags, s if (coveredvp->v_mountedhere != mp || coveredvp->v_mountedhere->mnt_gen != mnt_gen_r) { VOP_UNLOCK(coveredvp, 0); + vdrop(coveredvp); vfs_rel(mp); return (EBUSY); } } + /* * Only privileged root, or (if MNT_USER is set) the user that did the * original mount is permitted to unmount this filesystem. */ error = vfs_suser(mp, td); if (error != 0) { - if (coveredvp) + if (coveredvp != NULL) { VOP_UNLOCK(coveredvp, 0); + vdrop(coveredvp); + } vfs_rel(mp); return (error); } @@ -1249,8 +1252,10 @@ dounmount(struct mount *mp, int flags, s if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 || !TAILQ_EMPTY(&mp->mnt_uppers)) { MNT_IUNLOCK(mp); - if (coveredvp) + if (coveredvp != NULL) { VOP_UNLOCK(coveredvp, 0); + vdrop(coveredvp); + } vn_finished_write(mp); return (EBUSY); } @@ -1283,6 +1288,16 @@ dounmount(struct mount *mp, int flags, s if (mp->mnt_flag & MNT_EXPUBLIC) vfs_setpublicfs(NULL, NULL, NULL); + /* + * From now, we can claim that the use reference on the + * coveredvp is ours, and the ref can be released only by + * successfull unmount by us, or left for later unmount + * attempt. The previously acquired hold reference is no + * longer needed to protect the vnode from reuse. + */ + if (coveredvp != NULL) + vdrop(coveredvp); + vfs_msync(mp, MNT_WAIT); MNT_ILOCK(mp); async_flag = mp->mnt_flag & MNT_ASYNC;