1 /* $NetBSD: adlookup.c,v 1.5 2004/02/24 15:23:16 wiz Exp $ */
2
3 /*
4 * Copyright (c) 1994 Christian E. Hopps
5 * Copyright (c) 1996 Matthias Scheler
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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
21 *
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.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: adlookup.c,v 1.5 2004/02/24 15:23:16 wiz Exp $");
36
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>
42 #include <sys/time.h>
43 #include <sys/queue.h>
44 #include <fs/adosfs/adosfs.h>
45
46 #ifdef ADOSFS_EXACTMATCH
47 #define strmatch(s1, l1, s2, l2, i) \
48 ((l1) == (l2) && memcmp((s1), (s2), (l1)) == 0)
49 #else
50 #define strmatch(s1, l1, s2, l2, i) \
51 ((l1) == (l2) && adoscaseequ((s1), (s2), (l1), (i)))
52 #endif
53
54 /*
55 * adosfs lookup. enters with:
56 * pvp (parent vnode) referenced and locked.
57 * exit with:
58 * target vp referenced and locked.
59 * unlock pvp unless LOCKPARENT and at end of search.
60 * special cases:
61 * pvp == vp, just ref pvp, pvp already holds a ref and lock from
62 * caller, this will not occur with RENAME or CREATE.
63 * LOOKUP always unlocks parent if last element. (not now!?!?)
64 */
65 int
66 adosfs_lookup(v)
67 void *v;
68 {
69 struct vop_lookup_args /* {
70 struct vnode *a_dvp;
71 struct vnode **a_vpp;
72 struct componentname *a_cnp;
73 } */ *sp = v;
74 int nameiop, last, lockp, wantp, flags, error, nocache, i;
75 struct componentname *cnp;
76 struct vnode **vpp; /* place to store result */
77 struct anode *ap; /* anode to find */
78 struct vnode *vdp; /* vnode of search dir */
79 struct anode *adp; /* anode of search dir */
80 struct ucred *ucp; /* lookup credentials */
81 u_long bn, plen, hval;
82 const u_char *pelt;
83
84 #ifdef ADOSFS_DIAGNOSTIC
85 advopprint(sp);
86 #endif
87 cnp = sp->a_cnp;
88 vdp = sp->a_dvp;
89 adp = VTOA(vdp);
90 vpp = sp->a_vpp;
91 *vpp = NULL;
92 ucp = cnp->cn_cred;
93 nameiop = cnp->cn_nameiop;
94 cnp->cn_flags &= ~PDIRUNLOCK;
95 flags = cnp->cn_flags;
96 last = flags & ISLASTCN;
97 lockp = flags & LOCKPARENT;
98 wantp = flags & (LOCKPARENT | WANTPARENT);
99 pelt = (const u_char *)cnp->cn_nameptr;
100 plen = cnp->cn_namelen;
101 nocache = 0;
102
103 /*
104 * Check accessiblity of directory.
105 */
106 if ((error = VOP_ACCESS(vdp, VEXEC, ucp, cnp->cn_proc)) != 0)
107 return (error);
108
109 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
110 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
111 return (EROFS);
112
113 /*
114 * Before tediously performing a linear scan of the directory,
115 * check the name cache to see if the directory/name pair
116 * we are looking for is known already.
117 */
118 if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
119 return (error);
120
121 /*
122 * fake a '.'
123 */
124 if (plen == 1 && pelt[0] == '.') {
125 /* see special cases in prologue. */
126 *vpp = vdp;
127 goto found;
128 }
129 /*
130 * fake a ".."
131 */
132 if (flags & ISDOTDOT) {
133 if (vdp->v_type == VDIR && (vdp->v_flag & VROOT))
134 panic("adosfs .. attempted through root");
135 /*
136 * cannot get `..' while `vdp' is locked
137 * e.g. procA holds lock on `..' and waits for `vdp'
138 * we wait for `..' and hold lock on `vdp'. deadlock.
139 * because `vdp' may have been achieved through symlink
140 * fancy detection code that decreases the race
141 * window size is not reasonably possible.
142 *
143 * basically unlock the parent, try and lock the child (..)
144 * if that fails relock the parent (ignoring error) and
145 * fail. Otherwise we have the child (..) if this is the
146 * last and the caller requested LOCKPARENT, attempt to
147 * relock the parent. If that fails unlock the child (..)
148 * and fail. Otherwise we have succeded.
149 *
150 */
151 VOP_UNLOCK(vdp, 0); /* race */
152 cnp->cn_flags |= PDIRUNLOCK;
153 if ((error = VFS_VGET(vdp->v_mount,
154 (ino_t)adp->pblock, vpp)) != 0) {
155 if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY) == 0)
156 cnp->cn_flags &= ~PDIRUNLOCK;
157 } else if (last && lockp ) {
158 if ((error = vn_lock(vdp, LK_EXCLUSIVE))) {
159 vput(*vpp);
160 } else {
161 cnp->cn_flags &= ~PDIRUNLOCK;
162 }
163 }
164 if (error) {
165 *vpp = NULL;
166 return (error);
167 }
168 goto found_lockdone;
169 }
170
171 /*
172 * hash the name and grab the first block in chain
173 * then walk the chain. if chain has not been fully
174 * walked before, track the count in `tabi'
175 */
176 hval = adoshash(pelt, plen, adp->ntabent, IS_INTER(adp->amp));
177 bn = adp->tab[hval];
178 i = min(adp->tabi[hval], 0);
179 while (bn != 0) {
180 if ((error = VFS_VGET(vdp->v_mount, (ino_t)bn, vpp)) != 0) {
181 #ifdef ADOSFS_DIAGNOSTIC
182 printf("[aget] %d)", error);
183 #endif
184 /* XXX check to unlock parent possibly? */
185 return(error);
186 }
187 ap = VTOA(*vpp);
188 if (i <= 0) {
189 if (--i < adp->tabi[hval])
190 adp->tabi[hval] = i;
191 /*
192 * last header in chain lock count down by
193 * negating it to positive
194 */
195 if (ap->hashf == 0) {
196 #ifdef DEBUG
197 if (i != adp->tabi[hval])
198 panic("adlookup: wrong chain count");
199 #endif
200 adp->tabi[hval] = -adp->tabi[hval];
201 }
202 }
203 if (strmatch(pelt, plen, ap->name, strlen(ap->name),
204 IS_INTER(adp->amp)))
205 goto found;
206 bn = ap->hashf;
207 vput(*vpp);
208 }
209 *vpp = NULL;
210 /*
211 * not found
212 */
213 if ((nameiop == CREATE || nameiop == RENAME) && last) {
214
215 if (vdp->v_mount->mnt_flag & MNT_RDONLY)
216 return (EROFS);
217
218 if ((error = VOP_ACCESS(vdp, VWRITE, ucp, cnp->cn_proc)) != 0) {
219 #ifdef ADOSFS_DIAGNOSTIC
220 printf("[VOP_ACCESS] %d)", error);
221 #endif
222 return (error);
223 }
224 if (lockp == 0) {
225 VOP_UNLOCK(vdp, 0);
226 cnp->cn_flags |= PDIRUNLOCK;
227 }
228 cnp->cn_nameiop |= SAVENAME;
229 #ifdef ADOSFS_DIAGNOSTIC
230 printf("EJUSTRETURN)");
231 #endif
232 return(EJUSTRETURN);
233 }
234 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
235 cache_enter(vdp, NULL, cnp);
236 #ifdef ADOSFS_DIAGNOSTIC
237 printf("ENOENT)");
238 #endif
239 return(ENOENT);
240
241 found:
242 if (nameiop == DELETE && last) {
243 if ((error = VOP_ACCESS(vdp, VWRITE, ucp, cnp->cn_proc)) != 0) {
244 if (vdp != *vpp)
245 vput(*vpp);
246 *vpp = NULL;
247 return (error);
248 }
249 nocache = 1;
250 }
251 if (nameiop == RENAME && wantp && last) {
252 if (vdp == *vpp)
253 return(EISDIR);
254 if ((error = VOP_ACCESS(vdp, VWRITE, ucp, cnp->cn_proc)) != 0) {
255 vput(*vpp);
256 *vpp = NULL;
257 return (error);
258 }
259 cnp->cn_flags |= SAVENAME;
260 nocache = 1;
261 }
262 if (vdp == *vpp)
263 VREF(vdp);
264 else if (lockp == 0 || last == 0) {
265 VOP_UNLOCK(vdp, 0);
266 cnp->cn_flags |= PDIRUNLOCK;
267 }
268 found_lockdone:
269 if ((cnp->cn_flags & MAKEENTRY) && nocache == 0)
270 cache_enter(vdp, *vpp, cnp);
271
272 #ifdef ADOSFS_DIAGNOSTIC
273 printf("0)\n");
274 #endif
275 return(0);
276 }
Cache object: ea757763d6125a160e9ff9114f0e0fab
|