svn commit: r283602 - in head/sys: cddl/contrib/opensolaris/uts/common/fs/zfs kern
Konstantin Belousov
kib at FreeBSD.org
Wed May 27 09:22:52 UTC 2015
Author: kib
Date: Wed May 27 09:22:50 2015
New Revision: 283602
URL: https://svnweb.freebsd.org/changeset/base/283602
Log:
Right now, dounmount() is called with unreferenced mount point.
Nothing stops a parallel unmount to suceed before the given call to
dounmount() checks and locks the covered vnode. Prevent dounmount()
from acting on the freed (although type-stable) memory by changing the
interface to require the mount point to be referenced. dounmount()
consumes the reference on return, regardless of the sucessfull or
erronous result.
Tested by: pho
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Modified:
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
head/sys/kern/vfs_mount.c
head/sys/kern/vfs_subr.c
Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c Wed May 27 09:21:47 2015 (r283601)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c Wed May 27 09:22:50 2015 (r283602)
@@ -697,6 +697,7 @@ zfsctl_unmount_snap(zfs_snapentry_t *sep
return (0);
#else
+ vfs_ref(vn_mountedvfs(svp));
return (dounmount(vn_mountedvfs(svp), fflags, curthread));
#endif
}
Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Wed May 27 09:21:47 2015 (r283601)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c Wed May 27 09:22:50 2015 (r283602)
@@ -3481,6 +3481,7 @@ zfs_unmount_snap(const char *snapname)
#ifdef illumos
(void) dounmount(vfsp, MS_FORCE, kcred);
#else
+ vfs_ref(vfsp);
(void) dounmount(vfsp, MS_FORCE, curthread);
#endif
return (0);
Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c Wed May 27 09:21:47 2015 (r283601)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c Wed May 27 09:22:50 2015 (r283602)
@@ -2315,6 +2315,7 @@ bail:
* unmount this file system.
*/
if (vn_vfswlock(zfsvfs->z_vfs->vfs_vnodecovered) == 0)
+ vfs_ref(zfsvfs->z_vfs);
(void) dounmount(zfsvfs->z_vfs, MS_FORCE, curthread);
}
return (err);
Modified: head/sys/kern/vfs_mount.c
==============================================================================
--- head/sys/kern/vfs_mount.c Wed May 27 09:21:47 2015 (r283601)
+++ head/sys/kern/vfs_mount.c Wed May 27 09:22:50 2015 (r283602)
@@ -1128,12 +1128,7 @@ struct unmount_args {
#endif
/* ARGSUSED */
int
-sys_unmount(td, uap)
- struct thread *td;
- register struct unmount_args /* {
- char *path;
- int flags;
- } */ *uap;
+sys_unmount(struct thread *td, struct unmount_args *uap)
{
struct nameidata nd;
struct mount *mp;
@@ -1164,8 +1159,10 @@ sys_unmount(td, uap)
mtx_lock(&mountlist_mtx);
TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) {
if (mp->mnt_stat.f_fsid.val[0] == id0 &&
- mp->mnt_stat.f_fsid.val[1] == id1)
+ mp->mnt_stat.f_fsid.val[1] == id1) {
+ vfs_ref(mp);
break;
+ }
}
mtx_unlock(&mountlist_mtx);
} else {
@@ -1183,8 +1180,10 @@ sys_unmount(td, uap)
}
mtx_lock(&mountlist_mtx);
TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) {
- if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0)
+ if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0) {
+ vfs_ref(mp);
break;
+ }
}
mtx_unlock(&mountlist_mtx);
}
@@ -1202,8 +1201,10 @@ sys_unmount(td, uap)
/*
* Don't allow unmounting the root filesystem.
*/
- if (mp->mnt_flag & MNT_ROOTFS)
+ if (mp->mnt_flag & MNT_ROOTFS) {
+ vfs_rel(mp);
return (EINVAL);
+ }
error = dounmount(mp, uap->flags, td);
return (error);
}
@@ -1212,10 +1213,7 @@ sys_unmount(td, uap)
* Do the actual filesystem unmount.
*/
int
-dounmount(mp, flags, td)
- struct mount *mp;
- int flags;
- struct thread *td;
+dounmount(struct mount *mp, int flags, struct thread *td)
{
struct vnode *coveredvp, *fsrootvp;
int error;
@@ -1235,6 +1233,7 @@ dounmount(mp, flags, td)
if (coveredvp->v_mountedhere != mp ||
coveredvp->v_mountedhere->mnt_gen != mnt_gen_r) {
VOP_UNLOCK(coveredvp, 0);
+ vfs_rel(mp);
return (EBUSY);
}
}
@@ -1243,13 +1242,14 @@ dounmount(mp, flags, td)
* original mount is permitted to unmount this filesystem.
*/
error = vfs_suser(mp, td);
- if (error) {
+ if (error != 0) {
if (coveredvp)
VOP_UNLOCK(coveredvp, 0);
+ vfs_rel(mp);
return (error);
}
- vn_start_write(NULL, &mp, V_WAIT);
+ vn_start_write(NULL, &mp, V_WAIT | V_MNTREF);
MNT_ILOCK(mp);
if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 ||
!TAILQ_EMPTY(&mp->mnt_uppers)) {
Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c Wed May 27 09:21:47 2015 (r283601)
+++ head/sys/kern/vfs_subr.c Wed May 27 09:22:50 2015 (r283602)
@@ -3502,8 +3502,9 @@ vfs_unmountall(void)
*/
while(!TAILQ_EMPTY(&mountlist)) {
mp = TAILQ_LAST(&mountlist, mntlist);
+ vfs_ref(mp);
error = dounmount(mp, MNT_FORCE, td);
- if (error) {
+ if (error != 0) {
TAILQ_REMOVE(&mountlist, mp, mnt_list);
/*
* XXX: Due to the way in which we mount the root
More information about the svn-src-all
mailing list