diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 2e6095dd23f8..5dbd12db278f 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ - $NetBSD: syscalls.master,v 1.88 1999/02/10 18:02:28 kleink Exp $ + $NetBSD: syscalls.master,v 1.89 1999/03/22 17:01:55 sommerfe Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 @@ -564,3 +564,5 @@ sigset_t *oset); } 294 STD { int sys___sigsuspend14(const sigset_t *set); } 295 STD { int sys___sigreturn14(struct sigcontext *sigcntxp); } +296 STD { int sys___getcwd(char *bufp, size_t length); } +297 STD { int sys_fchroot(int fd); } diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index d48896906dd8..02e77ef06b1a 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_cache.c,v 1.18 1998/09/01 04:33:56 thorpej Exp $ */ +/* $NetBSD: vfs_cache.c,v 1.19 1999/03/22 17:01:55 sommerfe Exp $ */ /* * Copyright (c) 1989, 1993 @@ -69,6 +69,10 @@ LIST_HEAD(nchashhead, namecache) *nchashtbl; u_long nchash; /* size of hash table - 1 */ long numcache; /* number of cache entries allocated */ + +LIST_HEAD(ncvhashhead, namecache) *ncvhashtbl; +u_long ncvhash; /* size of hash table - 1 */ + TAILQ_HEAD(, namecache) nclruhead; /* LRU chain */ struct nchstats nchstats; /* cache effectiveness statistics */ @@ -163,10 +167,84 @@ cache_lookup(dvp, vpp, cnp) TAILQ_REMOVE(&nclruhead, ncp, nc_lru); LIST_REMOVE(ncp, nc_hash); ncp->nc_hash.le_prev = 0; + if (ncp->nc_vhash.le_prev != NULL) { + LIST_REMOVE(ncp, nc_vhash); + ncp->nc_vhash.le_prev = 0; + } TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru); return (0); } +/* + * Scan cache looking for name of directory entry pointing at vp. + * + * Fill in dvpp. + * + * If bufp is non-NULL, also place the name in the buffer which starts + * at bufp, immediately before *bpp, and move bpp backwards to point + * at the start of it. (Yes, this is a little baroque, but it's done + * this way to cater to the whims of getcwd). + * + * Returns 0 on success, -1 on cache miss, positive errno on failure. + */ +int +cache_revlookup (vp, dvpp, bpp, bufp) + struct vnode *vp, **dvpp; + char **bpp; + char *bufp; +{ + struct namecache *ncp; + struct vnode *dvp; + struct ncvhashhead *nvcpp; + + if (!doingcache) + goto out; + + nvcpp = &ncvhashtbl[(vp->v_id & ncvhash)]; + + for (ncp = nvcpp->lh_first; ncp != 0; ncp = ncp->nc_vhash.le_next) { + if ((ncp->nc_vp == vp) && + (ncp->nc_vpid == vp->v_id) && + ((dvp = ncp->nc_dvp) != 0) && + (dvp != vp) && /* avoid pesky . entries.. */ + (dvp->v_id == ncp->nc_dvpid)) + { + char *bp; + +#ifdef DIAGNOSTIC + if ((ncp->nc_nlen == 1) && + (ncp->nc_name[0] == '.')) + panic("cache_revlookup: found entry for ."); + + if ((ncp->nc_nlen == 2) && + (ncp->nc_name[0] == '.') && + (ncp->nc_name[1] == '.')) + panic("cache_revlookup: found entry for .."); +#endif + nchstats.ncs_revhits++; + + if (bufp) { + bp = *bpp; + bp -= ncp->nc_nlen; + if (bp <= bufp) { + *dvpp = 0; + return ERANGE; + } + memcpy(bp, ncp->nc_name, ncp->nc_nlen); + *bpp = bp; + } + + /* XXX MP: how do we know dvp won't evaporate? */ + *dvpp = dvp; + return 0; + } + } + nchstats.ncs_revmiss++; + out: + *dvpp = 0; + return -1; +} + /* * Add an entry to the cache */ @@ -178,6 +256,7 @@ cache_enter(dvp, vp, cnp) { register struct namecache *ncp; register struct nchashhead *ncpp; + register struct ncvhashhead *nvcpp; #ifdef DIAGNOSTIC if (cnp->cn_namelen > NCHNAMLEN) @@ -198,6 +277,10 @@ cache_enter(dvp, vp, cnp) LIST_REMOVE(ncp, nc_hash); ncp->nc_hash.le_prev = 0; } + if (ncp->nc_vhash.le_prev != 0) { + LIST_REMOVE(ncp, nc_vhash); + ncp->nc_vhash.le_prev = 0; + } } else return; /* grab the vnode we just found */ @@ -219,6 +302,24 @@ cache_enter(dvp, vp, cnp) TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru); ncpp = &nchashtbl[(cnp->cn_hash ^ dvp->v_id) & nchash]; LIST_INSERT_HEAD(ncpp, ncp, nc_hash); + + ncp->nc_vhash.le_prev = 0; + ncp->nc_vhash.le_next = 0; + + /* + * Create reverse-cache entries (used in getcwd) for directories. + */ + if (vp && + (vp != dvp) && + (vp->v_type == VDIR) && + ((ncp->nc_nlen > 2) || + ((ncp->nc_nlen == 2) && (ncp->nc_name[0] != '.') && (ncp->nc_name[1] != '.')) || + ((ncp->nc_nlen == 1) && (ncp->nc_name[0] != '.')))) + { + nvcpp = &ncvhashtbl[(vp->v_id & ncvhash)]; + LIST_INSERT_HEAD(nvcpp, ncp, nc_vhash); + } + } /* @@ -230,6 +331,7 @@ nchinit() TAILQ_INIT(&nclruhead); nchashtbl = hashinit(desiredvnodes, M_CACHE, M_WAITOK, &nchash); + ncvhashtbl = hashinit(desiredvnodes/8, M_CACHE, M_WAITOK, &ncvhash); pool_init(&namecache_pool, sizeof(struct namecache), 0, 0, 0, "ncachepl", 0, pool_page_alloc_nointr, pool_page_free_nointr, M_CACHE); @@ -285,8 +387,13 @@ cache_purgevfs(mp) LIST_REMOVE(ncp, nc_hash); ncp->nc_hash.le_prev = 0; } + if (ncp->nc_vhash.le_prev != 0) { + LIST_REMOVE(ncp, nc_vhash); + ncp->nc_vhash.le_prev = 0; + } /* cause rescan of list, it may have altered */ nxtcp = nclruhead.tqh_first; TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru); } } + diff --git a/sys/kern/vfs_getcwd.c b/sys/kern/vfs_getcwd.c new file mode 100644 index 000000000000..e885c294ad73 --- /dev/null +++ b/sys/kern/vfs_getcwd.c @@ -0,0 +1,643 @@ +/* $NetBSD: vfs_getcwd.c,v 1.1 1999/03/22 17:01:55 sommerfe Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* XXX only for DIRBLKSIZ */ + +#include + +static int +getcwd_scandir __P((struct vnode *, struct vnode **, + char **, char *, struct proc *)); +static int +getcwd_getcache __P((struct vnode **, struct vnode **, + char **, char *)); +static int +getcwd_common __P((struct vnode *, struct vnode *, + char **, char *, int, int, struct proc *)); + +int vn_isunder __P((struct vnode *, struct vnode *, struct proc *)); + +#define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4) + +/* + * 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? + */ + +/* + * Find parent vnode of cvp, return in *pvpp + * Scan it looking for name of directory entry pointing at cvp. + * + * Place the name in the buffer which starts at bufp, immediately + * before *bpp, and move bpp backwards to point at the start of it. + */ +static int +getcwd_scandir(cvp, pvpp, bpp, bufp, p) + struct vnode *cvp; + struct vnode **pvpp; + char **bpp; + char *bufp; + struct proc *p; +{ + char *entry; + 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 *pvp = NULL; + struct componentname cn; + int len, reclen; + tries = 0; + + /* + * Ok, we have to do it the hard way.. + * First, get parent vnode using lookup of .. + */ + cn.cn_nameiop = LOOKUP; + cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY | LOCKPARENT; + cn.cn_proc = p; + cn.cn_cred = p->p_ucred; + cn.cn_pnbuf = NULL; + cn.cn_nameptr = ".."; + cn.cn_namelen = 2; + cn.cn_hash = 0; + cn.cn_consume = 0; + + /* + * At this point, cvp is locked, and will be locked + * on return in all cases. + * On successful return, *pvpp will also be locked + */ + error = VOP_LOOKUP(cvp, pvpp, &cn); + if (error) { + *pvpp = NULL; + return error; + } + pvp = *pvpp; + + /* If we don't care about the pathname, we're done */ + if (bufp == NULL) + return 0; + + error = VOP_GETATTR(cvp, &va, p->p_ucred, p); + if (error) + return error; + 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_procp = p; + + eofflag = 0; + + error = VOP_READDIR(pvp, &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 */ + } + entry = NULL; + 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; + } + memcpy(bp, dp->d_name, dp->d_namlen); + error = 0; + *bpp = bp; + goto out; + } + cpos += reclen; + } + } + } while (!eofflag && !entry); +#if 0 + /* + * Deal with mount -o union, which unions only the + * root directory of the mount. + */ + if ((pvp->v_flag & VROOT) && + (pvp->v_mount->mnt_flag & MNT_UNION)) { + struct vnode *tvp = pvp; + pvp = pvp->v_mount->mnt_vnodecovered; + vput(tvp); + VREF(pvp); + *pvpp = pvp; + error = vn_lock(pvp, LK_EXCLUSIVE | LK_RETRY); + if (error != 0) { + vrele(pvp); + *pvpp = pvp = NULL; + goto out; + } + goto unionread; + } +#endif + error = ENOENT; + +out: + free(dirbuf, M_TEMP); + return error; +} + +/* + * Look in the vnode-to-name reverse cache to see if + * we can find things the easy way. + * + * XXX vn_lock/vget failure paths are untested. + */ + +static int +getcwd_getcache(vpp, dvpp, bpp, bufp) + struct vnode **vpp, **dvpp; + char **bpp; + char *bufp; +{ + struct vnode *cvp, *pvp = NULL; + int error; + + cvp = *vpp; + + error = cache_revlookup(cvp, dvpp, bpp, bufp); + if (error) + return error; + pvp = *dvpp; + + /* + * Do a little dance with the locks to avoid deadlocking + * someone going the other way. Since we're going up, we have + * to release the current lock before we take the parent lock, + * and then re-take the current lock. Since either lock can + * fail, causing us to abort, this is a little convoluted. + */ + + VOP_UNLOCK(cvp, 0); + /* cur now unlocked... */ + error = vget(pvp, LK_EXCLUSIVE | LK_RETRY); + if (error != 0) { + vrele(cvp); + *vpp = NULL; + *dvpp = NULL; + return error; + } + /* parent is now locked */ + error = vn_lock(cvp, LK_EXCLUSIVE | LK_RETRY); + if (error != 0) { + vrele(cvp); + *vpp = NULL; + return error; + } + /* ok, cur is now locked again.. */ + return 0; +} + +/* + * common routine shared by sys___getcwd() and vn_isunder() + */ + +#define GETCWD_CHECK_ACCESS 0x0001 + +static int getcwd_common (dvp, rvp, bpp, bufp, limit, flags, p) + struct vnode *dvp; + struct vnode *rvp; + char **bpp; + char *bufp; + int limit; + int flags; + struct proc *p; +{ + struct filedesc *fdp = p->p_fd; + struct vnode *pvp = NULL; + char *bp; + int error; + + if (rvp == NULL) { + rvp = fdp->fd_rdir; + if (rvp == NULL) + rvp = rootvnode; + } + + VREF(rvp); + VREF(dvp); + + /* + * Error handling invariant: + * Before a `goto out': + * dvp is either NULL, or locked and held. + * pvp is either NULL, or locked and held. + */ + + error = vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + if (error) { + vrele(dvp); + dvp = 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 (dvp == rvp) { + if (bufp) + *(--(*bpp)) = '/'; + goto out; + } + do { + if (dvp->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(dvp, VEXEC|VREAD, p->p_ucred, p); + if (error) + goto out; + } + + /* + * step up if we're a covered vnode.. + */ + while (dvp->v_flag & VROOT) { + struct vnode *tvp; + + if (dvp == rvp) + goto out; + + tvp = dvp; + dvp = dvp->v_mount->mnt_vnodecovered; + vput(tvp); + /* + * hodie natus est radici frater + */ + if (dvp == NULL) { + error = ENOENT; + goto out; + } + VREF(dvp); + error = vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + if (error != 0) { + vrele(dvp); + dvp = NULL; + goto out; + } + } + /* + * Look in the name cache; if that fails, look in the + * directory.. + */ + error = getcwd_getcache(&dvp, &pvp, bpp, bufp); + if (error == -1) + error = getcwd_scandir(dvp, &pvp, bpp, bufp, p); + if (error) + goto out; +#if DIAGNOSTIC + if (dvp == pvp) { + panic("getcwd: oops, dvp == pvp"); + } + if (bufp && (bp <= bufp)) { + panic("getcwd: oops, went back too far"); + } +#endif + if (bufp) *(--(*bpp)) = '/'; + + vput(dvp); + dvp = pvp; + pvp = NULL; + limit--; + } while ((dvp != rvp) && (limit > 0)); + +out: + if (pvp) + vput(pvp); + if (dvp) + vput(dvp); + vrele(rvp); + return error; +} + +/* + * Check if one directory can be found inside another in the directory + * hierarchy. + * + * Intended to be used in chroot, chdir, fchdir, etc., to ensure that + * chroot() actually means something. + */ +int vn_isunder(dvp, rvp, p) + struct vnode *dvp; + struct vnode *rvp; + struct proc *p; +{ + int error; + + error = getcwd_common (dvp, rvp, NULL, NULL, MAXPATHLEN/2, 0, p); + + if (!error) + return 1; + else + return 0; +} + +int sys___getcwd(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + register struct sys___getcwd_args /* { + syscallarg(char *) bufp; + syscallarg(size_t) length; + } */ *uap = v; + + int error; + char *path; + char *bp, *bend; + int len = SCARG(uap, length); + int lenused; + + if ((len < 2) || (len > MAXPATHLEN*4)) + return ERANGE; + + path = (char *)malloc(len, M_TEMP, M_WAITOK); + if (!path) + return ENOMEM; + + bp = &path[len]; + bend = bp; + *(--bp) = '\0'; + + error = getcwd_common (p->p_fd->fd_cdir, NULL, &bp, path, len/2, + GETCWD_CHECK_ACCESS, p); + + if (error) + goto out; + lenused = bend - bp; + *retval = lenused; + /* put the result into user buffer */ + error = copyout(bp, SCARG(uap, bufp), lenused); + +out: + free(path, M_TEMP); + return error; +} + + + +/* + * Find pathname of process's current directory. + * + * Use vfs vnode-to-name reverse cache; if that fails, fall back + * to reading directory contents. + */ + +/* + * XXX Untested vs. mount -o union; probably does the wrong thing. + * XXX Untested vs chroot + * XXX most error paths probably work, but many locking-related ones + * aren't tested well. + */ +#if 0 + +int +sys___getcwd(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + register struct sys___getcwd_args /* { + syscallarg(char *) bufp; + syscallarg(size_t) length; + } */ *uap = v; + + struct filedesc *fdp = p->p_fd; + struct vnode *cvp = NULL, *pvp = NULL, *rootvp = NULL; + int error; + char *path; + char *bp, *bend; + int len = SCARG(uap, length); + int lenused; + + if ((len < 2) || (len > MAXPATHLEN*4)) + return ERANGE; + + path = (char *)malloc(len, M_TEMP, M_WAITOK); + if (!path) + return ENOMEM; + + bp = &path[len]; + bend = bp; + *(--bp) = '\0'; + + rootvp = fdp->fd_rdir; + if (rootvp == NULL) + rootvp = rootvnode; + + cvp = fdp->fd_cdir; + + VREF(rootvp); + VREF(cvp); + + /* + * Error handling invariant: + * Before a `goto out': + * cvp is either NULL, or locked and held. + * pvp is either NULL, or locked and held. + */ + + error = vn_lock(cvp, LK_EXCLUSIVE | LK_RETRY); + if (error) { + vrele(cvp); + cvp = NULL; + goto out; + } + /* + * 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 (cvp == rootvp) { + *(--bp) = '/'; + goto hitroot; + } + do { + /* + * so, are we even allowed to look at this directory? + */ + + error = VOP_ACCESS(cvp, VEXEC|VREAD, p->p_ucred, p); + if (error) + goto out; + + /* + * step up if we're a covered vnode.. + */ + while (cvp->v_flag & VROOT) { + struct vnode *tvp; + + if (cvp == rootvp) + goto hitroot; + + tvp = cvp; + cvp = cvp->v_mount->mnt_vnodecovered; + vput(tvp); + VREF(cvp); + error = vn_lock(cvp, LK_EXCLUSIVE | LK_RETRY); + if (error != 0) { + vrele(cvp); + cvp = NULL; + goto out; + } + } + /* + * Look in the name cache; if that fails, look in the directory.. + */ + error = getcwd_getcache(&cvp, &pvp, &bp, path); + if (error == -1) + error = getcwd_scandir(cvp, &pvp, &bp, path, p); + + if (error) + goto out; + if (bp <= path) { + error = ERANGE; + goto out; + } + *(--bp) = '/'; + + vput(cvp); + cvp = pvp; + pvp = NULL; + + } while (cvp != rootvp); +hitroot: + + lenused = bend - bp; + *retval = lenused; + /* put the result into user buffer */ + error = copyout(bp, SCARG(uap, bufp), lenused); + +out: + if (pvp) + vput(pvp); + if (cvp) + vput(cvp); + vrele(rootvp); + free(path, M_TEMP); + return error; +} +#endif diff --git a/sys/sys/namei.h b/sys/sys/namei.h index e4eadd271e8d..8c91a886d044 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -1,4 +1,4 @@ -/* $NetBSD: namei.h,v 1.14 1998/03/01 02:24:13 fvdl Exp $ */ +/* $NetBSD: namei.h,v 1.15 1999/03/22 17:01:55 sommerfe Exp $ */ /* * Copyright (c) 1985, 1989, 1991, 1993 @@ -163,6 +163,7 @@ struct nameidata { struct namecache { LIST_ENTRY(namecache) nc_hash; /* hash chain */ TAILQ_ENTRY(namecache) nc_lru; /* LRU chain */ + LIST_ENTRY(namecache) nc_vhash; /* directory hash chain */ struct vnode *nc_dvp; /* vnode of parent of name */ u_long nc_dvpid; /* capability number of nc_dvp */ struct vnode *nc_vp; /* vnode the name refers to */ @@ -179,6 +180,7 @@ int relookup __P((struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)); void cache_purge __P((struct vnode *)); int cache_lookup __P((struct vnode *, struct vnode **, struct componentname *)); +int cache_revlookup __P((struct vnode *, struct vnode **, char **, char *)); void cache_enter __P((struct vnode *, struct vnode *, struct componentname *)); void nchinit __P((void)); struct mount; @@ -198,5 +200,7 @@ struct nchstats { long ncs_long; /* long names that ignore cache */ long ncs_pass2; /* names found with passes == 2 */ long ncs_2passes; /* number of times we attempt it */ + long ncs_revhits; /* reverse-cache hits */ + long ncs_revmiss; /* reverse-cache misses */ }; #endif /* !_SYS_NAMEI_H_ */ diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index f12f9e4df046..8b5a31128601 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1,4 +1,4 @@ -/* $NetBSD: vnode.h,v 1.57 1998/11/18 20:24:59 thorpej Exp $ */ +/* $NetBSD: vnode.h,v 1.58 1999/03/22 17:01:55 sommerfe Exp $ */ /* * Copyright (c) 1989, 1993 @@ -229,6 +229,7 @@ extern int vttoif_tab[]; #define FSYNC_WAIT 0x0001 /* fsync: wait for completition */ #define FSYNC_DATAONLY 0x0002 /* fsync: hint: sync file data only */ +#define FSYNC_RECLAIM 0x0004 /* fsync: hint: vnode is being reclaimed */ #define HOLDRELE(vp) holdrele(vp) #define VHOLD(vp) vhold(vp) @@ -483,6 +484,7 @@ int vn_stat __P((struct vnode *vp, struct stat *sb, struct proc *p)); int vn_write __P((struct file *fp, off_t *offset, struct uio *uio, struct ucred *cred, int flags)); int vn_writechk __P((struct vnode *vp)); +int vn_isunder __P((struct vnode *dvp, struct vnode *rvp, struct proc *p)); struct vnode * checkalias __P((struct vnode *vp, dev_t nvp_rdev, struct mount *mp)); void vput __P((struct vnode *vp));