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; /*