mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-17 10:26:15 +00:00
Merge kern___cwd() and vn_fullpath(), which were virtually identical,
except for places where people forget to update one of them. We now collect only one set of stats for both of these routines. Other changes in this commit include: - Start acquiring Giant again in vn_fullpath(), since it is required when crossing a mount point. - Expand the scope of the cache lock to avoid dropping it and picking it up again for every pathname component. This also makes it trivial to avoid races in stats collection. - Assert that nc_dvp == v_dd for directories instead of returning an error to userland when this is not true. AFAIK, it should always be true when v_dd is non-null. - For vn_fullpath(), handle the first (non-directory) vnode separately. Glanced at by: jeff, phk
This commit is contained in:
parent
76e96613b2
commit
dd33f0d92f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=144318
@ -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;) {
|
||||
if (vp->v_vflag & VV_ROOT) {
|
||||
if (vp->v_mount == NULL) { /* forced unmount */
|
||||
FILEDESC_UNLOCK(fdp);
|
||||
free(buf, M_TEMP);
|
||||
return (EBADF);
|
||||
}
|
||||
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);
|
||||
numfullpathfail1++;
|
||||
return (ENOTDIR);
|
||||
}
|
||||
CACHE_LOCK();
|
||||
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();
|
||||
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);
|
||||
}
|
||||
for (i = ncp->nc_nlen - 1; i >= 0; i--) {
|
||||
if (bp == buf) {
|
||||
numfullpathfail4++;
|
||||
CACHE_UNLOCK();
|
||||
FILEDESC_UNLOCK(fdp);
|
||||
free(buf, M_TEMP);
|
||||
return (ENOMEM);
|
||||
}
|
||||
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);
|
||||
}
|
||||
*--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 */
|
||||
error = EBADF;
|
||||
break;
|
||||
}
|
||||
vp = vp->v_mount->mnt_vnodecovered;
|
||||
continue;
|
||||
}
|
||||
if (vp->v_dd->v_id != vp->v_ddid) {
|
||||
numfullpathfail1++;
|
||||
error = ENOTDIR;
|
||||
break;
|
||||
}
|
||||
ncp = TAILQ_FIRST(&vp->v_cache_dst);
|
||||
if (!ncp) {
|
||||
numfullpathfail2++;
|
||||
error = ENOENT;
|
||||
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) {
|
||||
numfullpathfail4++;
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user