summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/vfs_cache.c160
-rw-r--r--sys/sys/vnode.h1
2 files changed, 76 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);
}
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index af1723f..3feae69 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -598,6 +598,7 @@ int insmntque1(struct vnode *vp, struct mount *mp,
int insmntque(struct vnode *vp, struct mount *mp);
u_quad_t init_va_filerev(void);
int speedup_syncer(void);
+int vn_vptocnp(struct vnode **vp, char *buf, u_int *buflen);
#define textvp_fullpath(p, rb, rfb) \
vn_fullpath(FIRST_THREAD_IN_PROC(p), (p)->p_textvp, rb, rfb)
int vn_fullpath(struct thread *td, struct vnode *vn,
OpenPOWER on IntegriCloud