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