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