xref: /original-bsd/sys/miscfs/umapfs/umap_subr.c (revision 3b235ced)
1 /*
2  * Copyright (c) 1992, 1993
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  * %sccs.include.redist.c%
9  *
10  *	@(#)umap_subr.c	8.6 (Berkeley) 01/26/94
11  *
12  * $Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
13  */
14 
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <sys/vnode.h>
20 #include <sys/mount.h>
21 #include <sys/namei.h>
22 #include <sys/malloc.h>
23 #include <miscfs/umapfs/umap.h>
24 
25 #define LOG2_SIZEVNODE 7		/* log2(sizeof struct vnode) */
26 #define	NUMAPNODECACHE 16
27 #define	UMAP_NHASH(vp) ((((u_long) vp)>>LOG2_SIZEVNODE) & (NUMAPNODECACHE-1))
28 
29 /*
30  * Null layer cache:
31  * Each cache entry holds a reference to the target vnode
32  * along with a pointer to the alias vnode.  When an
33  * entry is added the target vnode is VREF'd.  When the
34  * alias is removed the target vnode is vrele'd.
35  */
36 
37 /*
38  * Cache head
39  */
40 struct umap_node_cache {
41 	struct umap_node	*ac_forw;
42 	struct umap_node	*ac_back;
43 };
44 
45 static struct umap_node_cache umap_node_cache[NUMAPNODECACHE];
46 
47 /*
48  * Initialise cache headers
49  */
50 umapfs_init()
51 {
52 	struct umap_node_cache *ac;
53 #ifdef UMAPFS_DIAGNOSTIC
54 	printf("umapfs_init\n");		/* printed during system boot */
55 #endif
56 
57 	for (ac = umap_node_cache; ac < umap_node_cache + NUMAPNODECACHE; ac++)
58 		ac->ac_forw = ac->ac_back = (struct umap_node *) ac;
59 }
60 
61 /*
62  * Compute hash list for given target vnode
63  */
64 static struct umap_node_cache *
65 umap_node_hash(targetvp)
66 	struct vnode *targetvp;
67 {
68 
69 	return (&umap_node_cache[UMAP_NHASH(targetvp)]);
70 }
71 
72 /*
73  * umap_findid is called by various routines in umap_vnodeops.c to
74  * find a user or group id in a map.
75  */
76 static u_long
77 umap_findid(id, map, nentries)
78 	u_long id;
79 	u_long map[][2];
80 	int nentries;
81 {
82 	int i;
83 
84 	/* Find uid entry in map */
85 	i = 0;
86 	while ((i<nentries) && ((map[i][0]) != id))
87 		i++;
88 
89 	if (i < nentries)
90 		return (map[i][1]);
91 	else
92 		return (-1);
93 
94 }
95 
96 /*
97  * umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to
98  * find a user or group id in a map, in reverse.
99  */
100 u_long
101 umap_reverse_findid(id, map, nentries)
102 	u_long id;
103 	u_long map[][2];
104 	int nentries;
105 {
106 	int i;
107 
108 	/* Find uid entry in map */
109 	i = 0;
110 	while ((i<nentries) && ((map[i][1]) != id))
111 		i++;
112 
113 	if (i < nentries)
114 		return (map[i][0]);
115 	else
116 		return (-1);
117 
118 }
119 
120 /*
121  * Return alias for target vnode if already exists, else 0.
122  */
123 static struct vnode *
124 umap_node_find(mp, targetvp)
125 	struct mount *mp;
126 	struct vnode *targetvp;
127 {
128 	struct umap_node_cache *hd;
129 	struct umap_node *a;
130 	struct vnode *vp;
131 
132 #ifdef UMAPFS_DIAGNOSTIC
133 	printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp);
134 #endif
135 
136 	/*
137 	 * Find hash base, and then search the (two-way) linked
138 	 * list looking for a umap_node structure which is referencing
139 	 * the target vnode.  If found, the increment the umap_node
140 	 * reference count (but NOT the target vnode's VREF counter).
141 	 */
142 	hd = umap_node_hash(targetvp);
143 
144  loop:
145 	for (a = hd->ac_forw; a != (struct umap_node *) hd; a = a->umap_forw) {
146 		if (a->umap_lowervp == targetvp &&
147 		    a->umap_vnode->v_mount == mp) {
148 			vp = UMAPTOV(a);
149 			/*
150 			 * We need vget for the VXLOCK
151 			 * stuff, but we don't want to lock
152 			 * the lower node.
153 			 */
154 			if (vget(vp, 0)) {
155 #ifdef UMAPFS_DIAGNOSTIC
156 				printf ("umap_node_find: vget failed.\n");
157 #endif
158 				goto loop;
159 			}
160 			return (vp);
161 		}
162 	}
163 
164 #ifdef UMAPFS_DIAGNOSTIC
165 	printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp);
166 #endif
167 
168 	return (0);
169 }
170 
171 /*
172  * Make a new umap_node node.
173  * Vp is the alias vnode, lofsvp is the target vnode.
174  * Maintain a reference to (targetvp).
175  */
176 static int
177 umap_node_alloc(mp, lowervp, vpp)
178 	struct mount *mp;
179 	struct vnode *lowervp;
180 	struct vnode **vpp;
181 {
182 	struct umap_node_cache *hd;
183 	struct umap_node *xp;
184 	struct vnode *othervp, *vp;
185 	int error;
186 
187 	if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, vpp))
188 		return (error);
189 	vp = *vpp;
190 
191 	MALLOC(xp, struct umap_node *, sizeof(struct umap_node),
192 	    M_TEMP, M_WAITOK);
193 	vp->v_type = lowervp->v_type;
194 	xp->umap_vnode = vp;
195 	vp->v_data = xp;
196 	xp->umap_lowervp = lowervp;
197 	/*
198 	 * Before we insert our new node onto the hash chains,
199 	 * check to see if someone else has beaten us to it.
200 	 * (We could have slept in MALLOC.)
201 	 */
202 	if (othervp = umap_node_find(lowervp)) {
203 		FREE(xp, M_TEMP);
204 		vp->v_type = VBAD;	/* node is discarded */
205 		vp->v_usecount = 0;	/* XXX */
206 		*vpp = othervp;
207 		return (0);
208 	}
209 	VREF(lowervp);   /* Extra VREF will be vrele'd in umap_node_create */
210 	hd = umap_node_hash(lowervp);
211 	insque(xp, hd);
212 	return (0);
213 }
214 
215 
216 /*
217  * Try to find an existing umap_node vnode refering
218  * to it, otherwise make a new umap_node vnode which
219  * contains a reference to the target vnode.
220  */
221 int
222 umap_node_create(mp, targetvp, newvpp)
223 	struct mount *mp;
224 	struct vnode *targetvp;
225 	struct vnode **newvpp;
226 {
227 	struct vnode *aliasvp;
228 
229 	if (aliasvp = umap_node_find(mp, targetvp)) {
230 		/*
231 		 * Take another reference to the alias vnode
232 		 */
233 #ifdef UMAPFS_DIAGNOSTIC
234 		vprint("umap_node_create: exists", ap->umap_vnode);
235 #endif
236 		/* VREF(aliasvp); */
237 	} else {
238 		int error;
239 
240 		/*
241 		 * Get new vnode.
242 		 */
243 #ifdef UMAPFS_DIAGNOSTIC
244 		printf("umap_node_create: create new alias vnode\n");
245 #endif
246 		/*
247 		 * Make new vnode reference the umap_node.
248 		 */
249 		if (error = umap_node_alloc(mp, targetvp, &aliasvp))
250 			return (error);
251 
252 		/*
253 		 * aliasvp is already VREF'd by getnewvnode()
254 		 */
255 	}
256 
257 	vrele(targetvp);
258 
259 #ifdef UMAPFS_DIAGNOSTIC
260 	vprint("umap_node_create: alias", aliasvp);
261 	vprint("umap_node_create: target", targetvp);
262 #endif
263 
264 	*newvpp = aliasvp;
265 	return (0);
266 }
267 
268 #ifdef UMAPFS_DIAGNOSTIC
269 int umap_checkvp_barrier = 1;
270 struct vnode *
271 umap_checkvp(vp, fil, lno)
272 	struct vnode *vp;
273 	char *fil;
274 	int lno;
275 {
276 	struct umap_node *a = VTOUMAP(vp);
277 #if 0
278 	/*
279 	 * Can't do this check because vop_reclaim runs
280 	 * with funny vop vector.
281 	 */
282 	if (vp->v_op != umap_vnodeop_p) {
283 		printf ("umap_checkvp: on non-umap-node\n");
284 		while (umap_checkvp_barrier) /*WAIT*/ ;
285 		panic("umap_checkvp");
286 	}
287 #endif
288 	if (a->umap_lowervp == NULL) {
289 		/* Should never happen */
290 		int i; u_long *p;
291 		printf("vp = %x, ZERO ptr\n", vp);
292 		for (p = (u_long *) a, i = 0; i < 8; i++)
293 			printf(" %x", p[i]);
294 		printf("\n");
295 		/* wait for debugger */
296 		while (umap_checkvp_barrier) /*WAIT*/ ;
297 		panic("umap_checkvp");
298 	}
299 	if (a->umap_lowervp->v_usecount < 1) {
300 		int i; u_long *p;
301 		printf("vp = %x, unref'ed lowervp\n", vp);
302 		for (p = (u_long *) a, i = 0; i < 8; i++)
303 			printf(" %x", p[i]);
304 		printf("\n");
305 		/* wait for debugger */
306 		while (umap_checkvp_barrier) /*WAIT*/ ;
307 		panic ("umap with unref'ed lowervp");
308 	}
309 #if 0
310 	printf("umap %x/%d -> %x/%d [%s, %d]\n",
311 	        a->umap_vnode, a->umap_vnode->v_usecount,
312 		a->umap_lowervp, a->umap_lowervp->v_usecount,
313 		fil, lno);
314 #endif
315 	return (a->umap_lowervp);
316 }
317 #endif
318 
319 /* umap_mapids maps all of the ids in a credential, both user and group. */
320 
321 void
322 umap_mapids(v_mount, credp)
323 	struct mount *v_mount;
324 	struct ucred *credp;
325 {
326 	int i, unentries, gnentries;
327 	u_long *groupmap, *usermap;
328 	uid_t uid;
329 	gid_t gid;
330 
331 	unentries =  MOUNTTOUMAPMOUNT(v_mount)->info_nentries;
332 	usermap =  &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]);
333 	gnentries =  MOUNTTOUMAPMOUNT(v_mount)->info_gnentries;
334 	groupmap =  &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]);
335 
336 	/* Find uid entry in map */
337 
338 	uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries);
339 
340 	if (uid != -1)
341 		credp->cr_uid = uid;
342 	else
343 		credp->cr_uid = (uid_t) NOBODY;
344 
345 #ifdef notdef
346 	/* cr_gid is the same as cr_groups[0] in 4BSD */
347 
348 	/* Find gid entry in map */
349 
350 	gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries);
351 
352 	if (gid != -1)
353 		credp->cr_gid = gid;
354 	else
355 		credp->cr_gid = NULLGROUP;
356 #endif
357 
358 	/* Now we must map each of the set of groups in the cr_groups
359 		structure. */
360 
361 	i = 0;
362 	while (credp->cr_groups[i] != 0) {
363 		gid = (gid_t) umap_findid(credp->cr_groups[i],
364 					groupmap, gnentries);
365 
366 		if (gid != -1)
367 			credp->cr_groups[i++] = gid;
368 		else
369 			credp->cr_groups[i++] = NULLGROUP;
370 	}
371 }
372