Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/vfs_syscalls.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/vfs_syscalls.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.345 retrieving revision 1.345.6.2 diff -u -p -r1.345 -r1.345.6.2 --- src/sys/kern/vfs_syscalls.c 2008/01/30 11:47:01 1.345 +++ src/sys/kern/vfs_syscalls.c 2008/06/02 13:24:14 1.345.6.2 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_syscalls.c,v 1.345 2008/01/30 11:47:01 ad Exp $ */ +/* $NetBSD: vfs_syscalls.c,v 1.345.6.2 2008/06/02 13:24:14 mjf Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -12,13 +12,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -70,7 +63,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.345 2008/01/30 11:47:01 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.345.6.2 2008/06/02 13:24:14 mjf Exp $"); #include "opt_compat_netbsd.h" #include "opt_compat_43.h" @@ -101,6 +94,8 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls #endif /* FILEASSOC */ #include #include +#include +#include #include #include @@ -193,11 +188,13 @@ mount_update(struct lwp *l, struct vnode if (error) goto out; - if (vfs_trybusy(mp, RW_WRITER, 0)) { + if (vfs_busy(mp, NULL)) { error = EPERM; goto out; } + mutex_enter(&mp->mnt_updating); + mp->mnt_flag &= ~MNT_OP_FLAGS; mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); @@ -248,7 +245,8 @@ mount_update(struct lwp *l, struct vnode if (mp->mnt_syncer != NULL) vfs_deallocate_syncvnode(mp); } - vfs_unbusy(mp, false); + mutex_exit(&mp->mnt_updating); + vfs_unbusy(mp, false, NULL); out: return (error); @@ -287,9 +285,16 @@ mount_get_vfsops(const char *fstype, str fstypename[0] = 'f'; #endif - if ((*vfsops = vfs_getopsbyname(fstypename)) == NULL) - return ENODEV; - return 0; + if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) + return 0; + + /* If we can autoload a vfs module, try again */ + (void)module_load(fstype, 0, NULL, MODULE_CLASS_VFS, true); + + if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) + return 0; + + return ENODEV; } static int @@ -341,9 +346,12 @@ mount_domount(struct lwp *l, struct vnod mp->mnt_refcnt = 1; TAILQ_INIT(&mp->mnt_vnodelist); - rw_init(&mp->mnt_lock); + rw_init(&mp->mnt_unmounting); mutex_init(&mp->mnt_renamelock, MUTEX_DEFAULT, IPL_NONE); - (void)vfs_busy(mp, RW_WRITER, 0); + mutex_init(&mp->mnt_updating, MUTEX_DEFAULT, IPL_NONE); + error = vfs_busy(mp, NULL); + KASSERT(error == 0); + mutex_enter(&mp->mnt_updating); mp->mnt_vnodecovered = vp; mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred); @@ -370,8 +378,8 @@ mount_domount(struct lwp *l, struct vnod cache_purge(vp); if (error != 0) { vp->v_mountedhere = NULL; - mp->mnt_op->vfs_refcount--; - vfs_unbusy(mp, false); + mutex_exit(&mp->mnt_updating); + vfs_unbusy(mp, false, NULL); vfs_destroy(mp); return error; } @@ -386,13 +394,17 @@ mount_domount(struct lwp *l, struct vnod checkdirs(vp); if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) error = vfs_allocate_syncvnode(mp); - vfs_unbusy(mp, false); + /* Hold an additional reference to the mount across VFS_START(). */ + mutex_exit(&mp->mnt_updating); + vfs_unbusy(mp, true, NULL); (void) VFS_STATVFS(mp, &mp->mnt_stat); error = VFS_START(mp, 0); if (error) { vrele(vp); vfs_destroy(mp); } + /* Drop reference held for VFS_START(). */ + vfs_destroy(mp); *vpp = NULL; return error; } @@ -419,15 +431,17 @@ mount_getargs(struct lwp *l, struct vnod if ((vp->v_vflag & VV_ROOT) == 0) return EINVAL; - if (vfs_trybusy(mp, RW_WRITER, NULL)) + if (vfs_busy(mp, NULL)) return EPERM; + mutex_enter(&mp->mnt_updating); mp->mnt_flag &= ~MNT_OP_FLAGS; mp->mnt_flag |= MNT_GETARGS; error = VFS_MOUNT(mp, path, data, data_len); mp->mnt_flag &= ~MNT_OP_FLAGS; + mutex_exit(&mp->mnt_updating); - vfs_unbusy(mp, false); + vfs_unbusy(mp, false, NULL); return (error); } @@ -488,18 +502,22 @@ do_sys_mount(struct lwp *l, struct vfsop * A lookup in VFS_MOUNT might result in an attempt to * lock this vnode again, so make the lock recursive. */ - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - recurse = vn_setrecurse(vp); - if (vfsops == NULL) { - if (flags & (MNT_GETARGS | MNT_UPDATE)) + if (flags & (MNT_GETARGS | MNT_UPDATE)) { + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + recurse = vn_setrecurse(vp); vfsops = vp->v_mount->mnt_op; - else { + } else { /* 'type' is userspace */ error = mount_get_vfsops(type, &vfsops); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + recurse = vn_setrecurse(vp); if (error != 0) goto done; } + } else { + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + recurse = vn_setrecurse(vp); } if (data != NULL && data_seg == UIO_USERSPACE) { @@ -564,32 +582,59 @@ void checkdirs(struct vnode *olddp) { struct cwdinfo *cwdi; - struct vnode *newdp; + struct vnode *newdp, *rele1, *rele2; struct proc *p; + bool retry; if (olddp->v_usecount == 1) return; if (VFS_ROOT(olddp->v_mountedhere, &newdp)) panic("mount: lost mount"); - mutex_enter(&proclist_lock); - PROCLIST_FOREACH(p, &allproc) { - cwdi = p->p_cwdi; - if (!cwdi) - continue; - rw_enter(&cwdi->cwdi_lock, RW_WRITER); - if (cwdi->cwdi_cdir == olddp) { - vrele(cwdi->cwdi_cdir); - VREF(newdp); - cwdi->cwdi_cdir = newdp; - } - if (cwdi->cwdi_rdir == olddp) { - vrele(cwdi->cwdi_rdir); - VREF(newdp); - cwdi->cwdi_rdir = newdp; + + do { + retry = false; + mutex_enter(proc_lock); + PROCLIST_FOREACH(p, &allproc) { + if ((p->p_flag & PK_MARKER) != 0) + continue; + if ((cwdi = p->p_cwdi) == NULL) + continue; + /* + * Can't change to the old directory any more, + * so even if we see a stale value it's not a + * problem. + */ + if (cwdi->cwdi_cdir != olddp && + cwdi->cwdi_rdir != olddp) + continue; + retry = true; + rele1 = NULL; + rele2 = NULL; + atomic_inc_uint(&cwdi->cwdi_refcnt); + mutex_exit(proc_lock); + rw_enter(&cwdi->cwdi_lock, RW_WRITER); + if (cwdi->cwdi_cdir == olddp) { + rele1 = cwdi->cwdi_cdir; + VREF(newdp); + cwdi->cwdi_cdir = newdp; + } + if (cwdi->cwdi_rdir == olddp) { + rele2 = cwdi->cwdi_rdir; + VREF(newdp); + cwdi->cwdi_rdir = newdp; + } + rw_exit(&cwdi->cwdi_lock); + cwdfree(cwdi); + if (rele1 != NULL) + vrele(rele1); + if (rele2 != NULL) + vrele(rele2); + mutex_enter(proc_lock); + break; } - rw_exit(&cwdi->cwdi_lock); - } - mutex_exit(&proclist_lock); + mutex_exit(proc_lock); + } while (retry); + if (rootvnode == olddp) { vrele(rootvnode); VREF(newdp); @@ -623,12 +668,14 @@ sys_unmount(struct lwp *l, const struct return (error); vp = nd.ni_vp; mp = vp->v_mount; + atomic_inc_uint(&mp->mnt_refcnt); VOP_UNLOCK(vp, 0); error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL); if (error) { vrele(vp); + vfs_destroy(mp); return (error); } @@ -637,6 +684,7 @@ sys_unmount(struct lwp *l, const struct */ if (mp->mnt_flag & MNT_ROOTFS) { vrele(vp); + vfs_destroy(mp); return (EINVAL); } @@ -645,27 +693,21 @@ sys_unmount(struct lwp *l, const struct */ if ((vp->v_vflag & VV_ROOT) == 0) { vrele(vp); + vfs_destroy(mp); return (EINVAL); } - /* - * XXX Freeze syncer. Must do this before locking the - * mount point. See dounmount() for details. - */ - mutex_enter(&syncer_mutex); - error = vfs_busy(mp, RW_WRITER, NULL); vrele(vp); - if (error != 0) { - mutex_exit(&syncer_mutex); - return (error); - } - - return (dounmount(mp, SCARG(uap, flags), l)); + error = dounmount(mp, SCARG(uap, flags), l); + return error; } /* - * Do the actual file system unmount. File system is assumed to have been - * marked busy by the caller. + * Do the actual file system unmount. File system is assumed to have + * been locked by the caller. + * + * => Caller gain reference to the mount, explicility for unmount. + * => Reference will be dropped in all cases. */ int dounmount(struct mount *mp, int flags, struct lwp *l) @@ -675,14 +717,25 @@ dounmount(struct mount *mp, int flags, s int async; int used_syncer; - KASSERT(rw_write_held(&mp->mnt_lock)); - #if NVERIEXEC > 0 error = veriexec_unmountchk(mp); if (error) return (error); #endif /* NVERIEXEC > 0 */ + /* + * XXX Freeze syncer. Must do this before locking the + * mount point. See dounmount() for details. + */ + mutex_enter(&syncer_mutex); + rw_enter(&mp->mnt_unmounting, RW_WRITER); + if ((mp->mnt_iflag & IMNT_GONE) != 0) { + rw_exit(&mp->mnt_unmounting); + mutex_exit(&syncer_mutex); + vfs_destroy(mp); + return ENOENT; + } + used_syncer = (mp->mnt_syncer != NULL); /* @@ -724,25 +777,26 @@ dounmount(struct mount *mp, int flags, s (void) vfs_allocate_syncvnode(mp); mp->mnt_iflag &= ~IMNT_UNMOUNT; mp->mnt_flag |= async; + rw_exit(&mp->mnt_unmounting); if (used_syncer) mutex_exit(&syncer_mutex); - vfs_unbusy(mp, false); return (error); } vfs_scrubvnlist(mp); mutex_enter(&mountlist_lock); - CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) coveredvp->v_mountedhere = NULL; + CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); + mp->mnt_iflag |= IMNT_GONE; mutex_exit(&mountlist_lock); if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL) panic("unmount: dangling vnode"); - mp->mnt_iflag |= IMNT_GONE; if (used_syncer) mutex_exit(&syncer_mutex); vfs_hooks_unmount(mp); - vfs_unbusy(mp, false); - vfs_destroy(mp); + rw_exit(&mp->mnt_unmounting); + vfs_destroy(mp); /* caller provided reference */ + vfs_destroy(mp); /* from mount(), final nail in coffin */ if (coveredvp != NULLVP) vrele(coveredvp); return (0); @@ -767,11 +821,12 @@ sys_sync(struct lwp *l, const void *v, r l = &lwp0; mutex_enter(&mountlist_lock); - for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) { - if (vfs_trybusy(mp, RW_READER, &mountlist_lock)) { - nmp = mp->mnt_list.cqe_prev; + for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; + mp = nmp) { + if (vfs_busy(mp, &nmp)) { continue; } + mutex_enter(&mp->mnt_updating); if ((mp->mnt_flag & MNT_RDONLY) == 0) { asyncflag = mp->mnt_flag & MNT_ASYNC; mp->mnt_flag &= ~MNT_ASYNC; @@ -779,10 +834,8 @@ sys_sync(struct lwp *l, const void *v, r if (asyncflag) mp->mnt_flag |= MNT_ASYNC; } - mutex_enter(&mountlist_lock); - nmp = mp->mnt_list.cqe_prev; - vfs_unbusy(mp, false); - + mutex_exit(&mp->mnt_updating); + vfs_unbusy(mp, false, &nmp); } mutex_exit(&mountlist_lock); #ifdef DEBUG @@ -850,6 +903,7 @@ done: if (cwdi->cwdi_rdir != NULL) { size_t len; char *bp; + char c; char *path = PNBUF_GET(); bp = path + MAXPATHLEN; @@ -869,8 +923,9 @@ done: * rest we cannot see, so we don't allow viewing the * data. */ - if (strncmp(bp, sp->f_mntonname, len) == 0) { - strlcpy(sp->f_mntonname, &sp->f_mntonname[len], + if (strncmp(bp, sp->f_mntonname, len) == 0 && + ((c = sp->f_mntonname[len]) == '/' || c == '\0')) { + (void)strlcpy(sp->f_mntonname, &sp->f_mntonname[len], sizeof(sp->f_mntonname)); if (sp->f_mntonname[0] == '\0') (void)strlcpy(sp->f_mntonname, "/", @@ -933,17 +988,16 @@ sys_statvfs1(struct lwp *l, const struct int do_sys_fstatvfs(struct lwp *l, int fd, int flags, struct statvfs *sb) { - struct proc *p = l->l_proc; - struct file *fp; + file_t *fp; struct mount *mp; int error; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, fd, &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(fd, &fp)) != 0) return (error); mp = ((struct vnode *)fp->f_data)->v_mount; - error = dostatvfs(mp, sb, l, flags, 1); - FILE_UNUSE(fp, l); + error = dostatvfs(mp, sb, curlwp, flags, 1); + fd_putfile(fd); return error; } @@ -989,33 +1043,29 @@ do_sys_getvfsstat(struct lwp *l, void *s count = 0; for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; mp = nmp) { - if (vfs_trybusy(mp, RW_READER, &mountlist_lock)) { - nmp = CIRCLEQ_NEXT(mp, mnt_list); + if (vfs_busy(mp, &nmp)) { continue; } if (sfsp && count < maxcount) { error = dostatvfs(mp, sb, l, flags, 0); if (error) { - mutex_enter(&mountlist_lock); - nmp = CIRCLEQ_NEXT(mp, mnt_list); - vfs_unbusy(mp, false); + vfs_unbusy(mp, false, &nmp); + error = 0; continue; } error = copyfn(sb, sfsp, entry_sz); if (error) { - vfs_unbusy(mp, false); + vfs_unbusy(mp, false, NULL); goto out; } sfsp = (char *)sfsp + entry_sz; root |= strcmp(sb->f_mntonname, "/") == 0; } count++; - mutex_enter(&mountlist_lock); - nmp = CIRCLEQ_NEXT(mp, mnt_list); - vfs_unbusy(mp, false); + vfs_unbusy(mp, false, &nmp); } - mutex_exit(&mountlist_lock); + if (root == 0 && p->p_cwdi->cwdi_rdir) { /* * fake a root entry @@ -1024,8 +1074,11 @@ do_sys_getvfsstat(struct lwp *l, void *s sb, l, flags, 1); if (error != 0) goto out; - if (sfsp) + if (sfsp) { error = copyfn(sb, sfsp, entry_sz); + if (error != 0) + goto out; + } count++; } if (sfsp && count > maxcount) @@ -1061,17 +1114,17 @@ sys_fchdir(struct lwp *l, const struct s syscallarg(int) fd; } */ struct proc *p = l->l_proc; - struct filedesc *fdp = p->p_fd; struct cwdinfo *cwdi; struct vnode *vp, *tdp; struct mount *mp; - struct file *fp; - int error; + file_t *fp; + int error, fd; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + fd = SCARG(uap, fd); + if ((error = fd_getvnode(fd, &fp)) != 0) return (error); - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; VREF(vp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); @@ -1084,11 +1137,12 @@ sys_fchdir(struct lwp *l, const struct s goto out; } while ((mp = vp->v_mountedhere) != NULL) { - if (vfs_busy(mp, RW_READER, NULL)) - continue; + error = vfs_busy(mp, NULL); vput(vp); + if (error != 0) + goto out; error = VFS_ROOT(mp, &tdp); - vfs_unbusy(mp, false); + vfs_unbusy(mp, false, NULL); if (error) goto out; vp = tdp; @@ -1111,7 +1165,7 @@ sys_fchdir(struct lwp *l, const struct s rw_exit(&cwdi->cwdi_lock); out: - FILE_UNUSE(fp, l); + fd_putfile(fd); return (error); } @@ -1123,19 +1177,18 @@ int sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval) { struct proc *p = l->l_proc; - struct filedesc *fdp = p->p_fd; struct cwdinfo *cwdi; struct vnode *vp; - struct file *fp; - int error; + file_t *fp; + int error, fd = SCARG(uap, fd); if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT, KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0) return error; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return error; - vp = (struct vnode *) fp->f_data; + vp = fp->f_data; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (vp->v_type != VDIR) error = ENOTDIR; @@ -1169,7 +1222,7 @@ sys_fchroot(struct lwp *l, const struct rw_exit(&cwdi->cwdi_lock); out: - FILE_UNUSE(fp, l); + fd_putfile(fd); return (error); } @@ -1288,8 +1341,7 @@ sys_open(struct lwp *l, const struct sys } */ struct proc *p = l->l_proc; struct cwdinfo *cwdi = p->p_cwdi; - struct filedesc *fdp = p->p_fd; - struct file *fp; + file_t *fp; struct vnode *vp; int flags, cmode; int type, indx, error; @@ -1299,8 +1351,7 @@ sys_open(struct lwp *l, const struct sys flags = FFLAGS(SCARG(uap, flags)); if ((flags & (FREAD | FWRITE)) == 0) return (EINVAL); - /* falloc() will use the file descriptor for us */ - if ((error = falloc(l, &fp, &indx)) != 0) + if ((error = fd_allocfile(&fp, &indx)) != 0) return (error); /* We're going to read cwdi->cwdi_cmask unlocked here. */ cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT; @@ -1308,21 +1359,16 @@ sys_open(struct lwp *l, const struct sys SCARG(uap, path)); l->l_dupfd = -indx - 1; /* XXX check for fdopen */ if ((error = vn_open(&nd, flags, cmode)) != 0) { - rw_enter(&fdp->fd_lock, RW_WRITER); - FILE_UNUSE(fp, l); - fdp->fd_ofiles[indx] = NULL; - rw_exit(&fdp->fd_lock); - ffree(fp); + fd_abort(p, fp, indx); if ((error == EDUPFD || error == EMOVEFD) && l->l_dupfd >= 0 && /* XXX from fdopen */ (error = - dupfdopen(l, indx, l->l_dupfd, flags, error)) == 0) { + fd_dupopen(l->l_dupfd, &indx, flags, error)) == 0) { *retval = indx; return (0); } if (error == ERESTART) error = EINTR; - fdremove(fdp, indx); return (error); } @@ -1346,19 +1392,16 @@ sys_open(struct lwp *l, const struct sys VOP_UNLOCK(vp, 0); error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type); if (error) { - (void) vn_close(vp, fp->f_flag, fp->f_cred, l); - FILE_UNUSE(fp, l); - ffree(fp); - fdremove(fdp, indx); + (void) vn_close(vp, fp->f_flag, fp->f_cred); + fd_abort(p, fp, indx); return (error); } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - fp->f_flag |= FHASLOCK; + atomic_or_uint(&fp->f_flag, FHASLOCK); } VOP_UNLOCK(vp, 0); *retval = indx; - FILE_SET_MATURE(fp); - FILE_UNUSE(fp, l); + fd_affix(p, fp, indx); return (0); } @@ -1599,16 +1642,18 @@ int dofhopen(struct lwp *l, const void *ufhp, size_t fhsize, int oflags, register_t *retval) { - struct filedesc *fdp = l->l_proc->p_fd; - struct file *fp; + file_t *fp; struct vnode *vp = NULL; kauth_cred_t cred = l->l_cred; - struct file *nfp; + file_t *nfp; int type, indx, error=0; struct flock lf; struct vattr va; fhandle_t *fh; int flags; + proc_t *p; + + p = curproc; /* * Must be super user @@ -1622,8 +1667,7 @@ dofhopen(struct lwp *l, const void *ufhp return (EINVAL); if ((flags & O_CREAT)) return (EINVAL); - /* falloc() will use the file descriptor for us */ - if ((error = falloc(l, &nfp, &indx)) != 0) + if ((error = fd_allocfile(&nfp, &indx)) != 0) return (error); fp = nfp; error = vfs_copyinfh_alloc(ufhp, fhsize, &fh); @@ -1655,8 +1699,11 @@ dofhopen(struct lwp *l, const void *ufhp } if ((error = VOP_OPEN(vp, flags, cred)) != 0) goto bad; - if (flags & FWRITE) + if (flags & FWRITE) { + mutex_enter(&vp->v_interlock); vp->v_writecount++; + mutex_exit(&vp->v_interlock); + } /* done with modified vn_open, now finish what sys_open does. */ @@ -1678,26 +1725,21 @@ dofhopen(struct lwp *l, const void *ufhp VOP_UNLOCK(vp, 0); error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type); if (error) { - (void) vn_close(vp, fp->f_flag, fp->f_cred, l); - FILE_UNUSE(fp, l); - ffree(fp); - fdremove(fdp, indx); + (void) vn_close(vp, fp->f_flag, fp->f_cred); + fd_abort(p, fp, indx); return (error); } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - fp->f_flag |= FHASLOCK; + atomic_or_uint(&fp->f_flag, FHASLOCK); } VOP_UNLOCK(vp, 0); *retval = indx; - FILE_SET_MATURE(fp); - FILE_UNUSE(fp, l); + fd_affix(p, fp, indx); vfs_copyinfh_free(fh); return (0); bad: - FILE_UNUSE(fp, l); - ffree(fp); - fdremove(fdp, indx); + fd_abort(p, fp, indx); if (vp != NULL) vput(vp); vfs_copyinfh_free(fh); @@ -1740,7 +1782,7 @@ do_fhstat(struct lwp *l, const void *ufh if (error != 0) return error; - error = vn_stat(vp, sb, l); + error = vn_stat(vp, sb); vput(vp); return error; } @@ -2163,55 +2205,47 @@ sys_lseek(struct lwp *l, const struct sy syscallarg(off_t) offset; syscallarg(int) whence; } */ - struct proc *p = l->l_proc; kauth_cred_t cred = l->l_cred; - struct filedesc *fdp = p->p_fd; - struct file *fp; + file_t *fp; struct vnode *vp; struct vattr vattr; off_t newoff; - int error; + int error, fd; - if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) + fd = SCARG(uap, fd); + + if ((fp = fd_getfile(fd)) == NULL) return (EBADF); - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { error = ESPIPE; - FILE_UNLOCK(fp); goto out; } switch (SCARG(uap, whence)) { case SEEK_CUR: newoff = fp->f_offset + SCARG(uap, offset); - FILE_USE(fp); break; case SEEK_END: - FILE_USE(fp); error = VOP_GETATTR(vp, &vattr, cred); if (error) { - FILE_UNUSE(fp, l); goto out; } newoff = SCARG(uap, offset) + vattr.va_size; break; case SEEK_SET: - FILE_USE(fp); newoff = SCARG(uap, offset); break; default: - FILE_UNLOCK(fp); error = EINVAL; goto out; } if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) == 0) { - FILE_LOCK(fp); *(off_t *)retval = fp->f_offset = newoff; - FILE_UNLOCK(fp); } - FILE_UNUSE(fp, l); out: + fd_putfile(fd); return (error); } @@ -2227,24 +2261,20 @@ sys_pread(struct lwp *l, const struct sy syscallarg(size_t) nbyte; syscallarg(off_t) offset; } */ - struct proc *p = l->l_proc; - struct filedesc *fdp = p->p_fd; - struct file *fp; + file_t *fp; struct vnode *vp; off_t offset; int error, fd = SCARG(uap, fd); - if ((fp = fd_getfile(fdp, fd)) == NULL) + if ((fp = fd_getfile(fd)) == NULL) return (EBADF); if ((fp->f_flag & FREAD) == 0) { - FILE_UNLOCK(fp); + fd_putfile(fd); return (EBADF); } - FILE_USE(fp); - - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { error = ESPIPE; goto out; @@ -2264,7 +2294,7 @@ sys_pread(struct lwp *l, const struct sy &offset, 0, retval)); out: - FILE_UNUSE(fp, l); + fd_putfile(fd); return (error); } @@ -2298,24 +2328,20 @@ sys_pwrite(struct lwp *l, const struct s syscallarg(size_t) nbyte; syscallarg(off_t) offset; } */ - struct proc *p = l->l_proc; - struct filedesc *fdp = p->p_fd; - struct file *fp; + file_t *fp; struct vnode *vp; off_t offset; int error, fd = SCARG(uap, fd); - if ((fp = fd_getfile(fdp, fd)) == NULL) + if ((fp = fd_getfile(fd)) == NULL) return (EBADF); if ((fp->f_flag & FWRITE) == 0) { - FILE_UNLOCK(fp); + fd_putfile(fd); return (EBADF); } - FILE_USE(fp); - - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { error = ESPIPE; goto out; @@ -2335,7 +2361,7 @@ sys_pwrite(struct lwp *l, const struct s &offset, 0, retval)); out: - FILE_UNUSE(fp, l); + fd_putfile(fd); return (error); } @@ -2407,8 +2433,7 @@ out: * Common code for all sys_stat functions, including compat versions. */ int -do_sys_stat(struct lwp *l, const char *path, unsigned int nd_flags, - struct stat *sb) +do_sys_stat(const char *path, unsigned int nd_flags, struct stat *sb) { int error; struct nameidata nd; @@ -2418,7 +2443,7 @@ do_sys_stat(struct lwp *l, const char *p error = namei(&nd); if (error != 0) return error; - error = vn_stat(nd.ni_vp, sb, l); + error = vn_stat(nd.ni_vp, sb); vput(nd.ni_vp); return error; } @@ -2437,7 +2462,7 @@ sys___stat30(struct lwp *l, const struct struct stat sb; int error; - error = do_sys_stat(l, SCARG(uap, path), FOLLOW, &sb); + error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); if (error) return error; return copyout(&sb, SCARG(uap, ub), sizeof(sb)); @@ -2457,7 +2482,7 @@ sys___lstat30(struct lwp *l, const struc struct stat sb; int error; - error = do_sys_stat(l, SCARG(uap, path), NOFOLLOW, &sb); + error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); if (error) return error; return copyout(&sb, SCARG(uap, ub), sizeof(sb)); @@ -2565,18 +2590,17 @@ sys_fchflags(struct lwp *l, const struct syscallarg(int) fd; syscallarg(u_long) flags; } */ - struct proc *p = l->l_proc; struct vnode *vp; - struct file *fp; + file_t *fp; int error; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; error = change_flags(vp, SCARG(uap, flags), l); VOP_UNLOCK(vp, 0); - FILE_UNUSE(fp, l); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -2670,16 +2694,14 @@ sys_fchmod(struct lwp *l, const struct s syscallarg(int) fd; syscallarg(int) mode; } */ - struct proc *p = l->l_proc; - struct file *fp; + file_t *fp; int error; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); - - error = change_mode((struct vnode *)fp->f_data, SCARG(uap, mode), l); - FILE_UNUSE(fp, l); + error = change_mode(fp->f_data, SCARG(uap, mode), l); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -2790,17 +2812,15 @@ sys_fchown(struct lwp *l, const struct s syscallarg(uid_t) uid; syscallarg(gid_t) gid; } */ - struct proc *p = l->l_proc; int error; - struct file *fp; + file_t *fp; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); - - error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid), - SCARG(uap, gid), l, 0); - FILE_UNUSE(fp, l); + error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid), + l, 0); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -2816,17 +2836,15 @@ sys___posix_fchown(struct lwp *l, const syscallarg(uid_t) uid; syscallarg(gid_t) gid; } */ - struct proc *p = l->l_proc; int error; - struct file *fp; + file_t *fp; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); - - error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid), - SCARG(uap, gid), l, 1); - FILE_UNUSE(fp, l); + error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid), + l, 1); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -2951,7 +2969,7 @@ sys_utimes(struct lwp *l, const struct s } */ return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW, - SCARG(uap, tptr), UIO_USERSPACE); + SCARG(uap, tptr), UIO_USERSPACE); } /* @@ -2966,16 +2984,14 @@ sys_futimes(struct lwp *l, const struct syscallarg(const struct timeval *) tptr; } */ int error; - struct file *fp; + file_t *fp; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); - - error = do_sys_utimes(l, fp->f_data, NULL, 0, - SCARG(uap, tptr), UIO_USERSPACE); - - FILE_UNUSE(fp, l); + error = do_sys_utimes(l, fp->f_data, NULL, 0, SCARG(uap, tptr), + UIO_USERSPACE); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -2992,7 +3008,7 @@ sys_lutimes(struct lwp *l, const struct } */ return do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW, - SCARG(uap, tptr), UIO_USERSPACE); + SCARG(uap, tptr), UIO_USERSPACE); } /* @@ -3089,20 +3105,19 @@ sys_ftruncate(struct lwp *l, const struc syscallarg(int) pad; syscallarg(off_t) length; } */ - struct proc *p = l->l_proc; struct vattr vattr; struct vnode *vp; - struct file *fp; + file_t *fp; int error; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); if ((fp->f_flag & FWRITE) == 0) { error = EINVAL; goto out; } - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if (vp->v_type == VDIR) error = EISDIR; @@ -3113,7 +3128,7 @@ sys_ftruncate(struct lwp *l, const struc } VOP_UNLOCK(vp, 0); out: - FILE_UNUSE(fp, l); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -3127,22 +3142,21 @@ sys_fsync(struct lwp *l, const struct sy /* { syscallarg(int) fd; } */ - struct proc *p = l->l_proc; struct vnode *vp; - struct file *fp; + file_t *fp; int error; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0); if (error == 0 && bioopsp != NULL && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)) (*bioopsp->io_fsync)(vp, 0); VOP_UNLOCK(vp, 0); - FILE_UNUSE(fp, l); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -3163,15 +3177,14 @@ sys_fsync_range(struct lwp *l, const str syscallarg(off_t) start; syscallarg(off_t) length; } */ - struct proc *p = l->l_proc; struct vnode *vp; - struct file *fp; + file_t *fp; int flags, nflags; off_t s, e, len; int error; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); if ((fp->f_flag & FWRITE) == 0) { @@ -3207,7 +3220,7 @@ sys_fsync_range(struct lwp *l, const str s = 0; } - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e); @@ -3217,7 +3230,7 @@ sys_fsync_range(struct lwp *l, const str VOP_UNLOCK(vp, 0); out: - FILE_UNUSE(fp, l); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -3231,23 +3244,22 @@ sys_fdatasync(struct lwp *l, const struc /* { syscallarg(int) fd; } */ - struct proc *p = l->l_proc; struct vnode *vp; - struct file *fp; + file_t *fp; int error; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); if ((fp->f_flag & FWRITE) == 0) { - FILE_UNUSE(fp, l); + fd_putfile(SCARG(uap, fd)); return (EBADF); } - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0); VOP_UNLOCK(vp, 0); - FILE_UNUSE(fp, l); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -3337,6 +3349,17 @@ do_sys_rename(const char *from, const ch * in nfs_serv.c. Proceed accordingly. */ vrele(fvp); + if ((fromnd.ni_cnd.cn_namelen == 1 && + fromnd.ni_cnd.cn_nameptr[0] == '.') || + (fromnd.ni_cnd.cn_namelen == 2 && + fromnd.ni_cnd.cn_nameptr[0] == '.' && + fromnd.ni_cnd.cn_nameptr[1] == '.')) { + error = EINVAL; + VFS_RENAMELOCK_EXIT(fs); + VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); + vrele(fromnd.ni_dvp); + goto out1; + } saveflag = fromnd.ni_cnd.cn_flags & SAVESTART; fromnd.ni_cnd.cn_flags &= ~SAVESTART; vn_lock(fromnd.ni_dvp, LK_EXCLUSIVE | LK_RETRY); @@ -3515,7 +3538,7 @@ sys_rmdir(struct lwp *l, const struct sy /* * The root of a mounted filesystem cannot be deleted. */ - if (vp->v_vflag & VV_ROOT) { + if ((vp->v_vflag & VV_ROOT) != 0 || vp->v_mountedhere != NULL) { error = EBUSY; goto out; } @@ -3543,12 +3566,11 @@ sys___getdents30(struct lwp *l, const st syscallarg(char *) buf; syscallarg(size_t) count; } */ - struct proc *p = l->l_proc; - struct file *fp; + file_t *fp; int error, done; - /* getvnode() will use the descriptor for us */ - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + /* fd_getvnode() will use the descriptor for us */ + if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { error = EBADF; @@ -3559,7 +3581,7 @@ sys___getdents30(struct lwp *l, const st ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, buf), done, error); *retval = done; out: - FILE_UNUSE(fp, l); + fd_putfile(SCARG(uap, fd)); return (error); } @@ -3635,24 +3657,22 @@ sys_revoke(struct lwp *l, const struct s * Convert a user file descriptor to a kernel file entry. */ int -getvnode(struct filedesc *fdp, int fd, struct file **fpp) +getvnode(int fd, file_t **fpp) { struct vnode *vp; - struct file *fp; + file_t *fp; - if ((fp = fd_getfile(fdp, fd)) == NULL) + if ((fp = fd_getfile(fd)) == NULL) return (EBADF); - FILE_USE(fp); - if (fp->f_type != DTYPE_VNODE) { - FILE_UNUSE(fp, NULL); + fd_putfile(fd); return (EINVAL); } - vp = (struct vnode *)fp->f_data; + vp = fp->f_data; if (vp->v_type == VBAD) { - FILE_UNUSE(fp, NULL); + fd_putfile(fd); return (EBADF); }