xref: /original-bsd/sys/miscfs/nullfs/null_subr.c (revision 333da485)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software donated to Berkeley by
6  * Jan-Simon Pendry.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)null_subr.c	8.4 (Berkeley) 01/21/94
11  *
12  * $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
13  */
14 
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <sys/vnode.h>
20 #include <sys/mount.h>
21 #include <sys/namei.h>
22 #include <sys/malloc.h>
23 #include <miscfs/nullfs/null.h>
24 
25 #define LOG2_SIZEVNODE 7		/* log2(sizeof struct vnode) */
26 #define	NNULLNODECACHE 16
27 #define	NULL_NHASH(vp) ((((u_long)vp)>>LOG2_SIZEVNODE) & (NNULLNODECACHE-1))
28 
29 /*
30  * Null layer cache:
31  * Each cache entry holds a reference to the lower vnode
32  * along with a pointer to the alias vnode.  When an
33  * entry is added the lower vnode is VREF'd.  When the
34  * alias is removed the lower vnode is vrele'd.
35  */
36 
37 /*
38  * Cache head
39  */
40 struct null_node_cache {
41 	struct null_node	*ac_forw;
42 	struct null_node	*ac_back;
43 };
44 
45 static struct null_node_cache null_node_cache[NNULLNODECACHE];
46 
47 /*
48  * Initialise cache headers
49  */
50 nullfs_init()
51 {
52 	struct null_node_cache *ac;
53 #ifdef NULLFS_DIAGNOSTIC
54 	printf("nullfs_init\n");		/* printed during system boot */
55 #endif
56 
57 	for (ac = null_node_cache; ac < null_node_cache + NNULLNODECACHE; ac++)
58 		ac->ac_forw = ac->ac_back = (struct null_node *) ac;
59 }
60 
61 /*
62  * Compute hash list for given lower vnode
63  */
64 static struct null_node_cache *
65 null_node_hash(lowervp)
66 struct vnode *lowervp;
67 {
68 
69 	return (&null_node_cache[NULL_NHASH(lowervp)]);
70 }
71 
72 /*
73  * Return a VREF'ed alias for lower vnode if already exists, else 0.
74  */
75 static struct vnode *
76 null_node_find(mp, lowervp)
77 	struct mount *mp;
78 	struct vnode *lowervp;
79 {
80 	struct null_node_cache *hd;
81 	struct null_node *a;
82 	struct vnode *vp;
83 
84 	/*
85 	 * Find hash base, and then search the (two-way) linked
86 	 * list looking for a null_node structure which is referencing
87 	 * the lower vnode.  If found, the increment the null_node
88 	 * reference count (but NOT the lower vnode's VREF counter).
89 	 */
90 	hd = null_node_hash(lowervp);
91 loop:
92 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
93 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
94 			vp = NULLTOV(a);
95 			/*
96 			 * We need vget for the VXLOCK
97 			 * stuff, but we don't want to lock
98 			 * the lower node.
99 			 */
100 			if (vget(vp, 0)) {
101 				printf ("null_node_find: vget failed.\n");
102 				goto loop;
103 			};
104 			return (vp);
105 		}
106 	}
107 
108 	return NULL;
109 }
110 
111 
112 /*
113  * Make a new null_node node.
114  * Vp is the alias vnode, lofsvp is the lower vnode.
115  * Maintain a reference to (lowervp).
116  */
117 static int
118 null_node_alloc(mp, lowervp, vpp)
119 	struct mount *mp;
120 	struct vnode *lowervp;
121 	struct vnode **vpp;
122 {
123 	struct null_node_cache *hd;
124 	struct null_node *xp;
125 	struct vnode *othervp, *vp;
126 	int error;
127 
128 	if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp))
129 		return (error);
130 	vp = *vpp;
131 
132 	MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
133 	vp->v_type = lowervp->v_type;
134 	xp->null_vnode = vp;
135 	vp->v_data = xp;
136 	xp->null_lowervp = lowervp;
137 	/*
138 	 * Before we insert our new node onto the hash chains,
139 	 * check to see if someone else has beaten us to it.
140 	 * (We could have slept in MALLOC.)
141 	 */
142 	if (othervp = null_node_find(lowervp)) {
143 		FREE(xp, M_TEMP);
144 		vp->v_type = VBAD;	/* node is discarded */
145 		vp->v_usecount = 0;	/* XXX */
146 		*vpp = othervp;
147 		return 0;
148 	};
149 	VREF(lowervp);   /* Extra VREF will be vrele'd in null_node_create */
150 	hd = null_node_hash(lowervp);
151 	insque(xp, hd);
152 	return 0;
153 }
154 
155 
156 /*
157  * Try to find an existing null_node vnode refering
158  * to it, otherwise make a new null_node vnode which
159  * contains a reference to the lower vnode.
160  */
161 int
162 null_node_create(mp, lowervp, newvpp)
163 	struct mount *mp;
164 	struct vnode *lowervp;
165 	struct vnode **newvpp;
166 {
167 	struct vnode *aliasvp;
168 
169 	if (aliasvp = null_node_find(mp, lowervp)) {
170 		/*
171 		 * null_node_find has taken another reference
172 		 * to the alias vnode.
173 		 */
174 #ifdef NULLFS_DIAGNOSTIC
175 		vprint("null_node_create: exists", NULLTOV(ap));
176 #endif
177 		/* VREF(aliasvp); --- done in null_node_find */
178 	} else {
179 		int error;
180 
181 		/*
182 		 * Get new vnode.
183 		 */
184 #ifdef NULLFS_DIAGNOSTIC
185 		printf("null_node_create: create new alias vnode\n");
186 #endif
187 
188 		/*
189 		 * Make new vnode reference the null_node.
190 		 */
191 		if (error = null_node_alloc(mp, lowervp, &aliasvp))
192 			return error;
193 
194 		/*
195 		 * aliasvp is already VREF'd by getnewvnode()
196 		 */
197 	}
198 
199 	vrele(lowervp);
200 
201 #ifdef DIAGNOSTIC
202 	if (lowervp->v_usecount < 1) {
203 		/* Should never happen... */
204 		vprint ("null_node_create: alias ");
205 		vprint ("null_node_create: lower ");
206 		printf ("null_node_create: lower has 0 usecount.\n");
207 		panic ("null_node_create: lower has 0 usecount.");
208 	};
209 #endif
210 
211 #ifdef NULLFS_DIAGNOSTIC
212 	vprint("null_node_create: alias", aliasvp);
213 	vprint("null_node_create: lower", lowervp);
214 #endif
215 
216 	*newvpp = aliasvp;
217 	return (0);
218 }
219 #ifdef NULLFS_DIAGNOSTIC
220 struct vnode *
221 null_checkvp(vp, fil, lno)
222 	struct vnode *vp;
223 	char *fil;
224 	int lno;
225 {
226 	struct null_node *a = VTONULL(vp);
227 #ifdef notyet
228 	/*
229 	 * Can't do this check because vop_reclaim runs
230 	 * with a funny vop vector.
231 	 */
232 	if (vp->v_op != null_vnodeop_p) {
233 		printf ("null_checkvp: on non-null-node\n");
234 		while (null_checkvp_barrier) /*WAIT*/ ;
235 		panic("null_checkvp");
236 	};
237 #endif
238 	if (a->null_lowervp == NULL) {
239 		/* Should never happen */
240 		int i; u_long *p;
241 		printf("vp = %x, ZERO ptr\n", vp);
242 		for (p = (u_long *) a, i = 0; i < 8; i++)
243 			printf(" %x", p[i]);
244 		printf("\n");
245 		/* wait for debugger */
246 		while (null_checkvp_barrier) /*WAIT*/ ;
247 		panic("null_checkvp");
248 	}
249 	if (a->null_lowervp->v_usecount < 1) {
250 		int i; u_long *p;
251 		printf("vp = %x, unref'ed lowervp\n", vp);
252 		for (p = (u_long *) a, i = 0; i < 8; i++)
253 			printf(" %x", p[i]);
254 		printf("\n");
255 		/* wait for debugger */
256 		while (null_checkvp_barrier) /*WAIT*/ ;
257 		panic ("null with unref'ed lowervp");
258 	};
259 #ifdef notyet
260 	printf("null %x/%d -> %x/%d [%s, %d]\n",
261 	        NULLTOV(a), NULLTOV(a)->v_usecount,
262 		a->null_lowervp, a->null_lowervp->v_usecount,
263 		fil, lno);
264 #endif
265 	return a->null_lowervp;
266 }
267 #endif
268