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