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