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
This commit is contained in:
marcus 2008-12-12 00:57:38 +00:00
parent 509ce401ea
commit 91e684d7f9
3 changed files with 95 additions and 24 deletions

View File

@ -169,6 +169,7 @@ SYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchstats, CTLFLAG_RD, &nchstats,
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, struct vnode *vn,
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 vnode *vp, struct vnode *rdir,
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 vnode *vp, struct vnode *rdir,
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++;

View File

@ -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,
};
@ -137,6 +138,13 @@ vop_einval(struct vop_generic_args *ap)
return (EINVAL);
}
int
vop_enoent(struct vop_generic_args *ap)
{
return (ENOENT);
}
int
vop_null(struct vop_generic_args *ap)
{

View File

@ -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;
};