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