svn commit: r185956 - head/sys/kern
Joe Marcus Clarke
marcus at FreeBSD.org
Thu Dec 11 16:57:39 PST 2008
Author: marcus (doc,ports committer)
Date: Fri Dec 12 00:57:38 2008
New Revision: 185956
URL: http://svn.freebsd.org/changeset/base/185956
Log:
Add a new VOP, VOP_VPTOCNP, which translates a vnode to its component name
on a best-effort basis. Teach vn_fullpath to use this new VOP if a
regular VFS cache lookup fails. This VOP is designed to supplement the
VFS cache to provide a better chance that a vnode-to-name lookup will
succeed.
Currently, an implementation for devfs is being committed. The default
implementation is to return ENOENT.
A big thanks to kib for the mentorship on this, and to pho for running it
through his stress test suite.
Reviewed by: arch
Approved by: kib
Modified:
head/sys/kern/vfs_cache.c
head/sys/kern/vfs_default.c
head/sys/kern/vnode_if.src
Modified: head/sys/kern/vfs_cache.c
==============================================================================
--- head/sys/kern/vfs_cache.c Fri Dec 12 00:56:00 2008 (r185955)
+++ head/sys/kern/vfs_cache.c Fri Dec 12 00:57:38 2008 (r185956)
@@ -169,6 +169,7 @@ SYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchs
static void cache_zap(struct namecache *ncp);
+static int vn_vptocnp(struct vnode **vp, char **bp, 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);
@@ -840,6 +841,38 @@ vn_fullpath_global(struct thread *td, st
return (error);
}
+static int
+vn_vptocnp(struct vnode **vp, char **bp, char *buf, u_int *buflen)
+{
+ struct vnode *dvp;
+ int error, vfslocked;
+
+ vhold(*vp);
+ CACHE_UNLOCK();
+ vfslocked = VFS_LOCK_GIANT((*vp)->v_mount);
+ vn_lock(*vp, LK_SHARED | LK_RETRY);
+ vdrop(*vp);
+ error = VOP_VPTOCNP(*vp, &dvp, buf, buflen);
+ VOP_UNLOCK(*vp, 0);
+ VFS_UNLOCK_GIANT(vfslocked);
+ if (error) {
+ numfullpathfail2++;
+ return (error);
+ }
+ *bp = buf + *buflen;
+ *vp = dvp;
+ CACHE_LOCK();
+ if ((*vp)->v_iflag & VI_DOOMED) {
+ /* forced unmount */
+ CACHE_UNLOCK();
+ vdrop(*vp);
+ return (ENOENT);
+ }
+ vdrop(*vp);
+
+ return (0);
+}
+
/*
* The magic behind kern___getcwd() and vn_fullpath().
*/
@@ -851,7 +884,8 @@ vn_fullpath1(struct thread *td, struct v
int error, i, slash_prefixed;
struct namecache *ncp;
- bp = buf + buflen - 1;
+ buflen--;
+ bp = buf + buflen;
*bp = '\0';
error = 0;
slash_prefixed = 0;
@@ -860,58 +894,77 @@ vn_fullpath1(struct thread *td, struct v
numfullpathcalls++;
if (vp->v_type != VDIR) {
ncp = TAILQ_FIRST(&vp->v_cache_dst);
- if (!ncp) {
- numfullpathfail2++;
- CACHE_UNLOCK();
- return (ENOENT);
+ if (ncp != NULL) {
+ for (i = ncp->nc_nlen - 1; i >= 0 && bp > buf; i--)
+ *--bp = ncp->nc_name[i];
+ if (bp == buf) {
+ numfullpathfail4++;
+ CACHE_UNLOCK();
+ return (ENOMEM);
+ }
+ vp = ncp->nc_dvp;
+ } else {
+ error = vn_vptocnp(&vp, &bp, buf, &buflen);
+ if (error) {
+ return (error);
+ }
}
- for (i = ncp->nc_nlen - 1; i >= 0 && bp > buf; i--)
- *--bp = ncp->nc_name[i];
- if (bp == buf) {
+ *--bp = '/';
+ buflen--;
+ if (buflen < 0) {
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_iflag & VI_DOOMED) { /* forced unmount */
+ CACHE_UNLOCK();
error = EBADF;
break;
}
vp = vp->v_mount->mnt_vnodecovered;
continue;
}
- if (vp->v_dd == NULL) {
+ if (vp->v_type != VDIR) {
numfullpathfail1++;
+ CACHE_UNLOCK();
error = ENOTDIR;
break;
}
ncp = TAILQ_FIRST(&vp->v_cache_dst);
- if (!ncp) {
- numfullpathfail2++;
- error = ENOENT;
- break;
+ if (ncp != NULL) {
+ MPASS(ncp->nc_dvp == vp->v_dd);
+ buflen -= ncp->nc_nlen - 1;
+ for (i = ncp->nc_nlen - 1; i >= 0 && bp != buf; i--)
+ *--bp = ncp->nc_name[i];
+ if (bp == buf) {
+ numfullpathfail4++;
+ CACHE_UNLOCK();
+ error = ENOMEM;
+ break;
+ }
+ vp = ncp->nc_dvp;
+ } else {
+ error = vn_vptocnp(&vp, &bp, buf, &buflen);
+ if (error) {
+ break;
+ }
}
- 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) {
+ *--bp = '/';
+ buflen--;
+ if (buflen < 0) {
numfullpathfail4++;
+ CACHE_UNLOCK();
error = ENOMEM;
break;
}
- *--bp = '/';
slash_prefixed = 1;
- vp = ncp->nc_dvp;
}
- if (error) {
- CACHE_UNLOCK();
+ if (error)
return (error);
- }
if (!slash_prefixed) {
if (bp == buf) {
numfullpathfail4++;
Modified: head/sys/kern/vfs_default.c
==============================================================================
--- head/sys/kern/vfs_default.c Fri Dec 12 00:56:00 2008 (r185955)
+++ head/sys/kern/vfs_default.c Fri Dec 12 00:57:38 2008 (r185956)
@@ -98,6 +98,7 @@ struct vop_vector default_vnodeops = {
.vop_revoke = VOP_PANIC,
.vop_strategy = vop_nostrategy,
.vop_unlock = vop_stdunlock,
+ .vop_vptocnp = VOP_ENOENT,
.vop_vptofh = vop_stdvptofh,
};
@@ -138,6 +139,13 @@ vop_einval(struct vop_generic_args *ap)
}
int
+vop_enoent(struct vop_generic_args *ap)
+{
+
+ return (ENOENT);
+}
+
+int
vop_null(struct vop_generic_args *ap)
{
Modified: head/sys/kern/vnode_if.src
==============================================================================
--- head/sys/kern/vnode_if.src Fri Dec 12 00:56:00 2008 (r185955)
+++ head/sys/kern/vnode_if.src Fri Dec 12 00:57:38 2008 (r185956)
@@ -595,3 +595,13 @@ vop_vptofh {
IN struct vnode *vp;
IN struct fid *fhp;
};
+
+%% vptocnp vp L L L
+%% vptocnp vpp - U -
+
+vop_vptocnp {
+ IN struct vnode *vp;
+ OUT struct vnode **vpp;
+ INOUT char *buf;
+ INOUT int *buflen;
+};
More information about the svn-src-head
mailing list