xref: /original-bsd/sys/miscfs/nullfs/null_subr.c (revision 7a38d872)
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  *	@(#)null_subr.c	8.3 (Berkeley) 01/04/94
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/nullfs/null.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 lower vnode
33  * along with a pointer to the alias vnode.  When an
34  * entry is added the lower vnode is VREF'd.  When the
35  * alias is removed the lower 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 lower vnode
64  */
65 static struct null_node_cache *
66 null_node_hash(lowervp)
67 struct vnode *lowervp;
68 {
69 
70 	return (&null_node_cache[NULL_NHASH(lowervp)]);
71 }
72 
73 /*
74  * Return a VREF'ed alias for lower vnode if already exists, else 0.
75  */
76 static struct vnode *
77 null_node_find(mp, lowervp)
78 	struct mount *mp;
79 	struct vnode *lowervp;
80 {
81 	struct null_node_cache *hd;
82 	struct null_node *a;
83 	struct vnode *vp;
84 
85 	/*
86 	 * Find hash base, and then search the (two-way) linked
87 	 * list looking for a null_node structure which is referencing
88 	 * the lower vnode.  If found, the increment the null_node
89 	 * reference count (but NOT the lower vnode's VREF counter).
90 	 */
91 	hd = null_node_hash(lowervp);
92 loop:
93 	for (a = hd->ac_forw; a != (struct null_node *) hd; a = a->null_forw) {
94 		if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
95 			vp = NULLTOV(a);
96 			/*
97 			 * We need vget for the VXLOCK
98 			 * stuff, but we don't want to lock
99 			 * the lower node.
100 			 */
101 			if (vget(vp, 0)) {
102 				printf ("null_node_find: vget failed.\n");
103 				goto loop;
104 			};
105 			return (vp);
106 		}
107 	}
108 
109 	return NULL;
110 }
111 
112 
113 /*
114  * Make a new null_node node.
115  * Vp is the alias vnode, lofsvp is the lower vnode.
116  * Maintain a reference to (lowervp).
117  */
118 static int
119 null_node_alloc(mp, lowervp, vpp)
120 	struct mount *mp;
121 	struct vnode *lowervp;
122 	struct vnode **vpp;
123 {
124 	struct null_node_cache *hd;
125 	struct null_node *xp;
126 	struct vnode *othervp, *vp;
127 	int error;
128 
129 	if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp))
130 		return (error);
131 	vp = *vpp;
132 
133 	MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
134 	vp->v_type = lowervp->v_type;
135 	xp->null_vnode = vp;
136 	vp->v_data = xp;
137 	xp->null_lowervp = lowervp;
138 	/*
139 	 * Before we insert our new node onto the hash chains,
140 	 * check to see if someone else has beaten us to it.
141 	 * (We could have slept in MALLOC.)
142 	 */
143 	if (othervp = null_node_find(lowervp)) {
144 		FREE(xp, M_TEMP);
145 		vp->v_type = VBAD;	/* node is discarded */
146 		vp->v_usecount = 0;	/* XXX */
147 		*vpp = othervp;
148 		return 0;
149 	};
150 	VREF(lowervp);   /* Extra VREF will be vrele'd in null_node_create */
151 	hd = null_node_hash(lowervp);
152 	insque(xp, hd);
153 	return 0;
154 }
155 
156 
157 /*
158  * Try to find an existing null_node vnode refering
159  * to it, otherwise make a new null_node vnode which
160  * contains a reference to the lower vnode.
161  */
162 int
163 null_node_create(mp, lowervp, newvpp)
164 	struct mount *mp;
165 	struct vnode *lowervp;
166 	struct vnode **newvpp;
167 {
168 	struct vnode *aliasvp;
169 
170 	if (aliasvp = null_node_find(mp, lowervp)) {
171 		/*
172 		 * null_node_find has taken another reference
173 		 * to the alias vnode.
174 		 */
175 #ifdef NULLFS_DIAGNOSTIC
176 		vprint("null_node_create: exists", NULLTOV(ap));
177 #endif
178 		/* VREF(aliasvp); --- done in null_node_find */
179 	} else {
180 		int error;
181 
182 		/*
183 		 * Get new vnode.
184 		 */
185 #ifdef NULLFS_DIAGNOSTIC
186 		printf("null_node_create: create new alias vnode\n");
187 #endif
188 
189 		/*
190 		 * Make new vnode reference the null_node.
191 		 */
192 		if (error = null_node_alloc(mp, lowervp, &aliasvp))
193 			return error;
194 
195 		/*
196 		 * aliasvp is already VREF'd by getnewvnode()
197 		 */
198 	}
199 
200 	vrele(lowervp);
201 
202 #ifdef DIAGNOSTIC
203 	if (lowervp->v_usecount < 1) {
204 		/* Should never happen... */
205 		vprint ("null_node_create: alias ");
206 		vprint ("null_node_create: lower ");
207 		printf ("null_node_create: lower has 0 usecount.\n");
208 		panic ("null_node_create: lower has 0 usecount.");
209 	};
210 #endif
211 
212 #ifdef NULLFS_DIAGNOSTIC
213 	vprint("null_node_create: alias", aliasvp);
214 	vprint("null_node_create: lower", lowervp);
215 #endif
216 
217 	*newvpp = aliasvp;
218 	return (0);
219 }
220 #ifdef NULLFS_DIAGNOSTIC
221 struct vnode *
222 null_checkvp(vp, fil, lno)
223 	struct vnode *vp;
224 	char *fil;
225 	int lno;
226 {
227 	struct null_node *a = VTONULL(vp);
228 #ifdef notyet
229 	/*
230 	 * Can't do this check because vop_reclaim runs
231 	 * with a funny vop vector.
232 	 */
233 	if (vp->v_op != null_vnodeop_p) {
234 		printf ("null_checkvp: on non-null-node\n");
235 		while (null_checkvp_barrier) /*WAIT*/ ;
236 		panic("null_checkvp");
237 	};
238 #endif
239 	if (a->null_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 (null_checkvp_barrier) /*WAIT*/ ;
248 		panic("null_checkvp");
249 	}
250 	if (a->null_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 (null_checkvp_barrier) /*WAIT*/ ;
258 		panic ("null with unref'ed lowervp");
259 	};
260 #ifdef notyet
261 	printf("null %x/%d -> %x/%d [%s, %d]\n",
262 	        NULLTOV(a), NULLTOV(a)->v_usecount,
263 		a->null_lowervp, a->null_lowervp->v_usecount,
264 		fil, lno);
265 #endif
266 	return a->null_lowervp;
267 }
268 #endif
269