summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_cache.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-05-31 14:57:43 +0000
committerkib <kib@FreeBSD.org>2009-05-31 14:57:43 +0000
commit443228ae3b3ba01eab22a02b6017cb6d8af64c34 (patch)
treee967370fdcc8de8ab496321c7238fa38b602185d /sys/kern/vfs_cache.c
parent0e1f2d3b3e4e791ad8dc69b5d3edfdbc1eca9771 (diff)
downloadFreeBSD-src-443228ae3b3ba01eab22a02b6017cb6d8af64c34.zip
FreeBSD-src-443228ae3b3ba01eab22a02b6017cb6d8af64c34.tar.gz
Eliminate code duplication in vn_fullpath1() around the cache lookups
and calls to vn_vptocnp() by moving more of the common code to vn_vptocnp(). Rename vn_vptocnp() to vn_vptocnp_locked() to signify that cache is locked around the call. Do not track buffer position by both the pointer and offset, use only buflen to record the start of the free space. Export vn_vptocnp() for external consumers as a wrapper around vn_vptocnp_locked() that locks the cache and handles hold counts. Tested by: pho
Diffstat (limited to 'sys/kern/vfs_cache.c')
-rw-r--r--sys/kern/vfs_cache.c160
1 files changed, 75 insertions, 85 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 01c5e4c..cdfb308 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -206,7 +206,7 @@ SYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchstats, CTLFLAG_RD | CTLFLAG_MPSAFE,
static void cache_zap(struct namecache *ncp);
-static int vn_vptocnp(struct vnode **vp, char **bp, char *buf, u_int *buflen);
+static int vn_vptocnp_locked(struct vnode **vp, char *buf, u_int *buflen);
static int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
char *buf, char **retbuf, u_int buflen);
@@ -1036,12 +1036,55 @@ vn_fullpath_global(struct thread *td, struct vnode *vn,
return (error);
}
+int
+vn_vptocnp(struct vnode **vp, char *buf, u_int *buflen)
+{
+ int error;
+
+ CACHE_RLOCK();
+ error = vn_vptocnp_locked(vp, buf, buflen);
+ if (error == 0) {
+ /*
+ * vn_vptocnp_locked() dropped hold acquired by
+ * VOP_VPTOCNP immediately after locking the
+ * cache. Since we are going to drop the cache rlock,
+ * re-hold the result.
+ */
+ vhold(*vp);
+ CACHE_RUNLOCK();
+ }
+ return (error);
+}
+
static int
-vn_vptocnp(struct vnode **vp, char **bp, char *buf, u_int *buflen)
+vn_vptocnp_locked(struct vnode **vp, char *buf, u_int *buflen)
{
struct vnode *dvp;
+ struct namecache *ncp;
int error, vfslocked;
+ TAILQ_FOREACH(ncp, &((*vp)->v_cache_dst), nc_dst) {
+ if ((ncp->nc_flag & NCF_ISDOTDOT) == 0)
+ break;
+ }
+ if (ncp != NULL) {
+ if (*buflen < ncp->nc_nlen) {
+ CACHE_RUNLOCK();
+ numfullpathfail4++;
+ error = ENOMEM;
+ SDT_PROBE(vfs, namecache, fullpath, return, error,
+ startvp, NULL, 0, 0);
+ return (error);
+ }
+ *buflen -= ncp->nc_nlen;
+ memcpy(buf + *buflen, ncp->nc_name, ncp->nc_nlen);
+ SDT_PROBE(vfs, namecache, fullpath, hit, ncp->nc_dvp,
+ ncp->nc_name, vp, 0, 0);
+ *vp = ncp->nc_dvp;
+ return (0);
+ }
+ SDT_PROBE(vfs, namecache, fullpath, miss, vp, 0, 0, 0, 0);
+
vhold(*vp);
CACHE_RUNLOCK();
vfslocked = VFS_LOCK_GIANT((*vp)->v_mount);
@@ -1052,16 +1095,21 @@ vn_vptocnp(struct vnode **vp, char **bp, char *buf, u_int *buflen)
VFS_UNLOCK_GIANT(vfslocked);
if (error) {
numfullpathfail2++;
+ SDT_PROBE(vfs, namecache, fullpath, return, error, startvp,
+ NULL, 0, 0);
return (error);
}
- *bp = buf + *buflen;
+
*vp = dvp;
CACHE_RLOCK();
if ((*vp)->v_iflag & VI_DOOMED) {
/* forced unmount */
CACHE_RUNLOCK();
vdrop(*vp);
- return (ENOENT);
+ error = ENOENT;
+ SDT_PROBE(vfs, namecache, fullpath, return, error, startvp,
+ NULL, 0, 0);
+ return (error);
}
vdrop(*vp);
@@ -1075,59 +1123,26 @@ 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;
+ int error, slash_prefixed;
#ifdef KDTRACE_HOOKS
struct vnode *startvp = vp;
#endif
buflen--;
- bp = buf + buflen;
- *bp = '\0';
+ buf[buflen] = '\0';
error = 0;
slash_prefixed = 0;
SDT_PROBE(vfs, namecache, fullpath, entry, vp, 0, 0, 0, 0);
- CACHE_RLOCK();
numfullpathcalls++;
+ CACHE_RLOCK();
if (vp->v_type != VDIR) {
- ncp = TAILQ_FIRST(&vp->v_cache_dst);
- if (ncp != NULL) {
- buflen -= ncp->nc_nlen;
- for (i = ncp->nc_nlen - 1; i >= 0 && bp != buf; i--)
- *--bp = ncp->nc_name[i];
- if (bp == buf) {
- numfullpathfail4++;
- CACHE_RUNLOCK();
- error = ENOMEM;
- SDT_PROBE(vfs, namecache, fullpath, return,
- error, startvp, NULL, 0, 0);
- return (error);
- }
- SDT_PROBE(vfs, namecache, fullpath, hit, ncp->nc_dvp,
- ncp->nc_name, vp, 0, 0);
- vp = ncp->nc_dvp;
- } else {
- SDT_PROBE(vfs, namecache, fullpath, miss, vp, 0, 0,
- 0, 0);
- error = vn_vptocnp(&vp, &bp, buf, &buflen);
- if (error) {
- SDT_PROBE(vfs, namecache, fullpath, return,
- error, startvp, NULL, 0, 0);
- return (error);
- }
- }
- if (buflen <= 0) {
- numfullpathfail4++;
- CACHE_RUNLOCK();
- error = ENOMEM;
- SDT_PROBE(vfs, namecache, fullpath, return, error,
- startvp, NULL, 0, 0);
+ error = vn_vptocnp_locked(&vp, buf, &buflen);
+ if (error)
return (error);
- }
- *--bp = '/';
- buflen--;
+ if (buflen == 0)
+ return (ENOMEM);
+ buf[--buflen] = '/';
slash_prefixed = 1;
}
while (vp != rdir && vp != rootvnode) {
@@ -1141,64 +1156,39 @@ vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
continue;
}
if (vp->v_type != VDIR) {
- numfullpathfail1++;
CACHE_RUNLOCK();
+ numfullpathfail1++;
error = ENOTDIR;
break;
}
- TAILQ_FOREACH(ncp, &vp->v_cache_dst, nc_dst)
- if ((ncp->nc_flag & NCF_ISDOTDOT) == 0)
- break;
- if (ncp != NULL) {
- buflen -= ncp->nc_nlen;
- for (i = ncp->nc_nlen - 1; i >= 0 && bp != buf; i--)
- *--bp = ncp->nc_name[i];
- if (bp == buf) {
- numfullpathfail4++;
- CACHE_RUNLOCK();
- error = ENOMEM;
- break;
- }
- SDT_PROBE(vfs, namecache, fullpath, hit, ncp->nc_dvp,
- ncp->nc_name, vp, 0, 0);
- vp = ncp->nc_dvp;
- } else {
- SDT_PROBE(vfs, namecache, fullpath, miss, vp, 0, 0,
- 0, 0);
- error = vn_vptocnp(&vp, &bp, buf, &buflen);
- if (error)
- break;
- }
- if (buflen <= 0) {
- numfullpathfail4++;
- CACHE_RUNLOCK();
+ error = vn_vptocnp_locked(&vp, buf, &buflen);
+ if (error)
+ break;
+ if (buflen == 0) {
error = ENOMEM;
break;
}
- *--bp = '/';
- buflen--;
+ buf[--buflen] = '/';
slash_prefixed = 1;
}
- if (error) {
- SDT_PROBE(vfs, namecache, fullpath, return, error, startvp,
- NULL, 0, 0);
+ if (error)
return (error);
- }
if (!slash_prefixed) {
- if (bp == buf) {
- numfullpathfail4++;
+ if (buflen == 0) {
CACHE_RUNLOCK();
+ numfullpathfail4++;
SDT_PROBE(vfs, namecache, fullpath, return, 0,
- startvp, bp, 0, 0);
+ startvp, fullpath, 0, 0);
return (ENOMEM);
- } else
- *--bp = '/';
+ }
+ buf[--buflen] = '/';
}
numfullpathfound++;
CACHE_RUNLOCK();
- SDT_PROBE(vfs, namecache, fullpath, return, 0, startvp, bp, 0, 0);
- *retbuf = bp;
+ SDT_PROBE(vfs, namecache, fullpath, return, 0, startvp, buf + *buflen,
+ 0, 0);
+ *retbuf = buf + buflen;
return (0);
}
OpenPOWER on IntegriCloud