xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 54754)
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 <lofs/lofs.h>
25 
26 #define LOG2_SIZEVNODE 7		/* log2(sizeof struct vnode) */
27 #define	NNULLNODECACHE 16
28 #define	NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-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 null_node_cache {
42 	struct null_node	*ac_forw;
43 	struct null_node	*ac_back;
44 };
45 
46 static struct null_node_cache null_node_cache[NNULLNODECACHE];
47 
48 /*
49  * Initialise cache headers
50  */
51 nullfs_init()
52 {
53 	struct null_node_cache *ac;
54 #ifdef NULLFS_DIAGNOSTIC
55 	printf("nullfs_init\n");		/* printed during system boot */
56 #endif
57 
58 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++)
59 		ac->ac_forw = ac->ac_back = (struct null_node *) ac;
60 }
61 
62 /*
63  * Compute hash list for given target vnode
64  */
65 static struct null_node_cache *
66 null_node_hash(targetvp)
67 struct vnode *targetvp;
68 {
69 	return (&null_node_cache[NULL_NHASH(targetvp)]);
70 }
71 
72 /*
73  * Make a new null_node node.
74  * Vp is the alias vnode, lofsvp is the target vnode.
75  * Maintain a reference to (targetvp).
76  */
77 static void
78 null_node_alloc(vp, targetvp)
79 	struct vnode *vp;
80 	struct vnode *targetvp;
81 {
82 	struct null_node_cache *hd;
83 	struct null_node *a;
84 
85 #ifdef NULLFS_DIAGNOSTIC
86 	printf("null_node_alloc(%x, %x)\n", vp, targetvp);
87 #endif
88 
89 	MALLOC(a, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
90 	a->null_vnode = vp;
91 	vp->v_data = a;
92 	VREF(targetvp);
93 	a->null_lowervp = targetvp;
94 	hd = null_node_hash(targetvp);
95 	insque(a, hd);
96 
97 #ifdef NULLFS_DIAGNOSTIC
98 	vprint("alloc vp", vp);
99 	vprint("alloc targetvp", targetvp);
100 #endif
101 }
102 
103 #ifdef NULLFS_DIAGNOSTIC
104 void
105 null_node_flushmp (mp)
106 	struct mount *mp;
107 {
108 	struct null_node_cache *ac;
109 	int i = 0;
110 	struct null_node *roota;
111 
112 	printf("null_node_flushmp (%x)\n", mp);
113 
114 	roota = VTONULLNODE(MOUNTTONULLMOUNT(mp)->nullm_rootvp);
115 
116 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) {
117 		struct null_node *a = ac->ac_forw;
118 		while (a != (struct null_node *) ac) {
119 			if (a != roota && a->null_vnode->v_mount == mp) {
120 				struct vnode *vp = a->null_lowervp;
121 				if (vp) {
122 					a->null_lowervp = 0;
123 					vprint("would vrele", vp);
124 					/*vrele(vp);*/
125 					i++;
126 				}
127 			}
128 			a = a->null_forw;
129 		}
130 	}
131 	if (i > 0)
132 		printf("null_node: vrele'd %d aliases\n", i);
133 }
134 #endif
135 
136 /*
137  * Return alias for target vnode if already exists, else 0.
138  */
139 static struct null_node *
140 null_node_find(mp, targetvp)
141 	struct mount *mp;
142 	struct vnode *targetvp;
143 {
144 	struct null_node_cache *hd;
145 	struct null_node *a;
146 
147 #ifdef NULLFS_DIAGNOSTIC
148 	printf("null_node_find(mp = %x, target = %x)\n", mp, targetvp);
149 #endif
150 
151 	/*
152 	 * Find hash base, and then search the (two-way) linked
153 	 * list looking for a null_node structure which is referencing
154 	 * the target vnode.  If found, the increment the null_node
155 	 * reference count (but NOT the target vnode's VREF counter).
156 	 */
157 	hd = null_node_hash(targetvp);
158 
159 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
160 		if (a->null_lowervp == targetvp && a->null_vnode->v_mount == mp) {
161 #ifdef NULLFS_DIAGNOSTIC
162 			printf("null_node_find(%x): found (%x,%x)->%x\n",
163 				targetvp, mp, a->null_vnode, targetvp);
164 #endif
165 			return (a);
166 		}
167 	}
168 
169 #ifdef NULLFS_DIAGNOSTIC
170 	printf("null_node_find(%x, %x): NOT found\n", mp, targetvp);
171 #endif
172 
173 	return (0);
174 }
175 
176 static int
177 null_node_alias(mp, targetvp, newvpp)
178 	struct mount *mp;
179 	struct vnode *targetvp;
180 	struct vnode **newvpp;
181 {
182 	struct null_node *ap;
183 	struct vnode *aliasvp;
184 
185 	if (targetvp->v_type != VDIR || targetvp->v_op == null_vnodeop_p) {
186 		*newvpp = targetvp;
187 		return;
188 	}
189 
190 	ap = null_node_find(mp, targetvp);
191 
192 	if (ap) {
193 		/*
194 		 * Take another reference to the alias vnode
195 		 */
196 #ifdef NULLFS_DIAGNOSTIC
197 		vprint("null_node_alias: exists", ap->null_vnode);
198 #endif
199 		aliasvp = ap->null_vnode;
200 		VREF(aliasvp);
201 	} else {
202 		int error;
203 
204 		/*
205 		 * Get new vnode.
206 		 */
207 #ifdef NULLFS_DIAGNOSTIC
208 		printf("null_node_alias: create new alias vnode\n");
209 #endif
210 		if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp))
211 			return (error);	/* XXX: VT_LOFS above */
212 
213 		/*
214 		 * Must be a directory
215 		 */
216 		aliasvp->v_type = VDIR;
217 
218 		/*
219 		 * Make new vnode reference the null_node.
220 		 */
221 		null_node_alloc(aliasvp, targetvp);
222 
223 		/*
224 		 * aliasvp is already VREF'd by getnewvnode()
225 		 */
226 	}
227 
228 	vrele(targetvp);
229 
230 #ifdef NULLFS_DIAGNOSTIC
231 	vprint("null_node_alias alias", aliasvp);
232 	vprint("null_node_alias target", targetvp);
233 #endif
234 
235 	*newvpp = aliasvp;
236 	return (0);
237 }
238 
239 /*
240  * Try to find an existing null_node vnode refering
241  * to it, otherwise make a new null_node vnode which
242  * contains a reference to the target vnode.
243  */
244 make_null_node(mp, vpp)
245 	struct mount *mp;
246 	struct vnode **vpp;
247 {
248 	int error;
249 	struct vnode *aliasvp;
250 	struct vnode *targetvp;
251 
252 #ifdef NULLFS_DIAGNOSTIC
253 	printf("make_null_node(mp = %x, vp = %x\n", mp, *vpp);
254 #endif
255 
256 	/*
257 	 * (targetvp) is locked at this point.
258 	 */
259 	targetvp = *vpp;
260 
261 #ifdef NULLFS_DIAGNOSTIC
262 	if (targetvp == 0)
263 		panic("make_null_node: null vp");
264 #endif
265 
266 	/*
267 	 * Try to find an existing reference to the target vnodes.
268 	 */
269 	return (null_node_alias(mp, targetvp, vpp));
270 }
271 
272 #ifdef NULLFS_DIAGNOSTIC
273 struct vnode *
274 null_checkvp(vp, fil, lno)
275 	struct vnode *vp;
276 	char *fil;
277 	int lno;
278 {
279 	struct null_node *a = VTONULLNODE(vp);
280 	if (a->null_lowervp == 0) {
281 		int i; u_long *p;
282 		printf("vp = %x, ZERO ptr\n", vp);
283 #ifdef notdef
284 		for (p = (u_long *) a, i = 0; i < 8; i++)
285 			printf(" %x", p[i]);
286 		printf("\n");
287 		DELAY(2000000);
288 		panic("null_checkvp");
289 #endif
290 	}
291 	printf("aliasvp %x/%d -> %x/%d [%s, %d]\n",
292 		a->null_vnode, a->null_vnode->v_usecount,
293 		a->null_lowervp, a->null_lowervp ? a->null_lowervp->v_usecount : -42,
294 		fil, lno);
295 	return a->null_lowervp;
296 }
297 #endif
298