xref: /freebsd/share/man/man9/VOP_LOOKUP.9 (revision aaf1f16e39da164cd6dfa049b53d61b9c9ed3216)
1fab63cc4SDoug Rabson.\" -*- nroff -*-
2fab63cc4SDoug Rabson.\"
3fab63cc4SDoug Rabson.\" Copyright (c) 1996 Doug Rabson
4fab63cc4SDoug Rabson.\"
5fab63cc4SDoug Rabson.\" All rights reserved.
6fab63cc4SDoug Rabson.\"
7fab63cc4SDoug Rabson.\" This program is free software.
8fab63cc4SDoug Rabson.\"
9fab63cc4SDoug Rabson.\" Redistribution and use in source and binary forms, with or without
10fab63cc4SDoug Rabson.\" modification, are permitted provided that the following conditions
11fab63cc4SDoug Rabson.\" are met:
12fab63cc4SDoug Rabson.\" 1. Redistributions of source code must retain the above copyright
13fab63cc4SDoug Rabson.\"    notice, this list of conditions and the following disclaimer.
14fab63cc4SDoug Rabson.\" 2. Redistributions in binary form must reproduce the above copyright
15fab63cc4SDoug Rabson.\"    notice, this list of conditions and the following disclaimer in the
16fab63cc4SDoug Rabson.\"    documentation and/or other materials provided with the distribution.
17fab63cc4SDoug Rabson.\"
18fab63cc4SDoug Rabson.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
19fab63cc4SDoug Rabson.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20fab63cc4SDoug Rabson.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21fab63cc4SDoug Rabson.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
22fab63cc4SDoug Rabson.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23fab63cc4SDoug Rabson.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24fab63cc4SDoug Rabson.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25fab63cc4SDoug Rabson.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26fab63cc4SDoug Rabson.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27fab63cc4SDoug Rabson.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28fab63cc4SDoug Rabson.\"
29aaf1f16eSPhilippe Charnier.\" $Id: VOP_LOOKUP.9,v 1.6 1997/11/23 17:58:55 bde Exp $
30fab63cc4SDoug Rabson.\"
3122301c4bSBruce Evans.Dd November 24, 1997
32fab63cc4SDoug Rabson.Os FreeBSD
33fab63cc4SDoug Rabson.Dt VOP_LOOKUP 9
34fab63cc4SDoug Rabson.Sh NAME
35fab63cc4SDoug Rabson.Nm VOP_LOOKUP
36fab63cc4SDoug Rabson.Nd lookup a component of a pathname
37fab63cc4SDoug Rabson.Sh SYNOPSIS
382e14815bSBruce Evans.Fd #include <sys/param.h>
39fab63cc4SDoug Rabson.Fd #include <sys/vnode.h>
40fab63cc4SDoug Rabson.Fd #include <sys/namei.h>
41fab63cc4SDoug Rabson.Ft int
42fab63cc4SDoug Rabson.Fn VOP_LOOKUP "struct vnode *dvp" "struct vnode **vpp" "struct componentname *cnp"
43fab63cc4SDoug Rabson.Sh DESCRIPTION
44fab63cc4SDoug RabsonThis VFS entry point looks up a single pathname component in a given directory.
45fab63cc4SDoug Rabson.Pp
46fab63cc4SDoug RabsonIts arguments are:
47fab63cc4SDoug Rabson.Bl -tag -width vpp
48fab63cc4SDoug Rabson.It Ar dvp
49fab63cc4SDoug Rabsonthe locked vnode of the directory to search
50fab63cc4SDoug Rabson.It Ar vpp
51fab63cc4SDoug Rabsonthe address of a variable where the resulting locked vnode should be stored
52fab63cc4SDoug Rabson.It Ar cnp
53fab63cc4SDoug Rabsonthe pathname component to be searched for
54fab63cc4SDoug Rabson.El
55fab63cc4SDoug Rabson.Pp
56fab63cc4SDoug Rabson.Fa Cnp
57fab63cc4SDoug Rabsonis a pointer to a componentname structure defined as follows:
58fab63cc4SDoug Rabson.Bd -literal
59fab63cc4SDoug Rabsonstruct componentname {
60fab63cc4SDoug Rabson	/*
61fab63cc4SDoug Rabson	 * Arguments to lookup.
62fab63cc4SDoug Rabson	 */
63fab63cc4SDoug Rabson	u_long	cn_nameiop;	/* namei operation */
64fab63cc4SDoug Rabson	u_long	cn_flags;	/* flags to namei */
65fab63cc4SDoug Rabson	struct	proc *cn_proc;	/* process requesting lookup */
66fab63cc4SDoug Rabson	struct	ucred *cn_cred;	/* credentials */
67fab63cc4SDoug Rabson	/*
68fab63cc4SDoug Rabson	 * Shared between lookup and commit routines.
69fab63cc4SDoug Rabson	 */
70fab63cc4SDoug Rabson	char	*cn_pnbuf;	/* pathname buffer */
71fab63cc4SDoug Rabson	char	*cn_nameptr;	/* pointer to looked up name */
72fab63cc4SDoug Rabson	long	cn_namelen;	/* length of looked up component */
73fab63cc4SDoug Rabson	u_long	cn_hash;	/* hash value of looked up name */
74fab63cc4SDoug Rabson	long	cn_consume;	/* chars to consume in lookup() */
75fab63cc4SDoug Rabson};
76fab63cc4SDoug Rabson.Ed
77fab63cc4SDoug Rabson.Pp
78fab63cc4SDoug RabsonConvert a component of a pathname into a pointer to a locked vnode.
79fab63cc4SDoug RabsonThis is a very central and rather complicated routine.
80fab63cc4SDoug RabsonIf the file system is not maintained in a strict tree hierarchy,
81fab63cc4SDoug Rabsonthis can result in a deadlock situation.
82fab63cc4SDoug Rabson.Pp
83fab63cc4SDoug RabsonThe
84fab63cc4SDoug Rabson.Fa cnp->cn_nameiop
85fab63cc4SDoug Rabsonargument is
86fab63cc4SDoug Rabson.Dv LOOKUP ,
87fab63cc4SDoug Rabson.Dv CREATE ,
88fab63cc4SDoug Rabson.Dv RENAME ,
89fab63cc4SDoug Rabsonor
90fab63cc4SDoug Rabson.Dv DELETE
91fab63cc4SDoug Rabsondepending on the intended use of the object.
92fab63cc4SDoug RabsonWhen
93fab63cc4SDoug Rabson.Dv CREATE ,
94fab63cc4SDoug Rabson.Dv RENAME ,
95fab63cc4SDoug Rabsonor
96fab63cc4SDoug Rabson.Dv DELETE
97fab63cc4SDoug Rabsonis specified, information usable in
98fab63cc4SDoug Rabsoncreating, renaming, or deleting a directory entry may be calculated.
99fab63cc4SDoug Rabson.Pp
100fab63cc4SDoug RabsonOverall outline of VOP_LOOKUP:
101fab63cc4SDoug Rabson.Bd -filled -offset indent
102fab63cc4SDoug RabsonCheck accessibility of directory.
103fab63cc4SDoug RabsonLook for name in cache, if found, then return name.
104fab63cc4SDoug RabsonSearch for name in directory, goto to found or notfound as appropriate.
105fab63cc4SDoug Rabson.Ed
106fab63cc4SDoug Rabson.Pp
107fab63cc4SDoug Rabsonnotfound:
108fab63cc4SDoug Rabson.Bd -filled -offset indent
109fab63cc4SDoug RabsonIf creating or renaming and at end of pathname,
110fab63cc4SDoug Rabsonreturn
111fab63cc4SDoug Rabson.Dv EJUSTRETURN ,
112fab63cc4SDoug Rabsonleaving info on available slots else return
113fab63cc4SDoug Rabson.Dv ENOENT .
114fab63cc4SDoug Rabson.Ed
115fab63cc4SDoug Rabson.Pp
116fab63cc4SDoug Rabsonfound:
117fab63cc4SDoug Rabson.Bd -filled -offset indent
118fab63cc4SDoug RabsonIf at end of path and deleting, return information to allow delete.
119fab63cc4SDoug RabsonIf at end of path and renaming, lock target
120fab63cc4SDoug Rabsoninode and return info to allow rename.
121fab63cc4SDoug RabsonIf not at end, add name to cache; if at end and neither creating
122fab63cc4SDoug Rabsonnor deleting, add name to cache.
123fab63cc4SDoug Rabson.Ed
124fab63cc4SDoug Rabson.Sh LOCKS
125fab63cc4SDoug RabsonThe directory,
126fab63cc4SDoug Rabson.Fa dvp
127fab63cc4SDoug Rabsonshould be locked on entry.
128fab63cc4SDoug RabsonIf an error (note: the return value
129fab63cc4SDoug Rabson.Dv EJUSTRETURN
130fab63cc4SDoug Rabsonis not considered an error)
131fab63cc4SDoug Rabsonis detected, it will be returned locked.
132fab63cc4SDoug RabsonOtherwise, it will be unlocked unless both
133fab63cc4SDoug Rabson.Dv LOCKPARENT
134fab63cc4SDoug Rabsonand
135fab63cc4SDoug Rabson.Dv ISLASTCN
136fab63cc4SDoug Rabsonare specified in
137fab63cc4SDoug Rabson.Fa cnp->cn_flags .
138fab63cc4SDoug RabsonIf an entry is found in the directory, it will be returned locked.
139fab63cc4SDoug Rabson.Sh RETURN VALUES
140fab63cc4SDoug RabsonZero is returned with
141fab63cc4SDoug Rabson.Fa *vpp
142fab63cc4SDoug Rabsonset to the locked vnode of the file if the component is found.
143fab63cc4SDoug RabsonIf the component being searched for is ".", then the vnode just has
144fab63cc4SDoug Rabsonan extra reference added to it with
145fab63cc4SDoug Rabson.Xr vref 9 .
146fab63cc4SDoug RabsonThe caller must take care to release the locks appropriately in this
147fab63cc4SDoug Rabsoncase.
148fab63cc4SDoug Rabson.Pp
149fab63cc4SDoug RabsonIf the component is not found and the operation is
150fab63cc4SDoug Rabson.Dv CREATE
151fab63cc4SDoug Rabsonor
152fab63cc4SDoug Rabson.Dv RENAME ,
153fab63cc4SDoug Rabsonthe flag
154fab63cc4SDoug Rabson.Dv ISLASTCN
155fab63cc4SDoug Rabsonis specified and the operation would succeed, the special return value
156fab63cc4SDoug Rabson.Dv EJUSTRETURN
157fab63cc4SDoug Rabsonis returned.
158fab63cc4SDoug RabsonOtherwise, an appropriate error code is returned.
159fab63cc4SDoug Rabson.Sh PSEUDOCODE
160fab63cc4SDoug Rabson.Bd -literal
161fab63cc4SDoug Rabsonint
162fab63cc4SDoug Rabsonvop_lookup(struct vnode *dvp,
163fab63cc4SDoug Rabson	   struct vnode **vpp,
164fab63cc4SDoug Rabson	   struct componentname *cnp)
165fab63cc4SDoug Rabson{
166fab63cc4SDoug Rabson    int error;
167fab63cc4SDoug Rabson    int nameiop = cnp->cn_nameiop;
168fab63cc4SDoug Rabson    int flags = cnp->cn_flags;
169fab63cc4SDoug Rabson    int lockparent = flags & LOCKPARENT;
170fab63cc4SDoug Rabson    int islastcn = flags & ISLASTCN;
171fab63cc4SDoug Rabson    struct vnode *vp = NULL;
172fab63cc4SDoug Rabson
173fab63cc4SDoug Rabson    /*
1743a9c9c6eSMike Pritchard     * Check accessibility of directory.
175fab63cc4SDoug Rabson     */
176fab63cc4SDoug Rabson    if (dvp->v_type != VDIR)
177fab63cc4SDoug Rabson	return ENOTDIR;
178fab63cc4SDoug Rabson
179fab63cc4SDoug Rabson    error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc);
180fab63cc4SDoug Rabson    if (error)
181fab63cc4SDoug Rabson	return (error);
182fab63cc4SDoug Rabson
183fab63cc4SDoug Rabson    if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
184fab63cc4SDoug Rabson	(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
185fab63cc4SDoug Rabson	return (EROFS);
186fab63cc4SDoug Rabson
187fab63cc4SDoug Rabson    /*
1883a9c9c6eSMike Pritchard     * Check name cache for directory/name pair.  This returns ENOENT
189fab63cc4SDoug Rabson     * if the name is known not to exist, -1 if the name was found, or
190fab63cc4SDoug Rabson     * zero if not.
191fab63cc4SDoug Rabson     */
192fab63cc4SDoug Rabson    error = cache_lookup(dvp, vpp, cnp);
193fab63cc4SDoug Rabson    if (error) {
194fab63cc4SDoug Rabson	int vpid;
195fab63cc4SDoug Rabson
196fab63cc4SDoug Rabson	if (error = ENOENT)
197fab63cc4SDoug Rabson	    return error;
198fab63cc4SDoug Rabson
199fab63cc4SDoug Rabson	vp = *vpp;
200fab63cc4SDoug Rabson	if (dvp == vp) {	/* lookup on "." */
201fab63cc4SDoug Rabson	    VREF(vp);
202fab63cc4SDoug Rabson	    error = 0;
203fab63cc4SDoug Rabson	} else if (flags & ISDOTDOT) {
204fab63cc4SDoug Rabson            /*
205fab63cc4SDoug Rabson	     * We need to unlock the directory before getting
206fab63cc4SDoug Rabson	     * the locked vnode for ".." to avoid deadlocks.
207fab63cc4SDoug Rabson	     */
208fab63cc4SDoug Rabson	    VOP_UNLOCK(dvp);
209fab63cc4SDoug Rabson	    error = vget(vp, 1);
210fab63cc4SDoug Rabson	    if (!error) {
211fab63cc4SDoug Rabson		if (lockparent && islastcn)
212fab63cc4SDoug Rabson		    error = VOP_LOCK(dvp);
213fab63cc4SDoug Rabson	    }
214fab63cc4SDoug Rabson	} else {
215fab63cc4SDoug Rabson	    error = vget(vp, 1);
216fab63cc4SDoug Rabson	    if (error || !(lockparent && islastcn)) {
217fab63cc4SDoug Rabson		VOP_UNLOCK(dvp);
218fab63cc4SDoug Rabson	    }
219fab63cc4SDoug Rabson	}
220fab63cc4SDoug Rabson
221fab63cc4SDoug Rabson	/*
222fab63cc4SDoug Rabson	 * Check that the capability number did not change
223fab63cc4SDoug Rabson	 * while we were waiting for the lock.
224fab63cc4SDoug Rabson	 */
225fab63cc4SDoug Rabson	if (!error) {
226fab63cc4SDoug Rabson	    if (vpid == vp->v_id) {
227fab63cc4SDoug Rabson		/*
228fab63cc4SDoug Rabson		 * dvp is locked if lockparent && islastcn.
229fab63cc4SDoug Rabson		 * vp is locked.
230fab63cc4SDoug Rabson		 */
231fab63cc4SDoug Rabson		return (0);
232fab63cc4SDoug Rabson	    }
233fab63cc4SDoug Rabson	    vput(vp);
234fab63cc4SDoug Rabson
235fab63cc4SDoug Rabson	    if (dvp != vp && lockparent && islastcn)
236fab63cc4SDoug Rabson		VOP_UNLOCK(pdp);
237fab63cc4SDoug Rabson	}
238fab63cc4SDoug Rabson
239fab63cc4SDoug Rabson	/*
240fab63cc4SDoug Rabson	 * Re-lock dvp for the directory search below.
241fab63cc4SDoug Rabson	 */
242fab63cc4SDoug Rabson	error = VOP_LOCK(dvp);
243fab63cc4SDoug Rabson	if (error) {
244fab63cc4SDoug Rabson	    return (error);
245fab63cc4SDoug Rabson	}
246fab63cc4SDoug Rabson
247fab63cc4SDoug Rabson	*vpp = NULL;
248fab63cc4SDoug Rabson    }
249fab63cc4SDoug Rabson
250fab63cc4SDoug Rabson    /*
251fab63cc4SDoug Rabson     * Search dvp for the component cnp->cn_nameptr.
252fab63cc4SDoug Rabson     */
253fab63cc4SDoug Rabson    ...;
254fab63cc4SDoug Rabson
255fab63cc4SDoug Rabson    if (!found) {
256fab63cc4SDoug Rabson	if ((nameiop == CREATE || nameiop == RENAME)
257fab63cc4SDoug Rabson	    && islastcn
258fab63cc4SDoug Rabson	    && directory dvp has not been removed) {
259fab63cc4SDoug Rabson	    /*
260fab63cc4SDoug Rabson	     * Check for write access on directory.
261fab63cc4SDoug Rabson	     */
262fab63cc4SDoug Rabson
263fab63cc4SDoug Rabson	    /*
264fab63cc4SDoug Rabson	     * Possibly record the position of a slot in the directory
265fab63cc4SDoug Rabson	     * large enough for the new component name.  This can be
266fab63cc4SDoug Rabson	     * recorded in the vnode private data for dvp.
267fab63cc4SDoug Rabson	     * Set the SAVENAME flag to hold onto the pathname for use
268fab63cc4SDoug Rabson	     * later in VOP_CREATE or VOP_RENAME.
269fab63cc4SDoug Rabson	     */
270fab63cc4SDoug Rabson	    cnp->cn_flags |= SAVENAME;
271fab63cc4SDoug Rabson	    if (!lockparent)
272fab63cc4SDoug Rabson		/*
273fab63cc4SDoug Rabson		 * Note that the extra data recorded above is only
274fab63cc4SDoug Rabson		 * useful if lockparent is specified.
275fab63cc4SDoug Rabson		 */
276fab63cc4SDoug Rabson		VOP_UNLOCK(dvp);
277fab63cc4SDoug Rabson
278fab63cc4SDoug Rabson	    return EJUSTRETURN;
279fab63cc4SDoug Rabson	}
280fab63cc4SDoug Rabson
281fab63cc4SDoug Rabson	/*
282fab63cc4SDoug Rabson	 * Consider inserting name into cache.
283fab63cc4SDoug Rabson	 */
284fab63cc4SDoug Rabson	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
285fab63cc4SDoug Rabson	    cache_enter(dvp, NULL, cnp);
286fab63cc4SDoug Rabson
287fab63cc4SDoug Rabson	return ENOENT;
288fab63cc4SDoug Rabson    } else {
289fab63cc4SDoug Rabson	/*
290fab63cc4SDoug Rabson	 * If deleting, and at end of pathname, return parameters
291fab63cc4SDoug Rabson	 * which can be used to remove file.  If the wantparent flag
292fab63cc4SDoug Rabson	 * isn't set, we return only the directory, otherwise we go on
293fab63cc4SDoug Rabson	 * and lock the inode, being careful with ".".
294fab63cc4SDoug Rabson	 */
295fab63cc4SDoug Rabson	if (nameiop == DELETE && islastcn) {
296fab63cc4SDoug Rabson	    /*
297fab63cc4SDoug Rabson	     * Check for write access on directory.
298fab63cc4SDoug Rabson	     */
299fab63cc4SDoug Rabson	    error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc);
300fab63cc4SDoug Rabson	    if (error)
301fab63cc4SDoug Rabson		return (error);
302fab63cc4SDoug Rabson
303fab63cc4SDoug Rabson	    if (found entry is same as dvp) {
304fab63cc4SDoug Rabson		VREF(dvp);
305fab63cc4SDoug Rabson		*vpp = dvp;
306fab63cc4SDoug Rabson		return 0;
307fab63cc4SDoug Rabson	    }
308fab63cc4SDoug Rabson
309fab63cc4SDoug Rabson	    error = VFS_VGET(dvp->v_mount, ..., &vp);
310fab63cc4SDoug Rabson	    if (error)
311fab63cc4SDoug Rabson		return error;
312fab63cc4SDoug Rabson
313fab63cc4SDoug Rabson	    if (directory is sticky
314fab63cc4SDoug Rabson		&& cred->cr_uid != 0
315fab63cc4SDoug Rabson		&& cred->cr_uid != owner of dvp
316fab63cc4SDoug Rabson		&& owner of vp != cred->cr_uid) {
317fab63cc4SDoug Rabson		vput(vp);
318fab63cc4SDoug Rabson		return EPERM;
319fab63cc4SDoug Rabson	    }
320fab63cc4SDoug Rabson	    *vpp = vp;
321fab63cc4SDoug Rabson	    if (!lockparent)
322fab63cc4SDoug Rabson		VOP_UNLOCK(dvp);
323fab63cc4SDoug Rabson
324fab63cc4SDoug Rabson	    return 0;
325fab63cc4SDoug Rabson	}
326fab63cc4SDoug Rabson
327fab63cc4SDoug Rabson	/*
328fab63cc4SDoug Rabson	 * If rewriting (RENAME), return the inode and the
329fab63cc4SDoug Rabson	 * information required to rewrite the present directory
330fab63cc4SDoug Rabson	 * Must get inode of directory entry to verify it's a
331fab63cc4SDoug Rabson	 * regular file, or empty directory.
332fab63cc4SDoug Rabson	 */
333fab63cc4SDoug Rabson	if (nameiop == RENAME && wantparent && islastcn) {
334fab63cc4SDoug Rabson	    error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc);
335fab63cc4SDoug Rabson	    if (error)
336fab63cc4SDoug Rabson		return (error);
337fab63cc4SDoug Rabson
338fab63cc4SDoug Rabson	    /*
339fab63cc4SDoug Rabson	     * Check for "."
340fab63cc4SDoug Rabson	     */
341fab63cc4SDoug Rabson	    if (found entry is same as dvp)
342fab63cc4SDoug Rabson		return EISDIR;
343fab63cc4SDoug Rabson
344fab63cc4SDoug Rabson	    error = VFS_VGET(dvp->v_mount, ..., &vp);
345fab63cc4SDoug Rabson	    if (error)
346fab63cc4SDoug Rabson		return error;
347fab63cc4SDoug Rabson	    *vpp = vp;
348fab63cc4SDoug Rabson	    /*
349fab63cc4SDoug Rabson	     * Save the name for use in VOP_RENAME later.
350fab63cc4SDoug Rabson	     */
351fab63cc4SDoug Rabson	    cnp->cn_flags |= SAVENAME;
352fab63cc4SDoug Rabson	    if (!lockparent)
353fab63cc4SDoug Rabson		VOP_UNLOCK(dvp);
354fab63cc4SDoug Rabson
355fab63cc4SDoug Rabson	    return 0;
356fab63cc4SDoug Rabson	}
357fab63cc4SDoug Rabson
358fab63cc4SDoug Rabson	/*
359fab63cc4SDoug Rabson	 * Step through the translation in the name.  We do not `vput' the
360fab63cc4SDoug Rabson	 * directory because we may need it again if a symbolic link
361fab63cc4SDoug Rabson	 * is relative to the current directory.  Instead we save it
362fab63cc4SDoug Rabson	 * unlocked as "pdp".  We must get the target inode before unlocking
363fab63cc4SDoug Rabson	 * the directory to insure that the inode will not be removed
364fab63cc4SDoug Rabson	 * before we get it.  We prevent deadlock by always fetching
365fab63cc4SDoug Rabson	 * inodes from the root, moving down the directory tree. Thus
366fab63cc4SDoug Rabson	 * when following backward pointers ".." we must unlock the
367fab63cc4SDoug Rabson	 * parent directory before getting the requested directory.
368fab63cc4SDoug Rabson	 * There is a potential race condition here if both the current
369fab63cc4SDoug Rabson	 * and parent directories are removed before the VFS_VGET for the
370fab63cc4SDoug Rabson	 * inode associated with ".." returns.  We hope that this occurs
371fab63cc4SDoug Rabson	 * infrequently since we cannot avoid this race condition without
372fab63cc4SDoug Rabson	 * implementing a sophisticated deadlock detection algorithm.
373fab63cc4SDoug Rabson	 * Note also that this simple deadlock detection scheme will not
374fab63cc4SDoug Rabson	 * work if the file system has any hard links other than ".."
375fab63cc4SDoug Rabson	 * that point backwards in the directory structure.
376fab63cc4SDoug Rabson	 */
377fab63cc4SDoug Rabson	if (flags & ISDOTDOT) {
378fab63cc4SDoug Rabson	    VOP_UNLOCK(dvp);	/* race to get the inode */
379fab63cc4SDoug Rabson	    error = VFS_VGET(dvp->v_mount, ..., &vp);
380fab63cc4SDoug Rabson	    if (error) {
381fab63cc4SDoug Rabson		VOP_LOCK(dvp);
382fab63cc4SDoug Rabson		return (error);
383fab63cc4SDoug Rabson	    }
384fab63cc4SDoug Rabson	    if (lockparent && islastcn) {
385fab63cc4SDoug Rabson		error = VOP_LOCK(dvp);
386fab63cc4SDoug Rabson		if (error) {
387fab63cc4SDoug Rabson		    vput(vp);
388fab63cc4SDoug Rabson		    return error;
389fab63cc4SDoug Rabson		}
390fab63cc4SDoug Rabson	    }
391fab63cc4SDoug Rabson	    *vpp = vp;
392fab63cc4SDoug Rabson	} else if (found entry is same as dvp) {
393fab63cc4SDoug Rabson	    VREF(dvp);	/* we want ourself, ie "." */
394fab63cc4SDoug Rabson	    *vpp = dvp;
395fab63cc4SDoug Rabson	} else {
396fab63cc4SDoug Rabson	    error = VFS_VGET(dvp->v_mount, ..., &vp);
397fab63cc4SDoug Rabson	    if (error)
398fab63cc4SDoug Rabson		return (error);
399fab63cc4SDoug Rabson	    if (!lockparent || !islastcn)
400fab63cc4SDoug Rabson		VOP_UNLOCK(dvp);
401fab63cc4SDoug Rabson	    *vpp = vp;
402fab63cc4SDoug Rabson	}
403fab63cc4SDoug Rabson
404fab63cc4SDoug Rabson	/*
405fab63cc4SDoug Rabson	 * Insert name into cache if appropriate.
406fab63cc4SDoug Rabson	 */
407fab63cc4SDoug Rabson	if (cnp->cn_flags & MAKEENTRY)
408fab63cc4SDoug Rabson	    cache_enter(dvp, *vpp, cnp);
409fab63cc4SDoug Rabson	return (0);
410fab63cc4SDoug Rabson    }
411fab63cc4SDoug Rabson}
412fab63cc4SDoug Rabson.Ed
413fab63cc4SDoug Rabson.Sh ERRORS
414eaa8b244SMike Pritchard.Bl -tag -width Er
415fab63cc4SDoug Rabson.It Bq Er ENOTDIR
416fab63cc4SDoug RabsonThe vnode
417fab63cc4SDoug Rabson.Fa dvp
418fab63cc4SDoug Rabsondoes not represent a directory.
419fab63cc4SDoug Rabson.It Bq Er ENOENT
420fab63cc4SDoug RabsonThe component
421fab63cc4SDoug Rabson.Fa dvp
422fab63cc4SDoug Rabsonwas not found in this directory.
42322301c4bSBruce Evans.It Bq Er EACCES
424fab63cc4SDoug Rabsonaccess for the specified operation is denied.
425fab63cc4SDoug Rabson.It Bq Er EJUSTRETURN
426fab63cc4SDoug Rabsona
427fab63cc4SDoug Rabson.Dv CREATE
428fab63cc4SDoug Rabsonor
429fab63cc4SDoug Rabson.Dv RENAME
430fab63cc4SDoug Rabsonoperation would be successful
431fab63cc4SDoug Rabson.El
432fab63cc4SDoug Rabson.Sh SEE ALSO
433bceb8aedSWolfram Schneider.Xr VOP_ABORTOP 9 ,
434fab63cc4SDoug Rabson.Xr VOP_ACCESS 9 ,
435fab63cc4SDoug Rabson.Xr VOP_CREATE 9 ,
436fab63cc4SDoug Rabson.Xr VOP_MKDIR 9 ,
437bceb8aedSWolfram Schneider.Xr VOP_MKNOD 9 ,
438fab63cc4SDoug Rabson.Xr VOP_RENAME 9 ,
439bceb8aedSWolfram Schneider.Xr VOP_SYMLINK 9
440fab63cc4SDoug Rabson.Sh HISTORY
441fab63cc4SDoug RabsonThe function
442fab63cc4SDoug Rabson.Nm
443eaa8b244SMike Pritchardappeared in
444eaa8b244SMike Pritchard.Bx 4.3 .
445fab63cc4SDoug Rabson.Sh SEE ALSO
446fab63cc4SDoug Rabson.Xr vnode 9
447fab63cc4SDoug Rabson.Sh AUTHORS
448aaf1f16eSPhilippe CharnierThis man page was written by
449aaf1f16eSPhilippe Charnier.An Doug Rabson ,
450aaf1f16eSPhilippe Charnierwith some text from comments in
451aaf1f16eSPhilippe Charnier.Pa ufs_lookup.c .
452