Move a big wodge of symlink-following code from nfsd to inside

lookup_for_nfsd(). This code is, or at least should be, the same as
the regular symlink-following code plus an extra flag nfsd needs.

The two lots of code can/will be merged in the future.
This commit is contained in:
dholland 2009-09-27 17:23:53 +00:00
parent a3c0999baa
commit 8d36057243
4 changed files with 155 additions and 114 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: namei.9,v 1.22 2009/09/27 17:19:07 dholland Exp $
.\" $NetBSD: namei.9,v 1.23 2009/09/27 17:23:53 dholland Exp $
.\"
.\" Copyright (c) 2001, 2005, 2006 The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -46,7 +46,8 @@
.Ft int
.Fn namei "struct nameidata *ndp"
.Ft int
.Fn lookup_for_nfsd "struct nameidata *ndp"
.Fn lookup_for_nfsd "struct nameidata *ndp" "struct vnode *startdir" \
"int neverfollow"
.Ft int
.Fn lookup_for_nfsd_index "struct nameidata *ndp"
.Ft int
@ -288,11 +289,19 @@ As of this writing the internal function
is comparable to the historic
.Fn lookup
but this code is slated for refactoring.
.It Fn lookup_for_nfsd "ndp"
.It Fn lookup_for_nfsd "ndp" "startdir" "neverfollow"
This is a private entry point into
.Nm
used by the NFS server code.
Its semantics are similar to the historic
It looks up a path starting from
.Fa startdir .
If
.Fa neverfollow
is set,
.Em any
symbolic link (not just at the end of the path) will cause an error.
Otherwise, it follows symlinks normally.
Its semantics are similar to a symlink-following loop around the historic
.Fn lookup
function described above.
It should not be used by new code.
@ -304,9 +313,6 @@ Its semantics are similar to the historic
.Fn lookup
function described above.
It should not be used by new code.
(For now it differs from the preceding private entry point in that it
has a different call site with a different context and different
custom initialization of what ought to be private namei state.)
.It Fn relookup "dvp" "vpp" "cnp"
Reacquire a path name component is a directory.
This is a quicker way to lookup a pathname component when the parent

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_lookup.c,v 1.119 2009/09/27 17:19:07 dholland Exp $ */
/* $NetBSD: vfs_lookup.c,v 1.120 2009/09/27 17:23:54 dholland Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.119 2009/09/27 17:19:07 dholland Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.120 2009/09/27 17:23:54 dholland Exp $");
#include "opt_magiclinks.h"
@ -1158,14 +1158,144 @@ bad:
*/
int
lookup_for_nfsd(struct nameidata *ndp)
lookup_for_nfsd(struct nameidata *ndp, struct vnode *dp, int neverfollow)
{
struct namei_state state;
int error;
struct iovec aiov;
struct uio auio;
int linklen;
char *cp;
/* For now at least we don't have to frob the state */
namei_init(&state, ndp);
/*
* BEGIN wodge of code from nfsd
*/
VREF(dp);
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
for (;;) {
state.cnp->cn_nameptr = state.cnp->cn_pnbuf;
state.ndp->ni_startdir = dp;
/*
* END wodge of code from nfsd
*/
error = do_lookup(&state);
if (error) {
/* BEGIN from nfsd */
if (ndp->ni_dvp) {
vput(ndp->ni_dvp);
}
PNBUF_PUT(state.cnp->cn_pnbuf);
/* END from nfsd */
namei_cleanup(&state);
return error;
}
/*
* BEGIN wodge of code from nfsd
*/
/*
* Check for encountering a symbolic link
*/
if ((state.cnp->cn_flags & ISSYMLINK) == 0) {
if ((state.cnp->cn_flags & LOCKPARENT) == 0 && state.ndp->ni_dvp) {
if (state.ndp->ni_dvp == state.ndp->ni_vp) {
vrele(state.ndp->ni_dvp);
} else {
vput(state.ndp->ni_dvp);
}
}
if (state.cnp->cn_flags & (SAVENAME | SAVESTART)) {
state.cnp->cn_flags |= HASBUF;
} else {
PNBUF_PUT(state.cnp->cn_pnbuf);
#if defined(DIAGNOSTIC)
state.cnp->cn_pnbuf = NULL;
#endif /* defined(DIAGNOSTIC) */
}
return (0);
} else {
if (neverfollow) {
error = EINVAL;
goto out;
}
if (state.ndp->ni_loopcnt++ >= MAXSYMLINKS) {
error = ELOOP;
goto out;
}
if (state.ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
error = VOP_ACCESS(ndp->ni_vp, VEXEC, state.cnp->cn_cred);
if (error != 0)
goto out;
}
if (state.ndp->ni_pathlen > 1)
cp = PNBUF_GET();
else
cp = state.cnp->cn_pnbuf;
aiov.iov_base = cp;
aiov.iov_len = MAXPATHLEN;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = 0;
auio.uio_rw = UIO_READ;
auio.uio_resid = MAXPATHLEN;
UIO_SETUP_SYSSPACE(&auio);
error = VOP_READLINK(ndp->ni_vp, &auio, state.cnp->cn_cred);
if (error) {
badlink:
if (ndp->ni_pathlen > 1)
PNBUF_PUT(cp);
goto out;
}
linklen = MAXPATHLEN - auio.uio_resid;
if (linklen == 0) {
error = ENOENT;
goto badlink;
}
if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
error = ENAMETOOLONG;
goto badlink;
}
if (ndp->ni_pathlen > 1) {
memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
PNBUF_PUT(state.cnp->cn_pnbuf);
state.cnp->cn_pnbuf = cp;
} else
state.cnp->cn_pnbuf[linklen] = '\0';
state.ndp->ni_pathlen += linklen;
vput(state.ndp->ni_vp);
dp = state.ndp->ni_dvp;
/*
* Check if root directory should replace current directory.
*/
if (state.cnp->cn_pnbuf[0] == '/') {
vput(dp);
dp = ndp->ni_rootdir;
VREF(dp);
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
}
}
}
out:
vput(state.ndp->ni_vp);
vput(state.ndp->ni_dvp);
state.ndp->ni_vp = NULL;
PNBUF_PUT(state.cnp->cn_pnbuf);
/*
* END wodge of code from nfsd
*/
namei_cleanup(&state);
return error;

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_srvsubs.c,v 1.4 2009/09/27 17:19:07 dholland Exp $ */
/* $NetBSD: nfs_srvsubs.c,v 1.5 2009/09/27 17:23:54 dholland Exp $ */
/*
* Copyright (c) 1989, 1993
@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nfs_srvsubs.c,v 1.4 2009/09/27 17:19:07 dholland Exp $");
__KERNEL_RCSID(0, "$NetBSD: nfs_srvsubs.c,v 1.5 2009/09/27 17:23:54 dholland Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@ -121,10 +121,9 @@ nfs_namei(struct nameidata *ndp, nfsrvfh_t *nsfh, uint32_t len, struct nfssvc_so
int i, rem;
struct mbuf *md;
char *fromcp, *tocp, *cp;
struct iovec aiov;
struct uio auio;
struct vnode *dp;
int error, rdonly, linklen;
int error, rdonly;
int neverfollow;
struct componentname *cnp = &ndp->ni_cnd;
*retdirp = NULL;
@ -254,111 +253,17 @@ nfs_namei(struct nameidata *ndp, nfsrvfh_t *nsfh, uint32_t len, struct nfssvc_so
cnp->cn_flags |= NOCROSSMOUNT;
}
VREF(dp);
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
for (;;) {
cnp->cn_nameptr = cnp->cn_pnbuf;
ndp->ni_startdir = dp;
neverfollow = !pubflag;
/*
* And call lookup() to do the real work
*/
error = lookup_for_nfsd(ndp);
error = lookup_for_nfsd(ndp, dp, neverfollow);
if (error) {
if (ndp->ni_dvp) {
vput(ndp->ni_dvp);
}
PNBUF_PUT(cnp->cn_pnbuf);
return (error);
}
return 0;
/*
* Check for encountering a symbolic link
*/
if ((cnp->cn_flags & ISSYMLINK) == 0) {
if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
if (ndp->ni_dvp == ndp->ni_vp) {
vrele(ndp->ni_dvp);
} else {
vput(ndp->ni_dvp);
}
}
if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
cnp->cn_flags |= HASBUF;
} else {
PNBUF_PUT(cnp->cn_pnbuf);
#if defined(DIAGNOSTIC)
cnp->cn_pnbuf = NULL;
#endif /* defined(DIAGNOSTIC) */
}
return (0);
} else {
if (!pubflag) {
error = EINVAL;
break;
}
if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
error = ELOOP;
break;
}
if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
if (error != 0)
break;
}
if (ndp->ni_pathlen > 1)
cp = PNBUF_GET();
else
cp = cnp->cn_pnbuf;
aiov.iov_base = cp;
aiov.iov_len = MAXPATHLEN;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = 0;
auio.uio_rw = UIO_READ;
auio.uio_resid = MAXPATHLEN;
UIO_SETUP_SYSSPACE(&auio);
error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
if (error) {
badlink:
if (ndp->ni_pathlen > 1)
PNBUF_PUT(cp);
break;
}
linklen = MAXPATHLEN - auio.uio_resid;
if (linklen == 0) {
error = ENOENT;
goto badlink;
}
if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
error = ENAMETOOLONG;
goto badlink;
}
if (ndp->ni_pathlen > 1) {
memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
PNBUF_PUT(cnp->cn_pnbuf);
cnp->cn_pnbuf = cp;
} else
cnp->cn_pnbuf[linklen] = '\0';
ndp->ni_pathlen += linklen;
vput(ndp->ni_vp);
dp = ndp->ni_dvp;
/*
* Check if root directory should replace current directory.
*/
if (cnp->cn_pnbuf[0] == '/') {
vput(dp);
dp = ndp->ni_rootdir;
VREF(dp);
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
}
}
}
vput(ndp->ni_dvp);
vput(ndp->ni_vp);
ndp->ni_vp = NULL;
out:
PNBUF_PUT(cnp->cn_pnbuf);
return (error);

View File

@ -1,4 +1,4 @@
/* $NetBSD: namei.src,v 1.12 2009/09/27 17:19:07 dholland Exp $ */
/* $NetBSD: namei.src,v 1.13 2009/09/27 17:23:54 dholland Exp $ */
/*
* Copyright (c) 1985, 1989, 1991, 1993
@ -228,7 +228,7 @@ int namei_simple_user(const char *, namei_simple_flags_t, struct vnode **);
int namei(struct nameidata *);
uint32_t namei_hash(const char *, const char **);
int lookup_for_nfsd(struct nameidata *);
int lookup_for_nfsd(struct nameidata *, struct vnode *, int neverfollow);
int lookup_for_nfsd_index(struct nameidata *);
int relookup(struct vnode *, struct vnode **, struct componentname *);
void cache_purge1(struct vnode *, const struct componentname *, int);