summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_syscalls.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-11-29 13:34:59 +0000
committerkib <kib@FreeBSD.org>2008-11-29 13:34:59 +0000
commitbf74bb2e167fcc7089b250309aa7131a27b672e2 (patch)
tree74a7c36a02638c961fd484be28f826c1acdb6a3a /sys/kern/vfs_syscalls.c
parent881f5f6bef889a5fc9f878e367245de363a1c55e (diff)
downloadFreeBSD-src-bf74bb2e167fcc7089b250309aa7131a27b672e2.zip
FreeBSD-src-bf74bb2e167fcc7089b250309aa7131a27b672e2.tar.gz
In the nfsrv_fhtovp(), after the vfs_getvfs() function found the pointer
to the fs, but before a vnode on the fs is locked, unmount may free fs structures, causing access to destroyed data and freed memory. Introduce a vfs_busymp() function that looks up and busies found fs while mountlist_mtx is held. Use it in nfsrv_fhtovp() and in the implementation of the handle syscalls. Two other uses of the vfs_getvfs() in the vfs_subr.c, namely in sysctl_vfs_ctl and vfs_getnewfsid seems to be ok. In particular, sysctl_vfs_ctl is protected by Giant by being a non-sleeping sysctl handler, that prevents Giant-locked unmount code to interfere with it. Noted by: tegge Reviewed by: dfr Tested by: pho MFC after: 1 month
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r--sys/kern/vfs_syscalls.c18
1 files changed, 9 insertions, 9 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index ad71a89..e4f4f8b 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -4382,12 +4382,13 @@ fhopen(td, uap)
if (error)
return(error);
/* find the mount point */
- mp = vfs_getvfs(&fhp.fh_fsid);
+ mp = vfs_busyfs(&fhp.fh_fsid);
if (mp == NULL)
return (ESTALE);
vfslocked = VFS_LOCK_GIANT(mp);
/* now give me my vnode, it gets returned to me locked */
error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
+ vfs_unbusy(mp);
if (error)
goto out;
/*
@@ -4520,7 +4521,6 @@ fhopen(td, uap)
bad:
vput(vp);
out:
- vfs_rel(mp);
VFS_UNLOCK_GIANT(vfslocked);
return (error);
}
@@ -4555,17 +4555,17 @@ fhstat(td, uap)
error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
if (error)
return (error);
- if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
+ if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
return (ESTALE);
vfslocked = VFS_LOCK_GIANT(mp);
- if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) {
- vfs_rel(mp);
+ error = VFS_FHTOVP(mp, &fh.fh_fid, &vp);
+ vfs_unbusy(mp);
+ if (error) {
VFS_UNLOCK_GIANT(vfslocked);
return (error);
}
error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
vput(vp);
- vfs_rel(mp);
VFS_UNLOCK_GIANT(vfslocked);
if (error)
return (error);
@@ -4615,13 +4615,13 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf)
error = priv_check(td, PRIV_VFS_FHSTATFS);
if (error)
return (error);
- if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
+ if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
return (ESTALE);
vfslocked = VFS_LOCK_GIANT(mp);
error = VFS_FHTOVP(mp, &fh.fh_fid, &vp);
if (error) {
+ vfs_unbusy(mp);
VFS_UNLOCK_GIANT(vfslocked);
- vfs_rel(mp);
return (error);
}
vput(vp);
@@ -4644,7 +4644,7 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf)
if (error == 0)
*buf = *sp;
out:
- vfs_rel(mp);
+ vfs_unbusy(mp);
VFS_UNLOCK_GIANT(vfslocked);
return (error);
}
OpenPOWER on IntegriCloud