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