xref: /original-bsd/sys/miscfs/umapfs/umap_subr.c (revision 3705696b)
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.1 (Berkeley) 06/10/93
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  * Return alias for target vnode if already exists, else 0.
75  */
76 static struct vnode *
77 umap_node_find(mp, targetvp)
78 	struct mount *mp;
79 	struct vnode *targetvp;
80 {
81 	struct umap_node_cache *hd;
82 	struct umap_node *a;
83 	struct vnode *vp;
84 
85 #ifdef UMAPFS_DIAGNOSTIC
86 	printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp);
87 #endif
88 
89 	/*
90 	 * Find hash base, and then search the (two-way) linked
91 	 * list looking for a umap_node structure which is referencing
92 	 * the target vnode.  If found, the increment the umap_node
93 	 * reference count (but NOT the target vnode's VREF counter).
94 	 */
95 	hd = umap_node_hash(targetvp);
96 
97  loop:
98 	for (a = hd->ac_forw; a != (struct umap_node *) hd; a = a->umap_forw) {
99 		if (a->umap_lowervp == targetvp &&
100 		    a->umap_vnode->v_mount == mp) {
101 			vp = UMAPTOV(a);
102 			/*
103 			 * We need vget for the VXLOCK
104 			 * stuff, but we don't want to lock
105 			 * the lower node.
106 			 */
107 			if (vget_nolock(vp)) {
108 				printf ("null_node_find: vget failed.\n");
109 				goto loop;
110 			}
111 			return (vp);
112 		}
113 	}
114 
115 #ifdef UMAPFS_DIAGNOSTIC
116 	printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp);
117 #endif
118 
119 	return (0);
120 }
121 
122 /*
123  * Make a new umap_node node.
124  * Vp is the alias vnode, lofsvp is the target vnode.
125  * Maintain a reference to (targetvp).
126  */
127 static int
128 umap_node_alloc(mp, lowervp, vpp)
129 	struct mount *mp;
130 	struct vnode *lowervp;
131 	struct vnode **vpp;
132 {
133 	struct umap_node_cache *hd;
134 	struct umap_node *xp;
135 	struct vnode *othervp, *vp;
136 	int error;
137 
138 	if (error = getnewvnode(VT_UFS, mp, umap_vnodeop_p, vpp))
139 		return (error);	/* XXX: VT_UMAP above */
140 	vp = *vpp;
141 
142 	MALLOC(xp, struct umap_node *, sizeof(struct umap_node),
143 	    M_TEMP, M_WAITOK);
144 	vp->v_type = lowervp->v_type;
145 	xp->umap_vnode = vp;
146 	vp->v_data = xp;
147 	xp->umap_lowervp = lowervp;
148 	/*
149 	 * Before we insert our new node onto the hash chains,
150 	 * check to see if someone else has beaten us to it.
151 	 * (We could have slept in MALLOC.)
152 	 */
153 	if (othervp = umap_node_find(lowervp)) {
154 		FREE(xp, M_TEMP);
155 		vp->v_type = VBAD;	/* node is discarded */
156 		vp->v_usecount = 0;	/* XXX */
157 		*vpp = othervp;
158 		return (0);
159 	}
160 	VREF(lowervp);   /* Extra VREF will be vrele'd in umap_node_create */
161 	hd = umap_node_hash(lowervp);
162 	insque(xp, hd);
163 	return (0);
164 }
165 
166 
167 /*
168  * Try to find an existing umap_node vnode refering
169  * to it, otherwise make a new umap_node vnode which
170  * contains a reference to the target vnode.
171  */
172 int
173 umap_node_create(mp, targetvp, newvpp)
174 	struct mount *mp;
175 	struct vnode *targetvp;
176 	struct vnode **newvpp;
177 {
178 	struct vnode *aliasvp;
179 
180 	if (aliasvp = umap_node_find(mp, targetvp)) {
181 		/*
182 		 * Take another reference to the alias vnode
183 		 */
184 #ifdef UMAPFS_DIAGNOSTIC
185 		vprint("umap_node_create: exists", ap->umap_vnode);
186 #endif
187 		/* VREF(aliasvp); */
188 	} else {
189 		int error;
190 
191 		/*
192 		 * Get new vnode.
193 		 */
194 #ifdef UMAPFS_DIAGNOSTIC
195 		printf("umap_node_create: create new alias vnode\n");
196 #endif
197 		/*
198 		 * Make new vnode reference the umap_node.
199 		 */
200 		if (error = umap_node_alloc(mp, targetvp, &aliasvp))
201 			return (error);
202 
203 		/*
204 		 * aliasvp is already VREF'd by getnewvnode()
205 		 */
206 	}
207 
208 	vrele(targetvp);
209 
210 #ifdef UMAPFS_DIAGNOSTIC
211 	vprint("umap_node_create: alias", aliasvp);
212 	vprint("umap_node_create: target", targetvp);
213 #endif
214 
215 	*newvpp = aliasvp;
216 	return (0);
217 }
218 
219 #ifdef UMAPFS_DIAGNOSTIC
220 int umap_checkvp_barrier = 1;
221 struct vnode *
222 umap_checkvp(vp, fil, lno)
223 	struct vnode *vp;
224 	char *fil;
225 	int lno;
226 {
227 	struct umap_node *a = VTOUMAP(vp);
228 #if 0
229 	/*
230 	 * Can't do this check because vop_reclaim runs
231 	 * with funny vop vector.
232 	 */
233 	if (vp->v_op != umap_vnodeop_p) {
234 		printf ("umap_checkvp: on non-umap-node\n");
235 		while (umap_checkvp_barrier) /*WAIT*/ ;
236 		panic("umap_checkvp");
237 	}
238 #endif
239 	if (a->umap_lowervp == NULL) {
240 		/* Should never happen */
241 		int i; u_long *p;
242 		printf("vp = %x, ZERO ptr\n", vp);
243 		for (p = (u_long *) a, i = 0; i < 8; i++)
244 			printf(" %x", p[i]);
245 		printf("\n");
246 		/* wait for debugger */
247 		while (umap_checkvp_barrier) /*WAIT*/ ;
248 		panic("umap_checkvp");
249 	}
250 	if (a->umap_lowervp->v_usecount < 1) {
251 		int i; u_long *p;
252 		printf("vp = %x, unref'ed lowervp\n", vp);
253 		for (p = (u_long *) a, i = 0; i < 8; i++)
254 			printf(" %x", p[i]);
255 		printf("\n");
256 		/* wait for debugger */
257 		while (umap_checkvp_barrier) /*WAIT*/ ;
258 		panic ("umap with unref'ed lowervp");
259 	}
260 #if 0
261 	printf("umap %x/%d -> %x/%d [%s, %d]\n",
262 	        a->umap_vnode, a->umap_vnode->v_usecount,
263 		a->umap_lowervp, a->umap_lowervp->v_usecount,
264 		fil, lno);
265 #endif
266 	return (a->umap_lowervp);
267 }
268 #endif
269 
270 /* umap_mapids maps all of the ids in a credential, both user and group. */
271 
272 umap_mapids(v_mount,credp)
273 	struct mount *v_mount;
274 	struct ucred *credp;
275 {
276 	int i,gid,uid,unentries,gnentries,*groupmap,*usermap;
277 
278 	unentries =  MOUNTTOUMAPMOUNT(v_mount)->info_nentries;
279 	usermap =  &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]);
280 	gnentries =  MOUNTTOUMAPMOUNT(v_mount)->info_gnentries;
281 	groupmap =  &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]);
282 
283 	/* Find uid entry in map */
284 
285 	uid = umap_findid(credp->cr_uid,usermap,unentries);
286 
287 	if (uid != -1) {
288 		credp->cr_uid =
289 			(u_short)uid;
290 	} else
291 		credp->cr_uid = (u_short)NOBODY;
292 
293 	/* Find gid entry in map */
294 
295 	gid = umap_findid(credp->cr_gid,groupmap,gnentries);
296 
297 	if (gid != -1) {
298 		credp->cr_gid =
299 			(u_short)gid;
300 	} else
301 		credp->cr_gid = (u_short)NULLGROUP;
302 
303 	/* Now we must map each of the set of groups in the cr_groups
304 		structure. */
305 
306 	i = 0;
307 	while (credp->cr_groups[i] != 0)
308 	{
309 		gid = umap_findid(credp->cr_groups[i],groupmap,
310 			gnentries);
311 
312 		if (gid != -1)
313 			credp->cr_groups[i++] = (u_short)gid;
314 		else
315 			credp->cr_groups[i++] = (u_short)NULLGROUP;
316 
317 	}
318 }
319 
320 /* umap_findid is called by various routines in umap_vnodeops.c to
321  * find a user or group id in a map.
322  */
323 
324 umap_findid(id,map,nentries)
325 	ushort id;
326 	int map[][2];
327 	int nentries;
328 {
329 	int i;
330 
331 	/* Find uid entry in map */
332 	i = 0;
333 	while ((i<nentries) && ((u_short)(map[i][0] ) != id))
334 		i++;
335 
336 	if ( i < nentries )
337 		return (map[i][1]);
338 	else
339 		return (-1);
340 
341 }
342 
343 /* umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to
344  * find a user or group id in a map, in reverse.
345  */
346 
347 umap_reverse_findid(id,map,nentries)
348 	ushort id;
349 	int map[][2];
350 	int nentries;
351 {
352 	int i;
353 
354 	/* Find uid entry in map */
355 	i = 0;
356 	while ((i<nentries) && ((u_short)(map[i][1] ) != id))
357 		i++;
358 
359 	if ( i < nentries )
360 		return (map[i][0]);
361 	else
362 		return (-1);
363 
364 }
365