1 /* $NetBSD: adlookup.c,v 1.12 2009/03/14 21:04:23 dsl Exp $ */
4 * Copyright (c) 1994 Christian E. Hopps
5 * Copyright (c) 1996 Matthias Scheler
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Christian E. Hopps.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: adlookup.c,v 1.12 2009/03/14 21:04:23 dsl Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/vnode.h>
40 #include <sys/namei.h>
41 #include <sys/mount.h>
43 #include <sys/queue.h>
44 #include <fs/adosfs/adosfs.h>
46 #ifdef ADOSFS_EXACTMATCH
47 #define strmatch(s1, l1, s2, l2, i) \
48 ((l1) == (l2) && memcmp((s1), (s2), (l1)) == 0)
50 #define strmatch(s1, l1, s2, l2, i) \
51 ((l1) == (l2) && adoscaseequ((s1), (s2), (l1), (i)))
55 * adosfs lookup. enters with:
56 * pvp (parent vnode) referenced and locked.
58 * target vp referenced and locked.
61 * pvp == vp, just ref pvp, pvp already holds a ref and lock from
62 * caller, this will not occur with RENAME or CREATE.
65 adosfs_lookup(void *v
)
67 struct vop_lookup_args
/* {
70 struct componentname *a_cnp;
72 int nameiop
, last
, flags
, error
, nocache
, i
;
73 struct componentname
*cnp
;
74 struct vnode
**vpp
; /* place to store result */
75 struct anode
*ap
; /* anode to find */
76 struct vnode
*vdp
; /* vnode of search dir */
77 struct anode
*adp
; /* anode of search dir */
78 kauth_cred_t ucp
; /* lookup credentials */
79 u_long bn
, plen
, hval
;
82 #ifdef ADOSFS_DIAGNOSTIC
91 nameiop
= cnp
->cn_nameiop
;
92 flags
= cnp
->cn_flags
;
93 last
= flags
& ISLASTCN
;
94 pelt
= (const u_char
*)cnp
->cn_nameptr
;
95 plen
= cnp
->cn_namelen
;
99 * Check accessiblity of directory.
101 if ((error
= VOP_ACCESS(vdp
, VEXEC
, ucp
)) != 0)
104 if ((flags
& ISLASTCN
) && (vdp
->v_mount
->mnt_flag
& MNT_RDONLY
) &&
105 (cnp
->cn_nameiop
== DELETE
|| cnp
->cn_nameiop
== RENAME
))
109 * Before tediously performing a linear scan of the directory,
110 * check the name cache to see if the directory/name pair
111 * we are looking for is known already.
113 if ((error
= cache_lookup(vdp
, vpp
, cnp
)) >= 0)
119 if (plen
== 1 && pelt
[0] == '.') {
120 /* see special cases in prologue. */
127 if (flags
& ISDOTDOT
) {
128 if (vdp
->v_type
== VDIR
&& (vdp
->v_vflag
& VV_ROOT
))
129 panic("adosfs .. attempted through root");
131 * cannot get `..' while `vdp' is locked
132 * e.g. procA holds lock on `..' and waits for `vdp'
133 * we wait for `..' and hold lock on `vdp'. deadlock.
134 * because `vdp' may have been achieved through symlink
135 * fancy detection code that decreases the race
136 * window size is not reasonably possible.
138 * basically unlock the parent, try and lock the child (..)
139 * if that fails relock the parent (ignoring error) and
140 * fail. Otherwise we have the child (..), attempt to
141 * relock the parent. If that fails unlock the child (..)
142 * and fail. Otherwise we have succeded.
145 VOP_UNLOCK(vdp
, 0); /* race */
146 error
= VFS_VGET(vdp
->v_mount
, (ino_t
)adp
->pblock
, vpp
);
147 vn_lock(vdp
, LK_EXCLUSIVE
| LK_RETRY
);
156 * hash the name and grab the first block in chain
157 * then walk the chain. if chain has not been fully
158 * walked before, track the count in `tabi'
160 hval
= adoshash(pelt
, plen
, adp
->ntabent
, IS_INTER(adp
->amp
));
162 i
= min(adp
->tabi
[hval
], 0);
164 if ((error
= VFS_VGET(vdp
->v_mount
, (ino_t
)bn
, vpp
166 #ifdef ADOSFS_DIAGNOSTIC
167 printf("[aget] %d)", error
);
173 if (--i
< adp
->tabi
[hval
])
176 * last header in chain lock count down by
177 * negating it to positive
179 if (ap
->hashf
== 0) {
181 if (i
!= adp
->tabi
[hval
])
182 panic("adlookup: wrong chain count");
184 adp
->tabi
[hval
] = -adp
->tabi
[hval
];
187 if (strmatch(pelt
, plen
, ap
->name
, strlen(ap
->name
),
197 if ((nameiop
== CREATE
|| nameiop
== RENAME
) && last
) {
199 if (vdp
->v_mount
->mnt_flag
& MNT_RDONLY
)
202 if ((error
= VOP_ACCESS(vdp
, VWRITE
, ucp
)) != 0) {
203 #ifdef ADOSFS_DIAGNOSTIC
204 printf("[VOP_ACCESS] %d)", error
);
208 cnp
->cn_nameiop
|= SAVENAME
;
209 #ifdef ADOSFS_DIAGNOSTIC
210 printf("EJUSTRETURN)");
214 if ((cnp
->cn_flags
& MAKEENTRY
) && nameiop
!= CREATE
)
215 cache_enter(vdp
, NULL
, cnp
);
216 #ifdef ADOSFS_DIAGNOSTIC
222 if (nameiop
== DELETE
&& last
) {
223 if ((error
= VOP_ACCESS(vdp
, VWRITE
, ucp
)) != 0) {
231 if (nameiop
== RENAME
&& last
) {
234 if ((error
= VOP_ACCESS(vdp
, VWRITE
, ucp
)) != 0) {
239 cnp
->cn_flags
|= SAVENAME
;
245 if ((cnp
->cn_flags
& MAKEENTRY
) && nocache
== 0)
246 cache_enter(vdp
, *vpp
, cnp
);
248 #ifdef ADOSFS_DIAGNOSTIC