aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_cache.c
diff options
context:
space:
mode:
authorDavid Schultz <das@FreeBSD.org>2005-03-30 02:59:32 +0000
committerDavid Schultz <das@FreeBSD.org>2005-03-30 02:59:32 +0000
commitdd33f0d92f4fb5b2db188fb70298081dd3cac4a5 (patch)
tree493780a85be64fd6636349f12946a5cc5fb89290 /sys/kern/vfs_cache.c
parent76e96613b2f618440c34c41d5f5674dd94238bdf (diff)
downloadsrc-dd33f0d92f4fb5b2db188fb70298081dd3cac4a5.tar.gz
src-dd33f0d92f4fb5b2db188fb70298081dd3cac4a5.zip
Notes
Diffstat (limited to 'sys/kern/vfs_cache.c')
-rw-r--r--sys/kern/vfs_cache.c221
1 files changed, 89 insertions, 132 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 65060e6625c6..92614f702637 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -169,6 +169,8 @@ SYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchstats, CTLFLAG_RD, &nchstats,
static void cache_zap(struct namecache *ncp);
+static int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, u_int buflen);
static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
@@ -700,14 +702,6 @@ static int disablecwd;
SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0,
"Disable the getcwd syscall");
-/* Various statistics for the getcwd syscall */
-static u_long numcwdcalls; STATNODE(CTLFLAG_RD, numcwdcalls, &numcwdcalls);
-static u_long numcwdfail1; STATNODE(CTLFLAG_RD, numcwdfail1, &numcwdfail1);
-static u_long numcwdfail2; STATNODE(CTLFLAG_RD, numcwdfail2, &numcwdfail2);
-static u_long numcwdfail3; STATNODE(CTLFLAG_RD, numcwdfail3, &numcwdfail3);
-static u_long numcwdfail4; STATNODE(CTLFLAG_RD, numcwdfail4, &numcwdfail4);
-static u_long numcwdfound; STATNODE(CTLFLAG_RD, numcwdfound, &numcwdfound);
-
/* Implementation of the getcwd syscall */
int
__getcwd(td, uap)
@@ -722,94 +716,31 @@ int
kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen)
{
char *bp, *tmpbuf;
- int error, i, slash_prefixed;
struct filedesc *fdp;
- struct namecache *ncp;
- struct vnode *vp;
+ int error;
- numcwdcalls++;
if (disablecwd)
return (ENODEV);
if (buflen < 2)
return (EINVAL);
if (buflen > MAXPATHLEN)
buflen = MAXPATHLEN;
- mtx_lock(&Giant);
- error = 0;
- tmpbuf = bp = malloc(buflen, M_TEMP, M_WAITOK);
- bp += buflen - 1;
- *bp = '\0';
+
+ tmpbuf = malloc(buflen, M_TEMP, M_WAITOK);
fdp = td->td_proc->p_fd;
- slash_prefixed = 0;
+ mtx_lock(&Giant);
FILEDESC_LOCK(fdp);
- for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) {
- if (vp->v_vflag & VV_ROOT) {
- if (vp->v_mount == NULL) { /* forced unmount */
- error = EBADF;
- goto out;
- }
- vp = vp->v_mount->mnt_vnodecovered;
- continue;
- }
- if (vp->v_dd->v_id != vp->v_ddid) {
- numcwdfail1++;
- error = ENOTDIR;
- goto out;
- }
- CACHE_LOCK();
- ncp = TAILQ_FIRST(&vp->v_cache_dst);
- if (!ncp) {
- numcwdfail2++;
- CACHE_UNLOCK();
- error = ENOENT;
- goto out;
- }
- if (ncp->nc_dvp != vp->v_dd) {
- numcwdfail3++;
- CACHE_UNLOCK();
- error = EBADF;
- goto out;
- }
- for (i = ncp->nc_nlen - 1; i >= 0; i--) {
- if (bp == tmpbuf) {
- numcwdfail4++;
- CACHE_UNLOCK();
- error = ENOMEM;
- goto out;
- }
- *--bp = ncp->nc_name[i];
- }
- if (bp == tmpbuf) {
- numcwdfail4++;
- CACHE_UNLOCK();
- error = ENOMEM;
- goto out;
- }
- *--bp = '/';
- slash_prefixed = 1;
- vp = vp->v_dd;
- CACHE_UNLOCK();
- }
- if (!slash_prefixed) {
- if (bp == tmpbuf) {
- numcwdfail4++;
- error = ENOMEM;
- goto out;
- }
- *--bp = '/';
- }
- FILEDESC_UNLOCK(fdp);
- mtx_unlock(&Giant);
- numcwdfound++;
- if (bufseg == UIO_SYSSPACE)
- bcopy(bp, buf, strlen(bp) + 1);
- else
- error = copyout(bp, buf, strlen(bp) + 1);
- free(tmpbuf, M_TEMP);
- return (error);
-out:
+ error = vn_fullpath1(td, fdp->fd_cdir, fdp->fd_rdir, tmpbuf,
+ &bp, buflen);
FILEDESC_UNLOCK(fdp);
mtx_unlock(&Giant);
+
+ if (!error) {
+ if (bufseg == UIO_SYSSPACE)
+ bcopy(bp, buf, strlen(bp) + 1);
+ else
+ error = copyout(bp, buf, strlen(bp) + 1);
+ }
free(tmpbuf, M_TEMP);
return (error);
}
@@ -827,10 +758,10 @@ static int disablefullpath;
SYSCTL_INT(_debug, OID_AUTO, disablefullpath, CTLFLAG_RW, &disablefullpath, 0,
"Disable the vn_fullpath function");
+/* These count for kern___getcwd(), too. */
STATNODE(numfullpathcalls);
STATNODE(numfullpathfail1);
STATNODE(numfullpathfail2);
-STATNODE(numfullpathfail3);
STATNODE(numfullpathfail4);
STATNODE(numfullpathfound);
@@ -841,90 +772,116 @@ STATNODE(numfullpathfound);
int
vn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf)
{
- char *bp, *buf;
- int i, slash_prefixed;
+ char *buf;
struct filedesc *fdp;
- struct namecache *ncp;
- struct vnode *vp;
+ int error;
- numfullpathcalls++;
if (disablefullpath)
return (ENODEV);
if (vn == NULL)
return (EINVAL);
+
buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
- bp = buf + MAXPATHLEN - 1;
- *bp = '\0';
fdp = td->td_proc->p_fd;
- slash_prefixed = 0;
- ASSERT_VOP_LOCKED(vn, "vn_fullpath");
+ mtx_lock(&Giant);
FILEDESC_LOCK(fdp);
- for (vp = vn; vp != fdp->fd_rdir && vp != rootvnode;) {
+ error = vn_fullpath1(td, vn, fdp->fd_rdir, buf, retbuf, MAXPATHLEN);
+ FILEDESC_UNLOCK(fdp);
+ mtx_unlock(&Giant);
+
+ if (!error)
+ *freebuf = buf;
+ else
+ free(buf, M_TEMP);
+ return (error);
+}
+
+/*
+ * The magic behind kern___getcwd() and vn_fullpath().
+ */
+static int
+vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, u_int buflen)
+{
+ char *bp;
+ int error, i, slash_prefixed;
+ struct namecache *ncp;
+
+ mtx_assert(&Giant, MA_OWNED);
+
+ bp = buf + buflen - 1;
+ *bp = '\0';
+ error = 0;
+ slash_prefixed = 0;
+
+ CACHE_LOCK();
+ numfullpathcalls++;
+ if (vp->v_type != VDIR) {
+ ncp = TAILQ_FIRST(&vp->v_cache_dst);
+ if (!ncp) {
+ numfullpathfail2++;
+ CACHE_UNLOCK();
+ return (ENOENT);
+ }
+ for (i = ncp->nc_nlen - 1; i >= 0 && bp > buf; i--)
+ *--bp = ncp->nc_name[i];
+ if (bp == buf) {
+ numfullpathfail4++;
+ CACHE_UNLOCK();
+ return (ENOMEM);
+ }
+ *--bp = '/';
+ slash_prefixed = 1;
+ vp = ncp->nc_dvp;
+ }
+ while (vp != rdir && vp != rootvnode) {
if (vp->v_vflag & VV_ROOT) {
if (vp->v_mount == NULL) { /* forced unmount */
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (EBADF);
+ error = EBADF;
+ break;
}
vp = vp->v_mount->mnt_vnodecovered;
continue;
}
- if (vp != vn && vp->v_dd->v_id != vp->v_ddid) {
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
+ if (vp->v_dd->v_id != vp->v_ddid) {
numfullpathfail1++;
- return (ENOTDIR);
+ error = ENOTDIR;
+ break;
}
- CACHE_LOCK();
ncp = TAILQ_FIRST(&vp->v_cache_dst);
if (!ncp) {
numfullpathfail2++;
- CACHE_UNLOCK();
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (ENOENT);
- }
- if (vp != vn && ncp->nc_dvp != vp->v_dd) {
- numfullpathfail3++;
- CACHE_UNLOCK();
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (EBADF);
+ error = ENOENT;
+ break;
}
- for (i = ncp->nc_nlen - 1; i >= 0; i--) {
- if (bp == buf) {
- numfullpathfail4++;
- CACHE_UNLOCK();
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (ENOMEM);
- }
+ MPASS(ncp->nc_dvp == vp->v_dd);
+ for (i = ncp->nc_nlen - 1; i >= 0 && bp != buf; i--)
*--bp = ncp->nc_name[i];
- }
if (bp == buf) {
numfullpathfail4++;
- CACHE_UNLOCK();
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
- return (ENOMEM);
+ error = ENOMEM;
+ break;
}
*--bp = '/';
slash_prefixed = 1;
vp = ncp->nc_dvp;
+ }
+ if (error) {
CACHE_UNLOCK();
+ return (error);
}
if (!slash_prefixed) {
if (bp == buf) {
numfullpathfail4++;
- FILEDESC_UNLOCK(fdp);
- free(buf, M_TEMP);
+ CACHE_UNLOCK();
return (ENOMEM);
+ } else {
+ *--bp = '/';
}
- *--bp = '/';
}
- FILEDESC_UNLOCK(fdp);
numfullpathfound++;
+ CACHE_UNLOCK();
+
*retbuf = bp;
- *freebuf = buf;
return (0);
}