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])
LIST_HEAD(null_node_hashhead,null_node)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 *
null_node_find(mp,lowervp)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
null_node_alloc(mp,lowervp,vpp)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
null_node_create(mp,lowervp,newvpp)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 *
null_checkvp(vp,fil,lno)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