xref: /csrg-svn/sys/miscfs/nullfs/null_subr.c (revision 54766)
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 /*
105  * NEEDSWORK:  The ability to set lowervp to null here
106  * implies that one can never count on lowervp staying null
107  * (even if vp is locked).  This seems quite bad.  Think
108  * about these things.
109  */
110 void
111 null_node_flushmp (mp)
112 	struct mount *mp;
113 {
114 	struct null_node_cache *ac;
115 	int i = 0;
116 	struct null_node *roota;
117 
118 	printf("null_node_flushmp (%x)\n", mp);
119 
120 	roota = VTONULLNODE(MOUNTTONULLMOUNT(mp)->nullm_rootvp);
121 
122 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++) {
123 		struct null_node *a = ac->ac_forw;
124 		while (a != (struct null_node *) ac) {
125 			if (a != roota && a->null_vnode->v_mount == mp) {
126 				struct vnode *vp = a->null_lowervp;
127 				if (vp) {
128 					a->null_lowervp = 0;
129 					vprint("would vrele", vp);
130 					/*vrele(vp);*/
131 					i++;
132 				}
133 			}
134 			a = a->null_forw;
135 		}
136 	}
137 	if (i > 0)
138 		printf("null_node: vrele'd %d aliases\n", i);
139 }
140 #endif
141 
142 /*
143  * Return alias for target vnode if already exists, else 0.
144  */
145 static struct null_node *
146 null_node_find(mp, targetvp)
147 	struct mount *mp;
148 	struct vnode *targetvp;
149 {
150 	struct null_node_cache *hd;
151 	struct null_node *a;
152 
153 #ifdef NULLFS_DIAGNOSTIC
154 	printf("null_node_find(mp = %x, target = %x)\n", mp, targetvp);
155 #endif
156 
157 	/*
158 	 * Find hash base, and then search the (two-way) linked
159 	 * list looking for a null_node structure which is referencing
160 	 * the target vnode.  If found, the increment the null_node
161 	 * reference count (but NOT the target vnode's VREF counter).
162 	 */
163 	hd = null_node_hash(targetvp);
164 
165 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
166 		if (a->null_lowervp == targetvp && a->null_vnode->v_mount == mp) {
167 #ifdef NULLFS_DIAGNOSTIC
168 			printf("null_node_find(%x): found (%x,%x)->%x\n",
169 				targetvp, mp, a->null_vnode, targetvp);
170 #endif
171 			return (a);
172 		}
173 	}
174 
175 #ifdef NULLFS_DIAGNOSTIC
176 	printf("null_node_find(%x, %x): NOT found\n", mp, targetvp);
177 #endif
178 
179 	return (0);
180 }
181 
182 /*
183  * Try to find an existing null_node vnode refering
184  * to it, otherwise make a new null_node vnode which
185  * contains a reference to the target vnode.
186  */
187 int
188 null_node_create(mp, targetvp, newvpp)
189 	struct mount *mp;
190 	struct vnode *targetvp;
191 	struct vnode **newvpp;
192 {
193 	struct null_node *ap;
194 	struct vnode *aliasvp;
195 
196 	if (targetvp->v_type != VDIR || targetvp->v_op == null_vnodeop_p) {
197 		*newvpp = targetvp;
198 		return;
199 	}
200 
201 	ap = null_node_find(mp, targetvp);
202 
203 	if (ap) {
204 		/*
205 		 * Take another reference to the alias vnode
206 		 */
207 #ifdef NULLFS_DIAGNOSTIC
208 		vprint("null_node_alias: exists", ap->null_vnode);
209 #endif
210 		aliasvp = ap->null_vnode;
211 		VREF(aliasvp);
212 	} else {
213 		int error;
214 
215 		/*
216 		 * Get new vnode.
217 		 */
218 #ifdef NULLFS_DIAGNOSTIC
219 		printf("null_node_alias: create new alias vnode\n");
220 #endif
221 		if (error = getnewvnode(VT_UFS, mp, null_vnodeop_p, &aliasvp))
222 			return (error);	/* XXX: VT_LOFS above */
223 
224 		/*
225 		 * Must be a directory
226 		 */
227 		aliasvp->v_type = VDIR;
228 
229 		/*
230 		 * Make new vnode reference the null_node.
231 		 */
232 		null_node_alloc(aliasvp, targetvp);
233 
234 		/*
235 		 * aliasvp is already VREF'd by getnewvnode()
236 		 */
237 	}
238 
239 	vrele(targetvp);
240 
241 #ifdef NULLFS_DIAGNOSTIC
242 	vprint("null_node_alias alias", aliasvp);
243 	vprint("null_node_alias target", targetvp);
244 #endif
245 
246 	*newvpp = aliasvp;
247 	return (0);
248 }
249 #ifdef NULLFS_DIAGNOSTIC
250 struct vnode *
251 null_checkvp(vp, fil, lno)
252 	struct vnode *vp;
253 	char *fil;
254 	int lno;
255 {
256 	struct null_node *a = VTONULLNODE(vp);
257 	if (a->null_lowervp == 0) {
258 		/* Should never happen */
259 		int i; u_long *p;
260 		printf("vp = %x, ZERO ptr\n", vp);
261 		for (p = (u_long *) a, i = 0; i < 8; i++)
262 			printf(" %x", p[i]);
263 		printf("\n");
264 		DELAY(2000000);
265 		panic("null_checkvp");
266 	}
267 	printf("nullvp %x/%d -> %x/%d [%s, %d]\n",
268 		a->null_vnode, a->null_vnode->v_usecount,
269 		a->null_lowervp, a->null_lowervp->v_usecount,
270 		fil, lno);
271 	return a->null_lowervp;
272 }
273 #endif
274