From fad57d0edbfceb0cebfb1dce61490df78fcc4a97 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 12 Nov 2004 00:09:56 +0000 Subject: [PATCH] VFS messaging/interfacing work stage 9/99: VFS 'NEW' API WORK. NOTE: unionfs and nullfs are temporarily broken by this commit. * Remove the old namecache API. Remove vfs_cache_lookup(), cache_lookup(), cache_enter(), namei() and lookup() are all gone. VOP_LOOKUP() and VOP_CACHEDLOOKUP() have been collapsed into a single non-caching VOP_LOOKUP(). * Complete the new VFS CACHE (namecache) API. The new API is able to supply topological guarentees and is able to reserve namespaces, including negative cache spaces (whether the target name exists or not), which the new API uses to reserve namespace for things like NRENAME and NCREATE (and others). * Complete the new namecache API. VOP_NRESOLVE, NLOOKUPDOTDOT, NCREATE, NMKDIR, NMKNOD, NLINK, NSYMLINK, NWHITEOUT, NRENAME, NRMDIR, NREMOVE. These new calls take (typicaly locked) namecache pointers rather then combinations of directory vnodes, file vnodes, and name components. The new calls are *MUCH* simpler in concept and implementation. For example, VOP_RENAME() has 8 arguments while VOP_NRENAME() has only 3 arguments. The new namecache API uses the namecache to lock namespaces without having to lock the underlying vnodes. For example, this allows the kernel to reserve the target name of a create function trivially. Namecache records are maintained BY THE KERNEL for both positive and negative hits. Generally speaking, the kernel layer is now responsible for resolving path elements. NRESOLVE is called when an unresolved namecache record needs to be resolved. Unlike the old VOP_LOOKUP, NRESOLVE is simply responsible for associating a vnode to a namecache record (positive hit) or telling the system that it's a negative hit, and not responsible for handling symlinks or other special cases or doing any of the other path lookup work, much unlike the old VOP_LOOKUP. It should be particularly noted that the new namecache topology does not allow disconnected namecache records. In rare cases where a vnode must be converted to a namecache pointer for new API operation via a file handle (i.e. NFS), the cache_fromdvp() function is provided and a new API VOP, VOP_NLOOKUPDOTDOT() is provided to allow the namecache to resolve the topology leading up to the requested vnode. These and other topological guarentees greatly reduce the complexity of the new namecache API. The new namei() is called nlookup(). This function uses a combination of cache_n*() calls, VOP_NRESOLVE(), and standard VOP calls resolve the supplied path, deal with symlinks, and so forth, in a nice small compact compartmentalized procedure. * The old VFS code is no longer responsible for maintaining namecache records, a function which was mostly adhoc cache_purge()s occuring before the VFS actually knows whether an operation will succeed or not. The new VFS code is typically responsible for adjusting the state of locked namecache records passed into it. For example, if NCREATE succeeds it must call cache_setvp() to associate the passed namecache record with the vnode representing the successfully created file. The new requirements are much less complex then the old requirements. * Most VFSs still implement the old API calls, albeit somewhat modified and in particular the VOP_LOOKUP function is now *MUCH* simpler. However, the kernel now uses the new API calls almost exclusively and relies on compatibility code installed in the default ops (vop_compat_*()) to convert the new calls to the old calls. * All kernel system calls and related support functions which used to do complex and confusing namei() operations now do far less complex and far less confusing nlookup() operations. * SPECOPS shortcutting has been implemented. User reads and writes now go directly to supporting functions which talk to the device via fileops rather then having to be routed through VOP_READ or VOP_WRITE, saving significant overhead. Note, however, that these only really effect /dev/null and /dev/zero. Implementing this was fairly easy, we now simply pass an optional struct file pointer to VOP_OPEN() and let spec_open() handle the override. SPECIAL NOTES: It should be noted that we must still lock a directory vnode LK_EXCLUSIVE before issuing a VOP_LOOKUP(), even for simple lookups, because a number of VFS's (including UFS) store active directory scanning information in the directory vnode. The legacy NAMEI_LOOKUP cases can be changed to use LK_SHARED once these VFS cases are fixed. In particular, we are now organized well enough to actually be able to do record locking within a directory for handling NCREATE, NDELETE, and NRENAME situations, but it hasn't been done yet. Many thanks to all of the testers and in particular David Rhodus for finding a large number of panics and other issues. --- sys/checkpt/checkpt.c | 19 +- sys/dev/disk/ccd/ccd.c | 35 +- sys/dev/disk/vn/vn.c | 52 +- sys/dev/misc/streams/streams.c | 11 +- sys/emulation/43bsd/43bsd_file.c | 29 +- sys/emulation/ibcs2/coff/imgact_coff.c | 30 +- sys/emulation/ibcs2/i386/ibcs2_stat.c | 31 +- sys/emulation/ibcs2/i386/ibcs2_util.c | 91 +- sys/emulation/ibcs2/i386/ibcs2_xenix.c | 23 +- sys/emulation/linux/i386/linux_machdep.c | 17 +- sys/emulation/linux/linux_file.c | 194 ++- sys/emulation/linux/linux_getcwd.c | 417 +----- sys/emulation/linux/linux_misc.c | 75 +- sys/emulation/linux/linux_stats.c | 14 +- sys/emulation/linux/linux_uid16.c | 30 +- sys/emulation/linux/linux_util.c | 63 +- sys/emulation/ndis/subr_ndis.c | 27 +- sys/emulation/svr4/svr4_misc.c | 31 +- sys/emulation/svr4/svr4_sysvec.c | 81 +- sys/kern/imgact_elf.c | 44 +- sys/kern/kern_acct.c | 42 +- sys/kern/kern_acl.c | 97 +- sys/kern/kern_clock.c | 79 +- sys/kern/kern_descrip.c | 133 +- sys/kern/kern_event.c | 3 +- sys/kern/kern_exec.c | 76 +- sys/kern/kern_fp.c | 86 +- sys/kern/kern_ktrace.c | 33 +- sys/kern/kern_linker.c | 24 +- sys/kern/kern_sig.c | 23 +- sys/kern/link_aout.c | 30 +- sys/kern/link_elf.c | 34 +- sys/kern/sys_pipe.c | 4 +- sys/kern/tty_tty.c | 4 +- sys/kern/uipc_syscalls.c | 8 +- sys/kern/uipc_usrreq.c | 67 +- sys/kern/vfs_cache.c | 905 ++++++------- sys/kern/vfs_default.c | 936 +++++++++++++- sys/kern/vfs_lookup.c | 668 +--------- sys/kern/vfs_nlookup.c | 128 +- sys/kern/vfs_subr.c | 39 +- sys/kern/vfs_syscalls.c | 1504 +++++++++++----------- sys/kern/vfs_vnops.c | 316 ++++- sys/kern/vfs_vopops.c | 535 ++++++-- sys/opencrypto/cryptodev.c | 3 +- sys/sys/buf2.h | 5 +- sys/sys/file.h | 5 +- sys/sys/filedesc.h | 5 +- sys/sys/kern_syscall.h | 37 +- sys/sys/mount.h | 10 +- sys/sys/namecache.h | 20 +- sys/sys/namei.h | 125 +- sys/sys/nlookup.h | 28 +- sys/sys/vfsops.h | 314 +++-- sys/sys/vnode.h | 21 +- sys/vfs/coda/coda_fbsd.c | 4 +- sys/vfs/coda/coda_vfsops.c | 19 +- sys/vfs/coda/coda_vnops.c | 68 +- sys/vfs/gnu/ext2fs/ext2_extern.h | 4 +- sys/vfs/gnu/ext2fs/ext2_lookup.c | 46 +- sys/vfs/gnu/ext2fs/ext2_vfsops.c | 30 +- sys/vfs/gnu/ext2fs/ext2_vnops.c | 175 ++- sys/vfs/hpfs/hpfs_vfsops.c | 58 +- sys/vfs/hpfs/hpfs_vnops.c | 24 +- sys/vfs/isofs/cd9660/cd9660_lookup.c | 21 +- sys/vfs/isofs/cd9660/cd9660_node.h | 6 +- sys/vfs/isofs/cd9660/cd9660_vfsops.c | 22 +- sys/vfs/isofs/cd9660/cd9660_vnops.c | 5 +- sys/vfs/msdosfs/denode.h | 4 +- sys/vfs/msdosfs/msdosfs_lookup.c | 31 +- sys/vfs/msdosfs/msdosfs_vfsops.c | 19 +- sys/vfs/msdosfs/msdosfs_vnops.c | 190 +-- sys/vfs/nfs/nfs.h | 14 +- sys/vfs/nfs/nfs_nqlease.c | 4 +- sys/vfs/nfs/nfs_serv.c | 757 +++++------ sys/vfs/nfs/nfs_socket.c | 4 +- sys/vfs/nfs/nfs_subs.c | 250 ++-- sys/vfs/nfs/nfs_syscalls.c | 26 +- sys/vfs/nfs/nfs_vnops.c | 367 +++--- sys/vfs/ntfs/ntfs_vfsops.c | 52 +- sys/vfs/ntfs/ntfs_vnops.c | 37 +- sys/vfs/nullfs/null_vfsops.c | 31 +- sys/vfs/nullfs/null_vnops.c | 60 +- sys/vfs/nwfs/nwfs_io.c | 8 +- sys/vfs/nwfs/nwfs_vnops.c | 88 +- sys/vfs/procfs/procfs_vnops.c | 5 +- sys/vfs/smbfs/smbfs_io.c | 11 +- sys/vfs/smbfs/smbfs_vnops.c | 99 +- sys/vfs/specfs/spec_vnops.c | 12 +- sys/vfs/udf/udf_vfsops.c | 22 +- sys/vfs/udf/udf_vnops.c | 25 +- sys/vfs/ufs/ffs_vfsops.c | 84 +- sys/vfs/ufs/ufs_extern.h | 6 +- sys/vfs/ufs/ufs_lookup.c | 55 +- sys/vfs/ufs/ufs_quota.c | 28 +- sys/vfs/ufs/ufs_vnops.c | 164 ++- sys/vfs/ufs/ufsmount.h | 3 +- sys/vfs/umapfs/umap_vfsops.c | 23 +- sys/vfs/union/union_subr.c | 63 +- sys/vfs/union/union_vfsops.c | 29 +- sys/vfs/union/union_vnops.c | 34 +- sys/vm/device_pager.c | 4 +- sys/vm/vm_object.c | 19 +- sys/vm/vm_swap.c | 20 +- 104 files changed, 5549 insertions(+), 5242 deletions(-) diff --git a/sys/checkpt/checkpt.c b/sys/checkpt/checkpt.c index 9ea63977de..1a1cd837dc 100644 --- a/sys/checkpt/checkpt.c +++ b/sys/checkpt/checkpt.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/checkpt/Attic/checkpt.c,v 1.5 2004/06/03 10:00:06 eirikn Exp $ + * $DragonFly: src/sys/checkpt/Attic/checkpt.c,v 1.6 2004/11/12 00:09:00 dillon Exp $ */ #include @@ -450,7 +450,9 @@ elf_getsigs(struct proc *p, struct file *fp) return error; } - +/* + * Returns a locked, refd vnode + */ static int ckpt_fhtovp(fhandle_t *fh, struct vnode **vpp) { @@ -480,22 +482,23 @@ ckpt_fhtovp(fhandle_t *fh, struct vnode **vpp) static int mmap_vp(struct vn_hdr *vnh) { - struct vnode **vpp, *vp; + struct vnode *vp; Elf_Phdr *phdr; struct file *fp; int error; TRACE_ENTER; - vpp = &vp; phdr = &vnh->vnh_phdr; - if ((error = ckpt_fhtovp(&vnh->vnh_fh, vpp)) != 0) + if ((error = ckpt_fhtovp(&vnh->vnh_fh, &vp)) != 0) return error; /* * XXX O_RDONLY -> or O_RDWR if file is PROT_WRITE, MAP_SHARED */ - if ((error = fp_vpopen(*vpp, O_RDONLY, &fp)) != 0) + if ((error = fp_vpopen(vp, O_RDONLY, &fp)) != 0) { + vput(vp); return error; + } error = mmap_phdr(fp, phdr); fp_close(fp); TRACE_EXIT; @@ -585,8 +588,10 @@ elf_getfiles(struct proc *p, struct file *fp) } if ((error = ckpt_fhtovp(&cfi->cfi_fh, &vp)) != 0) break; - if ((error = fp_vpopen(vp, OFLAGS(cfi->cfi_flags), &tempfp)) != 0) + if ((error = fp_vpopen(vp, OFLAGS(cfi->cfi_flags), &tempfp)) != 0) { + vput(vp); break; + } tempfp->f_offset = cfi->cfi_offset; /* XXX bail for now if we the index is * larger than the current file table diff --git a/sys/dev/disk/ccd/ccd.c b/sys/dev/disk/ccd/ccd.c index 7ae15a4f01..f392e293ff 100644 --- a/sys/dev/disk/ccd/ccd.c +++ b/sys/dev/disk/ccd/ccd.c @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/dev/ccd/ccd.c,v 1.73.2.1 2001/09/11 09:49:52 kris Exp $ */ -/* $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.17 2004/10/12 19:20:30 dillon Exp $ */ +/* $DragonFly: src/sys/dev/disk/ccd/ccd.c,v 1.18 2004/11/12 00:09:03 dillon Exp $ */ /* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */ @@ -97,7 +97,7 @@ #include #include #include -#include +#include #include #include #include @@ -1536,31 +1536,34 @@ ccddump(dev_t dev, u_int count, u_int blkno, u_int secsize) static int ccdlookup(char *path, struct thread *td, struct vnode **vpp) { - struct nameidata nd; + struct nlookupdata nd; + struct ucred *cred; struct vnode *vp; int error; - struct ucred *cred; KKASSERT(td->td_proc); cred = td->td_proc->p_ucred; + *vpp = NULL; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, path, td); - if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { + error = nlookup_init(&nd, path, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); + if (error) + return (error); + if ((error = vn_open(&nd, NULL, FREAD|FWRITE, 0)) != 0) { #ifdef DEBUG if (ccddebug & CCDB_FOLLOW|CCDB_INIT) printf("ccdlookup: vn_open error = %d\n", error); #endif - return (error); + goto done; } - vp = nd.ni_vp; + vp = nd.nl_open_vp; if (vp->v_usecount > 1) { error = EBUSY; - goto bad; + goto done; } if (!vn_isdisk(vp, &error)) - goto bad; + goto done; #ifdef DEBUG if (ccddebug & CCDB_VNODE) @@ -1568,14 +1571,12 @@ ccdlookup(char *path, struct thread *td, struct vnode **vpp) #endif VOP_UNLOCK(vp, 0, td); - NDFREE(&nd, NDF_ONLY_PNBUF); - *vpp = vp; + nd.nl_open_vp = NULL; + nlookup_done(&nd); + *vpp = vp; /* leave ref intact */ return (0); -bad: - VOP_UNLOCK(vp, 0, td); - NDFREE(&nd, NDF_ONLY_PNBUF); - /* vn_close does vrele() for vp */ - (void)vn_close(vp, FREAD|FWRITE, td); +done: + nlookup_done(&nd); return (error); } diff --git a/sys/dev/disk/vn/vn.c b/sys/dev/disk/vn/vn.c index f40b4446a6..dba56bd4bd 100644 --- a/sys/dev/disk/vn/vn.c +++ b/sys/dev/disk/vn/vn.c @@ -39,7 +39,7 @@ * * from: @(#)vn.c 8.6 (Berkeley) 4/1/94 * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $ - * $DragonFly: src/sys/dev/disk/vn/vn.c,v 1.12 2004/10/12 19:20:32 dillon Exp $ + * $DragonFly: src/sys/dev/disk/vn/vn.c,v 1.13 2004/11/12 00:09:04 dillon Exp $ */ /* @@ -65,7 +65,7 @@ #include #include #include -#include +#include #include #include #include @@ -541,35 +541,40 @@ vniocattach_file(vn, vio, dev, flag, td) struct thread *td; { struct vattr vattr; - struct nameidata nd; + struct nlookupdata nd; int error, flags; + struct vnode *vp; struct proc *p = td->td_proc; KKASSERT(p != NULL); flags = FREAD|FWRITE; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, vio->vn_file, td); - error = vn_open(&nd, flags, 0); - if (error) { + error = nlookup_init(&nd, vio->vn_file, + UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); + if (error) + return (error); + if ((error = vn_open(&nd, NULL, flags, 0)) != 0) { if (error != EACCES && error != EPERM && error != EROFS) - return (error); + goto done; flags &= ~FWRITE; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, - UIO_USERSPACE, vio->vn_file, td); - error = vn_open(&nd, flags, 0); + nlookup_done(&nd); + error = nlookup_init(&nd, vio->vn_file, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); if (error) return (error); + if ((error = vn_open(&nd, NULL, flags, 0)) != 0) + goto done; } - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_vp->v_type != VREG || - (error = VOP_GETATTR(nd.ni_vp, &vattr, td))) { - VOP_UNLOCK(nd.ni_vp, 0, td); - (void) vn_close(nd.ni_vp, flags, td); - return (error ? error : EINVAL); + vp = nd.nl_open_vp; + if (vp->v_type != VREG || + (error = VOP_GETATTR(vp, &vattr, td))) { + if (error == 0) + error = EINVAL; + goto done; } - VOP_UNLOCK(nd.ni_vp, 0, td); + VOP_UNLOCK(vp, 0, td); vn->sc_secsize = DEV_BSIZE; - vn->sc_vp = nd.ni_vp; + vn->sc_vp = vp; + nd.nl_open_vp = NULL; /* * If the size is specified, override the file attributes. Note that @@ -581,8 +586,9 @@ vniocattach_file(vn, vio, dev, flag, td) vn->sc_size = vattr.va_size / vn->sc_secsize; error = vnsetcred(vn, p->p_ucred); if (error) { - (void) vn_close(nd.ni_vp, flags, td); - return(error); + vn->sc_vp = NULL; + vn_close(vp, flags, td); + goto done; } vn->sc_flags |= VNF_INITED; if (flags == FREAD) @@ -602,7 +608,9 @@ vniocattach_file(vn, vio, dev, flag, td) IFOPT(vn, VN_FOLLOW) printf("vnioctl: SET vp %p size %x blks\n", vn->sc_vp, vn->sc_size); - return(0); +done: + nlookup_done(&nd); + return(error); } /* @@ -737,7 +745,7 @@ vnclear(struct vn_softc *vn) dsgone(&vn->sc_slices); vn->sc_flags &= ~VNF_INITED; if (vn->sc_vp != NULL) { - (void)vn_close(vn->sc_vp, vn->sc_flags & VNF_READONLY ? + vn_close(vn->sc_vp, vn->sc_flags & VNF_READONLY ? FREAD : (FREAD|FWRITE), td); vn->sc_vp = NULL; } diff --git a/sys/dev/misc/streams/streams.c b/sys/dev/misc/streams/streams.c index 1407b1ff2d..1f5f94c5cd 100644 --- a/sys/dev/misc/streams/streams.c +++ b/sys/dev/misc/streams/streams.c @@ -31,7 +31,7 @@ * in 3.0-980524-SNAP then hacked a bit (but probably not enough :-). * * $FreeBSD: src/sys/dev/streams/streams.c,v 1.16.2.1 2001/02/26 04:23:07 jlemon Exp $ - * $DragonFly: src/sys/dev/misc/streams/Attic/streams.c,v 1.13 2004/08/02 13:22:32 joerg Exp $ + * $DragonFly: src/sys/dev/misc/streams/Attic/streams.c,v 1.14 2004/11/12 00:09:07 dillon Exp $ */ #include @@ -242,8 +242,11 @@ streamsopen(dev_t dev, int oflags, int devtype, d_thread_t *td) return error; if ((error = socreate(family, &so, type, protocol, td)) != 0) { - p->p_fd->fd_ofiles[fd] = 0; - ffree(fp); + if (p->p_fd->fd_ofiles[fd] == fp) { + p->p_fd->fd_ofiles[fd] = NULL; + fdrop(fp, td); + } + fdrop(fp, td); return error; } @@ -251,8 +254,8 @@ streamsopen(dev_t dev, int oflags, int devtype, d_thread_t *td) fp->f_flag = FREAD|FWRITE; fp->f_ops = &svr4_netops; fp->f_type = DTYPE_SOCKET; - (void)svr4_stream_get(fp); + fdrop(fp, td); p->p_dupfd = fd; return ENXIO; } diff --git a/sys/emulation/43bsd/43bsd_file.c b/sys/emulation/43bsd/43bsd_file.c index 7a82c9a350..c621a888c2 100644 --- a/sys/emulation/43bsd/43bsd_file.c +++ b/sys/emulation/43bsd/43bsd_file.c @@ -37,7 +37,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/emulation/43bsd/43bsd_file.c,v 1.6 2004/10/12 19:20:33 dillon Exp $ + * $DragonFly: src/sys/emulation/43bsd/43bsd_file.c,v 1.7 2004/11/12 00:09:10 dillon Exp $ * from: DragonFly kern/vfs_syscalls.c,v 1.20 * * These syscalls used to live in kern/vfs_syscalls.c. They are modified @@ -58,8 +58,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -67,15 +68,14 @@ int ocreat(struct ocreat_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td); - - error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC, uap->mode, - &uap->sysmsg_result); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) { + error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC, + uap->mode, &uap->sysmsg_result); + } return (error); } @@ -103,14 +103,13 @@ olseek(struct olseek_args *uap) int otruncate(struct otruncate_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td); - - error = kern_truncate(&nd, uap->length); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_truncate(&nd, uap->length); + nlookup_done(&nd); return (error); } diff --git a/sys/emulation/ibcs2/coff/imgact_coff.c b/sys/emulation/ibcs2/coff/imgact_coff.c index aac6ba6829..449070186e 100644 --- a/sys/emulation/ibcs2/coff/imgact_coff.c +++ b/sys/emulation/ibcs2/coff/imgact_coff.c @@ -27,7 +27,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/i386/ibcs2/imgact_coff.c,v 1.40 1999/12/15 23:01:47 eivind Exp $ - * $DragonFly: src/sys/emulation/ibcs2/coff/Attic/imgact_coff.c,v 1.12 2004/10/12 19:20:34 dillon Exp $ + * $DragonFly: src/sys/emulation/ibcs2/coff/Attic/imgact_coff.c,v 1.13 2004/11/12 00:09:12 dillon Exp $ */ #include @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include @@ -154,7 +154,7 @@ coff_load_file(struct thread *td, char *name) { struct vmspace *vmspace; int error; - struct nameidata nd; + struct nlookupdata nd; struct vnode *vp; struct vattr attr; struct filehdr *fhdr; @@ -173,15 +173,16 @@ coff_load_file(struct thread *td, char *name) vmspace = td->td_proc->p_vmspace; /* XXX use of 'curthread' should be 'td'?*/ - NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME, UIO_SYSSPACE, name, curthread); - - error = namei(&nd); + error = nlookup_init(&nd, name, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) { + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + if (error) + error = ENOEXEC; + } if (error) - return error; - - vp = nd.ni_vp; - if (vp == NULL) - return ENOEXEC; + goto done; if (vp->v_writecount) { error = ETXTBSY; @@ -204,7 +205,7 @@ coff_load_file(struct thread *td, char *name) if ((error = VOP_ACCESS(vp, VEXEC, cred, td)) != 0) goto fail; - if ((error = VOP_OPEN(vp, FREAD, cred, td)) != 0) + if ((error = VOP_OPEN(vp, FREAD, cred, NULL, td)) != 0) goto fail; /* @@ -286,8 +287,9 @@ coff_load_file(struct thread *td, char *name) fail: VOP_UNLOCK(vp, 0, td); unlocked_fail: - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); + vrele(vp); +done: + nlookup_done(&nd); return error; } diff --git a/sys/emulation/ibcs2/i386/ibcs2_stat.c b/sys/emulation/ibcs2/i386/ibcs2_stat.c index 322513eca8..9c87fd4d2c 100644 --- a/sys/emulation/ibcs2/i386/ibcs2_stat.c +++ b/sys/emulation/ibcs2/i386/ibcs2_stat.c @@ -26,14 +26,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/i386/ibcs2/ibcs2_stat.c,v 1.10 1999/12/15 23:01:45 eivind Exp $ - * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_stat.c,v 1.9 2003/09/23 05:03:50 dillon Exp $ + * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_stat.c,v 1.10 2004/11/12 00:09:16 dillon Exp $ */ #include #include #include #include -#include +#include #include #include #include @@ -108,21 +108,24 @@ ibcs2_statfs(struct ibcs2_statfs_args *uap) struct mount *mp; struct statfs *sp; int error; - struct nameidata nd; + struct nlookupdata nd; caddr_t sg = stackgap_init(); CHECKALTEXIST(&sg, SCARG(uap, path)); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - mp = nd.ni_vp->v_mount; - sp = &mp->mnt_stat; - vrele(nd.ni_vp); - if ((error = VFS_STATFS(mp, sp, td)) != 0) - return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - return cvt_statfs(sp, (caddr_t)SCARG(uap, buf), SCARG(uap, len)); + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) { + mp = nd.nl_ncp->nc_mount; + sp = &mp->mnt_stat; + error = VFS_STATFS(mp, sp, td); + if (error == 0) { + sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + error = cvt_statfs(sp, (caddr_t)SCARG(uap, buf), + SCARG(uap, len)); + } + } + nlookup_done(&nd); } int diff --git a/sys/emulation/ibcs2/i386/ibcs2_util.c b/sys/emulation/ibcs2/i386/ibcs2_util.c index b428775e0f..84d9c0c2c7 100644 --- a/sys/emulation/ibcs2/i386/ibcs2_util.c +++ b/sys/emulation/ibcs2/i386/ibcs2_util.c @@ -28,13 +28,13 @@ * * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp * $FreeBSD: src/sys/i386/ibcs2/ibcs2_util.c,v 1.7 1999/12/15 23:01:45 eivind Exp $ - * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_util.c,v 1.8 2004/01/08 18:39:18 asmodai Exp $ + * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_util.c,v 1.9 2004/11/12 00:09:16 dillon Exp $ */ #include #include #include -#include +#include #include #include @@ -60,19 +60,15 @@ ibcs2_emul_find(sgp, prefix, path, pbuf, cflag) char **pbuf; int cflag; { - struct thread *td = curthread; /* XXX */ - struct ucred *cred; - struct nameidata nd; - struct nameidata ndroot; + struct nlookupdata nd; + struct nlookupdata ndroot; struct vattr vat; struct vattr vatroot; + struct vnode *vp; int error; char *ptr, *buf, *cp; size_t sz, len; - KKASSERT(td->td_proc); - cred = td->td_proc->p_ucred; - buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); *pbuf = path; @@ -111,21 +107,22 @@ ibcs2_emul_find(sgp, prefix, path, pbuf, cflag) for (cp = &ptr[len] - 1; *cp != '/'; cp--); *cp = '\0'; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td); - - if ((error = namei(&nd)) != 0) { - free(buf, M_TEMP); - return error; + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error) { + nlookup_done(&nd); + return (error); } - *cp = '/'; - } - else { - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td); - - if ((error = namei(&nd)) != 0) { - free(buf, M_TEMP); - return error; + } else { + + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error) { + nlookup_done(&nd); + return (error); } /* @@ -136,25 +133,24 @@ ibcs2_emul_find(sgp, prefix, path, pbuf, cflag) * root directory and never finding it, because "/" resolves * to the emulation root directory. This is expensive :-( */ - NDINIT(&ndroot, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, - ibcs2_emul_path, td); - - if ((error = namei(&ndroot)) != 0) { - /* Cannot happen! */ - free(buf, M_TEMP); - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); - return error; - } - - if ((error = VOP_GETATTR(nd.ni_vp, &vat, td)) != 0) { + error = nlookup_init(&ndroot, ibcs2_emul_path, UIO_SYSSPACE, + NLC_FOLLOW); + if (error == 0) + error = nlookup(&ndroot); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + if (error) goto done; - } - - if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, td)) - != 0) { + error = VOP_GETATTR(vp, &vat, nd.nl_td); + vrele(vp); + if (error == 0) + error = cache_vref(ndroot.nl_ncp, nd.nl_cred, &vp); + if (error) + goto done; + error = VOP_GETATTR(vp, &vatroot, nd.nl_td); + vrele(vp); + if (error) goto done; - } if (vat.va_fsid == vatroot.va_fsid && vat.va_fileid == vatroot.va_fileid) { @@ -163,22 +159,17 @@ ibcs2_emul_find(sgp, prefix, path, pbuf, cflag) } } - if (sgp == NULL) + if (sgp == NULL) { *pbuf = buf; - else { + } else { sz = &ptr[len] - buf; *pbuf = stackgap_alloc(sgp, sz + 1); error = copyout(buf, *pbuf, sz); free(buf, M_TEMP); } - - done: - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); - if (!cflag) { - NDFREE(&ndroot, NDF_ONLY_PNBUF); - vrele(ndroot.ni_vp); - } - return error; + nlookup_done(&nd); + if (!cflag) + nlookup_done(&ndroot); + return (error); } diff --git a/sys/emulation/ibcs2/i386/ibcs2_xenix.c b/sys/emulation/ibcs2/i386/ibcs2_xenix.c index ce8a63cebf..a9ee9d5aae 100644 --- a/sys/emulation/ibcs2/i386/ibcs2_xenix.c +++ b/sys/emulation/ibcs2/i386/ibcs2_xenix.c @@ -28,13 +28,13 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/i386/ibcs2/ibcs2_xenix.c,v 1.20 1999/12/15 23:01:46 eivind Exp $ - * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_xenix.c,v 1.9 2003/09/23 05:03:50 dillon Exp $ + * $DragonFly: src/sys/emulation/ibcs2/i386/Attic/ibcs2_xenix.c,v 1.10 2004/11/12 00:09:16 dillon Exp $ */ #include #include #include -#include +#include #include #include #include @@ -196,17 +196,19 @@ xenix_eaccess(struct xenix_eaccess_args *uap) struct proc *p = curproc; struct ucred *cred = p->p_ucred; struct vnode *vp; - struct nameidata nd; + struct nlookupdata nd; int error, flags; caddr_t sg = stackgap_init(); CHECKALTEXIST(&sg, SCARG(uap, path)); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return error; - vp = nd.ni_vp; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + if (error) + goto done; /* Flags == 0 means only check for existence. */ if (SCARG(uap, flags)) { @@ -220,7 +222,8 @@ xenix_eaccess(struct xenix_eaccess_args *uap) if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) error = VOP_ACCESS(vp, flags, cred, td); } - NDFREE(&nd, NDF_ONLY_PNBUF); vput(vp); - return error; +done: + nlookup_done(&nd); + return (error); } diff --git a/sys/emulation/linux/i386/linux_machdep.c b/sys/emulation/linux/i386/linux_machdep.c index 87e1e2032a..d4a82ea4f4 100644 --- a/sys/emulation/linux/i386/linux_machdep.c +++ b/sys/emulation/linux/i386/linux_machdep.c @@ -26,7 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/i386/linux/linux_machdep.c,v 1.6.2.4 2001/11/05 19:08:23 marcel Exp $ - * $DragonFly: src/sys/emulation/linux/i386/linux_machdep.c,v 1.14 2003/12/20 05:52:21 dillon Exp $ + * $DragonFly: src/sys/emulation/linux/i386/linux_machdep.c,v 1.15 2004/11/12 00:09:19 dillon Exp $ */ #include @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include @@ -104,8 +104,7 @@ bsd_to_linux_sigaltstack(int bsa) int linux_execve(struct linux_execve_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; struct image_args exec_args; char *path; int error; @@ -117,12 +116,14 @@ linux_execve(struct linux_execve_args *args) if (ldebug(execve)) printf(ARGS(execve, "%s"), path); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME, - UIO_SYSSPACE, path, td); - error = exec_copyin_args(&exec_args, path, PATH_SYSSPACE, - args->argp, args->envp); + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) { + error = exec_copyin_args(&exec_args, path, PATH_SYSSPACE, + args->argp, args->envp); + } if (error == 0) error = kern_execve(&nd, &exec_args); + nlookup_done(&nd); /* * The syscall result is returned in registers to the new program. diff --git a/sys/emulation/linux/linux_file.c b/sys/emulation/linux/linux_file.c index 29469ff880..1547bb206c 100644 --- a/sys/emulation/linux/linux_file.c +++ b/sys/emulation/linux/linux_file.c @@ -26,7 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/compat/linux/linux_file.c,v 1.41.2.6 2003/01/06 09:19:43 fjoe Exp $ - * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.18 2004/10/12 19:20:37 dillon Exp $ + * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.19 2004/11/12 00:09:18 dillon Exp $ */ #include "opt_compat.h" @@ -37,12 +37,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -62,8 +62,7 @@ int linux_creat(struct linux_creat_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -74,11 +73,11 @@ linux_creat(struct linux_creat_args *args) if (ldebug(creat)) printf(ARGS(creat, "%s, %d"), path, args->mode); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC, args->mode, - &args->sysmsg_result); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) { + error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC, + args->mode, &args->sysmsg_result); + } linux_free_path(&path); return(error); } @@ -89,7 +88,7 @@ linux_open(struct linux_open_args *args) { struct thread *td = curthread; struct proc *p = td->td_proc; - struct nameidata nd; + struct nlookupdata nd; char *path; int error, flags; @@ -135,9 +134,11 @@ linux_open(struct linux_open_args *args) flags |= O_EXCL; if (args->flags & LINUX_O_NOCTTY) flags |= O_NOCTTY; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_open(&nd, flags, args->mode, &args->sysmsg_result); + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) { + error = kern_open(&nd, flags, + args->mode, &args->sysmsg_result); + } if (error == 0 && !(flags & O_NOCTTY) && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { @@ -462,8 +463,7 @@ linux_getdents64(struct linux_getdents64_args *args) int linux_access(struct linux_access_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -474,11 +474,10 @@ linux_access(struct linux_access_args *args) if (ldebug(access)) printf(ARGS(access, "%s, %d"), path, args->flags); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ, - UIO_SYSSPACE, path, td); - - error = kern_access(&nd, args->flags); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_access(&nd, args->flags); + nlookup_done(&nd); linux_free_path(&path); return(error); } @@ -486,8 +485,7 @@ linux_access(struct linux_access_args *args) int linux_unlink(struct linux_unlink_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -498,10 +496,10 @@ linux_unlink(struct linux_unlink_args *args) if (ldebug(unlink)) printf(ARGS(unlink, "%s"), path); #endif - NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT, UIO_SYSSPACE, path, td); - - error = kern_unlink(&nd); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, 0); + if (error == 0) + error = kern_unlink(&nd); + nlookup_done(&nd); linux_free_path(&path); return(error); } @@ -532,8 +530,7 @@ linux_chdir(struct linux_chdir_args *args) int linux_chmod(struct linux_chmod_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -544,10 +541,10 @@ linux_chmod(struct linux_chmod_args *args) if (ldebug(chmod)) printf(ARGS(chmod, "%s, %d"), path, args->mode); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_chmod(&nd, args->mode); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_chmod(&nd, args->mode); + nlookup_done(&nd); linux_free_path(&path); return(error); } @@ -555,8 +552,7 @@ linux_chmod(struct linux_chmod_args *args) int linux_mkdir(struct linux_mkdir_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -567,9 +563,10 @@ linux_mkdir(struct linux_mkdir_args *args) if (ldebug(mkdir)) printf(ARGS(mkdir, "%s, %d"), path, args->mode); #endif - NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_SYSSPACE, path, td); - - error = kern_mkdir(&nd, args->mode); + error = nlookup_init(&nd, path, UIO_SYSSPACE, 0); + if (error == 0) + error = kern_mkdir(&nd, args->mode); + nlookup_done(&nd); linux_free_path(&path); return(error); @@ -578,8 +575,7 @@ linux_mkdir(struct linux_mkdir_args *args) int linux_rmdir(struct linux_rmdir_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -590,11 +586,10 @@ linux_rmdir(struct linux_rmdir_args *args) if (ldebug(rmdir)) printf(ARGS(rmdir, "%s"), path); #endif - NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT | CNP_LOCKLEAF, - UIO_SYSSPACE, path, td); - - error = kern_rmdir(&nd); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, 0); + if (error == 0) + error = kern_rmdir(&nd); + nlookup_done(&nd); linux_free_path(&path); return(error); } @@ -602,8 +597,7 @@ linux_rmdir(struct linux_rmdir_args *args) int linux_rename(struct linux_rename_args *args) { - struct thread *td = curthread; - struct nameidata fromnd, tond; + struct nlookupdata fromnd, tond; char *from, *to; int error; @@ -619,15 +613,14 @@ linux_rename(struct linux_rename_args *args) if (ldebug(rename)) printf(ARGS(rename, "%s, %s"), from, to); #endif - NDINIT(&fromnd, NAMEI_DELETE, CNP_WANTPARENT | CNP_SAVESTART, - UIO_SYSSPACE, from, td); - NDINIT(&tond, NAMEI_RENAME, - CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_NOCACHE | - CNP_SAVESTART | CNP_NOOBJ, - UIO_SYSSPACE, to, td); - - error = kern_rename(&fromnd, &tond); - + error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0); + if (error == 0) { + error = nlookup_init(&tond, to, UIO_SYSSPACE, 0); + if (error == 0) + error = kern_rename(&fromnd, &tond); + nlookup_done(&tond); + } + nlookup_done(&fromnd); linux_free_path(&from); linux_free_path(&to); return(error); @@ -637,9 +630,10 @@ int linux_symlink(struct linux_symlink_args *args) { struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path, *link; int error; + int mode; error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS); if (error) @@ -653,11 +647,12 @@ linux_symlink(struct linux_symlink_args *args) if (ldebug(symlink)) printf(ARGS(symlink, "%s, %s"), path, link); #endif - NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ, UIO_SYSSPACE, - link, td); - - error = kern_symlink(path, &nd); - + error = nlookup_init(&nd, link, UIO_SYSSPACE, 0); + if (error == 0) { + mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask; + error = kern_symlink(&nd, path, mode); + } + nlookup_done(&nd); linux_free_path(&path); linux_free_path(&link); return(error); @@ -666,8 +661,7 @@ linux_symlink(struct linux_symlink_args *args) int linux_readlink(struct linux_readlink_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -679,12 +673,12 @@ linux_readlink(struct linux_readlink_args *args) printf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf, args->count); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_NOOBJ, UIO_SYSSPACE, - path, td); - - error = kern_readlink(&nd, args->buf, args->count, - &args->sysmsg_result); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, 0); + if (error == 0) { + error = kern_readlink(&nd, args->buf, args->count, + &args->sysmsg_result); + } + nlookup_done(&nd); linux_free_path(&path); return(error); } @@ -692,8 +686,7 @@ linux_readlink(struct linux_readlink_args *args) int linux_truncate(struct linux_truncate_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -705,10 +698,10 @@ linux_truncate(struct linux_truncate_args *args) printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_truncate(&nd, args->length); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_truncate(&nd, args->length); + nlookup_done(&nd); linux_free_path(&path); return(error); } @@ -716,8 +709,7 @@ linux_truncate(struct linux_truncate_args *args) int linux_truncate64(struct linux_truncate64_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -729,10 +721,10 @@ linux_truncate64(struct linux_truncate64_args *args) printf(ARGS(truncate64, "%s, %lld"), path, (off_t)args->length); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_truncate(&nd, args->length); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_truncate(&nd, args->length); + nlookup_done(&nd); linux_free_path(&path); return error; } @@ -770,8 +762,7 @@ linux_ftruncate64(struct linux_ftruncate64_args *args) int linux_link(struct linux_link_args *args) { - struct thread *td = curthread; - struct nameidata nd, linknd; + struct nlookupdata nd, linknd; char *path, *link; int error; @@ -787,13 +778,14 @@ linux_link(struct linux_link_args *args) if (ldebug(link)) printf(ARGS(link, "%s, %s"), path, link); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_NOOBJ, UIO_SYSSPACE, - path, td); - NDINIT(&linknd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ, - UIO_SYSSPACE, link, td); - - error = kern_link(&nd, &linknd); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) { + error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0); + if (error == 0) + error = kern_link(&nd, &linknd); + nlookup_done(&linknd); + } + nlookup_done(&nd); linux_free_path(&path); linux_free_path(&link); return(error); @@ -1189,8 +1181,7 @@ linux_fcntl64(struct linux_fcntl64_args *args) int linux_chown(struct linux_chown_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -1201,10 +1192,10 @@ linux_chown(struct linux_chown_args *args) if (ldebug(chown)) printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_chown(&nd, args->uid, args->gid); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_chown(&nd, args->uid, args->gid); + nlookup_done(&nd); linux_free_path(&path); return(error); } @@ -1212,8 +1203,7 @@ linux_chown(struct linux_chown_args *args) int linux_lchown(struct linux_lchown_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -1224,10 +1214,10 @@ linux_lchown(struct linux_lchown_args *args) if (ldebug(lchown)) printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); #endif - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td); - - error = kern_chown(&nd, args->uid, args->gid); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, 0); + if (error == 0) + error = kern_chown(&nd, args->uid, args->gid); + nlookup_done(&nd); linux_free_path(&path); return(error); } diff --git a/sys/emulation/linux/linux_getcwd.c b/sys/emulation/linux/linux_getcwd.c index f6f2db7ad3..77bbb27427 100644 --- a/sys/emulation/linux/linux_getcwd.c +++ b/sys/emulation/linux/linux_getcwd.c @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/compat/linux/linux_getcwd.c,v 1.2.2.3 2001/11/05 19:08:22 marcel Exp $ */ -/* $DragonFly: src/sys/emulation/linux/linux_getcwd.c,v 1.17 2004/10/12 19:20:37 dillon Exp $ */ +/* $DragonFly: src/sys/emulation/linux/linux_getcwd.c,v 1.18 2004/11/12 00:09:18 dillon Exp $ */ /* $OpenBSD: linux_getcwd.c,v 1.2 2001/05/16 12:50:21 ho Exp $ */ /* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */ @@ -54,357 +54,15 @@ #include #include #include +#include #include /* XXX only for DIRBLKSIZ */ #include #include #include "linux_util.h" -static int -linux_getcwd_scandir (struct vnode **, struct vnode **, - char **, char *, struct thread *); -static int -linux_getcwd_common (struct vnode *, struct vnode *, - char **, char *, int, int, struct thread *); - #define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4) -/* - * Vnode variable naming conventions in this file: - * - * rvp: the current root we're aiming towards. - * lvp, *lvpp: the "lower" vnode - * uvp, *uvpp: the "upper" vnode. - * - * Since all the vnodes we're dealing with are directories, and the - * lookups are going *up* in the filesystem rather than *down*, the - * usual "pvp" (parent) or "dvp" (directory) naming conventions are - * too confusing. - */ - -/* - * XXX Will infinite loop in certain cases if a directory read reliably - * returns EINVAL on last block. - * XXX is EINVAL the right thing to return if a directory is malformed? - */ - -/* - * XXX Untested vs. mount -o union; probably does the wrong thing. - */ - -/* - * Find parent vnode of *lvpp, return in *uvpp - * - * If we care about the name, scan it looking for name of directory - * entry pointing at lvp. - * - * Place the name in the buffer which starts at bufp, immediately - * before *bpp, and move bpp backwards to point at the start of it. - * - * On entry, *lvpp is a locked vnode reference; on exit, it is vput and NULL'ed - * On exit, *uvpp is either NULL or is a locked vnode reference. - */ -static int -linux_getcwd_scandir(lvpp, uvpp, bpp, bufp, td) - struct vnode **lvpp; - struct vnode **uvpp; - char **bpp; - char *bufp; - struct thread *td; -{ - struct proc *p = td->td_proc; - int error = 0; - int eofflag; - off_t off; - int tries; - struct uio uio; - struct iovec iov; - char *dirbuf = NULL; - int dirbuflen; - ino_t fileno; - struct vattr va; - struct vnode *uvp = NULL; - struct vnode *lvp = *lvpp; - struct componentname cn; - int len, reclen; - tries = 0; - - KKASSERT(p); - - /* - * If we want the filename, get some info we need while the - * current directory is still locked. - */ - if (bufp != NULL) { - error = VOP_GETATTR(lvp, &va, td); - if (error) { - vput(lvp); - *lvpp = NULL; - *uvpp = NULL; - return error; - } - } - - /* - * Ok, we have to do it the hard way.. - * Next, get parent vnode using lookup of .. - */ - cn.cn_nameiop = NAMEI_LOOKUP; - cn.cn_flags = CNP_ISLASTCN | CNP_ISDOTDOT | CNP_RDONLY; - cn.cn_td = td; - cn.cn_cred = p->p_ucred; - cn.cn_pnbuf = NULL; - cn.cn_nameptr = ".."; - cn.cn_namelen = 2; - cn.cn_consume = 0; - - /* - * At this point, lvp is locked and will be unlocked by the lookup. - * On successful return, *uvpp will be locked - */ - error = VOP_LOOKUP(lvp, uvpp, &cn); - if (error) { - vput(lvp); - *lvpp = NULL; - *uvpp = NULL; - return error; - } - uvp = *uvpp; - - /* If we don't care about the pathname, we're done */ - if (bufp == NULL) { - vrele(lvp); - *lvpp = NULL; - return 0; - } - - fileno = va.va_fileid; - - dirbuflen = DIRBLKSIZ; - if (dirbuflen < va.va_blocksize) - dirbuflen = va.va_blocksize; - dirbuf = (char *)malloc(dirbuflen, M_TEMP, M_WAITOK); - -#if 0 -unionread: -#endif - off = 0; - do { - /* call VOP_READDIR of parent */ - iov.iov_base = dirbuf; - iov.iov_len = dirbuflen; - - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_offset = off; - uio.uio_resid = dirbuflen; - uio.uio_segflg = UIO_SYSSPACE; - uio.uio_rw = UIO_READ; - uio.uio_td = td; - - eofflag = 0; - - error = VOP_READDIR(uvp, &uio, p->p_ucred, &eofflag, 0, 0); - - off = uio.uio_offset; - - /* - * Try again if NFS tosses its cookies. - * XXX this can still loop forever if the directory is busted - * such that the second or subsequent page of it always - * returns EINVAL - */ - if ((error == EINVAL) && (tries < 3)) { - off = 0; - tries++; - continue; /* once more, with feeling */ - } - - if (!error) { - char *cpos; - struct dirent *dp; - - cpos = dirbuf; - tries = 0; - - /* scan directory page looking for matching vnode */ - for (len = (dirbuflen - uio.uio_resid); len > 0; len -= reclen) { - dp = (struct dirent *) cpos; - reclen = dp->d_reclen; - - /* check for malformed directory.. */ - if (reclen < DIRENT_MINSIZE) { - error = EINVAL; - goto out; - } - /* - * XXX should perhaps do VOP_LOOKUP to - * check that we got back to the right place, - * but getting the locking games for that - * right would be heinous. - */ - if ((dp->d_type != DT_WHT) && - (dp->d_fileno == fileno)) { - char *bp = *bpp; - bp -= dp->d_namlen; - - if (bp <= bufp) { - error = ERANGE; - goto out; - } - bcopy(dp->d_name, bp, dp->d_namlen); - error = 0; - *bpp = bp; - goto out; - } - cpos += reclen; - } - } - } while (!eofflag); - error = ENOENT; - -out: - vrele(lvp); - *lvpp = NULL; - free(dirbuf, M_TEMP); - return error; -} - - -/* - * common routine shared by sys___getcwd() and linux_vn_isunder() - */ - -#define GETCWD_CHECK_ACCESS 0x0001 - -static int -linux_getcwd_common (lvp, rvp, bpp, bufp, limit, flags, td) - struct vnode *lvp; - struct vnode *rvp; - char **bpp; - char *bufp; - int limit; - int flags; - struct thread *td; -{ - struct proc *p = td->td_proc; - struct filedesc *fdp; - struct vnode *uvp = NULL; - char *bp = NULL; - int error; - int perms = VEXEC; - - KKASSERT(p); - fdp = p->p_fd; - - if (rvp == NULL) { - rvp = fdp->fd_rdir; - if (rvp == NULL) - rvp = rootvnode; - } - - vref(rvp); - vref(lvp); - - /* - * Error handling invariant: - * Before a `goto out': - * lvp is either NULL, or locked and held. - * uvp is either NULL, or locked and held. - */ - - error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, td); - if (error) { - vrele(lvp); - lvp = NULL; - goto out; - } - if (bufp) - bp = *bpp; - /* - * this loop will terminate when one of the following happens: - * - we hit the root - * - getdirentries or lookup fails - * - we run out of space in the buffer. - */ - if (lvp == rvp) { - if (bp) - *(--bp) = '/'; - goto out; - } - do { - if (lvp->v_type != VDIR) { - error = ENOTDIR; - goto out; - } - - /* - * access check here is optional, depending on - * whether or not caller cares. - */ - if (flags & GETCWD_CHECK_ACCESS) { - error = VOP_ACCESS(lvp, perms, p->p_ucred, td); - if (error) - goto out; - perms = VEXEC|VREAD; - } - - /* - * step up if we're a covered vnode.. - */ - while (lvp->v_flag & VROOT) { - struct vnode *tvp; - - if (lvp == rvp) - goto out; - - tvp = lvp; - lvp = lvp->v_mount->mnt_vnodecovered; - vput(tvp); - /* - * hodie natus est radici frater - */ - if (lvp == NULL) { - error = ENOENT; - goto out; - } - vref(lvp); - error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, td); - if (error != 0) { - vrele(lvp); - lvp = NULL; - goto out; - } - } - error = linux_getcwd_scandir(&lvp, &uvp, &bp, bufp, td); - if (error) - goto out; -#if DIAGNOSTIC - if (lvp != NULL) - panic("getcwd: oops, forgot to null lvp"); - if (bufp && (bp <= bufp)) { - panic("getcwd: oops, went back too far"); - } -#endif - if (bp) - *(--bp) = '/'; - lvp = uvp; - uvp = NULL; - limit--; - } while ((lvp != rvp) && (limit > 0)); - -out: - if (bpp) - *bpp = bp; - if (uvp) - vput(uvp); - if (lvp) - vput(lvp); - vrele(rvp); - return error; -} - - /* * Find pathname of process's current directory. * @@ -415,66 +73,29 @@ out: int linux_getcwd(struct linux_getcwd_args *args) { - struct thread *td = curthread; - struct proc *p = td->td_proc; - struct __getcwd_args bsd; - caddr_t sg, bp, bend, path; - int error, len, lenused; - - KKASSERT(p); + int buflen; + int error; + char *buf; + char *bp; #ifdef DEBUG printf("Linux-emul(%ld): getcwd(%p, %d)\n", (long)p->p_pid, args->buf, args->bufsize); #endif - - sg = stackgap_init(); - bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE); - bsd.buflen = SPARE_USRSPACE; - bsd.sysmsg_result = 0; - error = __getcwd(&bsd); - args->sysmsg_result = bsd.sysmsg_result; - if (!error) { - lenused = strlen(bsd.buf) + 1; - if (lenused <= args->bufsize) { - args->sysmsg_result = lenused; - error = copyout(bsd.buf, args->buf, lenused); - } - else - error = ERANGE; - } else { - len = args->bufsize; - - if (len > MAXPATHLEN*4) - len = MAXPATHLEN*4; - else if (len < 2) - return ERANGE; - - path = (char *)malloc(len, M_TEMP, M_WAITOK); - - bp = &path[len]; - bend = bp; - *(--bp) = '\0'; - - /* - * 5th argument here is "max number of vnodes to traverse". - * Since each entry takes up at least 2 bytes in the output buffer, - * limit it to N/2 vnodes for an N byte buffer. - */ - - error = linux_getcwd_common (p->p_fd->fd_cdir, NULL, - &bp, path, len/2, GETCWD_CHECK_ACCESS, td); - - if (error) - goto out; - lenused = bend - bp; - args->sysmsg_result = lenused; - /* put the result into user buffer */ - error = copyout(bp, args->buf, lenused); - -out: - free(path, M_TEMP); + buflen = args->bufsize; + if (buflen < 2) + return (EINVAL); + if (buflen > MAXPATHLEN) + buflen = MAXPATHLEN; + + buf = malloc(buflen, M_TEMP, M_WAITOK); + bp = kern_getcwd(buf, buflen, &error); + if (error == 0) { + buflen = strlen(bp) + 1; + error = copyout(bp, args->buf, buflen); + args->sysmsg_result = buflen; } + free(buf, M_TEMP); return (error); } diff --git a/sys/emulation/linux/linux_misc.c b/sys/emulation/linux/linux_misc.c index 006dd508ae..21f8434be8 100644 --- a/sys/emulation/linux/linux_misc.c +++ b/sys/emulation/linux/linux_misc.c @@ -26,7 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/compat/linux/linux_misc.c,v 1.85.2.9 2002/09/24 08:11:41 mdodd Exp $ - * $DragonFly: src/sys/emulation/linux/linux_misc.c,v 1.21 2004/10/12 19:20:37 dillon Exp $ + * $DragonFly: src/sys/emulation/linux/linux_misc.c,v 1.22 2004/11/12 00:09:18 dillon Exp $ */ #include "opt_compat.h" @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include @@ -242,7 +242,7 @@ linux_uselib(struct linux_uselib_args *args) { struct thread *td = curthread; struct proc *p; - struct nameidata ni; + struct nlookupdata nd; struct vnode *vp; struct exec *a_out; struct vattr attr; @@ -269,27 +269,17 @@ linux_uselib(struct linux_uselib_args *args) locked = 0; vp = NULL; - NDINIT(&ni, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, - UIO_SYSSPACE, path, td); - error = namei(&ni); + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); if (error) goto cleanup; - - vp = ni.ni_vp; - /* - * XXX - This looks like a bogus check. A LOCKLEAF namei should not - * succeed without returning a vnode. - */ - if (vp == NULL) { - error = ENOEXEC; /* ?? */ - goto cleanup; - } - NDFREE(&ni, NDF_ONLY_PNBUF); - /* * From here on down, we have a locked vnode that must be unlocked. */ - locked++; + locked = 1; /* Writable? */ if (vp->v_writecount) { @@ -319,7 +309,7 @@ linux_uselib(struct linux_uselib_args *args) if (error) goto cleanup; - error = VOP_OPEN(vp, FREAD, p->p_ucred, td); + error = VOP_OPEN(vp, FREAD, p->p_ucred, NULL, td); if (error) goto cleanup; @@ -462,17 +452,20 @@ linux_uselib(struct linux_uselib_args *args) } cleanup: - /* Unlock vnode if needed */ - if (locked) - VOP_UNLOCK(vp, 0, td); - + /* Unlock/release vnode */ + if (vp) { + if (locked) + VOP_UNLOCK(vp, 0, td); + vrele(vp); + } /* Release the kernel mapping. */ - if (a_out) + if (a_out) { vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE); - + } + nlookup_done(&nd); linux_free_path(&path); - return error; + return (error); } int @@ -740,10 +733,9 @@ struct l_utimbuf { int linux_utime(struct linux_utime_args *args) { - struct thread *td = curthread; struct timeval tv[2]; struct l_utimbuf lut; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -764,10 +756,10 @@ linux_utime(struct linux_utime_args *args) tv[1].tv_sec = lut.l_modtime; tv[1].tv_usec = 0; } - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_utimes(&nd, args->times ? tv : NULL); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_utimes(&nd, args->times ? tv : NULL); + nlookup_done(&nd); cleanup: linux_free_path(&path); return (error); @@ -856,8 +848,7 @@ linux_wait4(struct linux_wait4_args *args) int linux_mknod(struct linux_mknod_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -869,13 +860,15 @@ linux_mknod(struct linux_mknod_args *args) printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev); #endif - NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_SYSSPACE, path, td); - - if (args->mode & S_IFIFO) { - error = kern_mkfifo(&nd, args->mode); - } else { - error = kern_mknod(&nd, args->mode, args->dev); + error = nlookup_init(&nd, path, UIO_SYSSPACE, 0); + if (error == 0) { + if (args->mode & S_IFIFO) { + error = kern_mkfifo(&nd, args->mode); + } else { + error = kern_mknod(&nd, args->mode, args->dev); + } } + nlookup_done(&nd); linux_free_path(&path); return(error); diff --git a/sys/emulation/linux/linux_stats.c b/sys/emulation/linux/linux_stats.c index 1c454339c1..c01dc53ac5 100644 --- a/sys/emulation/linux/linux_stats.c +++ b/sys/emulation/linux/linux_stats.c @@ -26,7 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/compat/linux/linux_stats.c,v 1.22.2.3 2001/11/05 19:08:23 marcel Exp $ - * $DragonFly: src/sys/emulation/linux/linux_stats.c,v 1.14 2004/10/05 07:57:41 dillon Exp $ + * $DragonFly: src/sys/emulation/linux/linux_stats.c,v 1.15 2004/11/12 00:09:18 dillon Exp $ */ #include @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -234,9 +233,8 @@ statfs_copyout(struct statfs *statfs, struct l_statfs_buf *buf) int linux_statfs(struct linux_statfs_args *args) { - struct thread *td = curthread; struct statfs statfs; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -247,10 +245,10 @@ linux_statfs(struct linux_statfs_args *args) if (ldebug(statfs)) printf(ARGS(statfs, "%s, *"), path); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_statfs(&nd, &statfs); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_statfs(&nd, &statfs); + nlookup_done(&nd); if (error == 0) error = statfs_copyout(&statfs, args->buf); linux_free_path(&path); diff --git a/sys/emulation/linux/linux_uid16.c b/sys/emulation/linux/linux_uid16.c index f49e645ce8..bc53800ed9 100644 --- a/sys/emulation/linux/linux_uid16.c +++ b/sys/emulation/linux/linux_uid16.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/compat/linux/linux_uid16.c,v 1.4.2.1 2001/10/21 03:57:35 marcel Exp $ - * $DragonFly: src/sys/emulation/linux/linux_uid16.c,v 1.9 2003/11/13 04:04:42 daver Exp $ + * $DragonFly: src/sys/emulation/linux/linux_uid16.c,v 1.10 2004/11/12 00:09:18 dillon Exp $ */ #include "opt_compat.h" @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -51,8 +51,7 @@ DUMMY(getresgid16); int linux_chown16(struct linux_chown16_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -64,10 +63,12 @@ linux_chown16(struct linux_chown16_args *args) printf(ARGS(chown16, "%s, %d, %d"), path, args->uid, args->gid); #endif - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td); - - error = kern_chown(&nd, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid)); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) { + error = kern_chown(&nd, CAST_NOCHG(args->uid), + CAST_NOCHG(args->gid)); + } + nlookup_done(&nd); linux_free_path(&path); return(error); } @@ -75,8 +76,7 @@ linux_chown16(struct linux_chown16_args *args) int linux_lchown16(struct linux_lchown16_args *args) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; @@ -88,10 +88,12 @@ linux_lchown16(struct linux_lchown16_args *args) printf(ARGS(lchown16, "%s, %d, %d"), path, args->uid, args->gid); #endif - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td); - - error = kern_chown(&nd, CAST_NOCHG(args->uid), CAST_NOCHG(args->gid)); - + error = nlookup_init(&nd, path, UIO_SYSSPACE, 0); + if (error == 0) { + error = kern_chown(&nd, CAST_NOCHG(args->uid), + CAST_NOCHG(args->gid)); + } + nlookup_done(&nd); linux_free_path(&path); return(error); } diff --git a/sys/emulation/linux/linux_util.c b/sys/emulation/linux/linux_util.c index 4c498358bd..5ce6fdbf28 100644 --- a/sys/emulation/linux/linux_util.c +++ b/sys/emulation/linux/linux_util.c @@ -28,13 +28,13 @@ * * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp * $FreeBSD: src/sys/compat/linux/linux_util.c,v 1.12.2.2 2001/11/05 19:08:23 marcel Exp $ - * $DragonFly: src/sys/emulation/linux/linux_util.c,v 1.9 2004/09/09 20:52:19 dillon Exp $ + * $DragonFly: src/sys/emulation/linux/linux_util.c,v 1.10 2004/11/12 00:09:18 dillon Exp $ */ #include #include #include -#include +#include #include #include @@ -53,8 +53,9 @@ int linux_copyin_path(char *uname, char **kname, int flags) { struct thread *td = curthread; - struct nameidata nd, ndroot; + struct nlookupdata nd, ndroot; struct vattr vat, vatroot; + struct vnode *vp, *vproot; char *buf, *cp; int error, length, dummy; @@ -93,17 +94,22 @@ linux_copyin_path(char *uname, char **kname, int flags) goto dont_translate; *cp = 0; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td); - error = namei(&nd); + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + nlookup_done(&nd); if (error) goto dont_translate; - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); *cp = '/'; return (0); case LINUX_PATH_EXISTS: - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td); - error = namei(&nd); + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + vp = NULL; + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + nlookup_done(&nd); if (error) goto dont_translate; @@ -120,28 +126,32 @@ linux_copyin_path(char *uname, char **kname, int flags) * emulation subtree does not exist. Cross our fingers * and return the untranslated path if something happens. */ - NDINIT(&ndroot, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, - linux_emul_path, td); - error = namei(&ndroot); + error = nlookup_init(&ndroot, linux_emul_path, UIO_SYSSPACE, + NLC_FOLLOW); + if (error == 0) + error = nlookup(&ndroot); + vproot = NULL; + if (error == 0) { + error = cache_vref(ndroot.nl_ncp, ndroot.nl_cred, + &vproot); + } + nlookup_done(&ndroot); if (error) { - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); + vrele(vp); goto dont_translate; } - error = VOP_GETATTR(nd.ni_vp, &vat, td); + error = VOP_GETATTR(vp, &vat, td); if (error == 0) { - error = VOP_GETATTR(ndroot.ni_vp, &vatroot, td); + error = VOP_GETATTR(vproot, &vatroot, td); if (error == 0) { if (vat.va_fsid == vatroot.va_fsid && vat.va_fileid == vatroot.va_fileid) error = ENOENT; } } - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); - NDFREE(&ndroot, NDF_ONLY_PNBUF); - vrele(ndroot.ni_vp); + vrele(vp); + vrele(vproot); if (error) goto dont_translate; return (0); @@ -165,8 +175,7 @@ done: int linux_translate_path(char *path, int size) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *buf; int error, length, dummy; @@ -178,16 +187,16 @@ linux_translate_path(char *path, int size) goto cleanup; /* - * If this errors, then the path probably doesn't exists. + * If this errors, then the path probably doesn't exist. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td); - error = namei(&nd); + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + nlookup_done(&nd); if (error) { error = 0; goto cleanup; } - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); /* * The alternate path does exist. Return it in the buffer if diff --git a/sys/emulation/ndis/subr_ndis.c b/sys/emulation/ndis/subr_ndis.c index 323a6078e0..ad4ae4b3a0 100644 --- a/sys/emulation/ndis/subr_ndis.c +++ b/sys/emulation/ndis/subr_ndis.c @@ -30,7 +30,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/compat/ndis/subr_ndis.c,v 1.62 2004/07/11 00:19:30 wpaul Exp $ - * $DragonFly: src/sys/emulation/ndis/subr_ndis.c,v 1.5 2004/10/12 19:20:40 dillon Exp $ + * $DragonFly: src/sys/emulation/ndis/subr_ndis.c,v 1.6 2004/11/12 00:09:20 dillon Exp $ */ /* @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include #include #include @@ -2543,11 +2543,12 @@ ndis_open_file(status, filehandle, filelength, filename, highestaddr) { char *afilename = NULL; struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; struct vattr vat; struct vattr *vap = &vat; ndis_fh *fh; + struct vnode *vp; char path[MAXPATHLEN]; ndis_unicode_to_ascii(filename->nus_buf, @@ -2562,29 +2563,31 @@ ndis_open_file(status, filehandle, filelength, filename, highestaddr) return; } - NDINIT2(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, - td, proc0.p_ucred); - - error = vn_open(&nd, FREAD, 0); + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP); + if (error == 0) + error = vn_open(&nd, NULL, FREAD, 0); if (error) { *status = NDIS_STATUS_FILE_NOT_FOUND; free(fh, M_TEMP); printf("NDIS: open file %s failed: %d\n", path, error); - return; + goto done; } - NDFREE(&nd, NDF_ONLY_PNBUF); + vp = nd.nl_open_vp; + nd.nl_open_vp = NULL; /* Get the file size. */ - VOP_GETATTR(nd.ni_vp, vap, td); - VOP_UNLOCK(nd.ni_vp, 0, td); + VOP_GETATTR(vp, vap, td); + VOP_UNLOCK(vp, 0, td); - fh->nf_vp = nd.ni_vp; + fh->nf_vp = vp; fh->nf_map = NULL; *filehandle = fh; *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF; *status = NDIS_STATUS_SUCCESS; +done: + nlookup_done(&nd); return; } diff --git a/sys/emulation/svr4/svr4_misc.c b/sys/emulation/svr4/svr4_misc.c index a53102eeb8..f8b80632ce 100644 --- a/sys/emulation/svr4/svr4_misc.c +++ b/sys/emulation/svr4/svr4_misc.c @@ -26,7 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/svr4/svr4_misc.c,v 1.13.2.7 2003/01/14 21:33:58 dillon Exp $ - * $DragonFly: src/sys/emulation/svr4/Attic/svr4_misc.c,v 1.25 2004/10/12 19:20:42 dillon Exp $ + * $DragonFly: src/sys/emulation/svr4/Attic/svr4_misc.c,v 1.26 2004/11/12 00:09:22 dillon Exp $ */ /* @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -1651,27 +1651,26 @@ svr4_sys_nice(struct svr4_sys_nice_args *uap) int svr4_sys_resolvepath(struct svr4_sys_resolvepath_args *uap) { - struct thread *td = curthread; /* XXX */ - struct nameidata nd; + struct nlookupdata nd; int error; int *retval; retval = &uap->sysmsg_result; - NDINIT(&nd, NAMEI_LOOKUP, CNP_SAVENAME, UIO_USERSPACE, - SCARG(uap, path), td); - - if ((error = namei(&nd)) != 0) - return error; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, 0); + if (error == 0) + error = nlookup(&nd); + if (error) + goto bad; - if ((error = copyout(nd.ni_cnd.cn_pnbuf, SCARG(uap, buf), - SCARG(uap, bufsiz))) != 0) + if ((error = copyout(nd.nl_path, SCARG(uap, buf), + SCARG(uap, bufsiz))) != 0) { goto bad; + } - *retval = strlen(nd.ni_cnd.cn_pnbuf) < SCARG(uap, bufsiz) ? - strlen(nd.ni_cnd.cn_pnbuf) + 1 : SCARG(uap, bufsiz); + *retval = strlen(nd.nl_path) < SCARG(uap, bufsiz) ? + strlen(nd.nl_path) + 1 : SCARG(uap, bufsiz); bad: - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_vp); - return error; + nlookup_done(&nd); + return (error); } diff --git a/sys/emulation/svr4/svr4_sysvec.c b/sys/emulation/svr4/svr4_sysvec.c index 4c2549723d..c03819bbc3 100644 --- a/sys/emulation/svr4/svr4_sysvec.c +++ b/sys/emulation/svr4/svr4_sysvec.c @@ -28,7 +28,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/svr4/svr4_sysvec.c,v 1.10.2.2 2002/07/09 14:12:43 robert Exp $ - * $DragonFly: src/sys/emulation/svr4/Attic/svr4_sysvec.c,v 1.10 2004/01/08 18:39:18 asmodai Exp $ + * $DragonFly: src/sys/emulation/svr4/Attic/svr4_sysvec.c,v 1.11 2004/11/12 00:09:22 dillon Exp $ */ /* XXX we use functions that might not exist. */ @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include @@ -251,10 +251,11 @@ svr4_emul_find(sgp, prefix, path, pbuf, cflag) int cflag; { struct thread *td = curthread; /* XXX */ - struct nameidata nd; - struct nameidata ndroot; + struct nlookupdata nd; + struct nlookupdata ndroot; struct vattr vat; struct vattr vatroot; + struct vnode *vp; int error; char *ptr, *buf, *cp; size_t sz, len; @@ -301,24 +302,31 @@ svr4_emul_find(sgp, prefix, path, pbuf, cflag) for (cp = &ptr[len] - 1; *cp != '/'; cp--); *cp = '\0'; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td); - - if ((error = namei(&nd)) != 0) { + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + nlookup_done(&nd); + if (error) { free(buf, M_TEMP); - return error; + return (error); } - NDFREE(&nd, NDF_ONLY_PNBUF); - *cp = '/'; - } - else { - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, buf, td); - - if ((error = namei(&nd)) != 0) { + } else { + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + vp = NULL; + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + nlookup_done(&nd); + if (error) { free(buf, M_TEMP); - return error; + return (error); } - NDFREE(&nd, NDF_ONLY_PNBUF); + error = VOP_GETATTR(vp, &vat, td); + vrele(vp); + if (error) + goto done; /* * We now compare the vnode of the svr4_root to the one @@ -328,47 +336,38 @@ svr4_emul_find(sgp, prefix, path, pbuf, cflag) * root directory and never finding it, because "/" resolves * to the emulation root directory. This is expensive :-( */ - NDINIT(&ndroot, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, - svr4_emul_path, td); - - if ((error = namei(&ndroot)) != 0) { - /* Cannot happen! */ + error = nlookup_init(&ndroot, svr4_emul_path, UIO_SYSSPACE, + NLC_FOLLOW); + if (error == 0) + error = nlookup(&ndroot); + vp = NULL; + if (error == 0) + error = cache_vref(ndroot.nl_ncp, ndroot.nl_cred, &vp); + nlookup_done(&ndroot); + if (error) { free(buf, M_TEMP); - vrele(nd.ni_vp); - return error; + return (error); } - NDFREE(&ndroot, NDF_ONLY_PNBUF); - - if ((error = VOP_GETATTR(nd.ni_vp, &vat, td)) != 0) { - goto done; - } - - if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, td)) - != 0) { + error = VOP_GETATTR(vp, &vatroot, td); + vrele(vp); + if (error) goto done; - } if (vat.va_fsid == vatroot.va_fsid && vat.va_fileid == vatroot.va_fileid) { error = ENOENT; goto done; } - } - if (sgp == NULL) + if (sgp == NULL) { *pbuf = buf; - else { + } else { sz = &ptr[len] - buf; *pbuf = stackgap_alloc(sgp, sz + 1); error = copyout(buf, *pbuf, sz); free(buf, M_TEMP); } - - done: - vrele(nd.ni_vp); - if (!cflag) - vrele(ndroot.ni_vp); return error; } diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 8cc245adb4..4a4e5318a0 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -27,7 +27,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/kern/imgact_elf.c,v 1.73.2.13 2002/12/28 19:49:41 dillon Exp $ - * $DragonFly: src/sys/kern/imgact_elf.c,v 1.22 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/imgact_elf.c,v 1.23 2004/11/12 00:09:23 dillon Exp $ */ #include @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -337,13 +337,13 @@ static int elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) { struct { - struct nameidata nd; + struct nlookupdata nd; struct vattr attr; struct image_params image_params; } *tempdata; const Elf_Ehdr *hdr = NULL; const Elf_Phdr *phdr = NULL; - struct nameidata *nd; + struct nlookupdata *nd; struct vmspace *vmspace = p->p_vmspace; struct vattr *attr; struct image_params *imgp; @@ -365,23 +365,23 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) imgp->attr = attr; imgp->firstpage = NULL; imgp->image_header = NULL; + imgp->vp = NULL; - NDINIT(nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW, - UIO_SYSSPACE, file, td); - - if ((error = namei(nd)) != 0) { - nd->ni_vp = NULL; + error = nlookup_init(nd, file, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(nd); + if (error == 0) + error = cache_vget(nd->nl_ncp, nd->nl_cred, LK_EXCLUSIVE, &imgp->vp); + nlookup_done(nd); + if (error) goto fail; - } - NDFREE(nd, NDF_ONLY_PNBUF); - imgp->vp = nd->ni_vp; /* * Check permissions, modes, uid, etc on the file, and "open" it. */ error = exec_check_permissions(imgp); if (error) { - VOP_UNLOCK(nd->ni_vp, 0, td); + VOP_UNLOCK(imgp->vp, 0, td); goto fail; } @@ -391,8 +391,8 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) * its VTEXT flag, too. */ if (error == 0) - nd->ni_vp->v_flag |= VTEXT; - VOP_UNLOCK(nd->ni_vp, 0, td); + imgp->vp->v_flag |= VTEXT; + VOP_UNLOCK(imgp->vp, 0, td); if (error) goto fail; @@ -429,7 +429,7 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) prot |= VM_PROT_READ; error = elf_load_section( - p, vmspace, nd->ni_vp, + p, vmspace, imgp->vp, phdr[i].p_offset, (caddr_t)phdr[i].p_vaddr + rbase, @@ -452,9 +452,10 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) fail: if (imgp->firstpage) exec_unmap_first_page(imgp); - if (nd->ni_vp) - vrele(nd->ni_vp); - + if (imgp->vp) { + vrele(imgp->vp); + imgp->vp = NULL; + } free(tempdata, M_TEMP); return error; @@ -801,9 +802,12 @@ elf_coredump(struct proc *p, struct vnode *vp, off_t limit) return (error); fsetcred(fp, p->p_ucred); + /* + * XXX fixme. + */ fp->f_data = (caddr_t)vp; fp->f_flag = O_CREAT|O_WRONLY|O_NOFOLLOW; - fp->f_ops = &vnops; + fp->f_ops = &vnode_fileops; fp->f_type = DTYPE_VNODE; VOP_UNLOCK(vp, 0, p->p_thread); diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index 110333885e..a6c9c59c21 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -38,7 +38,7 @@ * * @(#)kern_acct.c 8.1 (Berkeley) 6/14/93 * $FreeBSD: src/sys/kern/kern_acct.c,v 1.23.2.1 2002/07/24 18:33:55 johan Exp $ - * $DragonFly: src/sys/kern/kern_acct.c,v 1.15 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/kern_acct.c,v 1.16 2004/11/12 00:09:23 dillon Exp $ */ #include @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include #include @@ -123,7 +123,8 @@ acct(uap) } */ *uap; { struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; + struct vnode *vp; int error; /* Make sure that the caller is root. */ @@ -136,29 +137,40 @@ acct(uap) * appending and make sure it's a 'normal'. */ if (SCARG(uap, path) != NULL) { - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, - SCARG(uap, path), td); - error = vn_open(&nd, FWRITE | O_APPEND, 0); - if (error) + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, + NLC_LOCKVP); + if (error == 0) + error = vn_open(&nd, NULL, FWRITE | O_APPEND, 0); + if (error == 0 && nd.nl_open_vp->v_type != VREG) + error = EACCES; + if (error) { + nlookup_done(&nd); return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - VOP_UNLOCK(nd.ni_vp, 0, td); - if (nd.ni_vp->v_type != VREG) { - vn_close(nd.ni_vp, FWRITE | O_APPEND, td); - return (EACCES); } + vp = nd.nl_open_vp; + nd.nl_open_vp = NULL; + nlookup_done(&nd); + + VOP_UNLOCK(vp, 0, td); + } else { + vp = NULL; } /* * If accounting was previously enabled, kill the old space-watcher, - * close the file, and (if no new file was specified, leave). + * close the file. */ if (acctp != NULLVP || savacctp != NULLVP) { callout_stop(&acctwatch_handle); error = vn_close((acctp != NULLVP ? acctp : savacctp), - FWRITE | O_APPEND, td); + FWRITE | O_APPEND, td); acctp = savacctp = NULLVP; } + + /* + * If no new file opened then leave. We never did an nlookup so + * don't try cleaning it up. + */ if (SCARG(uap, path) == NULL) return (error); @@ -166,7 +178,7 @@ acct(uap) * Save the new accounting file vnode, and schedule the new * free space watcher. */ - acctp = nd.ni_vp; + acctp = vp; acctwatch(NULL); return (error); } diff --git a/sys/kern/kern_acl.c b/sys/kern/kern_acl.c index 4e7dc33463..8bd441a120 100644 --- a/sys/kern/kern_acl.c +++ b/sys/kern/kern_acl.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_acl.c,v 1.2.2.1 2000/07/28 18:48:16 rwatson Exp $ - * $DragonFly: src/sys/kern/kern_acl.c,v 1.7 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/kern_acl.c,v 1.8 2004/11/12 00:09:23 dillon Exp $ */ /* @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include @@ -156,18 +156,21 @@ vacl_aclcheck(struct vnode *vp, acl_type_t type, struct acl *aclp) int __acl_get_file(struct __acl_get_file_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; + struct vnode *vp; int error; - /* what flags are required here -- possible not LOCKLEAF? */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, - UIO_USERSPACE, SCARG(uap, path), td); - error = namei(&nd); - if (error) - return(error); - error = vacl_get_acl(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + nlookup_done(&nd); + if (error == 0) { + error = vacl_get_acl(vp, SCARG(uap, type), SCARG(uap, aclp)); + vrele(vp); + } return (error); } @@ -177,17 +180,21 @@ __acl_get_file(struct __acl_get_file_args *uap) int __acl_set_file(struct __acl_set_file_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; + struct vnode *vp; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, - UIO_USERSPACE, SCARG(uap, path), td); - error = namei(&nd); - if (error) - return(error); - error = vacl_set_acl(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + nlookup_done(&nd); + if (error == 0) { + error = vacl_set_acl(vp, SCARG(uap, type), SCARG(uap, aclp)); + vrele(vp); + } return (error); } @@ -233,17 +240,22 @@ __acl_set_fd(struct __acl_set_fd_args *uap) int __acl_delete_file(struct __acl_delete_file_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; + struct vnode *vp; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, - UIO_USERSPACE, SCARG(uap, path), td); - error = namei(&nd); - if (error) - return(error); - error = vacl_delete(nd.ni_vp, SCARG(uap, type)); - NDFREE(&nd, 0); + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + nlookup_done(&nd); + + if (error == 0) { + error = vacl_delete(vp, SCARG(uap, type)); + vrele(vp); + } return (error); } @@ -271,17 +283,22 @@ __acl_delete_fd(struct __acl_delete_fd_args *uap) int __acl_aclcheck_file(struct __acl_aclcheck_file_args *uap) { - struct thread *td = curthread; - struct nameidata nd; - int error; + struct nlookupdata nd; + struct vnode *vp; + int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, - UIO_USERSPACE, SCARG(uap, path), td); - error = namei(&nd); - if (error) - return(error); - error = vacl_aclcheck(nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + nlookup_done(&nd); + + if (error == 0) { + error = vacl_aclcheck(vp, SCARG(uap, type), SCARG(uap, aclp)); + vrele(vp); + } return (error); } diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index d64e348f8f..56c8be6050 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -70,7 +70,7 @@ * * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/kern_clock.c,v 1.105.2.10 2002/10/17 13:19:40 maxim Exp $ - * $DragonFly: src/sys/kern/kern_clock.c,v 1.24 2004/09/17 00:18:09 dillon Exp $ + * $DragonFly: src/sys/kern/kern_clock.c,v 1.25 2004/11/12 00:09:23 dillon Exp $ */ #include "opt_ntp.h" @@ -279,10 +279,14 @@ hardclock(systimer_t info, struct intrframe *frame) * stay in synch. * * Note that we never allow info->time (aka gd->gd_hardclock.time) - * to reverse index gd_cpuclock_base. + * to reverse index gd_cpuclock_base, but that it is possible for + * it to temporarily get behind in the seconds if something in the + * system locks interrupts for a long period of time. Since periodic + * timers count events, though everything should resynch again + * immediately. */ cputicks = info->time - gd->gd_cpuclock_base; - if (cputicks > cputimer_freq) { + if (cputicks >= cputimer_freq) { ++gd->gd_time_seconds; gd->gd_cpuclock_base += cputimer_freq; } @@ -676,6 +680,12 @@ SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, * Each cpu independantly maintains the current time of day, so all * we need to do to protect ourselves from changes is to do a loop * check on the seconds field changing out from under us. + * + * The system timer maintains a 32 bit count and due to various issues + * it is possible for the calculated delta to occassionally exceed + * cputimer_freq. If this occurs the cputimer_freq64_nsec multiplication + * can easily overflow, so we deal with the case. For uniformity we deal + * with the case in the usec case too. */ void getmicrouptime(struct timeval *tvp) @@ -687,6 +697,11 @@ getmicrouptime(struct timeval *tvp) tvp->tv_sec = gd->gd_time_seconds; delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tvp->tv_sec != gd->gd_time_seconds); + + if (delta >= cputimer_freq) { + tvp->tv_sec += delta / cputimer_freq; + delta %= cputimer_freq; + } tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; if (tvp->tv_usec >= 1000000) { tvp->tv_usec -= 1000000; @@ -704,11 +719,12 @@ getnanouptime(struct timespec *tsp) tsp->tv_sec = gd->gd_time_seconds; delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); - tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; - if (tsp->tv_nsec >= 1000000000) { - tsp->tv_nsec -= 1000000000; - ++tsp->tv_sec; + + if (delta >= cputimer_freq) { + tsp->tv_sec += delta / cputimer_freq; + delta %= cputimer_freq; } + tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; } void @@ -721,11 +737,12 @@ microuptime(struct timeval *tvp) tvp->tv_sec = gd->gd_time_seconds; delta = cputimer_count() - gd->gd_cpuclock_base; } while (tvp->tv_sec != gd->gd_time_seconds); - tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; - if (tvp->tv_usec >= 1000000) { - tvp->tv_usec -= 1000000; - ++tvp->tv_sec; + + if (delta >= cputimer_freq) { + tvp->tv_sec += delta / cputimer_freq; + delta %= cputimer_freq; } + tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; } void @@ -738,11 +755,12 @@ nanouptime(struct timespec *tsp) tsp->tv_sec = gd->gd_time_seconds; delta = cputimer_count() - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); - tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; - if (tsp->tv_nsec >= 1000000000) { - tsp->tv_nsec -= 1000000000; - ++tsp->tv_sec; + + if (delta >= cputimer_freq) { + tsp->tv_sec += delta / cputimer_freq; + delta %= cputimer_freq; } + tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; } /* @@ -759,6 +777,11 @@ getmicrotime(struct timeval *tvp) tvp->tv_sec = gd->gd_time_seconds; delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tvp->tv_sec != gd->gd_time_seconds); + + if (delta >= cputimer_freq) { + tvp->tv_sec += delta / cputimer_freq; + delta %= cputimer_freq; + } tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; tvp->tv_sec += basetime.tv_sec; @@ -779,6 +802,11 @@ getnanotime(struct timespec *tsp) tsp->tv_sec = gd->gd_time_seconds; delta = gd->gd_hardclock.time - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); + + if (delta >= cputimer_freq) { + tsp->tv_sec += delta / cputimer_freq; + delta %= cputimer_freq; + } tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; tsp->tv_sec += basetime.tv_sec; @@ -799,6 +827,11 @@ microtime(struct timeval *tvp) tvp->tv_sec = gd->gd_time_seconds; delta = cputimer_count() - gd->gd_cpuclock_base; } while (tvp->tv_sec != gd->gd_time_seconds); + + if (delta >= cputimer_freq) { + tvp->tv_sec += delta / cputimer_freq; + delta %= cputimer_freq; + } tvp->tv_usec = (cputimer_freq64_usec * delta) >> 32; tvp->tv_sec += basetime.tv_sec; @@ -819,6 +852,11 @@ nanotime(struct timespec *tsp) tsp->tv_sec = gd->gd_time_seconds; delta = cputimer_count() - gd->gd_cpuclock_base; } while (tsp->tv_sec != gd->gd_time_seconds); + + if (delta >= cputimer_freq) { + tsp->tv_sec += delta / cputimer_freq; + delta %= cputimer_freq; + } tsp->tv_nsec = (cputimer_freq64_nsec * delta) >> 32; tsp->tv_sec += basetime.tv_sec; @@ -941,7 +979,8 @@ pps_event(struct pps_state *pps, sysclock_t count, int event) ts.tv_sec = gd->gd_time_seconds; delta = count - gd->gd_cpuclock_base; } while (ts.tv_sec != gd->gd_time_seconds); - if (delta > cputimer_freq) { + + if (delta >= cputimer_freq) { ts.tv_sec += delta / cputimer_freq; delta %= cputimer_freq; } @@ -968,7 +1007,13 @@ pps_event(struct pps_state *pps, sysclock_t count, int event) /* magic, at its best... */ tcount = count - pps->ppscount[2]; pps->ppscount[2] = count; - delta = (cputimer_freq64_nsec * tcount) >> 32; + if (tcount >= cputimer_freq) { + delta = 1000000000 * (tcount / cputimer_freq) + + (cputimer_freq64_nsec * + (tcount % cputimer_freq)) >> 32; + } else { + delta = (cputimer_freq64_nsec * tcount) >> 32; + } hardpps(tsp, delta); } #endif diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 098616d279..2967202dbd 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -37,7 +37,7 @@ * * @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94 * $FreeBSD: src/sys/kern/kern_descrip.c,v 1.81.2.19 2004/02/28 00:43:31 tegge Exp $ - * $DragonFly: src/sys/kern/kern_descrip.c,v 1.30 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/kern_descrip.c,v 1.31 2004/11/12 00:09:23 dillon Exp $ */ #include "opt_compat.h" @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include #include #include @@ -876,62 +876,78 @@ fdavail(struct proc *p, int n) * is allocated and the file pointer is returned unassociated with * any process. resultfd is only used if p is not NULL and may * separately be NULL indicating that you don't need the returned fd. + * + * A held file pointer is returned. If a descriptor has been allocated + * an additional hold on the fp will be made due to the fd_ofiles[] + * reference. */ int falloc(struct proc *p, struct file **resultfp, int *resultfd) { - struct file *fp, *fq; - int error, i; static struct timeval lastfail; static int curfail; + struct file *fp; + int error; + fp = NULL; + + /* + * Handle filetable full issues and root overfill. + */ if (nfiles >= maxfiles - maxfilesrootres && ((p && p->p_ucred->cr_ruid != 0) || nfiles >= maxfiles)) { if (ppsratecheck(&lastfail, &curfail, 1)) { printf("kern.maxfiles limit exceeded by uid %d, please see tuning(7).\n", (p ? p->p_ucred->cr_ruid : -1)); } - return (ENFILE); + error = ENFILE; + goto done; } + /* * Allocate a new file descriptor. - * If the process has file descriptor zero open, add to the list - * of open files at that point, otherwise put it at the front of - * the list of open files. */ nfiles++; fp = malloc(sizeof(struct file), M_FILE, M_WAITOK | M_ZERO); - - /* - * wait until after malloc (which may have blocked) returns before - * allocating the slot, else a race might have shrunk it if we had - * allocated it before the malloc. - */ - i = -1; - if (p && (error = fdalloc(p, 0, &i))) { - nfiles--; - free(fp, M_FILE); - return (error); - } fp->f_count = 1; fp->f_ops = &badfileops; fp->f_seqcount = 1; - if (p) { + if (p) fp->f_cred = crhold(p->p_ucred); - if ((fq = p->p_fd->fd_ofiles[0]) != NULL) { - LIST_INSERT_AFTER(fq, fp, f_list); - } else { - LIST_INSERT_HEAD(&filehead, fp, f_list); + else + fp->f_cred = crhold(proc0.p_ucred); + LIST_INSERT_HEAD(&filehead, fp, f_list); + if (resultfd) { + if ((error = fsetfd(p, fp, resultfd)) != 0) { + fdrop(fp, p->p_thread); + fp = NULL; } - p->p_fd->fd_ofiles[i] = fp; } else { - fp->f_cred = crhold(proc0.p_ucred); - LIST_INSERT_HEAD(&filehead, fp, f_list); + error = 0; } - if (resultfp) - *resultfp = fp; - if (resultfd) - *resultfd = i; +done: + *resultfp = fp; + return (0); +} + +/* + * Associate a file pointer with a file descriptor. On success the fp + * will have an additional ref representing the fd_ofiles[] association. + */ +int +fsetfd(struct proc *p, struct file *fp, int *resultfd) +{ + int i; + int error; + + KKASSERT(p); + + i = -1; + if ((error = fdalloc(p, 0, &i)) == 0) { + fhold(fp); + p->p_fd->fd_ofiles[i] = fp; + } + *resultfd = i; return (0); } @@ -1334,7 +1350,7 @@ int fdcheckstd(struct proc *p) { struct thread *td = p->p_thread; - struct nameidata nd; + struct nlookupdata nd; struct filedesc *fdp; struct file *fp; register_t retval; @@ -1346,33 +1362,30 @@ fdcheckstd(struct proc *p) devnull = -1; error = 0; for (i = 0; i < 3; i++) { - if (fdp->fd_ofiles[i] != NULL) - continue; - if (devnull < 0) { - error = falloc(p, &fp, &fd); - if (error != 0) - break; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, - "/dev/null", td); - flags = FREAD | FWRITE; - error = vn_open(&nd, flags, 0); - if (error != 0) { - fdp->fd_ofiles[i] = NULL; - fdrop(fp, td); - break; - } - NDFREE(&nd, NDF_ONLY_PNBUF); - fp->f_data = (caddr_t)nd.ni_vp; - fp->f_flag = flags; - fp->f_ops = &vnops; - fp->f_type = DTYPE_VNODE; - VOP_UNLOCK(nd.ni_vp, 0, td); - devnull = fd; - } else { - error = kern_dup(DUP_FIXED, devnull, i, &retval); - if (error != 0) - break; - } + if (fdp->fd_ofiles[i] != NULL) + continue; + if (devnull < 0) { + if ((error = falloc(p, &fp, NULL)) != 0) + break; + + error = nlookup_init(&nd, "/dev/null", UIO_SYSSPACE, + NLC_FOLLOW|NLC_LOCKVP); + flags = FREAD | FWRITE; + if (error == 0) + error = vn_open(&nd, fp, flags, 0); + if (error == 0) + error = fsetfd(p, fp, &fd); + fdrop(fp, td); + nlookup_done(&nd); + if (error) + break; + KKASSERT(i == fd); + devnull = fd; + } else { + error = kern_dup(DUP_FIXED, devnull, i, &retval); + if (error != 0) + break; + } } return (error); } diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 65594000c7..c75c329fea 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_event.c,v 1.2.2.10 2004/04/04 07:03:14 cperciva Exp $ - * $DragonFly: src/sys/kern/kern_event.c,v 1.12 2004/05/13 23:49:23 dillon Exp $ + * $DragonFly: src/sys/kern/kern_event.c,v 1.13 2004/11/12 00:09:23 dillon Exp $ */ #include @@ -377,6 +377,7 @@ kqueue(struct kqueue_args *uap) TAILQ_INIT(&kq->kq_head); fp->f_data = (caddr_t)kq; uap->sysmsg_result = fd; + fdrop(fp, curthread); if (fdp->fd_knlistsize < 0) fdp->fd_knlistsize = 0; /* this process has a kq */ kq->kq_fdp = fdp; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 4ffc0e3084..5ff14ee9a5 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_exec.c,v 1.107.2.15 2002/07/30 15:40:46 nectar Exp $ - * $DragonFly: src/sys/kern/kern_exec.c,v 1.28 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/kern_exec.c,v 1.29 2004/11/12 00:09:23 dillon Exp $ */ #include @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -117,7 +117,7 @@ print_execve_args(struct image_args *args) static const struct execsw **execsw; int -kern_execve(struct nameidata *ndp, struct image_args *args) +kern_execve(struct nlookupdata *nd, struct image_args *args) { struct thread *td = curthread; struct proc *p = td->td_proc; @@ -164,13 +164,17 @@ kern_execve(struct nameidata *ndp, struct image_args *args) interpret: /* - * Translate the file name. namei() returns a vnode pointer - * in ni_vp amoung other things. + * Translate the file name to a vnode. Unlock the cache entry to + * improve parallelism for programs exec'd in parallel. */ - if ((error = namei(ndp)) != 0) + if ((error = nlookup(nd)) != 0) + goto exec_fail; + error = cache_vget(nd->nl_ncp, nd->nl_cred, LK_EXCLUSIVE, &imgp->vp); + KKASSERT(nd->nl_flags & NLC_NCPISLOCKED); + nd->nl_flags &= ~NLC_NCPISLOCKED; + cache_unlock(nd->nl_ncp); + if (error) goto exec_fail; - - imgp->vp = ndp->ni_vp; /* * Check file permissions (also 'opens' file) @@ -233,13 +237,13 @@ interpret: */ if (imgp->interpreted) { exec_unmap_first_page(imgp); - /* free name buffer and old vnode */ - NDFREE(ndp, NDF_ONLY_PNBUF); - vrele(ndp->ni_vp); - /* set new name to that of the interpreter */ - NDINIT(ndp, NAMEI_LOOKUP, - CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME, - UIO_SYSSPACE, imgp->interpreter_name, td); + nlookup_done(nd); + vrele(imgp->vp); + imgp->vp = NULL; + error = nlookup_init(nd, imgp->interpreter_name, UIO_SYSSPACE, + NLC_FOLLOW); + if (error) + goto exec_fail; goto interpret; } @@ -306,8 +310,8 @@ interpret: execsigs(p); /* name this process - nameiexec(p, ndp) */ - len = min(ndp->ni_cnd.cn_namelen,MAXCOMLEN); - bcopy(ndp->ni_cnd.cn_nameptr, p->p_comm, len); + len = min(nd->nl_ncp->nc_nlen, MAXCOMLEN); + bcopy(nd->nl_ncp->nc_name, p->p_comm, len); p->p_comm[len] = 0; /* @@ -385,8 +389,8 @@ interpret: */ if (p->p_textvp) /* release old reference */ vrele(p->p_textvp); - vref(ndp->ni_vp); - p->p_textvp = ndp->ni_vp; + p->p_textvp = imgp->vp; + vref(p->p_textvp); /* * Notify others that we exec'd, and clear the P_INEXEC flag @@ -435,8 +439,8 @@ exec_fail_dealloc: exec_unmap_first_page(imgp); if (imgp->vp) { - NDFREE(ndp, NDF_ONLY_PNBUF); vrele(imgp->vp); + imgp->vp = NULL; } if (error == 0) { @@ -463,19 +467,18 @@ exec_fail: int execve(struct execve_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; struct image_args args; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME, - UIO_USERSPACE, uap->fname, td); - - error = exec_copyin_args(&args, uap->fname, PATH_USERSPACE, - uap->argv, uap->envv); + error = nlookup_init(&nd, uap->fname, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) { + error = exec_copyin_args(&args, uap->fname, PATH_USERSPACE, + uap->argv, uap->envv); + } if (error == 0) error = kern_execve(&nd, &args); - + nlookup_done(&nd); exec_free_args(&args); /* @@ -497,11 +500,24 @@ exec_map_first_page(struct image_params *imgp) vm_page_t ma[VM_INITIAL_PAGEIN]; vm_page_t m; vm_object_t object; + int error; if (imgp->firstpage) exec_unmap_first_page(imgp); - VOP_GETVOBJECT(imgp->vp, &object); + /* + * XXX the callers should really use vn_open so we don't have to + * do this junk. + */ + if ((error = VOP_GETVOBJECT(imgp->vp, &object)) != 0) { + if (vn_canvmio(imgp->vp) == TRUE) { + error = vfs_object_create(imgp->vp, curthread); + if (error == 0) + error = VOP_GETVOBJECT(imgp->vp, &object); + } + } + if (error) + return (EIO); /* * We shouldn't need protection for vm_page_grab() but we certainly @@ -906,7 +922,7 @@ exec_check_permissions(imgp) * Call filesystem specific open routine (which does nothing in the * general case). */ - error = VOP_OPEN(vp, FREAD, p->p_ucred, td); + error = VOP_OPEN(vp, FREAD, p->p_ucred, NULL, td); if (error) return (error); diff --git a/sys/kern/kern_fp.c b/sys/kern/kern_fp.c index 79856b3c4e..8eda3c748b 100644 --- a/sys/kern/kern_fp.c +++ b/sys/kern/kern_fp.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/kern/kern_fp.c,v 1.8 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/kern_fp.c,v 1.9 2004/11/12 00:09:23 dillon Exp $ */ /* @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #include #include @@ -96,7 +96,7 @@ typedef struct file *file_t; int fp_open(const char *path, int flags, int mode, file_t *fpp) { - struct nameidata nd; + struct nlookupdata nd; struct thread *td; struct file *fp; int error; @@ -106,21 +106,15 @@ fp_open(const char *path, int flags, int mode, file_t *fpp) fp = *fpp; td = curthread; if (td->td_proc) { - if ((flags & O_ROOTCRED) == 0 && td->td_proc) + if ((flags & O_ROOTCRED) == 0) fsetcred(fp, td->td_proc->p_ucred); - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td); - } else { - NDINIT2(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td, proc0.p_ucred); } + error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_LOCKVP); flags = FFLAGS(flags); - if ((error = vn_open(&nd, flags, mode)) == 0) { - NDFREE(&nd, NDF_ONLY_PNBUF); - fp->f_data = (caddr_t)nd.ni_vp; - fp->f_flag = flags; - fp->f_ops = &vnops; - fp->f_type = DTYPE_VNODE; - VOP_UNLOCK(nd.ni_vp, 0, td); - } else { + if (error == 0) + error = vn_open(&nd, fp, flags, mode); + nlookup_done(&nd); + if (error) { fdrop(fp, td); *fpp = NULL; } @@ -129,8 +123,14 @@ fp_open(const char *path, int flags, int mode, file_t *fpp) /* - * fp_vpopen(): open a file pointer given a vnode. The vnode must be locked. - * The vnode will be returned unlocked whether an error occurs or not. + * fp_vpopen(): convert a vnode to a file pointer, call VOP_OPEN() on the + * the vnode. The vnode must be refd and locked. + * + * On success the vnode's ref is inherited by the file pointer and the caller + * should not vrele() it, and the vnode is unlocked. + * + * On failure the vnode remains locked and refd and the caller is responsible + * for vput()ing it. */ int fp_vpopen(struct vnode *vp, int flags, file_t *fpp) @@ -140,7 +140,6 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp) int vmode; int error; - *fpp = NULL; td = curthread; /* @@ -148,22 +147,22 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp) */ if (vp->v_type == VLNK) { error = EMLINK; - goto done; + goto bad2; } if (vp->v_type == VSOCK) { error = EOPNOTSUPP; - goto done; + goto bad2; } flags = FFLAGS(flags); vmode = 0; if (flags & (FWRITE | O_TRUNC)) { if (vp->v_type == VDIR) { error = EISDIR; - goto done; + goto bad2; } error = vn_writechk(vp); if (error) - goto done; + goto bad2; vmode |= VWRITE; } if (flags & FREAD) @@ -171,41 +170,50 @@ fp_vpopen(struct vnode *vp, int flags, file_t *fpp) if (vmode) { error = VOP_ACCESS(vp, vmode, td->td_proc->p_ucred, td); if (error) - goto done; - } - error = VOP_OPEN(vp, flags, td->td_proc->p_ucred, td); - if (error) - goto done; - /* - * Make sure that a VM object is created for VMIO support. - */ - if (vn_canvmio(vp) == TRUE) { - if ((error = vfs_object_create(vp, td)) != 0) - goto done; + goto bad2; } /* * File pointer setup */ if ((error = falloc(NULL, fpp, NULL)) != 0) - goto done; + goto bad2; fp = *fpp; if ((flags & O_ROOTCRED) == 0 && td->td_proc) fsetcred(fp, td->td_proc->p_ucred); fp->f_data = (caddr_t)vp; fp->f_flag = flags; - fp->f_ops = &vnops; + fp->f_ops = &vnode_fileops; fp->f_type = DTYPE_VNODE; + error = VOP_OPEN(vp, flags, td->td_proc->p_ucred, fp, td); + if (error) + goto bad1; + /* - * All done, set return value and update v_writecount now that no more - * errors can occur. + * Make sure that a VM object is created for VMIO support. + */ + if (vn_canvmio(vp) == TRUE) { + if ((error = vfs_object_create(vp, td)) != 0) { + VOP_CLOSE(vp, flags, td); + goto bad1; + } + } + + /* + * All done, update v_writecount now that no more errors can occur. */ - *fpp = fp; if (flags & FWRITE) vp->v_writecount++; -done: VOP_UNLOCK(vp, 0, td); + return (0); +bad1: + fp->f_ops = &badfileops; /* open failed, don't close */ + fp->f_data = NULL; + fdrop(fp, td); + /* leave the vnode intact, but fall through and unlock it anyway */ +bad2: + *fpp = NULL; return (error); } diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index b83585e082..ffb563d000 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -32,7 +32,7 @@ * * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93 * $FreeBSD: src/sys/kern/kern_ktrace.c,v 1.35.2.6 2002/07/05 22:36:38 darrenr Exp $ - * $DragonFly: src/sys/kern/kern_ktrace.c,v 1.16 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/kern_ktrace.c,v 1.17 2004/11/12 00:09:23 dillon Exp $ */ #include "opt_ktrace.h" @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -253,27 +253,28 @@ ktrace(struct ktrace_args *uap) int descend = uap->ops & KTRFLAG_DESCEND; int ret = 0; int error = 0; - struct nameidata nd; + struct nlookupdata nd; curp->p_traceflag |= KTRFAC_ACTIVE; if (ops != KTROP_CLEAR) { /* * an operation which requires a file argument. */ - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, uap->fname, td); - error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0); + error = nlookup_init(&nd, uap->fname, + UIO_USERSPACE, NLC_LOCKVP); + if (error == 0) + error = vn_open(&nd, NULL, FREAD|FWRITE|O_NOFOLLOW, 0); + if (error == 0 && nd.nl_open_vp->v_type != VREG) + error = EACCES; if (error) { curp->p_traceflag &= ~KTRFAC_ACTIVE; + nlookup_done(&nd); return (error); } - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; + vp = nd.nl_open_vp; + nd.nl_open_vp = NULL; + nlookup_done(&nd); VOP_UNLOCK(vp, 0, td); - if (vp->v_type != VREG) { - (void) vn_close(vp, FREAD|FWRITE, td); - curp->p_traceflag &= ~KTRFAC_ACTIVE; - return (EACCES); - } } /* * Clear all uses of the tracefile. XXX umm, what happens to the @@ -285,7 +286,7 @@ ktrace(struct ktrace_args *uap) if (ktrcanset(curp, p) && p->p_tracep == vp) { p->p_tracep = NULL; p->p_traceflag = 0; - (void) vn_close(vp, FREAD|FWRITE, td); + vn_close(vp, FREAD|FWRITE, td); } else { error = EPERM; } @@ -312,12 +313,12 @@ ktrace(struct ktrace_args *uap) error = ESRCH; goto done; } - LIST_FOREACH(p, &pg->pg_members, p_pglist) + LIST_FOREACH(p, &pg->pg_members, p_pglist) { if (descend) ret |= ktrsetchildren(curp, p, ops, facs, vp); else ret |= ktrops(curp, p, ops, facs, vp); - + } } else { /* * by pid @@ -336,7 +337,7 @@ ktrace(struct ktrace_args *uap) error = EPERM; done: if (vp != NULL) - (void) vn_close(vp, FWRITE, td); + vn_close(vp, FWRITE, td); curp->p_traceflag &= ~KTRFAC_ACTIVE; return (error); #else diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index de28449bcd..e9579b4a85 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_linker.c,v 1.41.2.3 2001/11/21 17:50:35 luigi Exp $ - * $DragonFly: src/sys/kern/kern_linker.c,v 1.19 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/kern_linker.c,v 1.20 2004/11/12 00:09:23 dillon Exp $ */ #include "opt_ddb.h" @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include @@ -1096,8 +1096,7 @@ linker_strdup(const char *str) char * linker_search_path(const char *name) { - struct nameidata nd; - struct thread *td = curthread; + struct nlookupdata nd; char *cp, *ep, *result; int error; enum vtype type; @@ -1124,16 +1123,17 @@ linker_search_path(const char *name) * Attempt to open the file, and return the path if we succeed and it's * a regular file. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, result, td); - error = vn_open(&nd, FREAD, 0); + error = nlookup_init(&nd, result, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP); + if (error == 0) + error = vn_open(&nd, NULL, FREAD, 0); if (error == 0) { - NDFREE(&nd, NDF_ONLY_PNBUF); - type = nd.ni_vp->v_type; - VOP_UNLOCK(nd.ni_vp, 0, td); - vn_close(nd.ni_vp, FREAD, td); - if (type == VREG) - return(result); + type = nd.nl_open_vp->v_type; + if (type == VREG) { + nlookup_done(&nd); + return (result); + } } + nlookup_done(&nd); free(result, M_LINKER); if (*ep == 0) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index ea0a838570..8e5ef2d9ad 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -37,7 +37,7 @@ * * @(#)kern_sig.c 8.7 (Berkeley) 4/18/94 * $FreeBSD: src/sys/kern/kern_sig.c,v 1.72.2.17 2003/05/16 16:34:34 obrien Exp $ - * $DragonFly: src/sys/kern/kern_sig.c,v 1.31 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/kern_sig.c,v 1.32 2004/11/12 00:09:23 dillon Exp $ */ #include "opt_ktrace.h" @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include #include #include @@ -1451,7 +1451,7 @@ coredump(struct proc *p) struct ucred *cred = p->p_ucred; struct thread *td = p->p_thread; struct flock lf; - struct nameidata nd; + struct nlookupdata nd; struct vattr vattr; int error, error1; char *name; /* name of corefile */ @@ -1477,13 +1477,17 @@ coredump(struct proc *p) name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid); if (name == NULL) return (EINVAL); - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, name, td); - error = vn_open(&nd, O_CREAT | FWRITE | O_NOFOLLOW, S_IRUSR | S_IWUSR); + error = nlookup_init(&nd, name, UIO_SYSSPACE, NLC_LOCKVP); + if (error == 0) + error = vn_open(&nd, NULL, O_CREAT | FWRITE | O_NOFOLLOW, S_IRUSR | S_IWUSR); free(name, M_TEMP); - if (error) + if (error) { + nlookup_done(&nd); return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; + } + vp = nd.nl_open_vp; + nd.nl_open_vp = NULL; + nlookup_done(&nd); VOP_UNLOCK(vp, 0, td); lf.l_whence = SEEK_SET; @@ -1510,8 +1514,7 @@ coredump(struct proc *p) VOP_UNLOCK(vp, 0, td); error = p->p_sysent->sv_coredump ? - p->p_sysent->sv_coredump(p, vp, limit) : - ENOSYS; + p->p_sysent->sv_coredump(p, vp, limit) : ENOSYS; out1: lf.l_type = F_UNLCK; diff --git a/sys/kern/link_aout.c b/sys/kern/link_aout.c index af5e8243a2..97d75a87ba 100644 --- a/sys/kern/link_aout.c +++ b/sys/kern/link_aout.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/link_aout.c,v 1.26 1999/12/24 15:33:36 bde Exp $ - * $DragonFly: src/sys/kern/link_aout.c,v 1.12 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/link_aout.c,v 1.13 2004/11/12 00:09:23 dillon Exp $ */ #ifndef __alpha__ @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -196,9 +196,10 @@ link_aout_load_module(const char* filename, linker_file_t* result) static int link_aout_load_file(const char* filename, linker_file_t* result) { - struct nameidata nd; + struct nlookupdata nd; struct thread *td = curthread; struct proc *p = td->td_proc; + struct vnode *vp; int error = 0; int resid; struct exec header; @@ -217,17 +218,22 @@ link_aout_load_file(const char* filename, linker_file_t* result) pathname = linker_search_path(filename); if (pathname == NULL) return ENOENT; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, pathname, td); - error = vn_open(&nd, FREAD, 0); + error = nlookup_init(&nd, pathname, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP); + if (error == 0) + error = vn_open(&nd, NULL, FREAD, 0); free(pathname, M_LINKER); - if (error) + if (error) { + nlookup_done(&nd); return error; - NDFREE(&nd, NDF_ONLY_PNBUF); + } + vp = nd.nl_open_vp; + nd.nl_open_vp = NULL; + nlookup_done(&nd); /* * Read the a.out header from the file. */ - error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &header, sizeof header, 0, + error = vn_rdwr(UIO_READ, vp, (void*) &header, sizeof header, 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td); if (error) goto out; @@ -246,8 +252,8 @@ link_aout_load_file(const char* filename, linker_file_t* result) /* * Read the text and data sections and zero the bss. */ - VOP_LEASE(nd.ni_vp, td, p->p_ucred, LEASE_READ); - error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) af->address, + VOP_LEASE(vp, td, p->p_ucred, LEASE_READ); + error = vn_rdwr(UIO_READ, vp, (void*) af->address, header.a_text + header.a_data, 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td); if (error) @@ -286,8 +292,8 @@ link_aout_load_file(const char* filename, linker_file_t* result) *result = lf; out: - VOP_UNLOCK(nd.ni_vp, 0, td); - vn_close(nd.ni_vp, FREAD, td); + VOP_UNLOCK(vp, 0, td); + vn_close(vp, FREAD, td); return error; } diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index 4169675874..69d9451f7c 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/link_elf.c,v 1.24 1999/12/24 15:33:36 bde Exp $ - * $DragonFly: src/sys/kern/link_elf.c,v 1.14 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/link_elf.c,v 1.15 2004/11/12 00:09:23 dillon Exp $ */ #include @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -394,9 +394,10 @@ link_elf_load_module(const char *filename, linker_file_t *result) static int link_elf_load_file(const char* filename, linker_file_t* result) { - struct nameidata nd; + struct nlookupdata nd; struct thread *td = curthread; /* XXX */ struct proc *p = td->td_proc; + struct vnode *vp; Elf_Ehdr *hdr; caddr_t firstpage; int nbytes, i; @@ -434,12 +435,17 @@ link_elf_load_file(const char* filename, linker_file_t* result) if (pathname == NULL) return ENOENT; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, pathname, td); - error = vn_open(&nd, FREAD, 0); + error = nlookup_init(&nd, pathname, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP); + if (error == 0) + error = vn_open(&nd, NULL, FREAD, 0); free(pathname, M_LINKER); - if (error) + if (error) { + nlookup_done(&nd); return error; - NDFREE(&nd, NDF_ONLY_PNBUF); + } + vp = nd.nl_open_vp; + nd.nl_open_vp = NULL; + nlookup_done(&nd); /* * Read the elf header from the file. @@ -450,7 +456,7 @@ link_elf_load_file(const char* filename, linker_file_t* result) goto out; } hdr = (Elf_Ehdr *)firstpage; - error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0, + error = vn_rdwr(UIO_READ, vp, firstpage, PAGE_SIZE, 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td); nbytes = PAGE_SIZE - resid; if (error) @@ -574,7 +580,7 @@ link_elf_load_file(const char* filename, linker_file_t* result) */ for (i = 0; i < 2; i++) { caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; - error = vn_rdwr(UIO_READ, nd.ni_vp, + error = vn_rdwr(UIO_READ, vp, segbase, segs[i]->p_filesz, segs[i]->p_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td); if (error) { @@ -642,7 +648,7 @@ link_elf_load_file(const char* filename, linker_file_t* result) goto out; } bzero(shdr, nbytes); - error = vn_rdwr(UIO_READ, nd.ni_vp, + error = vn_rdwr(UIO_READ, vp, (caddr_t)shdr, nbytes, hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td); if (error) @@ -667,12 +673,12 @@ link_elf_load_file(const char* filename, linker_file_t* result) error = ENOMEM; goto out; } - error = vn_rdwr(UIO_READ, nd.ni_vp, + error = vn_rdwr(UIO_READ, vp, ef->symbase, symcnt, shdr[symtabindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td); if (error) goto out; - error = vn_rdwr(UIO_READ, nd.ni_vp, + error = vn_rdwr(UIO_READ, vp, ef->strbase, strcnt, shdr[symstrindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td); if (error) @@ -696,8 +702,8 @@ out: free(shdr, M_LINKER); if (firstpage) free(firstpage, M_LINKER); - VOP_UNLOCK(nd.ni_vp, 0, td); - vn_close(nd.ni_vp, FREAD, td); + VOP_UNLOCK(vp, 0, td); + vn_close(vp, FREAD, td); return error; } diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 4aca992696..e5971f86bf 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -17,7 +17,7 @@ * are met. * * $FreeBSD: src/sys/kern/sys_pipe.c,v 1.60.2.13 2002/08/05 15:05:15 des Exp $ - * $DragonFly: src/sys/kern/sys_pipe.c,v 1.24 2004/07/24 20:30:00 dillon Exp $ + * $DragonFly: src/sys/kern/sys_pipe.c,v 1.25 2004/11/12 00:09:24 dillon Exp $ */ /* @@ -251,7 +251,6 @@ pipe(struct pipe_args *uap) pipeclose(wpipe); return (error); } - fhold(rf); uap->sysmsg_fds[0] = fd1; /* @@ -284,6 +283,7 @@ pipe(struct pipe_args *uap) rpipe->pipe_peer = wpipe; wpipe->pipe_peer = rpipe; fdrop(rf, td); + fdrop(wf, td); return (0); } diff --git a/sys/kern/tty_tty.c b/sys/kern/tty_tty.c index 9070030df2..ece68de2ce 100644 --- a/sys/kern/tty_tty.c +++ b/sys/kern/tty_tty.c @@ -32,7 +32,7 @@ * * @(#)tty_tty.c 8.2 (Berkeley) 9/23/93 * $FreeBSD: src/sys/kern/tty_tty.c,v 1.30 1999/09/25 18:24:24 phk Exp $ - * $DragonFly: src/sys/kern/tty_tty.c,v 1.10 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/tty_tty.c,v 1.11 2004/11/12 00:09:24 dillon Exp $ */ /* @@ -94,7 +94,7 @@ cttyopen(dev_t dev, int flag, int mode, struct thread *td) } else { vsetflags(ttyvp, VCTTYISOPEN); vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(ttyvp, flag, NOCRED, td); + error = VOP_OPEN(ttyvp, flag, NOCRED, NULL, td); VOP_UNLOCK(ttyvp, 0, td); } } else { diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index ca31070245..c555b38192 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -35,7 +35,7 @@ * * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 * $FreeBSD: src/sys/kern/uipc_syscalls.c,v 1.65.2.17 2003/04/04 17:11:16 tegge Exp $ - * $DragonFly: src/sys/kern/uipc_syscalls.c,v 1.43 2004/10/22 13:42:14 hsu Exp $ + * $DragonFly: src/sys/kern/uipc_syscalls.c,v 1.44 2004/11/12 00:09:24 dillon Exp $ */ #include "opt_ktrace.h" @@ -109,7 +109,6 @@ kern_socket(int domain, int type, int protocol, int *res) error = falloc(p, &fp, &fd); if (error) return (error); - fhold(fp); error = socreate(domain, &so, type, protocol, td); if (error) { if (fdp->fd_ofiles[fd] == fp) { @@ -271,7 +270,6 @@ kern_accept(int s, struct sockaddr **name, int *namelen, int *res) fdrop(lfp, td); return (error); } - fhold(nfp); *res = fd; head = (struct socket *)lfp->f_data; @@ -355,7 +353,7 @@ done: /* * Release explicitly held references before returning. */ - if (nfp != NULL) + if (nfp) fdrop(nfp, td); fdrop(lfp, td); return (error); @@ -501,13 +499,11 @@ kern_socketpair(int domain, int type, int protocol, int *sv) error = falloc(p, &fp1, &fd); if (error) goto free2; - fhold(fp1); sv[0] = fd; fp1->f_data = (caddr_t)so1; error = falloc(p, &fp2, &fd); if (error) goto free3; - fhold(fp2); fp2->f_data = (caddr_t)so2; sv[1] = fd; error = soconnect2(so1, so2); diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 3d12d11657..21bfbb1105 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -32,7 +32,7 @@ * * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 * $FreeBSD: src/sys/kern/uipc_usrreq.c,v 1.54.2.10 2003/03/04 17:28:09 nectar Exp $ - * $DragonFly: src/sys/kern/uipc_usrreq.c,v 1.16 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/uipc_usrreq.c,v 1.17 2004/11/12 00:09:24 dillon Exp $ */ #include @@ -45,12 +45,13 @@ #include #include #include -#include +#include #include #include #include #include #include +#include #include #include #include @@ -588,46 +589,37 @@ unp_bind(struct unpcb *unp, struct sockaddr *nam, struct thread *td) struct vnode *vp; struct vattr vattr; int error, namelen; - struct nameidata nd; + struct nlookupdata nd; char buf[SOCK_MAXADDRLEN]; if (unp->unp_vnode != NULL) return (EINVAL); namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); if (namelen <= 0) - return EINVAL; + return (EINVAL); strncpy(buf, soun->sun_path, namelen); buf[namelen] = 0; /* null-terminate the string */ - NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_SYSSPACE, buf, td); -/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ - error = namei(&nd); + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_LOCKVP|NLC_CREATE); + if (error == 0) + error = nlookup(&nd); + if (error == 0 && nd.nl_ncp->nc_vp != NULL) + error = EADDRINUSE; if (error) - return (error); - vp = nd.ni_vp; - if (vp != NULL) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - vrele(vp); - return (EADDRINUSE); - } + goto done; + VATTR_NULL(&vattr); vattr.va_type = VSOCK; vattr.va_mode = (ACCESSPERMS & ~p->p_fd->fd_cmask); - VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE); - error = VOP_CREATE(nd.ni_dvp, NCPNULL, &nd.ni_vp, &nd.ni_cnd, &vattr); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - if (error) - return (error); - vp = nd.ni_vp; - vp->v_socket = unp->unp_socket; - unp->unp_vnode = vp; - unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam); - VOP_UNLOCK(vp, 0, td); - return (0); + error = VOP_NCREATE(nd.nl_ncp, &vp, nd.nl_cred, &vattr); + if (error == 0) { + vp->v_socket = unp->unp_socket; + unp->unp_vnode = vp; + unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam); + VOP_UNLOCK(vp, 0, td); + } +done: + nlookup_done(&nd); + return (error); } static int @@ -639,7 +631,7 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) struct socket *so2, *so3; struct unpcb *unp, *unp2, *unp3; int error, len; - struct nameidata nd; + struct nlookupdata nd; char buf[SOCK_MAXADDRLEN]; KKASSERT(p); @@ -650,13 +642,16 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) strncpy(buf, soun->sun_path, len); buf[len] = 0; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, - UIO_SYSSPACE, buf, td); - error = namei(&nd); + vp = NULL; + error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + nlookup_done(&nd); if (error) return (error); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); + if (vp->v_type != VSOCK) { error = ENOTSOCK; goto bad; diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 8e3df922ad..844bdee3d1 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -67,7 +67,7 @@ * * @(#)vfs_cache.c 8.5 (Berkeley) 3/22/95 * $FreeBSD: src/sys/kern/vfs_cache.c,v 1.42.2.6 2001/10/05 20:07:03 dillon Exp $ - * $DragonFly: src/sys/kern/vfs_cache.c,v 1.41 2004/10/28 18:56:52 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_cache.c,v 1.42 2004/11/12 00:09:24 dillon Exp $ */ #include @@ -85,6 +85,7 @@ #include #include #include +#include #include /* @@ -112,6 +113,19 @@ MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries"); static LIST_HEAD(nchashhead, namecache) *nchashtbl; /* Hash Table */ static struct namecache_list ncneglist; /* instead of vnode */ +/* + * ncvp_debug - debug cache_fromvp(). This is used by the NFS server + * to create the namecache infrastructure leading to a dangling vnode. + * + * 0 Only errors are reported + * 1 Successes are reported + * 2 Successes + the whole directory scan is reported + * 3 Force the directory scan code run as if the parent vnode did not + * have a namecache record, even if it does have one. + */ +static int ncvp_debug; +SYSCTL_INT(_debug, OID_AUTO, ncvp_debug, CTLFLAG_RW, &ncvp_debug, 0, ""); + static u_long nchash; /* size of hash table */ SYSCTL_ULONG(_debug, OID_AUTO, nchash, CTLFLAG_RD, &nchash, 0, ""); @@ -262,7 +276,8 @@ cache_unlink_parent(struct namecache *ncp) } /* - * Allocate a new namecache structure. + * Allocate a new namecache structure. Most of the code does not require + * zero-termination of the string but it makes vop_compat_ncreate() easier. */ static struct namecache * cache_alloc(int nlen) @@ -271,7 +286,7 @@ cache_alloc(int nlen) ncp = malloc(sizeof(*ncp), M_VFSCACHE, M_WAITOK|M_ZERO); if (nlen) - ncp->nc_name = malloc(nlen, M_VFSCACHE, M_WAITOK); + ncp->nc_name = malloc(nlen + 1, M_VFSCACHE, M_WAITOK); ncp->nc_nlen = nlen; ncp->nc_flag = NCF_UNRESOLVED; ncp->nc_error = ENOTCONN; /* needs to be resolved */ @@ -375,6 +390,31 @@ cache_lock(struct namecache *ncp) } } +int +cache_lock_nonblock(struct namecache *ncp) +{ + thread_t td; + + KKASSERT(ncp->nc_refs != 0); + td = curthread; + if (ncp->nc_exlocks == 0) { + ncp->nc_exlocks = 1; + ncp->nc_locktd = td; + /* + * The vp associated with a locked ncp must be held + * to prevent it from being recycled (which would + * cause the ncp to become unresolved). + * + * XXX loop on race for later MPSAFE work. + */ + if (ncp->nc_vp) + vhold(ncp->nc_vp); + return(0); + } else { + return(EWOULDBLOCK); + } +} + void cache_unlock(struct namecache *ncp) { @@ -470,6 +510,13 @@ cache_setvp(struct namecache *ncp, struct vnode *vp) ncp->nc_flag &= ~NCF_UNRESOLVED; } +void +cache_settimeout(struct namecache *ncp, int nticks) +{ + if ((ncp->nc_timeout = ticks + nticks) == 0) + ncp->nc_timeout = 1; +} + /* * Disassociate the vnode or negative-cache association and mark a * namecache entry as unresolved again. Note that the ncp is still @@ -492,11 +539,12 @@ cache_setunresolved(struct namecache *ncp) if ((ncp->nc_flag & NCF_UNRESOLVED) == 0) { ncp->nc_flag |= NCF_UNRESOLVED; ncp->nc_flag &= ~(NCF_WHITEOUT|NCF_ISDIR|NCF_ISSYMLINK); + ncp->nc_timeout = 0; ncp->nc_error = ENOTCONN; ++numunres; if ((vp = ncp->nc_vp) != NULL) { --numcache; - ncp->nc_vp = NULL; /* safety */ + ncp->nc_vp = NULL; TAILQ_REMOVE(&vp->v_namecache, ncp, nc_vnode); /* @@ -513,13 +561,6 @@ cache_setunresolved(struct namecache *ncp) TAILQ_REMOVE(&ncneglist, ncp, nc_vnode); --numneg; } - -#if 0 - if (TAILQ_FIRST(&ncp->nc_list)) { - db_print_backtrace(); - printf("[diagnostic] cache_setunresolved() called on directory with children: %p %*.*s\n", ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name); - } -#endif } } @@ -540,23 +581,21 @@ cache_inval(struct namecache *ncp, int flags) if (flags & CINV_SELF) cache_setunresolved(ncp); - if (flags & CINV_PARENT) { - ncp->nc_flag |= NCF_REVALPARENT; + if (flags & CINV_PARENT) cache_unlink_parent(ncp); - } /* - * TEMPORARY XX old-api / rename handling. Any unresolved or - * negative cache-hit children with a ref count of 0 must be - * recursively destroyed or this disconnection from our parent, - * or the childrens disconnection from us, may leave them dangling - * forever. + * Children are invalidated when the parent is destroyed. This + * basically disconnects the children from the parent. Anyone + * CD'd into a child will no longer be able to ".." back up. * - * In the new API it won't be possible to unlink in the middle of - * the topology and we will have a cache_rename() to physically - * move a subtree from one place to another. + * Any unresolved or negative cache-hit children with a ref count + * of 0 must be immediately and recursively destroyed or this + * disconnection may leave them dangling forever. XXX this recursion + * could run the kernel out of stack, the children should be placed + * on a to-destroy list instead. */ - if (flags & (CINV_PARENT|CINV_CHILDREN)) { + if (flags & CINV_CHILDREN) { if ((kid = TAILQ_FIRST(&ncp->nc_list)) != NULL) cache_hold(kid); while (kid) { @@ -568,20 +607,9 @@ cache_inval(struct namecache *ncp, int flags) ) { cache_inval(kid, CINV_PARENT); } - cache_drop(kid); - kid = nextkid; - } - } - - /* - * TEMPORARY XXX old-api / rename handling. - */ - if (flags & CINV_CHILDREN) { - while ((kid = TAILQ_FIRST(&ncp->nc_list)) != NULL) { - kid->nc_flag |= NCF_REVALPARENT; - cache_hold(kid); cache_unlink_parent(kid); cache_drop(kid); + kid = nextkid; } } } @@ -607,6 +635,37 @@ cache_inval_vp(struct vnode *vp, int flags) } } +/* + * The source ncp has been renamed to the target ncp. Both fncp and tncp + * must be locked. Both will be set to unresolved, any children of tncp + * will be disconnected (the prior contents of the target is assumed to be + * destroyed by the rename operation, e.g. renaming over an empty directory), + * and all children of fncp will be moved to tncp. + * + * After we return the caller has the option of calling cache_setvp() if + * the vnode of the new target ncp is known. + * + * Any process CD'd into any of the children will no longer be able to ".." + * back out. An rm -rf can cause this situation to occur. + */ +void +cache_rename(struct namecache *fncp, struct namecache *tncp) +{ + struct namecache *scan; + + cache_setunresolved(fncp); + cache_setunresolved(tncp); + cache_inval(tncp, CINV_CHILDREN); + while ((scan = TAILQ_FIRST(&fncp->nc_list)) != NULL) { + cache_hold(scan); + cache_unlink_parent(scan); + cache_link_parent(scan, tncp); + if (scan->nc_flag & NCF_HASHED) + cache_rehash(scan); + cache_drop(scan); + } +} + /* * vget the vnode associated with the namecache entry. Resolve the namecache * entry if necessary and deal with namecache/vp races. The passed ncp must @@ -686,6 +745,259 @@ again: return(error); } +/* + * Convert a directory vnode to a namecache record without any other + * knowledge of the topology. This ONLY works with directory vnodes and + * is ONLY used by the NFS server. dvp must be refd but unlocked, and the + * returned ncp (if not NULL) will be held and unlocked. + * + * If 'makeit' is 0 and dvp has no existing namecache record, NULL is returned. + * If 'makeit' is 1 we attempt to track-down and create the namecache topology + * for dvp. This will fail only if the directory has been deleted out from + * under the caller. + * + * Callers must always check for a NULL return no matter the value of 'makeit'. + */ + +static int cache_inefficient_scan(struct namecache *ncp, struct ucred *cred, + struct vnode *dvp); + +struct namecache * +cache_fromdvp(struct vnode *dvp, struct ucred *cred, int makeit) +{ + struct namecache *ncp; + struct vnode *pvp; + int error; + + /* + * Temporary debugging code to force the directory scanning code + * to be exercised. + */ + ncp = NULL; + if (ncvp_debug >= 3 && makeit && TAILQ_FIRST(&dvp->v_namecache)) { + ncp = TAILQ_FIRST(&dvp->v_namecache); + printf("cache_fromdvp: forcing %s\n", ncp->nc_name); + goto force; + } + + /* + * Loop until resolution, inside code will break out on error. + */ + while ((ncp = TAILQ_FIRST(&dvp->v_namecache)) == NULL && makeit) { +force: + /* + * If dvp is the root of its filesystem it should already + * have a namecache pointer associated with it as a side + * effect of the mount, but it may have been disassociated. + */ + if (dvp->v_flag & VROOT) { + ncp = cache_get(dvp->v_mount->mnt_ncp); + error = cache_resolve_mp(ncp); + cache_put(ncp); + if (ncvp_debug) { + printf("cache_fromdvp: resolve root of mount %p error %d", + dvp->v_mount, error); + } + if (error) { + if (ncvp_debug) + printf(" failed\n"); + ncp = NULL; + break; + } + if (ncvp_debug) + printf(" succeeded\n"); + continue; + } + + /* + * Get the parent directory and resolve its ncp. + */ + error = vop_nlookupdotdot(dvp->v_ops, dvp, &pvp, cred); + if (error) { + printf("lookupdotdot failed %d %p\n", error, pvp); + break; + } + VOP_UNLOCK(pvp, 0, curthread); + + /* + * XXX this recursion could run the kernel out of stack, + * change to a less efficient algorithm if we get too deep + * (use 'makeit' for a depth counter?) + */ + ncp = cache_fromdvp(pvp, cred, makeit); + vrele(pvp); + if (ncp == NULL) + break; + + /* + * Do an inefficient scan of pvp (embodied by ncp) to look + * for dvp. This will create a namecache record for dvp on + * success. We loop up to recheck on success. + * + * ncp and dvp are both held but not locked. + */ + error = cache_inefficient_scan(ncp, cred, dvp); + cache_drop(ncp); + if (error) { + printf("cache_fromdvp: scan %p (%s) failed on dvp=%p\n", + pvp, ncp->nc_name, dvp); + ncp = NULL; + break; + } + if (ncvp_debug) { + printf("cache_fromdvp: scan %p (%s) succeeded\n", + pvp, ncp->nc_name); + } + } + if (ncp) + cache_hold(ncp); + return (ncp); +} + +/* + * Do an inefficient scan of the directory represented by ncp looking for + * the directory vnode dvp. ncp must be held but not locked on entry and + * will be held on return. dvp must be refd but not locked on entry and + * will remain refd on return. + * + * Why do this at all? Well, due to its stateless nature the NFS server + * converts file handles directly to vnodes without necessarily going through + * the namecache ops that would otherwise create the namecache topology + * leading to the vnode. We could either (1) Change the namecache algorithms + * to allow disconnect namecache records that are re-merged opportunistically, + * or (2) Make the NFS server backtrack and scan to recover a connected + * namecache topology in order to then be able to issue new API lookups. + * + * It turns out that (1) is a huge mess. It takes a nice clean set of + * namecache algorithms and introduces a lot of complication in every subsystem + * that calls into the namecache to deal with the re-merge case, especially + * since we are using the namecache to placehold negative lookups and the + * vnode might not be immediately assigned. (2) is certainly far less + * efficient then (1), but since we are only talking about directories here + * (which are likely to remain cached), the case does not actually run all + * that often and has the supreme advantage of not polluting the namecache + * algorithms. + */ +static int +cache_inefficient_scan(struct namecache *ncp, struct ucred *cred, + struct vnode *dvp) +{ + struct nlcomponent nlc; + struct namecache *rncp; + struct dirent *den; + struct vnode *pvp; + struct vattr vat; + struct iovec iov; + struct uio uio; + u_long *cookies; + off_t baseoff; + int ncookies; + int blksize; + int eofflag; + char *rbuf; + int error; + int xoff; + int i; + + vat.va_blocksize = 0; + if ((error = VOP_GETATTR(dvp, &vat, curthread)) != 0) + return (error); + if ((error = cache_vget(ncp, cred, LK_SHARED, &pvp)) != 0) + return (error); + if (ncvp_debug) + printf("inefficient_scan: directory iosize %ld vattr fileid = %ld\n", vat.va_blocksize, (long)vat.va_fileid); + if ((blksize = vat.va_blocksize) == 0) + blksize = DEV_BSIZE; + rbuf = malloc(blksize, M_TEMP, M_WAITOK); + rncp = NULL; + + eofflag = 0; + uio.uio_offset = 0; + cookies = NULL; +again: + baseoff = uio.uio_offset; + iov.iov_base = rbuf; + iov.iov_len = blksize; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_resid = blksize; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_rw = UIO_READ; + uio.uio_td = curthread; + + if (cookies) { + free(cookies, M_TEMP); + cookies = NULL; + } + if (ncvp_debug >= 2) + printf("cache_inefficient_scan: readdir @ %08x\n", (int)baseoff); + error = VOP_READDIR(pvp, &uio, cred, &eofflag, &ncookies, &cookies); + if (error == 0 && cookies == NULL) + error = EPERM; + if (error == 0) { + for (i = 0; i < ncookies; ++i) { + xoff = (int)(cookies[i] - (u_long)baseoff); + /* + * UFS plays a little trick to skip the first entry + * in a directory ("."), by assigning the cookie to + * dpoff + dp->d_reclen in the loop. This causes + * the last cookie to be assigned to the data-end of + * the directory. XXX + */ + if (xoff == blksize) + break; + KKASSERT(xoff >= 0 && xoff <= blksize); + den = (struct dirent *)(rbuf + xoff); + if (ncvp_debug >= 2) + printf("cache_inefficient_scan: %*.*s\n", + den->d_namlen, den->d_namlen, den->d_name); + if (den->d_type != DT_WHT && + den->d_fileno == vat.va_fileid) { + if (ncvp_debug) + printf("cache_inefficient_scan: MATCHED inode %ld path %s/%*.*s\n", vat.va_fileid, ncp->nc_name, den->d_namlen, den->d_namlen, den->d_name); + nlc.nlc_nameptr = den->d_name; + nlc.nlc_namelen = den->d_namlen; + VOP_UNLOCK(pvp, 0, curthread); + rncp = cache_nlookup(ncp, &nlc); + KKASSERT(rncp != NULL); + break; + } + } + if (rncp == NULL && eofflag == 0 && uio.uio_resid != blksize) + goto again; + } + if (cookies) { + free(cookies, M_TEMP); + cookies = NULL; + } + if (rncp) { + vrele(pvp); + if (rncp->nc_flag & NCF_UNRESOLVED) { + cache_setvp(rncp, dvp); + if (ncvp_debug >= 2) { + printf("cache_inefficient_scan: setvp %s/%s = %p\n", + ncp->nc_name, rncp->nc_name, dvp); + } + } else { + if (ncvp_debug >= 2) { + printf("cache_inefficient_scan: setvp %s/%s already set %p/%p\n", + ncp->nc_name, rncp->nc_name, dvp, + rncp->nc_vp); + } + } + if (rncp->nc_vp == NULL) + error = rncp->nc_error; + cache_put(rncp); + } else { + printf("cache_inefficient_scan: dvp %p NOT FOUND in %s\n", + dvp, ncp->nc_name); + vput(pvp); + error = ENOENT; + } + free(rbuf, M_TEMP); + return (error); +} + /* * Zap a namecache entry. The ncp is unconditionally set to an unresolved * state, which disassociates it from its vnode or ncneglist. @@ -811,7 +1123,7 @@ cache_hysteresis(void) * * Lookup an entry in the cache. A locked, referenced, non-NULL * entry is *always* returned, even if the supplied component is illegal. - * The returned namecache entry should be returned to the system with + * The resulting namecache entry should be returned to the system with * cache_put() or cache_unlock() + cache_drop(). * * namecache locks are recursive but care must be taken to avoid lock order @@ -833,8 +1145,8 @@ cache_hysteresis(void) * * The directory (par) may be unresolved, in which case any returned child * will likely also be marked unresolved. Likely but not guarenteed. Since - * the filesystem VOP_NEWLOOKUP() requires a resolved directory vnode the - * caller is responsible for resolving the namecache chain top-down. This API + * the filesystem lookup requires a resolved directory vnode the caller is + * responsible for resolving the namecache chain top-down. This API * specifically allows whole chains to be created in an unresolved state. */ struct namecache * @@ -904,12 +1216,15 @@ restart: /* * Initialize as a new UNRESOLVED entry, lock (non-blocking), - * and link to the parent. Only special mount points will have - * a namelen of 0. Those will have their nc_mount assigned through - * other means. + * and link to the parent. The mount point is usually inherited + * from the parent unless this is a special case such as a mount + * point where nlc_namelen is 0. The caller is responsible for + * setting nc_mount in that case. If nlc_namelen is 0 nc_name will + * be NULL. */ if (nlc->nlc_namelen) { bcopy(nlc->nlc_nameptr, ncp->nc_name, nlc->nlc_namelen); + ncp->nc_name[nlc->nlc_namelen] = 0; ncp->nc_mount = par->nc_mount; } nchpp = NCHHASH(hash); @@ -917,6 +1232,15 @@ restart: ncp->nc_flag |= NCF_HASHED; cache_link_parent(ncp, par); found: + /* + * stats and namecache size management + */ + if (ncp->nc_flag & NCF_UNRESOLVED) + ++gd->gd_nchstats->ncs_miss; + else if (ncp->nc_vp) + ++gd->gd_nchstats->ncs_goodhits; + else + ++gd->gd_nchstats->ncs_neghits; cache_hysteresis(); return(ncp); } @@ -930,12 +1254,15 @@ found: * direct parent of the cache entry we are trying to resolve should * have a valid vnode. If not then generate an error that we can * determine is related to a resolver bug. + * + * Note that successful resolution does not necessarily return an error + * code of 0. If the ncp resolves to a negative cache hit then ENOENT + * will be returned. */ int cache_resolve(struct namecache *ncp, struct ucred *cred) { struct namecache *par; - struct namecache *scan; int error; restart: @@ -1006,9 +1333,8 @@ restart: printf("[diagnostic] cache_resolve: raced on %*.*s\n", par->nc_nlen, par->nc_nlen, par->nc_name); cache_put(par); continue; - } else { - par->nc_error = - vop_resolve(par->nc_parent->nc_vp->v_ops, par, cred); + } else if (par->nc_flag & NCF_UNRESOLVED) { + par->nc_error = VOP_NRESOLVE(par, cred); } if ((error = par->nc_error) != 0) { if (par->nc_error != EAGAIN) { @@ -1026,33 +1352,21 @@ restart: } /* - * Call vop_resolve() to get the vp, then scan for any disconnected + * Call VOP_NRESOLVE() to get the vp, then scan for any disconnected * ncp's and reattach them. If this occurs the original ncp is marked * EAGAIN to force a relookup. + * + * NOTE: in order to call VOP_NRESOLVE(), the parent of the passed + * ncp must already be resolved. */ KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0); - ncp->nc_error = vop_resolve(ncp->nc_parent->nc_vp->v_ops, ncp, cred); + ncp->nc_error = VOP_NRESOLVE(ncp, cred); + /*vop_nresolve(ncp->nc_parent->nc_vp->v_ops, ncp, cred);*/ if (ncp->nc_error == EAGAIN) { printf("[diagnostic] cache_resolve: EAGAIN ncp %p %*.*s\n", ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name); goto restart; } - if (ncp->nc_error == 0) { - TAILQ_FOREACH(scan, &ncp->nc_vp->v_namecache, nc_vnode) { - if (scan != ncp && (scan->nc_flag & NCF_REVALPARENT)) { - cache_hold(scan); - cache_link_parent(scan, ncp->nc_parent); - cache_unlink_parent(ncp); - scan->nc_flag &= ~NCF_REVALPARENT; - ncp->nc_error = EAGAIN; - if (scan->nc_flag & NCF_HASHED) - cache_rehash(scan); - printf("[diagnostic] cache_resolve: relinked %*.*s\n", scan->nc_nlen, scan->nc_nlen, scan->nc_name); - cache_drop(scan); - break; - } - } - } return(ncp->nc_error); } @@ -1087,346 +1401,6 @@ cache_resolve_mp(struct namecache *ncp) return(ncp->nc_error); } -/* - * Lookup an entry in the cache. - * - * XXX OLD API ROUTINE! WHEN ALL VFSs HAVE BEEN CLEANED UP THIS PROCEDURE - * WILL BE REMOVED. NOTE: even though this is an old api function it had - * to be modified to vref() the returned vnode (whereas in 4.x an unreferenced - * vnode was returned). This is necessary because our namecache structure - * manipulation can cause the vnode to be recycled if it isn't refd. - * - * Lookup is called with dvp pointing to the directory to search, - * cnp pointing to the name of the entry being sought. - * - * If the lookup succeeds, a REFd but unlocked vnode is returned in *vpp, - * and a status of -1 is returned. - * - * If the lookup determines that the name does not exist (negative cacheing), - * a status of ENOENT is returned. - * - * If the lookup fails, a status of zero is returned. - * - * Matching UNRESOLVED entries are resolved. - * - * HACKS: we create dummy nodes for parents - */ -int -cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) -{ - struct namecache *ncp; - struct namecache *par; - struct namecache *bpar; - u_int32_t hash; - globaldata_t gd = mycpu; - - numcalls++; - *vpp = NULL; - - /* - * Obtain the namecache entry associated with dvp. If there is no - * entry then assume a miss. - */ - if ((par = TAILQ_FIRST(&dvp->v_namecache)) == NULL) { - if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) { - nummisszap++; - } else { - nummiss++; - } - gd->gd_nchstats->ncs_miss++; - return (0); - } - - /* - * Deal with "." and "..". Note that if the namecache is disjoint, - * we won't find a vnode for ".." and we return a miss. - */ - if (cnp->cn_nameptr[0] == '.') { - if (cnp->cn_namelen == 1) { - *vpp = dvp; - vref(*vpp); - dothits++; - numposhits++; /* include in total statistics */ - return (-1); - } - if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { - if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) { - dotdothits++; - numposhits++; - return (0); - } - if (par->nc_parent == NULL || - par->nc_parent->nc_vp == NULL) { - nummiss++; - gd->gd_nchstats->ncs_miss++; - return (0); - } - *vpp = par->nc_parent->nc_vp; - vref(*vpp); - dotdothits++; - numposhits++; /* include in total statistics */ - return (-1); - } - } - - /* - * Try to locate an existing entry - */ - cache_hold(par); - hash = fnv_32_buf(cnp->cn_nameptr, cnp->cn_namelen, FNV1_32_INIT); - bpar = par; - hash = fnv_32_buf(&bpar, sizeof(bpar), hash); -restart: - LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { - numchecks++; - - /* - * Zap entries that have timed out. Don't do anything if - * the entry is in an unresolved state or is held locked. - */ - if (ncp->nc_timeout && - (int)(ncp->nc_timeout - ticks) < 0 && - (ncp->nc_flag & NCF_UNRESOLVED) == 0 && - ncp->nc_exlocks == 0 - ) { - cache_zap(cache_get(ncp)); - goto restart; - } - - /* - * Break out if we find a matching entry. - */ - if (ncp->nc_parent == par && - ncp->nc_nlen == cnp->cn_namelen && - bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen) == 0 - ) { - if (cache_get_nonblock(ncp) == 0) - break; - cache_get(ncp); - cache_put(ncp); - goto restart; - } - } - cache_drop(par); - - /* - * We found an entry but it is unresolved, act the same as if we - * failed to locate the entry. cache_enter() will do the right - * thing. - */ - if (ncp && (ncp->nc_flag & NCF_UNRESOLVED)) { - cache_put(ncp); - ncp = NULL; - } - - /* - * If we failed to locate an entry, return 0 (indicates failure). - */ - if (ncp == NULL) { - if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) { - nummisszap++; - } else { - nummiss++; - } - gd->gd_nchstats->ncs_miss++; - return (0); - } - - /* - * If we found an entry, but we don't want to have one, we just - * return. The old API tried to zap the entry in the vfs_lookup() - * phase but this is too early to know whether the operation - * will have succeeded or not. The new API zaps it after the - * operation has succeeded, not here. - * - * At the same time, the old api's rename() function uses the - * old api lookup to clear out any negative cache hit on the - * target name. We still have to do that. - */ - if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) { - if (cnp->cn_nameiop == NAMEI_RENAME && ncp->nc_vp == NULL) - cache_zap(ncp); - else - cache_put(ncp); - return (0); - } - - /* - * If the vnode is not NULL then return the positive match. - */ - if (ncp->nc_vp) { - numposhits++; - gd->gd_nchstats->ncs_goodhits++; - *vpp = ncp->nc_vp; - vref(*vpp); - cache_put(ncp); - return (-1); - } - - /* - * If the vnode is NULL we found a negative match. If we want to - * create it, purge the negative match and return failure (as if - * we hadn't found a match in the first place). - */ - if (cnp->cn_nameiop == NAMEI_CREATE) { - numnegzaps++; - gd->gd_nchstats->ncs_badhits++; - cache_zap(ncp); - return (0); - } - - numneghits++; - - /* - * We found a "negative" match, ENOENT notifies client of this match. - * The nc_flag field records whether this is a whiteout. Since there - * is no vnode we can use the vnode tailq link field with ncneglist. - */ - TAILQ_REMOVE(&ncneglist, ncp, nc_vnode); - TAILQ_INSERT_TAIL(&ncneglist, ncp, nc_vnode); - gd->gd_nchstats->ncs_neghits++; - if (ncp->nc_flag & NCF_WHITEOUT) - cnp->cn_flags |= CNP_ISWHITEOUT; - cache_put(ncp); - return (ENOENT); -} - -/* - * Add an entry to the cache. (OLD API) - * - * XXX OLD API ROUTINE! WHEN ALL VFSs HAVE BEEN CLEANED UP THIS PROCEDURE - * WILL BE REMOVED. - * - * Generally speaking this is 'optional'. It's ok to do nothing at all. - * The only reason I don't just return is to try to set nc_timeout if - * requested. - */ -void -cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) -{ - struct namecache *par; - struct namecache *ncp; - struct namecache *new_ncp; - struct namecache *bpar; - struct nchashhead *nchpp; - u_int32_t hash; - - /* - * If the directory has no namecache entry we bail. This will result - * in a lot of misses but frankly we don't have much of a choice if - * we want to be compatible with the new api's storage scheme. - */ - if ((ncp = TAILQ_FIRST(&dvp->v_namecache)) == NULL) - return; - cache_hold(ncp); - - /* - * This may be a bit confusing. "." and ".." are 'virtual' entries. - * We do not actually create a namecache entry representing either. - * However, the ".." case is used to linkup a potentially disjoint - * directory with its parent, to disconnect a directory from its - * parent, or to change an existing linkage that may no longer be - * correct (as might occur when a subdirectory is renamed). - */ - - if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { - cache_drop(ncp); - return; - } - if (cnp->cn_namelen == 2 && cnp->cn_nameptr[0] == '.' && - cnp->cn_nameptr[1] == '.' - ) { - cache_drop(ncp); - return; - } - - /* - * Ok, no special cases, ncp is actually the parent directory so - * assign it to par. Note that it is held. - */ - par = ncp; - - /* - * Try to find a match in the hash table, allocate a new entry if - * we can't. We have to retry the loop after any potential blocking - * situation. - */ - bpar = par; - hash = fnv_32_buf(cnp->cn_nameptr, cnp->cn_namelen, FNV1_32_INIT); - hash = fnv_32_buf(&bpar, sizeof(bpar), hash); - - new_ncp = NULL; -againagain: - LIST_FOREACH(ncp, (NCHHASH(hash)), nc_hash) { - numchecks++; - - /* - * Break out if we find a matching entry. Because cache_enter - * is called with one or more vnodes potentially locked, we - * cannot block trying to get the ncp lock (or we might - * deadlock). - */ - if (ncp->nc_parent == par && - ncp->nc_nlen == cnp->cn_namelen && - bcmp(ncp->nc_name, cnp->cn_nameptr, ncp->nc_nlen) == 0 - ) { - if (cache_get_nonblock(ncp) != 0) { - printf("[diagnostic] cache_enter: avoided race on %p %*.*s\n", ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name); - cache_drop(par); - return; - } - break; - } - } - if (ncp == NULL) { - if (new_ncp == NULL) { - new_ncp = cache_alloc(cnp->cn_namelen); - goto againagain; - } - ncp = new_ncp; - bcopy(cnp->cn_nameptr, ncp->nc_name, cnp->cn_namelen); - nchpp = NCHHASH(hash); - LIST_INSERT_HEAD(nchpp, ncp, nc_hash); - ncp->nc_flag |= NCF_HASHED; - ncp->nc_mount = dvp->v_mount; - cache_link_parent(ncp, par); - } else if (new_ncp) { - cache_free(new_ncp); - } - cache_drop(par); - - /* - * Avoid side effects if we are simply re-entering the same - * information. - */ - if ((ncp->nc_flag & NCF_UNRESOLVED) == 0 && ncp->nc_vp == vp) { - ncp->nc_error = vp ? 0 : ENOENT; - } else { - cache_setunresolved(ncp); - cache_setvp(ncp, vp); - } - - /* - * Set a timeout - */ - if (cnp->cn_flags & CNP_CACHETIMEOUT) { - if ((ncp->nc_timeout = ticks + cnp->cn_timeout) == 0) - ncp->nc_timeout = 1; - } - - /* - * If the target vnode is NULL if this is to be a negative cache - * entry. - */ - if (vp == NULL) { - ncp->nc_flag &= ~NCF_WHITEOUT; - if (cnp->cn_flags & CNP_ISWHITEOUT) - ncp->nc_flag |= NCF_WHITEOUT; - } - cache_put(ncp); - cache_hysteresis(); -} - void cache_cleanneg(int count) { @@ -1457,6 +1431,11 @@ cache_cleanneg(int count) } } +/* + * Rehash a ncp. Rehashing is typically required if the name changes (should + * not generally occur) or the parent link changes. This function will + * unhash the ncp if the ncp is no longer hashable. + */ static void cache_rehash(struct namecache *ncp) { @@ -1467,14 +1446,16 @@ cache_rehash(struct namecache *ncp) ncp->nc_flag &= ~NCF_HASHED; LIST_REMOVE(ncp, nc_hash); } - hash = fnv_32_buf(ncp->nc_name, ncp->nc_nlen, FNV1_32_INIT); - hash = fnv_32_buf(&ncp->nc_parent, sizeof(ncp->nc_parent), hash); - nchpp = NCHHASH(hash); - LIST_INSERT_HEAD(nchpp, ncp, nc_hash); - ncp->nc_flag |= NCF_HASHED; + if (ncp->nc_nlen && ncp->nc_parent) { + hash = fnv_32_buf(ncp->nc_name, ncp->nc_nlen, FNV1_32_INIT); + hash = fnv_32_buf(&ncp->nc_parent, + sizeof(ncp->nc_parent), hash); + nchpp = NCHHASH(hash); + LIST_INSERT_HEAD(nchpp, ncp, nc_hash); + ncp->nc_flag |= NCF_HASHED; + } } - /* * Name cache initialization, from vfsinit() when we are booting */ @@ -1537,6 +1518,11 @@ vfs_cache_setroot(struct vnode *nvp, struct namecache *ncp) } /* + * XXX OLD API COMPAT FUNCTION. This really messes up the new namecache + * topology and is being removed as quickly as possible. The new VOP_N*() + * API calls are required to make specific adjustments using the supplied + * ncp pointers rather then just bogusly purging random vnodes. + * * Invalidate all namecache entries to a particular vnode as well as * any direct children of that vnode in the namecache. This is a * 'catch all' purge used by filesystems that do not know any better. @@ -1608,102 +1594,6 @@ cache_purgevfs(struct mount *mp) } } -/* - * Perform canonical checks and cache lookup and pass on to filesystem - * through the vop_cachedlookup only if needed. - * - * vop_lookup_args { - * struct vnode a_dvp; - * struct vnode **a_vpp; - * struct componentname *a_cnp; - * } - */ -int -vfs_cache_lookup(struct vop_lookup_args *ap) -{ - struct vnode *dvp, *vp; - int lockparent; - int error; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; - struct ucred *cred = cnp->cn_cred; - int flags = cnp->cn_flags; - struct thread *td = cnp->cn_td; - u_long vpid; /* capability number of vnode */ - - *vpp = NULL; - dvp = ap->a_dvp; - lockparent = flags & CNP_LOCKPARENT; - - if (dvp->v_type != VDIR) - return (ENOTDIR); - - if ((flags & CNP_ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) { - return (EROFS); - } - - error = VOP_ACCESS(dvp, VEXEC, cred, td); - - if (error) - return (error); - - error = cache_lookup(dvp, vpp, cnp); - - /* - * failure if error == 0, do a physical lookup - */ - if (!error) - return (VOP_CACHEDLOOKUP(dvp, vpp, cnp)); - - if (error == ENOENT) - return (error); - - vp = *vpp; - vpid = vp->v_id; - cnp->cn_flags &= ~CNP_PDIRUNLOCK; - if (dvp == vp) { /* lookup on "." */ - /* already ref'd from cache_lookup() */ - error = 0; - } else if (flags & CNP_ISDOTDOT) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= CNP_PDIRUNLOCK; - error = vget(vp, LK_EXCLUSIVE, td); - vrele(vp); - if (!error && lockparent && (flags & CNP_ISLASTCN)) { - if ((error = vn_lock(dvp, LK_EXCLUSIVE, td)) == 0) - cnp->cn_flags &= ~CNP_PDIRUNLOCK; - } - } else { - error = vget(vp, LK_EXCLUSIVE, td); - vrele(vp); - if (!lockparent || error || !(flags & CNP_ISLASTCN)) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= CNP_PDIRUNLOCK; - } - } - /* - * Check that the capability number did not change - * while we were waiting for the lock. - */ - if (!error) { - if (vpid == vp->v_id) - return (0); - vput(vp); - if (lockparent && dvp != vp && (flags & CNP_ISLASTCN)) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= CNP_PDIRUNLOCK; - } - } - if (cnp->cn_flags & CNP_PDIRUNLOCK) { - error = vn_lock(dvp, LK_EXCLUSIVE, td); - if (error) - return (error); - cnp->cn_flags &= ~CNP_PDIRUNLOCK; - } - return (VOP_CACHEDLOOKUP(dvp, vpp, cnp)); -} - static int disablecwd; SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, ""); @@ -1840,7 +1730,10 @@ vn_fullpath(struct proc *p, struct vnode *vn, char **retbuf, char **freebuf) if ((vn = p->p_textvp) == NULL) return (EINVAL); } - ncp = TAILQ_FIRST(&vn->v_namecache); + TAILQ_FOREACH(ncp, &vn->v_namecache, nc_vnode) { + if (ncp->nc_nlen) + break; + } if (ncp == NULL) return (EINVAL); diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 20ac585957..98f677e7eb 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -37,7 +37,7 @@ * * * $FreeBSD: src/sys/kern/vfs_default.c,v 1.28.2.7 2003/01/10 18:23:26 bde Exp $ - * $DragonFly: src/sys/kern/vfs_default.c,v 1.21 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_default.c,v 1.22 2004/11/12 00:09:24 dillon Exp $ */ #include @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -85,7 +86,6 @@ static struct vnodeopv_entry_desc default_vnodeop_entries[] = { { &vop_lease_desc, vop_null }, { &vop_lock_desc, (void *) vop_stdlock }, { &vop_mmap_desc, vop_einval }, - { &vop_resolve_desc, (void *) vop_noresolve }, { &vop_lookup_desc, (void *) vop_nolookup }, { &vop_open_desc, vop_null }, { &vop_pathconf_desc, vop_einval }, @@ -100,6 +100,17 @@ static struct vnodeopv_entry_desc default_vnodeop_entries[] = { { &vop_aclcheck_desc, vop_eopnotsupp }, { &vop_getextattr_desc, vop_eopnotsupp }, { &vop_setextattr_desc, vop_eopnotsupp }, + { &vop_nresolve_desc, (void *) vop_compat_nresolve }, + { &vop_nlookupdotdot_desc, (void *) vop_compat_nlookupdotdot }, + { &vop_ncreate_desc, (void *) vop_compat_ncreate }, + { &vop_nmkdir_desc, (void *) vop_compat_nmkdir }, + { &vop_nmknod_desc, (void *) vop_compat_nmknod }, + { &vop_nlink_desc, (void *) vop_compat_nlink }, + { &vop_nsymlink_desc, (void *) vop_compat_nsymlink }, + { &vop_nwhiteout_desc, (void *) vop_compat_nwhiteout }, + { &vop_nremove_desc, (void *) vop_compat_nremove }, + { &vop_nrmdir_desc, (void *) vop_compat_nrmdir }, + { &vop_nrename_desc, (void *) vop_compat_nrename }, { NULL, NULL } }; @@ -152,16 +163,16 @@ vop_panic(struct vop_generic_args *ap) } /* - * vop_noresolve { struct namecache *a_ncp } XXX STOPGAP FUNCTION + * vop_compat_resolve { struct namecache *a_ncp } XXX STOPGAP FUNCTION * * XXX OLD API ROUTINE! WHEN ALL VFSs HAVE BEEN CLEANED UP THIS PROCEDURE * WILL BE REMOVED. This procedure exists for all VFSs which have not - * yet implemented vop_resolve(). It converts vop_resolve() into a + * yet implemented VOP_NRESOLVE(). It converts VOP_NRESOLVE() into a * vop_lookup() and does appropriate translations. * * Resolve a ncp for VFSs which do not support the VOP. Eventually all * VFSs will support this VOP and this routine can be removed, since - * vop_resolve() is far less complex then the older LOOKUP/CACHEDLOOKUP + * VOP_NRESOLVE() is far less complex then the older LOOKUP/CACHEDLOOKUP * API. * * A locked ncp is passed in to be resolved. The NCP is resolved by @@ -171,11 +182,13 @@ vop_panic(struct vop_generic_args *ap) * negative cache entry. No vnode locks are retained and the * ncp is left locked on return. * + * The ncp will NEVER represent "", "." or "..", or contain any slashes. + * * There is a potential directory and vnode interlock. The lock order * requirement is: namecache, governing directory, resolved vnode. */ int -vop_noresolve(struct vop_resolve_args *ap) +vop_compat_nresolve(struct vop_nresolve_args *ap) { int error; struct vnode *dvp; @@ -191,15 +204,20 @@ vop_noresolve(struct vop_resolve_args *ap) if ((dvp = ncp->nc_parent->nc_vp) == NULL) return(EPERM); + /* + * UFS currently stores all sorts of side effects, including a loop + * variable, in the directory inode. That needs to be fixed and the + * other VFS's audited before we can switch to LK_SHARED. + */ if ((error = vget(dvp, LK_EXCLUSIVE, curthread)) != 0) { - printf("[diagnostic] vop_noresolve: EAGAIN on ncp %p %*.*s\n", - ncp, ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name); + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); return(EAGAIN); } bzero(&cnp, sizeof(cnp)); cnp.cn_nameiop = NAMEI_LOOKUP; - cnp.cn_flags = CNP_ISLASTCN; + cnp.cn_flags = 0; cnp.cn_nameptr = ncp->nc_name; cnp.cn_namelen = ncp->nc_nlen; cnp.cn_cred = ap->a_cred; @@ -232,67 +250,881 @@ vop_noresolve(struct vop_resolve_args *ap) return (error); } -#if 0 +/* + * vop_compat_nlookupdotdot { struct vnode *a_dvp, + * struct vnode **a_vpp, + * struct ucred *a_cred } + * + * Lookup the vnode representing the parent directory of the specified + * directory vnode. a_dvp should not be locked. If no error occurs *a_vpp + * will contained the parent vnode, locked and refd, else *a_vpp will be NULL. + * + * This function is designed to aid NFS server-side operations and is + * used by cache_fromdvp() to create a consistent, connected namecache + * topology. + * + * As part of the NEW API work, VFSs will first split their CNP_ISDOTDOT + * code out from their *_lookup() and create *_nlookupdotdot(). Then as time + * permits VFSs will implement the remaining *_n*() calls and finally get + * rid of their *_lookup() call. + */ +int +vop_compat_nlookupdotdot(struct vop_nlookupdotdot_args *ap) +{ + struct componentname cnp; + int error; + + /* + * UFS currently stores all sorts of side effects, including a loop + * variable, in the directory inode. That needs to be fixed and the + * other VFS's audited before we can switch to LK_SHARED. + */ + *ap->a_vpp = NULL; + if ((error = vget(ap->a_dvp, LK_EXCLUSIVE, curthread)) != 0) + return (error); + if (ap->a_dvp->v_type != VDIR) { + vput(ap->a_dvp); + return (ENOTDIR); + } + + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = NAMEI_LOOKUP; + cnp.cn_flags = CNP_ISDOTDOT; + cnp.cn_nameptr = ".."; + cnp.cn_namelen = 2; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = curthread; /* XXX */ + + /* + * vop_lookup() always returns vp locked. dvp may or may not be + * left locked depending on CNP_PDIRUNLOCK. + */ + error = vop_lookup(ap->a_head.a_ops, ap->a_dvp, ap->a_vpp, &cnp); + if (error == 0) + VOP_UNLOCK(*ap->a_vpp, 0, curthread); + if (cnp.cn_flags & CNP_PDIRUNLOCK) + vrele(ap->a_dvp); + else + vput(ap->a_dvp); + return (error); +} /* - * vop_noremove { struct namecache *a_ncp } XXX STOPGAP FUNCTION + * vop_compat_ncreate { struct namecache *a_ncp, XXX STOPGAP FUNCTION + * struct vnode *a_vpp, + * struct ucred *a_cred, + * struct vattr *a_vap } * - * Remove the file/dir represented by a_ncp. + * Create a file as specified by a_vap. Compatibility requires us to issue + * the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_CREATE in order + * to setup the directory inode's i_offset and i_count (e.g. in UFS). + */ +int +vop_compat_ncreate(struct vop_ncreate_args *ap) +{ + struct thread *td = curthread; + struct componentname cnp; + struct namecache *ncp; + struct vnode *dvp; + int error; + + /* + * Sanity checks, get a locked directory vnode. + */ + ncp = ap->a_ncp; /* locked namecache node */ + if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (ncp->nc_parent == NULL) + return(EPERM); + if ((dvp = ncp->nc_parent->nc_vp) == NULL) + return(EPERM); + + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); + return(EAGAIN); + } + + /* + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to create the entry in the + * directory inode. We expect a return code of EJUSTRETURN for + * the CREATE case. The cnp must simulated a saved-name situation. + */ + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = NAMEI_CREATE; + cnp.cn_flags = CNP_LOCKPARENT; + cnp.cn_nameptr = ncp->nc_name; + cnp.cn_namelen = ncp->nc_nlen; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = td; + *ap->a_vpp = NULL; + + error = vop_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp); + + /* + * EJUSTRETURN should be returned for this case, which means that + * the VFS has setup the directory inode for the create. The dvp we + * passed in is expected to remain in a locked state. + * + * If the VOP_OLD_CREATE is successful we are responsible for updating + * the cache state of the locked ncp that was passed to us. + */ + if (error == EJUSTRETURN) { + KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0); + VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE); + error = VOP_OLD_CREATE(dvp, ap->a_vpp, &cnp, ap->a_vap); + if (error == 0) { + cache_setunresolved(ncp); + cache_setvp(ncp, *ap->a_vpp); + } + } else { + if (error == 0) { + vput(*ap->a_vpp); + *ap->a_vpp = NULL; + error = EEXIST; + } + KKASSERT(*ap->a_vpp == NULL); + } + if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0) + VOP_UNLOCK(dvp, 0, td); + vrele(dvp); + return (error); +} + +/* + * vop_compat_nmkdir { struct namecache *a_ncp, XXX STOPGAP FUNCTION + * struct vnode *a_vpp, + * struct ucred *a_cred, + * struct vattr *a_vap } * - * XXX ultra difficult. A number of existing filesystems, including UFS, - * assume that the directory will remain locked and the lookup will - * store the directory offset and other things in the directory inode - * for the later VOP_REMOVE to use. We have to move all that - * functionality into e.g. UFS's VOP_REMOVE itself. + * Create a directory as specified by a_vap. Compatibility requires us to + * issue the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_MKDIR in + * order to setup the directory inode's i_offset and i_count (e.g. in UFS). */ -static int -vop_nonremove(struct vop_nremove_args *ap) +int +vop_compat_nmkdir(struct vop_nmkdir_args *ap) +{ + struct thread *td = curthread; + struct componentname cnp; + struct namecache *ncp; + struct vnode *dvp; + int error; + + /* + * Sanity checks, get a locked directory vnode. + */ + ncp = ap->a_ncp; /* locked namecache node */ + if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (ncp->nc_parent == NULL) + return(EPERM); + if ((dvp = ncp->nc_parent->nc_vp) == NULL) + return(EPERM); + + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); + return(EAGAIN); + } + + /* + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to create the entry in the + * directory inode. We expect a return code of EJUSTRETURN for + * the CREATE case. The cnp must simulated a saved-name situation. + */ + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = NAMEI_CREATE; + cnp.cn_flags = CNP_LOCKPARENT; + cnp.cn_nameptr = ncp->nc_name; + cnp.cn_namelen = ncp->nc_nlen; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = td; + *ap->a_vpp = NULL; + + error = vop_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp); + + /* + * EJUSTRETURN should be returned for this case, which means that + * the VFS has setup the directory inode for the create. The dvp we + * passed in is expected to remain in a locked state. + * + * If the VOP_OLD_MKDIR is successful we are responsible for updating + * the cache state of the locked ncp that was passed to us. + */ + if (error == EJUSTRETURN) { + KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0); + VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE); + error = VOP_OLD_MKDIR(dvp, ap->a_vpp, &cnp, ap->a_vap); + if (error == 0) { + cache_setunresolved(ncp); + cache_setvp(ncp, *ap->a_vpp); + } + } else { + if (error == 0) { + vput(*ap->a_vpp); + *ap->a_vpp = NULL; + error = EEXIST; + } + KKASSERT(*ap->a_vpp == NULL); + } + if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0) + VOP_UNLOCK(dvp, 0, td); + vrele(dvp); + return (error); +} + +/* + * vop_compat_nmknod { struct namecache *a_ncp, XXX STOPGAP FUNCTION + * struct vnode *a_vpp, + * struct ucred *a_cred, + * struct vattr *a_vap } + * + * Create a device or fifo node as specified by a_vap. Compatibility requires + * us to issue the appropriate VOP_OLD_LOOKUP before we issue VOP_OLD_MKNOD + * in order to setup the directory inode's i_offset and i_count (e.g. in UFS). + */ +int +vop_compat_nmknod(struct vop_nmknod_args *ap) +{ + struct thread *td = curthread; + struct componentname cnp; + struct namecache *ncp; + struct vnode *dvp; + int error; + + /* + * Sanity checks, get a locked directory vnode. + */ + ncp = ap->a_ncp; /* locked namecache node */ + if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (ncp->nc_parent == NULL) + return(EPERM); + if ((dvp = ncp->nc_parent->nc_vp) == NULL) + return(EPERM); + + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); + return(EAGAIN); + } + + /* + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to create the entry in the + * directory inode. We expect a return code of EJUSTRETURN for + * the CREATE case. The cnp must simulated a saved-name situation. + */ + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = NAMEI_CREATE; + cnp.cn_flags = CNP_LOCKPARENT; + cnp.cn_nameptr = ncp->nc_name; + cnp.cn_namelen = ncp->nc_nlen; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = td; + *ap->a_vpp = NULL; + + error = vop_lookup(ap->a_head.a_ops, dvp, ap->a_vpp, &cnp); + + /* + * EJUSTRETURN should be returned for this case, which means that + * the VFS has setup the directory inode for the create. The dvp we + * passed in is expected to remain in a locked state. + * + * If the VOP_OLD_MKNOD is successful we are responsible for updating + * the cache state of the locked ncp that was passed to us. + */ + if (error == EJUSTRETURN) { + KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0); + VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE); + error = VOP_OLD_MKNOD(dvp, ap->a_vpp, &cnp, ap->a_vap); + if (error == 0) { + cache_setunresolved(ncp); + cache_setvp(ncp, *ap->a_vpp); + } + } else { + if (error == 0) { + vput(*ap->a_vpp); + *ap->a_vpp = NULL; + error = EEXIST; + } + KKASSERT(*ap->a_vpp == NULL); + } + if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0) + VOP_UNLOCK(dvp, 0, td); + vrele(dvp); + return (error); +} + +/* + * vop_compat_nlink { struct namecache *a_ncp, XXX STOPGAP FUNCTION + * struct vnode *a_vp, + * struct ucred *a_cred } + * + * The passed vp is locked and represents the source. The passed ncp is + * locked and represents the target to create. + */ +int +vop_compat_nlink(struct vop_nlink_args *ap) +{ + struct thread *td = curthread; + struct componentname cnp; + struct namecache *ncp; + struct vnode *dvp; + struct vnode *tvp; + int error; + + /* + * Sanity checks, get a locked directory vnode. + */ + ncp = ap->a_ncp; /* locked namecache node */ + if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (ncp->nc_parent == NULL) + return(EPERM); + if ((dvp = ncp->nc_parent->nc_vp) == NULL) + return(EPERM); + + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); + return(EAGAIN); + } + + /* + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to create the entry in the + * directory inode. We expect a return code of EJUSTRETURN for + * the CREATE case. The cnp must simulated a saved-name situation. + */ + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = NAMEI_CREATE; + cnp.cn_flags = CNP_LOCKPARENT; + cnp.cn_nameptr = ncp->nc_name; + cnp.cn_namelen = ncp->nc_nlen; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = td; + + tvp = NULL; + error = vop_lookup(ap->a_head.a_ops, dvp, &tvp, &cnp); + + /* + * EJUSTRETURN should be returned for this case, which means that + * the VFS has setup the directory inode for the create. The dvp we + * passed in is expected to remain in a locked state. + * + * If the VOP_OLD_LINK is successful we are responsible for updating + * the cache state of the locked ncp that was passed to us. + */ + if (error == EJUSTRETURN) { + KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0); + VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE); + VOP_LEASE(ap->a_vp, td, ap->a_cred, LEASE_WRITE); + error = VOP_OLD_LINK(dvp, ap->a_vp, &cnp); + if (error == 0) { + cache_setunresolved(ncp); + cache_setvp(ncp, ap->a_vp); + } + } else { + if (error == 0) { + vput(tvp); + error = EEXIST; + } + } + if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0) + VOP_UNLOCK(dvp, 0, td); + vrele(dvp); + return (error); +} + +int +vop_compat_nsymlink(struct vop_nsymlink_args *ap) +{ + struct thread *td = curthread; + struct componentname cnp; + struct namecache *ncp; + struct vnode *dvp; + struct vnode *vp; + int error; + + /* + * Sanity checks, get a locked directory vnode. + */ + *ap->a_vpp = NULL; + ncp = ap->a_ncp; /* locked namecache node */ + if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (ncp->nc_parent == NULL) + return(EPERM); + if ((dvp = ncp->nc_parent->nc_vp) == NULL) + return(EPERM); + + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); + return(EAGAIN); + } + + /* + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to create the entry in the + * directory inode. We expect a return code of EJUSTRETURN for + * the CREATE case. The cnp must simulated a saved-name situation. + */ + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = NAMEI_CREATE; + cnp.cn_flags = CNP_LOCKPARENT; + cnp.cn_nameptr = ncp->nc_name; + cnp.cn_namelen = ncp->nc_nlen; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = td; + + vp = NULL; + error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp); + + /* + * EJUSTRETURN should be returned for this case, which means that + * the VFS has setup the directory inode for the create. The dvp we + * passed in is expected to remain in a locked state. + * + * If the VOP_OLD_SYMLINK is successful we are responsible for updating + * the cache state of the locked ncp that was passed to us. + */ + if (error == EJUSTRETURN) { + KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0); + VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE); + error = VOP_OLD_SYMLINK(dvp, &vp, &cnp, ap->a_vap, ap->a_target); + if (error == 0) { + cache_setunresolved(ncp); + cache_setvp(ncp, vp); + *ap->a_vpp = vp; + } + } else { + if (error == 0) { + vput(vp); + vp = NULL; + error = EEXIST; + } + KKASSERT(vp == NULL); + } + if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0) + VOP_UNLOCK(dvp, 0, td); + vrele(dvp); + return (error); +} + +/* + * vop_compat_nwhiteout { struct namecache *a_ncp, XXX STOPGAP FUNCTION + * struct ucred *a_cred, + * int a_flags } + * + * Issie a whiteout operation (create, lookup, or delete). Compatibility + * requires us to issue the appropriate VOP_OLD_LOOKUP before we issue + * VOP_OLD_WHITEOUT in order to setup the directory inode's i_offset and i_count + * (e.g. in UFS) for the NAMEI_CREATE and NAMEI_DELETE ops. For NAMEI_LOOKUP + * no lookup is necessary. + */ +int +vop_compat_nwhiteout(struct vop_nwhiteout_args *ap) { - struct namecache *ncfile; - struct namecache *ncdir; - struct componentname cnd; + struct thread *td = curthread; + struct componentname cnp; + struct namecache *ncp; + struct vnode *dvp; struct vnode *vp; - struct vnode *vpd; - thread_t td; int error; - td = curthread; - ncfile = ap->a_ncp; - ncdir = ncfile->nc_parent; + /* + * Sanity checks, get a locked directory vnode. + */ + ncp = ap->a_ncp; /* locked namecache node */ + if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (ncp->nc_parent == NULL) + return(EPERM); + if ((dvp = ncp->nc_parent->nc_vp) == NULL) + return(EPERM); - if ((error = cache_vget(ncdir, ap->a_cred, LK_EXCLUSIVE, &vpd)) != 0) - return (error); - if ((error = cache_vget(ncfile, ap->a_cred, LK_EXCLUSIVE, &vp)) != 0) { - vput(vpd); - return (error); + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); + return(EAGAIN); } - bzero(&cnd, sizeof(cnd)); - cnd.cn_nameiop = NAMEI_DELETE; - cnd.cn_td = td; - cnd.cn_cred = ap->a_cred; - cnd.cn_nameptr = ncfile->nc_name; - cnd.cn_namelen = ncfile->nc_nlen; - error = VOP_REMOVE(vpd, NCPNULL, vp, &cnd); - if (error == 0) - cache_purge(vp); - vput(vp); - vput(vpd); /* - * Re-resolve the ncp to match the fact that the file has been - * deleted from the namespace. If an error occured leave the ncp - * unresolved (meaning that we have no idea what the correct state - * is). + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to create the entry in the + * directory inode. We expect a return code of EJUSTRETURN for + * the CREATE case. The cnp must simulated a saved-name situation. + */ + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = ap->a_flags; + cnp.cn_flags = CNP_LOCKPARENT; + cnp.cn_nameptr = ncp->nc_name; + cnp.cn_namelen = ncp->nc_nlen; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = td; + + vp = NULL; + + /* + * EJUSTRETURN should be returned for the CREATE or DELETE cases. + * The VFS has setup the directory inode for the create. The dvp we + * passed in is expected to remain in a locked state. + * + * If the VOP_OLD_WHITEOUT is successful we are responsible for updating + * the cache state of the locked ncp that was passed to us. + */ + switch(ap->a_flags) { + case NAMEI_DELETE: + cnp.cn_flags |= CNP_DOWHITEOUT; + /* fall through */ + case NAMEI_CREATE: + error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp); + if (error == EJUSTRETURN) { + KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0); + VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE); + error = VOP_OLD_WHITEOUT(dvp, &cnp, ap->a_flags); + if (error == 0) + cache_setunresolved(ncp); + } else { + if (error == 0) { + vput(vp); + vp = NULL; + error = EEXIST; + } + KKASSERT(vp == NULL); + } + break; + case NAMEI_LOOKUP: + error = VOP_OLD_WHITEOUT(dvp, NULL, ap->a_flags); + break; + default: + error = EINVAL; + break; + } + if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0) + VOP_UNLOCK(dvp, 0, td); + vrele(dvp); + return (error); +} + + +/* + * vop_compat_nremove { struct namecache *a_ncp, XXX STOPGAP FUNCTION + * struct ucred *a_cred } + */ +int +vop_compat_nremove(struct vop_nremove_args *ap) +{ + struct thread *td = curthread; + struct componentname cnp; + struct namecache *ncp; + struct vnode *dvp; + struct vnode *vp; + int error; + + /* + * Sanity checks, get a locked directory vnode. */ + ncp = ap->a_ncp; /* locked namecache node */ + if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (ncp->nc_parent == NULL) + return(EPERM); + if ((dvp = ncp->nc_parent->nc_vp) == NULL) + return(EPERM); + + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); + return(EAGAIN); + } + + /* + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to delete the entry in the + * directory inode. We expect a return code of 0 for the DELETE + * case (meaning that a vp has been found). The cnp must simulated + * a saved-name situation. + */ + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = NAMEI_DELETE; + cnp.cn_flags = CNP_LOCKPARENT; + cnp.cn_nameptr = ncp->nc_name; + cnp.cn_namelen = ncp->nc_nlen; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = td; + + /* + * The vnode must be a directory and must not represent the + * current directory. + */ + vp = NULL; + error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp); + if (error == 0 && vp->v_type == VDIR) + error = EPERM; if (error == 0) { - cache_setunresolved(ncfile); - cache_setvp(ncfile, NULL); + KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0); + VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE); + VOP_LEASE(vp, td, ap->a_cred, LEASE_WRITE); + error = VOP_OLD_REMOVE(dvp, vp, &cnp); + if (error == 0) { + cache_setunresolved(ncp); + cache_setvp(ncp, NULL); + } } - return (error); + if (vp) { + if (dvp == vp) + vrele(vp); + else + vput(vp); + } + if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0) + VOP_UNLOCK(dvp, 0, td); + vrele(dvp); + return (error); } -#endif +/* + * vop_compat_nrmdir { struct namecache *a_ncp, XXX STOPGAP FUNCTION + * struct ucred *a_cred } + */ +int +vop_compat_nrmdir(struct vop_nrmdir_args *ap) +{ + struct thread *td = curthread; + struct componentname cnp; + struct namecache *ncp; + struct vnode *dvp; + struct vnode *vp; + int error; + + /* + * Sanity checks, get a locked directory vnode. + */ + ncp = ap->a_ncp; /* locked namecache node */ + if (ncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (ncp->nc_parent == NULL) + return(EPERM); + if ((dvp = ncp->nc_parent->nc_vp) == NULL) + return(EPERM); + + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + ncp, ncp->nc_name); + return(EAGAIN); + } + + /* + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to delete the entry in the + * directory inode. We expect a return code of 0 for the DELETE + * case (meaning that a vp has been found). The cnp must simulated + * a saved-name situation. + */ + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = NAMEI_DELETE; + cnp.cn_flags = CNP_LOCKPARENT; + cnp.cn_nameptr = ncp->nc_name; + cnp.cn_namelen = ncp->nc_nlen; + cnp.cn_cred = ap->a_cred; + cnp.cn_td = td; + + /* + * The vnode must be a directory and must not represent the + * current directory. + */ + vp = NULL; + error = vop_lookup(ap->a_head.a_ops, dvp, &vp, &cnp); + if (error == 0 && vp->v_type != VDIR) + error = ENOTDIR; + if (error == 0 && vp == dvp) + error = EINVAL; + if (error == 0 && (vp->v_flag & VROOT)) + error = EBUSY; + if (error == 0) { + KKASSERT((cnp.cn_flags & CNP_PDIRUNLOCK) == 0); + VOP_LEASE(dvp, td, ap->a_cred, LEASE_WRITE); + VOP_LEASE(vp, td, ap->a_cred, LEASE_WRITE); + error = VOP_OLD_RMDIR(dvp, vp, &cnp); + + /* + * Note that this invalidation will cause any process + * currently CD'd into the directory being removed to be + * disconnected from the topology and not be able to ".." + * back out. + */ + if (error == 0) + cache_inval(ncp, CINV_SELF|CINV_PARENT); + } + if (vp) { + if (dvp == vp) + vrele(vp); + else + vput(vp); + } + if ((cnp.cn_flags & CNP_PDIRUNLOCK) == 0) + VOP_UNLOCK(dvp, 0, td); + vrele(dvp); + return (error); +} + +/* + * vop_compat_nrename { struct namecache *a_fncp, XXX STOPGAP FUNCTION + * struct namecache *a_tncp, + * struct ucred *a_cred } + * + * This is a fairly difficult procedure. The old VOP_OLD_RENAME requires that + * the source directory and vnode be unlocked and the target directory and + * vnode (if it exists) be locked. All arguments will be vrele'd and + * the targets will also be unlocked regardless of the return code. + */ +int +vop_compat_nrename(struct vop_nrename_args *ap) +{ + struct thread *td = curthread; + struct componentname fcnp; + struct componentname tcnp; + struct namecache *fncp; + struct namecache *tncp; + struct vnode *fdvp, *fvp; + struct vnode *tdvp, *tvp; + int error; + + /* + * Sanity checks, get referenced vnodes representing the source. + */ + fncp = ap->a_fncp; /* locked namecache node */ + if (fncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + return(EPERM); + if (fncp->nc_parent == NULL) + return(EPERM); + if ((fdvp = fncp->nc_parent->nc_vp) == NULL) + return(EPERM); + + /* + * Temporarily lock the source directory and lookup in DELETE mode to + * check permissions. XXX delete permissions should have been + * checked by nlookup(), we need to add NLC_DELETE for delete + * checking. It is unclear whether VFS's require the directory setup + * info NAMEI_DELETE causes to be stored in the fdvp's inode, but + * since it isn't locked and since UFS always does a relookup of + * the source, it is believed that the only side effect that matters + * is the permissions check. + */ + if ((error = vget(fdvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + fncp, fncp->nc_name); + return(EAGAIN); + } + + bzero(&fcnp, sizeof(fcnp)); + fcnp.cn_nameiop = NAMEI_DELETE; + fcnp.cn_flags = CNP_LOCKPARENT; + fcnp.cn_nameptr = fncp->nc_name; + fcnp.cn_namelen = fncp->nc_nlen; + fcnp.cn_cred = ap->a_cred; + fcnp.cn_td = td; + + /* + * note: vop_lookup (i.e. VOP_OLD_LOOKUP) always returns a locked + * fvp. + */ + fvp = NULL; + error = vop_lookup(ap->a_head.a_ops, fdvp, &fvp, &fcnp); + if (error == 0 && (fvp->v_flag & VROOT)) { + vput(fvp); /* as if vop_lookup had failed */ + error = EBUSY; + } + if ((fcnp.cn_flags & CNP_PDIRUNLOCK) == 0) { + fcnp.cn_flags |= CNP_PDIRUNLOCK; + VOP_UNLOCK(fdvp, 0, td); + } + if (error) { + vrele(fdvp); + return (error); + } + VOP_UNLOCK(fvp, 0, td); + /* + * fdvp and fvp are now referenced and unlocked. + * + * Get a locked directory vnode for the target and lookup the target + * in CREATE mode so it places the required information in the + * directory inode. + */ + tncp = ap->a_tncp; /* locked namecache node */ + if (tncp->nc_flag & NCF_MOUNTPT) /* can't cross a mount point! */ + error = EPERM; + if (tncp->nc_parent == NULL) + error = EPERM; + if ((tdvp = tncp->nc_parent->nc_vp) == NULL) + error = EPERM; + if (error) { + vrele(fdvp); + vrele(fvp); + return (error); + } + if ((error = vget(tdvp, LK_EXCLUSIVE, td)) != 0) { + printf("[diagnostic] vop_compat_resolve: EAGAIN on ncp %p %s\n", + tncp, tncp->nc_name); + vrele(fdvp); + vrele(fvp); + return(EAGAIN); + } + + /* + * Setup the cnp for a traditional vop_lookup() call. The lookup + * caches all information required to create the entry in the + * target directory inode. + */ + bzero(&tcnp, sizeof(tcnp)); + tcnp.cn_nameiop = NAMEI_RENAME; + tcnp.cn_flags = CNP_LOCKPARENT; + tcnp.cn_nameptr = tncp->nc_name; + tcnp.cn_namelen = tncp->nc_nlen; + tcnp.cn_cred = ap->a_cred; + tcnp.cn_td = td; + + tvp = NULL; + error = vop_lookup(ap->a_head.a_ops, tdvp, &tvp, &tcnp); + + if (error == EJUSTRETURN) { + /* + * Target does not exist. tvp should be NULL. + */ + KKASSERT(tvp == NULL); + KKASSERT((tcnp.cn_flags & CNP_PDIRUNLOCK) == 0); + error = VOP_OLD_RENAME(fdvp, fvp, &fcnp, tdvp, tvp, &tcnp); + if (error == 0) { + cache_rename(fncp, tncp); + cache_setvp(tncp, fvp); + } + } else if (error == 0) { + /* + * Target exists. VOP_OLD_RENAME should correctly delete the + * target. + */ + KKASSERT((tcnp.cn_flags & CNP_PDIRUNLOCK) == 0); + error = VOP_OLD_RENAME(fdvp, fvp, &fcnp, tdvp, tvp, &tcnp); + if (error == 0) { + cache_rename(fncp, tncp); + cache_setvp(tncp, fvp); + } + } else { + vrele(fdvp); + vrele(fvp); + if (tcnp.cn_flags & CNP_PDIRUNLOCK) + vrele(tdvp); + else + vput(tdvp); + } + return (error); +} static int vop_nolookup(ap) @@ -580,7 +1412,7 @@ vop_stdgetvobject(ap) */ int vfs_stdmount(struct mount *mp, char *path, caddr_t data, - struct nameidata *ndp, struct thread *td) + struct nlookupdata *nd, struct thread *td) { return (0); } diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 2933160b4d..9980dbf478 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -37,7 +37,7 @@ * * @(#)vfs_lookup.c 8.4 (Berkeley) 2/16/94 * $FreeBSD: src/sys/kern/vfs_lookup.c,v 1.38.2.3 2001/08/31 19:36:49 dillon Exp $ - * $DragonFly: src/sys/kern/vfs_lookup.c,v 1.20 2004/10/22 18:03:50 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_lookup.c,v 1.21 2004/11/12 00:09:24 dillon Exp $ */ #include "opt_ktrace.h" @@ -63,639 +63,56 @@ SYSCTL_INT(_vfs, OID_AUTO, varsym_enable, CTLFLAG_RW, &varsym_enable, 0, "Enable Variant Symlinks"); /* - * Convert a pathname into a pointer to a locked inode. + * OLD API FUNCTION * - * The CNP_FOLLOW flag is set when symbolic links are to be followed - * when they occur at the end of the name translation process. - * Symbolic links are always followed for all other pathname - * components other than the last. + * Relookup a path name component. This function is only used by the + * old API *_rename() code under very specific conditions. CNP_LOCKPARENT + * must be set in the cnp. dvp must be unlocked on entry and will be left + * unlocked if an error occurs. * - * The segflg defines whether the name is to be copied from user - * space or kernel space. - * - * Overall outline of namei: - * - * copy in name - * get starting directory - * while (!done && !error) { - * call lookup to search path. - * if symbolic link, massage name in buffer and continue - * } - * - * NOTE: when namei() is called from a pure thread the system rootvnode - * will be used as a basis for the search. + * The returned *vpp will be NULL if an error occurs. Note that no error + * will occur (error == 0) for CREATE requests on a non-existant target, but + * *vpp will be NULL in that case. Both dvp and *vpp (if not NULL) will be + * locked in the no-error case. No additional references are made to dvp, + * only the locking state changes. */ int -namei(struct nameidata *ndp) +relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) { - struct filedesc *fdp; /* pointer to file descriptor state */ - char *cp; /* pointer into pathname argument */ - struct vnode *dp; /* the directory we are searching */ - struct iovec aiov; /* uio for reading symbolic links */ - struct uio auio; - int error, linklen; - struct componentname *cnp = &ndp->ni_cnd; - struct proc *p; - - KKASSERT(ndp->ni_cnd.cn_td != NULL); - p = cnp->cn_td->td_proc; - if (p == NULL) { - KKASSERT(ndp->ni_segflg == UIO_SYSSPACE); - printf("namei() from non-process\n"); - fdp = NULL; - } else { - KKASSERT(cnp->cn_cred == p->p_ucred); /* YYY */ - fdp = p->p_fd; - } - KASSERT(cnp->cn_cred, ("namei: bad cred/proc")); - KASSERT((cnp->cn_nameiop & (~NAMEI_OPMASK)) == 0, - ("namei: nameiop contaminated with flags")); - KASSERT((cnp->cn_flags & NAMEI_OPMASK) == 0, - ("namei: flags contaminated with nameiops")); - - /* - * Get a buffer for the name to be translated, and copy the - * name into the buffer. - */ - if ((cnp->cn_flags & CNP_HASBUF) == 0) - cnp->cn_pnbuf = zalloc(namei_zone); - if (ndp->ni_segflg == UIO_SYSSPACE) - error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, - MAXPATHLEN, (size_t *)&ndp->ni_pathlen); - else - error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, - MAXPATHLEN, (size_t *)&ndp->ni_pathlen); - - /* - * Don't allow empty pathnames. - * POSIX.1 requirement: "" is not a vaild file name. - */ - if (!error && *cnp->cn_pnbuf == '\0') - error = ENOENT; - - if (error) { - zfree(namei_zone, cnp->cn_pnbuf); - ndp->ni_vp = NULL; - return (error); - } - ndp->ni_loopcnt = 0; -#ifdef KTRACE - if (KTRPOINT(cnp->cn_td, KTR_NAMEI)) - ktrnamei(cnp->cn_td->td_proc->p_tracep, cnp->cn_pnbuf); -#endif - - /* - * Get starting point for the translation. - */ - if (fdp) { - ndp->ni_rootdir = fdp->fd_rdir; - ndp->ni_topdir = fdp->fd_jdir; - dp = fdp->fd_cdir; - } else { - ndp->ni_rootdir = rootvnode; - ndp->ni_topdir = rootvnode; - dp = rootvnode; - } - vref(dp); - for (;;) { - /* - * Check if root directory should replace current directory. - * Done at start of translation and after symbolic link. - */ - cnp->cn_nameptr = cnp->cn_pnbuf; - if (*(cnp->cn_nameptr) == '/') { - vrele(dp); - while (*(cnp->cn_nameptr) == '/') { - cnp->cn_nameptr++; - ndp->ni_pathlen--; - } - dp = ndp->ni_rootdir; - vref(dp); - } - ndp->ni_startdir = dp; - error = lookup(ndp); - if (error) { - zfree(namei_zone, cnp->cn_pnbuf); - return (error); - } - /* - * Check for symbolic link - */ - if ((cnp->cn_flags & CNP_ISSYMLINK) == 0) { - if ((cnp->cn_flags & (CNP_SAVENAME | CNP_SAVESTART)) == 0) - zfree(namei_zone, cnp->cn_pnbuf); - else - cnp->cn_flags |= CNP_HASBUF; - - if (vn_canvmio(ndp->ni_vp) == TRUE && - (cnp->cn_nameiop != NAMEI_DELETE) && - ((cnp->cn_flags & (CNP_NOOBJ|CNP_LOCKLEAF)) == - CNP_LOCKLEAF)) - vfs_object_create(ndp->ni_vp, ndp->ni_cnd.cn_td); - - return (0); - } - if ((cnp->cn_flags & CNP_LOCKPARENT) && ndp->ni_pathlen == 1) - VOP_UNLOCK(ndp->ni_dvp, 0, cnp->cn_td); - if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { - error = ELOOP; - break; - } - if (ndp->ni_pathlen > 1) - cp = zalloc(namei_zone); - else - cp = cnp->cn_pnbuf; - aiov.iov_base = cp; - aiov.iov_len = MAXPATHLEN; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_td = cnp->cn_td; - auio.uio_resid = MAXPATHLEN; - error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); - if (error) { - if (ndp->ni_pathlen > 1) - zfree(namei_zone, cp); - break; - } - linklen = MAXPATHLEN - auio.uio_resid; - if (linklen == 0) { - if (ndp->ni_pathlen > 1) - zfree(namei_zone, cp); - error = ENOENT; - break; - } - if (varsym_enable) { - linklen = varsymreplace(cp, linklen, MAXPATHLEN); - if (linklen < 0) { - if (ndp->ni_pathlen > 1) - zfree(namei_zone, cp); - error = ENAMETOOLONG; - break; - } - } - if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { - if (ndp->ni_pathlen > 1) - zfree(namei_zone, cp); - error = ENAMETOOLONG; - break; - } - if (ndp->ni_pathlen > 1) { - bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); - zfree(namei_zone, cnp->cn_pnbuf); - cnp->cn_pnbuf = cp; - } else { - cnp->cn_pnbuf[linklen] = '\0'; - } - ndp->ni_pathlen += linklen; - vput(ndp->ni_vp); - dp = ndp->ni_dvp; - } - zfree(namei_zone, cnp->cn_pnbuf); - vrele(ndp->ni_dvp); - vput(ndp->ni_vp); - ndp->ni_vp = NULL; - return (error); -} - -/* - * Old API function, search a patchname. This is an *EXTREMELY* complicated - * function. - * - * The pathname is pointed to by ni_ptr and is of length ni_pathlen. - * The starting directory is taken from ni_startdir. The pathname is - * descended until done, or a symbolic link is encountered. The variable - * ni_more is clear if the path is completed; it is set to one if a - * symbolic link needing interpretation is encountered. - * - * The flag argument is NAMEI_LOOKUP, CREATE, RENAME, or DELETE depending on - * whether the name is to be looked up, created, renamed, or deleted. - * When CREATE, RENAME, or DELETE is specified, information usable in - * creating, renaming, or deleting a directory entry may be calculated. - * If flag has LOCKPARENT or'ed into it, the parent directory is returned - * locked. If flag has WANTPARENT or'ed into it, the parent directory is - * returned unlocked. Otherwise the parent directory is not returned. If - * the target of the pathname exists and LOCKLEAF is or'ed into the flag - * the target is returned locked, otherwise it is returned unlocked. - * When creating or renaming and LOCKPARENT is specified, the target may not - * be ".". When deleting and LOCKPARENT is specified, the target may be ".". - * - * SPECIAL CASE: When a symbolic link is encountered the parent - * directory is always returned in ni_dvp regardless of WANTPARENT|LOCKPARENT - * and the symbolic link is returned in ni_vp. If the symbolic link was not - * the last component ni_dvp will be returned UNLOCKED, regardless of - * LOCKPARENT. If the symbolic link is the last component then ni_dvp will - * be returned locked or unlocked based on LOCKPARENT. - * - * SPECIAL CASE: If an error occurs ni_vp and/or ni_dvp may contain garbage - * on return. - * - * VOP_LOOKUP EXPECTATIONS: VOP_LOOKUP() takes a locked directory vnode - * and returns a locked target vnode on success. VOP_LOOKUP() may unlock the - * directory vnode passed to it, in which case it will set CNP_PDIRUNLOCK. - * However, this only occurs under very specific circumstances. The - * directory vnode will only be returned locked if (1) returned vnode == - * directory vnode, or (2) CNP_LOCKPARENT *AND* CNP_LASTCN are both set. - */ -int -lookup(struct nameidata *ndp) -{ - char *cp; /* pointer into pathname argument */ - struct vnode *dp = NULL; /* the directory we are searching */ - struct vnode *tdp; /* saved dp */ - struct mount *mp; /* mount table entry */ - int docache; /* == 0 do not cache last component */ - int wantparent; /* 1 => wantparent or lockparent flag */ + struct thread *td = cnp->cn_td; int rdonly; /* lookup read-only flag bit */ - int trailing_slash; int error = 0; - int dpunlocked = 0; /* dp has already been unlocked */ - struct componentname *cnp = &ndp->ni_cnd; - struct thread *td = cnp->cn_td; /* * Setup: break out flag bits into variables. */ - wantparent = cnp->cn_flags & (CNP_LOCKPARENT | CNP_WANTPARENT); - docache = (cnp->cn_flags & CNP_NOCACHE) ^ CNP_NOCACHE; - if (cnp->cn_nameiop == NAMEI_DELETE || - (wantparent && cnp->cn_nameiop != NAMEI_CREATE && - cnp->cn_nameiop != NAMEI_LOOKUP)) - docache = 0; - rdonly = cnp->cn_flags & CNP_RDONLY; - ndp->ni_dvp = NULL; - cnp->cn_flags &= ~CNP_ISSYMLINK; - dp = ndp->ni_startdir; - ndp->ni_startdir = NULLVP; - vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); - -dirloop: - /* - * Search a new directory. - * - * The last component of the filename is left accessible via - * cnp->cn_nameptr for callers that need the name. Callers needing - * the name set the CNP_SAVENAME flag. When done, they assume - * responsibility for freeing the pathname buffer. - */ - cnp->cn_consume = 0; - for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) - continue; - cnp->cn_namelen = cp - cnp->cn_nameptr; - if (cnp->cn_namelen > NAME_MAX) { - error = ENAMETOOLONG; - goto bad; - } -#ifdef NAMEI_DIAGNOSTIC - { char c = *cp; - *cp = '\0'; - printf("{%s}: ", cnp->cn_nameptr); - *cp = c; } -#endif - ndp->ni_pathlen -= cnp->cn_namelen; - ndp->ni_next = cp; - - /* - * Replace multiple slashes by a single slash and trailing slashes - * by a null. This must be done before VOP_LOOKUP() because some - * fs's don't know about trailing slashes. Remember if there were - * trailing slashes to handle symlinks, existing non-directories - * and non-existing files that won't be directories specially later. - */ - trailing_slash = 0; - while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) { - cp++; - ndp->ni_pathlen--; - if (*cp == '\0') { - trailing_slash = 1; - *ndp->ni_next = '\0'; /* XXX for direnter() ... */ - } - } - ndp->ni_next = cp; - - cnp->cn_flags |= CNP_MAKEENTRY; - if (*cp == '\0' && docache == 0) - cnp->cn_flags &= ~CNP_MAKEENTRY; - if (cnp->cn_namelen == 2 && - cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') - cnp->cn_flags |= CNP_ISDOTDOT; - else - cnp->cn_flags &= ~CNP_ISDOTDOT; - if (*ndp->ni_next == 0) - cnp->cn_flags |= CNP_ISLASTCN; - else - cnp->cn_flags &= ~CNP_ISLASTCN; - - - /* - * Check for degenerate name (e.g. / or "") - * which is a way of talking about a directory, - * e.g. like "/." or ".". - */ - if (cnp->cn_nameptr[0] == '\0') { - if (dp->v_type != VDIR) { - error = ENOTDIR; - goto bad; - } - if (cnp->cn_nameiop != NAMEI_LOOKUP) { - error = EISDIR; - goto bad; - } - if (wantparent) { - ndp->ni_dvp = dp; - vref(dp); - } - ndp->ni_vp = dp; - if (!(cnp->cn_flags & (CNP_LOCKPARENT | CNP_LOCKLEAF))) - VOP_UNLOCK(dp, 0, cnp->cn_td); - /* XXX This should probably move to the top of function. */ - if (cnp->cn_flags & CNP_SAVESTART) - panic("lookup: CNP_SAVESTART"); - return (0); - } - - /* - * Handle "..": two special cases. - * 1. If at root directory (e.g. after chroot) - * or at absolute root directory - * then ignore it so can't get out. - * 2. If this vnode is the root of a mounted - * filesystem, then replace it with the - * vnode which was mounted on so we take the - * .. in the other file system. - * 3. If the vnode is the top directory of - * the jail or chroot, don't let them out. - */ - if (cnp->cn_flags & CNP_ISDOTDOT) { - for (;;) { - if (dp == ndp->ni_rootdir || - dp == ndp->ni_topdir || - dp == rootvnode) { - ndp->ni_dvp = dp; - ndp->ni_vp = dp; - vref(dp); - goto nextname; - } - if ((dp->v_flag & VROOT) == 0 || - (cnp->cn_flags & CNP_NOCROSSMOUNT)) - break; - if (dp->v_mount == NULL) { /* forced unmount */ - error = EBADF; - goto bad; - } - tdp = dp; - dp = dp->v_mount->mnt_vnodecovered; - vput(tdp); - vref(dp); - vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); - } - } - - /* - * We now have a segment name to search for, and a directory to search. - */ -unionlookup: - ndp->ni_dvp = dp; - ndp->ni_vp = NULL; + KKASSERT(cnp->cn_flags & CNP_LOCKPARENT); + KKASSERT(cnp->cn_flags & CNP_PDIRUNLOCK); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); cnp->cn_flags &= ~CNP_PDIRUNLOCK; - ASSERT_VOP_LOCKED(dp, "lookup"); - if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) { - KASSERT(ndp->ni_vp == NULL, ("leaf should be empty")); -#ifdef NAMEI_DIAGNOSTIC - printf("not found\n"); -#endif - if ((error == ENOENT) && - (dp->v_flag & VROOT) && (dp->v_mount != NULL) && - (dp->v_mount->mnt_flag & MNT_UNION)) { - tdp = dp; - dp = dp->v_mount->mnt_vnodecovered; - if (cnp->cn_flags & CNP_PDIRUNLOCK) - vrele(tdp); - else - vput(tdp); - vref(dp); - vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); - goto unionlookup; - } - - if (error != EJUSTRETURN) - goto bad; - /* - * If creating and at end of pathname, then can consider - * allowing file to be created. - */ - if (rdonly) { - error = EROFS; - goto bad; - } - if (*cp == '\0' && trailing_slash && - !(cnp->cn_flags & CNP_WILLBEDIR)) { - error = ENOENT; - goto bad; - } - /* - * We return with ni_vp NULL to indicate that the entry - * doesn't currently exist, leaving a pointer to the - * (possibly locked) directory inode in ndp->ni_dvp. - */ - if (cnp->cn_flags & CNP_SAVESTART) { - ndp->ni_startdir = ndp->ni_dvp; - vref(ndp->ni_startdir); - } - return (0); - } -#ifdef NAMEI_DIAGNOSTIC - printf("found\n"); -#endif - - ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup"); - /* - * Take into account any additional components consumed by - * the underlying filesystem. - */ - if (cnp->cn_consume > 0) { - cnp->cn_nameptr += cnp->cn_consume; - ndp->ni_next += cnp->cn_consume; - ndp->ni_pathlen -= cnp->cn_consume; - cnp->cn_consume = 0; - } - - dp = ndp->ni_vp; - - /* - * Check to see if the vnode has been mounted on; - * if so find the root of the mounted file system. - */ - while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && - (cnp->cn_flags & CNP_NOCROSSMOUNT) == 0) { - if (vfs_busy(mp, 0, NULL, td)) - continue; - VOP_UNLOCK(dp, 0, td); - error = VFS_ROOT(mp, &tdp); - vfs_unbusy(mp, td); - if (error) { - dpunlocked = 1; - goto bad2; - } - vrele(dp); - ndp->ni_vp = dp = tdp; - } - - /* - * Check for symbolic link - */ - if ((dp->v_type == VLNK) && - ((cnp->cn_flags & CNP_FOLLOW) || trailing_slash || - *ndp->ni_next == '/')) { - cnp->cn_flags |= CNP_ISSYMLINK; - if (dp->v_mount == NULL) { - /* We can't know whether the directory was mounted with - * NOSYMFOLLOW, so we can't follow safely. */ - error = EBADF; - goto bad2; - } - if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) { - error = EACCES; - goto bad2; - } - return (0); - } - - /* - * Check for bogus trailing slashes. - */ - if (trailing_slash && dp->v_type != VDIR) { - error = ENOTDIR; - goto bad2; - } - -nextname: - /* - * Not a symbolic link. If more pathname, - * continue at next component, else return. - */ - if (*ndp->ni_next == '/') { - cnp->cn_nameptr = ndp->ni_next; - while (*cnp->cn_nameptr == '/') { - cnp->cn_nameptr++; - ndp->ni_pathlen--; - } - if (ndp->ni_dvp != ndp->ni_vp) - ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup"); - vrele(ndp->ni_dvp); - goto dirloop; - } - /* - * Disallow directory write attempts on read-only file systems. - */ - if (rdonly && - (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) { - error = EROFS; - goto bad2; - } - if (cnp->cn_flags & CNP_SAVESTART) { - ndp->ni_startdir = ndp->ni_dvp; - vref(ndp->ni_startdir); - } - if (!wantparent) - vrele(ndp->ni_dvp); - - if ((cnp->cn_flags & CNP_LOCKLEAF) == 0) - VOP_UNLOCK(dp, 0, td); - return (0); - -bad2: - if ((cnp->cn_flags & (CNP_LOCKPARENT | CNP_PDIRUNLOCK)) == CNP_LOCKPARENT && - *ndp->ni_next == '\0') - VOP_UNLOCK(ndp->ni_dvp, 0, td); - vrele(ndp->ni_dvp); -bad: - if (dpunlocked) - vrele(dp); - else - vput(dp); - ndp->ni_vp = NULL; - return (error); -} - -/* - * relookup - lookup a path name component - * Used by lookup to re-aquire things. - */ -int -relookup(dvp, vpp, cnp) - struct vnode *dvp, **vpp; - struct componentname *cnp; -{ - struct thread *td = cnp->cn_td; - struct vnode *dp = 0; /* the directory we are searching */ - int wantparent; /* 1 => wantparent or lockparent flag */ - int rdonly; /* lookup read-only flag bit */ - int error = 0; -#ifdef NAMEI_DIAGNOSTIC - int newhash; /* DEBUG: check name hash */ - char *cp; /* DEBUG: check name ptr/len */ -#endif - - /* - * Setup: break out flag bits into variables. - */ - wantparent = cnp->cn_flags & (CNP_LOCKPARENT|CNP_WANTPARENT); + *vpp = NULL; rdonly = cnp->cn_flags & CNP_RDONLY; - cnp->cn_flags &= ~CNP_ISSYMLINK; - dp = dvp; - vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); -/* dirloop: */ /* * Search a new directory. - * - * The last component of the filename is left accessible via - * cnp->cn_nameptr for callers that need the name. Callers needing - * the name set the CNP_SAVENAME flag. When done, they assume - * responsibility for freeing the pathname buffer. */ -#ifdef NAMEI_DIAGNOSTIC - if (cnp->cn_namelen != cp - cnp->cn_nameptr) - panic ("relookup: bad len"); - if (*cp != 0) - panic("relookup: not last component"); - printf("{%s}: ", cnp->cn_nameptr); -#endif /* - * Check for degenerate name (e.g. / or "") - * which is a way of talking about a directory, - * e.g. like "/." or ".". + * Degenerate lookups (e.g. "/", "..", derived from "/.", etc) + * are not allowed. */ if (cnp->cn_nameptr[0] == '\0') { - if (cnp->cn_nameiop != NAMEI_LOOKUP || wantparent) { - error = EISDIR; - goto bad; - } - if (dp->v_type != VDIR) { - error = ENOTDIR; - goto bad; - } - if (!(cnp->cn_flags & CNP_LOCKLEAF)) - VOP_UNLOCK(dp, 0, td); - *vpp = dp; - /* XXX This should probably move to the top of function. */ - if (cnp->cn_flags & CNP_SAVESTART) - panic("lookup: CNP_SAVESTART"); - return (0); + error = EISDIR; + goto bad; } - if (cnp->cn_flags & CNP_ISDOTDOT) panic ("relookup: lookup on dot-dot"); /* * We now have a segment name to search for, and a directory to search. */ - if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) { + if ((error = VOP_OLD_LOOKUP(dvp, vpp, cnp)) != 0) { KASSERT(*vpp == NULL, ("leaf should be empty")); if (error != EJUSTRETURN) goto bad; @@ -707,9 +124,6 @@ relookup(dvp, vpp, cnp) error = EROFS; goto bad; } - /* ASSERT(dvp == ndp->ni_startdir) */ - if (cnp->cn_flags & CNP_SAVESTART) - vref(dvp); /* * We return with ni_vp NULL to indicate that the entry * doesn't currently exist, leaving a pointer to the @@ -717,43 +131,33 @@ relookup(dvp, vpp, cnp) */ return (0); } - dp = *vpp; /* * Check for symbolic link */ - KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & CNP_FOLLOW), + KASSERT((*vpp)->v_type != VLNK || !(cnp->cn_flags & CNP_FOLLOW), ("relookup: symlink found.\n")); /* * Disallow directory write attempts on read-only file systems. */ - if (rdonly && - (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) { + if (rdonly && (cnp->cn_nameiop == NAMEI_DELETE || + cnp->cn_nameiop == NAMEI_RENAME)) { error = EROFS; - goto bad2; + goto bad; } - /* ASSERT(dvp == ndp->ni_startdir) */ - if (cnp->cn_flags & CNP_SAVESTART) - vref(dvp); - - if (!wantparent) - vrele(dvp); - - if (vn_canvmio(dp) == TRUE && - ((cnp->cn_flags & (CNP_NOOBJ|CNP_LOCKLEAF)) == CNP_LOCKLEAF)) - vfs_object_create(dp, cnp->cn_td); - - if ((cnp->cn_flags & CNP_LOCKLEAF) == 0) - VOP_UNLOCK(dp, 0, td); + KKASSERT((cnp->cn_flags & CNP_PDIRUNLOCK) == 0); return (0); -bad2: - if ((cnp->cn_flags & CNP_LOCKPARENT) && (cnp->cn_flags & CNP_ISLASTCN)) - VOP_UNLOCK(dvp, 0, td); - vrele(dvp); bad: - vput(dp); - *vpp = NULL; + if ((cnp->cn_flags & CNP_PDIRUNLOCK) == 0) { + cnp->cn_flags |= CNP_PDIRUNLOCK; + VOP_UNLOCK(dvp, 0, td); + } + if (*vpp) { + vput(*vpp); + *vpp = NULL; + } return (error); } + diff --git a/sys/kern/vfs_nlookup.c b/sys/kern/vfs_nlookup.c index 3cedaeb802..25c858ce86 100644 --- a/sys/kern/vfs_nlookup.c +++ b/sys/kern/vfs_nlookup.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/kern/vfs_nlookup.c,v 1.6 2004/10/07 20:18:33 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_nlookup.c,v 1.7 2004/11/12 00:09:24 dillon Exp $ */ /* * nlookup() is the 'new' namei interface. Rather then return directory and @@ -125,6 +125,50 @@ nlookup_init(struct nlookupdata *nd, return(error); } +/* + * This works similarly to nlookup_init() but does not assume a process + * context. rootncp is always chosen for the root directory and the cred + * and starting directory are supplied in arguments. + */ +int +nlookup_init_raw(struct nlookupdata *nd, + const char *path, enum uio_seg seg, int flags, + struct ucred *cred, struct namecache *ncstart) +{ + size_t pathlen; + thread_t td; + int error; + + td = curthread; + + bzero(nd, sizeof(struct nlookupdata)); + nd->nl_path = zalloc(namei_zone); + nd->nl_flags |= NLC_HASBUF; + if (seg == UIO_SYSSPACE) + error = copystr(path, nd->nl_path, MAXPATHLEN, &pathlen); + else + error = copyinstr(path, nd->nl_path, MAXPATHLEN, &pathlen); + + /* + * Don't allow empty pathnames. + * POSIX.1 requirement: "" is not a vaild file name. + */ + if (error == 0 && pathlen <= 1) + error = ENOENT; + + if (error == 0) { + nd->nl_ncp = cache_hold(ncstart); + nd->nl_rootncp = cache_hold(rootncp); + nd->nl_jailncp = cache_hold(rootncp); + nd->nl_cred = crhold(cred); + nd->nl_td = td; + nd->nl_flags |= flags; + } else { + nlookup_done(nd); + } + return(error); +} + /* * Cleanup a nlookupdata structure after we are through with it. This may * be called on any nlookupdata structure initialized with nlookup_init(). @@ -159,7 +203,21 @@ nlookup_done(struct nlookupdata *nd) crfree(nd->nl_cred); nd->nl_cred = NULL; } - nd->nl_flags = 0; + if (nd->nl_open_vp) { + if (nd->nl_flags & NLC_LOCKVP) { + VOP_UNLOCK(nd->nl_open_vp, 0, nd->nl_td); + nd->nl_flags &= ~NLC_LOCKVP; + } + vn_close(nd->nl_open_vp, nd->nl_vp_fmode, nd->nl_td); + nd->nl_open_vp = NULL; + } + nd->nl_flags = 0; /* clear remaining flags (just clear everything) */ +} + +void +nlookup_zero(struct nlookupdata *nd) +{ + bzero(nd, sizeof(struct nlookupdata)); } /* @@ -200,6 +258,11 @@ nlookup_simple(const char *str, enum uio_seg seg, * Intermediate directory elements, including the current directory, require * execute (search) permission. nlookup does not examine the access * permissions on the returned element. + * + * If NLC_CREATE or NLC_DELETE is set the last directory must allow node + * creation (VCREATE/VDELETE), and an error code of 0 will be returned for + * a non-existant target. Otherwise a non-existant target will cause + * ENOENT to be returned. */ int nlookup(struct nlookupdata *nd) @@ -207,6 +270,7 @@ nlookup(struct nlookupdata *nd) struct nlcomponent nlc; struct namecache *ncp; char *ptr; + char *xptr; int error; int len; @@ -279,7 +343,10 @@ nlookup(struct nlookupdata *nd) * mount point and skip the mount-under node. If we are at the root * ".." just returns the root. * - * This subsection returns a locked, refd 'ncp'. + * This subsection returns a locked, refd 'ncp' unless it errors out. + * The namecache topology is not allowed to be disconnected, so + * encountering a NULL parent will generate EINVAL. This typically + * occurs when a directory is removed out from under a process. */ if (nlc.nlc_namelen == 1 && nlc.nlc_nameptr[0] == '.') { ncp = cache_get(nd->nl_ncp); @@ -290,18 +357,16 @@ nlookup(struct nlookupdata *nd) ncp = cache_get(ncp); } else { while ((ncp->nc_flag & NCF_MOUNTPT) && ncp != nd->nl_rootncp) { - /* ignore NCF_REVALPARENT on a mount point */ ncp = ncp->nc_parent; /* get to underlying node */ KKASSERT(ncp != NULL && 1); } - if (ncp->nc_flag & NCF_REVALPARENT) { - printf("[diagnostic] nlookup can't .. past a renamed directory: %*.*s\n", ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name); - error = EINVAL; - break; - } - if (ncp != nd->nl_rootncp) + if (ncp != nd->nl_rootncp) { ncp = ncp->nc_parent; - KKASSERT(ncp != NULL && 2); + if (ncp == NULL) { + error = EINVAL; + break; + } + } ncp = cache_get(ncp); } } else { @@ -332,7 +397,18 @@ nlookup(struct nlookupdata *nd) } /* - * Early completion + * Early completion. ENOENT is not an error if this is the last + * component and NLC_CREATE was requested. Note that ncp->nc_error + * is left as ENOENT in that case, which we check later on. + */ + for (xptr = ptr; *xptr == '/'; ++xptr) + ; + if (error == ENOENT && *xptr == 0 && (nd->nl_flags & NLC_CREATE)) { + error = naccess(ncp, VCREATE, nd->nl_cred); + } + + /* + * Early completion on error. */ if (error) { cache_put(ncp); @@ -423,12 +499,16 @@ nlookup(struct nlookupdata *nd) /* * Skip any slashes to get to the next element. If there * are any slashes at all the current element must be a - * directory. If it isn't we break without incrementing - * ptr and fall through to the failure case below. + * directory or, in the create case, intended to become a directory. + * If it isn't we break without incrementing ptr and fall through + * to the failure case below. */ while (*ptr == '/') { - if ((ncp->nc_flag & NCF_ISDIR) == 0) + if ((ncp->nc_flag & NCF_ISDIR) == 0 && + !(nd->nl_flags & NLC_WILLBEDIR) + ) { break; + } ++ptr; } @@ -453,12 +533,26 @@ nlookup(struct nlookupdata *nd) break; } + /* + * Successful lookup of last element. + * + * Check directory permissions if a deletion is specified. + */ + if (*ptr == 0 && (nd->nl_flags & NLC_DELETE)) { + if ((error = naccess(ncp, VDELETE, nd->nl_cred)) != 0) { + cache_put(ncp); + break; + } + } + /* * XXX vnode canvmio (test in mmap(), read(), and write()) */ /* - * Termination: no more elements. + * Termination: no more elements. If NLC_CREATE was set the + * ncp may represent a negative hit (ncp->nc_error will be ENOENT), + * but we still return an error code of 0. */ cache_drop(nd->nl_ncp); nd->nl_ncp = ncp; @@ -597,7 +691,7 @@ naccess(struct namecache *ncp, int vmode, struct ucred *cred) ) { if ((par = ncp->nc_parent) == NULL) { if (error != EAGAIN) - error = EROFS; + error = EINVAL; } else { cache_hold(par); error = naccess(par, VWRITE, cred); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index cc396958c6..d2bde5fba0 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -37,7 +37,7 @@ * * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 * $FreeBSD: src/sys/kern/vfs_subr.c,v 1.249.2.30 2003/04/04 20:35:57 tegge Exp $ - * $DragonFly: src/sys/kern/vfs_subr.c,v 1.45 2004/10/25 19:14:32 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_subr.c,v 1.46 2004/11/12 00:09:24 dillon Exp $ */ /* @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include @@ -88,6 +87,8 @@ static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure"); int numvnodes; SYSCTL_INT(_debug, OID_AUTO, numvnodes, CTLFLAG_RD, &numvnodes, 0, ""); +int vfs_fastdev; +SYSCTL_INT(_vfs, OID_AUTO, fastdev, CTLFLAG_RW, &vfs_fastdev, 0, ""); enum vtype iftovt_tab[16] = { VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, @@ -1790,40 +1791,6 @@ vn_isdisk(struct vnode *vp, int *errp) return (1); } -void -NDFREE(struct nameidata *ndp, const uint flags) -{ - if (!(flags & NDF_NO_FREE_PNBUF) && - (ndp->ni_cnd.cn_flags & CNP_HASBUF)) { - zfree(namei_zone, ndp->ni_cnd.cn_pnbuf); - ndp->ni_cnd.cn_flags &= ~CNP_HASBUF; - } - if (!(flags & NDF_NO_DVP_UNLOCK) && - (ndp->ni_cnd.cn_flags & CNP_LOCKPARENT) && - ndp->ni_dvp != ndp->ni_vp) { - VOP_UNLOCK(ndp->ni_dvp, 0, ndp->ni_cnd.cn_td); - } - if (!(flags & NDF_NO_DVP_RELE) && - (ndp->ni_cnd.cn_flags & (CNP_LOCKPARENT|CNP_WANTPARENT))) { - vrele(ndp->ni_dvp); - ndp->ni_dvp = NULL; - } - if (!(flags & NDF_NO_VP_UNLOCK) && - (ndp->ni_cnd.cn_flags & CNP_LOCKLEAF) && ndp->ni_vp) { - VOP_UNLOCK(ndp->ni_vp, 0, ndp->ni_cnd.cn_td); - } - if (!(flags & NDF_NO_VP_RELE) && - ndp->ni_vp) { - vrele(ndp->ni_vp); - ndp->ni_vp = NULL; - } - if (!(flags & NDF_NO_STARTDIR_RELE) && - (ndp->ni_cnd.cn_flags & CNP_SAVESTART)) { - vrele(ndp->ni_startdir); - ndp->ni_startdir = NULL; - } -} - #ifdef DEBUG_VFS_LOCKS void diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 6737631764..208524b3aa 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -37,7 +37,7 @@ * * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 * $FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.151.2.18 2003/04/04 20:35:58 tegge Exp $ - * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.45 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.46 2004/11/12 00:09:24 dillon Exp $ */ #include @@ -322,7 +322,7 @@ update: /* * Mount the filesystem. * XXX The final recipients of VFS_MOUNT just overwrite the ndp they - * get. No freeing of cn_pnbuf. + * get. */ error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), td); if (mp->mnt_flag & MNT_UPDATE) { @@ -453,7 +453,7 @@ unmount(struct unmount_args *uap) struct vnode *vp; struct mount *mp; int error; - struct nameidata nd; + struct nlookupdata nd; KKASSERT(p); if (p->p_ucred->cr_prison != NULL) @@ -461,12 +461,16 @@ unmount(struct unmount_args *uap) if (usermount == 0 && (error = suser(td))) return (error); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + nlookup_done(&nd); + if (error) return (error); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); + mp = vp->v_mount; /* @@ -639,43 +643,42 @@ SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, ""); int quotactl(struct quotactl_args *uap) { - struct thread *td = curthread; - struct proc *p = td->td_proc; + struct nlookupdata nd; + struct thread *td; + struct proc *p; struct mount *mp; int error; - struct nameidata nd; - KKASSERT(p); + td = curthread; + p = td->td_proc; if (p->p_ucred->cr_prison && !prison_quotas) return (EPERM); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, - SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - mp = nd.ni_vp->v_mount; - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); - return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), - SCARG(uap, arg), td)); + + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) { + mp = nd.nl_ncp->nc_mount; + error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), + SCARG(uap, arg), nd.nl_td); + } + nlookup_done(&nd); + return (error); } int -kern_statfs(struct nameidata *nd, struct statfs *buf) +kern_statfs(struct nlookupdata *nd, struct statfs *buf) { struct thread *td = curthread; struct mount *mp; struct statfs *sp; int error; - error = namei(nd); - if (error) + if ((error = nlookup(nd)) != 0) return (error); - mp = nd->ni_vp->v_mount; + mp = nd->nl_ncp->nc_mount; sp = &mp->mnt_stat; - NDFREE(nd, NDF_ONLY_PNBUF); - vrele(nd->ni_vp); - error = VFS_STATFS(mp, sp, td); - if (error) + if ((error = VFS_STATFS(mp, sp, td)) != 0) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; bcopy(sp, buf, sizeof(*buf)); @@ -693,15 +696,14 @@ kern_statfs(struct nameidata *nd, struct statfs *buf) int statfs(struct statfs_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; struct statfs buf; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td); - - error = kern_statfs(&nd, &buf); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_statfs(&nd, &buf); + nlookup_done(&nd); if (error == 0) error = copyout(&buf, uap->buf, sizeof(*uap->buf)); return (error); @@ -921,10 +923,9 @@ chdir(struct chdir_args *uap) int error; error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); - if (error == 0) { + if (error == 0) error = kern_chdir(&nd); - nlookup_done(&nd); - } + nlookup_done(&nd); return (error); } @@ -1042,10 +1043,9 @@ chroot(struct chroot_args *uap) KKASSERT(td->td_proc); error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); - if (error == 0) { + if (error == 0) error = kern_chroot(&nd); - nlookup_done(&nd); - } + nlookup_done(&nd); return (error); } @@ -1067,79 +1067,91 @@ checkvp_chdir(struct vnode *vp, struct thread *td) } int -kern_open(struct nameidata *nd, int oflags, int mode, int *res) +kern_open(struct nlookupdata *nd, int oflags, int mode, int *res) { struct thread *td = curthread; struct proc *p = td->td_proc; struct filedesc *fdp = p->p_fd; - struct file *fp; - struct vnode *vp; int cmode, flags; struct file *nfp; + struct file *fp; + struct vnode *vp; int type, indx, error; - int ndxerror; struct flock lf; - struct nlookupdata ndx; if ((oflags & O_ACCMODE) == O_ACCMODE) return (EINVAL); flags = FFLAGS(oflags); - error = falloc(p, &nfp, &indx); + error = falloc(p, &nfp, NULL); if (error) return (error); fp = nfp; cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; - p->p_dupfd = -indx - 1; /* XXX check for fdopen */ + /* - * Bump the ref count to prevent another process from closing - * the descriptor while we are blocked in vn_open() + * XXX p_dupfd is a real mess. It allows a device to return a + * file descriptor to be duplicated rather then doing the open + * itself. */ - fhold(fp); + p->p_dupfd = -1; /* - * XXX temporary hack so we can record the namecache pointer - * associated with an open descriptor. + * Call vn_open() to do the lookup and assign the vnode to the + * file pointer. vn_open() does not change the ref count on fp + * and the vnode, on success, will be inherited by the file pointer + * and unlocked. */ - ndxerror = nlookup_init(&ndx, nd->ni_dirp, nd->ni_segflg, - ((nd->ni_cnd.cn_flags & CNP_FOLLOW) ? NLC_FOLLOW : 0)); - - error = vn_open(nd, flags, cmode); + nd->nl_flags |= NLC_LOCKVP; + error = vn_open(nd, fp, flags, cmode); + nlookup_done(nd); if (error) { - /* - * release our own reference - */ - fdrop(fp, td); - /* * handle special fdopen() case. bleh. dupfdopen() is * responsible for dropping the old contents of ofiles[indx] * if it succeeds. + * + * Note that if fsetfd() succeeds it will add a ref to fp + * which represents the fd_ofiles[] assignment. We must still + * drop our reference. */ - if ((error == ENODEV || error == ENXIO) && - p->p_dupfd >= 0 && /* XXX from fdopen */ - (error = - dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { - *res = indx; - nlookup_done(&ndx); - return (0); - } - /* - * Clean up the descriptor, but only if another thread hadn't - * replaced or closed it. - */ - if (fdp->fd_ofiles[indx] == fp) { - fdp->fd_ofiles[indx] = NULL; - fdrop(fp, td); + if ((error == ENODEV || error == ENXIO) && p->p_dupfd >= 0) { + if (fsetfd(p, fp, &indx) == 0) { + error = dupfdopen(fdp, indx, p->p_dupfd, flags, error); + if (error == 0) { + *res = indx; + fdrop(fp, td); /* our ref */ + return (0); + } + if (fdp->fd_ofiles[indx] == fp) { + fdp->fd_ofiles[indx] = NULL; + fdrop(fp, td); /* fd_ofiles[] ref */ + } + } } - + fdrop(fp, td); /* our ref */ if (error == ERESTART) error = EINTR; - nlookup_done(&ndx); return (error); } + + /* + * ref the vnode for ourselves so it can't be ripped out from under + * is. XXX need an ND flag to request that the vnode be returned + * anyway. + */ + vp = (struct vnode *)fp->f_data; + vref(vp); + if ((error = fsetfd(p, fp, &indx)) != 0) { + fdrop(fp, td); + vrele(vp); + return (error); + } + + /* + * If no error occurs the vp will have been assigned to the file + * pointer. + */ p->p_dupfd = 0; - NDFREE(nd, NDF_ONLY_PNBUF); - vp = nd->ni_vp; /* * There should be 2 references on the file, one from the descriptor @@ -1152,18 +1164,13 @@ kern_open(struct nameidata *nd, int oflags, int mode, int *res) if (fp->f_count == 1) { KASSERT(fdp->fd_ofiles[indx] != fp, ("Open file descriptor lost all refs")); - VOP_UNLOCK(vp, 0, td); - vn_close(vp, flags & FMASK, td); + vrele(vp); + fo_close(fp, td); fdrop(fp, td); *res = indx; - nlookup_done(&ndx); return 0; } - fp->f_data = (caddr_t)vp; - fp->f_flag = flags & FMASK; - fp->f_ops = &vnops; - fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); if (flags & (O_EXLOCK | O_SHLOCK)) { lf.l_whence = SEEK_SET; lf.l_start = 0; @@ -1175,7 +1182,7 @@ kern_open(struct nameidata *nd, int oflags, int mode, int *res) type = F_FLOCK; if ((flags & FNONBLOCK) == 0) type |= F_WAIT; - VOP_UNLOCK(vp, 0, td); + if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) { /* * lock request failed. Normally close the descriptor @@ -1183,41 +1190,21 @@ kern_open(struct nameidata *nd, int oflags, int mode, int *res) * it when we weren't looking. One reference is * owned by the descriptor array, the other by us. */ + vrele(vp); if (fdp->fd_ofiles[indx] == fp) { fdp->fd_ofiles[indx] = NULL; fdrop(fp, td); } fdrop(fp, td); - nlookup_done(&ndx); return (error); } - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); fp->f_flag |= FHASLOCK; } /* assert that vn_open created a backing object if one is needed */ KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0, ("open: vmio vnode has no backing object after vn_open")); - VOP_UNLOCK(vp, 0, td); - /* - * If the vp is a directory locate the ncp to store with the file - * descriptor. XXX temporary. We may eventually wish to do this - * permanently as it would provide an invaluable diagnostic tool, - * but first the entire open path needs to be converted from - * namei to nlookup so we can avoid having to do a double-lookup. - * - * The primary purpose of storing the ncp with the file pointer is - * so it can be used in fchdir() and fchroot() syscalls, allowing - * us to retain an unbroken namecache topology. - */ - if (ndxerror == 0 && vp->v_type == VDIR) { - if ((ndxerror = nlookup(&ndx)) == 0) { - fp->f_ncp = ndx.nl_ncp; - ndx.nl_ncp = NULL; - cache_unlock(fp->f_ncp); - } - } - nlookup_done(&ndx); + vrele(vp); /* * release our private reference, leaving the one associated with the @@ -1237,20 +1224,22 @@ kern_open(struct nameidata *nd, int oflags, int mode, int *res) int open(struct open_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td); - - error = kern_open(&nd, uap->flags, uap->mode, &uap->sysmsg_result); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) { + error = kern_open(&nd, uap->flags, + uap->mode, &uap->sysmsg_result); + } + nlookup_done(&nd); return (error); } int -kern_mknod(struct nameidata *nd, int mode, int dev) +kern_mknod(struct nlookupdata *nd, int mode, int dev) { + struct namecache *ncp; struct thread *td = curthread; struct proc *p = td->td_proc; struct vnode *vp; @@ -1271,61 +1260,47 @@ kern_mknod(struct nameidata *nd, int mode, int dev) } if (error) return (error); + bwillwrite(); - error = namei(nd); - if (error) + nd->nl_flags |= NLC_CREATE; + if ((error = nlookup(nd)) != 0) return (error); - vp = nd->ni_vp; - if (vp != NULL) - error = EEXIST; - else { - VATTR_NULL(&vattr); - vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask; - vattr.va_rdev = dev; - whiteout = 0; + ncp = nd->nl_ncp; + if (ncp->nc_vp) + return (EEXIST); - switch (mode & S_IFMT) { - case S_IFMT: /* used by badsect to flag bad sectors */ - vattr.va_type = VBAD; - break; - case S_IFCHR: - vattr.va_type = VCHR; - break; - case S_IFBLK: - vattr.va_type = VBLK; - break; - case S_IFWHT: - whiteout = 1; - break; - default: - error = EINVAL; - break; - } + VATTR_NULL(&vattr); + vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask; + vattr.va_rdev = dev; + whiteout = 0; + + switch (mode & S_IFMT) { + case S_IFMT: /* used by badsect to flag bad sectors */ + vattr.va_type = VBAD; + break; + case S_IFCHR: + vattr.va_type = VCHR; + break; + case S_IFBLK: + vattr.va_type = VBLK; + break; + case S_IFWHT: + whiteout = 1; + break; + default: + error = EINVAL; + break; } if (error == 0) { - VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE); - if (whiteout) - error = VOP_WHITEOUT(nd->ni_dvp, NCPNULL, - &nd->ni_cnd, NAMEI_CREATE); - else { - error = VOP_MKNOD(nd->ni_dvp, NCPNULL, &nd->ni_vp, - &nd->ni_cnd, &vattr); + if (whiteout) { + error = VOP_NWHITEOUT(ncp, nd->nl_cred, NAMEI_CREATE); + } else { + vp = NULL; + error = VOP_NMKNOD(ncp, &vp, nd->nl_cred, &vattr); if (error == 0) - vput(nd->ni_vp); + vput(vp); } - NDFREE(nd, NDF_ONLY_PNBUF); - vput(nd->ni_dvp); - } else { - NDFREE(nd, NDF_ONLY_PNBUF); - if (nd->ni_dvp == vp) - vrele(nd->ni_dvp); - else - vput(nd->ni_dvp); - if (vp) - vrele(vp); } - ASSERT_VOP_UNLOCKED(nd->ni_dvp, "mknod"); - ASSERT_VOP_UNLOCKED(nd->ni_vp, "mknod"); return (error); } @@ -1337,48 +1312,42 @@ kern_mknod(struct nameidata *nd, int mode, int dev) int mknod(struct mknod_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_USERSPACE, uap->path, - td); - - error = kern_mknod(&nd, uap->mode, uap->dev); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) + error = kern_mknod(&nd, uap->mode, uap->dev); + nlookup_done(&nd); return (error); } int -kern_mkfifo(struct nameidata *nd, int mode) +kern_mkfifo(struct nlookupdata *nd, int mode) { + struct namecache *ncp; struct thread *td = curthread; struct proc *p = td->td_proc; struct vattr vattr; + struct vnode *vp; int error; bwillwrite(); - error = namei(nd); - if (error) + + nd->nl_flags |= NLC_CREATE; + if ((error = nlookup(nd)) != 0) return (error); - if (nd->ni_vp != NULL) { - NDFREE(nd, NDF_ONLY_PNBUF); - if (nd->ni_dvp == nd->ni_vp) - vrele(nd->ni_dvp); - else - vput(nd->ni_dvp); - vrele(nd->ni_vp); + ncp = nd->nl_ncp; + if (ncp->nc_vp) return (EEXIST); - } + VATTR_NULL(&vattr); vattr.va_type = VFIFO; vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask; - VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE); - error = VOP_MKNOD(nd->ni_dvp, NCPNULL, &nd->ni_vp, &nd->ni_cnd, &vattr); + vp = NULL; + error = VOP_NMKNOD(ncp, &vp, nd->nl_cred, &vattr); if (error == 0) - vput(nd->ni_vp); - NDFREE(nd, NDF_ONLY_PNBUF); - vput(nd->ni_dvp); + vput(vp); return (error); } @@ -1390,58 +1359,62 @@ kern_mkfifo(struct nameidata *nd, int mode) int mkfifo(struct mkfifo_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_USERSPACE, uap->path, - td); - - error = kern_mkfifo(&nd, uap->mode); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) + error = kern_mkfifo(&nd, uap->mode); + nlookup_done(&nd); return (error); } int -kern_link(struct nameidata *nd, struct nameidata *linknd) +kern_link(struct nlookupdata *nd, struct nlookupdata *linknd) { struct thread *td = curthread; - struct proc *p = td->td_proc; struct vnode *vp; int error; + /* + * Lookup the source and obtained a locked vnode. + * + * XXX relookup on vget failure / race ? + */ bwillwrite(); - error = namei(nd); - if (error) + if ((error = nlookup(nd)) != 0) return (error); - NDFREE(nd, NDF_ONLY_PNBUF); - vp = nd->ni_vp; + vp = nd->nl_ncp->nc_vp; + KKASSERT(vp != NULL); if (vp->v_type == VDIR) - error = EPERM; /* POSIX */ - else { - error = namei(linknd); - if (error == 0) { - if (linknd->ni_vp != NULL) { - if (linknd->ni_vp) - vrele(linknd->ni_vp); - error = EEXIST; - } else { - VOP_LEASE(linknd->ni_dvp, td, p->p_ucred, - LEASE_WRITE); - VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE); - error = VOP_LINK(linknd->ni_dvp, NCPNULL, vp, - &linknd->ni_cnd); - } - NDFREE(linknd, NDF_ONLY_PNBUF); - if (linknd->ni_dvp == linknd->ni_vp) - vrele(linknd->ni_dvp); - else - vput(linknd->ni_dvp); - ASSERT_VOP_UNLOCKED(linknd->ni_dvp, "link"); - ASSERT_VOP_UNLOCKED(linknd->ni_vp, "link"); - } + return (EPERM); /* POSIX */ + if ((error = vget(vp, LK_EXCLUSIVE, td)) != 0) + return (error); + + /* + * Unlock the source so we can lookup the target without deadlocking + * (XXX vp is locked already, possible other deadlock?). The target + * must not exist. + */ + KKASSERT(nd->nl_flags & NLC_NCPISLOCKED); + nd->nl_flags &= ~NLC_NCPISLOCKED; + cache_unlock(nd->nl_ncp); + + linknd->nl_flags |= NLC_CREATE; + if ((error = nlookup(linknd)) != 0) { + vput(vp); + return (error); } - vrele(vp); + if (linknd->nl_ncp->nc_vp) { + vput(vp); + return (EEXIST); + } + + /* + * Finally run the new API VOP. + */ + error = VOP_NLINK(linknd->nl_ncp, vp, linknd->nl_cred); + vput(vp); return (error); } @@ -1453,53 +1426,41 @@ kern_link(struct nameidata *nd, struct nameidata *linknd) int link(struct link_args *uap) { - struct thread *td = curthread; - struct nameidata nd, linknd; + struct nlookupdata nd, linknd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_NOOBJ, UIO_USERSPACE, - uap->path, td); - NDINIT(&linknd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ, - UIO_USERSPACE, uap->link, td); - - error = kern_link(&nd, &linknd); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) { + error = nlookup_init(&linknd, uap->link, UIO_USERSPACE, 0); + if (error == 0) + error = kern_link(&nd, &linknd); + nlookup_done(&linknd); + } + nlookup_done(&nd); return (error); } int -kern_symlink(char *path, struct nameidata *nd) +kern_symlink(struct nlookupdata *nd, char *path, int mode) { - struct thread *td = curthread; - struct proc *p = td->td_proc; + struct namecache *ncp; struct vattr vattr; + struct vnode *vp; int error; bwillwrite(); - error = namei(nd); - if (error) + nd->nl_flags |= NLC_CREATE; + if ((error = nlookup(nd)) != 0) return (error); - if (nd->ni_vp) { - NDFREE(nd, NDF_ONLY_PNBUF); - if (nd->ni_dvp == nd->ni_vp) - vrele(nd->ni_dvp); - else - vput(nd->ni_dvp); - vrele(nd->ni_vp); + ncp = nd->nl_ncp; + if (ncp->nc_vp) return (EEXIST); - } + VATTR_NULL(&vattr); - vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; - VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE); - error = VOP_SYMLINK(nd->ni_dvp, NCPNULL, &nd->ni_vp, &nd->ni_cnd, - &vattr, path); - NDFREE(nd, NDF_ONLY_PNBUF); + vattr.va_mode = mode; + error = VOP_NSYMLINK(ncp, &vp, nd->nl_cred, &vattr, path); if (error == 0) - vput(nd->ni_vp); - vput(nd->ni_dvp); - ASSERT_VOP_UNLOCKED(nd->ni_dvp, "symlink"); - ASSERT_VOP_UNLOCKED(nd->ni_vp, "symlink"); - + vput(vp); return (error); } @@ -1512,16 +1473,20 @@ int symlink(struct symlink_args *uap) { struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; char *path; int error; + int mode; path = zalloc(namei_zone); error = copyinstr(uap->path, path, MAXPATHLEN, NULL); if (error == 0) { - NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ, - UIO_USERSPACE, uap->link, td); - error = kern_symlink(path, &nd); + error = nlookup_init(&nd, uap->link, UIO_USERSPACE, 0); + if (error == 0) { + mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask; + error = kern_symlink(&nd, path, mode); + } + nlookup_done(&nd); } zfree(namei_zone, path); return (error); @@ -1536,83 +1501,32 @@ symlink(struct symlink_args *uap) int undelete(struct undelete_args *uap) { - struct thread *td = curthread; - struct proc *p = td->td_proc; + struct nlookupdata nd; int error; - struct nameidata nd; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, 0); bwillwrite(); - NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT | CNP_DOWHITEOUT, UIO_USERSPACE, - SCARG(uap, path), td); - error = namei(&nd); - if (error) - return (error); - - if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & CNP_ISWHITEOUT)) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - if (nd.ni_vp) - vrele(nd.ni_vp); - return (EEXIST); - } - - VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE); - error = VOP_WHITEOUT(nd.ni_dvp, NCPNULL, &nd.ni_cnd, NAMEI_DELETE); + nd.nl_flags |= NLC_DELETE; + if (error == 0) + error = nlookup(&nd); if (error == 0) - cache_purge(nd.ni_vp); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete"); - ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete"); + error = VOP_NWHITEOUT(nd.nl_ncp, nd.nl_cred, NAMEI_DELETE); + nlookup_done(&nd); return (error); } int -kern_unlink(struct nameidata *nd) +kern_unlink(struct nlookupdata *nd) { - struct thread *td = curthread; - struct proc *p = td->td_proc; - struct vnode *vp; + struct namecache *ncp; int error; bwillwrite(); - error = namei(nd); - if (error) + nd->nl_flags |= NLC_DELETE; + if ((error = nlookup(nd)) != 0) return (error); - vp = nd->ni_vp; - VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - - if (vp->v_type == VDIR) - error = EPERM; /* POSIX */ - else { - /* - * The root of a mounted filesystem cannot be deleted. - * - * XXX: can this only be a VDIR case? - */ - if (vp->v_flag & VROOT) - error = EBUSY; - } - - if (error == 0) { - VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE); - error = VOP_REMOVE(nd->ni_dvp, NCPNULL, vp, &nd->ni_cnd); - if (error == 0) - cache_purge(vp); - } - NDFREE(nd, NDF_ONLY_PNBUF); - if (nd->ni_dvp == vp) - vrele(nd->ni_dvp); - else - vput(nd->ni_dvp); - if (vp != NULLVP) - vput(vp); - ASSERT_VOP_UNLOCKED(nd->ni_dvp, "unlink"); - ASSERT_VOP_UNLOCKED(nd->ni_vp, "unlink"); + ncp = nd->nl_ncp; + error = VOP_NREMOVE(ncp, nd->nl_cred); return (error); } @@ -1624,15 +1538,13 @@ kern_unlink(struct nameidata *nd) int unlink(struct unlink_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT, UIO_USERSPACE, uap->path, - td); - - error = kern_unlink(&nd); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) + error = kern_unlink(&nd); + nlookup_done(&nd); return (error); } @@ -1688,29 +1600,17 @@ lseek(struct lseek_args *uap) } int -kern_access(struct nameidata *nd, int aflags) +kern_access(struct nlookupdata *nd, int aflags) { struct thread *td = curthread; - struct proc *p = td->td_proc; - struct ucred *cred, *tmpcred; struct vnode *vp; int error, flags; - cred = p->p_ucred; - /* - * Create and modify a temporary credential instead of one that - * is potentially shared. This could also mess up socket - * buffer accounting which can run in an interrupt context. - */ - tmpcred = crdup(cred); - tmpcred->cr_uid = p->p_ucred->cr_ruid; - tmpcred->cr_groups[0] = p->p_ucred->cr_rgid; - p->p_ucred = tmpcred; - nd->ni_cnd.cn_cred = tmpcred; - error = namei(nd); + if ((error = nlookup(nd)) != 0) + return (error); + error = cache_vget(nd->nl_ncp, nd->nl_cred, LK_EXCLUSIVE, &vp); if (error) - goto out1; - vp = nd->ni_vp; + return (error); /* Flags == 0 means only check for existence. */ if (aflags) { @@ -1722,13 +1622,9 @@ kern_access(struct nameidata *nd, int aflags) if (aflags & X_OK) flags |= VEXEC; if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) - error = VOP_ACCESS(vp, flags, tmpcred, td); + error = VOP_ACCESS(vp, flags, nd->nl_cred, td); } - NDFREE(nd, NDF_ONLY_PNBUF); vput(vp); -out1: - p->p_ucred = cred; - crfree(tmpcred); return (error); } @@ -1740,15 +1636,13 @@ out1: int access(struct access_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ, - UIO_USERSPACE, uap->path, td); - - error = kern_access(&nd, uap->flags); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_access(&nd, uap->flags); + nlookup_done(&nd); return (error); } @@ -1789,8 +1683,8 @@ stat(struct stat_args *uap) error = kern_stat(&nd, &st); if (error == 0) error = copyout(&st, uap->ub, sizeof(*uap->ub)); - nlookup_done(&nd); } + nlookup_done(&nd); return (error); } @@ -1811,8 +1705,8 @@ lstat(struct lstat_args *uap) error = kern_stat(&nd, &st); if (error == 0) error = copyout(&st, uap->ub, sizeof(*uap->ub)); - nlookup_done(&nd); } + nlookup_done(&nd); return (error); } @@ -1848,23 +1742,28 @@ int nstat(struct nstat_args *uap) { struct thread *td = curthread; + struct vnode *vp; struct stat sb; struct nstat nsb; + struct nlookupdata nd; int error; - struct nameidata nd; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ, - UIO_USERSPACE, SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(nd.ni_vp, &sb, td); - vput(nd.ni_vp); - if (error) - return (error); - cvtnstat(&sb, &nsb); - error = copyout(&nsb, SCARG(uap, ub), sizeof (nsb)); - return (error); + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + nlookup_done(&nd); + if (error == 0) { + error = vn_stat(vp, &sb, td); + vput(vp); + if (error == 0) { + cvtnstat(&sb, &nsb); + error = copyout(&nsb, SCARG(uap, ub), sizeof(nsb)); + } + } + return (error); } /* @@ -1877,24 +1776,27 @@ int nlstat(struct nlstat_args *uap) { struct thread *td = curthread; - int error; struct vnode *vp; struct stat sb; struct nstat nsb; - struct nameidata nd; + struct nlookupdata nd; + int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_NOOBJ, - UIO_USERSPACE, SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(vp, &sb, td); - vput(vp); - if (error) - return (error); - cvtnstat(&sb, &nsb); - error = copyout(&nsb, SCARG(uap, ub), sizeof (nsb)); + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, 0); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + nlookup_done(&nd); + if (error == 0) { + error = vn_stat(vp, &sb, td); + vput(vp); + if (error == 0) { + cvtnstat(&sb, &nsb); + error = copyout(&nsb, SCARG(uap, ub), sizeof(nsb)); + } + } return (error); } @@ -1907,17 +1809,21 @@ nlstat(struct nlstat_args *uap) int pathconf(struct pathconf_args *uap) { - struct thread *td = curthread; + struct nlookupdata nd; + struct vnode *vp; int error; - struct nameidata nd; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ, - UIO_USERSPACE, SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), uap->sysmsg_fds); - vput(nd.ni_vp); + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + nlookup_done(&nd); + if (error == 0) { + error = VOP_PATHCONF(vp, SCARG(uap, name), uap->sysmsg_fds); + vput(vp); + } return (error); } @@ -1927,7 +1833,7 @@ pathconf(struct pathconf_args *uap) * in VOP_READLINK(). */ int -kern_readlink(struct nameidata *nd, char *buf, int count, int *res) +kern_readlink(struct nlookupdata *nd, char *buf, int count, int *res) { struct thread *td = curthread; struct proc *p = td->td_proc; @@ -1936,14 +1842,14 @@ kern_readlink(struct nameidata *nd, char *buf, int count, int *res) struct uio auio; int error; - error = namei(nd); + if ((error = nlookup(nd)) != 0) + return (error); + error = cache_vget(nd->nl_ncp, nd->nl_cred, LK_EXCLUSIVE, &vp); if (error) return (error); - NDFREE(nd, NDF_ONLY_PNBUF); - vp = nd->ni_vp; - if (vp->v_type != VLNK) + if (vp->v_type != VLNK) { error = EINVAL; - else { + } else { aiov.iov_base = buf; aiov.iov_len = count; auio.uio_iov = &aiov; @@ -1968,16 +1874,15 @@ kern_readlink(struct nameidata *nd, char *buf, int count, int *res) int readlink(struct readlink_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_NOOBJ, UIO_USERSPACE, - uap->path, td); - - error = kern_readlink(&nd, uap->buf, uap->count, - &uap->sysmsg_result); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) { + error = kern_readlink(&nd, uap->buf, uap->count, + &uap->sysmsg_result); + } + nlookup_done(&nd); return (error); } @@ -2017,18 +1922,23 @@ setfflags(struct vnode *vp, int flags) int chflags(struct chflags_args *uap) { - struct thread *td = curthread; + struct nlookupdata nd; + struct vnode *vp; int error; - struct nameidata nd; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, - SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfflags(nd.ni_vp, SCARG(uap, flags)); - vrele(nd.ni_vp); - return error; + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + /* XXX Add NLC flag indicating modifying operation? */ + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + nlookup_done(&nd); + if (error == 0) { + error = setfflags(vp, SCARG(uap, flags)); + vrele(vp); + } + return (error); } /* @@ -2068,17 +1978,19 @@ setfmode(struct vnode *vp, int mode) } int -kern_chmod(struct nameidata *nd, int mode) +kern_chmod(struct nlookupdata *nd, int mode) { + struct vnode *vp; int error; - error = namei(nd); - if (error) + /* XXX Add NLC flag indicating modifying operation? */ + if ((error = nlookup(nd)) != 0) return (error); - NDFREE(nd, NDF_ONLY_PNBUF); - error = setfmode(nd->ni_vp, mode); - vrele(nd->ni_vp); - return error; + if ((error = cache_vref(nd->nl_ncp, nd->nl_cred, &vp)) != 0) + return (error); + error = setfmode(vp, mode); + vrele(vp); + return (error); } /* @@ -2090,14 +2002,13 @@ kern_chmod(struct nameidata *nd, int mode) int chmod(struct chmod_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td); - - error = kern_chmod(&nd, uap->mode); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_chmod(&nd, uap->mode); + nlookup_done(&nd); return (error); } @@ -2110,17 +2021,14 @@ chmod(struct chmod_args *uap) int lchmod(struct lchmod_args *uap) { - struct thread *td = curthread; + struct nlookupdata nd; int error; - struct nameidata nd; - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfmode(nd.ni_vp, SCARG(uap, mode)); - vrele(nd.ni_vp); - return error; + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) + error = kern_chmod(&nd, uap->mode); + nlookup_done(&nd); + return (error); } /* @@ -2161,16 +2069,18 @@ setfown(struct vnode *vp, uid_t uid, gid_t gid) } int -kern_chown(struct nameidata *nd, int uid, int gid) +kern_chown(struct nlookupdata *nd, int uid, int gid) { + struct vnode *vp; int error; - error = namei(nd); - if (error) + /* XXX Add NLC flag indicating modifying operation? */ + if ((error = nlookup(nd)) != 0) return (error); - NDFREE(nd, NDF_ONLY_PNBUF); - error = setfown(nd->ni_vp, uid, gid); - vrele(nd->ni_vp); + if ((error = cache_vref(nd->nl_ncp, nd->nl_cred, &vp)) != 0) + return (error); + error = setfown(vp, uid, gid); + vrele(vp); return (error); } @@ -2182,14 +2092,13 @@ kern_chown(struct nameidata *nd, int uid, int gid) int chown(struct chown_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td); - - error = kern_chown(&nd, uap->uid, uap->gid); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_chown(&nd, uap->uid, uap->gid); + nlookup_done(&nd); return (error); } @@ -2201,14 +2110,13 @@ chown(struct chown_args *uap) int lchown(struct lchown_args *uap) { - struct thread *td = curthread; + struct nlookupdata nd; int error; - struct nameidata nd; - - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, uap->path, td); - - error = kern_chown(&nd, uap->uid, uap->gid); + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) + error = kern_chown(&nd, uap->uid, uap->gid); + nlookup_done(&nd); return (error); } @@ -2269,20 +2177,21 @@ setutimes(struct vnode *vp, const struct timespec *ts, int nullflag) } int -kern_utimes(struct nameidata *nd, struct timeval *tptr) +kern_utimes(struct nlookupdata *nd, struct timeval *tptr) { struct timespec ts[2]; + struct vnode *vp; int error; - error = getutimes(tptr, ts); - if (error) + if ((error = getutimes(tptr, ts)) != 0) return (error); - error = namei(nd); - if (error) + /* XXX Add NLC flag indicating modifying operation? */ + if ((error = nlookup(nd)) != 0) return (error); - NDFREE(nd, NDF_ONLY_PNBUF); - error = setutimes(nd->ni_vp, ts, tptr == NULL); - vrele(nd->ni_vp); + if ((error = cache_vref(nd->nl_ncp, nd->nl_cred, &vp)) != 0) + return (error); + error = setutimes(vp, ts, tptr == NULL); + vrele(vp); return (error); } @@ -2294,9 +2203,8 @@ kern_utimes(struct nameidata *nd, struct timeval *tptr) int utimes(struct utimes_args *uap) { - struct thread *td = curthread; struct timeval tv[2]; - struct nameidata nd; + struct nlookupdata nd; int error; if (uap->tptr) { @@ -2304,10 +2212,10 @@ utimes(struct utimes_args *uap) if (error) return (error); } - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td); - - error = kern_utimes(&nd, uap->tptr ? tv : NULL); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_utimes(&nd, uap->tptr ? tv : NULL); + nlookup_done(&nd); return (error); } @@ -2319,9 +2227,8 @@ utimes(struct utimes_args *uap) int lutimes(struct lutimes_args *uap) { - struct thread *td = curthread; struct timeval tv[2]; - struct nameidata nd; + struct nlookupdata nd; int error; if (uap->tptr) { @@ -2329,10 +2236,10 @@ lutimes(struct lutimes_args *uap) if (error) return (error); } - NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, uap->path, td); - - error = kern_utimes(&nd, uap->tptr ? tv : NULL); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) + error = kern_utimes(&nd, uap->tptr ? tv : NULL); + nlookup_done(&nd); return (error); } @@ -2378,29 +2285,31 @@ futimes(struct futimes_args *uap) } int -kern_truncate(struct nameidata* nd, off_t length) +kern_truncate(struct nlookupdata *nd, off_t length) { - struct thread *td = curthread; - struct proc *p = td->td_proc; struct vnode *vp; struct vattr vattr; int error; if (length < 0) return(EINVAL); - if ((error = namei(nd)) != 0) + /* XXX Add NLC flag indicating modifying operation? */ + if ((error = nlookup(nd)) != 0) return (error); - vp = nd->ni_vp; - NDFREE(nd, NDF_ONLY_PNBUF); - VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - if (vp->v_type == VDIR) + if ((error = cache_vref(nd->nl_ncp, nd->nl_cred, &vp)) != 0) + return (error); + VOP_LEASE(vp, nd->nl_td, nd->nl_cred, LEASE_WRITE); + if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, nd->nl_td)) != 0) { + vrele(vp); + return (error); + } + if (vp->v_type == VDIR) { error = EISDIR; - else if ((error = vn_writechk(vp)) == 0 && - (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, td)) == 0) { + } else if ((error = vn_writechk(vp)) == 0 && + (error = VOP_ACCESS(vp, VWRITE, nd->nl_cred, nd->nl_td)) == 0) { VATTR_NULL(&vattr); vattr.va_size = length; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, td); + error = VOP_SETATTR(vp, &vattr, nd->nl_cred, nd->nl_td); } vput(vp); return (error); @@ -2414,14 +2323,13 @@ kern_truncate(struct nameidata* nd, off_t length) int truncate(struct truncate_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td); - - error = kern_truncate(&nd, uap->length); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = kern_truncate(&nd, uap->length); + nlookup_done(&nd); return error; } @@ -2501,87 +2409,126 @@ fsync(struct fsync_args *uap) } int -kern_rename(struct nameidata *fromnd, struct nameidata *tond) +kern_rename(struct nlookupdata *fromnd, struct nlookupdata *tond) { - struct thread *td = curthread; - struct proc *p = td->td_proc; - struct vnode *tvp, *fvp, *tdvp; + struct namecache *fncpd; + struct namecache *tncpd; + struct namecache *ncp; + struct mount *mp; int error; bwillwrite(); - error = namei(fromnd); - if (error) + if ((error = nlookup(fromnd)) != 0) return (error); - fvp = fromnd->ni_vp; - if (fromnd->ni_vp->v_type == VDIR) - tond->ni_cnd.cn_flags |= CNP_WILLBEDIR; - error = namei(tond); - if (error) { - /* Translate error code for rename("dir1", "dir2/."). */ - if (error == EISDIR && fvp->v_type == VDIR) - error = EINVAL; - NDFREE(fromnd, NDF_ONLY_PNBUF); - vrele(fromnd->ni_dvp); - vrele(fvp); - goto out1; - } - tdvp = tond->ni_dvp; - tvp = tond->ni_vp; - if (tvp != NULL) { - if (fvp->v_type == VDIR && tvp->v_type != VDIR) { - error = ENOTDIR; - goto out; - } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { + if ((fncpd = fromnd->nl_ncp->nc_parent) == NULL) + return (ENOENT); + cache_hold(fncpd); + + /* + * unlock the source ncp so we can lookup the target ncp without + * deadlocking. The target may or may not exist so we do not check + * for a target vp like kern_mkdir() and other creation functions do. + * + * The source and target directories are ref'd and rechecked after + * everything is relocked to determine if the source or target file + * has been renamed. + */ + KKASSERT(fromnd->nl_flags & NLC_NCPISLOCKED); + fromnd->nl_flags &= ~NLC_NCPISLOCKED; + cache_unlock(fromnd->nl_ncp); + + tond->nl_flags |= NLC_CREATE; + if ((error = nlookup(tond)) != 0) { + cache_drop(fncpd); + return (error); + } + if ((tncpd = tond->nl_ncp->nc_parent) == NULL) { + cache_drop(fncpd); + return (ENOENT); + } + cache_hold(tncpd); + + /* + * If the source and target are the same there is nothing to do + */ + if (fromnd->nl_ncp == tond->nl_ncp) { + cache_drop(fncpd); + cache_drop(tncpd); + return (0); + } + + /* + * relock the source ncp + */ + if (cache_lock_nonblock(fromnd->nl_ncp) == 0) { + cache_resolve(fromnd->nl_ncp, fromnd->nl_cred); + } else if (fromnd->nl_ncp > tond->nl_ncp) { + cache_lock(fromnd->nl_ncp); + cache_resolve(fromnd->nl_ncp, fromnd->nl_cred); + } else { + cache_unlock(tond->nl_ncp); + cache_lock(fromnd->nl_ncp); + cache_resolve(fromnd->nl_ncp, fromnd->nl_cred); + cache_lock(tond->nl_ncp); + cache_resolve(tond->nl_ncp, tond->nl_cred); + } + fromnd->nl_flags |= NLC_NCPISLOCKED; + + /* + * make sure the parent directories linkages are the same + */ + if (fncpd != fromnd->nl_ncp->nc_parent || + tncpd != tond->nl_ncp->nc_parent) { + cache_drop(fncpd); + cache_drop(tncpd); + return (ENOENT); + } + + /* + * Both the source and target must be within the same filesystem and + * in the same filesystem as their parent directories within the + * namecache topology. + */ + mp = fncpd->nc_mount; + if (mp != tncpd->nc_mount || mp != fromnd->nl_ncp->nc_mount || + mp != tond->nl_ncp->nc_mount) { + cache_drop(fncpd); + cache_drop(tncpd); + return (EXDEV); + } + + /* + * If the target exists and either the source or target is a directory, + * then both must be directories. + */ + if (tond->nl_ncp->nc_vp) { + if (fromnd->nl_ncp->nc_vp->v_type == VDIR) { + if (tond->nl_ncp->nc_vp->v_type != VDIR) + error = ENOTDIR; + } else if (tond->nl_ncp->nc_vp->v_type == VDIR) { error = EISDIR; - goto out; } } - if (fvp == tdvp) - error = EINVAL; + /* - * If the source is the same as the destination (that is, if they - * are links to the same vnode), then there is nothing to do. + * You cannot rename a source into itself or a subdirectory of itself. + * We check this by travsersing the target directory upwards looking + * for a match against the source. */ - if (fvp == tvp) - error = -1; -out: - if (!error) { - VOP_LEASE(tdvp, td, p->p_ucred, LEASE_WRITE); - if (fromnd->ni_dvp != tdvp) { - VOP_LEASE(fromnd->ni_dvp, td, p->p_ucred, LEASE_WRITE); - } - if (tvp) { - VOP_LEASE(tvp, td, p->p_ucred, LEASE_WRITE); + if (error == 0) { + for (ncp = tncpd; ncp; ncp = ncp->nc_parent) { + if (fromnd->nl_ncp == ncp) { + error = EINVAL; + break; + } } - error = VOP_RENAME(fromnd->ni_dvp, NCPNULL, fromnd->ni_vp, - &fromnd->ni_cnd, tond->ni_dvp, NCPNULL, tond->ni_vp, - &tond->ni_cnd); - if (error == 0) - cache_purge(fromnd->ni_vp); - NDFREE(fromnd, NDF_ONLY_PNBUF); - NDFREE(tond, NDF_ONLY_PNBUF); - } else { - NDFREE(fromnd, NDF_ONLY_PNBUF); - NDFREE(tond, NDF_ONLY_PNBUF); - if (tdvp == tvp) - vrele(tdvp); - else - vput(tdvp); - if (tvp) - vput(tvp); - vrele(fromnd->ni_dvp); - vrele(fvp); - } - vrele(tond->ni_startdir); - ASSERT_VOP_UNLOCKED(fromnd->ni_dvp, "rename"); - ASSERT_VOP_UNLOCKED(fromnd->ni_vp, "rename"); - ASSERT_VOP_UNLOCKED(tond->ni_dvp, "rename"); - ASSERT_VOP_UNLOCKED(tond->ni_vp, "rename"); -out1: - if (fromnd->ni_startdir) - vrele(fromnd->ni_startdir); - if (error == -1) - return (0); + } + + cache_drop(fncpd); + cache_drop(tncpd); + if (error) + return (error); + error = VOP_NRENAME(fromnd->nl_ncp, tond->nl_ncp, tond->nl_cred); return (error); } @@ -2594,58 +2541,47 @@ out1: int rename(struct rename_args *uap) { - struct thread *td = curthread; - struct nameidata fromnd, tond; + struct nlookupdata fromnd, tond; int error; - NDINIT(&fromnd, NAMEI_DELETE, CNP_WANTPARENT | CNP_SAVESTART, - UIO_USERSPACE, uap->from, td); - NDINIT(&tond, NAMEI_RENAME, - CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_NOCACHE | - CNP_SAVESTART | CNP_NOOBJ, - UIO_USERSPACE, uap->to, td); - - error = kern_rename(&fromnd, &tond); - + error = nlookup_init(&fromnd, uap->from, UIO_USERSPACE, 0); + if (error == 0) { + error = nlookup_init(&tond, uap->to, UIO_USERSPACE, 0); + if (error == 0) + error = kern_rename(&fromnd, &tond); + nlookup_done(&tond); + } + nlookup_done(&fromnd); return (error); } int -kern_mkdir(struct nameidata *nd, int mode) +kern_mkdir(struct nlookupdata *nd, int mode) { struct thread *td = curthread; struct proc *p = td->td_proc; + struct namecache *ncp; struct vnode *vp; struct vattr vattr; int error; bwillwrite(); - nd->ni_cnd.cn_flags |= CNP_WILLBEDIR; - error = namei(nd); - if (error) + nd->nl_flags |= NLC_WILLBEDIR | NLC_CREATE; + if ((error = nlookup(nd)) != 0) return (error); - vp = nd->ni_vp; - if (vp) { - NDFREE(nd, NDF_ONLY_PNBUF); - if (nd->ni_dvp == vp) - vrele(nd->ni_dvp); - else - vput(nd->ni_dvp); - vrele(vp); + + ncp = nd->nl_ncp; + if (ncp->nc_vp) return (EEXIST); - } + VATTR_NULL(&vattr); vattr.va_type = VDIR; vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; - VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE); - error = VOP_MKDIR(nd->ni_dvp, NCPNULL, &nd->ni_vp, &nd->ni_cnd, - &vattr); - NDFREE(nd, NDF_ONLY_PNBUF); - vput(nd->ni_dvp); + + vp = NULL; + error = VOP_NMKDIR(ncp, &vp, p->p_ucred, &vattr); if (error == 0) - vput(nd->ni_vp); - ASSERT_VOP_UNLOCKED(nd->ni_dvp, "mkdir"); - ASSERT_VOP_UNLOCKED(nd->ni_vp, "mkdir"); + vput(vp); return (error); } @@ -2658,65 +2594,29 @@ kern_mkdir(struct nameidata *nd, int mode) int mkdir(struct mkdir_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_USERSPACE, uap->path, - td); - - error = kern_mkdir(&nd, uap->mode); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) + error = kern_mkdir(&nd, uap->mode); + nlookup_done(&nd); return (error); } int -kern_rmdir(struct nameidata *nd) +kern_rmdir(struct nlookupdata *nd) { - struct thread *td = curthread; - struct proc *p = td->td_proc; - struct vnode *vp; + struct namecache *ncp; int error; bwillwrite(); - error = namei(nd); - if (error) + nd->nl_flags |= NLC_DELETE; + if ((error = nlookup(nd)) != 0) return (error); - vp = nd->ni_vp; - if (vp->v_type != VDIR) { - error = ENOTDIR; - goto out; - } - /* - * No rmdir "." please. - */ - if (nd->ni_dvp == vp) { - error = EINVAL; - goto out; - } - /* - * The root of a mounted filesystem cannot be deleted. - */ - if (vp->v_flag & VROOT) - error = EBUSY; - else { - VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE); - VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE); - error = VOP_RMDIR(nd->ni_dvp, NCPNULL, nd->ni_vp, - &nd->ni_cnd); - if (error == 0) - cache_purge(vp); - } -out: - NDFREE(nd, NDF_ONLY_PNBUF); - if (nd->ni_dvp == vp) - vrele(nd->ni_dvp); - else - vput(nd->ni_dvp); - if (vp != NULLVP) - vput(vp); - ASSERT_VOP_UNLOCKED(nd->ni_dvp, "rmdir"); - ASSERT_VOP_UNLOCKED(nd->ni_vp, "rmdir"); + + ncp = nd->nl_ncp; + error = VOP_NRMDIR(ncp, nd->nl_cred); return (error); } @@ -2729,15 +2629,13 @@ out: int rmdir(struct rmdir_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; int error; - NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT | CNP_LOCKLEAF, - UIO_USERSPACE, uap->path, td); - - error = kern_rmdir(&nd); - + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error == 0) + error = kern_rmdir(&nd); + nlookup_done(&nd); return (error); } @@ -2867,34 +2765,36 @@ int revoke(struct revoke_args *uap) { struct thread *td = curthread; - struct proc *p = td->td_proc; - struct vnode *vp; + struct nlookupdata nd; struct vattr vattr; + struct vnode *vp; + struct ucred *cred; int error; - struct nameidata nd; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - if (vp->v_type != VCHR && vp->v_type != VBLK) { - error = EINVAL; - goto out; - } - if ((error = VOP_GETATTR(vp, &vattr, td)) != 0) - goto out; - if (p->p_ucred->cr_uid != vattr.va_uid && - (error = suser_cred(p->p_ucred, PRISON_ROOT))) - goto out; - if (count_udev(vp->v_udev) > 0) { - if ((error = vx_lock(vp)) == 0) { - VOP_REVOKE(vp, REVOKEALL); - vx_unlock(vp); + vp = NULL; + error = nlookup_init(&nd, SCARG(uap, path), UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + cred = crhold(nd.nl_cred); + nlookup_done(&nd); + if (error == 0) { + if (vp->v_type != VCHR && vp->v_type != VBLK) + error = EINVAL; + if (error == 0) + error = VOP_GETATTR(vp, &vattr, td); + if (error == 0 && cred->cr_uid != vattr.va_uid) + error = suser_cred(cred, PRISON_ROOT); + if (error == 0 && count_udev(vp->v_udev) > 0) { + if ((error = vx_lock(vp)) == 0) { + VOP_REVOKE(vp, REVOKEALL); + vx_unlock(vp); + } } + vrele(vp); } -out: - vrele(vp); + crfree(cred); return (error); } @@ -2923,7 +2823,7 @@ int getfh(struct getfh_args *uap) { struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; fhandle_t fh; struct vnode *vp; int error; @@ -2931,22 +2831,24 @@ getfh(struct getfh_args *uap) /* * Must be super user */ - error = suser(td); - if (error) + if ((error = suser(td)) != 0) return (error); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE, uap->fname, td); - error = namei(&nd); - if (error) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - bzero(&fh, sizeof(fh)); - fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(vp, &fh.fh_fid); - vput(vp); - if (error) - return (error); - error = copyout(&fh, uap->fhp, sizeof (fh)); + + vp = NULL; + error = nlookup_init(&nd, uap->fname, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + nlookup_done(&nd); + if (error == 0) { + bzero(&fh, sizeof(fh)); + fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(vp, &fh.fh_fid); + vput(vp); + if (error == 0) + error = copyout(&fh, uap->fhp, sizeof(fh)); + } return (error); } @@ -2970,10 +2872,10 @@ fhopen(struct fhopen_args *uap) struct vattr vat; struct vattr *vap = &vat; struct flock lf; - struct file *fp; struct filedesc *fdp = p->p_fd; int fmode, mode, error, type; struct file *nfp; + struct file *fp; int indx; /* @@ -3044,39 +2946,65 @@ fhopen(struct fhopen_args *uap) if (error) goto bad; } - error = VOP_OPEN(vp, fmode, p->p_ucred, td); - if (error) - goto bad; + /* - * Make sure that a VM object is created for VMIO support. + * VOP_OPEN needs the file pointer so it can potentially override + * it. + * + * WARNING! no f_ncp will be associated when fhopen()ing a directory. + * XXX */ - if (vn_canvmio(vp) == TRUE) { - if ((error = vfs_object_create(vp, td)) != 0) - goto bad; + if ((error = falloc(p, &nfp, NULL)) != 0) + goto bad; + fp = nfp; + + fp->f_data = (caddr_t)vp; + fp->f_flag = fmode & FMASK; + fp->f_ops = &vnode_fileops; + fp->f_type = DTYPE_VNODE; + + error = VOP_OPEN(vp, fmode, p->p_ucred, fp, td); + if (error) { + /* + * setting f_ops this way prevents VOP_CLOSE from being + * called or fdrop() releasing the vp from v_data. Since + * the VOP_OPEN failed we don't want to VOP_CLOSE. + */ + fp->f_ops = &badfileops; + fp->f_data = NULL; + fdrop(fp, td); + goto bad; } if (fmode & FWRITE) vp->v_writecount++; /* - * end of vn_open code + * The fp now owns a reference on the vnode. We still have our own + * ref+lock. + */ + vref(vp); + + /* + * Make sure that a VM object is created for VMIO support. If this + * fails just fdrop() normally to clean up. */ + if (vn_canvmio(vp) == TRUE) { + if ((error = vfs_object_create(vp, td)) != 0) { + fdrop(fp, td); + goto bad; + } + } - if ((error = falloc(p, &nfp, &indx)) != 0) { + /* + * The open was successful, associate it with a file descriptor. + */ + if ((error = fsetfd(p, fp, &indx)) != 0) { if (fmode & FWRITE) vp->v_writecount--; + fdrop(fp, td); goto bad; } - fp = nfp; - /* - * hold an extra reference to avoid having fp ripped out - * from under us while we block in the lock op. - */ - fhold(fp); - nfp->f_data = (caddr_t)vp; - nfp->f_flag = fmode & FMASK; - nfp->f_ops = &vnops; - nfp->f_type = DTYPE_VNODE; if (fmode & (O_EXLOCK | O_SHLOCK)) { lf.l_whence = SEEK_SET; lf.l_start = 0; @@ -3104,6 +3032,7 @@ fhopen(struct fhopen_args *uap) * release our private reference. */ fdrop(fp, td); + vrele(vp); return (error); } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); @@ -3112,7 +3041,7 @@ fhopen(struct fhopen_args *uap) if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0)) vfs_object_create(vp, td); - VOP_UNLOCK(vp, 0, td); + vput(vp); fdrop(fp, td); uap->sysmsg_result = indx; return (0); @@ -3213,18 +3142,23 @@ fhstatfs(struct fhstatfs_args *uap) int extattrctl(struct extattrctl_args *uap) { - struct thread *td = curthread; - struct nameidata nd; + struct nlookupdata nd; struct mount *mp; + struct vnode *vp; int error; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return (error); - mp = nd.ni_vp->v_mount; - NDFREE(&nd, 0); - return (VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname), - SCARG(uap, arg), td)); + vp = NULL; + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) { + mp = nd.nl_ncp->nc_mount; + error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), + SCARG(uap, attrname), SCARG(uap, arg), + nd.nl_td); + } + nlookup_done(&nd); + return (error); } /* @@ -3236,22 +3170,34 @@ extattrctl(struct extattrctl_args *uap) int extattr_set_file(struct extattr_set_file_args *uap) { - struct thread *td = curthread; - struct proc *p = td->td_proc; - struct nameidata nd; - struct uio auio; - struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; char attrname[EXTATTR_MAXNAMELEN]; - u_int iovlen, cnt; - int error, i; + struct iovec aiov[UIO_SMALLIOV]; + struct iovec *needfree; + struct nlookupdata nd; + struct iovec *iov; + struct vnode *vp; + struct uio auio; + u_int iovlen; + u_int cnt; + int error; + int i; error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); if (error) return (error); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return(error); + + vp = NULL; + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + if (error) { + nlookup_done(&nd); + return (error); + } + + needfree = NULL; iovlen = uap->iovcnt * sizeof(struct iovec); if (uap->iovcnt > UIO_SMALLIOV) { if (uap->iovcnt > UIO_MAXIOV) { @@ -3260,13 +3206,14 @@ extattr_set_file(struct extattr_set_file_args *uap) } MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); needfree = iov; - } else + } else { iov = aiov; + } auio.uio_iov = iov; auio.uio_iovcnt = uap->iovcnt; auio.uio_rw = UIO_WRITE; auio.uio_segflg = UIO_USERSPACE; - auio.uio_td = td; + auio.uio_td = nd.nl_td; auio.uio_offset = 0; if ((error = copyin(uap->iovp, iov, iovlen))) goto done; @@ -3280,13 +3227,14 @@ extattr_set_file(struct extattr_set_file_args *uap) iov++; } cnt = auio.uio_resid; - error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_ucred, td); + error = VOP_SETEXTATTR(vp, attrname, &auio, nd.nl_cred, nd.nl_td); cnt -= auio.uio_resid; uap->sysmsg_result = cnt; done: + vput(vp); + nlookup_done(&nd); if (needfree) FREE(needfree, M_IOV); - NDFREE(&nd, 0); return (error); } @@ -3299,39 +3247,50 @@ done: int extattr_get_file(struct extattr_get_file_args *uap) { - struct thread *td = curthread; - struct proc *p = td->td_proc; - struct nameidata nd; - struct uio auio; - struct iovec *iov, *needfree, aiov[UIO_SMALLIOV]; char attrname[EXTATTR_MAXNAMELEN]; - u_int iovlen, cnt; - int error, i; + struct iovec aiov[UIO_SMALLIOV]; + struct iovec *needfree; + struct nlookupdata nd; + struct iovec *iov; + struct vnode *vp; + struct uio auio; + u_int iovlen; + u_int cnt; + int error; + int i; error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); if (error) return (error); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) + + vp = NULL; + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + if (error) { + nlookup_done(&nd); return (error); + } + iovlen = uap->iovcnt * sizeof (struct iovec); + needfree = NULL; if (uap->iovcnt > UIO_SMALLIOV) { if (uap->iovcnt > UIO_MAXIOV) { - NDFREE(&nd, 0); - return (EINVAL); + error = EINVAL; + goto done; } MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); needfree = iov; } else { iov = aiov; - needfree = NULL; } auio.uio_iov = iov; auio.uio_iovcnt = uap->iovcnt; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_USERSPACE; - auio.uio_td = td; + auio.uio_td = nd.nl_td; auio.uio_offset = 0; if ((error = copyin(uap->iovp, iov, iovlen))) goto done; @@ -3345,13 +3304,14 @@ extattr_get_file(struct extattr_get_file_args *uap) iov++; } cnt = auio.uio_resid; - error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_ucred, td); + error = VOP_GETEXTATTR(vp, attrname, &auio, nd.nl_cred, nd.nl_td); cnt -= auio.uio_resid; uap->sysmsg_result = cnt; done: + vput(vp); + nlookup_done(&nd); if (needfree) FREE(needfree, M_IOV); - NDFREE(&nd, 0); return(error); } @@ -3362,21 +3322,29 @@ done: int extattr_delete_file(struct extattr_delete_file_args *uap) { - struct thread *td = curthread; - struct proc *p = td->td_proc; - struct nameidata nd; char attrname[EXTATTR_MAXNAMELEN]; - int error; + struct nlookupdata nd; + struct vnode *vp; + int error; error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); if (error) return(error); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), td); - if ((error = namei(&nd)) != 0) - return(error); - error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_ucred, td); - NDFREE(&nd, 0); + + vp = NULL; + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + if (error) { + nlookup_done(&nd); + return (error); + } + + error = VOP_SETEXTATTR(vp, attrname, NULL, nd.nl_cred, nd.nl_td); + vput(vp); + nlookup_done(&nd); return(error); } diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index cfe6347f01..0a14a7e70a 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -37,7 +37,7 @@ * * @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/vfs_vnops.c,v 1.87.2.13 2002/12/29 18:19:53 dillon Exp $ - * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.24 2004/11/05 18:43:20 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.25 2004/11/12 00:09:24 dillon Exp $ */ #include @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include @@ -60,89 +60,144 @@ static int vn_ioctl (struct file *fp, u_long com, caddr_t data, struct thread *td); static int vn_read (struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td); +static int svn_read (struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct thread *td); static int vn_poll (struct file *fp, int events, struct ucred *cred, struct thread *td); static int vn_kqfilter (struct file *fp, struct knote *kn); static int vn_statfile (struct file *fp, struct stat *sb, struct thread *td); static int vn_write (struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td); +static int svn_write (struct file *fp, struct uio *uio, + struct ucred *cred, int flags, struct thread *td); -struct fileops vnops = { +struct fileops vnode_fileops = { NULL, /* port */ NULL, /* clone */ vn_read, vn_write, vn_ioctl, vn_poll, vn_kqfilter, vn_statfile, vn_closefile }; +struct fileops specvnode_fileops = { + NULL, /* port */ + NULL, /* clone */ + svn_read, svn_write, vn_ioctl, vn_poll, vn_kqfilter, + vn_statfile, vn_closefile +}; + /* - * Common code for vnode open operations. - * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. - * - * Note that this does NOT free nameidata for the successful case, - * due to the NDINIT being done elsewhere. + * Shortcut the device read/write. This avoids a lot of vnode junk. + * Basically the specfs vnops for read and write take the locked vnode, + * unlock it (because we can't hold the vnode locked while reading or writing + * a device which may block indefinitely), issues the device operation, then + * relock the vnode before returning, plus other junk. This bypasses all + * of that and just does the device operation. + */ +void +vn_setspecops(struct file *fp) +{ + if (vfs_fastdev && fp->f_ops == &vnode_fileops) { + fp->f_ops = &specvnode_fileops; + } +} + +/* + * Common code for vnode open operations. Check permissions, and call + * the VOP_NOPEN or VOP_NCREATE routine. + * + * The caller is responsible for setting up nd with nlookup_init() and + * for cleaning it up with nlookup_done(), whether we return an error + * or not. + * + * On success nd->nl_open_vp will hold a referenced and, if requested, + * locked vnode. A locked vnode is requested via NLC_LOCKVP. If fp + * is non-NULL the vnode will be installed in the file pointer. + * + * NOTE: The vnode is referenced just once on return whether or not it + * is also installed in the file pointer. */ int -vn_open(ndp, fmode, cmode) - struct nameidata *ndp; - int fmode, cmode; +vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode) { struct vnode *vp; - struct thread *td = ndp->ni_cnd.cn_td; - struct ucred *cred = ndp->ni_cnd.cn_cred; + struct thread *td = nd->nl_td; + struct ucred *cred = nd->nl_cred; struct vattr vat; struct vattr *vap = &vat; + struct namecache *ncp; int mode, error; + /* + * Lookup the path and create or obtain the vnode. After a + * successful lookup a locked nd->nl_ncp will be returned. + * + * The result of this section should be a locked vnode. + * + * XXX with only a little work we should be able to avoid locking + * the vnode if FWRITE, O_CREAT, and O_TRUNC are *not* set. + */ if (fmode & O_CREAT) { - ndp->ni_cnd.cn_nameiop = NAMEI_CREATE; - ndp->ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_LOCKLEAF; + /* + * CONDITIONAL CREATE FILE CASE + * + * Setting NLC_CREATE causes a negative hit to store + * the negative hit ncp and not return an error. Then + * nc_error or nc_vp may be checked to see if the ncp + * represents a negative hit. NLC_CREATE also requires + * write permission on the governing directory or EPERM + * is returned. + */ if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0) - ndp->ni_cnd.cn_flags |= CNP_FOLLOW; + nd->nl_flags |= NLC_FOLLOW; + nd->nl_flags |= NLC_CREATE; bwillwrite(); - error = namei(ndp); + error = nlookup(nd); if (error) return (error); - if (ndp->ni_vp == NULL) { + + ncp = nd->nl_ncp; + + if (ncp->nc_vp == NULL) { VATTR_NULL(vap); vap->va_type = VREG; vap->va_mode = cmode; if (fmode & O_EXCL) vap->va_vaflags |= VA_EXCLUSIVE; - VOP_LEASE(ndp->ni_dvp, td, cred, LEASE_WRITE); - error = VOP_CREATE(ndp->ni_dvp, NCPNULL, &ndp->ni_vp, - &ndp->ni_cnd, vap); - if (error) { - NDFREE(ndp, NDF_ONLY_PNBUF); - vput(ndp->ni_dvp); + error = VOP_NCREATE(ncp, &vp, nd->nl_cred, vap); + if (error) return (error); - } - vput(ndp->ni_dvp); - ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "create"); - ASSERT_VOP_LOCKED(ndp->ni_vp, "create"); fmode &= ~O_TRUNC; - vp = ndp->ni_vp; + ASSERT_VOP_LOCKED(vp, "create"); + /* locked vnode is returned */ } else { - if (ndp->ni_dvp == ndp->ni_vp) - vrele(ndp->ni_dvp); - else - vput(ndp->ni_dvp); - ndp->ni_dvp = NULL; - vp = ndp->ni_vp; if (fmode & O_EXCL) { error = EEXIST; - goto bad; + } else { + error = cache_vget(ncp, cred, + LK_EXCLUSIVE, &vp); } + if (error) + return (error); fmode &= ~O_CREAT; } } else { - ndp->ni_cnd.cn_nameiop = NAMEI_LOOKUP; - ndp->ni_cnd.cn_flags = CNP_LOCKLEAF | - ((fmode & O_NOFOLLOW) ? 0 : CNP_FOLLOW); - error = namei(ndp); + /* + * NORMAL OPEN FILE CASE + */ + error = nlookup(nd); + if (error) + return (error); + + ncp = nd->nl_ncp; + + error = cache_vget(ncp, cred, LK_EXCLUSIVE, &vp); if (error) return (error); - vp = ndp->ni_vp; } + + /* + * We have a locked vnode now. + */ if (vp->v_type == VLNK) { error = EMLINK; goto bad; @@ -181,22 +236,79 @@ vn_open(ndp, fmode, cmode) if (error) goto bad; } - error = VOP_OPEN(vp, fmode, cred, td); - if (error) + + /* + * Setup the fp so VOP_OPEN can override it. No descriptor has been + * associated with the fp yet so we own it clean. f_data will inherit + * our vp reference as long as we do not shift f_ops to &badfileops. + * f_ncp inherits nl_ncp . + */ + if (fp) { + fp->f_data = (caddr_t)vp; + fp->f_flag = fmode & FMASK; + fp->f_ops = &vnode_fileops; + fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); + if (vp->v_type == VDIR) { + fp->f_ncp = nd->nl_ncp; + nd->nl_ncp = NULL; + cache_unlock(fp->f_ncp); + } + } + + /* + * Get rid of nl_ncp. vn_open does not return it (it returns the + * vnode or the file pointer). Note: we can't leave nl_ncp locked + * through the VOP_OPEN anyway since the VOP_OPEN may block, e.g. + * on /dev/ttyd0 + */ + if (nd->nl_ncp) { + cache_put(nd->nl_ncp); + nd->nl_ncp = NULL; + } + + error = VOP_OPEN(vp, fmode, cred, fp, td); + if (error) { + /* + * setting f_ops to &badfileops will prevent the descriptor + * code from trying to close and release the vnode, since + * the open failed we do not want to call close. + */ + fp->f_data = NULL; + fp->f_ops = &badfileops; goto bad; + } + if (fmode & FWRITE) + vp->v_writecount++; + /* - * Make sure that a VM object is created for VMIO support. + * Make sure that a VM object is created for VMIO support. If this + * fails we have to be sure to match VOP_CLOSE's with VOP_OPEN's. + * Cleanup the fp so we can just vput() the vp in 'bad'. */ if (vn_canvmio(vp) == TRUE) { - if ((error = vfs_object_create(vp, td)) != 0) + if ((error = vfs_object_create(vp, td)) != 0) { + fp->f_data = NULL; + fp->f_ops = &badfileops; + VOP_CLOSE(vp, fmode, td); goto bad; + } } - if (fmode & FWRITE) - vp->v_writecount++; + /* + * Return the vnode. XXX needs some cleaning up. The vnode is + * only returned in the fp == NULL case, otherwise the vnode ref + * is inherited by the fp and we unconditionally unlock it. + */ + if (fp == NULL) { + nd->nl_open_vp = vp; + nd->nl_vp_fmode = fmode; + if ((nd->nl_flags & NLC_LOCKVP) == 0) + VOP_UNLOCK(vp, 0, td); + } else { + VOP_UNLOCK(vp, 0, td); + } return (0); bad: - NDFREE(ndp, NDF_ONLY_PNBUF); vput(vp); return (error); } @@ -408,6 +520,56 @@ vn_read(fp, uio, cred, flags, td) return (error); } +/* + * Device-optimized file table vnode read routine. + * + * This bypasses the VOP table and talks directly to the device. Most + * filesystems just route to specfs and can make this optimization. + */ +static int +svn_read(fp, uio, cred, flags, td) + struct file *fp; + struct uio *uio; + struct ucred *cred; + struct thread *td; + int flags; +{ + struct vnode *vp; + int ioflag; + int error; + dev_t dev; + + KASSERT(uio->uio_td == td, ("uio_td %p is not td %p", uio->uio_td, td)); + + vp = (struct vnode *)fp->f_data; + if (vp == NULL || vp->v_type == VBAD) + return (EBADF); + + if ((dev = vp->v_rdev) == NULL) + return (EBADF); + reference_dev(dev); + + if (uio->uio_resid == 0) + return (0); + if ((flags & FOF_OFFSET) == 0) + uio->uio_offset = fp->f_offset; + + ioflag = 0; + if (fp->f_flag & FNONBLOCK) + ioflag |= IO_NDELAY; + if (fp->f_flag & O_DIRECT) + ioflag |= IO_DIRECT; + ioflag |= sequential_heuristic(uio, fp); + + error = dev_dread(dev, uio, ioflag); + + release_dev(dev); + if ((flags & FOF_OFFSET) == 0) + fp->f_offset = uio->uio_offset; + fp->f_nextoff = uio->uio_offset; + return (error); +} + /* * File table vnode write routine. */ @@ -451,6 +613,64 @@ vn_write(fp, uio, cred, flags, td) return (error); } +/* + * Device-optimized file table vnode write routine. + * + * This bypasses the VOP table and talks directly to the device. Most + * filesystems just route to specfs and can make this optimization. + */ +static int +svn_write(fp, uio, cred, flags, td) + struct file *fp; + struct uio *uio; + struct ucred *cred; + struct thread *td; + int flags; +{ + struct vnode *vp; + int ioflag; + int error; + dev_t dev; + + KASSERT(uio->uio_td == td, ("uio_procp %p is not p %p", + uio->uio_td, td)); + + vp = (struct vnode *)fp->f_data; + if (vp == NULL || vp->v_type == VBAD) + return (EBADF); + if (vp->v_type == VREG) + bwillwrite(); + vp = (struct vnode *)fp->f_data; /* XXX needed? */ + + if ((dev = vp->v_rdev) == NULL) + return (EBADF); + reference_dev(dev); + + if ((flags & FOF_OFFSET) == 0) + uio->uio_offset = fp->f_offset; + + ioflag = IO_UNIT; + if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) + ioflag |= IO_APPEND; + if (fp->f_flag & FNONBLOCK) + ioflag |= IO_NDELAY; + if (fp->f_flag & O_DIRECT) + ioflag |= IO_DIRECT; + if ((fp->f_flag & O_FSYNC) || + (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))) + ioflag |= IO_SYNC; + ioflag |= sequential_heuristic(uio, fp); + + error = dev_dwrite(dev, uio, ioflag); + + release_dev(dev); + if ((flags & FOF_OFFSET) == 0) + fp->f_offset = uio->uio_offset; + fp->f_nextoff = uio->uio_offset; + + return (error); +} + /* * File table vnode stat routine. */ diff --git a/sys/kern/vfs_vopops.c b/sys/kern/vfs_vopops.c index d6b4d6fa12..0848a06159 100644 --- a/sys/kern/vfs_vopops.c +++ b/sys/kern/vfs_vopops.c @@ -32,7 +32,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/kern/vfs_vopops.c,v 1.9 2004/10/12 19:20:46 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_vopops.c,v 1.10 2004/11/12 00:09:24 dillon Exp $ */ #include @@ -128,6 +128,13 @@ VDESC_NO_OFFSET, \ VDESC_NO_OFFSET) +#define VNODEOP_DESC_INIT_NCP2_CRED(name) \ + VNODEOP_DESC_INIT(name, 0, NULL, \ + VDESC_NO_OFFSET, \ + __offsetof(VARGSSTRUCT(name), a_cred), \ + VDESC_NO_OFFSET, \ + VDESC_NO_OFFSET) + #define VNODEOP_DESC_INIT_NCP_CRED(name) \ VNODEOP_DESC_INIT(name, 0, NULL, \ VDESC_NO_OFFSET, \ @@ -135,6 +142,23 @@ VDESC_NO_OFFSET, \ VDESC_NO_OFFSET) +#define VNODEOP_DESC_INIT_NCP_VP_CRED(name) \ + static int VOFFNAME(name)[] = { \ + __offsetof(VARGSSTRUCT(name), a_vp), \ + VDESC_NO_OFFSET }; \ + VNODEOP_DESC_INIT(name, 0, VOFFNAME(name), \ + VDESC_NO_OFFSET, \ + __offsetof(VARGSSTRUCT(name), a_cred), \ + VDESC_NO_OFFSET, \ + VDESC_NO_OFFSET) + +#define VNODEOP_DESC_INIT_NCP_CRED_VPP(name) \ + VNODEOP_DESC_INIT(name, 0, NULL, \ + __offsetof(VARGSSTRUCT(name), a_vpp), \ + __offsetof(VARGSSTRUCT(name), a_cred), \ + VDESC_NO_OFFSET, \ + VDESC_NO_OFFSET) + #define VNODEOP_DESC_INIT_DVP_VPP_CNP(name) \ static int VOFFNAME(name)[] = { \ __offsetof(VARGSSTRUCT(name), a_dvp), \ @@ -145,6 +169,16 @@ VDESC_NO_OFFSET, \ __offsetof(VARGSSTRUCT(name), a_cnp)) +#define VNODEOP_DESC_INIT_DVP_VPP_CRED(name) \ + static int VOFFNAME(name)[] = { \ + __offsetof(VARGSSTRUCT(name), a_dvp), \ + VDESC_NO_OFFSET }; \ + VNODEOP_DESC_INIT(name, 0, VOFFNAME(name), \ + __offsetof(VARGSSTRUCT(name), a_vpp), \ + __offsetof(VARGSSTRUCT(name), a_cred), \ + VDESC_NO_OFFSET, \ + VDESC_NO_OFFSET) + #define VNODEOP_DESC_INIT_DVP_CNP(name) \ static int VOFFNAME(name)[] = { \ __offsetof(VARGSSTRUCT(name), a_dvp), \ @@ -179,9 +213,7 @@ VNODEOP_DESC_INIT_SIMPLE(default); VNODEOP_DESC_INIT_VP(islocked); -VNODEOP_DESC_INIT_NCP_CRED(resolve); VNODEOP_DESC_INIT_DVP_VPP_CNP(lookup); -VNODEOP_DESC_INIT_DVP_VPP_CNP(cachedlookup); VNODEOP_DESC_INIT_DVP_VPP_CNP(create); VNODEOP_DESC_INIT_DVP_CNP(whiteout); VNODEOP_DESC_INIT_DVP_VPP_CNP(mknod); @@ -200,7 +232,6 @@ VNODEOP_DESC_INIT_VP(revoke); VNODEOP_DESC_INIT_VP_CRED(mmap); VNODEOP_DESC_INIT_VP(fsync); VNODEOP_DESC_INIT_DVP_VP_CNP(remove); -VNODEOP_DESC_INIT_NCP_CRED(nremove); VNODEOP_DESC_INIT_TDVP_VP_CNP(link); static int VOFFNAME(rename)[] = { @@ -219,6 +250,7 @@ VNODEOP_DESC_INIT(rename, VDESC_NO_OFFSET, VDESC_NO_OFFSET, __offsetof(VARGSSTRUCT(rename), a_fcnp)); + VNODEOP_DESC_INIT_DVP_VPP_CNP(mkdir); VNODEOP_DESC_INIT_DVP_VP_CNP(rmdir); VNODEOP_DESC_INIT_DVP_VPP_CNP(symlink); @@ -249,6 +281,18 @@ VNODEOP_DESC_INIT_VP(destroyvobject); VNODEOP_DESC_INIT_VP(getvobject); VNODEOP_DESC_INIT_SIMPLE(vfsset); +VNODEOP_DESC_INIT_NCP_CRED(nresolve); +VNODEOP_DESC_INIT_DVP_VPP_CRED(nlookupdotdot); +VNODEOP_DESC_INIT_NCP_CRED_VPP(ncreate); +VNODEOP_DESC_INIT_NCP_CRED_VPP(nmkdir); +VNODEOP_DESC_INIT_NCP_CRED_VPP(nmknod); +VNODEOP_DESC_INIT_NCP_VP_CRED(nlink); +VNODEOP_DESC_INIT_NCP_CRED_VPP(nsymlink); +VNODEOP_DESC_INIT_NCP_CRED(nwhiteout); +VNODEOP_DESC_INIT_NCP_CRED(nremove); +VNODEOP_DESC_INIT_NCP_CRED(nrmdir); +VNODEOP_DESC_INIT_NCP2_CRED(nrename); + /* * The DO_OPS macro basicallys calls ops->blah(&ap) but is also responsible * for checking vv_flags and executing additional hook functions. @@ -291,21 +335,6 @@ vop_islocked(struct vop_ops *ops, struct vnode *vp, struct thread *td) return(error); } -int -vop_resolve(struct vop_ops *ops, struct namecache *ncp, struct ucred *cred) -{ - struct vop_resolve_args ap; - int error; - - ap.a_head.a_desc = &vop_resolve_desc; - ap.a_head.a_ops = ops; - ap.a_ncp = ncp; - ap.a_cred = cred; - - DO_OPS(ops, error, &ap, vop_resolve); - return(error); -} - int vop_lookup(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp) @@ -324,24 +353,7 @@ vop_lookup(struct vop_ops *ops, struct vnode *dvp, } int -vop_cachedlookup(struct vop_ops *ops, struct vnode *dvp, - struct vnode **vpp, struct componentname *cnp) -{ - struct vop_cachedlookup_args ap; - int error; - - ap.a_head.a_desc = &vop_cachedlookup_desc; - ap.a_head.a_ops = ops; - ap.a_dvp = dvp; - ap.a_vpp = vpp; - ap.a_cnp = cnp; - - DO_OPS(ops, error, &ap, vop_cachedlookup); - return(error); -} - -int -vop_create(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +vop_create(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap) { struct vop_create_args ap; @@ -350,7 +362,6 @@ vop_create(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, ap.a_head.a_desc = &vop_create_desc; ap.a_head.a_ops = ops; ap.a_dvp = dvp; - ap.a_par = par; ap.a_vpp = vpp; ap.a_cnp = cnp; ap.a_vap = vap; @@ -360,7 +371,7 @@ vop_create(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, } int -vop_whiteout(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +vop_whiteout(struct vop_ops *ops, struct vnode *dvp, struct componentname *cnp, int flags) { struct vop_whiteout_args ap; @@ -369,7 +380,6 @@ vop_whiteout(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, ap.a_head.a_desc = &vop_whiteout_desc; ap.a_head.a_ops = ops; ap.a_dvp = dvp; - ap.a_par = par; ap.a_cnp = cnp; ap.a_flags = flags; @@ -378,7 +388,7 @@ vop_whiteout(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, } int -vop_mknod(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +vop_mknod(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap) { struct vop_mknod_args ap; @@ -387,7 +397,6 @@ vop_mknod(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, ap.a_head.a_desc = &vop_mknod_desc; ap.a_head.a_ops = ops; ap.a_dvp = dvp; - ap.a_par = par; ap.a_vpp = vpp; ap.a_cnp = cnp; ap.a_vap = vap; @@ -398,7 +407,7 @@ vop_mknod(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, int vop_open(struct vop_ops *ops, struct vnode *vp, int mode, struct ucred *cred, - struct thread *td) + struct file *fp, struct thread *td) { struct vop_open_args ap; int error; @@ -406,6 +415,7 @@ vop_open(struct vop_ops *ops, struct vnode *vp, int mode, struct ucred *cred, ap.a_head.a_desc = &vop_open_desc; ap.a_head.a_ops = ops; ap.a_vp = vp; + ap.a_fp = fp; ap.a_mode = mode; ap.a_cred = cred; ap.a_td = td; @@ -641,7 +651,7 @@ vop_fsync(struct vop_ops *ops, struct vnode *vp, int waitfor, struct thread *td) } int -vop_remove(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +vop_remove(struct vop_ops *ops, struct vnode *dvp, struct vnode *vp, struct componentname *cnp) { struct vop_remove_args ap; @@ -650,7 +660,6 @@ vop_remove(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, ap.a_head.a_desc = &vop_remove_desc; ap.a_head.a_ops = ops; ap.a_dvp = dvp; - ap.a_par = par; ap.a_vp = vp; ap.a_cnp = cnp; @@ -659,22 +668,7 @@ vop_remove(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, } int -vop_nremove(struct vop_ops *ops, struct namecache *ncp, struct ucred *cred) -{ - struct vop_nremove_args ap; - int error; - - ap.a_head.a_desc = &vop_nremove_desc; - ap.a_head.a_ops = ops; - ap.a_ncp = ncp; - ap.a_cred = cred; - - DO_OPS(ops, error, &ap, vop_nremove); - return(error); -} - -int -vop_link(struct vop_ops *ops, struct vnode *tdvp, struct namecache *par, +vop_link(struct vop_ops *ops, struct vnode *tdvp, struct vnode *vp, struct componentname *cnp) { struct vop_link_args ap; @@ -683,7 +677,6 @@ vop_link(struct vop_ops *ops, struct vnode *tdvp, struct namecache *par, ap.a_head.a_desc = &vop_link_desc; ap.a_head.a_ops = ops; ap.a_tdvp = tdvp; - ap.a_par = par; ap.a_vp = vp; ap.a_cnp = cnp; @@ -692,10 +685,9 @@ vop_link(struct vop_ops *ops, struct vnode *tdvp, struct namecache *par, } int -vop_rename(struct vop_ops *ops, struct vnode *fdvp, struct namecache *fpar, - struct vnode *fvp, struct componentname *fcnp, - struct vnode *tdvp, struct namecache *tpar, - struct vnode *tvp, struct componentname *tcnp) +vop_rename(struct vop_ops *ops, + struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp, + struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp) { struct vop_rename_args ap; int error; @@ -703,11 +695,9 @@ vop_rename(struct vop_ops *ops, struct vnode *fdvp, struct namecache *fpar, ap.a_head.a_desc = &vop_rename_desc; ap.a_head.a_ops = ops; ap.a_fdvp = fdvp; - ap.a_fpar = fpar; ap.a_fvp = fvp; ap.a_fcnp = fcnp; ap.a_tdvp = tdvp; - ap.a_tpar = tpar; ap.a_tvp = tvp; ap.a_tcnp = tcnp; @@ -716,7 +706,7 @@ vop_rename(struct vop_ops *ops, struct vnode *fdvp, struct namecache *fpar, } int -vop_mkdir(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +vop_mkdir(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap) { struct vop_mkdir_args ap; @@ -725,7 +715,6 @@ vop_mkdir(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, ap.a_head.a_desc = &vop_mkdir_desc; ap.a_head.a_ops = ops; ap.a_dvp = dvp; - ap.a_par = par; ap.a_vpp = vpp; ap.a_cnp = cnp; ap.a_vap = vap; @@ -735,7 +724,7 @@ vop_mkdir(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, } int -vop_rmdir(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +vop_rmdir(struct vop_ops *ops, struct vnode *dvp, struct vnode *vp, struct componentname *cnp) { struct vop_rmdir_args ap; @@ -744,7 +733,6 @@ vop_rmdir(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, ap.a_head.a_desc = &vop_rmdir_desc; ap.a_head.a_ops = ops; ap.a_dvp = dvp; - ap.a_par = par; ap.a_vp = vp; ap.a_cnp = cnp; @@ -753,7 +741,7 @@ vop_rmdir(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, } int -vop_symlink(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +vop_symlink(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap, char *target) { @@ -763,7 +751,6 @@ vop_symlink(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, ap.a_head.a_desc = &vop_symlink_desc; ap.a_head.a_ops = ops; ap.a_dvp = dvp; - ap.a_par = par; ap.a_vpp = vpp; ap.a_cnp = cnp; ap.a_vap = vap; @@ -1219,6 +1206,279 @@ vop_vfsset(struct vop_ops *ops, int op, const char *opstr) return(error); } +/* + * NEW API FUNCTIONS + * + * nresolve takes a locked ncp and a cred and resolves the ncp into a + * positive or negative hit. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_nresolve(struct vop_ops *ops, struct namecache *ncp, struct ucred *cred) +{ + struct vop_nresolve_args ap; + int error; + + ap.a_head.a_desc = &vop_nresolve_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_cred = cred; + + DO_OPS(ops, error, &ap, vop_nresolve); + return(error); +} + +/* + * nlookupdotdot takes an unlocked directory, dvp, and looks up "..", returning + * a locked parent directory in *vpp. If an error occurs *vpp will be NULL. + */ +int +vop_nlookupdotdot(struct vop_ops *ops, struct vnode *dvp, + struct vnode **vpp, struct ucred *cred) +{ + struct vop_nlookupdotdot_args ap; + int error; + + ap.a_head.a_desc = &vop_nlookupdotdot_desc; + ap.a_head.a_ops = ops; + ap.a_dvp = dvp; + ap.a_vpp = vpp; + ap.a_cred = cred; + + DO_OPS(ops, error, &ap, vop_nlookupdotdot); + return(error); +} + +/* + * ncreate takes a locked, resolved ncp that typically represents a negative + * cache hit and creates the file or node specified by the ncp, cred, and + * vattr. If no error occurs a locked vnode is returned in *vpp. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_ncreate(struct vop_ops *ops, struct namecache *ncp, + struct vnode **vpp, struct ucred *cred, struct vattr *vap) +{ + struct vop_ncreate_args ap; + int error; + + ap.a_head.a_desc = &vop_ncreate_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_vpp = vpp; + ap.a_cred = cred; + ap.a_vap = vap; + + DO_OPS(ops, error, &ap, vop_ncreate); + return(error); +} + +/* + * nmkdir takes a locked, resolved ncp that typically represents a negative + * cache hit and creates the directory specified by the ncp, cred, and + * vattr. If no error occurs a locked vnode is returned in *vpp. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_nmkdir(struct vop_ops *ops, struct namecache *ncp, + struct vnode **vpp, struct ucred *cred, struct vattr *vap) +{ + struct vop_nmkdir_args ap; + int error; + + ap.a_head.a_desc = &vop_nmkdir_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_vpp = vpp; + ap.a_cred = cred; + ap.a_vap = vap; + + DO_OPS(ops, error, &ap, vop_nmkdir); + return(error); +} + +/* + * nmknod takes a locked, resolved ncp that typically represents a negative + * cache hit and creates the node specified by the ncp, cred, and + * vattr. If no error occurs a locked vnode is returned in *vpp. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_nmknod(struct vop_ops *ops, struct namecache *ncp, + struct vnode **vpp, struct ucred *cred, struct vattr *vap) +{ + struct vop_nmknod_args ap; + int error; + + ap.a_head.a_desc = &vop_nmknod_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_vpp = vpp; + ap.a_cred = cred; + ap.a_vap = vap; + + DO_OPS(ops, error, &ap, vop_nmknod); + return(error); +} + +/* + * nlink takes a locked, resolved ncp that typically represents a negative + * cache hit and creates the node specified by the ncp, cred, and + * existing vnode. The passed vp must be locked and will remain locked + * on return, as does the ncp, whether an error occurs or not. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_nlink(struct vop_ops *ops, struct namecache *ncp, + struct vnode *vp, struct ucred *cred) +{ + struct vop_nlink_args ap; + int error; + + ap.a_head.a_desc = &vop_nlink_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_vp = vp; + ap.a_cred = cred; + + DO_OPS(ops, error, &ap, vop_nlink); + return(error); +} + +/* + * nsymlink takes a locked, resolved ncp that typically represents a negative + * cache hit and creates a symbolic link based on cred, vap, and target (the + * contents of the link). If no error occurs a locked vnode is returned in + * *vpp. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_nsymlink(struct vop_ops *ops, struct namecache *ncp, + struct vnode **vpp, struct ucred *cred, + struct vattr *vap, char *target) +{ + struct vop_nsymlink_args ap; + int error; + + ap.a_head.a_desc = &vop_nsymlink_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_vpp = vpp; + ap.a_cred = cred; + ap.a_vap = vap; + ap.a_target = target; + + DO_OPS(ops, error, &ap, vop_nsymlink); + return(error); +} + +/* + * nwhiteout takes a locked, resolved ncp that can represent a positive or + * negative hit and executes the whiteout function specified in flags. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_nwhiteout(struct vop_ops *ops, struct namecache *ncp, + struct ucred *cred, int flags) +{ + struct vop_nwhiteout_args ap; + int error; + + ap.a_head.a_desc = &vop_nwhiteout_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_cred = cred; + ap.a_flags = flags; + + DO_OPS(ops, error, &ap, vop_nwhiteout); + return(error); +} + +/* + * nremove takes a locked, resolved ncp that generally represents a + * positive hit and removes the file. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_nremove(struct vop_ops *ops, struct namecache *ncp, struct ucred *cred) +{ + struct vop_nremove_args ap; + int error; + + ap.a_head.a_desc = &vop_nremove_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_cred = cred; + + DO_OPS(ops, error, &ap, vop_nremove); + return(error); +} + +/* + * nrmdir takes a locked, resolved ncp that generally represents a + * directory and removes the directory. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. + */ +int +vop_nrmdir(struct vop_ops *ops, struct namecache *ncp, struct ucred *cred) +{ + struct vop_nrmdir_args ap; + int error; + + ap.a_head.a_desc = &vop_nrmdir_desc; + ap.a_head.a_ops = ops; + ap.a_ncp = ncp; + ap.a_cred = cred; + + DO_OPS(ops, error, &ap, vop_nrmdir); + return(error); +} + +/* + * nrename takes TWO locked, resolved ncp's and the cred of the caller + * and renames the source ncp to the target ncp. The target ncp may + * represent a positive or negative hit. + * + * The namecache is automatically adjusted by this function. The ncp + * is left locked on return. The source ncp is typically changed to + * a negative cache hit and the target ncp typically takes on the + * source ncp's underlying file. + */ +int +vop_nrename(struct vop_ops *ops, struct namecache *fncp, + struct namecache *tncp, struct ucred *cred) +{ + struct vop_nrename_args ap; + int error; + + ap.a_head.a_desc = &vop_nrename_desc; + ap.a_head.a_ops = ops; + ap.a_fncp = fncp; + ap.a_tncp = tncp; + ap.a_cred = cred; + + DO_OPS(ops, error, &ap, vop_nrename); + return(error); +} + /************************************************************************ * PRIMARY VNODE OPERATIONS FORWARDING CALLS * ************************************************************************ @@ -1258,16 +1518,6 @@ vop_islocked_ap(struct vop_islocked_args *ap) return(error); } -int -vop_resolve_ap(struct vop_resolve_args *ap) -{ - int error; - - DO_OPS(ap->a_head.a_ops, error, ap, vop_resolve); - return(error); -} - - int vop_lookup_ap(struct vop_lookup_args *ap) { @@ -1277,15 +1527,6 @@ vop_lookup_ap(struct vop_lookup_args *ap) return(error); } -int -vop_cachedlookup_ap(struct vop_cachedlookup_args *ap) -{ - int error; - - DO_OPS(ap->a_head.a_ops, error, ap, vop_cachedlookup); - return(error); -} - int vop_create_ap(struct vop_create_args *ap) { @@ -1448,15 +1689,6 @@ vop_remove_ap(struct vop_remove_args *ap) return(error); } -int -vop_nremove_ap(struct vop_nremove_args *ap) -{ - int error; - - DO_OPS(ap->a_head.a_ops, error, ap, vop_nremove); - return(error); -} - int vop_link_ap(struct vop_link_args *ap) { @@ -1736,3 +1968,102 @@ vop_vfsset_ap(struct vop_vfsset_args *ap) return(error); } +int +vop_nresolve_ap(struct vop_nresolve_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nresolve); + return(error); +} + +int +vop_nlookupdotdot_ap(struct vop_nlookupdotdot_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nlookupdotdot); + return(error); +} + +int +vop_ncreate_ap(struct vop_ncreate_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_ncreate); + return(error); +} + +int +vop_nmkdir_ap(struct vop_nmkdir_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nmkdir); + return(error); +} + +int +vop_nmknod_ap(struct vop_nmknod_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nmknod); + return(error); +} + +int +vop_nlink_ap(struct vop_nlink_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nlink); + return(error); +} + +int +vop_nsymlink_ap(struct vop_nsymlink_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nsymlink); + return(error); +} + +int +vop_nwhiteout_ap(struct vop_nwhiteout_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nwhiteout); + return(error); +} + +int +vop_nremove_ap(struct vop_nremove_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nremove); + return(error); +} + +int +vop_nrmdir_ap(struct vop_nrmdir_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nrmdir); + return(error); +} + +int +vop_nrename_ap(struct vop_nrename_args *ap) +{ + int error; + + DO_OPS(ap->a_head.a_ops, error, ap, vop_nrename); + return(error); +} + diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c index 9e6d24e744..6b887993d7 100644 --- a/sys/opencrypto/cryptodev.c +++ b/sys/opencrypto/cryptodev.c @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.4.2.4 2003/06/03 00:09:02 sam Exp $ */ -/* $DragonFly: src/sys/opencrypto/cryptodev.c,v 1.8 2004/05/19 22:53:01 dillon Exp $ */ +/* $DragonFly: src/sys/opencrypto/cryptodev.c,v 1.9 2004/11/12 00:09:25 dillon Exp $ */ /* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */ /* @@ -728,7 +728,6 @@ cryptoioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) FREE(fcr, M_XDATA); return (error); } - fhold(f); f->f_flag = FREAD | FWRITE; f->f_type = DTYPE_CRYPTO; f->f_ops = &cryptofops; diff --git a/sys/sys/buf2.h b/sys/sys/buf2.h index 062d7ee9e5..5b22c2b943 100644 --- a/sys/sys/buf2.h +++ b/sys/sys/buf2.h @@ -37,7 +37,7 @@ * * @(#)buf.h 8.9 (Berkeley) 3/30/95 * $FreeBSD: src/sys/sys/buf.h,v 1.88.2.10 2003/01/25 19:02:23 dillon Exp $ - * $DragonFly: src/sys/sys/buf2.h,v 1.8 2004/11/09 17:36:42 dillon Exp $ + * $DragonFly: src/sys/sys/buf2.h,v 1.9 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_BUF2_H_ @@ -59,7 +59,6 @@ * * Get a lock sleeping non-interruptably until it becomes available. */ -static __inline int BUF_LOCK (struct buf *, int); static __inline int BUF_LOCK(struct buf *bp, int locktype) { @@ -79,7 +78,6 @@ BUF_LOCK(struct buf *bp, int locktype) /* * Get a lock sleeping with specified interruptably and timeout. */ -static __inline int BUF_TIMELOCK (struct buf *, int, char *, int, int); static __inline int BUF_TIMELOCK(struct buf *bp, int locktype, char *wmesg, int catch, int timo) { @@ -100,7 +98,6 @@ BUF_TIMELOCK(struct buf *bp, int locktype, char *wmesg, int catch, int timo) * Release a lock. Only the acquiring process may free the lock unless * it has been handed off to biodone. */ -static __inline void BUF_UNLOCK (struct buf *); static __inline void BUF_UNLOCK(struct buf *bp) { diff --git a/sys/sys/file.h b/sys/sys/file.h index d2f98e1a00..71086c56c0 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -32,7 +32,7 @@ * * @(#)file.h 8.3 (Berkeley) 1/9/95 * $FreeBSD: src/sys/sys/file.h,v 1.22.2.7 2002/11/21 23:39:24 sam Exp $ - * $DragonFly: src/sys/sys/file.h,v 1.11 2004/09/30 18:59:50 dillon Exp $ + * $DragonFly: src/sys/sys/file.h,v 1.12 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_FILE_H_ @@ -136,7 +136,8 @@ extern int fp_mmap(void *addr, size_t size, int prot, int flags, struct file *fp extern int fp_close(struct file *fp); extern struct filelist filehead; /* head of list of open files */ -extern struct fileops vnops; +extern struct fileops vnode_fileops; +extern struct fileops specvnode_fileops; extern struct fileops badfileops; extern int maxfiles; /* kernel limit on number of open files */ extern int maxfilesrootres; /* descriptors reserved for root use */ diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 20cd4ff99f..09b5038998 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -32,7 +32,7 @@ * * @(#)filedesc.h 8.1 (Berkeley) 6/2/93 * $FreeBSD: src/sys/sys/filedesc.h,v 1.19.2.5 2003/06/06 20:21:32 tegge Exp $ - * $DragonFly: src/sys/sys/filedesc.h,v 1.7 2003/10/13 21:15:48 dillon Exp $ + * $DragonFly: src/sys/sys/filedesc.h,v 1.8 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_FILEDESC_H_ @@ -165,7 +165,8 @@ int dupfdopen (struct filedesc *, int, int, int, int); int fdalloc (struct proc *p, int want, int *result); int fdavail (struct proc *p, int n); int falloc (struct proc *p, struct file **resultfp, int *resultfd); -void fsetcred(struct file *fp, struct ucred *cr); +int fsetfd (struct proc *p, struct file *fp, int *resultfd); +void fsetcred (struct file *fp, struct ucred *cr); void ffree (struct file *); struct filedesc *fdinit (struct proc *p); struct filedesc *fdshare (struct proc *p); diff --git a/sys/sys/kern_syscall.h b/sys/sys/kern_syscall.h index fa50d9eb75..e7f2445331 100644 --- a/sys/sys/kern_syscall.h +++ b/sys/sys/kern_syscall.h @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/kern_syscall.h,v 1.19 2004/09/30 18:59:50 dillon Exp $ + * $DragonFly: src/sys/sys/kern_syscall.h,v 1.20 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_KERN_SYSCALL_H_ @@ -37,7 +37,6 @@ struct image_args; struct mbuf; struct msghdr; struct namecache; -struct nameidata; struct nlookupdata; struct rlimit; struct rusage; @@ -64,7 +63,7 @@ int kern_fstat(int fd, struct stat *st); /* * Prototypes for syscalls in kern/kern_exec.c */ -int kern_execve(struct nameidata *nd, struct image_args *args); +int kern_execve(struct nlookupdata *nd, struct image_args *args); /* * Prototypes for syscalls in kern/kern_exit.c @@ -118,30 +117,30 @@ int kern_socketpair(int domain, int type, int protocol, int *sockv); /* * Prototypes for syscalls in kern/vfs_syscalls.c */ -int kern_access(struct nameidata *nd, int aflags); +int kern_access(struct nlookupdata *nd, int aflags); int kern_chdir(struct nlookupdata *nd); -int kern_chmod(struct nameidata *nd, int mode); -int kern_chown(struct nameidata *nd, int uid, int gid); +int kern_chmod(struct nlookupdata *nd, int mode); +int kern_chown(struct nlookupdata *nd, int uid, int gid); /*int kern_chroot(struct namecache *ncp);*/ int kern_fstatfs(int fd, struct statfs *buf); int kern_ftruncate(int fd, off_t length); int kern_futimes(int fd, struct timeval *tptr); int kern_getdirentries(int fd, char *buf, u_int count, long *basep, int *res); -int kern_link(struct nameidata *nd, struct nameidata *linknd); +int kern_link(struct nlookupdata *nd, struct nlookupdata *linknd); int kern_lseek(int fd, off_t offset, int whence, off_t *res); -int kern_mkdir(struct nameidata *nd, int mode); -int kern_mkfifo(struct nameidata *nd, int mode); -int kern_mknod(struct nameidata *nd, int mode, int dev); -int kern_open(struct nameidata *nd, int flags, int mode, int *res); -int kern_readlink(struct nameidata *nd, char *buf, int count, int *res); -int kern_rename(struct nameidata *fromnd, struct nameidata *tond); -int kern_rmdir(struct nameidata *nd); +int kern_mkdir(struct nlookupdata *nd, int mode); +int kern_mkfifo(struct nlookupdata *nd, int mode); +int kern_mknod(struct nlookupdata *nd, int mode, int dev); +int kern_open(struct nlookupdata *nd, int flags, int mode, int *res); +int kern_readlink(struct nlookupdata *nd, char *buf, int count, int *res); +int kern_rename(struct nlookupdata *fromnd, struct nlookupdata *tond); +int kern_rmdir(struct nlookupdata *nd); int kern_stat(struct nlookupdata *nd, struct stat *st); -int kern_statfs(struct nameidata *nd, struct statfs *buf); -int kern_symlink(char *path, struct nameidata *nd); -int kern_truncate(struct nameidata *nd, off_t length); -int kern_unlink(struct nameidata *nd); -int kern_utimes(struct nameidata *nd, struct timeval *tptr); +int kern_statfs(struct nlookupdata *nd, struct statfs *buf); +int kern_symlink(struct nlookupdata *nd, char *path, int mode); +int kern_truncate(struct nlookupdata *nd, off_t length); +int kern_unlink(struct nlookupdata *nd); +int kern_utimes(struct nlookupdata *nd, struct timeval *tptr); /* * Prototypes for syscalls in kern/vfs_cache.c diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 878b3d062b..5b0f3750eb 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -32,7 +32,7 @@ * * @(#)mount.h 8.21 (Berkeley) 5/20/95 * $FreeBSD: src/sys/sys/mount.h,v 1.89.2.7 2003/04/04 20:35:57 tegge Exp $ - * $DragonFly: src/sys/sys/mount.h,v 1.13 2004/09/30 18:59:50 dillon Exp $ + * $DragonFly: src/sys/sys/mount.h,v 1.14 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_MOUNT_H_ @@ -122,6 +122,10 @@ struct statfs { * * NOTE: Any vnode marked VPLACEMARKER is a placemarker and should ALWAYS BE * SKIPPED. NO OTHER FIELDS IN SUCH VNODES ARE VALID. + * + * NOTE: All VFSs must at least populate mnt_vn_ops or those VOP ops that + * only take namecache pointers will not be able to find their operations + * vector via namecache->nc_mount. */ TAILQ_HEAD(vnodelst, vnode); @@ -341,7 +345,7 @@ TAILQ_HEAD(mntlist, mount); /* struct mntlist */ */ #ifdef __STDC__ struct nlookupdata; -struct nameidata; +struct nlookupdata; struct mbuf; #endif @@ -479,7 +483,7 @@ extern struct nfs_public nfs_pub; * functions or casting entries in the VFS op table to "enopnotsupp()". */ int vfs_stdmount (struct mount *mp, char *path, caddr_t data, - struct nameidata *ndp, struct thread *p); + struct nlookupdata *ndp, struct thread *p); int vfs_stdstart (struct mount *mp, int flags, struct thread *p); int vfs_stdunmount (struct mount *mp, int mntflags, struct thread *p); int vfs_stdroot (struct mount *mp, struct vnode **vpp); diff --git a/sys/sys/namecache.h b/sys/sys/namecache.h index ff2267fd46..ffd0645dda 100644 --- a/sys/sys/namecache.h +++ b/sys/sys/namecache.h @@ -62,7 +62,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/namecache.h,v 1.14 2004/10/19 05:55:31 dillon Exp $ + * $DragonFly: src/sys/sys/namecache.h,v 1.15 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_NAMECACHE_H_ @@ -92,6 +92,9 @@ TAILQ_HEAD(namecache_list, namecache); * point, may have to obtain multiple namespace record locks to avoid * confusion, but only the one representing the physical directory is passed * into lower layer VOP calls. + * + * Many new API VOP operations do not pass vnodes. In these cases the + * operations vector is typically obtained via nc_mount->mnt_vn_ops. */ struct namecache { LIST_ENTRY(namecache) nc_hash; /* hash chain (nc_parent,name) */ @@ -109,7 +112,7 @@ struct namecache { int nc_timeout; /* compared against ticks, or 0 */ int nc_exlocks; /* namespace locking */ struct thread *nc_locktd; /* namespace locking */ - struct mount *nc_mount; + struct mount *nc_mount; /* associated mount for vopops */ }; typedef struct namecache *namecache_t; @@ -127,7 +130,6 @@ typedef struct namecache *namecache_t; #define NCF_UNUSED080 0x0080 #define NCF_ISSYMLINK 0x0100 /* represents a symlink */ #define NCF_ISDIR 0x0200 /* represents a directory */ -#define NCF_REVALPARENT 0x0400 /* reevaluate the parent link */ /* * cache_inval[_vp]() flags @@ -136,9 +138,6 @@ typedef struct namecache *namecache_t; #define CINV_SELF 0x0002 /* disconnect vp from namecache */ #define CINV_CHILDREN 0x0004 /* disconnect children in namecache */ -#define NCPNULL ((struct namecache *)NULL) /* placemarker */ -#define NCPPNULL ((struct namecache **)NULL) /* placemarker */ - #ifdef _KERNEL struct vop_lookup_args; @@ -147,13 +146,11 @@ struct nlcomponent; struct mount; void cache_lock(struct namecache *ncp); +int cache_lock_nonblock(struct namecache *ncp); void cache_unlock(struct namecache *ncp); void cache_setvp(struct namecache *ncp, struct vnode *vp); +void cache_settimeout(struct namecache *ncp, int nticks); void cache_setunresolved(struct namecache *ncp); -int cache_lookup(struct vnode *dvp, struct vnode **vpp, - struct componentname *cnp); -void cache_enter(struct vnode *dvp, struct vnode *vp, - struct componentname *cnp); struct namecache *cache_nlookup(struct namecache *par, struct nlcomponent *nlc); struct namecache *cache_allocroot(struct mount *mp, struct vnode *vp); void cache_inval(struct namecache *ncp, int flags); @@ -169,9 +166,10 @@ struct namecache *cache_get(struct namecache *ncp); struct namecache *cache_hold(struct namecache *ncp); void cache_put(struct namecache *ncp); void cache_drop(struct namecache *ncp); -int vfs_cache_lookup(struct vop_lookup_args *ap); +void cache_rename(struct namecache *fncp, struct namecache *tncp); int cache_vget(struct namecache *, struct ucred *, int, struct vnode **); int cache_vref(struct namecache *, struct ucred *, struct vnode **); +struct namecache *cache_fromdvp(struct vnode *, struct ucred *, int); #endif diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 9ed779292e..8a87586223 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -32,7 +32,7 @@ * * @(#)namei.h 8.5 (Berkeley) 1/9/95 * $FreeBSD: src/sys/sys/namei.h,v 1.29.2.2 2001/09/30 21:12:54 luigi Exp $ - * $DragonFly: src/sys/sys/namei.h,v 1.14 2004/09/28 00:25:31 dillon Exp $ + * $DragonFly: src/sys/sys/namei.h,v 1.15 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_NAMEI_H_ @@ -67,47 +67,12 @@ struct componentname { /* * Shared between lookup and commit routines. */ - char *cn_pnbuf; /* pathname buffer */ char *cn_nameptr; /* pointer to looked up name */ long cn_namelen; /* length of looked up component */ long cn_consume; /* chars to consume in lookup() */ int cn_timeout; /* if CNP_CACHETIMEOUT is set, in ticks */ }; -/* - * Encapsulation of namei parameters. - */ -struct nameidata { - /* - * Arguments to namei/lookup. - */ - const char *ni_dirp; /* pathname pointer */ - enum uio_seg ni_segflg; /* location of pathname */ - /* - * Arguments to lookup. - */ - struct vnode *ni_startdir; /* starting directory */ - struct vnode *ni_rootdir; /* logical root directory */ - struct vnode *ni_topdir; /* logical top directory */ - /* - * Results: returned from/manipulated by lookup - */ - struct vnode *ni_vp; /* vnode of result */ - struct vnode *ni_dvp; /* vnode of intermediate directory */ - /* - * Shared between namei and lookup/commit routines. - */ - size_t ni_pathlen; /* remaining chars in path incl \0 */ - char *ni_next; /* next location in pathname */ - u_long ni_loopcnt; /* count of symlinks encountered */ - /* - * Lookup parameters: this structure describes the subset of - * information from the nameidata structure that is passed - * through the VOP interface. - */ - struct componentname ni_cnd; -}; - #ifdef _KERNEL /* * namei operations @@ -120,99 +85,37 @@ struct nameidata { /* * namei operational modifier flags, stored in ni_cnd.flags */ -#define CNP_LOCKLEAF 0x00000004 /* return target vnode locked */ + /* (LOCKLEAF) 0x00000004 */ #define CNP_LOCKPARENT 0x00000008 /* return parent vnode locked */ #define CNP_WANTPARENT 0x00000010 /* return parent vnode unlocked */ -#define CNP_NOCACHE 0x00000020 /* name must not be left in cache */ + /* (NOCACHE) 0x00000020 */ #define CNP_FOLLOW 0x00000040 /* follow symbolic links */ -#define CNP_NOOBJ 0x00000080 /* don't create object */ + /* (NOOBJ) 0x00000080 */ #define CNP_MODMASK 0x00c000fc /* mask of operational modifiers */ /* * Namei parameter descriptors. - * - * SAVENAME may be set by either the callers of namei or by VOP_LOOKUP. - * If the caller of namei sets the flag (for example execve wants to - * know the name of the program that is being executed), then it must - * free the buffer. If VOP_LOOKUP sets the flag, then the buffer must - * be freed by either the commit routine or the VOP_ABORT routine. - * SAVESTART is set only by the callers of namei. It implies SAVENAME - * plus the addition of saving the parent directory that contains the - * name in ni_startdir. It allows repeated calls to lookup for the - * name being sought. The caller is responsible for releasing the - * buffer and for vrele'ing ni_startdir. */ -#define CNP_NOCROSSMOUNT 0x00000100 /* do not cross mount points */ + /* (NOCROSSMOUNT) 0x00000100 */ #define CNP_RDONLY 0x00000200 /* lookup with read-only semantics */ -#define CNP_HASBUF 0x00000400 /* has allocated pathname buffer */ -#define CNP_SAVENAME 0x00000800 /* save pathname buffer */ -#define CNP_SAVESTART 0x00001000 /* save starting directory */ + /* (HASBUF) 0x00000400 */ + /* (SAVENAME) 0x00000800 */ + /* (CNP_SAVESTART) 0x00001000 */ #define CNP_ISDOTDOT 0x00002000 /* current component name is .. */ -#define CNP_MAKEENTRY 0x00004000 /* entry will be added to name cache */ -#define CNP_ISLASTCN 0x00008000 /* flag last component of pathname */ -#define CNP_ISSYMLINK 0x00010000 /* symlink needs interpretation */ + /* (MAKEENTRY) 0x00004000 */ + /* (ISLASTCN) 0x00008000 */ + /* (ISSYMLINK) 0x00010000 */ #define CNP_ISWHITEOUT 0x00020000 /* found whiteout */ #define CNP_DOWHITEOUT 0x00040000 /* do whiteouts */ -#define CNP_WILLBEDIR 0x00080000 /* will be dir, allow trailing / */ -#define CNP_ISUNICODE 0x00100000 /* current component name is unicode*/ + /* (WILLBEDIR) 0x00080000 */ + /* (ISUNICODE) 0x00100000 */ #define CNP_PDIRUNLOCK 0x00200000 /* fs lookup() unlocked parent dir */ /* (WANTDNCP) 0x00400000 */ /* (WANTNCP) 0x00800000 */ -#define CNP_CACHETIMEOUT 0x01000000 /* apply timeout to cache entry */ + /* (CACHETIMEOUT) 0x01000000 */ #define CNP_PARAMASK 0x011fff00 /* mask of parameter descriptors */ -/* - * Initialization of an nameidata structure. - */ - -static __inline void -_NDINIT(struct nameidata *ndp, u_long op, u_long flags, enum uio_seg segflg, - const char *namep, struct thread *td -) { - ndp->ni_cnd.cn_nameiop = op; - ndp->ni_cnd.cn_flags = flags; - ndp->ni_segflg = segflg; - ndp->ni_dirp = namep; - ndp->ni_cnd.cn_td = td; -} - -static __inline void -NDINIT(struct nameidata *ndp, u_long op, u_long flags, enum uio_seg segflg, - const char *namep, struct thread *td -) { - struct proc *p; - - _NDINIT(ndp, op, flags, segflg, namep, td); - p = td->td_proc; - KKASSERT(p != NULL); - ndp->ni_cnd.cn_cred = p->p_ucred; -} - -static __inline void -NDINIT2(struct nameidata *ndp, u_long op, u_long flags, enum uio_seg segflg, - const char *namep, struct thread *td, struct ucred *cr -) { - _NDINIT(ndp, op, flags, segflg, namep, td); - ndp->ni_cnd.cn_cred = cr; -} - -#define NDF_NO_DVP_RELE 0x00000001 -#define NDF_NO_DVP_UNLOCK 0x00000002 -#define NDF_NO_DVP_PUT 0x00000003 -#define NDF_NO_VP_RELE 0x00000004 -#define NDF_NO_VP_UNLOCK 0x00000008 -#define NDF_NO_VP_PUT (NDF_NO_VP_RELE|NDF_NO_VP_UNLOCK) -#define NDF_NO_STARTDIR_RELE 0x00000010 -#define NDF_NO_FREE_PNBUF 0x00000020 - -#define NDF_ONLY_PNBUF (~NDF_NO_FREE_PNBUF) -#define NDF_ONLY_PNBUF_AND_NCPS (~(NDF_NO_FREE_PNBUF|NDF_NO_DNCP_RELE|NDF_NO_NCP_RELE)) - -void NDFREE (struct nameidata *, const uint); - extern int varsym_enable; -int namei (struct nameidata *ndp); -int lookup (struct nameidata *ndp); int relookup (struct vnode *dvp, struct vnode **vpp, struct componentname *cnp); #endif diff --git a/sys/sys/nlookup.h b/sys/sys/nlookup.h index 4e87372369..7560c61e21 100644 --- a/sys/sys/nlookup.h +++ b/sys/sys/nlookup.h @@ -31,12 +31,17 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/nlookup.h,v 1.2 2004/09/30 18:59:50 dillon Exp $ + * $DragonFly: src/sys/sys/nlookup.h,v 1.3 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_NLOOKUP_H_ #define _SYS_NLOOKUP_H_ +#ifndef _SYS_UIO_H_ +#include +#endif + +struct vnode; struct vattr; struct mount; struct namecache; @@ -60,6 +65,12 @@ struct nlcomponent { * access checks. */ struct nlookupdata { + /* + * These fields are setup by nlookup_init() with nl_ncp set to + * the current directory if a process or the root directory if + * a pure thread. The result from nlookup() will be returned in + * nl_ncp. + */ struct namecache *nl_ncp; /* start-point and result */ struct namecache *nl_rootncp; /* root directory */ struct namecache *nl_jailncp; /* jail directory */ @@ -70,6 +81,14 @@ struct nlookupdata { int nl_flags; /* operations flags */ int nl_loopcnt; /* symlinks encountered */ + + /* + * These fields are populated by vn_open(). nlookup_done() will + * vn_close() a non-NULL vp so if you extract it be sure to NULL out + * nl_open_vp. + */ + struct vnode *nl_open_vp; + int nl_vp_fmode; }; #define NLC_FOLLOW 0x00000001 /* follow leaf symlink */ @@ -78,10 +97,17 @@ struct nlookupdata { #define NLC_ISWHITEOUT 0x00000008 #define NLC_WILLBEDIR 0x00000010 #define NLC_NCPISLOCKED 0x00000020 +#define NLC_LOCKVP 0x00000040 /* nl_open_vp from vn_open */ +#define NLC_CREATE 0x00000080 +#define NLC_DELETE 0x00000100 +#define NLC_NFS_RDONLY 0x00010000 /* set by nfs_namei() only */ +#define NLC_NFS_NOSOFTLINKTRAV 0x00020000 /* do not traverse softlnks */ #ifdef _KERNEL int nlookup_init(struct nlookupdata *, const char *, enum uio_seg, int); +int nlookup_init_raw(struct nlookupdata *, const char *, enum uio_seg, int, struct ucred *, struct namecache *); +void nlookup_zero(struct nlookupdata *); void nlookup_done(struct nlookupdata *); struct namecache *nlookup_simple(const char *str, enum uio_seg seg, int niflags, int *error); diff --git a/sys/sys/vfsops.h b/sys/sys/vfsops.h index 1996b4d804..5f16a22194 100644 --- a/sys/sys/vfsops.h +++ b/sys/sys/vfsops.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/vfsops.h,v 1.8 2004/10/12 19:20:48 dillon Exp $ + * $DragonFly: src/sys/sys/vfsops.h,v 1.9 2004/11/12 00:09:27 dillon Exp $ */ /* @@ -76,6 +76,7 @@ struct componentname; struct vattr; struct ucred; struct uio; +struct file; struct knote; struct vm_object; struct vm_page; @@ -93,12 +94,6 @@ struct vop_islocked_args { struct thread *a_td; }; -struct vop_resolve_args { - struct vop_generic_args a_head; - struct namecache *a_ncp; - struct ucred *a_cred; -}; - struct vop_lookup_args { struct vop_generic_args a_head; struct vnode *a_dvp; @@ -106,17 +101,9 @@ struct vop_lookup_args { struct componentname *a_cnp; }; -struct vop_cachedlookup_args { - struct vop_generic_args a_head; - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; -}; - struct vop_create_args { struct vop_generic_args a_head; struct vnode *a_dvp; - struct namecache *a_par; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; @@ -125,7 +112,6 @@ struct vop_create_args { struct vop_whiteout_args { struct vop_generic_args a_head; struct vnode *a_dvp; - struct namecache *a_par; struct componentname *a_cnp; int a_flags; }; @@ -133,7 +119,6 @@ struct vop_whiteout_args { struct vop_mknod_args { struct vop_generic_args a_head; struct vnode *a_dvp; - struct namecache *a_par; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; @@ -144,6 +129,7 @@ struct vop_open_args { struct vnode *a_vp; int a_mode; struct ucred *a_cred; + struct file *a_fp; /* optional fp for fileops override */ struct thread *a_td; }; @@ -249,21 +235,13 @@ struct vop_fsync_args { struct vop_remove_args { struct vop_generic_args a_head; struct vnode *a_dvp; - struct namecache *a_par; struct vnode *a_vp; struct componentname *a_cnp; }; -struct vop_nremove_args { - struct vop_generic_args a_head; - struct namecache *a_ncp; /* locked namespace */ - struct ucred *a_cred; -}; - struct vop_link_args { struct vop_generic_args a_head; struct vnode *a_tdvp; - struct namecache *a_par; struct vnode *a_vp; struct componentname *a_cnp; }; @@ -271,11 +249,9 @@ struct vop_link_args { struct vop_rename_args { struct vop_generic_args a_head; struct vnode *a_fdvp; - struct namecache *a_fpar; struct vnode *a_fvp; struct componentname *a_fcnp; struct vnode *a_tdvp; - struct namecache *a_tpar; struct vnode *a_tvp; struct componentname *a_tcnp; }; @@ -283,7 +259,6 @@ struct vop_rename_args { struct vop_mkdir_args { struct vop_generic_args a_head; struct vnode *a_dvp; - struct namecache *a_par; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; @@ -292,7 +267,6 @@ struct vop_mkdir_args { struct vop_rmdir_args { struct vop_generic_args a_head; struct vnode *a_dvp; - struct namecache *a_par; struct vnode *a_vp; struct componentname *a_cnp; }; @@ -300,7 +274,6 @@ struct vop_rmdir_args { struct vop_symlink_args { struct vop_generic_args a_head; struct vnode *a_dvp; - struct namecache *a_par; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; @@ -503,6 +476,88 @@ struct vop_vfsset_args { const char *a_opstr; }; +/* + * NEW API + */ +struct vop_nresolve_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; + struct ucred *a_cred; +}; + +struct vop_nlookupdotdot_args { + struct vop_generic_args a_head; + struct vnode *a_dvp; + struct vnode **a_vpp; + struct ucred *a_cred; +}; + +struct vop_ncreate_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; /* locked namespace */ + struct vnode **a_vpp; /* returned refd & locked */ + struct ucred *a_cred; + struct vattr *a_vap; +}; + +struct vop_nmkdir_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; /* locked namespace */ + struct vnode **a_vpp; /* returned refd & locked */ + struct ucred *a_cred; + struct vattr *a_vap; +}; + +struct vop_nmknod_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; + struct vnode **a_vpp; + struct ucred *a_cred; + struct vattr *a_vap; +}; + +struct vop_nlink_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; + struct vnode *a_vp; + struct ucred *a_cred; +}; + +struct vop_nsymlink_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; + struct vnode **a_vpp; + struct ucred *a_cred; + struct vattr *a_vap; + char *a_target; +}; + +struct vop_nwhiteout_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; + struct ucred *a_cred; + int a_flags; +}; + +struct vop_nremove_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; /* locked namespace */ + struct ucred *a_cred; +}; + +struct vop_nrmdir_args { + struct vop_generic_args a_head; + struct namecache *a_ncp; /* locked namespace */ + struct ucred *a_cred; +}; + +struct vop_nrename_args { + struct vop_generic_args a_head; + struct namecache *a_fncp; /* locked namespace / from */ + struct namecache *a_tncp; /* locked namespace / to */ + struct ucred *a_cred; +}; + /* * This structure is the post-compiled VOP operations vector. vop_ops are * typically per-mount entities. The first section is used by our vop_*() @@ -530,9 +585,8 @@ struct vop_ops { #define vop_ops_first_field vop_default int (*vop_default)(struct vop_generic_args *); int (*vop_islocked)(struct vop_islocked_args *); - int (*vop_resolve)(struct vop_resolve_args *); int (*vop_lookup)(struct vop_lookup_args *); - int (*vop_cachedlookup)(struct vop_cachedlookup_args *); + int (*vop_unused03)(void *); int (*vop_create)(struct vop_create_args *); int (*vop_whiteout)(struct vop_whiteout_args *); int (*vop_mknod)(struct vop_mknod_args *); @@ -582,8 +636,19 @@ struct vop_ops { int (*vop_destroyvobject)(struct vop_destroyvobject_args *); int (*vop_getvobject)(struct vop_getvobject_args *); int (*vop_vfsset)(struct vop_vfsset_args *); + + int (*vop_nresolve)(struct vop_nresolve_args *); + int (*vop_nlookupdotdot)(struct vop_nlookupdotdot_args *); + int (*vop_ncreate)(struct vop_ncreate_args *); + int (*vop_nmkdir)(struct vop_nmkdir_args *); + int (*vop_nmknod)(struct vop_nmknod_args *); + int (*vop_nlink)(struct vop_nlink_args *); + int (*vop_nsymlink)(struct vop_nsymlink_args *); + int (*vop_nwhiteout)(struct vop_nwhiteout_args *); int (*vop_nremove)(struct vop_nremove_args *); -#define vop_ops_last_field vop_nremove + int (*vop_nrmdir)(struct vop_nrmdir_args *); + int (*vop_nrename)(struct vop_nrename_args *); +#define vop_ops_last_field vop_nrename }; #define VVF_JOURNAL_HOOK 0x0001 /* FUTURE */ @@ -612,9 +677,7 @@ union vop_args_union { struct vop_generic_args vu_head; struct vop_generic_args vu_default; struct vop_islocked_args vu_islocked; - struct vop_resolve_args vu_resolve; struct vop_lookup_args vu_lookup; - struct vop_cachedlookup_args vu_cachedlookup; struct vop_create_args vu_create; struct vop_whiteout_args vu_whiteout; struct vop_mknod_args vu_mknod; @@ -633,7 +696,6 @@ union vop_args_union { struct vop_mmap_args vu_mmap; struct vop_fsync_args vu_fsync; struct vop_remove_args vu_remove; - struct vop_nremove_args vu_nremove; struct vop_link_args vu_link; struct vop_rename_args vu_rename; struct vop_mkdir_args vu_mkdir; @@ -665,6 +727,18 @@ union vop_args_union { struct vop_destroyvobject_args vu_destroyvobject; struct vop_getvobject_args vu_getvobject; struct vop_vfsset_args vu_vfsset; + + struct vop_nresolve_args vu_nresolve; + struct vop_nlookupdotdot_args vu_nlookupdotdot; + struct vop_ncreate_args vu_ncreate; + struct vop_nmkdir_args vu_nmkdir; + struct vop_nmknod_args vu_nmknod; + struct vop_nlink_args vu_nlink; + struct vop_nsymlink_args vu_nsymlink; + struct vop_nwhiteout_args vu_nwhiteout; + struct vop_nremove_args vu_nremove; + struct vop_nrmdir_args vu_nrmdir; + struct vop_nrename_args vu_nrename; }; #ifdef _KERNEL @@ -678,21 +752,18 @@ union vop_args_union { * in a message and dispatch it to the correct thread. */ int vop_islocked(struct vop_ops *ops, struct vnode *vp, struct thread *td); -int vop_resolve(struct vop_ops *ops, struct namecache *ncp, struct ucred *cred); int vop_lookup(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp); -int vop_cachedlookup(struct vop_ops *ops, struct vnode *dvp, - struct vnode **vpp, struct componentname *cnp); -int vop_create(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +int vop_create(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap); -int vop_whiteout(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +int vop_whiteout(struct vop_ops *ops, struct vnode *dvp, struct componentname *cnp, int flags); -int vop_mknod(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +int vop_mknod(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap); int vop_open(struct vop_ops *ops, struct vnode *vp, int mode, - struct ucred *cred, struct thread *td); + struct ucred *cred, struct file *file, struct thread *td); int vop_close(struct vop_ops *ops, struct vnode *vp, int fflag, struct thread *td); int vop_access(struct vop_ops *ops, struct vnode *vp, int mode, @@ -718,20 +789,20 @@ int vop_mmap(struct vop_ops *ops, struct vnode *vp, int fflags, struct ucred *cred, struct thread *td); int vop_fsync(struct vop_ops *ops, struct vnode *vp, int waitfor, struct thread *td); -int vop_remove(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +int vop_remove(struct vop_ops *ops, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); -int vop_link(struct vop_ops *ops, struct vnode *tdvp, struct namecache *par, +int vop_link(struct vop_ops *ops, struct vnode *tdvp, struct vnode *vp, struct componentname *cnp); -int vop_rename(struct vop_ops *ops, struct vnode *fdvp, struct namecache *fpar, +int vop_rename(struct vop_ops *ops, struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp, - struct vnode *tdvp, struct namecache *tpar, - struct vnode *tvp, struct componentname *tcnp); -int vop_mkdir(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, + struct vnode *tdvp, struct vnode *tvp, + struct componentname *tcnp); +int vop_mkdir(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap); -int vop_rmdir(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +int vop_rmdir(struct vop_ops *ops, struct vnode *dvp, struct vnode *vp, struct componentname *cnp); -int vop_symlink(struct vop_ops *ops, struct vnode *dvp, struct namecache *par, +int vop_symlink(struct vop_ops *ops, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap, char *target); int vop_readdir(struct vop_ops *ops, struct vnode *vp, struct uio *uio, @@ -782,7 +853,29 @@ int vop_getvobject(struct vop_ops *ops, struct vnode *vp, struct vm_object **objpp); int vop_vfsset(struct vop_ops *ops, int op, const char *opstr); -int vop_nremove(struct vop_ops *ops, struct namecache *ncp, struct ucred *cred); +int vop_nresolve(struct vop_ops *ops, struct namecache *ncp, + struct ucred *cred); +int vop_nlookupdotdot(struct vop_ops *ops, struct vnode *dvp, + struct vnode **vpp, struct ucred *cred); +int vop_ncreate(struct vop_ops *ops, struct namecache *ncp, + struct vnode **vpp, struct ucred *cred, struct vattr *vap); +int vop_nmkdir(struct vop_ops *ops, struct namecache *ncp, + struct vnode **vpp, struct ucred *cred, struct vattr *vap); +int vop_nmknod(struct vop_ops *ops, struct namecache *ncp, + struct vnode **vpp, struct ucred *cred, struct vattr *vap); +int vop_nlink(struct vop_ops *ops, struct namecache *ncp, struct vnode *vp, + struct ucred *cred); +int vop_nsymlink(struct vop_ops *ops, struct namecache *ncp, + struct vnode **vpp, struct ucred *cred, + struct vattr *vap, char *target); +int vop_nwhiteout(struct vop_ops *ops, struct namecache *ncp, + struct ucred *cred, int flags); +int vop_nremove(struct vop_ops *ops, struct namecache *ncp, + struct ucred *cred); +int vop_nrmdir(struct vop_ops *ops, struct namecache *ncp, + struct ucred *cred); +int vop_nrename(struct vop_ops *ops, struct namecache *fncp, + struct namecache *tncp, struct ucred *cred); /* * Kernel VOP forwarding wrappers. These are called when a VFS such as @@ -795,9 +888,7 @@ int vop_nremove(struct vop_ops *ops, struct namecache *ncp, struct ucred *cred); */ int vop_vnoperate_ap(struct vop_generic_args *ap); int vop_islocked_ap(struct vop_islocked_args *ap); -int vop_resolve_ap(struct vop_resolve_args *ap); int vop_lookup_ap(struct vop_lookup_args *ap); -int vop_cachedlookup_ap(struct vop_cachedlookup_args *ap); int vop_create_ap(struct vop_create_args *ap); int vop_whiteout_ap(struct vop_whiteout_args *ap); int vop_mknod_ap(struct vop_mknod_args *ap); @@ -816,7 +907,6 @@ int vop_revoke_ap(struct vop_revoke_args *ap); int vop_mmap_ap(struct vop_mmap_args *ap); int vop_fsync_ap(struct vop_fsync_args *ap); int vop_remove_ap(struct vop_remove_args *ap); -int vop_nremove_ap(struct vop_nremove_args *ap); int vop_link_ap(struct vop_link_args *ap); int vop_rename_ap(struct vop_rename_args *ap); int vop_mkdir_ap(struct vop_mkdir_args *ap); @@ -849,6 +939,18 @@ int vop_destroyvobject_ap(struct vop_destroyvobject_args *ap); int vop_getvobject_ap(struct vop_getvobject_args *ap); int vop_vfsset_ap(struct vop_vfsset_args *ap); +int vop_nresolve_ap(struct vop_nresolve_args *ap); +int vop_nlookupdotdot_ap(struct vop_nlookupdotdot_args *ap); +int vop_ncreate_ap(struct vop_ncreate_args *ap); +int vop_nmkdir_ap(struct vop_nmkdir_args *ap); +int vop_nmknod_ap(struct vop_nmknod_args *ap); +int vop_nlink_ap(struct vop_nlink_args *ap); +int vop_nsymlink_ap(struct vop_nsymlink_args *ap); +int vop_nwhiteout_ap(struct vop_nwhiteout_args *ap); +int vop_nremove_ap(struct vop_nremove_args *ap); +int vop_nrmdir_ap(struct vop_nrmdir_args *ap); +int vop_nrename_ap(struct vop_nrename_args *ap); + /* * VOP operations descriptor. This is used by the vop_ops compiler * to convert VFS vector arrays (typically in vfs/blah/blah_vnops.c) @@ -856,9 +958,7 @@ int vop_vfsset_ap(struct vop_vfsset_args *ap); */ extern struct vnodeop_desc vop_default_desc; extern struct vnodeop_desc vop_islocked_desc; -extern struct vnodeop_desc vop_resolve_desc; extern struct vnodeop_desc vop_lookup_desc; -extern struct vnodeop_desc vop_cachedlookup_desc; extern struct vnodeop_desc vop_create_desc; extern struct vnodeop_desc vop_whiteout_desc; extern struct vnodeop_desc vop_mknod_desc; @@ -877,7 +977,6 @@ extern struct vnodeop_desc vop_revoke_desc; extern struct vnodeop_desc vop_mmap_desc; extern struct vnodeop_desc vop_fsync_desc; extern struct vnodeop_desc vop_remove_desc; -extern struct vnodeop_desc vop_nremove_desc; extern struct vnodeop_desc vop_link_desc; extern struct vnodeop_desc vop_rename_desc; extern struct vnodeop_desc vop_mkdir_desc; @@ -910,27 +1009,28 @@ extern struct vnodeop_desc vop_destroyvobject_desc; extern struct vnodeop_desc vop_getvobject_desc; extern struct vnodeop_desc vop_vfsset_desc; +extern struct vnodeop_desc vop_nresolve_desc; +extern struct vnodeop_desc vop_nlookupdotdot_desc; +extern struct vnodeop_desc vop_ncreate_desc; +extern struct vnodeop_desc vop_nmkdir_desc; +extern struct vnodeop_desc vop_nmknod_desc; +extern struct vnodeop_desc vop_nlink_desc; +extern struct vnodeop_desc vop_nsymlink_desc; +extern struct vnodeop_desc vop_nwhiteout_desc; +extern struct vnodeop_desc vop_nremove_desc; +extern struct vnodeop_desc vop_nrmdir_desc; +extern struct vnodeop_desc vop_nrename_desc; + #endif /* - * VOP_ macro compatibility. Remove these as we get rid of the VOP macros. - * We have to convert the VOP macros into the vop_*() version that requires - * the appropriate v_ops structure pointer for the first arg. + * VOP_*() convenience macros extract the operations vector and make the + * vop_*() call. */ #define VOP_ISLOCKED(vp, td) \ vop_islocked((vp)->v_ops, vp, td) -#define VOP_LOOKUP(dvp, vpp, cnp) \ - vop_lookup((dvp)->v_ops, dvp, vpp, cnp) -#define VOP_CACHEDLOOKUP(dvp, vpp, cnp) \ - vop_cachedlookup((dvp)->v_ops, dvp, vpp, cnp) -#define VOP_CREATE(dvp, par, vpp, cnp, vap) \ - vop_create((dvp)->v_ops, dvp, par, vpp, cnp, vap) -#define VOP_WHITEOUT(dvp, par, cnp, flags) \ - vop_whiteout((dvp)->v_ops, dvp, par, cnp, flags) -#define VOP_MKNOD(dvp, par, vpp, cnp, vap) \ - vop_mknod((dvp)->v_ops, dvp, par, vpp, cnp, vap) -#define VOP_OPEN(vp, mode, cred, td) \ - vop_open((vp)->v_ops, vp, mode, cred, td) +#define VOP_OPEN(vp, mode, cred, fp, td) \ + vop_open((vp)->v_ops, vp, mode, cred, fp, td) #define VOP_CLOSE(vp, fflag, td) \ vop_close((vp)->v_ops, vp, fflag, td) #define VOP_ACCESS(vp, mode, cred, td) \ @@ -957,18 +1057,6 @@ extern struct vnodeop_desc vop_vfsset_desc; vop_mmap((vp)->v_ops, vp, fflags, cred, td) #define VOP_FSYNC(vp, waitfor, td) \ vop_fsync((vp)->v_ops, vp, waitfor, td) -#define VOP_REMOVE(dvp, par, vp, cnp) \ - vop_remove((dvp)->v_ops, dvp, par, vp, cnp) -#define VOP_LINK(tdvp, par, vp, cnp) \ - vop_link((tdvp)->v_ops, tdvp, par, vp, cnp) -#define VOP_RENAME(fdvp, fpar, fvp, fcnp, tdvp, tpar, tvp, tcnp) \ - vop_rename((fdvp)->v_ops, fdvp, fpar, fvp, fcnp, tdvp, tpar, tvp, tcnp) -#define VOP_MKDIR(dvp, par, vpp, cnp, vap) \ - vop_mkdir((dvp)->v_ops, dvp, par, vpp, cnp, vap) -#define VOP_RMDIR(dvp, par, vp, cnp) \ - vop_rmdir((dvp)->v_ops, dvp, par, vp, cnp) -#define VOP_SYMLINK(dvp, par, vpp, cnp, vap, target) \ - vop_symlink((dvp)->v_ops, dvp, par, vpp, cnp, vap, target) #define VOP_READDIR(vp, uio, cred, eofflag, ncookies, cookies) \ vop_readdir((vp)->v_ops, vp, uio, cred, eofflag, ncookies, cookies) #define VOP_READLINK(vp, uio, cred) \ @@ -1021,5 +1109,61 @@ extern struct vnodeop_desc vop_vfsset_desc; vop_getvobject((vp)->v_ops, vp, objpp) /* no VOP_VFSSET() */ +/* + * 'OLD' VOP calls. These calls may only be made by the new API + * compatibility functions in kern/vfs_default.c. Attempting to + * call these functions directly will confuse the namecache. These + * calls are deprecated and being removed from the system and from + * the VFS's. + */ +#define VOP_OLD_LOOKUP(dvp, vpp, cnp) \ + vop_lookup((dvp)->v_ops, dvp, vpp, cnp) +#define VOP_OLD_CREATE(dvp, vpp, cnp, vap) \ + vop_create((dvp)->v_ops, dvp, vpp, cnp, vap) +#define VOP_OLD_MKDIR(dvp, vpp, cnp, vap) \ + vop_mkdir((dvp)->v_ops, dvp, vpp, cnp, vap) +#define VOP_OLD_MKNOD(dvp, vpp, cnp, vap) \ + vop_mknod((dvp)->v_ops, dvp, vpp, cnp, vap) +#define VOP_OLD_LINK(tdvp, vp, cnp) \ + vop_link((tdvp)->v_ops, tdvp, vp, cnp) +#define VOP_OLD_SYMLINK(dvp, vpp, cnp, vap, target) \ + vop_symlink((dvp)->v_ops, dvp, vpp, cnp, vap, target) +#define VOP_OLD_WHITEOUT(dvp, cnp, flags) \ + vop_whiteout((dvp)->v_ops, dvp, cnp, flags) +#define VOP_OLD_RENAME(fdvp, fvp, fcnp, tdvp, tvp, tcnp) \ + vop_rename((fdvp)->v_ops, fdvp, fvp, fcnp, tdvp, tvp, tcnp) +#define VOP_OLD_RMDIR(dvp, vp, cnp) \ + vop_rmdir((dvp)->v_ops, dvp, vp, cnp) +#define VOP_OLD_REMOVE(dvp, vp, cnp) \ + vop_remove((dvp)->v_ops, dvp, vp, cnp) + +/* + * 'NEW' VOP calls. These calls use namespaces as an operational basis + * rather then vnodes and replace the OLD calls. Eventually all VFS's + * will support these calls. Those that do not fall through to compatibility + * code in kern/vfs_default which does the magic required to call the old + * routines. + */ +#define VOP_NRESOLVE(ncp, cred) \ + vop_nresolve((ncp)->nc_mount->mnt_vn_ops, ncp, cred) +#define VOP_NCREATE(ncp, vpp, cred, vap) \ + vop_ncreate((ncp)->nc_mount->mnt_vn_ops, ncp, vpp, cred, vap) +#define VOP_NMKDIR(ncp, vpp, cred, vap) \ + vop_nmkdir((ncp)->nc_mount->mnt_vn_ops, ncp, vpp, cred, vap) +#define VOP_NMKNOD(ncp, vpp, cred, vap) \ + vop_nmknod((ncp)->nc_mount->mnt_vn_ops, ncp, vpp, cred, vap) +#define VOP_NLINK(ncp, vp, cred) \ + vop_nlink((ncp)->nc_mount->mnt_vn_ops, ncp, vp, cred) +#define VOP_NSYMLINK(ncp, vpp, cred, vap, target) \ + vop_nsymlink((ncp)->nc_mount->mnt_vn_ops, ncp, vpp, cred, vap, target) +#define VOP_NWHITEOUT(ncp, cred, flags) \ + vop_nwhiteout((ncp)->nc_mount->mnt_vn_ops, ncp, cred, flags) +#define VOP_NRENAME(fncp, tncp, cred) \ + vop_nrename((fncp)->nc_mount->mnt_vn_ops, fncp, tncp, cred) +#define VOP_NRMDIR(ncp, cred) \ + vop_nrmdir((ncp)->nc_mount->mnt_vn_ops, ncp, cred) +#define VOP_NREMOVE(ncp, cred) \ + vop_nremove((ncp)->nc_mount->mnt_vn_ops, ncp, cred) + #endif diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 7ab06a2d4e..5ace2ee7f7 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -32,7 +32,7 @@ * * @(#)vnode.h 8.7 (Berkeley) 2/4/94 * $FreeBSD: src/sys/sys/vnode.h,v 1.111.2.19 2002/12/29 18:19:53 dillon Exp $ - * $DragonFly: src/sys/sys/vnode.h,v 1.25 2004/10/12 19:20:48 dillon Exp $ + * $DragonFly: src/sys/sys/vnode.h,v 1.26 2004/11/12 00:09:27 dillon Exp $ */ #ifndef _SYS_VNODE_H_ @@ -279,6 +279,7 @@ extern struct vattr va_null; /* predefined null vattr structure */ extern int vfs_ioopt; extern int numvnodes; extern int freevnodes; +extern int vfs_fastdev; /* fast specfs device access */ /* * Macro/function to check for client cache inconsistency w.r.t. leasing. @@ -496,7 +497,7 @@ vn_canvmio(struct vnode *vp) */ struct file; struct mount; -struct nameidata; +struct nlookupdata; struct ostat; struct proc; struct thread; @@ -555,8 +556,9 @@ int debug_vn_lock (struct vnode *vp, int flags, struct thread *td, #define vn_lock(vp,flags,p) debug_vn_lock(vp,flags,p,__FILE__,__LINE__) #endif +void vn_setspecops (struct file *fp); int vn_fullpath (struct proc *p, struct vnode *vn, char **retbuf, char **freebuf); -int vn_open (struct nameidata *ndp, int fmode, int cmode); +int vn_open (struct nlookupdata *ndp, struct file *fp, int fmode, int cmode); void vn_pollevent (struct vnode *vp, int events); void vn_pollgone (struct vnode *vp); int vn_pollrecord (struct vnode *vp, struct thread *td, int events); @@ -576,7 +578,6 @@ int vop_stdislocked (struct vop_islocked_args *ap); int vop_stdlock (struct vop_lock_args *ap); int vop_stdrlock (struct vop_lock_args *ap); int vop_stdunlock (struct vop_unlock_args *ap); -int vop_noresolve(struct vop_resolve_args *ap); int vop_nopoll (struct vop_poll_args *ap); int vop_stdpathconf (struct vop_pathconf_args *ap); int vop_stdpoll (struct vop_poll_args *ap); @@ -592,6 +593,18 @@ int vop_stdcreatevobject (struct vop_createvobject_args *ap); int vop_stddestroyvobject (struct vop_destroyvobject_args *ap); int vop_stdgetvobject (struct vop_getvobject_args *ap); +int vop_compat_nresolve(struct vop_nresolve_args *ap); +int vop_compat_nlookupdotdot(struct vop_nlookupdotdot_args *ap); +int vop_compat_ncreate(struct vop_ncreate_args *ap); +int vop_compat_nmkdir(struct vop_nmkdir_args *ap); +int vop_compat_nmknod(struct vop_nmknod_args *ap); +int vop_compat_nlink(struct vop_nlink_args *ap); +int vop_compat_nsymlink(struct vop_nsymlink_args *ap); +int vop_compat_nwhiteout(struct vop_nwhiteout_args *ap); +int vop_compat_nremove(struct vop_nremove_args *ap); +int vop_compat_nrmdir(struct vop_nrmdir_args *ap); +int vop_compat_nrename(struct vop_nrename_args *ap); + int vx_lock (struct vnode *vp); void vx_unlock (struct vnode *vp); int vx_get (struct vnode *vp); diff --git a/sys/vfs/coda/coda_fbsd.c b/sys/vfs/coda/coda_fbsd.c index 874b07af30..abcb2b5231 100644 --- a/sys/vfs/coda/coda_fbsd.c +++ b/sys/vfs/coda/coda_fbsd.c @@ -28,7 +28,7 @@ * * @(#) src/sys/coda/coda_fbsd.cr,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ * $FreeBSD: src/sys/coda/coda_fbsd.c,v 1.18 1999/09/25 18:23:43 phk Exp $ - * $DragonFly: src/sys/vfs/coda/Attic/coda_fbsd.c,v 1.7 2004/05/19 22:53:03 dillon Exp $ + * $DragonFly: src/sys/vfs/coda/Attic/coda_fbsd.c,v 1.8 2004/11/12 00:09:28 dillon Exp $ * */ @@ -140,7 +140,7 @@ coda_fbsd_getpages(void *v) if (cfvp == NULL) { opened_internally = 1; - error = VOP_OPEN(vp, FREAD, cred, p); + error = VOP_OPEN(vp, FREAD, cred, NULL, p); printf("coda_getp: Internally Opening %p\n", vp); if (error) { diff --git a/sys/vfs/coda/coda_vfsops.c b/sys/vfs/coda/coda_vfsops.c index 6c33998272..7b5457221b 100644 --- a/sys/vfs/coda/coda_vfsops.c +++ b/sys/vfs/coda/coda_vfsops.c @@ -28,7 +28,7 @@ * * @(#) src/sys/cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ * $FreeBSD: src/sys/coda/coda_vfsops.c,v 1.24.2.1 2001/07/26 20:36:45 iedowse Exp $ - * $DragonFly: src/sys/vfs/coda/Attic/coda_vfsops.c,v 1.17 2004/10/12 19:20:50 dillon Exp $ + * $DragonFly: src/sys/vfs/coda/Attic/coda_vfsops.c,v 1.18 2004/11/12 00:09:28 dillon Exp $ * */ @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include @@ -123,7 +123,7 @@ coda_mount(struct mount *vfsp, /* Allocated and initialized by mount(2) */ ViceFid rootfid; ViceFid ctlfid; int error; - struct nameidata nd; + struct nlookupdata nd; ENTRY; @@ -137,10 +137,13 @@ coda_mount(struct mount *vfsp, /* Allocated and initialized by mount(2) */ } /* Validate mount device. Similar to getmdev(). */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, data, td); - error = namei(&nd); - dvp = nd.ni_vp; - + dvp = NULL; + error = nlookup_init(&nd, data, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &dvp); + nlookup_done(&nd); if (error) { MARK_INT_FAIL(CODA_MOUNT_STATS); return (error); @@ -148,12 +151,10 @@ coda_mount(struct mount *vfsp, /* Allocated and initialized by mount(2) */ if (dvp->v_type != VCHR) { MARK_INT_FAIL(CODA_MOUNT_STATS); vrele(dvp); - NDFREE(&nd, NDF_ONLY_PNBUF); return(ENXIO); } udev = dvp->v_udev; vrele(dvp); - NDFREE(&nd, NDF_ONLY_PNBUF); #if 0 /* YYY huh? what paranoia is this? */ /* diff --git a/sys/vfs/coda/coda_vnops.c b/sys/vfs/coda/coda_vnops.c index 79092881fe..827191642b 100644 --- a/sys/vfs/coda/coda_vnops.c +++ b/sys/vfs/coda/coda_vnops.c @@ -28,7 +28,7 @@ * * @(#) src/sys/coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ * $FreeBSD: src/sys/coda/coda_vnops.c,v 1.22.2.1 2001/06/29 16:26:22 shafeeq Exp $ - * $DragonFly: src/sys/vfs/coda/Attic/coda_vnops.c,v 1.22 2004/10/12 19:20:50 dillon Exp $ + * $DragonFly: src/sys/vfs/coda/Attic/coda_vnops.c,v 1.23 2004/11/12 00:09:28 dillon Exp $ * */ @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -162,7 +163,7 @@ struct vnodeopv_entry_desc coda_vnodeop_entries[] = { missing { &vop_reallocblks_desc, (void *) ufs_missingop }, - { &vop_cachedlookup_desc, (void *) ufs_lookup }, + { &vop_lookup_desc, (void *) ufs_lookup }, { &vop_whiteout_desc, (void *) ufs_whiteout }, #endif { NULL, NULL } @@ -291,7 +292,7 @@ coda_open(void *v) cp->c_inode = inode; /* Open the cache file. */ - error = VOP_OPEN(vp, flag, cred, td); + error = VOP_OPEN(vp, flag, cred, NULL, td); if (error) { printf("coda_open: VOP_OPEN on container failed %d\n", error); return (error); @@ -442,7 +443,7 @@ coda_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw rw, int ioflag, opened_internally = 1; MARK_INT_GEN(CODA_OPEN_STATS); error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE), - cred, td); + cred, NULL, td); printf("coda_rdwr: Internally Opening %p\n", vp); if (error) { printf("coda_rdwr: VOP_OPEN on container failed %d\n", error); @@ -514,7 +515,7 @@ coda_ioctl(void *v) /* locals */ int error; struct vnode *tvp; - struct nameidata ndp; + struct nlookupdata nd; struct PioctlData *iap = (struct PioctlData *)data; MARK_ENTRY(CODA_IOCTL_STATS); @@ -535,9 +536,14 @@ coda_ioctl(void *v) /* Should we use the name cache here? It would get it from lookupname sooner or later anyway, right? */ - NDINIT(&ndp, NAMEI_LOOKUP, (iap->follow ? CNP_FOLLOW : 0), UIO_USERSPACE, iap->path, td); - error = namei(&ndp); - tvp = ndp.ni_vp; + tvp = NULL; + error = nlookup_init(&nd, iap->path, UIO_USERSPACE, + (iap->follow ? NLC_FOLLOW : 0)); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &tvp); + nlookup_done(&nd); if (error) { MARK_INT_FAIL(CODA_IOCTL_STATS); @@ -552,7 +558,6 @@ coda_ioctl(void *v) */ if (tvp->v_tag != VT_CODA) { vrele(tvp); - NDFREE(&ndp, NDF_ONLY_PNBUF); MARK_INT_FAIL(CODA_IOCTL_STATS); CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: %s not a coda object\n", @@ -561,7 +566,7 @@ coda_ioctl(void *v) } if (iap->vi.in_size > VC_MAXDATASIZE) { - NDFREE(&ndp, 0); + vrele(tvp); return(EINVAL); } error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag, data, cred, td); @@ -572,7 +577,6 @@ coda_ioctl(void *v) CODADEBUG(CODA_IOCTL, myprintf(("Ioctl returns %d \n", error)); ) vrele(tvp); - NDFREE(&ndp, NDF_ONLY_PNBUF); return(error); } @@ -1011,32 +1015,13 @@ coda_lookup(void *v) * we need to save the last component of the name. (Create will * have to free the name buffer later...lucky us...) */ - if (((cnp->cn_nameiop == NAMEI_CREATE) || (cnp->cn_nameiop == NAMEI_RENAME)) - && (cnp->cn_flags & CNP_ISLASTCN) - && (error == ENOENT)) + if ((cnp->cn_nameiop == NAMEI_CREATE || cnp->cn_nameiop == NAMEI_RENAME) + && error == ENOENT) { error = EJUSTRETURN; - cnp->cn_flags |= CNP_SAVENAME; *ap->a_vpp = NULL; } - /* - * If we are removing, and we are at the last element, and we - * found it, then we need to keep the name around so that the - * removal will go ahead as planned. Unfortunately, this will - * probably also lock the to-be-removed vnode, which may or may - * not be a good idea. I'll have to look at the bits of - * coda_remove to make sure. We'll only save the name if we did in - * fact find the name, otherwise coda_remove won't have a chance - * to free the pathname. - */ - if ((cnp->cn_nameiop == NAMEI_DELETE) - && (cnp->cn_flags & CNP_ISLASTCN) - && !error) - { - cnp->cn_flags |= CNP_SAVENAME; - } - /* * If the lookup went well, we need to (potentially?) unlock the * parent, and lock the child. We are only responsible for @@ -1047,7 +1032,7 @@ coda_lookup(void *v) * we are ISLASTCN */ if (!error || (error == EJUSTRETURN)) { - if (!(cnp->cn_flags & CNP_LOCKPARENT) || !(cnp->cn_flags & CNP_ISLASTCN)) { + if ((cnp->cn_flags & CNP_LOCKPARENT) == 0) { if ((error = VOP_UNLOCK(dvp, 0, td))) { return error; } @@ -1152,17 +1137,10 @@ coda_create(void *v) } if (!error) { - if (cnp->cn_flags & CNP_LOCKLEAF) { - if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) { - printf("coda_create: "); - panic("unlocked parent but couldn't lock child"); - } - } -#ifdef OLD_DIAGNOSTIC - else { - printf("coda_create: LOCKLEAF not set!\n"); + if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) { + printf("coda_create: "); + panic("unlocked parent but couldn't lock child"); } -#endif } return(error); } @@ -1350,8 +1328,6 @@ coda_rename(void *v) exit: CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error));) - /* XXX - do we need to call cache pureg on the moved vnode? */ - cache_purge(ap->a_fvp); /* It seems to be incumbent on us to drop locks on all four vnodes */ /* From-vnodes are not locked, only ref'd. To-vnodes are locked. */ @@ -1596,7 +1572,7 @@ coda_readdir(void *v) if (cp->c_ovp == NULL) { opened_internally = 1; MARK_INT_GEN(CODA_OPEN_STATS); - error = VOP_OPEN(vp, FREAD, cred, td); + error = VOP_OPEN(vp, FREAD, cred, NULL, td); printf("coda_readdir: Internally Opening %p\n", vp); if (error) { printf("coda_readdir: VOP_OPEN on container failed %d\n", error); diff --git a/sys/vfs/gnu/ext2fs/ext2_extern.h b/sys/vfs/gnu/ext2fs/ext2_extern.h index a6b765d226..be60465a9c 100644 --- a/sys/vfs/gnu/ext2fs/ext2_extern.h +++ b/sys/vfs/gnu/ext2fs/ext2_extern.h @@ -38,7 +38,7 @@ * * @(#)ffs_extern.h 8.3 (Berkeley) 4/16/94 * $FreeBSD: src/sys/gnu/ext2fs/ext2_extern.h,v 1.22.6.1 2000/11/05 19:17:40 bde Exp $ - * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_extern.h,v 1.6 2004/08/17 18:57:33 dillon Exp $ + * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_extern.h,v 1.7 2004/11/12 00:09:30 dillon Exp $ */ #ifndef _SYS_GNU_EXT2FS_EXT2_EXTERN_H_ @@ -67,7 +67,7 @@ int ext2_truncate (struct vnode *, off_t, int, struct ucred *, struct thread *); int ext2_update (struct vnode *, int); int ext2_valloc (struct vnode *, int, struct ucred *, struct vnode **); int ext2_vfree (struct vnode *, ino_t, int); -int ext2_lookup (struct vop_cachedlookup_args *); +int ext2_lookup (struct vop_lookup_args *); int ext2_readdir (struct vop_readdir_args *); void ext2_print_dinode (struct dinode *); void ext2_print_inode (struct inode *); diff --git a/sys/vfs/gnu/ext2fs/ext2_lookup.c b/sys/vfs/gnu/ext2fs/ext2_lookup.c index 19461a33b6..28f14f1621 100644 --- a/sys/vfs/gnu/ext2fs/ext2_lookup.c +++ b/sys/vfs/gnu/ext2fs/ext2_lookup.c @@ -5,7 +5,7 @@ * University of Utah, Department of Computer Science * * $FreeBSD: src/sys/gnu/ext2fs/ext2_lookup.c,v 1.21.2.3 2002/11/17 02:02:42 bde Exp $ - * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_lookup.c,v 1.15 2004/10/12 19:20:55 dillon Exp $ + * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_lookup.c,v 1.16 2004/11/12 00:09:30 dillon Exp $ */ /* * Copyright (c) 1989, 1993 @@ -289,7 +289,7 @@ ext2_readdir(struct vop_readdir_args *ap) * struct componentname *a_cnp) */ int -ext2_lookup(struct vop_cachedlookup_args *ap) +ext2_lookup(struct vop_lookup_args *ap) { struct vnode *vdp; /* vnode for directory being searched */ struct inode *dp; /* inode for directory being searched */ @@ -341,8 +341,7 @@ ext2_lookup(struct vop_cachedlookup_args *ap) */ slotstatus = FOUND; slotfreespace = slotsize = slotneeded = 0; - if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && - (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) { slotstatus = NONE; slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen); /* was @@ -492,7 +491,7 @@ searchloop: * allowing file to be created. */ if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && - (flags & CNP_ISLASTCN) && dp->i_nlink != 0) { + dp->i_nlink != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. @@ -533,16 +532,10 @@ searchloop: * NB - if the directory is unlocked, then this * information cannot be used. */ - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) VOP_UNLOCK(vdp, 0, td); return (EJUSTRETURN); } - /* - * Insert name into cache (as non-existent) if appropriate. - */ - if ((cnp->cn_flags & CNP_MAKEENTRY) && nameiop != NAMEI_CREATE) - cache_enter(vdp, *vpp, cnp); return (ENOENT); found: @@ -565,7 +558,7 @@ found: * If the final component of path name, save information * in the cache as to where the entry was found. */ - if ((flags & CNP_ISLASTCN) && nameiop == NAMEI_LOOKUP) + if (nameiop == NAMEI_LOOKUP) dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1); /* @@ -575,7 +568,7 @@ found: * the directory (in ndp->ni_dvp), otherwise we go * on and lock the inode, being careful with ".". */ - if (nameiop == NAMEI_DELETE && (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_DELETE) { /* * Write access to directory required to delete files. */ @@ -623,8 +616,7 @@ found: * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ - if (nameiop == NAMEI_RENAME && wantparent && - (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_RENAME && wantparent) { if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0) return (error); /* @@ -636,7 +628,6 @@ found: if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) return (error); *vpp = tdp; - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) VOP_UNLOCK(vdp, 0, td); return (0); @@ -668,8 +659,7 @@ found: vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td); return (error); } - if (lockparent && (flags & CNP_ISLASTCN) && - (error = vn_lock(pdp, LK_EXCLUSIVE, td))) { + if (lockparent && (error = vn_lock(pdp, LK_EXCLUSIVE, td))) { vput(tdp); return (error); } @@ -680,16 +670,10 @@ found: } else { if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) return (error); - if (!lockparent || !(flags & CNP_ISLASTCN)) + if (!lockparent) VOP_UNLOCK(pdp, 0, td); *vpp = tdp; } - - /* - * Insert name into cache if appropriate. - */ - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(vdp, *vpp, cnp); return (0); } @@ -736,9 +720,9 @@ ext2_dirbadentry(struct vnode *dp, struct ext2_dir_entry_2 *de, /* * Write a directory entry after a call to namei, using the parameters - * that it left in nameidata. The argument ip is the inode which the new - * directory entry will refer to. Dvp is a pointer to the directory to - * be written, which was left locked by namei. Remaining parameters + * that it left in the directory inode. The argument ip is the inode which + * the new directory entry will refer to. Dvp is a pointer to the directory + * to be written, which was left locked by namei. Remaining parameters * (dp->i_offset, dp->i_count) indicate how the space for the new * entry is to be obtained. */ @@ -757,10 +741,6 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp) int DIRBLKSIZ = ip->i_e2fs->s_blocksize; -#if DIAGNOSTIC - if ((cnp->cn_flags & CNP_SAVENAME) == 0) - panic("direnter: missing name"); -#endif dp = VTOI(dvp); newdir.inode = ip->i_number; newdir.name_len = cnp->cn_namelen; @@ -876,7 +856,7 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp) /* * Remove a directory entry after a call to namei, using - * the parameters which it left in nameidata. The entry + * the parameters which it left in the directory inode. The entry * dp->i_offset contains the offset into the directory of the * entry to be eliminated. The dp->i_count field contains the * size of the previous record in the directory. If this diff --git a/sys/vfs/gnu/ext2fs/ext2_vfsops.c b/sys/vfs/gnu/ext2fs/ext2_vfsops.c index 44eb43ab98..e54f392f42 100644 --- a/sys/vfs/gnu/ext2fs/ext2_vfsops.c +++ b/sys/vfs/gnu/ext2fs/ext2_vfsops.c @@ -38,14 +38,14 @@ * * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94 * $FreeBSD: src/sys/gnu/ext2fs/ext2_vfsops.c,v 1.63.2.7 2002/07/01 00:18:51 iedowse Exp $ - * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vfsops.c,v 1.21 2004/10/12 19:20:55 dillon Exp $ + * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vfsops.c,v 1.22 2004/11/12 00:09:30 dillon Exp $ */ #include "opt_quota.h" #include #include -#include +#include #include #include #include @@ -195,7 +195,7 @@ ext2_mount(struct mount *mp, char *path, int error, flags; mode_t accessmode; struct ucred *cred; - struct nameidata nd; + struct nlookupdata nd; if ((error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) != 0) return (error); @@ -274,11 +274,15 @@ ext2_mount(struct mount *mp, char *path, * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); - if ((error = namei(&nd)) != 0) + devvp = NULL; + error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp); + nlookup_done(&nd); + if (error) return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - devvp = nd.ni_vp; if (!vn_isdisk(devvp, &error)) { vrele(devvp); @@ -315,14 +319,12 @@ ext2_mount(struct mount *mp, char *path, } ump = VFSTOUFS(mp); fs = ump->um_e2fs; - (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); + copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); - bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, - MNAMELEN); - (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, - &size); + bcopy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN); + copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - (void)ext2_statfs(mp, &mp->mnt_stat, td); + ext2_statfs(mp, &mp->mnt_stat, td); return (0); } @@ -660,7 +662,7 @@ ext2_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) ronly = (mp->mnt_flag & MNT_RDONLY) != 0; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td); + error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL, td); VOP_UNLOCK(devvp, 0, td); if (error) return (error); diff --git a/sys/vfs/gnu/ext2fs/ext2_vnops.c b/sys/vfs/gnu/ext2fs/ext2_vnops.c index 1cdb5faac4..3ddf83f8c7 100644 --- a/sys/vfs/gnu/ext2fs/ext2_vnops.c +++ b/sys/vfs/gnu/ext2fs/ext2_vnops.c @@ -44,7 +44,7 @@ * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95 * @(#)ext2_vnops.c 8.7 (Berkeley) 2/3/94 * $FreeBSD: src/sys/gnu/ext2fs/ext2_vnops.c,v 1.51.2.2 2003/01/02 17:26:18 bde Exp $ - * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vnops.c,v 1.16 2004/10/12 19:20:55 dillon Exp $ + * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vnops.c,v 1.17 2004/11/12 00:09:30 dillon Exp $ */ #include "opt_quota.h" @@ -99,10 +99,9 @@ static int ext2_putpages (struct vop_putpages_args *); /* Global vfs data structures for ufs. */ struct vnodeopv_entry_desc ext2_vnodeop_entries[] = { { &vop_default_desc, (void *) ufs_vnoperate }, - { &vop_cachedlookup_desc, (void *) ext2_lookup }, { &vop_fsync_desc, (void *) ext2_fsync }, { &vop_inactive_desc, (void *) ext2_inactive }, - { &vop_lookup_desc, (void *) vfs_cache_lookup }, + { &vop_lookup_desc, (void *) ext2_lookup }, { &vop_read_desc, (void *) ext2_read }, { &vop_readdir_desc, (void *) ext2_readdir }, { &vop_reallocblks_desc, (void *) ext2_reallocblks }, @@ -319,10 +318,6 @@ ext2_link(struct vop_link_args *ap) struct inode *ip; int error; -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("ufs_link: no name"); -#endif if (tdvp->v_mount != vp->v_mount) { error = EXDEV; goto out2; @@ -356,8 +351,8 @@ out2: } /* - * Rename system call. - * See comments in sys/ufs/ufs/ufs_vnops.c + * Rename system call. fdvp, fvp are ref'd. tvp, tdvp are ref'd and locked. + * all vp's are released and must be in an unlocked state on return. * * ext2_rename(struct vnode *a_fdvp, struct vnode *a_fvp, * struct componentname *a_fcnp, struct vnode *a_tdvp, @@ -379,16 +374,12 @@ ext2_rename(struct vop_rename_args *ap) int error = 0; u_char namlen; -#ifdef DIAGNOSTIC - if ((tcnp->cn_flags & CNP_HASBUF) == 0 || - (fcnp->cn_flags & CNP_HASBUF) == 0) - panic("ufs_rename: no name"); -#endif /* * Check for cross-device rename. */ if ((fvp->v_mount != tdvp->v_mount) || - (tvp && (fvp->v_mount != tvp->v_mount))) { + (tvp && (fvp->v_mount != tvp->v_mount)) || + tvp == tdvp) { error = EXDEV; abortit: if (tdvp == tvp) @@ -413,13 +404,17 @@ abortit: * not call us in that case. Temporarily just warn if they do. */ if (fvp == tvp) { - printf("ext2_rename: fvp == tvp (can't happen)\n"); error = 0; goto abortit; } if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0) goto abortit; + + /* + * fvp, tvp, tdvp locked. fdvp not locked but note that fdvp may + * be equal to tdvp. + */ dp = VTOI(fdvp); ip = VTOI(fvp); if (ip->i_nlink >= LINK_MAX) { @@ -448,16 +443,17 @@ abortit: oldparent = dp->i_number; doingdirectory++; } - vrele(fdvp); /* - * When the target exists, both the directory - * and target vnodes are returned locked. + * tvp is non-NULL if the target exists. fvp is still locked but + * we will unlock it soon. The 'bad' goto target requires dp and + * xp to be correctly assigned. */ dp = VTOI(tdvp); - xp = NULL; if (tvp) xp = VTOI(tvp); + else + xp = NULL; /* * 1) Bump link count while we're moving stuff @@ -484,23 +480,57 @@ abortit: */ error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_td); VOP_UNLOCK(fvp, 0, td); + + /* + * tvp (if not NULL) and tdvp are locked. fvp and fdvp are not. + * dp and xp are set according to tdvp and tvp. + */ if (oldparent != dp->i_number) newparent = dp->i_number; if (doingdirectory && newparent) { if (error) /* write access check above */ goto bad; - if (xp != NULL) + + /* + * Prepare for relookup, get rid of xp + */ + if (xp != NULL) { vput(tvp); + xp = NULL; + } + + /* + * checkpath vput()'s tdvp (VTOI(dp)) on return no matter what, + * get an extra ref so we wind up with just an unlocked, ref'd + * tdvp. The 'out' target skips xp and tdvp cleanups. Our + * tdvp is now unlocked so we have to clean it up ourselves. + */ + vref(tdvp); error = ext2_checkpath(ip, dp, tcnp->cn_cred); - if (error) + if (error) { + vrele(tdvp); goto out; - vref(tdvp); + } + /* + * relookup no longer messes with the ref count. An unlocked + * tdvp must be passed and if no error occurs a locked tdvp + * will be returned. We have to use the out target again. + */ error = relookup(tdvp, &tvp, tcnp); - if (error) + if (error) { + if (tcnp->cn_flags & CNP_PDIRUNLOCK) + vrele(tdvp); + else + vput(tdvp); goto out; - vrele(tdvp); + } + + /* + * tdvp is locked at this point. in the RENAME case tvp may + * be NULL without an error, assign xp accordingly. The + * 'bad' target can be used again after this. + */ dp = VTOI(tdvp); - xp = NULL; if (tvp) xp = VTOI(tvp); } @@ -510,6 +540,9 @@ abortit: * Otherwise, rewrite the target directory * entry to reference the source inode and * expunge the original entry's existence. + * + * tdvp and tvp are cleaned up by this code. tvp is only good if + * xp is not NULL. */ if (xp == NULL) { if (dp->i_dev != ip->i_dev) @@ -539,6 +572,11 @@ abortit: } goto bad; } + + /* + * manual cleanup, we can't use the bad or out target after + * this. + */ vput(tdvp); } else { if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) @@ -575,7 +613,6 @@ abortit: error = ENOTDIR; goto bad; } - cache_purge(tdvp); } else if (doingdirectory) { error = EISDIR; goto bad; @@ -593,7 +630,13 @@ abortit: dp->i_nlink--; dp->i_flag |= IN_CHANGE; } + + /* + * manual cleanup, we can't use the bad or out target after + * this. + */ vput(tdvp); + /* * Adjust the link count of the target to * reflect the dirrewrite above. If this is @@ -616,27 +659,65 @@ abortit: xp = NULL; } + /* + * tvp and tdvp have been cleaned up. The bad and out targets may + * not be used. fvp and fdvp are ref'd but not locked. ip + * still represents the old fvp and ip->i_flag may still have IN_RENAME + * set (if doingdirectory). + */ + /* * 3) Unlink the source. + * + * fdvp is locked and ref'd. ap->a_fvp holds the old lookup unlocked + * and ref'd, fvp will hold the new lookup locked and ref'd. + * + * After the relookup ap->a_fvp must be released as part of our + * cleanup, not just fdvp and fvp. And, on success, fdvp and + * fvp will be locked so the bad and out targets cannot be used. */ fcnp->cn_flags &= ~CNP_MODMASK; - fcnp->cn_flags |= CNP_LOCKPARENT | CNP_LOCKLEAF; - vref(fdvp); + fcnp->cn_flags |= CNP_LOCKPARENT; + KKASSERT(fcnp->cn_flags & CNP_PDIRUNLOCK); error = relookup(fdvp, &fvp, fcnp); - if (error == 0) - vrele(fdvp); - if (fvp != NULL) { - xp = VTOI(fvp); - dp = VTOI(fdvp); - } else { + if (error) { /* * From name has disappeared. */ if (doingdirectory) panic("ufs_rename: lost dir entry"); + /* ip->i_flag only sets IN_RENAME if doingdirectory */ vrele(ap->a_fvp); + if (fcnp->cn_flags & CNP_PDIRUNLOCK) + vrele(fdvp); + else + vput(fdvp); return (0); } + KKASSERT((fcnp->cn_flags & CNP_PDIRUNLOCK) == 0); + + /* + * This case shouldn't occur + */ + if (fvp == NULL) { + /* + * From name has disappeared. + */ + if (doingdirectory) + panic("ufs_rename: lost dir entry"); + /* ip->i_flag only sets IN_RENAME if doingdirectory */ + vrele(ap->a_fvp); + vput(fvp); + vput(fdvp); + return (0); + } + + /* + * fvp and fdvp are both ref'd and locked. + */ + xp = VTOI(fvp); + dp = VTOI(fdvp); + /* * Ensure that the directory entry still exists and has not * changed while the new name has been entered. If the source is @@ -650,6 +731,7 @@ abortit: if (xp != ip) { if (doingdirectory) panic("ufs_rename: lost dir entry"); + /* ip->i_flag only sets IN_RENAME if doingdirectory */ } else { /* * If the source is a directory with a @@ -681,7 +763,6 @@ abortit: IO_NODELOCKED|IO_SYNC, tcnp->cn_cred, (int *)0, NULL); - cache_purge(fdvp); } } } @@ -692,17 +773,16 @@ abortit: } xp->i_flag &= ~IN_RENAME; } - if (dp) - vput(fdvp); - if (xp) - vput(fvp); + vput(fdvp); + vput(fvp); vrele(ap->a_fvp); return (error); bad: if (xp) vput(ITOV(xp)); - vput(ITOV(dp)); + if (dp) + vput(ITOV(dp)); out: if (doingdirectory) ip->i_flag &= ~IN_RENAME; @@ -711,8 +791,9 @@ out: ip->i_flag |= IN_CHANGE; ip->i_flag &= ~IN_RENAME; vput(fvp); - } else + } else { vrele(fvp); + } return (error); } @@ -733,10 +814,6 @@ ext2_mkdir(struct vop_mkdir_args *ap) struct dirtemplate dirtemplate, *dtp; int error, dmode; -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("ufs_mkdir: no name"); -#endif dp = VTOI(dvp); if ((nlink_t)dp->i_nlink >= LINK_MAX) { error = EMLINK; @@ -930,7 +1007,6 @@ ext2_rmdir(struct vop_rmdir_args *ap) goto out; dp->i_nlink--; dp->i_flag |= IN_CHANGE; - cache_purge(dvp); VOP_UNLOCK(dvp, 0, td); /* * Truncate inode. The only stuff left @@ -945,7 +1021,6 @@ ext2_rmdir(struct vop_rmdir_args *ap) */ ip->i_nlink -= 2; error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td); - cache_purge(ITOV(ip)); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); out: return (error); @@ -997,10 +1072,6 @@ ext2_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, int error; pdir = VTOI(dvp); -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("ext2_makeinode: no name"); -#endif *vpp = NULL; if ((mode & IFMT) == 0) mode |= IFREG; diff --git a/sys/vfs/hpfs/hpfs_vfsops.c b/sys/vfs/hpfs/hpfs_vfsops.c index a9d14bb0bd..4ada31e148 100644 --- a/sys/vfs/hpfs/hpfs_vfsops.c +++ b/sys/vfs/hpfs/hpfs_vfsops.c @@ -24,13 +24,13 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/fs/hpfs/hpfs_vfsops.c,v 1.3.2.2 2001/12/25 01:44:45 dillon Exp $ - * $DragonFly: src/sys/vfs/hpfs/hpfs_vfsops.c,v 1.22 2004/10/12 19:20:56 dillon Exp $ + * $DragonFly: src/sys/vfs/hpfs/hpfs_vfsops.c,v 1.23 2004/11/12 00:09:33 dillon Exp $ */ #include #include -#include +#include #include #include #include @@ -93,7 +93,7 @@ static int hpfs_checkexp (struct mount *, struct sockaddr *, int *, struct ucred **); #else /* defined(__NetBSD__) */ static int hpfs_mount (struct mount *, const char *, void *, - struct nameidata *, struct proc *); + struct nlookupdata *, struct proc *); static void hpfs_init (void); static int hpfs_mountroot (void); static int hpfs_sysctl (int *, u_int, void *, size_t *, void *, @@ -169,11 +169,11 @@ hpfs_mount(struct mount *mp, struct thread *td) { u_int size; - int err = 0; + int error; struct vnode *devvp; struct hpfs_args args; struct hpfsmount *hpmp = 0; - struct nameidata nd; + struct nlookupdata nd; dprintf(("hpfs_mount():\n")); /* @@ -183,8 +183,8 @@ hpfs_mount(struct mount *mp, */ /* copy in user arguments*/ - err = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); - if (err) + error = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); + if (error) goto error_1; /* can't get arguments*/ /* @@ -198,15 +198,15 @@ hpfs_mount(struct mount *mp, if (args.fspec == 0) { dprintf(("export 0x%x\n",args.export.ex_flags)); - err = vfs_export(mp, &hpmp->hpm_export, &args.export); - if (err) { + error = vfs_export(mp, &hpmp->hpm_export, &args.export); + if (error) { printf("hpfs_mount: vfs_export failed %d\n", - err); + error); } goto success; } else { dprintf(("name [FAILED]\n")); - err = EINVAL; + error = EINVAL; goto success; } dprintf(("\n")); @@ -216,26 +216,26 @@ hpfs_mount(struct mount *mp, * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); - err = namei(&nd); - if (err) { - /* can't get devvp!*/ + devvp = NULL; + error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp); + nlookup_done(&nd); + if (error) goto error_1; - } - - devvp = nd.ni_vp; - /* XXX NDFREE */ #if defined(__DragonFly__) - if (!vn_isdisk(devvp, &err)) + if (!vn_isdisk(devvp, &error)) goto error_2; #else /* defined(__NetBSD__) */ if (devvp->v_type != VBLK) { - err = ENOTBLK; + error = ENOTBLK; goto error_2; } if (umajor(devvp->v_udev) >= nblkdev) { - err = ENXIO; + error = ENXIO; goto error_2; } #endif @@ -266,8 +266,8 @@ hpfs_mount(struct mount *mp, &size); /* real size*/ bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - err = hpfs_mountfs(devvp, mp, &args, td); - if (err) + error = hpfs_mountfs(devvp, mp, &args, td); + if (error) goto error_2; /* @@ -276,10 +276,8 @@ hpfs_mount(struct mount *mp, * * This code is common to root and non-root mounts */ - (void)VFS_STATFS(mp, &mp->mnt_stat, td); - - goto success; - + VFS_STATFS(mp, &mp->mnt_stat, td); + return (error); error_2: /* error with devvp held*/ @@ -289,7 +287,7 @@ error_2: /* error with devvp held*/ error_1: /* no state to back out*/ success: - return( err); + return (error); } /* @@ -337,7 +335,7 @@ hpfs_mountfs(struct vnode *devvp, struct mount *mp, struct hpfs_args *argsp, ronly = (mp->mnt_flag & MNT_RDONLY) != 0; VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td); + error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL, td); VOP__UNLOCK(devvp, 0, td); if (error) return (error); diff --git a/sys/vfs/hpfs/hpfs_vnops.c b/sys/vfs/hpfs/hpfs_vnops.c index 6b1b778d4e..141c85338c 100644 --- a/sys/vfs/hpfs/hpfs_vnops.c +++ b/sys/vfs/hpfs/hpfs_vnops.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/fs/hpfs/hpfs_vnops.c,v 1.2.2.2 2002/01/15 18:35:09 semenu Exp $ - * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.20 2004/10/12 19:20:56 dillon Exp $ + * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.21 2004/11/12 00:09:33 dillon Exp $ */ #include @@ -1147,13 +1147,12 @@ hpfs_lookup(struct vop_lookup_args *ap) error = VFS_VGET(hpmp->hpm_mp, dhp->h_fn.fn_parent, ap->a_vpp); - if(error) { + if (error) { VOP__LOCK(dvp, 0, cnp->cn_td); return(error); } - if( lockparent && (flags & CNP_ISLASTCN) && - (error = VOP__LOCK(dvp, 0, cnp->cn_td)) ) { + if (lockparent && (error = VOP__LOCK(dvp, 0, cnp->cn_td))) { vput( *(ap->a_vpp) ); return (error); } @@ -1166,11 +1165,10 @@ hpfs_lookup(struct vop_lookup_args *ap) error = hpfs_genlookupbyname(dhp, cnp->cn_nameptr, cnp->cn_namelen, &bp, &dep); if (error) { - if ((error == ENOENT) && (flags & CNP_ISLASTCN) && + if (error == ENOENT && (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME)) { if(!lockparent) VOP__UNLOCK(dvp, 0, cnp->cn_td); - cnp->cn_flags |= CNP_SAVENAME; return (EJUSTRETURN); } @@ -1180,7 +1178,7 @@ hpfs_lookup(struct vop_lookup_args *ap) dprintf(("hpfs_lookup: fnode: 0x%x, CPID: 0x%x\n", dep->de_fnode, dep->de_cpid)); - if (nameiop == NAMEI_DELETE && (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_DELETE) { error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_td); if (error) { brelse(bp); @@ -1214,12 +1212,8 @@ hpfs_lookup(struct vop_lookup_args *ap) brelse(bp); - if(!lockparent || !(flags & CNP_ISLASTCN)) + if(!lockparent) VOP__UNLOCK(dvp, 0, cnp->cn_td); - if ((flags & CNP_MAKEENTRY) && - (!(flags & CNP_ISLASTCN) || - (nameiop != NAMEI_DELETE && nameiop != NAMEI_CREATE))) - cache_enter(dvp, *ap->a_vpp, cnp); } return (error); } @@ -1255,9 +1249,6 @@ hpfs_create(struct vop_create_args *ap) dprintf(("hpfs_create(0x%x, %s, %ld): \n", VTOHP(ap->a_dvp)->h_no, ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen)); - if (!(ap->a_cnp->cn_flags & CNP_HASBUF)) - panic ("hpfs_create: no name\n"); - error = hpfs_makefnode (ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap); return (error); @@ -1319,8 +1310,7 @@ struct vnodeopv_entry_desc hpfs_vnodeop_entries[] = { { &vop_islocked_desc, (void *)vop_stdislocked }, { &vop_unlock_desc, (void *)vop_stdunlock }, { &vop_lock_desc, (void *)vop_stdlock }, - { &vop_cachedlookup_desc, (void *)hpfs_lookup }, - { &vop_lookup_desc, (void *)vfs_cache_lookup }, + { &vop_lookup_desc, (void *)hpfs_lookup }, { &vop_access_desc, (void *)hpfs_access }, { &vop_close_desc, (void *)hpfs_close }, { &vop_open_desc, (void *)hpfs_open }, diff --git a/sys/vfs/isofs/cd9660/cd9660_lookup.c b/sys/vfs/isofs/cd9660/cd9660_lookup.c index df637b1012..4543a1ab12 100644 --- a/sys/vfs/isofs/cd9660/cd9660_lookup.c +++ b/sys/vfs/isofs/cd9660/cd9660_lookup.c @@ -39,7 +39,7 @@ * * @(#)cd9660_lookup.c 8.2 (Berkeley) 1/23/94 * $FreeBSD: src/sys/isofs/cd9660/cd9660_lookup.c,v 1.23.2.2 2001/11/04 06:19:47 dillon Exp $ - * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_lookup.c,v 1.14 2004/10/12 19:20:58 dillon Exp $ + * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_lookup.c,v 1.15 2004/11/12 00:09:34 dillon Exp $ */ #include @@ -90,7 +90,7 @@ * struct componentname *a_cnp) */ int -cd9660_lookup(struct vop_cachedlookup_args *ap) +cd9660_lookup(struct vop_lookup_args *ap) { struct vnode *vdp; /* vnode for directory being searched */ globaldata_t gd = mycpu; @@ -305,11 +305,6 @@ notfound: if (bp != NULL) brelse(bp); - /* - * Insert name into cache (as non-existent) if appropriate. - */ - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(vdp, *vpp, cnp); if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) return (EROFS); return (ENOENT); @@ -323,7 +318,7 @@ found: * If the final component of path name, save information * in the cache as to where the entry was found. */ - if ((flags & CNP_ISLASTCN) && nameiop == NAMEI_LOOKUP) + if (nameiop == NAMEI_LOOKUP) dp->i_diroff = dp->i_offset; /* @@ -359,7 +354,7 @@ found: vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td); return (error); } - if (lockparent && (flags & CNP_ISLASTCN)) { + if (lockparent) { if ((error = vn_lock(pdp, LK_EXCLUSIVE, td)) != 0) { cnp->cn_flags |= CNP_PDIRUNLOCK; vput(tdp); @@ -378,18 +373,12 @@ found: brelse(bp); if (error) return (error); - if (!lockparent || !(flags & CNP_ISLASTCN)) { + if (!lockparent) { cnp->cn_flags |= CNP_PDIRUNLOCK; VOP_UNLOCK(pdp, 0, td); } *vpp = tdp; } - - /* - * Insert name into cache if appropriate. - */ - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(vdp, *vpp, cnp); return (0); } diff --git a/sys/vfs/isofs/cd9660/cd9660_node.h b/sys/vfs/isofs/cd9660/cd9660_node.h index 8833c6fd9d..381190025e 100644 --- a/sys/vfs/isofs/cd9660/cd9660_node.h +++ b/sys/vfs/isofs/cd9660/cd9660_node.h @@ -37,7 +37,7 @@ * * @(#)cd9660_node.h 8.6 (Berkeley) 5/14/95 * $FreeBSD: src/sys/isofs/cd9660/cd9660_node.h,v 1.20 1999/12/29 04:54:37 peter Exp $ - * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.h,v 1.5 2004/08/28 19:02:15 dillon Exp $ + * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.h,v 1.6 2004/11/12 00:09:34 dillon Exp $ */ #include @@ -103,14 +103,14 @@ MALLOC_DECLARE(M_ISOFSNODE); struct buf; struct vop_bmap_args; -struct vop_cachedlookup_args; +struct vop_lookup_args; struct vop_inactive_args; struct vop_reclaim_args; /* * Prototypes for ISOFS vnode operations */ -int cd9660_lookup (struct vop_cachedlookup_args *); +int cd9660_lookup (struct vop_lookup_args *); int cd9660_inactive (struct vop_inactive_args *); int cd9660_reclaim (struct vop_reclaim_args *); int cd9660_bmap (struct vop_bmap_args *); diff --git a/sys/vfs/isofs/cd9660/cd9660_vfsops.c b/sys/vfs/isofs/cd9660/cd9660_vfsops.c index 534e1c8895..df729e375c 100644 --- a/sys/vfs/isofs/cd9660/cd9660_vfsops.c +++ b/sys/vfs/isofs/cd9660/cd9660_vfsops.c @@ -37,13 +37,13 @@ * * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 * $FreeBSD: src/sys/isofs/cd9660/cd9660_vfsops.c,v 1.74.2.7 2002/04/08 09:39:29 bde Exp $ - * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vfsops.c,v 1.22 2004/10/12 19:20:58 dillon Exp $ + * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vfsops.c,v 1.23 2004/11/12 00:09:34 dillon Exp $ */ #include #include #include -#include +#include #include #include #include @@ -155,7 +155,7 @@ iso_mountroot(struct mount *mp, struct thread *td) args.flags = ISOFSMNT_ROOT; vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(rootvp, FREAD, FSCRED, td); + error = VOP_OPEN(rootvp, FREAD, FSCRED, NULL, td); VOP_UNLOCK(rootvp, 0, td); if (error) return (error); @@ -188,7 +188,7 @@ cd9660_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) int error; mode_t accessmode; struct iso_mnt *imp = 0; - struct nameidata nd; + struct nlookupdata nd; if ((mp->mnt_flag & MNT_ROOTFS) != 0) { return (iso_mountroot(mp, td)); @@ -214,11 +214,15 @@ cd9660_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); - if ((error = namei(&nd))) + devvp = NULL; + error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp); + nlookup_done(&nd); + if (error) return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - devvp = nd.ni_vp; if (!vn_isdisk(devvp, &error)) { vrele(devvp); @@ -302,7 +306,7 @@ iso_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td, return (error); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(devvp, FREAD, FSCRED, td); + error = VOP_OPEN(devvp, FREAD, FSCRED, NULL, td); VOP_UNLOCK(devvp, 0, td); if (error) return error; diff --git a/sys/vfs/isofs/cd9660/cd9660_vnops.c b/sys/vfs/isofs/cd9660/cd9660_vnops.c index 6789df54de..2205176961 100644 --- a/sys/vfs/isofs/cd9660/cd9660_vnops.c +++ b/sys/vfs/isofs/cd9660/cd9660_vnops.c @@ -37,7 +37,7 @@ * * @(#)cd9660_vnops.c 8.19 (Berkeley) 5/27/95 * $FreeBSD: src/sys/isofs/cd9660/cd9660_vnops.c,v 1.62 1999/12/15 23:01:51 eivind Exp $ - * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vnops.c,v 1.12 2004/09/24 09:18:03 dillon Exp $ + * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vnops.c,v 1.13 2004/11/12 00:09:34 dillon Exp $ */ #include @@ -847,13 +847,12 @@ struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { { &vop_access_desc, (void *) cd9660_access }, { &vop_advlock_desc, (void *) cd9660_advlock }, { &vop_bmap_desc, (void *) cd9660_bmap }, - { &vop_cachedlookup_desc, (void *) cd9660_lookup }, + { &vop_lookup_desc, (void *) cd9660_lookup }, { &vop_getattr_desc, (void *) cd9660_getattr }, { &vop_inactive_desc, (void *) cd9660_inactive }, { &vop_ioctl_desc, (void *) cd9660_ioctl }, { &vop_islocked_desc, (void *) vop_stdislocked }, { &vop_lock_desc, (void *) vop_stdlock }, - { &vop_lookup_desc, (void *) vfs_cache_lookup }, { &vop_pathconf_desc, (void *) cd9660_pathconf }, { &vop_print_desc, (void *) cd9660_print }, { &vop_read_desc, (void *) cd9660_read }, diff --git a/sys/vfs/msdosfs/denode.h b/sys/vfs/msdosfs/denode.h index 4802bcd1f5..f9eceeb741 100644 --- a/sys/vfs/msdosfs/denode.h +++ b/sys/vfs/msdosfs/denode.h @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/msdosfs/denode.h,v 1.20 1999/12/29 04:54:52 peter Exp $ */ -/* $DragonFly: src/sys/vfs/msdosfs/denode.h,v 1.8 2004/08/28 19:02:18 dillon Exp $ */ +/* $DragonFly: src/sys/vfs/msdosfs/denode.h,v 1.9 2004/11/12 00:09:36 dillon Exp $ */ /* $NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $ */ /*- @@ -258,7 +258,7 @@ struct defid { #endif }; -int msdosfs_lookup (struct vop_cachedlookup_args *); +int msdosfs_lookup (struct vop_lookup_args *); int msdosfs_inactive (struct vop_inactive_args *); int msdosfs_reclaim (struct vop_reclaim_args *); diff --git a/sys/vfs/msdosfs/msdosfs_lookup.c b/sys/vfs/msdosfs/msdosfs_lookup.c index 97f919218d..bcf299ccb2 100644 --- a/sys/vfs/msdosfs/msdosfs_lookup.c +++ b/sys/vfs/msdosfs/msdosfs_lookup.c @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/msdosfs/msdosfs_lookup.c,v 1.30.2.1 2000/11/03 15:55:39 bp Exp $ */ -/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_lookup.c,v 1.12 2004/10/12 19:21:00 dillon Exp $ */ +/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_lookup.c,v 1.13 2004/11/12 00:09:36 dillon Exp $ */ /* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */ /*- @@ -82,7 +82,7 @@ * struct componentname *a_cnp) */ int -msdosfs_lookup(struct vop_cachedlookup_args *ap) +msdosfs_lookup(struct vop_lookup_args *ap) { struct vnode *vdp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; @@ -179,8 +179,7 @@ msdosfs_lookup(struct vop_cachedlookup_args *ap) * case it doesn't already exist. */ slotcount = wincnt; - if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && - (flags & CNP_ISLASTCN)) + if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) slotcount = 0; #ifdef MSDOSFS_DEBUG @@ -334,7 +333,7 @@ notfound: slotcount, slotoffset); #endif if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && - (flags & CNP_ISLASTCN) && dp->de_refcnt != 0) { + dp->de_refcnt != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. @@ -362,18 +361,12 @@ notfound: * NB - if the directory is unlocked, then this * information cannot be used. */ - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) { VOP_UNLOCK(vdp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; } return (EJUSTRETURN); } - /* - * Insert name into cache (as non-existent) if appropriate. - */ - if ((cnp->cn_flags & CNP_MAKEENTRY) && nameiop != NAMEI_CREATE) - cache_enter(vdp, *vpp, cnp); return (ENOENT); found: @@ -427,7 +420,7 @@ foundroot: * the directory (in ndp->ni_dvp), otherwise we go * on and lock the inode, being careful with ".". */ - if (nameiop == NAMEI_DELETE && (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_DELETE) { /* * Don't allow deleting the root. */ @@ -467,8 +460,7 @@ foundroot: * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ - if (nameiop == NAMEI_RENAME && wantparent && - (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_RENAME && wantparent) { if (blkoff == MSDOSFSROOT_OFS) return EROFS; /* really? XXX */ @@ -486,7 +478,6 @@ foundroot: if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) return (error); *vpp = DETOV(tdp); - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) { VOP_UNLOCK(vdp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; @@ -523,7 +514,7 @@ foundroot: cnp->cn_flags &= ~CNP_PDIRUNLOCK; return (error); } - if (lockparent && (flags & CNP_ISLASTCN)) { + if (lockparent) { error = vn_lock(pdp, LK_EXCLUSIVE, td); if (error) { vput(DETOV(tdp)); @@ -538,18 +529,12 @@ foundroot: } else { if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) return (error); - if (!lockparent || !(flags & CNP_ISLASTCN)) { + if (!lockparent) { VOP_UNLOCK(pdp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; } *vpp = DETOV(tdp); } - - /* - * Insert name into cache if appropriate. - */ - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(vdp, *vpp, cnp); return (0); } diff --git a/sys/vfs/msdosfs/msdosfs_vfsops.c b/sys/vfs/msdosfs/msdosfs_vfsops.c index df6e0d9eed..eaab2658c8 100644 --- a/sys/vfs/msdosfs/msdosfs_vfsops.c +++ b/sys/vfs/msdosfs/msdosfs_vfsops.c @@ -1,5 +1,5 @@ /* $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/sys/msdosfs/Attic/msdosfs_vfsops.c,v 1.60.2.8 2004/03/02 09:43:04 tjr Exp $ */ -/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vfsops.c,v 1.20 2004/10/12 19:21:00 dillon Exp $ */ +/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vfsops.c,v 1.21 2004/11/12 00:09:36 dillon Exp $ */ /* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ /*- @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include #include @@ -235,7 +235,7 @@ msdosfs_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) int error, flags; mode_t accessmode; struct proc *p = td->td_proc; - struct nameidata nd; + struct nlookupdata nd; KKASSERT(p); @@ -299,12 +299,15 @@ msdosfs_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); - error = namei(&nd); + devvp = NULL; + error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp); + nlookup_done(&nd); if (error) return (error); - devvp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); if (!vn_isdisk(devvp, &error)) { vrele(devvp); @@ -397,7 +400,7 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp, struct thread *td, ronly = (mp->mnt_flag & MNT_RDONLY) != 0; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td); + error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL, td); VOP_UNLOCK(devvp, 0, td); if (error) return (error); diff --git a/sys/vfs/msdosfs/msdosfs_vnops.c b/sys/vfs/msdosfs/msdosfs_vnops.c index fd743c5b6c..336060b6cf 100644 --- a/sys/vfs/msdosfs/msdosfs_vnops.c +++ b/sys/vfs/msdosfs/msdosfs_vnops.c @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/msdosfs/msdosfs_vnops.c,v 1.95.2.4 2003/06/13 15:05:47 trhodes Exp $ */ -/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vnops.c,v 1.20 2004/11/03 22:07:21 dillon Exp $ */ +/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vnops.c,v 1.21 2004/11/12 00:09:36 dillon Exp $ */ /* $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $ */ /*- @@ -125,9 +125,7 @@ static int msdosfs_putpages (struct vop_putpages_args *); /* * Create a regular file. On entry the directory to contain the file being - * created is locked. We must release before we return. We must also free - * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or - * only if the SAVESTART bit in cn_flags is clear on success. + * created is locked. We must release before we return. * * msdosfs_create(struct vnode *a_dvp, struct vnode **a_vpp, * struct componentname *a_cnp, struct vattr *a_vap) @@ -163,10 +161,6 @@ msdosfs_create(struct vop_create_args *ap) * use the absence of the owner write bit to make the file * readonly. */ -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("msdosfs_create: no name"); -#endif bzero(&ndirent, sizeof(ndirent)); error = uniqdosname(pdep, cnp, ndirent.de_Name); if (error) @@ -987,11 +981,6 @@ msdosfs_rename(struct vop_rename_args *ap) pmp = VFSTOMSDOSFS(fdvp->v_mount); -#ifdef DIAGNOSTIC - if ((tcnp->cn_flags & CNP_HASBUF) == 0 || - (fcnp->cn_flags & CNP_HASBUF) == 0) - panic("msdosfs_rename: no name"); -#endif /* * Check for cross-device rename. */ @@ -1018,6 +1007,10 @@ abortit: goto abortit; } + /* + * fvp, fdvp are unlocked, tvp, tdvp are locked. Lock fvp and note + * that we have to unlock it to use the abortit target. + */ error = vn_lock(fvp, LK_EXCLUSIVE, td); if (error) goto abortit; @@ -1048,11 +1041,14 @@ abortit: } /* - * When the target exists, both the directory - * and target vnodes are returned locked. + * fvp locked, fdvp unlocked, tvp, tdvp locked. DE_RENAME only + * set if doingdirectory. We will get fvp unlocked in fairly + * short order. dp and xp must be setup and fvp must be unlocked + * for the out and bad targets to work properly. */ dp = VTODE(tdvp); xp = tvp ? VTODE(tvp) : NULL; + /* * Remember direntry place to use for destination */ @@ -1073,27 +1069,56 @@ abortit: VOP_UNLOCK(fvp, 0, td); if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster) newparent = 1; + + /* + * ok. fvp, fdvp unlocked, tvp, tdvp locked. tvp may be NULL. + * DE_RENAME only set if doingdirectory. + */ if (doingdirectory && newparent) { if (error) /* write access check above */ goto bad; - if (xp != NULL) + if (xp != NULL) { vput(tvp); + xp = NULL; + } /* - * doscheckpath() vput()'s dp, - * so we have to do a relookup afterwards + * checkpath vput's tdvp (VTOI(dp)) on return no matter what, + * get an extra ref so we wind up with just an unlocked, ref'd + * tdvp. The 'out' target skips tvp and tdvp cleanups (tdvp + * isn't locked so we can't use the out target). */ + vref(tdvp); error = doscheckpath(ip, dp); - if (error) + if (error) { + vrele(tdvp); goto out; - if ((tcnp->cn_flags & CNP_SAVESTART) == 0) - panic("msdosfs_rename: lost to startdir"); + } + /* + * relookup no longer messes with the ref count. tdvp must + * be unlocked on entry and on success will be locked on + * return. + */ error = relookup(tdvp, &tvp, tcnp); - if (error) + if (error) { + if (tcnp->cn_flags & CNP_PDIRUNLOCK) + vrele(tdvp); + else + vput(tdvp); goto out; + } + + /* + * tvp and tdvp are now locked again. + */ dp = VTODE(tdvp); xp = tvp ? VTODE(tvp) : NULL; } + /* + * tvp and tdvp are now locked again, the 'bad' target can be used + * to clean them up again. Delete an existant target and clean + * up tvp. Set xp to NULL to indicate that tvp has been cleaned up. + */ if (xp != NULL) { /* * Target must be empty if a directory and have no links @@ -1109,7 +1134,6 @@ abortit: error = ENOTDIR; goto bad; } - cache_purge(tdvp); } else if (doingdirectory) { error = EISDIR; goto bad; @@ -1119,6 +1143,7 @@ abortit: goto bad; vput(tvp); xp = NULL; + tvp = NULL; } /* @@ -1128,32 +1153,49 @@ abortit: */ error = uniqdosname(VTODE(tdvp), tcnp, toname); if (error) - goto abortit; + goto bad; /* - * Since from wasn't locked at various places above, - * have to do a relookup here. + * Since from wasn't locked at various places above, we have to do + * a relookup here. If the target and source are the same directory + * we have to unlock the target directory in order to safely relookup + * the source, because relookup expects its directory to be unlocked. + * + * Note that ap->a_fvp is still valid and ref'd. Any cleanup must + * now take that into account. + * + * The tdvp locking issues make this a real mess. */ fcnp->cn_flags &= ~CNP_MODMASK; - fcnp->cn_flags |= CNP_LOCKPARENT | CNP_LOCKLEAF; - if ((fcnp->cn_flags & CNP_SAVESTART) == 0) - panic("msdosfs_rename: lost from startdir"); - if (!newparent) + fcnp->cn_flags |= CNP_LOCKPARENT; + if (newparent == 0) VOP_UNLOCK(tdvp, 0, td); - if (relookup(fdvp, &fvp, fcnp) == 0) - vrele(fdvp); - if (fvp == NULL) { + error = relookup(fdvp, &fvp, fcnp); + if (error || fvp == NULL) { /* - * From name has disappeared. + * From name has disappeared. Note: fdvp might == tdvp. + * + * DE_RENAME is only set if doingdirectory. */ if (doingdirectory) panic("rename: lost dir entry"); + if (fcnp->cn_flags & CNP_PDIRUNLOCK) + vrele(fdvp); + else + vput(fdvp); + if (newparent == 0) + vrele(tdvp); + else + vput(tdvp); vrele(ap->a_fvp); - if (newparent) - VOP_UNLOCK(tdvp, 0, td); - vrele(tdvp); - return 0; + return(0); } + + /* + * No error occured. tdvp, fdvp and fvp are all locked. If + * newparent was 0 be aware that fdvp == tdvp. tvp has been cleaned + * up. ap->a_fvp is still refd. + */ xp = VTODE(fvp); zp = VTODE(fdvp); from_diroffset = zp->de_fndoffset; @@ -1165,22 +1207,17 @@ abortit: * no further work to be done. If the source is a directory * then it cannot have been rmdir'ed or renamed; this is * prohibited by the DE_RENAME flag. + * + * DE_RENAME is only set if doingdirectory. */ if (xp != ip) { if (doingdirectory) panic("rename: lost dir entry"); - vrele(ap->a_fvp); - VOP_UNLOCK(fvp, 0, td); - if (newparent) - VOP_UNLOCK(fdvp, 0, td); - xp = NULL; + goto done; } else { u_long new_dirclust; u_long new_diroffset; - vrele(fvp); - xp = NULL; - /* * First write a new entry in the destination * directory and mark the entry in the source directory @@ -1196,30 +1233,21 @@ abortit: error = createde(ip, dp, (struct denode **)0, tcnp); if (error) { bcopy(oldname, ip->de_Name, 11); - if (newparent) - VOP_UNLOCK(fdvp, 0, td); - VOP_UNLOCK(fvp, 0, td); - goto bad; + goto done; } ip->de_refcnt++; zp->de_fndoffset = from_diroffset; error = removede(zp, ip); if (error) { /* XXX should really panic here, fs is corrupt */ - if (newparent) - VOP_UNLOCK(fdvp, 0, td); - VOP_UNLOCK(fvp, 0, td); - goto bad; + goto done; } if (!doingdirectory) { error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0, &new_dirclust, 0); if (error) { /* XXX should really panic here, fs is corrupt */ - if (newparent) - VOP_UNLOCK(fdvp, 0, td); - VOP_UNLOCK(fvp, 0, td); - goto bad; + goto done; } if (new_dirclust == MSDOSFSROOT) new_diroffset = to_diroffset; @@ -1227,8 +1255,6 @@ abortit: new_diroffset = to_diroffset & pmp->pm_crbomask; msdosfs_reinsert(ip, new_dirclust, new_diroffset); } - if (newparent) - VOP_UNLOCK(fdvp, 0, td); } /* @@ -1240,14 +1266,14 @@ abortit: if (cn == MSDOSFSROOT) { /* this should never happen */ panic("msdosfs_rename(): updating .. in root directory?"); - } else + } else { bn = cntobn(pmp, cn); + } error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, &bp); if (error) { /* XXX should really panic here, fs is corrupt */ brelse(bp); - VOP_UNLOCK(fvp, 0, td); - goto bad; + goto done; } dotdotp = (struct direntry *)bp->b_data + 1; putushort(dotdotp->deStartCluster, dp->de_StartCluster); @@ -1256,18 +1282,40 @@ abortit: error = bwrite(bp); if (error) { /* XXX should really panic here, fs is corrupt */ - VOP_UNLOCK(fvp, 0, td); - goto bad; + goto done; } } - VOP_UNLOCK(fvp, 0, td); + /* + * done case fvp, fdvp, tdvp are locked. ap->a_fvp is refd + */ +done: + if (doingdirectory) + ip->de_flag &= ~DE_RENAME; /* XXX fvp not locked */ + vput(fvp); + if (newparent) + vput(fdvp); + else + vrele(fdvp); + vput(tdvp); + vrele(ap->a_fvp); + return (error); + + /* + * 'bad' target: xp governs tvp. tvp and tdvp arel ocked, fdvp and fvp + * are not locked. ip points to fvp's inode which may have DE_RENAME + * set. + */ bad: if (xp) vput(tvp); vput(tdvp); out: - ip->de_flag &= ~DE_RENAME; + /* + * 'out' target: tvp and tdvp have already been cleaned up. + */ + if (doingdirectory) + ip->de_flag &= ~DE_RENAME; vrele(fdvp); vrele(fvp); return (error); @@ -1385,10 +1433,6 @@ msdosfs_mkdir(struct vop_mkdir_args *ap) * cluster. This will be written to an empty slot in the parent * directory. */ -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("msdosfs_mkdir: no name"); -#endif error = uniqdosname(pdep, cnp, ndirent.de_Name); if (error) goto bad; @@ -1461,7 +1505,6 @@ msdosfs_rmdir(struct vop_rmdir_args *ap) * Truncate the directory that is being deleted. */ error = detrunc(ip, (u_long)0, IO_SYNC, td); - cache_purge(vp); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); out: @@ -1898,7 +1941,7 @@ struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = { { &vop_default_desc, vop_defaultop }, { &vop_access_desc, (void *) msdosfs_access }, { &vop_bmap_desc, (void *) msdosfs_bmap }, - { &vop_cachedlookup_desc, (void *) msdosfs_lookup }, + { &vop_lookup_desc, (void *) msdosfs_lookup }, { &vop_close_desc, (void *) msdosfs_close }, { &vop_create_desc, (void *) msdosfs_create }, { &vop_fsync_desc, (void *) msdosfs_fsync }, @@ -1907,7 +1950,6 @@ struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = { { &vop_islocked_desc, (void *) vop_stdislocked }, { &vop_link_desc, (void *) msdosfs_link }, { &vop_lock_desc, (void *) vop_stdlock }, - { &vop_lookup_desc, (void *) vfs_cache_lookup }, { &vop_mkdir_desc, (void *) msdosfs_mkdir }, { &vop_mknod_desc, (void *) msdosfs_mknod }, { &vop_pathconf_desc, (void *) msdosfs_pathconf }, diff --git a/sys/vfs/nfs/nfs.h b/sys/vfs/nfs/nfs.h index 8ccb227e33..379bb89a84 100644 --- a/sys/vfs/nfs/nfs.h +++ b/sys/vfs/nfs/nfs.h @@ -35,7 +35,7 @@ * * @(#)nfs.h 8.4 (Berkeley) 5/1/95 * $FreeBSD: src/sys/nfs/nfs.h,v 1.53.2.5 2002/02/20 01:35:34 iedowse Exp $ - * $DragonFly: src/sys/vfs/nfs/nfs.h,v 1.7 2004/09/16 15:15:51 joerg Exp $ + * $DragonFly: src/sys/vfs/nfs/nfs.h,v 1.8 2004/11/12 00:09:37 dillon Exp $ */ #ifndef _NFS_NFS_H_ @@ -307,7 +307,10 @@ extern vm_zone_t nfsmount_zone; extern struct callout nfs_timer_handle; -struct uio; struct buf; struct vattr; struct nameidata; /* XXX */ +struct uio; +struct buf; +struct vattr; +struct nlookupdata; /* * The set of signals the interrupt an I/O in progress for NFSMNT_INT mounts. @@ -617,9 +620,10 @@ int nfs_request (struct vnode *, struct mbuf *, int, struct thread *, caddr_t *); int nfs_loadattrcache (struct vnode **, struct mbuf **, caddr_t *, struct vattr *, int); -int nfs_namei (struct nameidata *, fhandle_t *, int, - struct nfssvc_sock *, struct sockaddr *, struct mbuf **, - caddr_t *, struct vnode **, struct thread *, int, int); +int nfs_namei (struct nlookupdata *, struct ucred *, int, + struct vnode **, struct vnode **, fhandle_t *, int, + struct nfssvc_sock *, struct sockaddr *, struct mbuf **, + caddr_t *, struct vnode **, struct thread *, int, int); void nfsm_adj (struct mbuf *, int, int); int nfsm_mbuftouio (struct mbuf **, struct uio *, int, caddr_t *); void nfsrv_initcache (void); diff --git a/sys/vfs/nfs/nfs_nqlease.c b/sys/vfs/nfs/nfs_nqlease.c index abb5ca2ff7..b7b7a8231d 100644 --- a/sys/vfs/nfs/nfs_nqlease.c +++ b/sys/vfs/nfs/nfs_nqlease.c @@ -35,7 +35,7 @@ * * @(#)nfs_nqlease.c 8.9 (Berkeley) 5/20/95 * $FreeBSD: src/sys/nfs/nfs_nqlease.c,v 1.50 2000/02/13 03:32:05 peter Exp $ - * $DragonFly: src/sys/vfs/nfs/Attic/nfs_nqlease.c,v 1.19 2004/10/12 19:21:01 dillon Exp $ + * $DragonFly: src/sys/vfs/nfs/Attic/nfs_nqlease.c,v 1.20 2004/11/12 00:09:37 dillon Exp $ */ @@ -1062,7 +1062,7 @@ nqnfs_clientd(struct nfsmount *nmp, struct ucred *cred, struct nfsd_cargs *ncd, if (np->n_flag & NQNFSEVICTED) { if (vp->v_type == VDIR) nfs_invaldir(vp); - cache_purge(vp); + cache_inval_vp(vp, CINV_SELF); (void) nfs_vinvalbuf(vp, V_SAVE, td, 0); np->n_flag &= ~NQNFSEVICTED; diff --git a/sys/vfs/nfs/nfs_serv.c b/sys/vfs/nfs/nfs_serv.c index c1ad8301e7..eaadab8a66 100644 --- a/sys/vfs/nfs/nfs_serv.c +++ b/sys/vfs/nfs/nfs_serv.c @@ -35,7 +35,7 @@ * * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95 * $FreeBSD: src/sys/nfs/nfs_serv.c,v 1.93.2.6 2002/12/29 18:19:53 dillon Exp $ - * $DragonFly: src/sys/vfs/nfs/nfs_serv.c,v 1.19 2004/10/12 19:21:01 dillon Exp $ + * $DragonFly: src/sys/vfs/nfs/nfs_serv.c,v 1.20 2004/11/12 00:09:37 dillon Exp $ */ /* @@ -61,19 +61,12 @@ * Warning: always pay careful attention to resource cleanup on return * and note that nfsm_*() macros can terminate a procedure on certain * errors. - * - * lookup() and namei() - * may return garbage in various structural fields/return elements - * if an error is returned, and may garbage up nd.ni_dvp even if no - * error is returned and you did not request LOCKPARENT or WANTPARENT. - * - * We use the ni_cnd.cn_flags 'HASBUF' flag to track whether the name - * buffer has been freed or not. */ #include #include #include +#include #include #include #include @@ -152,21 +145,6 @@ static int nfsrv_access (struct vnode *,int,struct ucred *,int, static void nfsrvw_coalesce (struct nfsrv_descript *, struct nfsrv_descript *); -/* - * Clear nameidata fields that are tested in nsfmout cleanup code prior - * to using first nfsm macro (that might jump to the cleanup code). - */ - -static __inline -void -ndclear(struct nameidata *nd) -{ - nd->ni_cnd.cn_flags = 0; - nd->ni_vp = NULL; - nd->ni_dvp = NULL; - nd->ni_startdir = NULL; -} - /* * nfs v3 access service */ @@ -450,8 +428,10 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct nfs_fattr *fp; - struct nameidata nd, ind, *ndp = &nd; - struct vnode *vp, *dirp = NULL; + struct nlookupdata nd; + struct vnode *vp; + struct vnode *dirp; + struct namecache *ncp; nfsfh_t nfh; fhandle_t *fhp; caddr_t cp; @@ -466,7 +446,9 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); + nlookup_zero(&nd); + dirp = NULL; + vp = NULL; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); @@ -474,10 +456,8 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, pubflag = nfs_ispublicfh(fhp); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = NAMEI_LOOKUP; - nd.ni_cnd.cn_flags = CNP_LOCKLEAF | CNP_SAVESTART; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, + error = nfs_namei(&nd, cred, NAMEI_LOOKUP, NULL, &vp, + fhp, len, slp, nam, &md, &dpos, &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), pubflag); /* @@ -505,7 +485,7 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, */ if (pubflag) { - if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) { + if (vp->v_type == VDIR && nfs_pub.np_index != NULL) { /* * Setup call to lookup() to see if we can find * the index file. Arguably, this doesn't belong @@ -519,29 +499,30 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * However, the cnd resource continues to be maintained * via the original nd. Confused? You aren't alone! */ - ind = nd; - VOP_UNLOCK(nd.ni_vp, 0, td); - ind.ni_pathlen = strlen(nfs_pub.np_index); - ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf = - nfs_pub.np_index; - ind.ni_startdir = nd.ni_vp; - vref(ind.ni_startdir); - - error = lookup(&ind); - ind.ni_dvp = NULL; + VOP_UNLOCK(vp, 0, td); + ncp = cache_hold(nd.nl_ncp); + nlookup_done(&nd); + error = nlookup_init_raw(&nd, nfs_pub.np_index, + UIO_SYSSPACE, 0, cred, ncp); + cache_drop(ncp); + if (error == 0) + error = nlookup(&nd); if (error == 0) { /* * Found an index file. Get rid of - * the old references. transfer nd.ni_vp' + * the old references. transfer vp and + * load up the new vp. Fortunately we do + * not have to deal with dvp, that would be + * a huge mess. */ if (dirp) vrele(dirp); - dirp = nd.ni_vp; - nd.ni_vp = NULL; - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - ndp = &ind; + dirp = vp; + vp = NULL; + error = cache_vget(nd.nl_ncp, nd.nl_cred, + LK_EXCLUSIVE, &vp); + KKASSERT(error == 0); } error = 0; } @@ -552,9 +533,9 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * to NFS I/O. */ - if (ndp->ni_vp->v_mount != nfs_pub.np_mount) { - vput(nd.ni_vp); - nd.ni_vp = NULL; + if (vp->v_mount != nfs_pub.np_mount) { + vput(vp); + vp = NULL; error = EPERM; } } @@ -579,22 +560,22 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, goto nfsmout; } +#if 0 + /* XXX not sure how to deal with this */ nqsrv_getl(ndp->ni_startdir, ND_READ); +#endif /* * Clear out some resources prior to potentially blocking. This * is not as critical as ni_dvp resources in other routines, but * it helps. */ - vrele(ndp->ni_startdir); - ndp->ni_startdir = NULL; - NDFREE(&nd, NDF_ONLY_PNBUF); + nlookup_done(&nd); /* * Get underlying attribute, then release remaining resources ( for * the same potential blocking reason ) and reply. */ - vp = ndp->ni_vp; bzero((caddr_t)fhp, sizeof(nfh)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; error = VFS_VPTOFH(vp, &fhp->fh_fid); @@ -602,7 +583,7 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = VOP_GETATTR(vp, vap, td); vput(vp); - ndp->ni_vp = NULL; + vp = NULL; nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3)); if (error) { nfsm_srvpostop_attr(dirattr_ret, &dirattr); @@ -621,11 +602,9 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsmout: if (dirp) vrele(dirp); - NDFREE(&nd, NDF_ONLY_PNBUF); - if (ndp->ni_startdir) - vrele(ndp->ni_startdir); - if (ndp->ni_vp) - vput(ndp->ni_vp); + nlookup_done(&nd); /* may be called twice */ + if (vp) + vput(vp); return (error); } @@ -1580,7 +1559,7 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct vattr *vap = &va; struct nfsv2_sattr *sp; u_int32_t *tl; - struct nameidata nd; + struct nlookupdata nd; int32_t t1; caddr_t bpos; int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1; @@ -1588,7 +1567,9 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, caddr_t cp; char *cp2; struct mbuf *mb, *mb2, *mreq; - struct vnode *dirp = (struct vnode *)0; + struct vnode *dirp; + struct vnode *dvp; + struct vnode *vp; nfsfh_t nfh; fhandle_t *fhp; u_quad_t frev, tempsize; @@ -1598,16 +1579,15 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, #ifndef nolint rdev = 0; #endif - ndclear(&nd); + nlookup_zero(&nd); + dirp = NULL; + dvp = NULL; + vp = NULL; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = NAMEI_CREATE; - nd.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_SAVESTART; - /* * Call namei and do initial cleanup to get a few things * out of the way. If we get an initial error we cleanup @@ -1617,8 +1597,9 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * be valid at all if an error occurs so we have to invalidate it * prior to calling nfsm_reply ( which might goto nfsmout ). */ - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, cred, NAMEI_CREATE, &dvp, &vp, + fhp, len, slp, nam, &md, &dpos, &dirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) { dirfor_ret = VOP_GETATTR(dirp, &dirfor, td); @@ -1637,10 +1618,10 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, /* * No error. Continue. State: * - * startdir is valid ( we release this immediately ) * dirp may be valid - * nd.ni_vp may be valid - * nd.ni_dvp is valid + * vp may be valid or NULL if the target does not + * exist. + * dvp is valid * * The error state is set through the code and we may also do some * opportunistic releasing of vnodes to avoid holding locks through @@ -1653,7 +1634,7 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, how = fxdr_unsigned(int, *tl); switch (how) { case NFSV3CREATE_GUARDED: - if (nd.ni_vp) { + if (vp) { error = EEXIST; break; } @@ -1698,24 +1679,20 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * The only possible error we can have at this point is EEXIST. * nd.ni_vp will also be non-NULL in that case. */ - if (nd.ni_vp == NULL) { + if (vp == NULL) { if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; if (vap->va_type == VREG || vap->va_type == VSOCK) { - nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_CREATE(nd.ni_dvp, NCPNULL, &nd.ni_vp, - &nd.ni_cnd, vap); - if (error) - NDFREE(&nd, NDF_ONLY_PNBUF); - else { - nfsrv_object_create(nd.ni_vp); + nqsrv_getl(dvp, ND_WRITE); + error = VOP_NCREATE(nd.nl_ncp, &vp, nd.nl_cred, vap); + if (error == 0) { + nfsrv_object_create(vp); if (exclusive_flag) { exclusive_flag = 0; VATTR_NULL(vap); bcopy(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF); - error = VOP_SETATTR(nd.ni_vp, vap, cred, - td); + error = VOP_SETATTR(vp, vap, cred, td); } } } else if ( @@ -1734,22 +1711,24 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, goto nfsmreply0; } vap->va_rdev = rdev; - nqsrv_getl(nd.ni_dvp, ND_WRITE); + nqsrv_getl(dvp, ND_WRITE); - error = VOP_MKNOD(nd.ni_dvp, NCPNULL, &nd.ni_vp, - &nd.ni_cnd, vap); - if (error) { - NDFREE(&nd, NDF_ONLY_PNBUF); + error = VOP_NMKNOD(nd.nl_ncp, &vp, nd.nl_cred, vap); + if (error) goto nfsmreply0; - } - vput(nd.ni_vp); - nd.ni_vp = NULL; +#if 0 + /* + * XXX what is this junk supposed to do ? + */ + + vput(vp); + vp = NULL; /* * release dvp prior to lookup */ - vput(nd.ni_dvp); - nd.ni_dvp = NULL; + vput(dvp); + dvp = NULL; /* * Setup for lookup. @@ -1774,29 +1753,30 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = EINVAL; goto nfsmreply0; } +#endif } else { error = ENXIO; } } else { if (vap->va_size != -1) { - error = nfsrv_access(nd.ni_vp, VWRITE, cred, - (nd.ni_cnd.cn_flags & CNP_RDONLY), td, 0); + error = nfsrv_access(vp, VWRITE, cred, + (nd.nl_flags & NLC_NFS_RDONLY), td, 0); if (!error) { - nqsrv_getl(nd.ni_vp, ND_WRITE); + nqsrv_getl(vp, ND_WRITE); tempsize = vap->va_size; VATTR_NULL(vap); vap->va_size = tempsize; - error = VOP_SETATTR(nd.ni_vp, vap, cred, td); + error = VOP_SETATTR(vp, vap, cred, td); } } } if (!error) { bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); + fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(vp, &fhp->fh_fid); if (!error) - error = VOP_GETATTR(nd.ni_vp, vap, td); + error = VOP_GETATTR(vp, vap, td); } if (v3) { if (exclusive_flag && !error && @@ -1827,21 +1807,17 @@ nfsmreply0: /* fall through */ nfsmout: - if (nd.ni_startdir) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - } if (dirp) vrele(dirp); - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); + nlookup_done(&nd); + if (dvp) { + if (dvp == vp) + vrele(dvp); else - vput(nd.ni_dvp); + vput(dvp); } - if (nd.ni_vp) - vput(nd.ni_vp); + if (vp) + vput(vp); return (error); } @@ -1859,7 +1835,7 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct vattr va, dirfor, diraft; struct vattr *vap = &va; u_int32_t *tl; - struct nameidata nd; + struct nlookupdata nd; int32_t t1; caddr_t bpos; int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1; @@ -1867,30 +1843,32 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, enum vtype vtyp; char *cp2; struct mbuf *mb, *mb2, *mreq; - struct vnode *vp, *dirp = (struct vnode *)0; + struct vnode *dirp; + struct vnode *dvp; + struct vnode *vp; nfsfh_t nfh; fhandle_t *fhp; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); + nlookup_zero(&nd); + dirp = NULL; + dvp = NULL; + vp = NULL; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = NAMEI_CREATE; - nd.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_SAVESTART; - /* * Handle nfs_namei() call. If an error occurs, the nd structure * is not valid. However, nfsm_*() routines may still jump to * nfsmout. */ - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, cred, NAMEI_CREATE, &dvp, &vp, + fhp, len, slp, nam, &md, &dpos, &dirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) dirfor_ret = VOP_GETATTR(dirp, &dirfor, td); if (error) { @@ -1917,7 +1895,7 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, /* * Iff doesn't exist, create it. */ - if (nd.ni_vp) { + if (vp) { error = EEXIST; goto out; } @@ -1925,33 +1903,30 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; if (vtyp == VSOCK) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_CREATE(nd.ni_dvp, NCPNULL, &nd.ni_vp, - &nd.ni_cnd, vap); - if (error) - NDFREE(&nd, NDF_ONLY_PNBUF); + nqsrv_getl(dvp, ND_WRITE); + error = VOP_NCREATE(nd.nl_ncp, &vp, nd.nl_cred, vap); } else { if (vtyp != VFIFO && (error = suser_cred(cred, 0))) goto out; - nqsrv_getl(nd.ni_dvp, ND_WRITE); + nqsrv_getl(dvp, ND_WRITE); - error = VOP_MKNOD(nd.ni_dvp, NCPNULL, &nd.ni_vp, - &nd.ni_cnd, vap); - if (error) { - NDFREE(&nd, NDF_ONLY_PNBUF); + error = VOP_NMKNOD(nd.nl_ncp, &vp, nd.nl_cred, vap); + if (error) goto out; - } - vput(nd.ni_vp); - nd.ni_vp = NULL; + +#if 0 + vput(vp); + vp = NULL; /* * Release dvp prior to lookup */ - vput(nd.ni_dvp); - nd.ni_dvp = NULL; + vput(dvp); + dvp = NULL; + /* + * XXX what is this stuff for? + */ KKASSERT(td->td_proc); nd.ni_cnd.cn_nameiop = NAMEI_LOOKUP; nd.ni_cnd.cn_flags &= ~(CNP_LOCKPARENT); @@ -1965,25 +1940,21 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, goto out; if (nd.ni_cnd.cn_flags & CNP_ISSYMLINK) error = EINVAL; +#endif } /* * send response, cleanup, return. */ out: - if (nd.ni_startdir) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - } - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); + nlookup_done(&nd); + if (dvp) { + if (dvp == vp) + vrele(dvp); else - vput(nd.ni_dvp); - nd.ni_dvp = NULL; + vput(dvp); + dvp = NULL; } - vp = nd.ni_vp; if (!error) { bzero((caddr_t)fhp, sizeof(nfh)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; @@ -1994,7 +1965,6 @@ out: if (vp) { vput(vp); vp = NULL; - nd.ni_vp = NULL; } diraft_ret = VOP_GETATTR(dirp, &diraft, td); if (dirp) { @@ -2011,17 +1981,15 @@ out: nfsmout: if (dirp) vrele(dirp); - if (nd.ni_startdir) - vrele(nd.ni_startdir); - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); + nlookup_done(&nd); + if (dvp) { + if (dvp == vp) + vrele(dvp); else - vput(nd.ni_dvp); + vput(dvp); } - if (nd.ni_vp) - vput(nd.ni_vp); + if (vp) + vput(vp); return (error); } @@ -2036,7 +2004,7 @@ nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct sockaddr *nam = nfsd->nd_nam; caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; - struct nameidata nd; + struct nlookupdata nd; u_int32_t *tl; int32_t t1; caddr_t bpos; @@ -2045,73 +2013,68 @@ nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, char *cp2; struct mbuf *mb, *mreq; struct vnode *dirp; + struct vnode *dvp; + struct vnode *vp; struct vattr dirfor, diraft; nfsfh_t nfh; fhandle_t *fhp; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); + nlookup_zero(&nd); + dirp = NULL; + dvp = NULL; + vp = NULL; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = NAMEI_DELETE; - nd.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_LOCKLEAF; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, cred, NAMEI_DELETE, &dvp, &vp, + fhp, len, slp, nam, &md, &dpos, &dirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { - if (v3) { + if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, td); - } else { - vrele(dirp); - dirp = NULL; - } } if (error == 0) { - if (nd.ni_vp->v_type == VDIR) { + if (vp->v_type == VDIR) { error = EPERM; /* POSIX */ goto out; } /* * The root of a mounted filesystem cannot be deleted. */ - if (nd.ni_vp->v_flag & VROOT) { + if (vp->v_flag & VROOT) { error = EBUSY; goto out; } out: if (!error) { - nqsrv_getl(nd.ni_dvp, ND_WRITE); - nqsrv_getl(nd.ni_vp, ND_WRITE); - error = VOP_REMOVE(nd.ni_dvp, NCPNULL, nd.ni_vp, &nd.ni_cnd); - if (error == 0) - cache_purge(nd.ni_vp); - NDFREE(&nd, NDF_ONLY_PNBUF); + nqsrv_getl(dvp, ND_WRITE); + nqsrv_getl(vp, ND_WRITE); + error = VOP_NREMOVE(nd.nl_ncp, nd.nl_cred); } } - if (dirp && v3) { + if (dirp && v3) diraft_ret = VOP_GETATTR(dirp, &diraft, td); - vrele(dirp); - dirp = NULL; - } nfsm_reply(NFSX_WCCDATA(v3)); if (v3) { nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); error = 0; } nfsmout: - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); + nlookup_done(&nd); + if (dirp) + vrele(dirp); + if (dvp) { + if (dvp == vp) + vrele(dvp); else - vput(nd.ni_dvp); + vput(dvp); } - if (nd.ni_vp) - vput(nd.ni_vp); + if (vp) + vput(vp); return(error); } @@ -2134,9 +2097,10 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mreq; - struct nameidata fromnd, tond; - struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0; - struct vnode *tdirp = (struct vnode *)0; + struct nlookupdata fromnd, tond; + struct vnode *fvp, *fdirp; + struct vnode *tvp, *tdirp; + struct namecache *ncp; struct vattr fdirfor, fdiraft, tdirfor, tdiraft; nfsfh_t fnfh, tnfh; fhandle_t *ffhp, *tfhp; @@ -2154,8 +2118,10 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * Clear fields incase goto nfsmout occurs from macro. */ - ndclear(&fromnd); - ndclear(&tond); + nlookup_zero(&fromnd); + nlookup_zero(&tond); + fdirp = NULL; + tdirp = NULL; nfsm_srvmtofh(ffhp); nfsm_srvnamesiz(len); @@ -2164,18 +2130,12 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * the second nfs_namei() call, in case it is remapped. */ saved_uid = cred->cr_uid; - fromnd.ni_cnd.cn_cred = cred; - fromnd.ni_cnd.cn_nameiop = NAMEI_DELETE; - fromnd.ni_cnd.cn_flags = CNP_WANTPARENT | CNP_SAVESTART; - error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, - &dpos, &fdirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&fromnd, cred, NAMEI_DELETE, NULL, NULL, + ffhp, len, slp, nam, &md, &dpos, &fdirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (fdirp) { - if (v3) { + if (v3) fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, td); - } else { - vrele(fdirp); - fdirp = NULL; - } } if (error) { nfsm_reply(2 * NFSX_WCCDATA(v3)); @@ -2184,29 +2144,48 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = 0; goto nfsmout; } - fvp = fromnd.ni_vp; + + /* + * We have to unlock the from ncp before we can safely lookup + * the target ncp. + */ + KKASSERT(fromnd.nl_flags & NLC_NCPISLOCKED); + cache_unlock(fromnd.nl_ncp); + fromnd.nl_flags &= ~NLC_NCPISLOCKED; nfsm_srvmtofh(tfhp); nfsm_strsiz(len2, NFS_MAXNAMLEN); cred->cr_uid = saved_uid; - tond.ni_cnd.cn_cred = cred; - tond.ni_cnd.cn_nameiop = NAMEI_RENAME; - tond.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_LOCKLEAF | - CNP_NOCACHE | CNP_SAVESTART; - error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, - &dpos, &tdirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + + error = nfs_namei(&tond, cred, NAMEI_RENAME, NULL, NULL, + tfhp, len2, slp, nam, &md, &dpos, &tdirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (tdirp) { - if (v3) { + if (v3) tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, td); - } else { - vrele(tdirp); - tdirp = NULL; - } } if (error) goto out1; - tdvp = tond.ni_dvp; - tvp = tond.ni_vp; + /* + * relock the source + */ + if (cache_lock_nonblock(fromnd.nl_ncp) == 0) { + cache_resolve(fromnd.nl_ncp, fromnd.nl_cred); + } else if (fromnd.nl_ncp > tond.nl_ncp) { + cache_lock(fromnd.nl_ncp); + cache_resolve(fromnd.nl_ncp, fromnd.nl_cred); + } else { + cache_unlock(tond.nl_ncp); + cache_lock(fromnd.nl_ncp); + cache_resolve(fromnd.nl_ncp, fromnd.nl_cred); + cache_lock(tond.nl_ncp); + cache_resolve(tond.nl_ncp, tond.nl_cred); + } + fromnd.nl_flags |= NLC_NCPISLOCKED; + + tvp = tond.nl_ncp->nc_vp; + fvp = fromnd.nl_ncp->nc_vp; + if (tvp != NULL) { if (fvp->v_type == VDIR && tvp->v_type != VDIR) { if (v3) @@ -2236,53 +2215,57 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = ENOTEMPTY; goto out; } - if (fvp->v_mount != tdvp->v_mount) { + if (fromnd.nl_ncp->nc_mount != tond.nl_ncp->nc_mount) { if (v3) error = EXDEV; else error = ENOTEMPTY; goto out; } - if (fvp == tdvp) { + if (fromnd.nl_ncp == tond.nl_ncp->nc_parent) { if (v3) error = EINVAL; else error = ENOTEMPTY; } + + /* + * You cannot rename a source into itself or a subdirectory of itself. + * We check this by travsering the target directory upwards looking + * for a match against the source. + */ + if (error == 0) { + for (ncp = tond.nl_ncp; ncp; ncp = ncp->nc_parent) { + if (fromnd.nl_ncp == ncp) { + error = EINVAL; + break; + } + } + } + /* * If source is the same as the destination (that is the * same vnode with the same name in the same directory), * then there is nothing to do. */ - if (fvp == tvp && fromnd.ni_dvp == tdvp && - fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && - !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, - fromnd.ni_cnd.cn_namelen)) + if (fromnd.nl_ncp == tond.nl_ncp) error = -1; out: if (!error) { /* - * The VOP_RENAME function releases all vnode references & + * The VOP_NRENAME function releases all vnode references & * locks prior to returning so we need to clear the pointers * to bypass cleanup code later on. */ - nqsrv_getl(fromnd.ni_dvp, ND_WRITE); +#if 0 + /* XXX should be handled by NRENAME */ + nqsrv_getl(fdvp, ND_WRITE); nqsrv_getl(tdvp, ND_WRITE); if (tvp) { nqsrv_getl(tvp, ND_WRITE); } - error = VOP_RENAME(fromnd.ni_dvp, NCPNULL, fromnd.ni_vp, &fromnd.ni_cnd, - tond.ni_dvp, NCPNULL, tond.ni_vp, &tond.ni_cnd); - if (error == 0) - cache_purge(fromnd.ni_vp); - fromnd.ni_dvp = NULL; - fromnd.ni_vp = NULL; - tond.ni_dvp = NULL; - tond.ni_vp = NULL; - if (error) { - fromnd.ni_cnd.cn_flags &= ~CNP_HASBUF; - tond.ni_cnd.cn_flags &= ~CNP_HASBUF; - } +#endif + error = VOP_NRENAME(fromnd.nl_ncp, tond.nl_ncp, tond.nl_cred); } else { if (error == -1) error = 0; @@ -2303,36 +2286,12 @@ out1: /* fall through */ nfsmout: - /* - * Clear out tond related fields - */ if (tdirp) vrele(tdirp); - if (tond.ni_startdir) - vrele(tond.ni_startdir); - NDFREE(&tond, NDF_ONLY_PNBUF); - if (tond.ni_dvp) { - if (tond.ni_dvp == tond.ni_vp) - vrele(tond.ni_dvp); - else - vput(tond.ni_dvp); - } - if (tond.ni_vp) - vput(tond.ni_vp); - - /* - * Clear out fromnd related fields - */ + nlookup_done(&tond); if (fdirp) vrele(fdirp); - if (fromnd.ni_startdir) - vrele(fromnd.ni_startdir); - NDFREE(&fromnd, NDF_ONLY_PNBUF); - if (fromnd.ni_dvp) - vrele(fromnd.ni_dvp); - if (fromnd.ni_vp) - vrele(fromnd.ni_vp); - + nlookup_done(&fromnd); return (error); } @@ -2347,7 +2306,7 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct sockaddr *nam = nfsd->nd_nam; caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; - struct nameidata nd; + struct nlookupdata nd; u_int32_t *tl; int32_t t1; caddr_t bpos; @@ -2355,14 +2314,18 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mreq; - struct vnode *vp = NULL, *xp, *dirp = (struct vnode *)0; + struct vnode *dirp; + struct vnode *dvp; + struct vnode *vp; + struct vnode *xp; struct vattr dirfor, diraft, at; nfsfh_t nfh, dnfh; fhandle_t *fhp, *dfhp; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); + nlookup_zero(&nd); + dirp = dvp = vp = xp = NULL; fhp = &nfh.fh_generic; dfhp = &dnfh.fh_generic; @@ -2370,56 +2333,50 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsm_srvmtofh(dfhp); nfsm_srvnamesiz(len); - error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam, + error = nfsrv_fhtovp(fhp, FALSE, &xp, cred, slp, nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); if (error) { nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); nfsm_srvpostop_attr(getret, &at); nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); - vp = NULL; + xp = NULL; error = 0; goto nfsmout; } - if (vp->v_type == VDIR) { + if (xp->v_type == VDIR) { error = EPERM; /* POSIX */ goto out1; } - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = NAMEI_CREATE; - nd.ni_cnd.cn_flags = CNP_LOCKPARENT; - error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + + error = nfs_namei(&nd, cred, NAMEI_CREATE, &dvp, &vp, + dfhp, len, slp, nam, &md, &dpos, &dirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { - if (v3) { + if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, td); - } else { - vrele(dirp); - dirp = NULL; - } } if (error) goto out1; - xp = nd.ni_vp; - if (xp != NULL) { + if (vp != NULL) { error = EEXIST; goto out; } - xp = nd.ni_dvp; - if (vp->v_mount != xp->v_mount) + if (xp->v_mount != dvp->v_mount) error = EXDEV; out: if (!error) { - nqsrv_getl(vp, ND_WRITE); +#if 0 nqsrv_getl(xp, ND_WRITE); - error = VOP_LINK(nd.ni_dvp, NCPNULL, vp, &nd.ni_cnd); - NDFREE(&nd, NDF_ONLY_PNBUF); + nqsrv_getl(vp, ND_WRITE); +#endif + error = VOP_NLINK(nd.nl_ncp, xp, nd.nl_cred); } /* fall through */ out1: if (v3) - getret = VOP_GETATTR(vp, &at, td); + getret = VOP_GETATTR(xp, &at, td); if (dirp) diraft_ret = VOP_GETATTR(dirp, &diraft, td); nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); @@ -2431,19 +2388,19 @@ out1: /* fall through */ nfsmout: - NDFREE(&nd, NDF_ONLY_PNBUF); + nlookup_done(&nd); if (dirp) vrele(dirp); - if (vp) - vrele(vp); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); + if (xp) + vrele(xp); + if (dvp) { + if (dvp == vp) + vrele(dvp); else - vput(nd.ni_dvp); + vput(dvp); } - if (nd.ni_vp) - vrele(nd.ni_vp); + if (vp) + vput(vp); return(error); } @@ -2459,7 +2416,7 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; struct vattr va, dirfor, diraft; - struct nameidata nd; + struct nlookupdata nd; struct vattr *vap = &va; u_int32_t *tl; int32_t t1; @@ -2470,29 +2427,26 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1; int v3 = (nfsd->nd_flag & ND_NFSV3); struct mbuf *mb, *mreq, *mb2; - struct vnode *dirp = (struct vnode *)0; + struct vnode *dirp; + struct vnode *vp; nfsfh_t nfh; fhandle_t *fhp; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); + nlookup_zero(&nd); + dirp = vp = NULL; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = NAMEI_CREATE; - nd.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_SAVESTART; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + + error = nfs_namei(&nd, cred, NAMEI_CREATE, NULL, &vp, + fhp, len, slp, nam, &md, &dpos, &dirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { - if (v3) { + if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, td); - } else { - vrele(dirp); - dirp = NULL; - } } if (error) goto out; @@ -2517,30 +2471,30 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, vap->va_mode = nfstov_mode(sp->sa_mode); } *(pathcp + len2) = '\0'; - if (nd.ni_vp) { + if (vp) { error = EEXIST; goto out; } - /* - * issue symlink op. SAVESTART is set so the underlying path component - * is only freed by the VOP if an error occurs. - */ if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; - nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_SYMLINK(nd.ni_dvp, NCPNULL, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); - if (error) - NDFREE(&nd, NDF_ONLY_PNBUF); - else - vput(nd.ni_vp); - nd.ni_vp = NULL; +#if 0 + nqsrv_getl(dvp, ND_WRITE); +#endif + error = VOP_NSYMLINK(nd.nl_ncp, &vp, nd.nl_cred, vap, pathcp); + if (error == 0) { + bzero((caddr_t)fhp, sizeof(nfh)); + fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(vp, &fhp->fh_fid); + if (!error) + error = VOP_GETATTR(vp, vap, td); + } + +#if 0 /* - * releases directory prior to potential lookup op. + * We have a vp in hand from the new API call, we do not have to + * look it up again. */ - vput(nd.ni_dvp); - nd.ni_dvp = NULL; - if (error == 0) { if (v3) { /* @@ -2552,7 +2506,6 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, */ nd.ni_cnd.cn_nameiop = NAMEI_LOOKUP; nd.ni_cnd.cn_flags &= ~(CNP_LOCKPARENT | CNP_FOLLOW); - nd.ni_cnd.cn_flags |= CNP_LOCKLEAF; nd.ni_cnd.cn_td = td; nd.ni_cnd.cn_cred = cred; @@ -2570,11 +2523,12 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, } } } +#endif out: - /* - * These releases aren't strictly required, does even doing them - * make any sense? XXX can nfsm_reply() block? - */ + if (vp) { + vput(vp); + vp = NULL; + } if (pathcp) { FREE(pathcp, M_TEMP); pathcp = NULL; @@ -2584,10 +2538,6 @@ out: vrele(dirp); dirp = NULL; } - if (nd.ni_startdir) { - vrele(nd.ni_startdir); - nd.ni_startdir = NULL; - } nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); if (v3) { if (!error) { @@ -2600,22 +2550,13 @@ out: /* fall through */ nfsmout: - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) - vrele(nd.ni_vp); - if (nd.ni_startdir) - vrele(nd.ni_startdir); + nlookup_done(&nd); + if (vp) + vput(vp); if (dirp) vrele(dirp); if (pathcp) FREE(pathcp, M_TEMP); - return (error); } @@ -2633,7 +2574,7 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct vattr va, dirfor, diraft; struct vattr *vap = &va; struct nfs_fattr *fp; - struct nameidata nd; + struct nlookupdata nd; caddr_t cp; u_int32_t *tl; int32_t t1; @@ -2642,31 +2583,27 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mb2, *mreq; - struct vnode *dirp = NULL; - int vpexcl = 0; + struct vnode *dirp; + struct vnode *vp; nfsfh_t nfh; fhandle_t *fhp; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); + nlookup_zero(&nd); + dirp = NULL; + vp = NULL; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = NAMEI_CREATE; - nd.ni_cnd.cn_flags = CNP_LOCKPARENT; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + error = nfs_namei(&nd, cred, NAMEI_CREATE, NULL, &vp, + fhp, len, slp, nam, &md, &dpos, &dirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { - if (v3) { + if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, td); - } else { - vrele(dirp); - dirp = NULL; - } } if (error) { nfsm_reply(NFSX_WCCDATA(v3)); @@ -2688,8 +2625,7 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, */ vap->va_type = VDIR; - if (nd.ni_vp != NULL) { - NDFREE(&nd, NDF_ONLY_PNBUF); + if (vp != NULL) { error = EEXIST; goto out; } @@ -2701,20 +2637,17 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, */ if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; +#if 0 nqsrv_getl(nd.ni_dvp, ND_WRITE); - error = VOP_MKDIR(nd.ni_dvp, NCPNULL, &nd.ni_vp, &nd.ni_cnd, vap); - NDFREE(&nd, NDF_ONLY_PNBUF); - vpexcl = 1; - - vput(nd.ni_dvp); - nd.ni_dvp = NULL; +#endif + error = VOP_NMKDIR(nd.nl_ncp, &vp, nd.nl_cred, vap); - if (!error) { + if (error == 0) { bzero((caddr_t)fhp, sizeof(nfh)); - fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); - if (!error) - error = VOP_GETATTR(nd.ni_vp, vap, td); + fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; + error = VFS_VPTOFH(vp, &fhp->fh_fid); + if (error == 0) + error = VOP_GETATTR(vp, vap, td); } out: if (dirp) @@ -2735,21 +2668,11 @@ out: /* fall through */ nfsmout: + nlookup_done(&nd); if (dirp) vrele(dirp); - if (nd.ni_dvp) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == nd.ni_vp && vpexcl) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) { - if (vpexcl) - vput(nd.ni_vp); - else - vrele(nd.ni_vp); - } + if (vp) + vput(vp); return (error); } @@ -2771,31 +2694,29 @@ nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, int v3 = (nfsd->nd_flag & ND_NFSV3); char *cp2; struct mbuf *mb, *mreq; - struct vnode *vp, *dirp = (struct vnode *)0; + struct vnode *dirp; + struct vnode *vp; struct vattr dirfor, diraft; nfsfh_t nfh; fhandle_t *fhp; - struct nameidata nd; + struct nlookupdata nd; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); - ndclear(&nd); + nlookup_zero(&nd); + dirp = NULL; + vp = NULL; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); - nd.ni_cnd.cn_cred = cred; - nd.ni_cnd.cn_nameiop = NAMEI_DELETE; - nd.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_LOCKLEAF; - error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); + + error = nfs_namei(&nd, cred, NAMEI_DELETE, NULL, &vp, + fhp, len, slp, nam, &md, &dpos, &dirp, + td, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { - if (v3) { + if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, td); - } else { - vrele(dirp); - dirp = NULL; - } } if (error) { nfsm_reply(NFSX_WCCDATA(v3)); @@ -2803,18 +2724,11 @@ nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = 0; goto nfsmout; } - vp = nd.ni_vp; if (vp->v_type != VDIR) { error = ENOTDIR; goto out; } - /* - * No rmdir "." please. - */ - if (nd.ni_dvp == vp) { - error = EINVAL; - goto out; - } + /* * The root of a mounted filesystem cannot be deleted. */ @@ -2826,13 +2740,15 @@ out: * component is freed by the VOP after either. */ if (!error) { +#if 0 nqsrv_getl(nd.ni_dvp, ND_WRITE); nqsrv_getl(vp, ND_WRITE); - error = VOP_RMDIR(nd.ni_dvp, NCPNULL, nd.ni_vp, &nd.ni_cnd); - if (error == 0) - cache_purge(nd.ni_vp); +#endif + vput(vp); + vp = NULL; + error = VOP_NRMDIR(nd.nl_ncp, nd.nl_cred); } - NDFREE(&nd, NDF_ONLY_PNBUF); + nlookup_done(&nd); if (dirp) diraft_ret = VOP_GETATTR(dirp, &diraft, td); @@ -2844,18 +2760,11 @@ out: /* fall through */ nfsmout: - NDFREE(&nd, NDF_ONLY_PNBUF); + nlookup_done(&nd); if (dirp) vrele(dirp); - if (nd.ni_dvp) { - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - if (nd.ni_vp) - vput(nd.ni_vp); - + if (vp) + vput(vp); return(error); } diff --git a/sys/vfs/nfs/nfs_socket.c b/sys/vfs/nfs/nfs_socket.c index e5950e5a6e..d50d638289 100644 --- a/sys/vfs/nfs/nfs_socket.c +++ b/sys/vfs/nfs/nfs_socket.c @@ -35,7 +35,7 @@ * * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95 * $FreeBSD: src/sys/nfs/nfs_socket.c,v 1.60.2.6 2003/03/26 01:44:46 alfred Exp $ - * $DragonFly: src/sys/vfs/nfs/nfs_socket.c,v 1.20 2004/09/17 10:03:35 dillon Exp $ + * $DragonFly: src/sys/vfs/nfs/nfs_socket.c,v 1.21 2004/11/12 00:09:37 dillon Exp $ */ /* @@ -1166,7 +1166,7 @@ tryagain: * lookup cache, just in case. */ if (error == ESTALE) - cache_purge(vp); + cache_inval_vp(vp, CINV_SELF); if (nmp->nm_flag & NFSMNT_NFSV3) { *mrp = mrep; *mdp = md; diff --git a/sys/vfs/nfs/nfs_subs.c b/sys/vfs/nfs/nfs_subs.c index e6278a5d1b..c1caa7e1eb 100644 --- a/sys/vfs/nfs/nfs_subs.c +++ b/sys/vfs/nfs/nfs_subs.c @@ -35,7 +35,7 @@ * * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 * $FreeBSD: /repoman/r/ncvs/src/sys/nfsclient/nfs_subs.c,v 1.128 2004/04/14 23:23:55 peadar Exp $ - * $DragonFly: src/sys/vfs/nfs/nfs_subs.c,v 1.22 2004/10/12 19:21:01 dillon Exp $ + * $DragonFly: src/sys/vfs/nfs/nfs_subs.c,v 1.23 2004/11/12 00:09:37 dillon Exp $ */ /* @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -561,8 +562,6 @@ extern int nfssvc(struct proc *, struct nfssvc_args *, int *); LIST_HEAD(nfsnodehashhead, nfsnode); -int nfs_webnamei (struct nameidata *, struct vnode *, struct proc *); - u_quad_t nfs_curusec(void) { @@ -1353,7 +1352,10 @@ nfs_getattrcache(struct vnode *vp, struct vattr *vaper) np = VTONFS(vp); vap = &np->n_vattr; nmp = VFSTONFS(vp->v_mount); - /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ + + /* + * Dynamic timeout based on how recently the file was modified. + */ timeo = (time_second - np->n_mtime) / 10; #ifdef NFS_ACDEBUG @@ -1415,6 +1417,7 @@ nfs_getattrcache(struct vnode *vp, struct vattr *vaper) } #ifndef NFS_NOSERVER + /* * Set up nameidata for a lookup() call and do it. * @@ -1424,37 +1427,41 @@ nfs_getattrcache(struct vnode *vp, struct vattr *vaper) * the lookup result is within the public fs, and deny access if * it is not. * - * nfs_namei() clears out garbage fields that namei() might leave garbage. - * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no - * error occurs but the parent was not requested. - * * dirp may be set whether an error is returned or not, and must be * released by the caller. + * + * On return nd->nl_ncp usually points to the target ncp, which may represent + * a negative hit. + * + * NOTE: the caller must call nlookup_done(nd) unconditionally on return + * to cleanup. */ int -nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, - struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, - caddr_t *dposp, struct vnode **retdirp, struct thread *td, - int kerbflag, int pubflag) +nfs_namei(struct nlookupdata *nd, struct ucred *cred, int nameiop, + struct vnode **dvpp, struct vnode **vpp, + fhandle_t *fhp, int len, + struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, + caddr_t *dposp, struct vnode **dirpp, struct thread *td, + int kerbflag, int pubflag) { int i, rem; + int flags; struct mbuf *md; char *fromcp, *tocp, *cp; - struct iovec aiov; - struct uio auio; + char *namebuf; + struct namecache *ncp; struct vnode *dp; - int error, rdonly, linklen; - struct componentname *cnp = &ndp->ni_cnd; + int error, rdonly; - *retdirp = (struct vnode *)0; - cnp->cn_pnbuf = zalloc(namei_zone); + namebuf = zalloc(namei_zone); + flags = 0; + *dirpp = NULL; /* - * Copy the name from the mbuf list to ndp->ni_pnbuf - * and set the various ndp fields appropriately. + * Copy the name from the mbuf list to namebuf. */ fromcp = *dposp; - tocp = cnp->cn_pnbuf; + tocp = namebuf; md = *mdp; rem = mtod(md, caddr_t) + md->m_len - fromcp; for (i = 0; i < len; i++) { @@ -1486,10 +1493,11 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, } /* - * Extract and set starting directory. + * Extract and set starting directory. The returned dp is refd + * but not locked. */ - error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, - nam, &rdonly, kerbflag, pubflag); + error = nfsrv_fhtovp(fhp, FALSE, &dp, cred, slp, + nam, &rdonly, kerbflag, pubflag); if (error) goto out; if (dp->v_type != VDIR) { @@ -1498,14 +1506,12 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, goto out; } - if (rdonly) - cnp->cn_flags |= CNP_RDONLY; - /* * Set return directory. Reference to dp is implicitly transfered - * to the returned pointer + * to the returned pointer. This must be set before we potentially + * goto out below. */ - *retdirp = dp; + *dirpp = dp; if (pubflag) { /* @@ -1513,7 +1519,7 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, * and the 'native path' indicator. */ cp = zalloc(namei_zone); - fromcp = cnp->cn_pnbuf; + fromcp = namebuf; tocp = cp; if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { switch ((unsigned char)*fromcp) { @@ -1553,151 +1559,79 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, *tocp++ = *fromcp++; } *tocp = '\0'; - zfree(namei_zone, cnp->cn_pnbuf); - cnp->cn_pnbuf = cp; + zfree(namei_zone, namebuf); + namebuf = cp; } - ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; - ndp->ni_segflg = UIO_SYSSPACE; - - if (pubflag) { - ndp->ni_rootdir = rootvnode; - ndp->ni_loopcnt = 0; - if (cnp->cn_pnbuf[0] == '/') - dp = rootvnode; - } else { - cnp->cn_flags |= CNP_NOCROSSMOUNT; + /* + * Setup for search. We need to get a start directory from dp. Note + * that dp is ref'd, but we no longer 'own' the ref (*dirpp owns it). + */ + if (pubflag == 0) { + flags |= NLC_NFS_NOSOFTLINKTRAV; + flags |= NLC_NOCROSSMOUNT; } + if (rdonly) + flags |= NLC_NFS_RDONLY; + if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) + flags |= NLC_CREATE; /* - * Initialize for scan, set ni_startdir and bump ref on dp again - * because lookup() will dereference ni_startdir. + * We need a starting ncp from the directory vnode dp. dp must not + * be locked. The returned ncp will be refd but not locked. + * + * If no suitable ncp is found we instruct cache_fromdvp() to create + * one. If this fails the directory has probably been removed while + * the target was chdir'd into it and any further lookup will fail. */ + if ((ncp = cache_fromdvp(dp, cred, 1)) == NULL) { + error = EINVAL; + goto out; + } + nlookup_init_raw(nd, namebuf, UIO_SYSSPACE, flags, cred, ncp); + cache_drop(ncp); - cnp->cn_td = td; - vref(dp); - ndp->ni_startdir = dp; - - for (;;) { - cnp->cn_nameptr = cnp->cn_pnbuf; - /* - * Call lookup() to do the real work. If an error occurs, - * ndp->ni_vp and ni_dvp are left uninitialized or NULL and - * we do not have to dereference anything before returning. - * In either case ni_startdir will be dereferenced and NULLed - * out. - */ - error = lookup(ndp); - if (error) - break; - - /* - * Check for encountering a symbolic link. Trivial - * termination occurs if no symlink encountered. - * Note: zfree is safe because error is 0, so we will - * not zfree it again when we break. - */ - if ((cnp->cn_flags & CNP_ISSYMLINK) == 0) { - nfsrv_object_create(ndp->ni_vp); - if (cnp->cn_flags & (CNP_SAVENAME | CNP_SAVESTART)) - cnp->cn_flags |= CNP_HASBUF; - else - zfree(namei_zone, cnp->cn_pnbuf); - break; - } + /* + * Ok, do the lookup. + */ + error = nlookup(nd); - /* - * Validate symlink - */ - if ((cnp->cn_flags & CNP_LOCKPARENT) && ndp->ni_pathlen == 1) - VOP_UNLOCK(ndp->ni_dvp, 0, td); - if (!pubflag) { - error = EINVAL; - goto badlink2; + /* + * If no error occured return the requested dvpp and vpp. If + * NLC_CREATE was specified nd->nl_ncp may represent a negative + * cache hit in which case we do not attempt to obtain the vp. + */ + if (error == 0) { + ncp = nd->nl_ncp; + if (dvpp) { + if (ncp->nc_parent && + ncp->nc_parent->nc_mount == ncp->nc_mount) { + error = cache_vget(ncp->nc_parent, nd->nl_cred, + LK_EXCLUSIVE, dvpp); + } else { + error = ENXIO; + } } - - if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { - error = ELOOP; - goto badlink2; + if (vpp && ncp->nc_vp) { + error = cache_vget(ncp, nd->nl_cred, LK_EXCLUSIVE, vpp); } - if (ndp->ni_pathlen > 1) - cp = zalloc(namei_zone); - else - cp = cnp->cn_pnbuf; - aiov.iov_base = cp; - aiov.iov_len = MAXPATHLEN; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_td = NULL; - auio.uio_resid = MAXPATHLEN; - error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); if (error) { - badlink1: - if (ndp->ni_pathlen > 1) - zfree(namei_zone, cp); - badlink2: - vrele(ndp->ni_dvp); - vput(ndp->ni_vp); - break; - } - linklen = MAXPATHLEN - auio.uio_resid; - if (linklen == 0) { - error = ENOENT; - goto badlink1; - } - if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { - error = ENAMETOOLONG; - goto badlink1; - } - - /* - * Adjust or replace path - */ - if (ndp->ni_pathlen > 1) { - bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); - zfree(namei_zone, cnp->cn_pnbuf); - cnp->cn_pnbuf = cp; - } else - cnp->cn_pnbuf[linklen] = '\0'; - ndp->ni_pathlen += linklen; - - /* - * Cleanup refs for next loop and check if root directory - * should replace current directory. Normally ni_dvp - * becomes the new base directory and is cleaned up when - * we loop. Explicitly null pointers after invalidation - * to clarify operation. - */ - vput(ndp->ni_vp); - ndp->ni_vp = NULL; - - if (cnp->cn_pnbuf[0] == '/') { - vrele(ndp->ni_dvp); - ndp->ni_dvp = ndp->ni_rootdir; - vref(ndp->ni_dvp); + if (dvpp && *dvpp) { + vput(*dvpp); + *dvpp = NULL; + } + if (vpp && *vpp) { + vput(*vpp); + *vpp = NULL; + } } - ndp->ni_startdir = ndp->ni_dvp; - ndp->ni_dvp = NULL; } /* - * nfs_namei() guarentees that fields will not contain garbage - * whether an error occurs or not. This allows the caller to track - * cleanup state trivially. + * Finish up. */ out: - if (error) { - zfree(namei_zone, cnp->cn_pnbuf); - ndp->ni_vp = NULL; - ndp->ni_dvp = NULL; - ndp->ni_startdir = NULL; - cnp->cn_flags &= ~CNP_HASBUF; - } else if ((ndp->ni_cnd.cn_flags & (CNP_WANTPARENT|CNP_LOCKPARENT)) == 0) { - ndp->ni_dvp = NULL; - } + zfree(namei_zone, namebuf); return (error); } diff --git a/sys/vfs/nfs/nfs_syscalls.c b/sys/vfs/nfs/nfs_syscalls.c index d716a04896..3f7db35c50 100644 --- a/sys/vfs/nfs/nfs_syscalls.c +++ b/sys/vfs/nfs/nfs_syscalls.c @@ -35,7 +35,7 @@ * * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 * $FreeBSD: src/sys/nfs/nfs_syscalls.c,v 1.58.2.1 2000/11/26 02:30:06 dillon Exp $ - * $DragonFly: src/sys/vfs/nfs/nfs_syscalls.c,v 1.18 2004/08/02 13:22:34 joerg Exp $ + * $DragonFly: src/sys/vfs/nfs/nfs_syscalls.c,v 1.19 2004/11/12 00:09:37 dillon Exp $ */ #include @@ -56,7 +56,7 @@ #include #include #include -#include +#include #include #include @@ -137,7 +137,7 @@ int nfssvc(struct nfssvc_args *uap) { #ifndef NFS_NOSERVER - struct nameidata nd; + struct nlookupdata nd; struct file *fp; struct sockaddr *nam; struct nfsd_args nfsdarg; @@ -147,6 +147,7 @@ nfssvc(struct nfssvc_args *uap) struct nfssvc_sock *slp; struct nfsuid *nuidp; struct nfsmount *nmp; + struct vnode *vp; #endif /* NFS_NOSERVER */ int error; struct thread *td = curthread; @@ -172,16 +173,21 @@ nfssvc(struct nfssvc_args *uap) error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); if (error) return (error); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, - UIO_USERSPACE, ncd.ncd_dirp, td); - error = namei(&nd); + vp = NULL; + error = nlookup_init(&nd, ncd.ncd_dirp, UIO_USERSPACE, + NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, &vp); + nlookup_done(&nd); if (error) return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - if ((nd.ni_vp->v_flag & VROOT) == 0) + + if ((vp->v_flag & VROOT) == 0) error = EINVAL; - nmp = VFSTONFS(nd.ni_vp->v_mount); - vput(nd.ni_vp); + nmp = VFSTONFS(vp->v_mount); + vput(vp); if (error) return (error); if ((nmp->nm_state & NFSSTA_MNTD) && diff --git a/sys/vfs/nfs/nfs_vnops.c b/sys/vfs/nfs/nfs_vnops.c index cf908db2bf..6a8ccbb308 100644 --- a/sys/vfs/nfs/nfs_vnops.c +++ b/sys/vfs/nfs/nfs_vnops.c @@ -35,7 +35,7 @@ * * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95 * $FreeBSD: src/sys/nfs/nfs_vnops.c,v 1.150.2.5 2001/12/20 19:56:28 dillon Exp $ - * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.35 2004/10/12 19:21:01 dillon Exp $ + * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.36 2004/11/12 00:09:37 dillon Exp $ */ @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -135,6 +136,8 @@ static int nfs_readlink (struct vop_readlink_args *); static int nfs_print (struct vop_print_args *); static int nfs_advlock (struct vop_advlock_args *); static int nfs_bwrite (struct vop_bwrite_args *); + +static int nfs_nresolve (struct vop_nresolve_args *); /* * Global vfs data structures for nfs */ @@ -174,6 +177,8 @@ struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { { &vop_symlink_desc, (void *) nfs_symlink }, { &vop_unlock_desc, (void *) vop_stdunlock }, { &vop_write_desc, (void *) nfs_write }, + + { &vop_nresolve_desc, (void *) nfs_nresolve }, { NULL, NULL } }; @@ -371,9 +376,10 @@ nfs_access(struct vop_access_args *ap) * Does our cached result allow us to give a definite yes to * this request? */ - if ((mycpu->gd_time_seconds < (np->n_modestamp + nfsaccess_cache_timeout)) && - (ap->a_cred->cr_uid == np->n_modeuid) && - ((np->n_mode & mode) == mode)) { + if (np->n_modestamp && + (mycpu->gd_time_seconds < (np->n_modestamp + nfsaccess_cache_timeout)) && + (ap->a_cred->cr_uid == np->n_modeuid) && + ((np->n_mode & mode) == mode)) { nfsstats.accesscache_hits++; } else { /* @@ -525,8 +531,14 @@ nfs_open(struct vop_open_args *ap) } } } - if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) - np->n_attrstamp = 0; /* For Open/Close consistency */ + + /* + * Clear attrstamp only if opening with write access. It is unclear + * whether we should do this at all here, but we certainly should not + * clear attrstamp unconditionally. + */ + if (ap->a_mode & FWRITE) + np->n_attrstamp = 0; return (0); } @@ -809,9 +821,129 @@ nfsmout: return (error); } +/* + * NEW API CALL - replaces nfs_lookup(). However, we cannot remove + * nfs_lookup() until all remaining new api calls are implemented. + * + * Resolve a namecache entry. This function is passed a locked ncp and + * must call cache_setvp() on it as appropriate to resolve the entry. + */ +static int +nfs_nresolve(struct vop_nresolve_args *ap) +{ + struct thread *td = curthread; + struct namecache *ncp; + struct ucred *cred; + struct nfsnode *np; + struct vnode *dvp; + struct vnode *nvp; + nfsfh_t *fhp; + int attrflag; + int fhsize; + int error; + int len; + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; + u_int32_t *tl; + int32_t t1, t2; + + cred = ap->a_cred; + ncp = ap->a_ncp; + + KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp); + dvp = ncp->nc_parent->nc_vp; + if ((error = vget(dvp, LK_SHARED, td)) != 0) + return (error); + + nvp = NULL; + v3 = NFS_ISV3(dvp); + nfsstats.lookupcache_misses++; + nfsstats.rpccnt[NFSPROC_LOOKUP]++; + len = ncp->nc_nlen; + nfsm_reqhead(dvp, NFSPROC_LOOKUP, + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); + nfsm_fhtom(dvp, v3); + nfsm_strtom(ncp->nc_name, len, NFS_MAXNAMLEN); + nfsm_request(dvp, NFSPROC_LOOKUP, td, ap->a_cred); + if (error) { + /* + * Cache negatve lookups to reduce NFS traffic, but use + * a fast timeout. Otherwise use a timeout of 1 tick. + * XXX we should add a namecache flag for no-caching + * to uncache the negative hit as soon as possible, but + * we cannot simply destroy the entry because it is used + * as a placeholder by the caller. + */ + if (error == ENOENT) { + int nticks; + + if (nfsneg_cache_timeout) + nticks = nfsneg_cache_timeout * hz; + else + nticks = 1; + cache_setvp(ncp, NULL); + cache_settimeout(ncp, nticks); + } + nfsm_postop_attr(dvp, attrflag); + m_freem(mrep); + goto nfsmout; + } + + /* + * Success, get the file handle, do various checks, and load + * post-operation data from the reply packet. Theoretically + * we should never be looking up "." so, theoretically, we + * should never get the same file handle as our directory. But + * we check anyway. XXX + * + * Note that no timeout is set for the positive cache hit. We + * assume, theoretically, that ESTALE returns will be dealt with + * properly to handle NFS races and in anycase we cannot depend + * on a timeout to deal with NFS open/create/excl issues so instead + * of a bad hack here the rest of the NFS client code needs to do + * the right thing. + */ + nfsm_getfh(fhp, fhsize, v3); + + np = VTONFS(dvp); + if (NFS_CMPFH(np, fhp, fhsize)) { + vref(dvp); + nvp = dvp; + } else { + error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); + if (error) { + m_freem(mrep); + vput(dvp); + return (error); + } + nvp = NFSTOV(np); + } + if (v3) { + nfsm_postop_attr(nvp, attrflag); + nfsm_postop_attr(dvp, attrflag); + } else { + nfsm_loadattr(nvp, NULL); + } + cache_setvp(ncp, nvp); + m_freem(mrep); +nfsmout: + vput(dvp); + if (nvp) { + if (nvp == dvp) + vrele(nvp); + else + vput(nvp); + } + return (error); +} + /* * 'cached' nfs directory lookup * + * NOTE: cannot be removed until NFS implements all the new n*() API calls. + * * nfs_lookup(struct vnodeop_desc *a_desc, struct vnode *a_dvp, * struct vnode **a_vpp, struct componentname *a_cnp) */ @@ -840,7 +972,7 @@ nfs_lookup(struct vop_lookup_args *ap) * Read-only mount check and directory check. */ *vpp = NULLVP; - if ((flags & CNP_ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && + if ((dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) return (EROFS); @@ -857,102 +989,9 @@ nfs_lookup(struct vop_lookup_args *ap) wantparent = flags & (CNP_LOCKPARENT|CNP_WANTPARENT); nmp = VFSTONFS(dvp->v_mount); np = VTONFS(dvp); - error = cache_lookup(dvp, vpp, cnp); - if (error != 0) { - struct vattr vattr; - int vpid; - if (error == ENOENT) { - if (nfsneg_cache_timeout) { - *vpp = NULLVP; - return (error); - } - goto miss; - } - if (error > 0) { - printf("nfs_lookup: %*.*s weird error %d\n", - (int)cnp->cn_namelen, (int)cnp->cn_namelen, - cnp->cn_nameptr, error); - *vpp = NULLVP; - return (error); - } - - /* - * At this point we have a cache hit (error should be -1). - * The vnode returned in *vpp will be referenced but not - * locked. - */ - if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) { - vrele(*vpp); - *vpp = NULLVP; - return (error); - } - - newvp = *vpp; - vpid = newvp->v_id; - /* - * See the comment starting `Step through' in ufs/ufs_lookup.c - * for an explanation of the locking protocol - */ - if (dvp == newvp) { - /* newvp already ref'd from lookup */ - error = 0; - } else if (flags & CNP_ISDOTDOT) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= CNP_PDIRUNLOCK; - error = vget(newvp, LK_EXCLUSIVE, td); - vrele(newvp); /* get rid of ref from lookup */ - if (!error && lockparent && (flags & CNP_ISLASTCN)) { - error = vn_lock(dvp, LK_EXCLUSIVE, td); - if (error == 0) - cnp->cn_flags &= ~CNP_PDIRUNLOCK; - } - } else { - error = vget(newvp, LK_EXCLUSIVE, td); - vrele(newvp); /* get rid of ref from lookup */ - if (!lockparent || error || !(flags & CNP_ISLASTCN)) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= CNP_PDIRUNLOCK; - } - } - if (!error) { - /* - * Attempt to do a better job synchronizing our cache - * to the NFS server by checking the vnode against - * the nfs-only cache via VOP_GETATTR(). - * - * WARNING! An old ctime check has been removed. We - * can't just willy-nilly purge a directory vnode that - * might have children in the new VFS scheme. The - * ctime check was bogus anyway. - */ - if (vpid == newvp->v_id) { - if (VOP_GETATTR(newvp, &vattr, td) == 0) { - nfsstats.lookupcache_hits++; - if (cnp->cn_nameiop != NAMEI_LOOKUP && - (flags & CNP_ISLASTCN)) - cnp->cn_flags |= CNP_SAVENAME; - return (0); - } - cache_purge(newvp); - } - vput(newvp); - if (lockparent && dvp != newvp && (flags & CNP_ISLASTCN)) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= CNP_PDIRUNLOCK; - } - } - error = vn_lock(dvp, LK_EXCLUSIVE, td); - if (error == 0) - cnp->cn_flags &= ~CNP_PDIRUNLOCK; - *vpp = NULLVP; - if (error) - return (error); - } - -miss: /* - * Cache miss, go the wire. + * Go to the wire. */ error = 0; newvp = NULLVP; @@ -965,24 +1004,6 @@ miss: nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_td, cnp->cn_cred); if (error) { - /* - * Cache negatve lookups to reduce NFS traffic, but use - * a fast timeout. - */ - if (error == ENOENT && - (cnp->cn_flags & CNP_MAKEENTRY) && - cnp->cn_nameiop == NAMEI_LOOKUP && - nfsneg_cache_timeout) { - int toval = nfsneg_cache_timeout * hz; - if (cnp->cn_flags & CNP_CACHETIMEOUT) { - if (cnp->cn_timeout > toval) - cnp->cn_timeout = toval; - } else { - cnp->cn_flags |= CNP_CACHETIMEOUT; - cnp->cn_timeout = toval; - } - cache_enter(dvp, NULL, cnp); - } nfsm_postop_attr(dvp, attrflag); m_freem(mrep); goto nfsmout; @@ -992,7 +1013,7 @@ miss: /* * Handle RENAME case... */ - if (cnp->cn_nameiop == NAMEI_RENAME && wantparent && (flags & CNP_ISLASTCN)) { + if (cnp->cn_nameiop == NAMEI_RENAME && wantparent) { if (NFS_CMPFH(np, fhp, fhsize)) { m_freem(mrep); return (EISDIR); @@ -1010,7 +1031,6 @@ miss: nfsm_loadattr(newvp, (struct vattr *)0); *vpp = newvp; m_freem(mrep); - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; @@ -1028,7 +1048,7 @@ miss: return (error); /* NOTE: return error from nget */ } newvp = NFSTOV(np); - if (lockparent && (flags & CNP_ISLASTCN)) { + if (lockparent) { error = vn_lock(dvp, LK_EXCLUSIVE, td); if (error) { vput(newvp); @@ -1045,7 +1065,7 @@ miss: m_freem(mrep); return (error); } - if (!lockparent || !(flags & CNP_ISLASTCN)) { + if (!lockparent) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; } @@ -1056,13 +1076,13 @@ miss: nfsm_postop_attr(dvp, attrflag); } else nfsm_loadattr(newvp, (struct vattr *)0); - if (cnp->cn_nameiop != NAMEI_LOOKUP && (flags & CNP_ISLASTCN)) - cnp->cn_flags |= CNP_SAVENAME; +#if 0 + /* XXX MOVE TO nfs_nremove() */ if ((cnp->cn_flags & CNP_MAKEENTRY) && - (cnp->cn_nameiop != NAMEI_DELETE || !(flags & CNP_ISLASTCN))) { - np->n_ctime = np->n_vattr.va_ctime.tv_sec; - cache_enter(dvp, newvp, cnp); + cnp->cn_nameiop != NAMEI_DELETE) { + np->n_ctime = np->n_vattr.va_ctime.tv_sec; /* XXX */ } +#endif *vpp = newvp; m_freem(mrep); nfsmout: @@ -1071,8 +1091,9 @@ nfsmout: vrele(newvp); *vpp = NULLVP; } - if ((cnp->cn_nameiop == NAMEI_CREATE || cnp->cn_nameiop == NAMEI_RENAME) && - (flags & CNP_ISLASTCN) && error == ENOENT) { + if ((cnp->cn_nameiop == NAMEI_CREATE || + cnp->cn_nameiop == NAMEI_RENAME) && + error == ENOENT) { if (!lockparent) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; @@ -1082,8 +1103,6 @@ nfsmout: else error = EJUSTRETURN; } - if (cnp->cn_nameiop != NAMEI_LOOKUP && (flags & CNP_ISLASTCN)) - cnp->cn_flags |= CNP_SAVENAME; } return (error); } @@ -1412,8 +1431,6 @@ nfsmout: if (newvp) vput(newvp); } else { - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(dvp, newvp, cnp); *vpp = newvp; } VTONFS(dvp)->n_flag |= NMODIFIED; @@ -1544,8 +1561,6 @@ nfsmout: error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_td); } if (!error) { - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(dvp, newvp, cnp); /* * The new np may have enough info for access * checks, make sure rucred and wucred are @@ -1589,8 +1604,6 @@ nfs_remove(struct vop_remove_args *ap) struct vattr vattr; #ifndef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("nfs_remove: no name"); if (vp->v_usecount < 1) panic("nfs_remove: bad v_usecount"); #endif @@ -1599,14 +1612,6 @@ nfs_remove(struct vop_remove_args *ap) else if (vp->v_usecount == 1 || (np->n_sillyrename && VOP_GETATTR(vp, &vattr, cnp->cn_td) == 0 && vattr.va_nlink > 1)) { - /* - * Purge the name cache so that the chance of a lookup for - * the name succeeding while the remove is in progress is - * minimized. Without node locking it can still happen, such - * that an I/O op returns ESTALE, but since you get this if - * another host removes the file.. - */ - cache_purge(vp); /* * throw away biocache buffers, mainly to avoid * unnecessary delayed writes later. @@ -1624,8 +1629,9 @@ nfs_remove(struct vop_remove_args *ap) */ if (error == ENOENT) error = 0; - } else if (!np->n_sillyrename) + } else if (!np->n_sillyrename) { error = nfs_sillyrename(dvp, vp, cnp); + } np->n_attrstamp = 0; return (error); } @@ -1689,11 +1695,6 @@ nfs_rename(struct vop_rename_args *ap) struct componentname *fcnp = ap->a_fcnp; int error; -#ifndef DIAGNOSTIC - if ((tcnp->cn_flags & CNP_HASBUF) == 0 || - (fcnp->cn_flags & CNP_HASBUF) == 0) - panic("nfs_rename: no name"); -#endif /* Check for cross-device rename */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { @@ -1717,33 +1718,25 @@ nfs_rename(struct vop_rename_args *ap) /* * If the tvp exists and is in use, sillyrename it before doing the * rename of the new file over it. + * * XXX Can't sillyrename a directory. * - * We must purge tvp from the cache (old API) or further accesses - * will see the old version of the file and return ESTALE. + * We do not attempt to do any namecache purges in this old API + * routine. The new API compat functions have access to the actual + * namecache structures and will do it for us. */ if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename && tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) { - cache_purge(tvp); vput(tvp); tvp = NULL; } else if (tvp) { - cache_purge(tvp); + ; } error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen, tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred, tcnp->cn_td); - cache_purge(fvp); -#if 0 - if (fvp->v_type == VDIR) { - if (tvp != NULL && tvp->v_type == VDIR) - cache_purge(tdvp); - cache_purge(fdvp); - } -#endif - out: if (tdvp == tvp) vrele(tdvp); @@ -2083,10 +2076,6 @@ nfsmout: VTONFS(dvp)->n_flag |= NMODIFIED; if (!wccflag) VTONFS(dvp)->n_attrstamp = 0; -#if 0 - cache_purge(dvp); -#endif - cache_purge(vp); /* * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. */ @@ -2338,8 +2327,6 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop) nfsuint64 *cookiep; caddr_t bpos, dpos, cp2, dpossav1, dpossav2; struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2; - struct nameidata nami, *ndp = &nami; - struct componentname *cnp = &ndp->ni_cnd; nfsuint64 cookie; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *dnp = VTONFS(vp), *np; @@ -2347,6 +2334,9 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop) u_quad_t fileno; int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i; int attrflag, fhsize; + struct namecache *ncp; + struct namecache *dncp; + struct nlcomponent nlc; #ifndef nolint dp = (struct dirent *)0; @@ -2356,7 +2346,16 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop) (uiop->uio_resid & (DIRBLKSIZ - 1))) panic("nfs readdirplusrpc bad uio"); #endif - ndp->ni_dvp = vp; + /* + * Obtain the namecache record for the directory so we have something + * to use as a basis for creating the entries. This function will + * return a held (but not locked) ncp. The ncp may be disconnected + * from the tree and cannot be used for upward traversals, and the + * ncp may be unnamed. Note that other unrelated operations may + * cause the ncp to be named at any time. + */ + dncp = cache_fromdvp(vp, NULL, 0); + bzero(&nlc, sizeof(nlc)); newvp = NULLVP; /* @@ -2432,8 +2431,8 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop) uiop->uio_resid -= DIRHDSIZ; uiop->uio_iov->iov_base += DIRHDSIZ; uiop->uio_iov->iov_len -= DIRHDSIZ; - cnp->cn_nameptr = uiop->uio_iov->iov_base; - cnp->cn_namelen = len; + nlc.nlc_nameptr = uiop->uio_iov->iov_base; + nlc.nlc_namelen = len; nfsm_mtouio(uiop, len); cp = uiop->uio_iov->iov_base; tlen -= len; @@ -2488,8 +2487,20 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop) md = mdsav2; dp->d_type = IFTODT(VTTOIF(np->n_vattr.va_type)); - ndp->ni_vp = newvp; - cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); + if (dncp) { + printf("NFS/READDIRPLUS, ENTER %*.*s\n", + nlc.nlc_namelen, nlc.nlc_namelen, + nlc.nlc_nameptr); + ncp = cache_nlookup(dncp, &nlc); + cache_setunresolved(ncp); + cache_setvp(ncp, newvp); + cache_put(ncp); + } else { + printf("NFS/READDIRPLUS, UNABLE TO ENTER" + " %*.*s\n", + nlc.nlc_namelen, nlc.nlc_namelen, + nlc.nlc_nameptr); + } } } else { /* Just skip over the file handle */ @@ -2549,6 +2560,8 @@ nfsmout: vput(newvp); newvp = NULLVP; } + if (dncp) + cache_drop(dncp); return (error); } @@ -2572,7 +2585,7 @@ nfs_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) * completely destroys performance. We can't do it anyway with the * new VFS API since we would be breaking the namecache topology. */ - cache_purge(vp); + cache_purge(vp); /* XXX */ np = VTONFS(vp); #ifndef DIAGNOSTIC if (vp->v_type == VDIR) diff --git a/sys/vfs/ntfs/ntfs_vfsops.c b/sys/vfs/ntfs/ntfs_vfsops.c index 85efbdfb88..d2535e6f27 100644 --- a/sys/vfs/ntfs/ntfs_vfsops.c +++ b/sys/vfs/ntfs/ntfs_vfsops.c @@ -26,7 +26,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/ntfs/ntfs_vfsops.c,v 1.20.2.5 2001/12/25 01:44:45 dillon Exp $ - * $DragonFly: src/sys/vfs/ntfs/ntfs_vfsops.c,v 1.23 2004/10/12 19:21:02 dillon Exp $ + * $DragonFly: src/sys/vfs/ntfs/ntfs_vfsops.c,v 1.24 2004/11/12 00:09:38 dillon Exp $ */ @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include @@ -225,12 +225,13 @@ ntfs_mount(struct mount *mp, struct thread *td) { size_t size; - int err = 0; + int error; struct vnode *devvp; struct ntfs_args args; - struct nameidata nd; + struct nlookupdata nd; struct vnode *rootvp; + error = 0; #ifdef __DragonFly__ /* * Use NULL path to flag a root mount @@ -254,7 +255,7 @@ ntfs_mount(struct mount *mp, /* * Attempt mount */ - if( ( err = ntfs_mountfs(rootvp, mp, &args, td)) != 0) { + if( ( error = ntfs_mountfs(rootvp, mp, &args, td)) != 0) { /* fs specific cleanup (if any)*/ goto error_1; } @@ -271,8 +272,8 @@ ntfs_mount(struct mount *mp, */ /* copy in user arguments*/ - err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args)); - if (err) + error = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args)); + if (error) goto error_1; /* can't get arguments*/ /* @@ -287,12 +288,12 @@ ntfs_mount(struct mount *mp, * will return the vfs_export() error code. */ struct ntfsmount *ntm = VFSTONTFS(mp); - err = vfs_export(mp, &ntm->ntm_export, &args.export); + error = vfs_export(mp, &ntm->ntm_export, &args.export); goto success; } printf("ntfs_mount(): MNT_UPDATE not supported\n"); - err = EINVAL; + error = EINVAL; goto error_1; } @@ -300,25 +301,26 @@ ntfs_mount(struct mount *mp, * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); - err = namei(&nd); - if (err) { - /* can't get devvp!*/ + devvp = NULL; + error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp); + nlookup_done(&nd); + if (error) goto error_1; - } - NDFREE(&nd, NDF_ONLY_PNBUF); - devvp = nd.ni_vp; #if defined(__DragonFly__) - if (!vn_isdisk(devvp, &err)) + if (!vn_isdisk(devvp, &error)) goto error_2; #else if (devvp->v_type != VBLK) { - err = ENOTBLK; + error = ENOTBLK; goto error_2; } if (umajor(devvp->v_udev) >= nblkdev) { - err = ENXIO; + error = ENXIO; goto error_2; } #endif @@ -331,13 +333,13 @@ ntfs_mount(struct mount *mp, */ if (devvp != ntmp->um_devvp) - err = EINVAL; /* needs translation */ + error = EINVAL; /* needs translation */ else vrele(devvp); /* * Update device name only on success */ - if( !err) { + if( !error) { /* Save "mounted from" info for mount point (NULL pad)*/ copyinstr( args.fspec, mp->mnt_stat.f_mntfromname, @@ -373,9 +375,9 @@ ntfs_mount(struct mount *mp, &size); /* real size*/ bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - err = ntfs_mountfs(devvp, mp, &args, td); + error = ntfs_mountfs(devvp, mp, &args, td); } - if (err) { + if (error) { goto error_2; } @@ -401,7 +403,7 @@ error_2: /* error with devvp held*/ error_1: /* no state to back out*/ success: - return(err); + return(error); } /* @@ -449,7 +451,7 @@ ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, ronly = (mp->mnt_flag & MNT_RDONLY) != 0; VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td); + error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL, td); VOP__UNLOCK(devvp, 0, td); if (error) return (error); diff --git a/sys/vfs/ntfs/ntfs_vnops.c b/sys/vfs/ntfs/ntfs_vnops.c index 5a37ab2053..d0735421bf 100644 --- a/sys/vfs/ntfs/ntfs_vnops.c +++ b/sys/vfs/ntfs/ntfs_vnops.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/ntfs/ntfs_vnops.c,v 1.9.2.4 2002/08/06 19:35:18 semenu Exp $ - * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.18 2004/10/12 19:21:02 dillon Exp $ + * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.19 2004/11/12 00:09:38 dillon Exp $ * */ @@ -717,29 +717,7 @@ ntfs_lookup(struct vop_lookup_args *ap) (int)cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_namelen, dip->i_number, lockparent, wantparent)); - error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_td); - if(error) - return (error); - - if ((cnp->cn_flags & CNP_ISLASTCN) && - (dvp->v_mount->mnt_flag & MNT_RDONLY) && - (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) - return (EROFS); - -#ifdef __NetBSD__ - /* - * We now have a segment name to search for, and a directory - * to search. - * - * Before tediously performing a linear scan of the directory, - * check the name cache to see if the directory/name pair - * we are looking for is known already. - */ - if ((error = cache_lookup(ap->a_dvp, ap->a_vpp, cnp)) >= 0) - return (error); -#endif - - if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { + if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { dprintf(("ntfs_lookup: faking . directory in %d\n", dip->i_number)); @@ -770,7 +748,7 @@ ntfs_lookup(struct vop_lookup_args *ap) return (error); } - if (lockparent && (cnp->cn_flags & CNP_ISLASTCN)) { + if (lockparent) { error = VN_LOCK(dvp, LK_EXCLUSIVE, cnp->cn_td); if (error) { vput( *(ap->a_vpp) ); @@ -788,13 +766,9 @@ ntfs_lookup(struct vop_lookup_args *ap) dprintf(("ntfs_lookup: found ino: %d\n", VTONT(*ap->a_vpp)->i_number)); - if(!lockparent || !(cnp->cn_flags & CNP_ISLASTCN)) + if (!lockparent) VOP__UNLOCK(dvp, 0, cnp->cn_td); } - - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(dvp, *ap->a_vpp, cnp); - return (error); } @@ -872,8 +846,7 @@ struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = { { &vop_islocked_desc, (void *)vop_stdislocked }, { &vop_unlock_desc, (void *)vop_stdunlock }, { &vop_lock_desc, (void *)vop_stdlock }, - { &vop_cachedlookup_desc,(void *)ntfs_lookup }, - { &vop_lookup_desc, (void *)vfs_cache_lookup }, + { &vop_lookup_desc, (void *)ntfs_lookup }, { &vop_access_desc, (void *)ntfs_access }, { &vop_close_desc, (void *)ntfs_close }, diff --git a/sys/vfs/nullfs/null_vfsops.c b/sys/vfs/nullfs/null_vfsops.c index 96b6a8ec2a..0418522403 100644 --- a/sys/vfs/nullfs/null_vfsops.c +++ b/sys/vfs/nullfs/null_vfsops.c @@ -37,7 +37,7 @@ * * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 * $FreeBSD: src/sys/miscfs/nullfs/null_vfsops.c,v 1.35.2.3 2001/07/26 20:37:11 iedowse Exp $ - * $DragonFly: src/sys/vfs/nullfs/null_vfsops.c,v 1.13 2004/10/12 19:21:04 dillon Exp $ + * $DragonFly: src/sys/vfs/nullfs/null_vfsops.c,v 1.14 2004/11/12 00:09:40 dillon Exp $ */ /* @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include "null.h" extern struct vnodeopv_entry_desc null_vnodeop_entries[]; @@ -91,7 +91,7 @@ nullfs_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) struct null_mount *xmp; u_int size; int isvnunlocked = 0; - struct nameidata nd; + struct nlookupdata nd; NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); @@ -121,28 +121,27 @@ nullfs_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) /* * Find lower node */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_WANTPARENT | CNP_LOCKLEAF, - UIO_USERSPACE, args.target, td); - error = namei(&nd); + lowerrootvp = NULL; + error = nlookup_init(&nd, args.target, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) { + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, + &lowerrootvp); + } + nlookup_done(&nd); + /* * Re-lock vnode. */ if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY, td); - if (error) return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - + /* * Sanity check on lower vnode - */ - lowerrootvp = nd.ni_vp; - - vrele(nd.ni_dvp); - nd.ni_dvp = NULLVP; - - /* + * * Check multi null mount to avoid `lock against myself' panic. */ if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { diff --git a/sys/vfs/nullfs/null_vnops.c b/sys/vfs/nullfs/null_vnops.c index 9d5f100e59..d53b9f5a3c 100644 --- a/sys/vfs/nullfs/null_vnops.c +++ b/sys/vfs/nullfs/null_vnops.c @@ -38,7 +38,7 @@ * Ancestors: * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92 * $FreeBSD: src/sys/miscfs/nullfs/null_vnops.c,v 1.38.2.6 2002/07/31 00:32:28 semenu Exp $ - * $DragonFly: src/sys/vfs/nullfs/null_vnops.c,v 1.19 2004/10/27 08:52:06 dillon Exp $ + * $DragonFly: src/sys/vfs/nullfs/null_vnops.c,v 1.20 2004/11/12 00:09:40 dillon Exp $ * ...and... * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project * @@ -191,7 +191,13 @@ static int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW, &null_bug_bypass, 0, ""); -static int null_resolve(struct vop_resolve_args *ap); +static int null_nresolve(struct vop_nresolve_args *ap); +static int null_ncreate(struct vop_ncreate_args *ap); +static int null_nmkdir(struct vop_nmkdir_args *ap); +static int null_nremove(struct vop_nremove_args *ap); +static int null_nrmdir(struct vop_nrmdir_args *ap); +static int null_nrename(struct vop_nrename_args *ap); + static int null_revoke(struct vop_revoke_args *ap); static int null_access(struct vop_access_args *ap); static int null_createvobject(struct vop_createvobject_args *ap); @@ -386,8 +392,7 @@ null_lookup(struct vop_lookup_args *ap) struct vnode *vp, *ldvp, *lvp; int error; - if ((flags & CNP_ISLASTCN) && - (dvp->v_mount->mnt_flag & MNT_RDONLY) && + if ((dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) { return (EROFS); @@ -412,7 +417,7 @@ null_lookup(struct vop_lookup_args *ap) */ vp = lvp = NULL; error = VOP_LOOKUP(ldvp, &lvp, cnp); - if (error == EJUSTRETURN && (flags & CNP_ISLASTCN) && + if (error == EJUSTRETURN && (dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == NAMEI_CREATE || cnp->cn_nameiop == NAMEI_RENAME)) { @@ -513,9 +518,42 @@ null_getattr(struct vop_getattr_args *ap) * Resolve a locked ncp at the nullfs layer. */ static int -null_resolve(struct vop_resolve_args *ap) +null_nresolve(struct vop_nresolve_args *ap) { - return(vop_noresolve(ap)); + return(vop_compat_nresolve(ap)); +} + +/* + * Create a file + */ +static int +null_ncreate(struct vop_ncreate_args *ap) +{ + return(vop_compat_ncreate(ap)); +} + +static int +null_nmkdir(struct vop_nmkdir_args *ap) +{ + return(vop_compat_nmkdir(ap)); +} + +static int +null_nremove(struct vop_nremove_args *ap) +{ + return(vop_compat_nremove(ap)); +} + +static int +null_nrmdir(struct vop_nrmdir_args *ap) +{ + return(vop_compat_nrmdir(ap)); +} + +static int +null_nrename(struct vop_nrename_args *ap) +{ + return(vop_compat_nrename(ap)); } /* @@ -898,7 +936,6 @@ null_getvobject(struct vop_getvobject_args *ap) */ struct vnodeopv_entry_desc null_vnodeop_entries[] = { { &vop_default_desc, (void *) null_bypass }, - { &vop_resolve_desc, (void *) null_resolve }, { &vop_access_desc, (void *) null_access }, { &vop_createvobject_desc, (void *) null_createvobject }, { &vop_destroyvobject_desc, (void *) null_destroyvobject }, @@ -915,6 +952,13 @@ struct vnodeopv_entry_desc null_vnodeop_entries[] = { { &vop_setattr_desc, (void *) null_setattr }, { &vop_unlock_desc, (void *) null_unlock }, { &vop_revoke_desc, (void *) null_revoke }, + + { &vop_nresolve_desc, (void *) null_nresolve }, + { &vop_ncreate_desc, (void *) null_ncreate }, + { &vop_nmkdir_desc, (void *) null_nmkdir }, + { &vop_nremove_desc, (void *) null_nremove }, + { &vop_nrmdir_desc, (void *) null_nrmdir }, + { &vop_nrename_desc, (void *) null_nrename }, { NULL, NULL } }; diff --git a/sys/vfs/nwfs/nwfs_io.c b/sys/vfs/nwfs/nwfs_io.c index 4cced63ac0..ef8fe7fb01 100644 --- a/sys/vfs/nwfs/nwfs_io.c +++ b/sys/vfs/nwfs/nwfs_io.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/nwfs/nwfs_io.c,v 1.6.2.1 2000/10/25 02:11:10 bp Exp $ - * $DragonFly: src/sys/vfs/nwfs/nwfs_io.c,v 1.12 2004/10/12 19:21:05 dillon Exp $ + * $DragonFly: src/sys/vfs/nwfs/nwfs_io.c,v 1.13 2004/11/12 00:09:42 dillon Exp $ * */ #include @@ -81,7 +81,6 @@ nwfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) struct nwnode *np = VTONW(vp); struct nw_entry_info fattr; struct vnode *newvp; - struct componentname cn; ncpfid fid; np = VTONW(vp); @@ -135,9 +134,6 @@ nwfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) error = nwfs_nget(vp->v_mount, fid, &fattr, vp, &newvp); if (!error) { VTONW(newvp)->n_ctime = VTONW(newvp)->n_vattr.va_ctime.tv_sec; - cn.cn_nameptr = dp.d_name; - cn.cn_namelen = dp.d_namlen; - cache_enter(vp, newvp, &cn); vput(newvp); } else error = 0; @@ -504,7 +500,7 @@ nwfs_putpages(struct vop_putpages_args *ap) #ifndef NWFS_RWCACHE KKASSERT(td->td_proc); cred = td->td_proc->p_ucred; /* XXX */ - VOP_OPEN(vp, FWRITE, cred, td); + VOP_OPEN(vp, FWRITE, cred, NULL, td); error = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count, ap->a_sync, ap->a_rtvals); VOP_CLOSE(vp, FWRITE, cred, td); diff --git a/sys/vfs/nwfs/nwfs_vnops.c b/sys/vfs/nwfs/nwfs_vnops.c index 995bee2be2..b26deeac43 100644 --- a/sys/vfs/nwfs/nwfs_vnops.c +++ b/sys/vfs/nwfs/nwfs_vnops.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/nwfs/nwfs_vnops.c,v 1.6.2.3 2001/03/14 11:26:59 bp Exp $ - * $DragonFly: src/sys/vfs/nwfs/nwfs_vnops.c,v 1.19 2004/11/03 22:07:21 dillon Exp $ + * $DragonFly: src/sys/vfs/nwfs/nwfs_vnops.c,v 1.20 2004/11/12 00:09:42 dillon Exp $ */ #include #include @@ -384,9 +384,7 @@ nwfs_write(struct vop_write_args *ap) /* * nwfs_create call * Create a regular file. On entry the directory to contain the file being - * created is locked. We must release before we return. We must also free - * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or - * only if the SAVESTART bit in cn_flags is clear on success. + * created is locked. We must release before we return. * * nwfs_create(struct vnode *a_dvp, struct vnode **a_vpp, * struct componentname *a_cnpl, struct vattr *a_vap) @@ -431,8 +429,6 @@ nwfs_create(struct vop_create_args *ap) np->opened = 0; *vpp = vp; } - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(dvp, vp, cnp); } return (error); } @@ -459,7 +455,6 @@ nwfs_remove(struct vop_remove_args *ap) } else if (!ncp_conn_valid(NWFSTOCONN(nmp))) { error = EIO; } else { - cache_purge(vp); error = ncp_DeleteNSEntry(nmp, VTONW(dvp)->n_fid.f_id, cnp->cn_namelen,cnp->cn_nameptr,cnp->cn_td,cnp->cn_cred); if (error == 0) @@ -523,11 +518,6 @@ nwfs_rename(struct vop_rename_args *ap) if (error == 0x8992) error = EEXIST; - if (fvp->v_type == VDIR) { - if (tvp != NULL && tvp->v_type == VDIR) - cache_purge(tdvp); - cache_purge(fdvp); - } out: if (tdvp == tvp) vrele(tdvp); @@ -661,7 +651,6 @@ nwfs_rmdir(struct vop_rmdir_args *ap) error = ENOTEMPTY; dnp->n_flag |= NMODIFIED; nwfs_attr_cacheremove(dvp); - cache_purge(vp); return (error); } @@ -842,7 +831,7 @@ nwfs_lookup(struct vop_lookup_args *ap) struct nwnode *dnp, *npp; struct nw_entry_info fattr, *fap; ncpfid fid; - int nameiop=cnp->cn_nameiop, islastcn; + int nameiop=cnp->cn_nameiop; int lockparent, wantparent, error = 0, notfound; struct thread *td = cnp->cn_td; char _name[cnp->cn_namelen+1]; @@ -859,8 +848,7 @@ nwfs_lookup(struct vop_lookup_args *ap) NCPVNDEBUG("%d '%s' in '%s' id=d\n", nameiop, _name, VTONW(dvp)->n_name/*, VTONW(dvp)->n_name*/); - islastcn = flags & CNP_ISLASTCN; - if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != NAMEI_LOOKUP)) + if ((mp->mnt_flag & MNT_RDONLY) && nameiop != NAMEI_LOOKUP) return (EROFS); if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td))) return (error); @@ -876,53 +864,6 @@ printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & CNP_ISD if (error) return ENOENT; - error = cache_lookup(dvp, vpp, cnp); - NCPVNDEBUG("cache_lookup returned %d\n",error); - if (error > 0) - return error; - if (error) { /* name was found */ - struct vattr vattr; - int vpid; - - vp = *vpp; - vpid = vp->v_id; - if (dvp == vp) { /* lookup on current */ - /* vp already ref'd */ - error = 0; - NCPVNDEBUG("cached '.'"); - } else if (flags & CNP_ISDOTDOT) { - VOP_UNLOCK(dvp, 0, td); /* unlock parent */ - error = vget(vp, LK_EXCLUSIVE, td); - vrele(vp); - if (!error && lockparent && islastcn) - error = vn_lock(dvp, LK_EXCLUSIVE, td); - } else { - error = vget(vp, LK_EXCLUSIVE, td); - vrele(vp); - if (!lockparent || error || !islastcn) - VOP_UNLOCK(dvp, 0, td); - } - if (!error) { - if (vpid == vp->v_id) { - if (!VOP_GETATTR(vp, &vattr, td) - && vattr.va_ctime.tv_sec == VTONW(vp)->n_ctime) { - if (nameiop != NAMEI_LOOKUP && islastcn) - cnp->cn_flags |= CNP_SAVENAME; - NCPVNDEBUG("use cached vnode"); - return (0); - } - cache_purge(vp); - } - vput(vp); - if (lockparent && dvp != vp && islastcn) - VOP_UNLOCK(dvp, 0, td); - } - error = vn_lock(dvp, LK_EXCLUSIVE, td); - *vpp = NULLVP; - if (error) - return (error); - } - /* not in cache, so ... */ error = 0; *vpp = NULLVP; fap = NULL; @@ -957,8 +898,7 @@ printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & CNP_ISD return (notfound); /* hard error */ if (notfound) { /* entry not found */ /* Handle RENAME or CREATE case... */ - if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && wantparent && islastcn) { - cnp->cn_flags |= CNP_SAVENAME; + if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && wantparent) { if (!lockparent) VOP_UNLOCK(dvp, 0, td); return (EJUSTRETURN); @@ -968,7 +908,7 @@ printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & CNP_ISD NCPVNDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); }*/ /* handle DELETE case ... */ - if (nameiop == NAMEI_DELETE && islastcn) { /* delete last component */ + if (nameiop == NAMEI_DELETE) { /* delete last component */ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_td); if (error) return (error); if (NWCMPF(&dnp->n_fid, &fid)) { /* we found ourselfs */ @@ -979,18 +919,16 @@ printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & CNP_ISD error = nwfs_nget(mp, fid, fap, dvp, &vp); if (error) return (error); *vpp = vp; - cnp->cn_flags |= CNP_SAVENAME; /* I free it later */ if (!lockparent) VOP_UNLOCK(dvp, 0, td); return (0); } - if (nameiop == NAMEI_RENAME && islastcn && wantparent) { + if (nameiop == NAMEI_RENAME && wantparent) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_td); if (error) return (error); if (NWCMPF(&dnp->n_fid, &fid)) return EISDIR; error = nwfs_nget(mp, fid, fap, dvp, &vp); if (error) return (error); *vpp = vp; - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) VOP_UNLOCK(dvp, 0, td); return (0); @@ -1002,8 +940,7 @@ printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & CNP_ISD vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); return (error); } - if (lockparent && islastcn && - (error = vn_lock(dvp, LK_EXCLUSIVE, td))) { + if (lockparent && (error = vn_lock(dvp, LK_EXCLUSIVE, td))) { vput(vp); return (error); } @@ -1016,12 +953,15 @@ printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & CNP_ISD if (error) return (error); *vpp = vp; NCPVNDEBUG("lookup: getnewvp!\n"); - if (!lockparent || !islastcn) + if (!lockparent) VOP_UNLOCK(dvp, 0, td); } - if ((cnp->cn_flags & CNP_MAKEENTRY)/* && !islastcn*/) { +#if 0 + /* XXX MOVE TO NREMOVE */ + if ((cnp->cn_flags & CNP_MAKEENTRY)) { VTONW(*vpp)->n_ctime = VTONW(*vpp)->n_vattr.va_ctime.tv_sec; - cache_enter(dvp, *vpp, cnp); + /* XXX */ } +#endif return (0); } diff --git a/sys/vfs/procfs/procfs_vnops.c b/sys/vfs/procfs/procfs_vnops.c index bed1be08eb..54215d84d3 100644 --- a/sys/vfs/procfs/procfs_vnops.c +++ b/sys/vfs/procfs/procfs_vnops.c @@ -37,7 +37,7 @@ * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 * * $FreeBSD: src/sys/miscfs/procfs/procfs_vnops.c,v 1.76.2.7 2002/01/22 17:22:59 nectar Exp $ - * $DragonFly: src/sys/vfs/procfs/procfs_vnops.c,v 1.21 2004/10/20 09:00:35 dillon Exp $ + * $DragonFly: src/sys/vfs/procfs/procfs_vnops.c,v 1.22 2004/11/12 00:09:47 dillon Exp $ */ /* @@ -757,9 +757,6 @@ out: if ((cnp->cn_flags & CNP_LOCKPARENT) == 0) { cnp->cn_flags |= CNP_PDIRUNLOCK; VOP_UNLOCK(dvp, 0, cnp->cn_td); - } else if ((cnp->cn_flags & CNP_ISLASTCN) == 0) { - cnp->cn_flags |= CNP_PDIRUNLOCK; - VOP_UNLOCK(dvp, 0, cnp->cn_td); } } return (error); diff --git a/sys/vfs/smbfs/smbfs_io.c b/sys/vfs/smbfs/smbfs_io.c index dceb4102b8..7846fcfa0a 100644 --- a/sys/vfs/smbfs/smbfs_io.c +++ b/sys/vfs/smbfs/smbfs_io.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/fs/smbfs/smbfs_io.c,v 1.3.2.3 2003/01/17 08:20:26 tjr Exp $ - * $DragonFly: src/sys/vfs/smbfs/smbfs_io.c,v 1.13 2004/10/12 19:21:08 dillon Exp $ + * $DragonFly: src/sys/vfs/smbfs/smbfs_io.c,v 1.14 2004/11/12 00:09:48 dillon Exp $ * */ #include @@ -81,7 +81,6 @@ static int smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) { struct dirent de; - struct componentname cn; struct smb_cred scred; struct smbfs_fctx *ctx; struct vnode *newvp; @@ -158,12 +157,8 @@ smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) if (smbfs_fastlookup) { error = smbfs_nget(vp->v_mount, vp, ctx->f_name, ctx->f_nmlen, &ctx->f_attr, &newvp); - if (!error) { - cn.cn_nameptr = de.d_name; - cn.cn_namelen = de.d_namlen; - cache_enter(vp, newvp, &cn); + if (!error) vput(newvp); - } } error = uiomove((caddr_t)&de, DE_SIZE, uio); if (error) @@ -534,7 +529,7 @@ smbfs_putpages(struct vop_putpages_args *ap) #ifdef SMBFS_RWGENERIC KKASSERT(td->td_proc); cred = td->td_proc->p_ucred; - VOP_OPEN(vp, FWRITE, cred, td); + VOP_OPEN(vp, FWRITE, cred, NULL, td); error = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count, ap->a_sync, ap->a_rtvals); VOP_CLOSE(vp, FWRITE, cred, td); diff --git a/sys/vfs/smbfs/smbfs_vnops.c b/sys/vfs/smbfs/smbfs_vnops.c index eb991bb54e..6a28a3c6b1 100644 --- a/sys/vfs/smbfs/smbfs_vnops.c +++ b/sys/vfs/smbfs/smbfs_vnops.c @@ -30,7 +30,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/fs/smbfs/smbfs_vnops.c,v 1.2.2.8 2003/04/04 08:57:23 tjr Exp $ - * $DragonFly: src/sys/vfs/smbfs/smbfs_vnops.c,v 1.20 2004/10/12 19:21:08 dillon Exp $ + * $DragonFly: src/sys/vfs/smbfs/smbfs_vnops.c,v 1.21 2004/11/12 00:09:48 dillon Exp $ */ #include #include @@ -379,7 +379,7 @@ smbfs_setattr(struct vop_setattr_args *ap) */ if (np->n_opencount == 0) { if (vcp->vc_flags & SMBV_WIN95) { - error = VOP_OPEN(vp, FWRITE, ap->a_cred, ap->a_td); + error = VOP_OPEN(vp, FWRITE, ap->a_cred, NULL, ap->a_td); if (!error) { /* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); VOP_GETATTR(vp, &vattr, ap->a_td);*/ @@ -455,9 +455,7 @@ smbfs_write(struct vop_write_args *ap) /* * smbfs_create call * Create a regular file. On entry the directory to contain the file being - * created is locked. We must release before we return. We must also free - * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or - * only if the SAVESTART bit in cn_flags is clear on success. + * created is locked. We must release before we return. * * smbfs_create(struct vnode *a_dvp, struct vnode **a_vpp, * struct componentname *a_cnp, struct vattr *a_vap) @@ -497,8 +495,6 @@ smbfs_create(struct vop_create_args *ap) if (error) return error; *vpp = vp; - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(dvp, vp, cnp); return error; } @@ -520,7 +516,6 @@ smbfs_remove(struct vop_remove_args *ap) return EPERM; smb_makescred(&scred, cnp->cn_td, cnp->cn_cred); error = smbfs_smb_delete(np, &scred); - cache_purge(vp); return error; } @@ -587,12 +582,6 @@ smbfs_rename(struct vop_rename_args *ap) tcnp->cn_nameptr, tcnp->cn_namelen, &scred); } - if (fvp->v_type == VDIR) { - if (tvp != NULL && tvp->v_type == VDIR) - cache_purge(tdvp); - cache_purge(fdvp); - } - out_cacherem: smbfs_attr_cacheremove(fdvp); smbfs_attr_cacheremove(tdvp); @@ -709,8 +698,6 @@ smbfs_rmdir(struct vop_rmdir_args *ap) error = smbfs_smb_rmdir(np, &scred); dnp->n_flag |= NMODIFIED; smbfs_attr_cacheremove(dvp); -/* cache_purge(dvp);*/ - cache_purge(vp); return error; } @@ -1038,7 +1025,7 @@ smbfs_lookup(struct vop_lookup_args *ap) int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; int nmlen = cnp->cn_namelen; - int lockparent, wantparent, error, islastcn, isdot; + int lockparent, wantparent, error, isdot; SMBVDEBUG("\n"); cnp->cn_flags &= ~CNP_PDIRUNLOCK; @@ -1060,8 +1047,7 @@ smbfs_lookup(struct vop_lookup_args *ap) *cp = c; } #endif - islastcn = flags & CNP_ISLASTCN; - if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != NAMEI_LOOKUP)) + if ((mp->mnt_flag & MNT_RDONLY) && nameiop != NAMEI_LOOKUP) return EROFS; if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) return error; @@ -1076,64 +1062,6 @@ smbfs_lookup(struct vop_lookup_args *ap) if (error) return ENOENT; - error = cache_lookup(dvp, vpp, cnp); - SMBVDEBUG("cache_lookup returned %d\n", error); - if (error > 0) - return error; - if (error) { /* name was found */ - struct vattr vattr; - int vpid; - - vp = *vpp; - vpid = vp->v_id; - if (dvp == vp) { /* lookup on current */ - /* vp already refd from cache_lookup() */ - error = 0; - SMBVDEBUG("cached '.'\n"); - } else if (flags & CNP_ISDOTDOT) { - VOP_UNLOCK(dvp, 0, td); /* unlock parent */ - cnp->cn_flags |= CNP_PDIRUNLOCK; - error = vget(vp, LK_EXCLUSIVE, td); - vrele(vp); - if (!error && lockparent && islastcn) { - error = vn_lock(dvp, LK_EXCLUSIVE, td); - if (error == 0) - cnp->cn_flags &= ~CNP_PDIRUNLOCK; - } - } else { - error = vget(vp, LK_EXCLUSIVE, td); - vrele(vp); - if (!lockparent || error || !islastcn) { - VOP_UNLOCK(dvp, 0, td); - cnp->cn_flags |= CNP_PDIRUNLOCK; - } - } - if (!error) { - if (vpid == vp->v_id) { - if (!VOP_GETATTR(vp, &vattr, td) - /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { - if (nameiop != NAMEI_LOOKUP && islastcn) - cnp->cn_flags |= CNP_SAVENAME; - SMBVDEBUG("use cached vnode\n"); - return (0); - } - cache_purge(vp); - } - vput(vp); - if (lockparent && dvp != vp && islastcn) - VOP_UNLOCK(dvp, 0, td); - } - error = vn_lock(dvp, LK_EXCLUSIVE, td); - *vpp = NULLVP; - if (error) { - cnp->cn_flags |= CNP_PDIRUNLOCK; - return (error); - } - cnp->cn_flags &= ~CNP_PDIRUNLOCK; - } - /* - * entry is not in the cache or has been expired - */ error = 0; *vpp = NULLVP; smb_makescred(&scred, td, cnp->cn_cred); @@ -1154,11 +1082,10 @@ smbfs_lookup(struct vop_lookup_args *ap) /* * Handle RENAME or CREATE case... */ - if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && wantparent && islastcn) { + if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && wantparent) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) return error; - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; @@ -1172,7 +1099,7 @@ smbfs_lookup(struct vop_lookup_args *ap) /* * handle DELETE case ... */ - if (nameiop == NAMEI_DELETE && islastcn) { /* delete last component */ + if (nameiop == NAMEI_DELETE) { /* delete last component */ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) return error; @@ -1185,14 +1112,13 @@ smbfs_lookup(struct vop_lookup_args *ap) if (error) return error; *vpp = vp; - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; } return 0; } - if (nameiop == NAMEI_RENAME && islastcn && wantparent) { + if (nameiop == NAMEI_RENAME && wantparent) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); if (error) return error; @@ -1202,7 +1128,6 @@ smbfs_lookup(struct vop_lookup_args *ap) if (error) return error; *vpp = vp; - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; @@ -1216,7 +1141,7 @@ smbfs_lookup(struct vop_lookup_args *ap) vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); return error; } - if (lockparent && islastcn) { + if (lockparent) { error = vn_lock(dvp, LK_EXCLUSIVE, td); if (error) { cnp->cn_flags |= CNP_PDIRUNLOCK; @@ -1234,14 +1159,10 @@ smbfs_lookup(struct vop_lookup_args *ap) return error; *vpp = vp; SMBVDEBUG("lookup: getnewvp!\n"); - if (!lockparent || !islastcn) { + if (!lockparent) { VOP_UNLOCK(dvp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; } } - if ((cnp->cn_flags & CNP_MAKEENTRY)/* && !islastcn*/) { -/* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ - cache_enter(dvp, *vpp, cnp); - } return 0; } diff --git a/sys/vfs/specfs/spec_vnops.c b/sys/vfs/specfs/spec_vnops.c index 38cf70727a..f0966a0a28 100644 --- a/sys/vfs/specfs/spec_vnops.c +++ b/sys/vfs/specfs/spec_vnops.c @@ -32,7 +32,7 @@ * * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 * $FreeBSD: src/sys/miscfs/specfs/spec_vnops.c,v 1.131.2.4 2001/02/26 04:23:20 jlemon Exp $ - * $DragonFly: src/sys/vfs/specfs/spec_vnops.c,v 1.21 2004/10/12 19:21:09 dillon Exp $ + * $DragonFly: src/sys/vfs/specfs/spec_vnops.c,v 1.22 2004/11/12 00:09:50 dillon Exp $ */ #include @@ -267,6 +267,16 @@ spec_open(struct vop_open_args *ap) dev_dname(dev), cp); } } + + /* + * If we were handed a file pointer we may be able to install a + * shortcut which issues device read and write operations directly + * from the fileops rather then having to go through spec_read() + * and spec_write(). + */ + if (ap->a_fp) + vn_setspecops(ap->a_fp); + if (dev_ref_debug) printf("spec_open: %s %d\n", dev->si_name, vp->v_opencount); done: diff --git a/sys/vfs/udf/udf_vfsops.c b/sys/vfs/udf/udf_vfsops.c index c1b3a6ccc4..3ba822248e 100644 --- a/sys/vfs/udf/udf_vfsops.c +++ b/sys/vfs/udf/udf_vfsops.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/fs/udf/udf_vfsops.c,v 1.16 2003/11/05 06:56:08 scottl Exp $ - * $DragonFly: src/sys/vfs/udf/udf_vfsops.c,v 1.9 2004/10/12 19:21:10 dillon Exp $ + * $DragonFly: src/sys/vfs/udf/udf_vfsops.c,v 1.10 2004/11/12 00:09:51 dillon Exp $ */ /* udf_vfsops.c */ @@ -84,7 +84,7 @@ #include #include #include -#include +#include #include #include #include @@ -139,7 +139,7 @@ udf_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) struct udf_mnt *imp = 0; size_t size; int error; - struct nameidata nd; + struct nlookupdata nd; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EROFS); @@ -161,11 +161,15 @@ udf_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) } /* Check that the mount device exists */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); - if ((error = namei(&nd))) - return(error); - NDFREE(&nd, NDF_ONLY_PNBUF); - devvp = nd.ni_vp; + devvp = NULL; + error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp); + nlookup_done(&nd); + if (error) + return (error); if (vn_isdisk(devvp, &error) == 0) { vrele(devvp); @@ -255,7 +259,7 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) return(error); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(devvp, FREAD, FSCRED, td); + error = VOP_OPEN(devvp, FREAD, FSCRED, NULL, td); VOP_UNLOCK(devvp, 0, td); if (error) return(error); diff --git a/sys/vfs/udf/udf_vnops.c b/sys/vfs/udf/udf_vnops.c index c1338f258d..198e23487e 100644 --- a/sys/vfs/udf/udf_vnops.c +++ b/sys/vfs/udf/udf_vnops.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/fs/udf/udf_vnops.c,v 1.33 2003/12/07 05:04:49 scottl Exp $ - * $DragonFly: src/sys/vfs/udf/udf_vnops.c,v 1.9 2004/10/12 19:21:10 dillon Exp $ + * $DragonFly: src/sys/vfs/udf/udf_vnops.c,v 1.10 2004/11/12 00:09:51 dillon Exp $ */ /* udf_vnops.c */ @@ -59,7 +59,7 @@ static int udf_readdir(struct vop_readdir_args *); static int udf_readlink(struct vop_readlink_args *ap); static int udf_strategy(struct vop_strategy_args *); static int udf_bmap(struct vop_bmap_args *); -static int udf_lookup(struct vop_cachedlookup_args *); +static int udf_lookup(struct vop_lookup_args *); static int udf_reclaim(struct vop_reclaim_args *); static int udf_readatoffset(struct udf_node *, int *, int, struct buf **, uint8_t **); static int udf_bmap_internal(struct udf_node *, uint32_t, daddr_t *, uint32_t *); @@ -68,10 +68,9 @@ struct vnodeopv_entry_desc udf_vnodeop_entries[] = { { &vop_default_desc, vop_defaultop }, { &vop_access_desc, (void *) udf_access }, { &vop_bmap_desc, (void *) udf_bmap }, - { &vop_cachedlookup_desc, (void *) udf_lookup }, + { &vop_lookup_desc, (void *) udf_lookup }, { &vop_getattr_desc, (void *) udf_getattr }, { &vop_ioctl_desc, (void *) udf_ioctl }, - { &vop_lookup_desc, (void *) vfs_cache_lookup }, { &vop_pathconf_desc, (void *) udf_pathconf }, { &vop_read_desc, (void *) udf_read }, { &vop_readdir_desc, (void *) udf_readdir }, @@ -897,7 +896,7 @@ udf_bmap(struct vop_bmap_args *a) * The all powerful VOP_LOOKUP(). */ static int -udf_lookup(struct vop_cachedlookup_args *a) +udf_lookup(struct vop_lookup_args *a) { struct vnode *dvp; struct vnode *tdp = NULL; @@ -988,20 +987,16 @@ lookloop: * Remember where this entry was if it's the final * component. */ - if ((flags & CNP_ISLASTCN) && nameiop == NAMEI_LOOKUP) + if (nameiop == NAMEI_LOOKUP) node->diroff = ds->offset + ds->off; if (numdirpasses == 2) gd->gd_nchstats->ncs_pass2++; - if (!(flags & CNP_LOCKPARENT) || !(flags & CNP_ISLASTCN)) { + if ((flags & CNP_LOCKPARENT) == 0) { a->a_cnp->cn_flags |= CNP_PDIRUNLOCK; VOP_UNLOCK(dvp, 0, td); } *vpp = tdp; - - /* Put this entry in the cache */ - if (flags & CNP_MAKEENTRY) - cache_enter(dvp, *vpp, a->a_cnp); } } else { /* Name wasn't found on this pass. Do another pass? */ @@ -1011,13 +1006,7 @@ lookloop: udf_closedir(ds); goto lookloop; } - - /* Enter name into cache as non-existant */ - if (flags & CNP_MAKEENTRY) - cache_enter(dvp, *vpp, a->a_cnp); - - if ((flags & CNP_ISLASTCN) && - (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME)) { + if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) { error = EROFS; } else { error = ENOENT; diff --git a/sys/vfs/ufs/ffs_vfsops.c b/sys/vfs/ufs/ffs_vfsops.c index 84f519919c..48d688826c 100644 --- a/sys/vfs/ufs/ffs_vfsops.c +++ b/sys/vfs/ufs/ffs_vfsops.c @@ -32,7 +32,7 @@ * * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 * $FreeBSD: src/sys/ufs/ffs/ffs_vfsops.c,v 1.117.2.10 2002/06/23 22:34:52 iedowse Exp $ - * $DragonFly: src/sys/vfs/ufs/ffs_vfsops.c,v 1.27 2004/11/09 04:25:59 dillon Exp $ + * $DragonFly: src/sys/vfs/ufs/ffs_vfsops.c,v 1.28 2004/11/12 00:09:52 dillon Exp $ */ #include "opt_quota.h" @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include @@ -104,16 +104,12 @@ extern struct vnodeopv_entry_desc ffs_fifoop_entries[]; * mp mount point structure * path NULL (flag for root mount!!!) * data - * ndp * p process (user credentials check [statfs]) * * mount * mp mount point structure * path path to mount point * data pointer to argument struct in user space - * ndp mount point namei() return (used for - * credentials on reload), reused to look - * up block device. * p process (user credentials check) * * RETURNS: 0 Success @@ -129,7 +125,7 @@ extern struct vnodeopv_entry_desc ffs_fifoop_entries[]; * NOTES: * A NULL path can be used for a flag since the mount * system call will fail with EFAULT in copyinstr in - * namei() if it is a genuine NULL from the user. + * nlookup() if it is a genuine NULL from the user. */ static int ffs_mount(struct mount *mp, /* mount struct pointer */ @@ -138,37 +134,38 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ struct thread *td) /* process requesting mount */ { size_t size; - int err = 0; + int error; struct vnode *devvp; struct ufs_args args; struct ufsmount *ump = 0; struct fs *fs; - int error, flags, ronly = 0; + int flags, ronly = 0; mode_t accessmode; struct ucred *cred; - struct nameidata nd; + struct nlookupdata nd; struct vnode *rootvp; KKASSERT(td->td_proc); cred = td->td_proc->p_ucred; + error = 0; /* * Use NULL path to flag a root mount */ - if( path == NULL) { + if (path == NULL) { /* *** * Mounting root filesystem *** */ - if ((err = bdevvp(rootdev, &rootvp))) { + if ((error = bdevvp(rootdev, &rootvp))) { printf("ffs_mountroot: can't find rootvp\n"); - return (err); + return (error); } - if( ( err = ffs_mountfs(rootvp, mp, td, M_FFSNODE)) != 0) { + if( ( error = ffs_mountfs(rootvp, mp, td, M_FFSNODE)) != 0) { /* fs specific cleanup (if any)*/ goto error_1; } @@ -184,8 +181,8 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ */ /* copy in user arguments*/ - err = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); - if (err) + error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); + if (error) goto error_1; /* can't get arguments*/ /* @@ -196,7 +193,7 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ ump = VFSTOUFS(mp); fs = ump->um_fs; devvp = ump->um_devvp; - err = 0; + error = 0; ronly = fs->fs_ronly; /* MNT_RELOAD might change this */ if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { /* @@ -211,15 +208,15 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; if (mp->mnt_flag & MNT_SOFTDEP) { - err = softdep_flushfiles(mp, flags, td); + error = softdep_flushfiles(mp, flags, td); } else { - err = ffs_flushfiles(mp, flags, td); + error = ffs_flushfiles(mp, flags, td); } ronly = 1; } - if (!err && (mp->mnt_flag & MNT_RELOAD)) - err = ffs_reload(mp, NULL, td); - if (err) { + if (!error && (mp->mnt_flag & MNT_RELOAD)) + error = ffs_reload(mp, NULL, td); + if (error) { goto error_1; } if (ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { @@ -248,15 +245,15 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ printf( "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", fs->fs_fsmnt); - err = EPERM; + error = EPERM; goto error_1; } } /* check to see if we need to start softdep */ if (fs->fs_flags & FS_DOSOFTDEP) { - err = softdep_mount(devvp, mp, fs); - if (err) + error = softdep_mount(devvp, mp, fs); + if (error) goto error_1; } @@ -278,7 +275,7 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ * Process export requests. Jumping to "success" * will return the vfs_export() error code. */ - err = vfs_export(mp, &ump->um_export, &args.export); + error = vfs_export(mp, &ump->um_export, &args.export); goto success; } } @@ -287,17 +284,17 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); - err = namei(&nd); - if (err) { - /* can't get devvp!*/ + devvp = NULL; + error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp); + nlookup_done(&nd); + if (error) goto error_1; - } - NDFREE(&nd, NDF_ONLY_PNBUF); - devvp = nd.ni_vp; - - if (!vn_isdisk(devvp, &err)) + if (!vn_isdisk(devvp, &error)) goto error_2; /* @@ -332,7 +329,7 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ printf("cannot update mount, udev does" " not match %08x vs %08x\n", devvp->v_udev, ump->um_devvp->v_udev); - err = EINVAL; /* needs translation */ + error = EINVAL; /* needs translation */ } } else { vrele(devvp); @@ -340,7 +337,7 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ /* * Update device name only on success */ - if( !err) { + if (!error) { /* Save "mounted from" info for mount point (NULL pad)*/ copyinstr( args.fspec, mp->mnt_stat.f_mntfromname, @@ -375,9 +372,9 @@ ffs_mount(struct mount *mp, /* mount struct pointer */ &size); /* real size*/ bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); - err = ffs_mountfs(devvp, mp, td, M_FFSNODE); + error = ffs_mountfs(devvp, mp, td, M_FFSNODE); } - if (err) { + if (error) { goto error_2; } @@ -401,7 +398,7 @@ error_2: /* error with devvp held*/ error_1: /* no state to back out*/ success: - if (!err && path && (mp->mnt_flag & MNT_UPDATE)) { + if (!error && path && (mp->mnt_flag & MNT_UPDATE)) { /* Update clean flag after changing read-onlyness. */ fs = ump->um_fs; if (ronly != fs->fs_ronly) { @@ -411,7 +408,7 @@ success: ffs_sbupdate(ump, MNT_WAIT); } } - return (err); + return (error); } /* @@ -625,11 +622,10 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td, ronly = (mp->mnt_flag & MNT_RDONLY) != 0; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td); + error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL, td); VOP_UNLOCK(devvp, 0, td); if (error) return (error); - dev = devvp->v_rdev; if (dev->si_iosize_max != 0) mp->mnt_iosize_max = dev->si_iosize_max; @@ -641,6 +637,8 @@ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td, * block device. This excludes the original MFS implementation. * Note that it is optional that the backing device be VMIOed. This * increases the opportunity for metadata caching. + * + * This call must be made after the VOP_OPEN. */ if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) { vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); diff --git a/sys/vfs/ufs/ufs_extern.h b/sys/vfs/ufs/ufs_extern.h index 5a95436b1d..e9398d1c7d 100644 --- a/sys/vfs/ufs/ufs_extern.h +++ b/sys/vfs/ufs/ufs_extern.h @@ -32,7 +32,7 @@ * * @(#)ufs_extern.h 8.10 (Berkeley) 5/14/95 * $FreeBSD: src/sys/ufs/ufs/ufs_extern.h,v 1.27.2.1 2000/12/28 11:01:46 ps Exp $ - * $DragonFly: src/sys/vfs/ufs/ufs_extern.h,v 1.9 2004/08/28 19:02:30 dillon Exp $ + * $DragonFly: src/sys/vfs/ufs/ufs_extern.h,v 1.10 2004/11/12 00:09:52 dillon Exp $ */ #ifndef _UFS_UFS_EXTERN_H_ @@ -50,7 +50,7 @@ struct ufid; struct vfsconf; struct vnode; struct vop_bmap_args; -struct vop_cachedlookup_args; +struct vop_lookup_args; struct vop_generic_args; struct vop_inactive_args; struct vop_reclaim_args; @@ -86,7 +86,7 @@ void ufs_ihashrem(struct inode *); int ufs_inactive(struct vop_inactive_args *); int ufs_init(struct vfsconf *); void ufs_itimes(struct vnode *vp); -int ufs_lookup(struct vop_cachedlookup_args *); +int ufs_lookup(struct vop_lookup_args *); int ufs_reclaim(struct vop_reclaim_args *); int ufs_root(struct mount *, struct vnode **); int ufs_start(struct mount *, int, struct thread *); diff --git a/sys/vfs/ufs/ufs_lookup.c b/sys/vfs/ufs/ufs_lookup.c index 07913788c3..d552f6d9b9 100644 --- a/sys/vfs/ufs/ufs_lookup.c +++ b/sys/vfs/ufs/ufs_lookup.c @@ -37,7 +37,7 @@ * * @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95 * $FreeBSD: src/sys/ufs/ufs/ufs_lookup.c,v 1.33.2.7 2001/09/22 19:22:13 iedowse Exp $ - * $DragonFly: src/sys/vfs/ufs/ufs_lookup.c,v 1.15 2004/10/12 19:21:12 dillon Exp $ + * $DragonFly: src/sys/vfs/ufs/ufs_lookup.c,v 1.16 2004/11/12 00:09:52 dillon Exp $ */ #include "opt_ufs.h" @@ -93,21 +93,6 @@ SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); * be "."., but the caller must check to ensure it does an vrele and vput * instead of two vputs. * - * This routine is actually used as VOP_CACHEDLOOKUP method, and the - * filesystem employs the generic vfs_cache_lookup() as VOP_LOOKUP - * method. - * - * vfs_cache_lookup() performs the following for us: - * check that it is a directory - * check accessibility of directory - * check for modification attempts on read-only mounts - * if name found in cache - * if at end of path and deleting or creating - * drop it - * else - * return name. - * return VOP_CACHEDLOOKUP() - * * Overall outline of ufs_lookup: * * search for name in directory, to found or notfound @@ -125,7 +110,7 @@ SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); * struct componentname *a_cnp) */ int -ufs_lookup(struct vop_cachedlookup_args *ap) +ufs_lookup(struct vop_lookup_args *ap) { struct vnode *vdp; /* vnode for directory being searched */ struct inode *dp; /* inode for directory being searched */ @@ -179,8 +164,7 @@ ufs_lookup(struct vop_cachedlookup_args *ap) */ slotstatus = FOUND; slotfreespace = slotsize = slotneeded = 0; - if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && - (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) { slotstatus = NONE; slotneeded = DIRECTSIZ(cnp->cn_namelen); } @@ -392,7 +376,7 @@ notfound: (nameiop == NAMEI_DELETE && (ap->a_cnp->cn_flags & CNP_DOWHITEOUT) && (ap->a_cnp->cn_flags & CNP_ISWHITEOUT))) && - (flags & CNP_ISLASTCN) && dp->i_effnlink != 0) { + dp->i_effnlink != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. @@ -440,18 +424,12 @@ notfound: * NB - if the directory is unlocked, then this * information cannot be used. */ - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) { VOP_UNLOCK(vdp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; } return (EJUSTRETURN); } - /* - * Insert name into cache (as non-existent) if appropriate. - */ - if ((cnp->cn_flags & CNP_MAKEENTRY) && nameiop != NAMEI_CREATE) - cache_enter(vdp, *vpp, cnp); return (ENOENT); found: @@ -473,7 +451,7 @@ found: * If the final component of path name, save information * in the cache as to where the entry was found. */ - if ((flags & CNP_ISLASTCN) && nameiop == NAMEI_LOOKUP) + if (nameiop == NAMEI_LOOKUP) dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1); /* @@ -483,7 +461,7 @@ found: * the directory (in ndp->ni_dvp), otherwise we go * on and lock the inode, being careful with ".". */ - if (nameiop == NAMEI_DELETE && (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_DELETE) { /* * Write access to directory required to delete files. */ @@ -541,7 +519,7 @@ found: * Must get inode of directory entry to verify it's a * regular file, or empty directory. */ - if (nameiop == NAMEI_RENAME && wantparent && (flags & CNP_ISLASTCN)) { + if (nameiop == NAMEI_RENAME && wantparent) { if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_td)) != 0) return (error); /* @@ -560,7 +538,6 @@ found: if (error) return (error); *vpp = tdp; - cnp->cn_flags |= CNP_SAVENAME; if (!lockparent) { VOP_UNLOCK(vdp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; @@ -596,7 +573,7 @@ found: cnp->cn_flags &= ~CNP_PDIRUNLOCK; return (error); } - if (lockparent && (flags & CNP_ISLASTCN)) { + if (lockparent) { if ((error = vn_lock(pdp, LK_EXCLUSIVE, td)) != 0) { vput(tdp); return (error); @@ -611,18 +588,12 @@ found: error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp); if (error) return (error); - if (!lockparent || !(flags & CNP_ISLASTCN)) { + if (!lockparent) { VOP_UNLOCK(pdp, 0, td); cnp->cn_flags |= CNP_PDIRUNLOCK; } *vpp = tdp; } - - /* - * Insert name into cache if appropriate. - */ - if (cnp->cn_flags & CNP_MAKEENTRY) - cache_enter(vdp, *vpp, cnp); return (0); } @@ -692,10 +663,6 @@ ufs_makedirentry(struct inode *ip, struct componentname *cnp, struct direct *newdirp) { -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_SAVENAME) == 0) - panic("ufs_makedirentry: missing name"); -#endif newdirp->d_ino = ip->i_number; newdirp->d_namlen = cnp->cn_namelen; bcopy(cnp->cn_nameptr, newdirp->d_name, (unsigned)cnp->cn_namelen + 1); @@ -713,7 +680,7 @@ ufs_makedirentry(struct inode *ip, struct componentname *cnp, /* * Write a directory entry after a call to namei, using the parameters - * that it left in nameidata. The argument dirp is the new directory + * that it left in the directory inode. The argument dirp is the new directory * entry contents. Dvp is a pointer to the directory to be written, * which was left locked by namei. Remaining parameters (dp->i_offset, * dp->i_count) indicate how the space for the new entry is to be obtained. @@ -946,7 +913,7 @@ ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp, /* * Remove a directory entry after a call to namei, using - * the parameters which it left in nameidata. The entry + * the parameters which it left in the directory inode. The entry * dp->i_offset contains the offset into the directory of the * entry to be eliminated. The dp->i_count field contains the * size of the previous record in the directory. If this diff --git a/sys/vfs/ufs/ufs_quota.c b/sys/vfs/ufs/ufs_quota.c index 5d9ca51055..e16bedc2bf 100644 --- a/sys/vfs/ufs/ufs_quota.c +++ b/sys/vfs/ufs/ufs_quota.c @@ -35,7 +35,7 @@ * * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 * $FreeBSD: src/sys/ufs/ufs/ufs_quota.c,v 1.27.2.3 2002/01/15 10:33:32 phk Exp $ - * $DragonFly: src/sys/vfs/ufs/ufs_quota.c,v 1.16 2004/10/12 19:21:12 dillon Exp $ + * $DragonFly: src/sys/vfs/ufs/ufs_quota.c,v 1.17 2004/11/12 00:09:52 dillon Exp $ */ #include @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -380,7 +380,7 @@ quotaon(struct thread *td, struct mount *mp, int type, caddr_t fname) struct vnode *vp, **vpp; struct dquot *dq; int error; - struct nameidata nd; + struct nlookupdata nd; struct ucred *cred; struct scaninfo scaninfo; @@ -388,23 +388,27 @@ quotaon(struct thread *td, struct mount *mp, int type, caddr_t fname) cred = td->td_proc->p_ucred; vpp = &ump->um_quotas[type]; - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, fname, td); - error = vn_open(&nd, FREAD|FWRITE, 0); - if (error) + error = nlookup_init(&nd, fname, UIO_USERSPACE, NLC_FOLLOW|NLC_LOCKVP); + if (error == 0) + error = vn_open(&nd, NULL, FREAD|FWRITE, 0); + if (error == 0 && nd.nl_open_vp->v_type != VREG) + error = EACCES; + if (error) { + nlookup_done(&nd); return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - VOP_UNLOCK(vp, 0, td); - if (vp->v_type != VREG) { - (void) vn_close(vp, FREAD|FWRITE, td); - return (EACCES); } + vp = nd.nl_open_vp; + nd.nl_open_vp = NULL; + nlookup_done(&nd); + + VOP_UNLOCK(vp, 0, td); if (*vpp != vp) quotaoff(td, mp, type); ump->um_qflags[type] |= QTF_OPENING; mp->mnt_flag |= MNT_QUOTA; vp->v_flag |= VSYSTEM; *vpp = vp; + /* XXX release duplicate vp if *vpp == vp? */ /* * Save the credential of the process that turned on quotas. * Set up the time limits for this quota. diff --git a/sys/vfs/ufs/ufs_vnops.c b/sys/vfs/ufs/ufs_vnops.c index 76781c2628..59c90974f0 100644 --- a/sys/vfs/ufs/ufs_vnops.c +++ b/sys/vfs/ufs/ufs_vnops.c @@ -37,7 +37,7 @@ * * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95 * $FreeBSD: src/sys/ufs/ufs/ufs_vnops.c,v 1.131.2.8 2003/01/02 17:26:19 bde Exp $ - * $DragonFly: src/sys/vfs/ufs/ufs_vnops.c,v 1.23 2004/10/12 19:21:12 dillon Exp $ + * $DragonFly: src/sys/vfs/ufs/ufs_vnops.c,v 1.24 2004/11/12 00:09:52 dillon Exp $ */ #include "opt_quota.h" @@ -717,10 +717,6 @@ ufs_link(struct vop_link_args *ap) struct direct newdir; int error; -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("ufs_link: no name"); -#endif if (tdvp->v_mount != vp->v_mount) { error = EXDEV; goto out2; @@ -788,8 +784,6 @@ ufs_whiteout(struct vop_whiteout_args *ap) case NAMEI_CREATE: /* create a new directory whiteout */ #ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_SAVENAME) == 0) - panic("ufs_whiteout: missing name"); if (dvp->v_mount->mnt_maxsymlinklen <= 0) panic("ufs_whiteout: old format filesystem"); #endif @@ -862,11 +856,6 @@ ufs_rename(struct vop_rename_args *ap) int doingdirectory = 0; int error = 0, ioflag; -#ifdef DIAGNOSTIC - if ((tcnp->cn_flags & CNP_HASBUF) == 0 || - (fcnp->cn_flags & CNP_HASBUF) == 0) - panic("ufs_rename: no name"); -#endif /* DIAGNOSTIC */ /* * Check for cross-device rename. */ @@ -903,6 +892,11 @@ abortit: if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0) goto abortit; + + /* + * Note: now that fvp is locked we have to be sure to unlock it before + * using the 'abortit' target. + */ dp = VTOI(fdvp); ip = VTOI(fvp); if (ip->i_nlink >= LINK_MAX) { @@ -932,16 +926,20 @@ abortit: doingdirectory = 1; } VN_KNOTE(fdvp, NOTE_WRITE); /* XXX right place? */ - vrele(fdvp); /* - * When the target exists, both the directory - * and target vnodes are returned locked. + * fvp still locked. ip->i_flag has IN_RENAME set if doingdirectory. + * Cleanup fvp requirements so we can unlock it. + * + * tvp and tdvp are locked. tvp may be NULL. Now that dp and xp + * is setup we can use the 'bad' target if we unlock fvp. We cannot + * use the abortit target anymore because of IN_RENAME. */ dp = VTOI(tdvp); - xp = NULL; if (tvp) xp = VTOI(tvp); + else + xp = NULL; /* * 1) Bump link count while we're moving stuff @@ -972,28 +970,71 @@ abortit: */ error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_td); VOP_UNLOCK(fvp, 0, td); + + /* + * We are now back to where we were in that fvp, fdvp are unlocked + * and tvp, tdvp are locked. tvp may be NULL. IN_RENAME may be + * set. Only the bad target or, if we clean up tvp and tdvp, the + * out target, may be used. + */ if (oldparent != dp->i_number) newparent = dp->i_number; if (doingdirectory && newparent) { if (error) /* write access check above */ goto bad; - if (xp != NULL) + + /* + * Once we start messing with tvp and tdvp we cannot use the + * 'bad' target, only finish cleaning tdvp and tvp up and + * use the 'out' target. + * + * This cleans up tvp. + */ + if (xp != NULL) { vput(tvp); + xp = NULL; + } + + /* + * This is a real mess. ufs_checkpath vput's the target + * directory so retain an extra ref and note that tdvp will + * lose its lock on return. This leaves us with one good + * ref after ufs_checkpath returns. + */ + vref(tdvp); error = ufs_checkpath(ip, dp, tcnp->cn_cred); - if (error) + tcnp->cn_flags |= CNP_PDIRUNLOCK; + if (error) { + vrele(tdvp); goto out; - if ((tcnp->cn_flags & CNP_SAVESTART) == 0) - panic("ufs_rename: lost to startdir"); - vref(tdvp); + } + + /* + * relookup no longer messes with tdvp's refs. tdvp must be + * unlocked on entry and will be locked on a successful + * return. + */ error = relookup(tdvp, &tvp, tcnp); - if (error) + if (error) { + if (tcnp->cn_flags & CNP_PDIRUNLOCK) + vrele(tdvp); + else + vput(tdvp); goto out; - vrele(tdvp); + } + KKASSERT((tcnp->cn_flags & CNP_PDIRUNLOCK) == 0); dp = VTOI(tdvp); - xp = NULL; if (tvp) xp = VTOI(tvp); } + + /* + * We are back to fvp, fdvp unlocked, tvp, tdvp locked. tvp may + * be NULL (xp will also be NULL in that case), and IN_RENAME will + * be set if doingdirectory. This means we can use the 'bad' target + * again. + */ + /* * 2) If target doesn't exist, link the target * to the source and unlink the source. @@ -1077,9 +1118,9 @@ abortit: error = ENOTDIR; goto bad; } - cache_purge(tvp); + /* cache_purge removed - handled by VFS compat layer */ } else if (doingdirectory == 0) { - cache_purge(tvp); + /* cache_purge removed - handled by VFS compat layer */ } else { error = EISDIR; goto bad; @@ -1136,29 +1177,44 @@ abortit: xp = NULL; } + /* + * tvp and tdvp have been cleaned up. only fvp and fdvp (both + * unlocked) remain. We are about to overwrite fvp but we have to + * keep 'ip' intact so we cannot release the old fvp, which is still + * refd and accessible via ap->a_fvp. + * + * This means we cannot use either 'bad' or 'out' to cleanup any + * more. + */ + /* * 3) Unlink the source. */ fcnp->cn_flags &= ~CNP_MODMASK; - fcnp->cn_flags |= CNP_LOCKPARENT | CNP_LOCKLEAF; - if ((fcnp->cn_flags & CNP_SAVESTART) == 0) - panic("ufs_rename: lost from startdir"); - vref(fdvp); + fcnp->cn_flags |= CNP_LOCKPARENT; error = relookup(fdvp, &fvp, fcnp); - if (error == 0) - vrele(fdvp); - if (fvp != NULL) { - xp = VTOI(fvp); - dp = VTOI(fdvp); - } else { + if (error || fvp == NULL) { /* - * From name has disappeared. + * From name has disappeared. IN_RENAME will not be set if + * we get past the panic so we don't have to clean it up. */ if (doingdirectory) panic("ufs_rename: lost dir entry"); vrele(ap->a_fvp); - return (0); + if (fcnp->cn_flags & CNP_PDIRUNLOCK) + vrele(fdvp); + else + vput(fdvp); + return(0); } + KKASSERT((fcnp->cn_flags & CNP_PDIRUNLOCK) == 0); + + /* + * fdvp and fvp are locked. + */ + xp = VTOI(fvp); + dp = VTOI(fdvp); + /* * Ensure that the directory entry still exists and has not * changed while the new name has been entered. If the source is @@ -1166,7 +1222,7 @@ abortit: * either case there is no further work to be done. If the source * is a directory then it cannot have been rmdir'ed; the IN_RENAME * flag ensures that it cannot be moved by another rename or removed - * by a rmdir. + * by a rmdir. Cleanup IN_RENAME. */ if (xp != ip) { if (doingdirectory) @@ -1181,23 +1237,15 @@ abortit: if (doingdirectory && newparent) { xp->i_offset = mastertemplate.dot_reclen; ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0); - /*cache_purge(fdvp);*/ + /* cache_purge removed - handled by VFS compat layer */ } error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0); xp->i_flag &= ~IN_RENAME; } - /* - * The old API can only do a kitchen sink invalidation. It will - * not be possible to '..' through the disconnected fvp (if a - * directory) until it is reconnected by a forward lookup. - */ - cache_purge(fvp); VN_KNOTE(fvp, NOTE_RENAME); - if (dp) - vput(fdvp); - if (xp) - vput(fvp); + vput(fdvp); + vput(fvp); vrele(ap->a_fvp); return (error); @@ -1216,8 +1264,9 @@ out: if (DOINGSOFTDEP(fvp)) softdep_change_linkcnt(ip); vput(fvp); - } else + } else { vrele(fvp); + } return (error); } @@ -1242,10 +1291,6 @@ ufs_mkdir(struct vop_mkdir_args *ap) int error, dmode; long blkoff; -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("ufs_mkdir: no name"); -#endif dp = VTOI(dvp); if ((nlink_t)dp->i_nlink >= LINK_MAX) { error = EMLINK; @@ -1507,7 +1552,7 @@ ufs_rmdir(struct vop_rmdir_args *ap) error = UFS_TRUNCATE(vp, (off_t)0, ioflag, cnp->cn_cred, cnp->cn_td); } - cache_purge(vp); + /* cache_purge removed - handled by VFS compat layer */ #ifdef UFS_DIRHASH /* Kill any active hash; i_effnlink == 0, so it will not come back. */ if (ip->i_dirhash != NULL) @@ -2005,10 +2050,6 @@ ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp, int error; pdir = VTOI(dvp); -#ifdef DIAGNOSTIC - if ((cnp->cn_flags & CNP_HASBUF) == 0) - panic("ufs_makeinode: no name"); -#endif *vpp = NULL; if ((mode & IFMT) == 0) mode |= IFREG; @@ -2232,7 +2273,7 @@ static struct vnodeopv_entry_desc ufs_vnodeop_entries[] = { { &vop_access_desc, (void *) ufs_access }, { &vop_advlock_desc, (void *) ufs_advlock }, { &vop_bmap_desc, (void *) ufs_bmap }, - { &vop_cachedlookup_desc, (void *) ufs_lookup }, + { &vop_lookup_desc, (void *) ufs_lookup }, { &vop_close_desc, (void *) ufs_close }, { &vop_create_desc, (void *) ufs_create }, { &vop_getattr_desc, (void *) ufs_getattr }, @@ -2240,7 +2281,6 @@ static struct vnodeopv_entry_desc ufs_vnodeop_entries[] = { { &vop_islocked_desc, (void *) vop_stdislocked }, { &vop_link_desc, (void *) ufs_link }, { &vop_lock_desc, (void *) vop_stdlock }, - { &vop_lookup_desc, (void *) vfs_cache_lookup }, { &vop_mkdir_desc, (void *) ufs_mkdir }, { &vop_mknod_desc, (void *) ufs_mknod }, { &vop_mmap_desc, (void *) ufs_mmap }, diff --git a/sys/vfs/ufs/ufsmount.h b/sys/vfs/ufs/ufsmount.h index 1e9dc6111f..10af4ce534 100644 --- a/sys/vfs/ufs/ufsmount.h +++ b/sys/vfs/ufs/ufsmount.h @@ -32,7 +32,7 @@ * * @(#)ufsmount.h 8.6 (Berkeley) 3/30/95 * $FreeBSD: src/sys/ufs/ufs/ufsmount.h,v 1.17 1999/12/29 04:55:06 peter Exp $ - * $DragonFly: src/sys/vfs/ufs/ufsmount.h,v 1.5 2004/07/18 19:43:48 drhodus Exp $ + * $DragonFly: src/sys/vfs/ufs/ufsmount.h,v 1.6 2004/11/12 00:09:52 dillon Exp $ */ #ifndef _UFS_UFS_UFSMOUNT_H_ @@ -64,7 +64,6 @@ MALLOC_DECLARE(M_UFSMNT); struct buf; struct inode; -struct nameidata; struct timeval; struct ucred; struct uio; diff --git a/sys/vfs/umapfs/umap_vfsops.c b/sys/vfs/umapfs/umap_vfsops.c index af0eeaa017..febce560bc 100644 --- a/sys/vfs/umapfs/umap_vfsops.c +++ b/sys/vfs/umapfs/umap_vfsops.c @@ -36,7 +36,7 @@ * @(#)umap_vfsops.c 8.8 (Berkeley) 5/14/95 * * $FreeBSD: src/sys/miscfs/umapfs/umap_vfsops.c,v 1.31.2.2 2001/09/11 09:49:53 kris Exp $ - * $DragonFly: src/sys/vfs/umapfs/Attic/umap_vfsops.c,v 1.13 2004/10/12 19:21:13 dillon Exp $ + * $DragonFly: src/sys/vfs/umapfs/Attic/umap_vfsops.c,v 1.14 2004/11/12 00:09:53 dillon Exp $ */ /* @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include "umap.h" #include @@ -92,7 +92,7 @@ umapfs_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) struct vnode *lowerrootvp, *vp; struct vnode *umapm_rootvp; struct umap_mount *amp; - struct nameidata nd; + struct nlookupdata nd; u_int size; int error; #ifdef DEBUG @@ -126,23 +126,24 @@ umapfs_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) /* * Find lower node */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_WANTPARENT | CNP_LOCKLEAF, - UIO_USERSPACE, args.target, td); - error = namei(&nd); + lowerrootvp = NULL; + error = nlookup_init(&nd, args.target, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) { + error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE, + &lowerrootvp); + } + nlookup_done(&nd); if (error) return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); /* * Sanity check on lower vnode */ - lowerrootvp = nd.ni_vp; #ifdef DEBUG printf("vp = %p, check for VDIR...\n", (void *)lowerrootvp); #endif - vrele(nd.ni_dvp); - nd.ni_dvp = 0; - if (lowerrootvp->v_type != VDIR) { vput(lowerrootvp); return (EINVAL); diff --git a/sys/vfs/union/union_subr.c b/sys/vfs/union/union_subr.c index 131c102070..bc2f412388 100644 --- a/sys/vfs/union/union_subr.c +++ b/sys/vfs/union/union_subr.c @@ -36,7 +36,7 @@ * * @(#)union_subr.c 8.20 (Berkeley) 5/20/95 * $FreeBSD: src/sys/miscfs/union/union_subr.c,v 1.43.2.2 2001/12/25 01:44:45 dillon Exp $ - * $DragonFly: src/sys/vfs/union/union_subr.c,v 1.16 2004/10/12 19:21:14 dillon Exp $ + * $DragonFly: src/sys/vfs/union/union_subr.c,v 1.17 2004/11/12 00:09:55 dillon Exp $ */ #include @@ -748,7 +748,7 @@ union_copyup(struct union_node *un, int docopy, struct ucred *cred, * from VOP_CLOSE */ vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(lvp, FREAD, cred, td); + error = VOP_OPEN(lvp, FREAD, cred, NULL, td); if (error == 0 && vn_canvmio(lvp) == TRUE) error = vfs_object_create(lvp, td); if (error == 0) { @@ -777,8 +777,8 @@ union_copyup(struct union_node *un, int docopy, struct ucred *cred, int i; for (i = 0; i < un->un_openl; i++) { - (void) VOP_CLOSE(lvp, FREAD, td); - (void) VOP_OPEN(uvp, FREAD, cred, td); + VOP_CLOSE(lvp, FREAD, td); + VOP_OPEN(uvp, FREAD, cred, NULL, td); } if (un->un_openl) { if (vn_canvmio(uvp) == TRUE) @@ -819,19 +819,17 @@ union_relookup(struct union_mount *um, struct vnode *dvp, struct vnode **vpp, * Conclusion: Horrible. */ cn->cn_namelen = pathlen; - cn->cn_pnbuf = zalloc(namei_zone); - bcopy(path, cn->cn_pnbuf, cn->cn_namelen); - cn->cn_pnbuf[cn->cn_namelen] = '\0'; + cn->cn_nameptr = zalloc(namei_zone); + bcopy(path, cn->cn_nameptr, cn->cn_namelen); + cn->cn_nameptr[cn->cn_namelen] = '\0'; cn->cn_nameiop = NAMEI_CREATE; - cn->cn_flags = (CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_HASBUF | - CNP_SAVENAME | CNP_ISLASTCN); + cn->cn_flags = CNP_LOCKPARENT; cn->cn_td = cnp->cn_td; if (um->um_op == UNMNT_ABOVE) cn->cn_cred = cnp->cn_cred; else cn->cn_cred = um->um_cred; - cn->cn_nameptr = cn->cn_pnbuf; cn->cn_consume = cnp->cn_consume; vref(dvp); @@ -844,9 +842,11 @@ union_relookup(struct union_mount *um, struct vnode *dvp, struct vnode **vpp, */ if ((error = relookup(dvp, vpp, cn)) != 0) { + zfree(namei_zone, cn->cn_nameptr); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, cnp->cn_td); return(error); } + zfree(namei_zone, cn->cn_nameptr); /* * If no error occurs, dvp will be returned locked with the reference @@ -886,10 +886,6 @@ union_mkshadow(struct union_mount *um, struct vnode *dvp, return (error); if (*vpp) { - if (cn.cn_flags & CNP_HASBUF) { - zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~CNP_HASBUF; - } if (dvp == *vpp) vrele(*vpp); else @@ -913,11 +909,7 @@ union_mkshadow(struct union_mount *um, struct vnode *dvp, /* VOP_LEASE: dvp is locked */ VOP_LEASE(dvp, td, cn.cn_cred, LEASE_WRITE); - error = VOP_MKDIR(dvp, NCPNULL, vpp, &cn, &va); - if (cn.cn_flags & CNP_HASBUF) { - zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~CNP_HASBUF; - } + error = VOP_MKDIR(dvp, vpp, &cn, &va); /*vput(dvp);*/ return (error); } @@ -949,10 +941,6 @@ union_mkwhiteout(struct union_mount *um, struct vnode *dvp, return (error); if (wvp) { - if (cn.cn_flags & CNP_HASBUF) { - zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~CNP_HASBUF; - } if (wvp == dvp) vrele(wvp); else @@ -963,11 +951,7 @@ union_mkwhiteout(struct union_mount *um, struct vnode *dvp, /* VOP_LEASE: dvp is locked */ VOP_LEASE(dvp, td, cred, LEASE_WRITE); - error = VOP_WHITEOUT(dvp, NCPNULL, &cn, NAMEI_CREATE); - if (cn.cn_flags & CNP_HASBUF) { - zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~CNP_HASBUF; - } + error = VOP_WHITEOUT(dvp, &cn, NAMEI_CREATE); return (error); } @@ -1013,14 +997,12 @@ union_vn_create(struct vnode **vpp, struct union_node *un, struct thread *td) * copied in the first place). */ cn.cn_namelen = strlen(un->un_path); - cn.cn_pnbuf = zalloc(namei_zone); - bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1); + cn.cn_nameptr = zalloc(namei_zone); + bcopy(un->un_path, cn.cn_nameptr, cn.cn_namelen+1); cn.cn_nameiop = NAMEI_CREATE; - cn.cn_flags = (CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_HASBUF | - CNP_SAVENAME | CNP_ISLASTCN); + cn.cn_flags = CNP_LOCKPARENT; cn.cn_td = td; cn.cn_cred = cred; - cn.cn_nameptr = cn.cn_pnbuf; cn.cn_consume = 0; /* @@ -1030,6 +1012,7 @@ union_vn_create(struct vnode **vpp, struct union_node *un, struct thread *td) */ vref(un->un_dirvp); error = relookup(un->un_dirvp, &vp, &cn); + zfree(namei_zone, cn.cn_nameptr); if (error) return (error); @@ -1039,10 +1022,6 @@ union_vn_create(struct vnode **vpp, struct union_node *un, struct thread *td) */ if (vp) { vput(un->un_dirvp); - if (cn.cn_flags & CNP_HASBUF) { - zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~CNP_HASBUF; - } if (vp == un->un_dirvp) vrele(vp); else @@ -1064,16 +1043,12 @@ union_vn_create(struct vnode **vpp, struct union_node *un, struct thread *td) vap->va_type = VREG; vap->va_mode = cmode; VOP_LEASE(un->un_dirvp, td, cred, LEASE_WRITE); - error = VOP_CREATE(un->un_dirvp, NCPNULL, &vp, &cn, vap); - if (cn.cn_flags & CNP_HASBUF) { - zfree(namei_zone, cn.cn_pnbuf); - cn.cn_flags &= ~CNP_HASBUF; - } + error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap); vput(un->un_dirvp); if (error) return (error); - error = VOP_OPEN(vp, fmode, cred, td); + error = VOP_OPEN(vp, fmode, cred, NULL, td); if (error == 0 && vn_canvmio(vp) == TRUE) error = vfs_object_create(vp, td); if (error) { @@ -1287,7 +1262,7 @@ union_dircheck(struct thread *td, struct vnode **vp, struct file *fp) } if (lvp != NULLVP) { - error = VOP_OPEN(lvp, FREAD, fp->f_cred, td); + error = VOP_OPEN(lvp, FREAD, fp->f_cred, NULL, td); if (error == 0 && vn_canvmio(lvp) == TRUE) error = vfs_object_create(lvp, td); if (error) { diff --git a/sys/vfs/union/union_vfsops.c b/sys/vfs/union/union_vfsops.c index 8f08bb887e..b1b3f504f0 100644 --- a/sys/vfs/union/union_vfsops.c +++ b/sys/vfs/union/union_vfsops.c @@ -36,7 +36,7 @@ * * @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95 * $FreeBSD: src/sys/miscfs/union/union_vfsops.c,v 1.39.2.2 2001/10/25 19:18:53 dillon Exp $ - * $DragonFly: src/sys/vfs/union/union_vfsops.c,v 1.16 2004/10/12 19:21:14 dillon Exp $ + * $DragonFly: src/sys/vfs/union/union_vfsops.c,v 1.17 2004/11/12 00:09:55 dillon Exp $ */ /* @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +81,7 @@ union_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) struct vnode *upperrootvp = NULLVP; struct union_mount *um = 0; struct ucred *cred = 0; - struct nameidata nd; + struct nlookupdata nd; char *cp = 0; int len; u_int size; @@ -131,26 +132,18 @@ union_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) #endif /* - * Obtain upper vnode by calling namei() on the path. The + * Obtain upper vnode by calling nlookup() on the path. The * upperrootvp will be turned referenced but not locked. */ - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_WANTPARENT, - UIO_USERSPACE, args.target, td); - - error = namei(&nd); - -#if 0 - if (lowerrootvp->v_tag == VT_UNION) - vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY, td); -#endif + error = nlookup_init(&nd, args.target, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &upperrootvp); + nlookup_done(&nd); if (error) goto bad; - NDFREE(&nd, NDF_ONLY_PNBUF); - upperrootvp = nd.ni_vp; - vrele(nd.ni_dvp); - nd.ni_dvp = NULL; - UDEBUG(("mount_root UPPERVP %p locked = %d\n", upperrootvp, VOP_ISLOCKED(upperrootvp, NULL))); @@ -220,7 +213,7 @@ union_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) * supports whiteout operations */ if ((mp->mnt_flag & MNT_RDONLY) == 0) { - error = VOP_WHITEOUT(um->um_uppervp, NCPNULL, NULL, NAMEI_LOOKUP); + error = VOP_WHITEOUT(um->um_uppervp, NULL, NAMEI_LOOKUP); if (error) goto bad; } diff --git a/sys/vfs/union/union_vnops.c b/sys/vfs/union/union_vnops.c index c716faa56c..efddc3b155 100644 --- a/sys/vfs/union/union_vnops.c +++ b/sys/vfs/union/union_vnops.c @@ -36,7 +36,7 @@ * * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95 * $FreeBSD: src/sys/miscfs/union/union_vnops.c,v 1.72 1999/12/15 23:02:14 eivind Exp $ - * $DragonFly: src/sys/vfs/union/union_vnops.c,v 1.16 2004/10/12 19:21:14 dillon Exp $ + * $DragonFly: src/sys/vfs/union/union_vnops.c,v 1.17 2004/11/12 00:09:55 dillon Exp $ */ #include @@ -229,8 +229,10 @@ union_lookup1(struct vnode *udvp, struct vnode **pdvp, struct vnode **vpp, */ UDEBUG(("parentdir %p result %p flag %lx\n", dvp, tdvp, cnp->cn_flags)); - if (dvp != tdvp && (cnp->cn_flags & CNP_ISLASTCN) == 0) +#if 0 + if (dvp != tdvp && (cnp->cn_flags & CNP_XXXISLASTCN) == 0) vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); +#endif /* * Lastly check if the current node is a mount point in @@ -299,8 +301,7 @@ union_lookup(struct vop_lookup_args *ap) /* * Disallow write attemps to the filesystem mounted read-only. */ - if ((cnp->cn_flags & CNP_ISLASTCN) && - (dvp->v_mount->mnt_flag & MNT_RDONLY) && + if ((dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) { return (EROFS); } @@ -367,7 +368,7 @@ union_lookup(struct vop_lookup_args *ap) /* * Disallow write attemps to the filesystem mounted read-only. */ - if (uerror == EJUSTRETURN && (cnp->cn_flags & CNP_ISLASTCN) && + if (uerror == EJUSTRETURN && (dvp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == NAMEI_CREATE || cnp->cn_nameiop == NAMEI_RENAME)) { error = EROFS; @@ -593,8 +594,7 @@ out: */ if (*ap->a_vpp != dvp) { - if ((error == 0 || error == EJUSTRETURN) && - (!lockparent || (cnp->cn_flags & CNP_ISLASTCN) == 0)) { + if ((error == 0 || error == EJUSTRETURN) && !lockparent) { VOP_UNLOCK(dvp, 0, td); } } @@ -636,7 +636,7 @@ union_create(struct vop_create_args *ap) struct vnode *vp; struct mount *mp; - error = VOP_CREATE(dvp, NCPNULL, &vp, cnp, ap->a_vap); + error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap); if (error == 0) { mp = ap->a_dvp->v_mount; VOP_UNLOCK(vp, 0, td); @@ -663,7 +663,7 @@ union_whiteout(struct vop_whiteout_args *ap) int error = EOPNOTSUPP; if ((uppervp = union_lock_upper(un, cnp->cn_td)) != NULLVP) { - error = VOP_WHITEOUT(un->un_uppervp, NCPNULL, cnp, ap->a_flags); + error = VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags); union_unlock_upper(uppervp, cnp->cn_td); } return(error); @@ -687,7 +687,7 @@ union_mknod(struct vop_mknod_args *ap) int error = EROFS; if ((dvp = union_lock_upper(dun, cnp->cn_td)) != NULL) { - error = VOP_MKNOD(dvp, NCPNULL, ap->a_vpp, cnp, ap->a_vap); + error = VOP_MKNOD(dvp, ap->a_vpp, cnp, ap->a_vap); union_unlock_upper(dvp, cnp->cn_td); } return (error); @@ -747,7 +747,7 @@ union_open(struct vop_open_args *ap) */ if (error == 0) - error = VOP_OPEN(tvp, mode, cred, td); + error = VOP_OPEN(tvp, mode, cred, NULL, td); /* * Absolutely necessary or UFS will blowup @@ -1234,7 +1234,7 @@ union_remove(struct vop_remove_args *ap) if ((uppervp = union_lock_upper(un, td)) != NULLVP) { if (union_dowhiteout(un, cnp->cn_cred, td)) cnp->cn_flags |= CNP_DOWHITEOUT; - error = VOP_REMOVE(upperdvp, NCPNULL, uppervp, cnp); + error = VOP_REMOVE(upperdvp, uppervp, cnp); #if 0 /* XXX */ if (!error) @@ -1312,7 +1312,7 @@ union_link(struct vop_link_args *ap) return (EROFS); VOP_UNLOCK(ap->a_tdvp, 0, td); /* unlock calling node */ - error = VOP_LINK(tdvp, NCPNULL, vp, cnp); /* call link on upper */ + error = VOP_LINK(tdvp, vp, cnp); /* call link on upper */ /* * We have to unlock tdvp prior to relocking our calling node in @@ -1465,7 +1465,7 @@ union_rename(struct vop_rename_args *ap) * cleanup to do. */ - return (VOP_RENAME(fdvp, NCPNULL, fvp, ap->a_fcnp, tdvp, NCPNULL, tvp, ap->a_tcnp)); + return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); /* * Error. We still have to release / vput the various elements. @@ -1501,7 +1501,7 @@ union_mkdir(struct vop_mkdir_args *ap) if ((upperdvp = union_lock_upper(dun, td)) != NULLVP) { struct vnode *vp; - error = VOP_MKDIR(upperdvp, NCPNULL, &vp, cnp, ap->a_vap); + error = VOP_MKDIR(upperdvp, &vp, cnp, ap->a_vap); union_unlock_upper(upperdvp, td); if (error == 0) { @@ -1536,7 +1536,7 @@ union_rmdir(struct vop_rmdir_args *ap) if ((uppervp = union_lock_upper(un, td)) != NULLVP) { if (union_dowhiteout(un, cnp->cn_cred, td)) cnp->cn_flags |= CNP_DOWHITEOUT; - error = VOP_RMDIR(upperdvp, NCPNULL, uppervp, ap->a_cnp); + error = VOP_RMDIR(upperdvp, uppervp, ap->a_cnp); union_unlock_upper(uppervp, td); } else { error = union_mkwhiteout( @@ -1567,7 +1567,7 @@ union_symlink(struct vop_symlink_args *ap) int error = EROFS; if ((dvp = union_lock_upper(dun, td)) != NULLVP) { - error = VOP_SYMLINK(dvp, NCPNULL, ap->a_vpp, cnp, ap->a_vap, + error = VOP_SYMLINK(dvp, ap->a_vpp, cnp, ap->a_vap, ap->a_target); union_unlock_upper(dvp, td); } diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c index 86ae2e8a64..a3b3750c09 100644 --- a/sys/vm/device_pager.c +++ b/sys/vm/device_pager.c @@ -37,7 +37,7 @@ * * @(#)device_pager.c 8.1 (Berkeley) 6/11/93 * $FreeBSD: src/sys/vm/device_pager.c,v 1.46.2.1 2000/08/02 21:54:37 peter Exp $ - * $DragonFly: src/sys/vm/device_pager.c,v 1.8 2004/07/21 01:25:18 dillon Exp $ + * $DragonFly: src/sys/vm/device_pager.c,v 1.9 2004/11/12 00:09:56 dillon Exp $ */ #include @@ -265,5 +265,7 @@ dev_pager_putfake(vm_page_t m) { if (!(m->flags & PG_FICTITIOUS)) panic("dev_pager_putfake: bad page"); + KKASSERT(m->object == NULL); zfree(fakepg_zone, m); } + diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index d58f049a2d..9e1b68f13e 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -62,7 +62,7 @@ * rights to redistribute these changes. * * $FreeBSD: src/sys/vm/vm_object.c,v 1.171.2.8 2003/05/26 19:17:56 alc Exp $ - * $DragonFly: src/sys/vm/vm_object.c,v 1.20 2004/10/12 19:21:16 dillon Exp $ + * $DragonFly: src/sys/vm/vm_object.c,v 1.21 2004/11/12 00:09:56 dillon Exp $ */ /* @@ -133,7 +133,6 @@ static int vm_object_page_collect_flush(vm_object_t object, vm_page_t p, int cur */ struct object_q vm_object_list; -static struct lwkt_token vm_object_list_token; static long vm_object_count; /* count of all objects */ vm_object_t kernel_object; vm_object_t kmem_object; @@ -185,9 +184,11 @@ _vm_object_allocate(objtype_t type, vm_size_t size, vm_object_t object) object->generation++; + crit_enter(); TAILQ_INSERT_TAIL(&vm_object_list, object, object_list); vm_object_count++; object_hash_rand = object->hash_rand; + crit_exit(); } /* @@ -199,8 +200,6 @@ void vm_object_init(void) { TAILQ_INIT(&vm_object_list); - lwkt_token_init(&vm_object_list_token); - vm_object_count = 0; kernel_object = &kernel_object_store; _vm_object_allocate(OBJT_DEFAULT, OFF_TO_IDX(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS), @@ -410,7 +409,6 @@ doterm: void vm_object_terminate(vm_object_t object) { - lwkt_tokref ilock; vm_page_t p; /* @@ -485,11 +483,14 @@ vm_object_terminate(vm_object_t object) /* * Remove the object from the global object list. */ - lwkt_gettoken(&ilock, &vm_object_list_token); + crit_enter(); TAILQ_REMOVE(&vm_object_list, object, object_list); - lwkt_reltoken(&ilock); + vm_object_count--; + crit_exit(); wakeup(object); + if (object->ref_count != 0) + panic("vm_object_terminate2: object with references, ref_count=%d", object->ref_count); /* * Free the space for the object. @@ -1187,6 +1188,7 @@ vm_object_backing_scan(vm_object_t object, int op) } } if (op & OBSC_COLLAPSE_WAIT) { + KKASSERT((backing_object->flags & OBJ_DEAD) == 0); vm_object_set_flag(backing_object, OBJ_DEAD); } @@ -1427,7 +1429,6 @@ vm_object_collapse(vm_object_t object) * If there is exactly one reference to the backing * object, we can collapse it into the parent. */ - vm_object_backing_scan(object, OBSC_COLLAPSE_WAIT); /* @@ -1494,12 +1495,14 @@ vm_object_collapse(vm_object_t object) KASSERT(backing_object->ref_count == 1, ("backing_object %p was somehow re-referenced during collapse!", backing_object)); KASSERT(TAILQ_FIRST(&backing_object->memq) == NULL, ("backing_object %p somehow has left over pages during collapse!", backing_object)); + crit_enter(); TAILQ_REMOVE( &vm_object_list, backing_object, object_list ); vm_object_count--; + crit_exit(); zfree(obj_zone, backing_object); diff --git a/sys/vm/vm_swap.c b/sys/vm/vm_swap.c index c4de00f3cf..3ed92a6e58 100644 --- a/sys/vm/vm_swap.c +++ b/sys/vm/vm_swap.c @@ -32,7 +32,7 @@ * * @(#)vm_swap.c 8.5 (Berkeley) 2/17/94 * $FreeBSD: src/sys/vm/vm_swap.c,v 1.96.2.2 2001/10/14 18:46:47 iedowse Exp $ - * $DragonFly: src/sys/vm/vm_swap.c,v 1.15 2004/10/12 19:21:16 dillon Exp $ + * $DragonFly: src/sys/vm/vm_swap.c,v 1.16 2004/11/12 00:09:56 dillon Exp $ */ #include "opt_swap.h" @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include /* XXX */ #include #include @@ -183,7 +183,7 @@ swapon(struct swapon_args *uap) struct thread *td = curthread; struct vattr attr; struct vnode *vp; - struct nameidata nd; + struct nlookupdata nd; int error; struct ucred *cred; @@ -194,14 +194,16 @@ swapon(struct swapon_args *uap) if (error) return (error); - NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->name, td); - error = namei(&nd); + vp = NULL; + error = nlookup_init(&nd, uap->name, UIO_USERSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(nd.nl_ncp, nd.nl_cred, &vp); + nlookup_done(&nd); if (error) return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - if (vn_isdisk(vp, &error)) error = swaponvp(td, vp, 0); else if (vp->v_type == VREG && vp->v_tag == VT_NFS && @@ -266,7 +268,7 @@ swaponvp(struct thread *td, struct vnode *vp, u_long nblks) return EINVAL; found: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - error = VOP_OPEN(vp, FREAD | FWRITE, cred, td); + error = VOP_OPEN(vp, FREAD | FWRITE, cred, NULL, td); VOP_UNLOCK(vp, 0, td); if (error) return (error); -- 2.41.0