xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 49736)
123401Smckusick /*
237715Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337715Smckusick  * All rights reserved.
423401Smckusick  *
544457Sbostic  * %sccs.include.redist.c%
637715Smckusick  *
7*49736Smckusick  *	@(#)vfs_lookup.c	7.30 (Berkeley) 05/15/91
823401Smckusick  */
930Sbill 
1017100Sbloom #include "param.h"
11*49736Smckusick #include "syslimits.h"
1237715Smckusick #include "time.h"
1337715Smckusick #include "namei.h"
1437715Smckusick #include "vnode.h"
1517100Sbloom #include "mount.h"
1637715Smckusick #include "errno.h"
1731650Smckusick #include "malloc.h"
1845914Smckusick #include "filedesc.h"
1945924Smckusick #include "proc.h"
2037715Smckusick 
2137582Smarc #ifdef KTRACE
2237582Smarc #include "ktrace.h"
2337582Smarc #endif
2430Sbill 
2530Sbill /*
2627268Smckusick  * Convert a pathname into a pointer to a locked inode.
2730Sbill  *
2816688Smckusick  * The FOLLOW flag is set when symbolic links are to be followed
299166Ssam  * when they occur at the end of the name translation process.
3027268Smckusick  * Symbolic links are always followed for all other pathname
3127268Smckusick  * components other than the last.
329166Ssam  *
3327268Smckusick  * The segflg defines whether the name is to be copied from user
3427268Smckusick  * space or kernel space.
3527268Smckusick  *
3615798Smckusick  * Overall outline of namei:
3715798Smckusick  *
387534Sroot  *	copy in name
397534Sroot  *	get starting directory
40*49736Smckusick  *	while (!done && !error) {
41*49736Smckusick  *		call lookup to search path.
42*49736Smckusick  *		if symbolic link, massage name in buffer and continue
43*49736Smckusick  *	}
44*49736Smckusick  */
45*49736Smckusick namei(ndp, p)
46*49736Smckusick 	register struct nameidata *ndp;
47*49736Smckusick 	struct proc *p;
48*49736Smckusick {
49*49736Smckusick 	register struct filedesc *fdp;	/* pointer to file descriptor state */
50*49736Smckusick 	register char *cp;		/* pointer into pathname argument */
51*49736Smckusick 	register struct vnode *dp;	/* the directory we are searching */
52*49736Smckusick 	struct iovec aiov;		/* uio for reading symbolic links */
53*49736Smckusick 	struct uio auio;
54*49736Smckusick 	int error, linklen;
55*49736Smckusick 
56*49736Smckusick 	ndp->ni_cred = p->p_ucred;
57*49736Smckusick 	fdp = p->p_fd;
58*49736Smckusick 
59*49736Smckusick 	/*
60*49736Smckusick 	 * Get a buffer for the name to be translated, and copy the
61*49736Smckusick 	 * name into the buffer.
62*49736Smckusick 	 */
63*49736Smckusick #ifdef DIAGNOSTIC
64*49736Smckusick 	if (ndp->ni_nameiop & HASBUF)
65*49736Smckusick 		panic("namei: reentered");
66*49736Smckusick #endif
67*49736Smckusick 	MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
68*49736Smckusick 	if (ndp->ni_segflg == UIO_SYSSPACE)
69*49736Smckusick 		error = copystr(ndp->ni_dirp, ndp->ni_pnbuf,
70*49736Smckusick 			    MAXPATHLEN, &ndp->ni_pathlen);
71*49736Smckusick 	else
72*49736Smckusick 		error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf,
73*49736Smckusick 			    MAXPATHLEN, &ndp->ni_pathlen);
74*49736Smckusick 	if (error) {
75*49736Smckusick 		free(ndp->ni_pnbuf, M_NAMEI);
76*49736Smckusick 		ndp->ni_vp = NULL;
77*49736Smckusick 		return (error);
78*49736Smckusick 	}
79*49736Smckusick 	ndp->ni_loopcnt = 0;
80*49736Smckusick #ifdef KTRACE
81*49736Smckusick 	if (KTRPOINT(p, KTR_NAMEI))
82*49736Smckusick 		ktrnamei(p->p_tracep, ndp->ni_pnbuf);
83*49736Smckusick #endif
84*49736Smckusick 
85*49736Smckusick 	/*
86*49736Smckusick 	 * Get starting point for the translation.
87*49736Smckusick 	 */
88*49736Smckusick 	if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
89*49736Smckusick 		ndp->ni_rootdir = rootdir;
90*49736Smckusick 	dp = fdp->fd_cdir;
91*49736Smckusick 	VREF(dp);
92*49736Smckusick 	for (;;) {
93*49736Smckusick 		/*
94*49736Smckusick 		 * Check if root directory should replace current directory.
95*49736Smckusick 		 * Done at start of translation and after symbolic link.
96*49736Smckusick 		 */
97*49736Smckusick 		ndp->ni_ptr = ndp->ni_pnbuf;
98*49736Smckusick 		if (*ndp->ni_ptr == '/') {
99*49736Smckusick 			vrele(dp);
100*49736Smckusick 			while (*ndp->ni_ptr == '/') {
101*49736Smckusick 				ndp->ni_ptr++;
102*49736Smckusick 				ndp->ni_pathlen--;
103*49736Smckusick 			}
104*49736Smckusick 			dp = ndp->ni_rootdir;
105*49736Smckusick 			VREF(dp);
106*49736Smckusick 		}
107*49736Smckusick 		ndp->ni_startdir = dp;
108*49736Smckusick 		if (error = lookup(ndp, p)) {
109*49736Smckusick 			FREE(ndp->ni_pnbuf, M_NAMEI);
110*49736Smckusick 			return (error);
111*49736Smckusick 		}
112*49736Smckusick 		/*
113*49736Smckusick 		 * Check for symbolic link
114*49736Smckusick 		 */
115*49736Smckusick 		if (ndp->ni_more == 0) {
116*49736Smckusick 			if ((ndp->ni_nameiop & (SAVENAME | SAVESTART)) == 0)
117*49736Smckusick 				FREE(ndp->ni_pnbuf, M_NAMEI);
118*49736Smckusick 			else
119*49736Smckusick 				ndp->ni_nameiop |= HASBUF;
120*49736Smckusick 			return (0);
121*49736Smckusick 		}
122*49736Smckusick 		if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1)
123*49736Smckusick 			VOP_UNLOCK(ndp->ni_dvp);
124*49736Smckusick 		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
125*49736Smckusick 			error = ELOOP;
126*49736Smckusick 			break;
127*49736Smckusick 		}
128*49736Smckusick 		if (ndp->ni_pathlen > 1)
129*49736Smckusick 			MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
130*49736Smckusick 		else
131*49736Smckusick 			cp = ndp->ni_pnbuf;
132*49736Smckusick 		aiov.iov_base = cp;
133*49736Smckusick 		aiov.iov_len = MAXPATHLEN;
134*49736Smckusick 		auio.uio_iov = &aiov;
135*49736Smckusick 		auio.uio_iovcnt = 1;
136*49736Smckusick 		auio.uio_offset = 0;
137*49736Smckusick 		auio.uio_rw = UIO_READ;
138*49736Smckusick 		auio.uio_segflg = UIO_SYSSPACE;
139*49736Smckusick 		auio.uio_procp = (struct proc *)0;
140*49736Smckusick 		auio.uio_resid = MAXPATHLEN;
141*49736Smckusick 		if (error = VOP_READLINK(ndp->ni_vp, &auio, p->p_ucred)) {
142*49736Smckusick 			if (ndp->ni_pathlen > 1)
143*49736Smckusick 				free(cp, M_NAMEI);
144*49736Smckusick 			break;
145*49736Smckusick 		}
146*49736Smckusick 		linklen = MAXPATHLEN - auio.uio_resid;
147*49736Smckusick 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
148*49736Smckusick 			if (ndp->ni_pathlen > 1)
149*49736Smckusick 				free(cp, M_NAMEI);
150*49736Smckusick 			error = ENAMETOOLONG;
151*49736Smckusick 			break;
152*49736Smckusick 		}
153*49736Smckusick 		if (ndp->ni_pathlen > 1) {
154*49736Smckusick 			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
155*49736Smckusick 			FREE(ndp->ni_pnbuf, M_NAMEI);
156*49736Smckusick 			ndp->ni_pnbuf = cp;
157*49736Smckusick 		} else
158*49736Smckusick 			ndp->ni_pnbuf[linklen] = '\0';
159*49736Smckusick 		ndp->ni_pathlen += linklen;
160*49736Smckusick 		vput(ndp->ni_vp);
161*49736Smckusick 		dp = ndp->ni_dvp;
162*49736Smckusick 	}
163*49736Smckusick 	FREE(ndp->ni_pnbuf, M_NAMEI);
164*49736Smckusick 	vrele(ndp->ni_dvp);
165*49736Smckusick 	vput(ndp->ni_vp);
166*49736Smckusick 	ndp->ni_vp = NULL;
167*49736Smckusick 	return (error);
168*49736Smckusick }
169*49736Smckusick 
170*49736Smckusick /*
171*49736Smckusick  * Search a pathname.
172*49736Smckusick  * This is a very central and rather complicated routine.
173*49736Smckusick  *
174*49736Smckusick  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
175*49736Smckusick  * The starting directory is taken from ni_startdir. The pathname is
176*49736Smckusick  * descended until done, or a symbolic link is encountered. The variable
177*49736Smckusick  * ni_more is clear if the path is completed; it is set to one if a
178*49736Smckusick  * symbolic link needing interpretation is encountered.
179*49736Smckusick  *
180*49736Smckusick  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
181*49736Smckusick  * whether the name is to be looked up, created, renamed, or deleted.
182*49736Smckusick  * When CREATE, RENAME, or DELETE is specified, information usable in
183*49736Smckusick  * creating, renaming, or deleting a directory entry may be calculated.
184*49736Smckusick  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
185*49736Smckusick  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
186*49736Smckusick  * returned unlocked. Otherwise the parent directory is not returned. If
187*49736Smckusick  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
188*49736Smckusick  * the target is returned locked, otherwise it is returned unlocked.
189*49736Smckusick  * When creating or renaming and LOCKPARENT is specified, the target may not
190*49736Smckusick  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
191*49736Smckusick  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
192*49736Smckusick  *
193*49736Smckusick  * Overall outline of lookup:
194*49736Smckusick  *
1957534Sroot  * dirloop:
196*49736Smckusick  *	identify next component of name at ndp->ni_ptr
1977534Sroot  *	handle degenerate case where name is null string
198*49736Smckusick  *	if .. and crossing mount points and on mounted filesys, find parent
199*49736Smckusick  *	call VOP_LOOKUP routine for next component name
200*49736Smckusick  *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
201*49736Smckusick  *	    component vnode returned in ni_vp (if it exists), locked.
202*49736Smckusick  *	if result vnode is mounted on and crossing mount points,
203*49736Smckusick  *	    find mounted on vnode
2047534Sroot  *	if more components of name, do next level at dirloop
205*49736Smckusick  *	return the answer in ni_vp, locked if LOCKLEAF set
206*49736Smckusick  *	    if LOCKPARENT set, return locked parent in ni_dvp
207*49736Smckusick  *	    if WANTPARENT set, return unlocked parent in ni_dvp
20830Sbill  */
209*49736Smckusick lookup(ndp, p)
21016688Smckusick 	register struct nameidata *ndp;
21147540Skarels 	struct proc *p;
21230Sbill {
2137534Sroot 	register char *cp;		/* pointer into pathname argument */
21437715Smckusick 	register struct vnode *dp = 0;	/* the directory we are searching */
21537715Smckusick 	struct vnode *tdp;		/* saved dp */
21637715Smckusick 	struct mount *mp;		/* mount table entry */
21718109Smckusick 	int docache;			/* == 0 do not cache last component */
21837715Smckusick 	int flag;			/* LOOKUP, CREATE, RENAME or DELETE */
21937715Smckusick 	int wantparent;			/* 1 => wantparent or lockparent flag */
22041337Smckusick 	int rdonly;			/* mounted read-only flag bit(s) */
22137715Smckusick 	int error = 0;
22230Sbill 
22341337Smckusick 	/*
22441337Smckusick 	 * Setup: break out flag bits into variables.
22541337Smckusick 	 */
22646508Smckusick 	flag = ndp->ni_nameiop & OPMASK;
22737715Smckusick 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
22816688Smckusick 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
22946746Smckusick 	if (flag == DELETE || (wantparent && flag != CREATE))
23015798Smckusick 		docache = 0;
23141400Smckusick 	rdonly = MNT_RDONLY;
23241337Smckusick 	if (ndp->ni_nameiop & REMOTE)
23341400Smckusick 		rdonly |= MNT_EXRDONLY;
234*49736Smckusick 	ndp->ni_dvp = NULL;
235*49736Smckusick 	ndp->ni_more = 0;
236*49736Smckusick 	dp = ndp->ni_startdir;
237*49736Smckusick 	ndp->ni_startdir = NULLVP;
23837715Smckusick 	VOP_LOCK(dp);
2397534Sroot 
2406571Smckusic dirloop:
24130Sbill 	/*
242*49736Smckusick 	 * Search a new directory.
243*49736Smckusick 	 *
244*49736Smckusick 	 * The ni_hash value is for use by vfs_cache.
245*49736Smckusick 	 * The last component of the filename is left accessible via
246*49736Smckusick 	 * ndp->ptr for callers that need the name. Callers needing
247*49736Smckusick 	 * the name set the SAVENAME flag. When done, they assume
248*49736Smckusick 	 * responsibility for freeing the pathname buffer.
2497534Sroot 	 */
250*49736Smckusick 	ndp->ni_hash = 0;
251*49736Smckusick 	for (cp = ndp->ni_ptr; *cp != 0 && *cp != '/'; cp++) {
252*49736Smckusick 		ndp->ni_hash += (unsigned char)*cp;
253*49736Smckusick 		if ((*cp & 0200) == 0)
254*49736Smckusick 			continue;
255*49736Smckusick 		if ((*cp & 0377) == ('/' | 0200) || flag != DELETE) {
256*49736Smckusick 			error = EINVAL;
257*49736Smckusick 			goto bad;
25837743Smckusick 		}
259*49736Smckusick 	}
260*49736Smckusick 	ndp->ni_namelen = cp - ndp->ni_ptr;
261*49736Smckusick 	if (ndp->ni_namelen >= NAME_MAX) {
262*49736Smckusick 		error = ENAMETOOLONG;
263*49736Smckusick 		goto bad;
264*49736Smckusick 	}
26537743Smckusick #ifdef NAMEI_DIAGNOSTIC
266*49736Smckusick 	{ char c = *cp;
267*49736Smckusick 	*cp = '\0';
268*49736Smckusick 	printf("{%s}: ", ndp->ni_ptr);
269*49736Smckusick 	*cp = c; }
27037743Smckusick #endif
271*49736Smckusick 	ndp->ni_pathlen -= ndp->ni_namelen;
272*49736Smckusick 	ndp->ni_next = cp;
27337715Smckusick 	ndp->ni_makeentry = 1;
27418109Smckusick 	if (*cp == '\0' && docache == 0)
27537715Smckusick 		ndp->ni_makeentry = 0;
27637715Smckusick 	ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
277*49736Smckusick 		ndp->ni_ptr[1] == '.' && ndp->ni_ptr[0] == '.');
2787534Sroot 
2797534Sroot 	/*
2807534Sroot 	 * Check for degenerate name (e.g. / or "")
2817534Sroot 	 * which is a way of talking about a directory,
2827534Sroot 	 * e.g. like "/." or ".".
2837534Sroot 	 */
28437715Smckusick 	if (ndp->ni_ptr[0] == '\0') {
28537715Smckusick 		if (flag != LOOKUP || wantparent) {
28637715Smckusick 			error = EISDIR;
2877534Sroot 			goto bad;
2885972Swnj 		}
289*49736Smckusick 		if (dp->v_type != VDIR) {
290*49736Smckusick 			error = ENOTDIR;
291*49736Smckusick 			goto bad;
292*49736Smckusick 		}
29337715Smckusick 		if (!(ndp->ni_nameiop & LOCKLEAF))
29437715Smckusick 			VOP_UNLOCK(dp);
29537715Smckusick 		ndp->ni_vp = dp;
296*49736Smckusick 		if (ndp->ni_nameiop & SAVESTART)
297*49736Smckusick 			panic("lookup: SAVESTART");
29837715Smckusick 		return (0);
2995972Swnj 	}
3007534Sroot 
3016571Smckusic 	/*
30237715Smckusick 	 * Handle "..": two special cases.
30337715Smckusick 	 * 1. If at root directory (e.g. after chroot)
30437715Smckusick 	 *    then ignore it so can't get out.
30537715Smckusick 	 * 2. If this vnode is the root of a mounted
306*49736Smckusick 	 *    filesystem, then replace it with the
30737715Smckusick 	 *    vnode which was mounted on so we take the
30837715Smckusick 	 *    .. in the other file system.
30936547Smckusick 	 */
31037715Smckusick 	if (ndp->ni_isdotdot) {
31136547Smckusick 		for (;;) {
312*49736Smckusick 			if (dp == ndp->ni_rootdir) {
31337715Smckusick 				ndp->ni_dvp = dp;
31438390Smckusick 				ndp->ni_vp = dp;
31538347Smckusick 				VREF(dp);
31637715Smckusick 				goto nextname;
31736547Smckusick 			}
31841337Smckusick 			if ((dp->v_flag & VROOT) == 0 ||
319*49736Smckusick 			    (ndp->ni_nameiop & NOCROSSMOUNT))
32036547Smckusick 				break;
32137715Smckusick 			tdp = dp;
32241400Smckusick 			dp = dp->v_mount->mnt_vnodecovered;
32337715Smckusick 			vput(tdp);
32438390Smckusick 			VREF(dp);
32537715Smckusick 			VOP_LOCK(dp);
32636547Smckusick 		}
32736547Smckusick 	}
32836547Smckusick 
32936547Smckusick 	/*
33015798Smckusick 	 * We now have a segment name to search for, and a directory to search.
33115798Smckusick 	 */
33248025Smckusick 	if (error = VOP_LOOKUP(dp, ndp, p)) {
333*49736Smckusick #ifdef DIAGNOSTIC
33437715Smckusick 		if (ndp->ni_vp != NULL)
33537715Smckusick 			panic("leaf should be empty");
336*49736Smckusick #endif
33737582Smarc #ifdef NAMEI_DIAGNOSTIC
33837715Smckusick 		printf("not found\n");
33937582Smarc #endif
34038581Smckusick 		if (flag == LOOKUP || flag == DELETE ||
34138581Smckusick 		    error != ENOENT || *cp != 0)
34238581Smckusick 			goto bad;
3435972Swnj 		/*
34437715Smckusick 		 * If creating and at end of pathname, then can consider
34537715Smckusick 		 * allowing file to be created.
3465972Swnj 		 */
34741400Smckusick 		if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) {
34837715Smckusick 			error = EROFS;
3497534Sroot 			goto bad;
35038581Smckusick 		}
3515972Swnj 		/*
35237715Smckusick 		 * We return with ni_vp NULL to indicate that the entry
35337715Smckusick 		 * doesn't currently exist, leaving a pointer to the
35437715Smckusick 		 * (possibly locked) directory inode in ndp->ni_dvp.
3555972Swnj 		 */
356*49736Smckusick 		if (ndp->ni_nameiop & SAVESTART) {
357*49736Smckusick 			ndp->ni_startdir = ndp->ni_dvp;
358*49736Smckusick 			VREF(ndp->ni_startdir);
359*49736Smckusick 		}
360*49736Smckusick 		return (0);
3617534Sroot 	}
36237582Smarc #ifdef NAMEI_DIAGNOSTIC
36337715Smckusick 	printf("found\n");
36437582Smarc #endif
3657534Sroot 
366*49736Smckusick 	dp = ndp->ni_vp;
3677534Sroot 	/*
36837715Smckusick 	 * Check for symbolic link
3697534Sroot 	 */
37037715Smckusick 	if ((dp->v_type == VLNK) &&
37137715Smckusick 	    ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
372*49736Smckusick 		ndp->ni_more = 1;
373*49736Smckusick 		return (0);
37415798Smckusick 	}
37515798Smckusick 
3767534Sroot 	/*
37737715Smckusick 	 * Check to see if the vnode has been mounted on;
37837715Smckusick 	 * if so find the root of the mounted file system.
3797534Sroot 	 */
38037715Smckusick mntloop:
38141337Smckusick 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
38241337Smckusick 	       (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
38341400Smckusick 		while(mp->mnt_flag & MNT_MLOCK) {
38441400Smckusick 			mp->mnt_flag |= MNT_MWAIT;
38537715Smckusick 			sleep((caddr_t)mp, PVFS);
38637715Smckusick 			goto mntloop;
38721014Smckusick 		}
388*49736Smckusick 		if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
3897534Sroot 			goto bad2;
39037715Smckusick 		vput(dp);
39137715Smckusick 		ndp->ni_vp = dp = tdp;
39230Sbill 	}
3937534Sroot 
39437715Smckusick nextname:
39530Sbill 	/*
3967534Sroot 	 * Not a symbolic link.  If more pathname,
3977534Sroot 	 * continue at next component, else return.
39830Sbill 	 */
399*49736Smckusick 	if (*ndp->ni_next == '/') {
400*49736Smckusick 		ndp->ni_ptr = ndp->ni_next;
40137715Smckusick 		while (*ndp->ni_ptr == '/') {
40237715Smckusick 			ndp->ni_ptr++;
40337715Smckusick 			ndp->ni_pathlen--;
40437715Smckusick 		}
40537715Smckusick 		vrele(ndp->ni_dvp);
4067534Sroot 		goto dirloop;
40730Sbill 	}
4087534Sroot 	/*
40938400Smckusick 	 * Check for read-only file systems.
4107534Sroot 	 */
41138400Smckusick 	if (flag == DELETE || flag == RENAME) {
41238267Smckusick 		/*
41338400Smckusick 		 * Disallow directory write attempts on read-only
41438400Smckusick 		 * file systems.
41538267Smckusick 		 */
41641400Smckusick 		if ((dp->v_mount->mnt_flag & rdonly) ||
41741400Smckusick 		    (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) {
41838267Smckusick 			error = EROFS;
41938267Smckusick 			goto bad2;
42038267Smckusick 		}
42138267Smckusick 	}
422*49736Smckusick 	if (ndp->ni_nameiop & SAVESTART) {
423*49736Smckusick 		ndp->ni_startdir = ndp->ni_dvp;
424*49736Smckusick 		VREF(ndp->ni_startdir);
425*49736Smckusick 	}
42637715Smckusick 	if (!wantparent)
42737715Smckusick 		vrele(ndp->ni_dvp);
42837715Smckusick 	if ((ndp->ni_nameiop & LOCKLEAF) == 0)
42937715Smckusick 		VOP_UNLOCK(dp);
43037715Smckusick 	return (0);
4317534Sroot 
43237715Smckusick bad2:
433*49736Smckusick 	if ((ndp->ni_nameiop & LOCKPARENT) && *ndp->ni_next == '\0')
43438001Smckusick 		VOP_UNLOCK(ndp->ni_dvp);
43537715Smckusick 	vrele(ndp->ni_dvp);
43637715Smckusick bad:
43737715Smckusick 	vput(dp);
43837715Smckusick 	ndp->ni_vp = NULL;
43910849Ssam 	return (error);
4405972Swnj }
441