git: 3b6792d28ac1 - main - vfs: factor symlink traversal out of namei
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 24 Mar 2022 13:11:49 UTC
The branch main has been updated by mjg:
URL: https://cgit.FreeBSD.org/src/commit/?id=3b6792d28ac16b38c6b56d1385b31b9c49a45723
commit 3b6792d28ac16b38c6b56d1385b31b9c49a45723
Author: Mateusz Guzik <mjg@FreeBSD.org>
AuthorDate: 2022-03-24 12:57:30 +0000
Commit: Mateusz Guzik <mjg@FreeBSD.org>
CommitDate: 2022-03-24 13:11:22 +0000
vfs: factor symlink traversal out of namei
The intent down the road is to eliminate the loop to begin with,
pushing traversal down to vfs_lookup, all while not allocating the
extra buffer.
---
sys/kern/vfs_lookup.c | 125 ++++++++++++++++++++++++++++----------------------
1 file changed, 71 insertions(+), 54 deletions(-)
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 29db916382b1..8b4ceecce462 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -511,6 +511,74 @@ errout:
return (error);
}
+static int __noinline
+namei_follow_link(struct nameidata *ndp)
+{
+ char *cp;
+ struct iovec aiov;
+ struct uio auio;
+ struct componentname *cnp;
+ struct thread *td;
+ int error, linklen;
+
+ error = 0;
+ cnp = &ndp->ni_cnd;
+ td = curthread;
+
+ if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
+ error = ELOOP;
+ goto out;
+ }
+#ifdef MAC
+ if ((cnp->cn_flags & NOMACCHECK) == 0) {
+ error = mac_vnode_check_readlink(td->td_ucred, ndp->ni_vp);
+ if (error != 0)
+ goto out;
+ }
+#endif
+ if (ndp->ni_pathlen > 1)
+ cp = uma_zalloc(namei_zone, M_WAITOK);
+ 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_segflg = UIO_SYSSPACE;
+ auio.uio_td = td;
+ auio.uio_resid = MAXPATHLEN;
+ error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
+ if (error != 0) {
+ if (ndp->ni_pathlen > 1)
+ uma_zfree(namei_zone, cp);
+ goto out;
+ }
+ linklen = MAXPATHLEN - auio.uio_resid;
+ if (linklen == 0) {
+ if (ndp->ni_pathlen > 1)
+ uma_zfree(namei_zone, cp);
+ error = ENOENT;
+ goto out;
+ }
+ if (linklen + ndp->ni_pathlen > MAXPATHLEN) {
+ if (ndp->ni_pathlen > 1)
+ uma_zfree(namei_zone, cp);
+ error = ENAMETOOLONG;
+ goto out;
+ }
+ if (ndp->ni_pathlen > 1) {
+ bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
+ uma_zfree(namei_zone, cnp->cn_pnbuf);
+ cnp->cn_pnbuf = cp;
+ } else
+ cnp->cn_pnbuf[linklen] = '\0';
+ ndp->ni_pathlen += linklen;
+out:
+ return (error);
+}
+
/*
* Convert a pathname into a pointer to a locked vnode.
*
@@ -534,14 +602,11 @@ errout:
int
namei(struct nameidata *ndp)
{
- char *cp; /* pointer into pathname argument */
struct vnode *dp; /* the directory we are searching */
- struct iovec aiov; /* uio for reading symbolic links */
struct componentname *cnp;
struct thread *td;
struct pwd *pwd;
- struct uio auio;
- int error, linklen;
+ int error;
enum cache_fpl_status status;
cnp = &ndp->ni_cnd;
@@ -675,57 +740,9 @@ namei(struct nameidata *ndp)
NDVALIDATE(ndp);
return (error);
}
- if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
- error = ELOOP;
- break;
- }
-#ifdef MAC
- if ((cnp->cn_flags & NOMACCHECK) == 0) {
- error = mac_vnode_check_readlink(td->td_ucred,
- ndp->ni_vp);
- if (error != 0)
- break;
- }
-#endif
- if (ndp->ni_pathlen > 1)
- cp = uma_zalloc(namei_zone, M_WAITOK);
- 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_segflg = UIO_SYSSPACE;
- auio.uio_td = td;
- auio.uio_resid = MAXPATHLEN;
- error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
- if (error != 0) {
- if (ndp->ni_pathlen > 1)
- uma_zfree(namei_zone, cp);
- break;
- }
- linklen = MAXPATHLEN - auio.uio_resid;
- if (linklen == 0) {
- if (ndp->ni_pathlen > 1)
- uma_zfree(namei_zone, cp);
- error = ENOENT;
- break;
- }
- if (linklen + ndp->ni_pathlen > MAXPATHLEN) {
- if (ndp->ni_pathlen > 1)
- uma_zfree(namei_zone, cp);
- error = ENAMETOOLONG;
+ error = namei_follow_link(ndp);
+ if (error != 0)
break;
- }
- if (ndp->ni_pathlen > 1) {
- bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
- uma_zfree(namei_zone, 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;
/*