diff options
author | jeff <jeff@FreeBSD.org> | 2006-02-22 06:19:08 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2006-02-22 06:19:08 +0000 |
commit | 7429328cf4ef5915d7909e8b69cc912ba858963c (patch) | |
tree | 3ea588fa3fc4ca5510712eea8adb0373229d9323 /sys | |
parent | d08a9e33bf08ff93d6851c4cf4dff5ba27154688 (diff) | |
download | FreeBSD-src-7429328cf4ef5915d7909e8b69cc912ba858963c.zip FreeBSD-src-7429328cf4ef5915d7909e8b69cc912ba858963c.tar.gz |
- Hold the vnode used in the statfs related functions until we're done with
the VFS_STATFS call to prevent the mount from disappearing while we're
stating.
- Convert these routines to use MPSAFE namei semantics.
MFC After: 1 week
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/vfs_extattr.c | 49 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 49 |
2 files changed, 56 insertions, 42 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index f208deb..00f180d 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -245,22 +245,21 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, struct statfs *sp, sb; int error; struct nameidata nd; + int vfslocked; - mtx_lock(&Giant); - NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td); + NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF|MPSAFE, pathseg, path, td); error = namei(&nd); - if (error) { - mtx_unlock(&Giant); + if (error) return (error); - } + vfslocked = NDHASGIANT(&nd); mp = nd.ni_vp->v_mount; sp = &mp->mnt_stat; NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) { - mtx_unlock(&Giant); + vput(nd.ni_vp); + VFS_UNLOCK_GIANT(vfslocked); return (error); } #endif @@ -271,17 +270,16 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, sp->f_namemax = NAME_MAX; sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; error = VFS_STATFS(mp, sp, td); - if (error) { - mtx_unlock(&Giant); + vput(nd.ni_vp); + VFS_UNLOCK_GIANT(vfslocked); + if (error) return (error); - } if (suser(td)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); sp = &sb; } - mtx_unlock(&Giant); *buf = *sp; return (0); } @@ -319,21 +317,26 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) struct mount *mp; struct statfs *sp, sb; struct vnode *vp; + int vfslocked; int error; error = getvnode(td->td_proc->p_fd, fd, &fp); if (error) return (error); vp = fp->f_vnode; - mp = vp->v_mount; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + /* Lock the vnode to prevent the mount from going away. */ + error = vn_lock(vp, LK_EXCLUSIVE, td); fdrop(fp, td); - if (vp->v_iflag & VI_DOOMED) + if (error) { + VFS_UNLOCK_GIANT(vfslocked); return (EBADF); - mtx_lock(&Giant); + } + mp = vp->v_mount; #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) { - mtx_unlock(&Giant); + VFS_UNLOCK_GIANT(vfslocked); return (error); } #endif @@ -345,17 +348,16 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) sp->f_namemax = NAME_MAX; sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; error = VFS_STATFS(mp, sp, td); - if (error) { - mtx_unlock(&Giant); + VOP_UNLOCK(vp, 0, td); + VFS_UNLOCK_GIANT(vfslocked); + if (error) return (error); - } if (suser(td)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); sp = &sb; } - mtx_unlock(&Giant); *buf = *sp; return (0); } @@ -691,6 +693,7 @@ fchdir(td, uap) #endif else error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); + /* XXX Unref'd mp access. */ while (!error && (mp = vp->v_mountedhere) != NULL) { int tvfslocked; if (vfs_busy(mp, 0, 0, td)) @@ -4243,13 +4246,16 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) } mp = vp->v_mount; sp = &mp->mnt_stat; - vput(vp); error = prison_canseemount(td->td_ucred, mp); - if (error) + if (error) { + vput(vp); + mtx_unlock(&Giant); return (error); + } #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) { + vput(vp); mtx_unlock(&Giant); return (error); } @@ -4261,6 +4267,7 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) sp->f_namemax = NAME_MAX; sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; error = VFS_STATFS(mp, sp, td); + vput(vp); mtx_unlock(&Giant); if (error) return (error); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index f208deb..00f180d 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -245,22 +245,21 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, struct statfs *sp, sb; int error; struct nameidata nd; + int vfslocked; - mtx_lock(&Giant); - NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td); + NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF|MPSAFE, pathseg, path, td); error = namei(&nd); - if (error) { - mtx_unlock(&Giant); + if (error) return (error); - } + vfslocked = NDHASGIANT(&nd); mp = nd.ni_vp->v_mount; sp = &mp->mnt_stat; NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) { - mtx_unlock(&Giant); + vput(nd.ni_vp); + VFS_UNLOCK_GIANT(vfslocked); return (error); } #endif @@ -271,17 +270,16 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, sp->f_namemax = NAME_MAX; sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; error = VFS_STATFS(mp, sp, td); - if (error) { - mtx_unlock(&Giant); + vput(nd.ni_vp); + VFS_UNLOCK_GIANT(vfslocked); + if (error) return (error); - } if (suser(td)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); sp = &sb; } - mtx_unlock(&Giant); *buf = *sp; return (0); } @@ -319,21 +317,26 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) struct mount *mp; struct statfs *sp, sb; struct vnode *vp; + int vfslocked; int error; error = getvnode(td->td_proc->p_fd, fd, &fp); if (error) return (error); vp = fp->f_vnode; - mp = vp->v_mount; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + /* Lock the vnode to prevent the mount from going away. */ + error = vn_lock(vp, LK_EXCLUSIVE, td); fdrop(fp, td); - if (vp->v_iflag & VI_DOOMED) + if (error) { + VFS_UNLOCK_GIANT(vfslocked); return (EBADF); - mtx_lock(&Giant); + } + mp = vp->v_mount; #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) { - mtx_unlock(&Giant); + VFS_UNLOCK_GIANT(vfslocked); return (error); } #endif @@ -345,17 +348,16 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf) sp->f_namemax = NAME_MAX; sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; error = VFS_STATFS(mp, sp, td); - if (error) { - mtx_unlock(&Giant); + VOP_UNLOCK(vp, 0, td); + VFS_UNLOCK_GIANT(vfslocked); + if (error) return (error); - } if (suser(td)) { bcopy(sp, &sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; prison_enforce_statfs(td->td_ucred, mp, &sb); sp = &sb; } - mtx_unlock(&Giant); *buf = *sp; return (0); } @@ -691,6 +693,7 @@ fchdir(td, uap) #endif else error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td); + /* XXX Unref'd mp access. */ while (!error && (mp = vp->v_mountedhere) != NULL) { int tvfslocked; if (vfs_busy(mp, 0, 0, td)) @@ -4243,13 +4246,16 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) } mp = vp->v_mount; sp = &mp->mnt_stat; - vput(vp); error = prison_canseemount(td->td_ucred, mp); - if (error) + if (error) { + vput(vp); + mtx_unlock(&Giant); return (error); + } #ifdef MAC error = mac_check_mount_stat(td->td_ucred, mp); if (error) { + vput(vp); mtx_unlock(&Giant); return (error); } @@ -4261,6 +4267,7 @@ kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) sp->f_namemax = NAME_MAX; sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; error = VFS_STATFS(mp, sp, td); + vput(vp); mtx_unlock(&Giant); if (error) return (error); |