summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2006-09-26 04:12:49 +0000
committertegge <tegge@FreeBSD.org>2006-09-26 04:12:49 +0000
commit83154f853d9ca39deb1add01e032aff1f0678514 (patch)
treeac46e0b5a80f88127d3d14dc940a5f2746573c00 /sys/kern
parentd7fe3e736512a1dd37a985037184eecf7df1f26d (diff)
downloadFreeBSD-src-83154f853d9ca39deb1add01e032aff1f0678514.zip
FreeBSD-src-83154f853d9ca39deb1add01e032aff1f0678514.tar.gz
Use mount interlock to protect all changes to mnt_flag and mnt_kern_flag.
This eliminates a race where MNT_UPDATE flag could be lost when nmount() raced against sync(), sync_fsync() or quotactl().
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_mqueue.c2
-rw-r--r--sys/kern/vfs_export.c10
-rw-r--r--sys/kern/vfs_extattr.c4
-rw-r--r--sys/kern/vfs_mount.c13
-rw-r--r--sys/kern/vfs_subr.c4
-rw-r--r--sys/kern/vfs_syscalls.c4
6 files changed, 37 insertions, 0 deletions
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index e95f800..d6cf2e5 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -561,8 +561,10 @@ mqfs_mount(struct mount *mp, struct thread *td)
return (EOPNOTSUPP);
mp->mnt_data = &mqfs_data;
+ MNT_ILOCK(mp);
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_kern_flag |= MNTK_MPSAFE;
+ MNT_IUNLOCK(mp);
vfs_getnewfsid(mp);
sbp = &mp->mnt_stat;
diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c
index 5552845..00237b6 100644
--- a/sys/kern/vfs_export.c
+++ b/sys/kern/vfs_export.c
@@ -117,7 +117,9 @@ vfs_hang_addrlist(mp, nep, argp)
bcopy(argp->ex_anon.cr_groups, np->netc_anon.cr_groups,
sizeof(np->netc_anon.cr_groups));
refcount_init(&np->netc_anon.cr_ref, 1);
+ MNT_ILOCK(mp);
mp->mnt_flag |= MNT_DEFEXPORTED;
+ MNT_IUNLOCK(mp);
return (0);
}
@@ -236,13 +238,17 @@ vfs_export(mp, argp)
return (ENOENT);
if (mp->mnt_flag & MNT_EXPUBLIC) {
vfs_setpublicfs(NULL, NULL, NULL);
+ MNT_ILOCK(mp);
mp->mnt_flag &= ~MNT_EXPUBLIC;
+ MNT_IUNLOCK(mp);
}
vfs_free_addrlist(nep);
mp->mnt_export = NULL;
free(nep, M_MOUNT);
nep = NULL;
+ MNT_ILOCK(mp);
mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);
+ MNT_IUNLOCK(mp);
}
if (argp->ex_flags & MNT_EXPORTED) {
if (nep == NULL) {
@@ -252,11 +258,15 @@ vfs_export(mp, argp)
if (argp->ex_flags & MNT_EXPUBLIC) {
if ((error = vfs_setpublicfs(mp, nep, argp)) != 0)
return (error);
+ MNT_ILOCK(mp);
mp->mnt_flag |= MNT_EXPUBLIC;
+ MNT_IUNLOCK(mp);
}
if ((error = vfs_hang_addrlist(mp, nep, argp)))
return (error);
+ MNT_ILOCK(mp);
mp->mnt_flag |= MNT_EXPORTED;
+ MNT_IUNLOCK(mp);
}
return (0);
}
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index cbef350..147b31e 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -133,11 +133,15 @@ sync(td, uap)
vfslocked = VFS_LOCK_GIANT(mp);
if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
+ MNT_ILOCK(mp);
asyncflag = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
+ MNT_IUNLOCK(mp);
vfs_msync(mp, MNT_NOWAIT);
VFS_SYNC(mp, MNT_NOWAIT, td);
+ MNT_ILOCK(mp);
mp->mnt_flag |= asyncflag;
+ MNT_IUNLOCK(mp);
vn_finished_write(mp);
}
VFS_UNLOCK_GIANT(vfslocked);
diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c
index 64c64c9..1e4cf6d 100644
--- a/sys/kern/vfs_mount.c
+++ b/sys/kern/vfs_mount.c
@@ -471,7 +471,9 @@ vfs_mount_alloc(struct vnode *vp, struct vfsconf *vfsp,
mp->mnt_vfc = vfsp;
vfsp->vfc_refcount++; /* XXX Unlocked */
mp->mnt_stat.f_type = vfsp->vfc_typenum;
+ MNT_ILOCK(mp);
mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
+ MNT_IUNLOCK(mp);
strlcpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
mp->mnt_vnodecovered = vp;
mp->mnt_cred = crdup(td->td_ucred);
@@ -848,6 +850,7 @@ vfs_domount(
return (EINVAL);
}
mp = vp->v_mount;
+ MNT_ILOCK(mp);
flag = mp->mnt_flag;
kern_flag = mp->mnt_kern_flag;
/*
@@ -856,9 +859,11 @@ vfs_domount(
*/
if ((fsflags & MNT_RELOAD) &&
((mp->mnt_flag & MNT_RDONLY) == 0)) {
+ MNT_IUNLOCK(mp);
vput(vp);
return (EOPNOTSUPP); /* Needs translation */
}
+ MNT_IUNLOCK(mp);
/*
* Only privileged root, or (if MNT_USER is set) the user that
* did the original mount is permitted to update it.
@@ -882,8 +887,10 @@ vfs_domount(
}
vp->v_iflag |= VI_MOUNT;
VI_UNLOCK(vp);
+ MNT_ILOCK(mp);
mp->mnt_flag |= fsflags &
(MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT | MNT_ROOTFS);
+ MNT_IUNLOCK(mp);
VOP_UNLOCK(vp, 0, td);
mp->mnt_optnew = fsdata;
vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt);
@@ -935,10 +942,12 @@ vfs_domount(
/*
* Set the mount level flags.
*/
+ MNT_ILOCK(mp);
if (fsflags & MNT_RDONLY)
mp->mnt_flag |= MNT_RDONLY;
mp->mnt_flag &=~ MNT_UPDATEMASK;
mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS);
+ MNT_IUNLOCK(mp);
/*
* Mount the filesystem.
* XXX The final recipients of VFS_MOUNT just overwrite the ndp they
@@ -968,12 +977,14 @@ vfs_domount(
*/
mp->mnt_optnew = NULL;
if (mp->mnt_flag & MNT_UPDATE) {
+ MNT_ILOCK(mp);
mp->mnt_flag &=
~(MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT);
if (error) {
mp->mnt_flag = flag;
mp->mnt_kern_flag = kern_flag;
}
+ MNT_IUNLOCK(mp);
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
if (mp->mnt_syncer == NULL)
error = vfs_allocate_syncvnode(mp);
@@ -1185,8 +1196,10 @@ dounmount(mp, flags, td)
vfs_setpublicfs(NULL, NULL, NULL);
vfs_msync(mp, MNT_WAIT);
+ MNT_ILOCK(mp);
async_flag = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
+ MNT_IUNLOCK(mp);
cache_purgevfs(mp); /* remove cache entries for this file sys */
if (mp->mnt_syncer != NULL)
vrele(mp->mnt_syncer);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 2903e7d..72c4b5c 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -3081,12 +3081,16 @@ sync_fsync(struct vop_fsync_args *ap)
vfs_unbusy(mp, td);
return (0);
}
+ MNT_ILOCK(mp);
asyncflag = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
+ MNT_IUNLOCK(mp);
vfs_msync(mp, MNT_NOWAIT);
error = VFS_SYNC(mp, MNT_LAZY, td);
+ MNT_ILOCK(mp);
if (asyncflag)
mp->mnt_flag |= MNT_ASYNC;
+ MNT_IUNLOCK(mp);
vn_finished_write(mp);
vfs_unbusy(mp, td);
return (error);
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index cbef350..147b31e 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -133,11 +133,15 @@ sync(td, uap)
vfslocked = VFS_LOCK_GIANT(mp);
if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
+ MNT_ILOCK(mp);
asyncflag = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
+ MNT_IUNLOCK(mp);
vfs_msync(mp, MNT_NOWAIT);
VFS_SYNC(mp, MNT_NOWAIT, td);
+ MNT_ILOCK(mp);
mp->mnt_flag |= asyncflag;
+ MNT_IUNLOCK(mp);
vn_finished_write(mp);
}
VFS_UNLOCK_GIANT(vfslocked);
OpenPOWER on IntegriCloud