umap_subr.c revision 1.2 1 /* $NetBSD: umap_subr.c,v 1.2 1994/06/29 06:35:11 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software donated to Berkeley by
8 * Jan-Simon Pendry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * from: Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp
39 * @(#)umap_subr.c 8.6 (Berkeley) 1/26/94
40 */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/time.h>
45 #include <sys/types.h>
46 #include <sys/vnode.h>
47 #include <sys/mount.h>
48 #include <sys/namei.h>
49 #include <sys/malloc.h>
50 #include <miscfs/umapfs/umap.h>
51
52 #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
53 #define NUMAPNODECACHE 16
54 #define UMAP_NHASH(vp) ((((u_long) vp)>>LOG2_SIZEVNODE) & (NUMAPNODECACHE-1))
55
56 /*
57 * Null layer cache:
58 * Each cache entry holds a reference to the target vnode
59 * along with a pointer to the alias vnode. When an
60 * entry is added the target vnode is VREF'd. When the
61 * alias is removed the target vnode is vrele'd.
62 */
63
64 /*
65 * Cache head
66 */
67 struct umap_node_cache {
68 struct umap_node *ac_forw;
69 struct umap_node *ac_back;
70 };
71
72 static struct umap_node_cache umap_node_cache[NUMAPNODECACHE];
73
74 /*
75 * Initialise cache headers
76 */
77 umapfs_init()
78 {
79 struct umap_node_cache *ac;
80 #ifdef UMAPFS_DIAGNOSTIC
81 printf("umapfs_init\n"); /* printed during system boot */
82 #endif
83
84 for (ac = umap_node_cache; ac < umap_node_cache + NUMAPNODECACHE; ac++)
85 ac->ac_forw = ac->ac_back = (struct umap_node *) ac;
86 }
87
88 /*
89 * Compute hash list for given target vnode
90 */
91 static struct umap_node_cache *
92 umap_node_hash(targetvp)
93 struct vnode *targetvp;
94 {
95
96 return (&umap_node_cache[UMAP_NHASH(targetvp)]);
97 }
98
99 /*
100 * umap_findid is called by various routines in umap_vnodeops.c to
101 * find a user or group id in a map.
102 */
103 static u_long
104 umap_findid(id, map, nentries)
105 u_long id;
106 u_long map[][2];
107 int nentries;
108 {
109 int i;
110
111 /* Find uid entry in map */
112 i = 0;
113 while ((i<nentries) && ((map[i][0]) != id))
114 i++;
115
116 if (i < nentries)
117 return (map[i][1]);
118 else
119 return (-1);
120
121 }
122
123 /*
124 * umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to
125 * find a user or group id in a map, in reverse.
126 */
127 u_long
128 umap_reverse_findid(id, map, nentries)
129 u_long id;
130 u_long map[][2];
131 int nentries;
132 {
133 int i;
134
135 /* Find uid entry in map */
136 i = 0;
137 while ((i<nentries) && ((map[i][1]) != id))
138 i++;
139
140 if (i < nentries)
141 return (map[i][0]);
142 else
143 return (-1);
144
145 }
146
147 /*
148 * Return alias for target vnode if already exists, else 0.
149 */
150 static struct vnode *
151 umap_node_find(mp, targetvp)
152 struct mount *mp;
153 struct vnode *targetvp;
154 {
155 struct umap_node_cache *hd;
156 struct umap_node *a;
157 struct vnode *vp;
158
159 #ifdef UMAPFS_DIAGNOSTIC
160 printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp);
161 #endif
162
163 /*
164 * Find hash base, and then search the (two-way) linked
165 * list looking for a umap_node structure which is referencing
166 * the target vnode. If found, the increment the umap_node
167 * reference count (but NOT the target vnode's VREF counter).
168 */
169 hd = umap_node_hash(targetvp);
170
171 loop:
172 for (a = hd->ac_forw; a != (struct umap_node *) hd; a = a->umap_forw) {
173 if (a->umap_lowervp == targetvp &&
174 a->umap_vnode->v_mount == mp) {
175 vp = UMAPTOV(a);
176 /*
177 * We need vget for the VXLOCK
178 * stuff, but we don't want to lock
179 * the lower node.
180 */
181 if (vget(vp, 0)) {
182 #ifdef UMAPFS_DIAGNOSTIC
183 printf ("umap_node_find: vget failed.\n");
184 #endif
185 goto loop;
186 }
187 return (vp);
188 }
189 }
190
191 #ifdef UMAPFS_DIAGNOSTIC
192 printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp);
193 #endif
194
195 return (0);
196 }
197
198 /*
199 * Make a new umap_node node.
200 * Vp is the alias vnode, lofsvp is the target vnode.
201 * Maintain a reference to (targetvp).
202 */
203 static int
204 umap_node_alloc(mp, lowervp, vpp)
205 struct mount *mp;
206 struct vnode *lowervp;
207 struct vnode **vpp;
208 {
209 struct umap_node_cache *hd;
210 struct umap_node *xp;
211 struct vnode *othervp, *vp;
212 int error;
213
214 if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, vpp))
215 return (error);
216 vp = *vpp;
217
218 MALLOC(xp, struct umap_node *, sizeof(struct umap_node),
219 M_TEMP, M_WAITOK);
220 vp->v_type = lowervp->v_type;
221 xp->umap_vnode = vp;
222 vp->v_data = xp;
223 xp->umap_lowervp = lowervp;
224 /*
225 * Before we insert our new node onto the hash chains,
226 * check to see if someone else has beaten us to it.
227 * (We could have slept in MALLOC.)
228 */
229 if (othervp = umap_node_find(lowervp)) {
230 FREE(xp, M_TEMP);
231 vp->v_type = VBAD; /* node is discarded */
232 vp->v_usecount = 0; /* XXX */
233 *vpp = othervp;
234 return (0);
235 }
236 VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */
237 hd = umap_node_hash(lowervp);
238 insque(xp, hd);
239 return (0);
240 }
241
242
243 /*
244 * Try to find an existing umap_node vnode refering
245 * to it, otherwise make a new umap_node vnode which
246 * contains a reference to the target vnode.
247 */
248 int
249 umap_node_create(mp, targetvp, newvpp)
250 struct mount *mp;
251 struct vnode *targetvp;
252 struct vnode **newvpp;
253 {
254 struct vnode *aliasvp;
255
256 if (aliasvp = umap_node_find(mp, targetvp)) {
257 /*
258 * Take another reference to the alias vnode
259 */
260 #ifdef UMAPFS_DIAGNOSTIC
261 vprint("umap_node_create: exists", ap->umap_vnode);
262 #endif
263 /* VREF(aliasvp); */
264 } else {
265 int error;
266
267 /*
268 * Get new vnode.
269 */
270 #ifdef UMAPFS_DIAGNOSTIC
271 printf("umap_node_create: create new alias vnode\n");
272 #endif
273 /*
274 * Make new vnode reference the umap_node.
275 */
276 if (error = umap_node_alloc(mp, targetvp, &aliasvp))
277 return (error);
278
279 /*
280 * aliasvp is already VREF'd by getnewvnode()
281 */
282 }
283
284 vrele(targetvp);
285
286 #ifdef UMAPFS_DIAGNOSTIC
287 vprint("umap_node_create: alias", aliasvp);
288 vprint("umap_node_create: target", targetvp);
289 #endif
290
291 *newvpp = aliasvp;
292 return (0);
293 }
294
295 #ifdef UMAPFS_DIAGNOSTIC
296 int umap_checkvp_barrier = 1;
297 struct vnode *
298 umap_checkvp(vp, fil, lno)
299 struct vnode *vp;
300 char *fil;
301 int lno;
302 {
303 struct umap_node *a = VTOUMAP(vp);
304 #if 0
305 /*
306 * Can't do this check because vop_reclaim runs
307 * with funny vop vector.
308 */
309 if (vp->v_op != umap_vnodeop_p) {
310 printf ("umap_checkvp: on non-umap-node\n");
311 while (umap_checkvp_barrier) /*WAIT*/ ;
312 panic("umap_checkvp");
313 }
314 #endif
315 if (a->umap_lowervp == NULL) {
316 /* Should never happen */
317 int i; u_long *p;
318 printf("vp = %x, ZERO ptr\n", vp);
319 for (p = (u_long *) a, i = 0; i < 8; i++)
320 printf(" %x", p[i]);
321 printf("\n");
322 /* wait for debugger */
323 while (umap_checkvp_barrier) /*WAIT*/ ;
324 panic("umap_checkvp");
325 }
326 if (a->umap_lowervp->v_usecount < 1) {
327 int i; u_long *p;
328 printf("vp = %x, unref'ed lowervp\n", vp);
329 for (p = (u_long *) a, i = 0; i < 8; i++)
330 printf(" %x", p[i]);
331 printf("\n");
332 /* wait for debugger */
333 while (umap_checkvp_barrier) /*WAIT*/ ;
334 panic ("umap with unref'ed lowervp");
335 }
336 #if 0
337 printf("umap %x/%d -> %x/%d [%s, %d]\n",
338 a->umap_vnode, a->umap_vnode->v_usecount,
339 a->umap_lowervp, a->umap_lowervp->v_usecount,
340 fil, lno);
341 #endif
342 return (a->umap_lowervp);
343 }
344 #endif
345
346 /* umap_mapids maps all of the ids in a credential, both user and group. */
347
348 void
349 umap_mapids(v_mount, credp)
350 struct mount *v_mount;
351 struct ucred *credp;
352 {
353 int i, unentries, gnentries;
354 uid_t uid, *usermap;
355 gid_t gid, *groupmap;
356
357 unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries;
358 usermap = &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]);
359 gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries;
360 groupmap = &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]);
361
362 /* Find uid entry in map */
363
364 uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries);
365
366 if (uid != -1)
367 credp->cr_uid = uid;
368 else
369 credp->cr_uid = (uid_t) NOBODY;
370
371 #ifdef notdef
372 /* cr_gid is the same as cr_groups[0] in 4BSD */
373
374 /* Find gid entry in map */
375
376 gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries);
377
378 if (gid != -1)
379 credp->cr_gid = gid;
380 else
381 credp->cr_gid = NULLGROUP;
382 #endif
383
384 /* Now we must map each of the set of groups in the cr_groups
385 structure. */
386
387 i = 0;
388 while (credp->cr_groups[i] != 0) {
389 gid = (gid_t) umap_findid(credp->cr_groups[i],
390 groupmap, gnentries);
391
392 if (gid != -1)
393 credp->cr_groups[i++] = gid;
394 else
395 credp->cr_groups[i++] = NULLGROUP;
396 }
397 }
398