diff options
author | kib <kib@FreeBSD.org> | 2008-11-29 13:34:59 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2008-11-29 13:34:59 +0000 |
commit | bf74bb2e167fcc7089b250309aa7131a27b672e2 (patch) | |
tree | 74a7c36a02638c961fd484be28f826c1acdb6a3a /sys/kern/vfs_syscalls.c | |
parent | 881f5f6bef889a5fc9f878e367245de363a1c55e (diff) | |
download | FreeBSD-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.c | 18 |
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); } |