37 #include <sys/cdefs.h>
40 #include "opt_capsicum.h"
41 #include "opt_kdtrace.h"
42 #include "opt_ktrace.h"
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/capability.h>
48 #include <sys/fcntl.h>
51 #include <sys/mutex.h>
52 #include <sys/namei.h>
53 #include <sys/vnode.h>
54 #include <sys/mount.h>
55 #include <sys/filedesc.h>
58 #include <sys/syscallsubr.h>
59 #include <sys/sysctl.h>
61 #include <sys/ktrace.h>
64 #include <security/audit/audit.h>
65 #include <security/mac/mac_framework.h>
69 #define NAMEI_DIAGNOSTIC 1
70 #undef NAMEI_DIAGNOSTIC
90 namei_zone = uma_zcreate(
"NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL,
101 "Enables/Disables shared locks for path name translation");
129 cnp->cn_pnbuf = NULL;
130 cnp->cn_nameptr = NULL;
137 struct filedesc *fdp;
143 struct componentname *cnp = &ndp->ni_cnd;
144 struct thread *td = cnp->cn_thread;
145 struct proc *p = td->td_proc;
148 KASSERT((cnp->cn_flags & MPSAFE) != 0 || mtx_owned(&
Giant) != 0,
149 (
"NOT MPSAFE and Giant not held"));
150 ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred;
151 KASSERT(cnp->cn_cred && p, (
"namei: bad cred/proc"));
152 KASSERT((cnp->cn_nameiop & (~OPMASK)) == 0,
153 (
"namei: nameiop contaminated with flags"));
154 KASSERT((cnp->cn_flags & OPMASK) == 0,
155 (
"namei: flags contaminated with nameiops"));
157 cnp->cn_flags &= ~LOCKSHARED;
161 cnp->cn_flags &= ~TRAILINGSLASH;
167 if ((cnp->cn_flags & HASBUF) == 0)
168 cnp->cn_pnbuf = uma_zalloc(
namei_zone, M_WAITOK);
169 if (ndp->ni_segflg == UIO_SYSSPACE)
170 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
171 MAXPATHLEN, (
size_t *)&ndp->ni_pathlen);
173 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
174 MAXPATHLEN, (
size_t *)&ndp->ni_pathlen);
179 if (!error && *cnp->cn_pnbuf ==
'\0')
182 #ifdef CAPABILITY_MODE
188 if (error == 0 && IN_CAPABILITY_MODE(td)) {
189 ndp->ni_strictrelative = 1;
190 if (ndp->ni_dirfd == AT_FDCWD)
201 if (KTRPOINT(td, KTR_NAMEI)) {
202 KASSERT(cnp->cn_thread == curthread,
203 (
"namei not using curthread"));
204 ktrnamei(cnp->cn_pnbuf);
211 ndp->ni_rootdir = fdp->fd_rdir;
212 ndp->ni_topdir = fdp->fd_jdir;
217 if (cnp->cn_flags & AUDITVNODE1)
218 AUDIT_ARG_UPATH1(td, ndp->ni_dirfd, cnp->cn_pnbuf);
219 if (cnp->cn_flags & AUDITVNODE2)
220 AUDIT_ARG_UPATH2(td, ndp->ni_dirfd, cnp->cn_pnbuf);
223 if (cnp->cn_pnbuf[0] !=
'/') {
224 if (ndp->ni_startdir != NULL) {
225 dp = ndp->ni_startdir;
227 }
else if (ndp->ni_dirfd != AT_FDCWD) {
228 if (cnp->cn_flags & AUDITVNODE1)
229 AUDIT_ARG_ATFD1(ndp->ni_dirfd);
230 if (cnp->cn_flags & AUDITVNODE2)
231 AUDIT_ARG_ATFD2(ndp->ni_dirfd);
233 ndp->ni_rightsneeded | CAP_LOOKUP,
234 &(ndp->ni_baserights), &dp);
243 if (ndp->ni_baserights != CAP_MASK_VALID)
244 ndp->ni_strictrelative = 1;
247 if (error != 0 || dp != NULL) {
248 FILEDESC_SUNLOCK(fdp);
249 if (error == 0 && dp->v_type != VDIR) {
250 vfslocked = VFS_LOCK_GIANT(dp->v_mount);
252 VFS_UNLOCK_GIANT(vfslocked);
264 FILEDESC_SUNLOCK(fdp);
265 if (ndp->ni_startdir != NULL) {
266 vfslocked = VFS_LOCK_GIANT(ndp->ni_startdir->v_mount);
267 vrele(ndp->ni_startdir);
268 VFS_UNLOCK_GIANT(vfslocked);
271 SDT_PROBE3(vfs,
namei,
lookup, entry, dp, cnp->cn_pnbuf,
273 vfslocked = VFS_LOCK_GIANT(dp->v_mount);
279 cnp->cn_nameptr = cnp->cn_pnbuf;
280 if (*(cnp->cn_nameptr) ==
'/') {
282 VFS_UNLOCK_GIANT(vfslocked);
283 if (ndp->ni_strictrelative != 0) {
285 return (ENOTCAPABLE);
287 while (*(cnp->cn_nameptr) ==
'/') {
291 dp = ndp->ni_rootdir;
292 vfslocked = VFS_LOCK_GIANT(dp->v_mount);
296 ndp->ni_cnd.cn_flags |= GIANTHELD;
297 ndp->ni_startdir = dp;
301 SDT_PROBE2(vfs,
namei,
lookup,
return, error, NULL);
304 vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
305 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
309 if ((cnp->cn_flags & ISSYMLINK) == 0) {
310 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
313 cnp->cn_flags |= HASBUF;
315 if ((cnp->cn_flags & MPSAFE) == 0) {
316 VFS_UNLOCK_GIANT(vfslocked);
317 }
else if (vfslocked)
318 ndp->ni_cnd.cn_flags |= GIANTHELD;
319 SDT_PROBE2(vfs,
namei,
lookup,
return, 0, ndp->ni_vp);
322 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
327 if ((cnp->cn_flags & NOMACCHECK) == 0) {
328 error = mac_vnode_check_readlink(td->td_ucred,
334 if (ndp->ni_pathlen > 1)
339 aiov.iov_len = MAXPATHLEN;
340 auio.uio_iov = &aiov;
343 auio.uio_rw = UIO_READ;
344 auio.uio_segflg = UIO_SYSSPACE;
346 auio.uio_resid = MAXPATHLEN;
347 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
349 if (ndp->ni_pathlen > 1)
353 linklen = MAXPATHLEN - auio.uio_resid;
355 if (ndp->ni_pathlen > 1)
360 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
361 if (ndp->ni_pathlen > 1)
363 error = ENAMETOOLONG;
366 if (ndp->ni_pathlen > 1) {
367 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
371 cnp->cn_pnbuf[linklen] =
'\0';
372 ndp->ni_pathlen += linklen;
380 VFS_UNLOCK_GIANT(vfslocked);
381 SDT_PROBE2(vfs,
namei,
lookup,
return, error, NULL);
389 if (mp == NULL || ((lkflags & LK_SHARED) &&
390 (!(mp->mnt_kern_flag & MNTK_LOOKUP_SHARED) ||
391 ((cnflags & ISDOTDOT) &&
392 (mp->mnt_kern_flag & MNTK_LOOKUP_EXCL_DOTDOT))))) {
393 lkflags &= ~LK_SHARED;
394 lkflags |= LK_EXCLUSIVE;
407 if ((flags & (ISLASTCN | LOCKLEAF)) != (ISLASTCN | LOCKLEAF))
411 if (!(flags & LOCKSHARED))
419 if (flags & ISOPEN) {
421 (mp->mnt_kern_flag & MNTK_EXTENDED_SHARED))
476 struct vnode *dp = 0;
485 struct componentname *cnp = &ndp->ni_cnd;
495 dvfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
498 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
499 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
500 KASSERT(cnp->cn_nameiop == LOOKUP || wantparent,
501 (
"CREATE, DELETE, RENAME require LOCKPARENT or WANTPARENT."));
502 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
503 if (cnp->cn_nameiop == DELETE ||
504 (wantparent && cnp->cn_nameiop != CREATE &&
505 cnp->cn_nameiop != LOOKUP))
507 rdonly = cnp->cn_flags & RDONLY;
508 cnp->cn_flags &= ~ISSYMLINK;
515 cnp->cn_lkflags = LK_SHARED;
517 cnp->cn_lkflags = LK_EXCLUSIVE;
518 dp = ndp->ni_startdir;
519 ndp->ni_startdir = NULLVP;
534 for (cp = cnp->cn_nameptr; *cp != 0 && *cp !=
'/'; cp++)
536 cnp->cn_namelen = cp - cnp->cn_nameptr;
537 if (cnp->cn_namelen > NAME_MAX) {
538 error = ENAMETOOLONG;
541 #ifdef NAMEI_DIAGNOSTIC
544 printf(
"{%s}: ", cnp->cn_nameptr);
547 ndp->ni_pathlen -= cnp->cn_namelen;
557 while (*cp ==
'/' && (cp[1] ==
'/' || cp[1] ==
'\0')) {
561 *ndp->ni_next =
'\0';
562 cnp->cn_flags |= TRAILINGSLASH;
567 cnp->cn_flags |= MAKEENTRY;
568 if (*cp ==
'\0' && docache == 0)
569 cnp->cn_flags &= ~MAKEENTRY;
570 if (cnp->cn_namelen == 2 &&
571 cnp->cn_nameptr[1] ==
'.' && cnp->cn_nameptr[0] ==
'.')
572 cnp->cn_flags |= ISDOTDOT;
574 cnp->cn_flags &= ~ISDOTDOT;
575 if (*ndp->ni_next == 0)
576 cnp->cn_flags |= ISLASTCN;
578 cnp->cn_flags &= ~ISLASTCN;
580 if ((cnp->cn_flags & ISLASTCN) != 0 &&
581 cnp->cn_namelen == 1 && cnp->cn_nameptr[0] ==
'.' &&
582 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
592 if (cnp->cn_nameptr[0] ==
'\0') {
593 if (dp->v_type != VDIR) {
597 if (cnp->cn_nameiop != LOOKUP) {
607 if (cnp->cn_flags & AUDITVNODE1)
608 AUDIT_ARG_VNODE1(dp);
609 else if (cnp->cn_flags & AUDITVNODE2)
610 AUDIT_ARG_VNODE2(dp);
612 if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
615 if (cnp->cn_flags & SAVESTART)
616 panic(
"lookup: SAVESTART");
637 if (cnp->cn_flags & ISDOTDOT) {
638 if (ndp->ni_strictrelative != 0) {
642 if ((cnp->cn_flags & ISLASTCN) != 0 &&
643 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
648 for (pr = cnp->cn_cred->cr_prison; pr != NULL;
650 if (dp == pr->pr_root)
652 if (dp == ndp->ni_rootdir ||
653 dp == ndp->ni_topdir ||
656 ((dp->v_vflag & VV_ROOT) != 0 &&
657 (cnp->cn_flags & NOCROSSMOUNT) != 0)) {
660 vfslocked = VFS_LOCK_GIANT(dp->v_mount);
664 if ((dp->v_vflag & VV_ROOT) == 0)
666 if (dp->v_iflag & VI_DOOMED) {
671 dp = dp->v_mount->mnt_vnodecovered;
672 tvfslocked = dvfslocked;
673 dvfslocked = VFS_LOCK_GIANT(dp->v_mount);
676 VFS_UNLOCK_GIANT(tvfslocked);
679 LK_RETRY, ISDOTDOT));
688 if ((cnp->cn_flags & NOMACCHECK) == 0) {
689 error = mac_vnode_check_lookup(cnp->cn_thread->td_ucred, dp,
697 ASSERT_VOP_LOCKED(dp,
"lookup");
698 VNASSERT(vfslocked == 0, dp, (
"lookup: vfslocked %d", vfslocked));
704 VOP_ISLOCKED(dp) == LK_SHARED &&
705 (cnp->cn_flags & ISLASTCN) && (cnp->cn_flags & LOCKPARENT))
706 vn_lock(dp, LK_UPGRADE|LK_RETRY);
707 if ((dp->v_iflag & VI_DOOMED) != 0) {
716 cnp->cn_lkflags = LK_EXCLUSIVE;
717 #ifdef NAMEI_DIAGNOSTIC
718 vprint(
"lookup in", dp);
720 lkflags_save = cnp->cn_lkflags;
723 if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
724 cnp->cn_lkflags = lkflags_save;
725 KASSERT(ndp->ni_vp == NULL, (
"leaf should be empty"));
726 #ifdef NAMEI_DIAGNOSTIC
729 if ((error == ENOENT) &&
730 (dp->v_vflag & VV_ROOT) && (dp->v_mount != NULL) &&
731 (dp->v_mount->mnt_flag & MNT_UNION)) {
733 dp = dp->v_mount->mnt_vnodecovered;
734 tvfslocked = dvfslocked;
735 dvfslocked = VFS_LOCK_GIANT(dp->v_mount);
738 VFS_UNLOCK_GIANT(tvfslocked);
741 LK_RETRY, cnp->cn_flags));
745 if (error != EJUSTRETURN)
758 if ((cnp->cn_flags & TRAILINGSLASH) &&
759 !(cnp->cn_flags & WILLBEDIR)) {
763 if ((cnp->cn_flags & LOCKPARENT) == 0)
770 if (cnp->cn_flags & SAVESTART) {
771 ndp->ni_startdir = ndp->ni_dvp;
772 VREF(ndp->ni_startdir);
776 cnp->cn_lkflags = lkflags_save;
777 #ifdef NAMEI_DIAGNOSTIC
784 if (cnp->cn_consume > 0) {
785 cnp->cn_nameptr += cnp->cn_consume;
786 ndp->ni_next += cnp->cn_consume;
787 ndp->ni_pathlen -= cnp->cn_consume;
792 vfslocked = VFS_LOCK_GIANT(dp->v_mount);
798 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
799 (cnp->cn_flags & NOCROSSMOUNT) == 0) {
803 VFS_UNLOCK_GIANT(vfslocked);
804 vfslocked = VFS_LOCK_GIANT(mp);
805 if (dp != ndp->ni_dvp)
809 VFS_UNLOCK_GIANT(dvfslocked);
814 cnp->cn_flags), &tdp);
816 if (vn_lock(
vp_crossmp, LK_SHARED | LK_NOWAIT))
817 panic(
"vp_crossmp exclusively locked or reclaimed");
822 ndp->ni_vp = dp = tdp;
828 if ((dp->v_type == VLNK) &&
829 ((cnp->cn_flags & FOLLOW) || (cnp->cn_flags & TRAILINGSLASH) ||
830 *ndp->ni_next ==
'/')) {
831 cnp->cn_flags |= ISSYMLINK;
832 if (dp->v_iflag & VI_DOOMED) {
840 if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
847 if (ndp->ni_dvp != ndp->ni_vp) {
848 VOP_UNLOCK(ndp->ni_dvp, 0);
859 KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next ==
'/',
860 (
"lookup: invalid path state."));
861 if (*ndp->ni_next ==
'/') {
862 cnp->cn_nameptr = ndp->ni_next;
863 while (*cnp->cn_nameptr ==
'/') {
867 if (ndp->ni_dvp != dp)
871 VFS_UNLOCK_GIANT(dvfslocked);
872 dvfslocked = vfslocked;
880 if ((cnp->cn_flags & TRAILINGSLASH) && dp->v_type != VDIR) {
888 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
892 if (cnp->cn_flags & SAVESTART) {
893 ndp->ni_startdir = ndp->ni_dvp;
894 VREF(ndp->ni_startdir);
898 if (ndp->ni_dvp != dp)
902 VFS_UNLOCK_GIANT(dvfslocked);
904 }
else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) {
905 VOP_UNLOCK(ndp->ni_dvp, 0);
909 if (cnp->cn_flags & AUDITVNODE1)
910 AUDIT_ARG_VNODE1(dp);
911 else if (cnp->cn_flags & AUDITVNODE2)
912 AUDIT_ARG_VNODE2(dp);
914 if ((cnp->cn_flags & LOCKLEAF) == 0)
922 VOP_ISLOCKED(dp) != LK_EXCLUSIVE) {
923 vn_lock(dp, LK_UPGRADE | LK_RETRY);
924 if (dp->v_iflag & VI_DOOMED) {
929 if (vfslocked && dvfslocked)
930 VFS_UNLOCK_GIANT(dvfslocked);
931 if (vfslocked || dvfslocked)
932 ndp->ni_cnd.cn_flags |= GIANTHELD;
936 if (ni_dvp_unlocked != 2) {
937 if (dp != ndp->ni_dvp && !ni_dvp_unlocked)
945 VFS_UNLOCK_GIANT(vfslocked);
946 VFS_UNLOCK_GIANT(dvfslocked);
947 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
957 relookup(
struct vnode *dvp,
struct vnode **vpp,
struct componentname *cnp)
959 struct vnode *dp = 0;
964 KASSERT(cnp->cn_flags & ISLASTCN,
965 (
"relookup: Not given last component."));
969 wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
970 KASSERT(wantparent, (
"relookup: parent not wanted."));
971 rdonly = cnp->cn_flags & RDONLY;
972 cnp->cn_flags &= ~ISSYMLINK;
974 cnp->cn_lkflags = LK_EXCLUSIVE;
975 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
985 #ifdef NAMEI_DIAGNOSTIC
986 printf(
"{%s}: ", cnp->cn_nameptr);
993 if (cnp->cn_nameptr[0] ==
'\0') {
998 KASSERT(cnp->cn_nameiop == LOOKUP, (
"nameiop must be LOOKUP"));
999 KASSERT(dp->v_type == VDIR, (
"dp is not a directory"));
1001 if (!(cnp->cn_flags & LOCKLEAF))
1005 if (cnp->cn_flags & SAVESTART)
1006 panic(
"lookup: SAVESTART");
1010 if (cnp->cn_flags & ISDOTDOT)
1011 panic (
"relookup: lookup on dot-dot");
1016 #ifdef NAMEI_DIAGNOSTIC
1017 vprint(
"search in:", dp);
1019 if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
1020 KASSERT(*vpp == NULL, (
"leaf should be empty"));
1021 if (error != EJUSTRETURN)
1032 if (cnp->cn_flags & SAVESTART)
1034 if ((cnp->cn_flags & LOCKPARENT) == 0)
1050 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
1061 if ((cnp->cn_flags & LOCKPARENT) == 0 && dvp != dp) {
1066 }
else if (!wantparent)
1071 KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & FOLLOW),
1072 (
"relookup: symlink found.\n"));
1075 if (cnp->cn_flags & SAVESTART)
1078 if ((cnp->cn_flags & LOCKLEAF) == 0)
1091 NDFREE(
struct nameidata *ndp,
const u_int flags)
1099 if (!(flags & NDF_NO_FREE_PNBUF) &&
1100 (ndp->ni_cnd.cn_flags & HASBUF)) {
1102 ndp->ni_cnd.cn_flags &= ~HASBUF;
1104 if (!(flags & NDF_NO_VP_UNLOCK) &&
1105 (ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp)
1107 if (!(flags & NDF_NO_VP_RELE) && ndp->ni_vp) {
1116 VOP_UNLOCK(ndp->ni_vp, 0);
1117 if (!(flags & NDF_NO_DVP_UNLOCK) &&
1118 (ndp->ni_cnd.cn_flags & LOCKPARENT) &&
1119 ndp->ni_dvp != ndp->ni_vp)
1121 if (!(flags & NDF_NO_DVP_RELE) &&
1122 (ndp->ni_cnd.cn_flags & (LOCKPARENT|WANTPARENT))) {
1131 VOP_UNLOCK(ndp->ni_dvp, 0);
1132 if (!(flags & NDF_NO_STARTDIR_RELE) &&
1133 (ndp->ni_cnd.cn_flags & SAVESTART)) {
1134 vrele(ndp->ni_startdir);
1135 ndp->ni_startdir = NULL;
1151 enum uio_seg pathseg,
char **pathbuf,
int create,
int dirfd)
1153 struct nameidata nd, ndroot;
1154 char *ptr, *
buf, *cp;
1158 buf = (
char *)
malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
1162 len = strlcpy(buf, prefix, MAXPATHLEN);
1163 if (len >= MAXPATHLEN) {
1168 sz = MAXPATHLEN - len;
1172 if (pathseg == UIO_SYSSPACE)
1173 error = copystr(path, ptr, sz, &len);
1175 error = copyinstr(path, ptr, sz, &len);
1189 if (dirfd != AT_FDCWD) {
1194 bcopy(ptr, buf, len);
1207 for (cp = &ptr[len] - 1; *cp !=
'/'; cp--);
1210 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td);
1216 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, buf, td);
1230 NDINIT(&ndroot, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, prefix,
1234 error =
namei(&ndroot);
1236 if (nd.ni_vp == ndroot.ni_vp)
1239 NDFREE(&ndroot, NDF_ONLY_PNBUF);
1240 vrele(ndroot.ni_vp);
1241 VFS_UNLOCK_GIANT(NDHASGIANT(&ndroot));
1245 NDFREE(&nd, NDF_ONLY_PNBUF);
1247 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
1252 bcopy(ptr, buf, len);
int fgetvp_rights(struct thread *td, int fd, cap_rights_t need, cap_rights_t *have, struct vnode **vpp)
static void nameiinit(void *dummy __unused)
void NDFREE(struct nameidata *ndp, const u_int flags)
SDT_PROBE_DEFINE3(vfs, namei, lookup, entry,"struct vnode *","char *","unsigned long")
void * malloc(unsigned long size, struct malloc_type *mtp, int flags)
static int compute_cn_lkflags(struct mount *mp, int lkflags, int cnflags)
void panic(const char *fmt,...)
static __inline int needs_exclusive_leaf(struct mount *mp, int flags)
void vref(struct vnode *vp)
TUNABLE_INT("vfs.lookup_shared",&lookup_shared)
void vput(struct vnode *vp)
void vfs_unbusy(struct mount *mp)
int namei(struct nameidata *ndp)
SDT_PROVIDER_DECLARE(vfs)
int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, struct vnode **vpp)
void free(void *addr, struct malloc_type *mtp)
int printf(const char *fmt,...)
int vfs_busy(struct mount *mp, int flags)
static struct vnode * vp_crossmp
int relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
SYSCTL_INT(_vfs, OID_AUTO, lookup_shared, CTLFLAG_RW,&lookup_shared, 0,"Enables/Disables shared locks for path name translation")
void vrele(struct vnode *vp)
static void namei_cleanup_cnp(struct componentname *cnp)
int kern_alternate_path(struct thread *td, const char *prefix, const char *path, enum uio_seg pathseg, char **pathbuf, int create, int dirfd)
SDT_PROBE_DEFINE2(vfs, namei, lookup, return,"int","struct vnode *")
static struct pollrec pr[POLL_LIST_LEN]
SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL)
int lookup(struct nameidata *ndp)