disallow read from the root directory
[unix-history] / usr / src / sys / miscfs / union / union_vnops.c
CommitLineData
a1fa407d
JSP
1/*
2 * Copyright (c) 1992, 1993, 1994 The Regents of the University of California.
3 * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
12abe7b1 7 * Jan-Simon Pendry.
a1fa407d
JSP
8 *
9 * %sccs.include.redist.c%
10 *
e2a2f3a7 11 * @(#)union_vnops.c 2.1 (Berkeley) %G%
a1fa407d
JSP
12 */
13
14#include <sys/param.h>
15#include <sys/systm.h>
16#include <sys/proc.h>
17#include <sys/file.h>
a1fa407d
JSP
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 <sys/buf.h>
25#include "union.h"
26
a1fa407d 27static int
79f80c71
JSP
28union_lookup1(udvp, dvp, vpp, cnp)
29 struct vnode *udvp;
a1fa407d
JSP
30 struct vnode *dvp;
31 struct vnode **vpp;
32 struct componentname *cnp;
33{
34 int error;
35 struct vnode *tdvp;
36 struct mount *mp;
37
81be6ee0
JSP
38 /*
39 * If stepping up the directory tree, check for going
40 * back across the mount point, in which case do what
41 * lookup would do by stepping back down the mount
42 * hierarchy.
43 */
a1fa407d
JSP
44 if (cnp->cn_flags & ISDOTDOT) {
45 for (;;) {
692a90df
JSP
46 /*
47 * Don't do the NOCROSSMOUNT check
48 * at this level. By definition,
49 * union fs deals with namespaces, not
50 * filesystems.
51 */
52 if ((dvp->v_flag & VROOT) == 0)
a1fa407d
JSP
53 break;
54
55 tdvp = dvp;
56 dvp = dvp->v_mount->mnt_vnodecovered;
57 vput(tdvp);
58 VREF(dvp);
59 VOP_LOCK(dvp);
60 }
61 }
ed5969c8 62
a1fa407d
JSP
63 error = VOP_LOOKUP(dvp, &tdvp, cnp);
64 if (error)
65 return (error);
66
81be6ee0 67 /*
ed5969c8
JSP
68 * The parent directory will have been unlocked, unless lookup
69 * found the last component. In which case, re-lock the node
70 * here to allow it to be unlocked again (phew) in union_lookup.
81be6ee0 71 */
ed5969c8 72 if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN))
81be6ee0
JSP
73 VOP_LOCK(dvp);
74
a1fa407d 75 dvp = tdvp;
81be6ee0
JSP
76
77 /*
78 * Lastly check if the current node is a mount point in
692a90df 79 * which case walk up the mount hierarchy making sure not to
81be6ee0
JSP
80 * bump into the root of the mount tree (ie. dvp != udvp).
81 */
79f80c71 82 while (dvp != udvp && (dvp->v_type == VDIR) &&
692a90df 83 (mp = dvp->v_mountedhere)) {
a1fa407d
JSP
84
85 if (mp->mnt_flag & MNT_MLOCK) {
86 mp->mnt_flag |= MNT_MWAIT;
87 sleep((caddr_t) mp, PVFS);
88 continue;
89 }
90
91 if (error = VFS_ROOT(mp, &tdvp)) {
92 vput(dvp);
93 return (error);
94 }
95
01dac67e 96 vput(dvp);
a1fa407d
JSP
97 dvp = tdvp;
98 }
99
100 *vpp = dvp;
101 return (0);
102}
103
104int
105union_lookup(ap)
106 struct vop_lookup_args /* {
107 struct vnodeop_desc *a_desc;
108 struct vnode *a_dvp;
109 struct vnode **a_vpp;
110 struct componentname *a_cnp;
111 } */ *ap;
112{
01dac67e 113 int error;
a1fa407d
JSP
114 int uerror, lerror;
115 struct vnode *uppervp, *lowervp;
116 struct vnode *upperdvp, *lowerdvp;
117 struct vnode *dvp = ap->a_dvp;
79f80c71 118 struct union_node *dun = VTOUNION(dvp);
a1fa407d
JSP
119 struct componentname *cnp = ap->a_cnp;
120 int lockparent = cnp->cn_flags & LOCKPARENT;
81be6ee0 121 int rdonly = cnp->cn_flags & RDONLY;
3b293975 122 struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
a1fa407d 123
01dac67e
JSP
124 cnp->cn_flags |= LOCKPARENT;
125
a1fa407d
JSP
126 upperdvp = dun->un_uppervp;
127 lowerdvp = dun->un_lowervp;
3b293975
JSP
128 uppervp = NULLVP;
129 lowervp = NULLVP;
a1fa407d
JSP
130
131 /*
132 * do the lookup in the upper level.
133 * if that level comsumes additional pathnames,
134 * then assume that something special is going
135 * on and just return that vnode.
136 */
a1fa407d 137 if (upperdvp) {
3b293975
JSP
138 uerror = union_lookup1(um->um_uppervp, upperdvp,
139 &uppervp, cnp);
e2a2f3a7
JSP
140 /*if (uppervp == upperdvp)
141 dun->un_flags |= UN_KLOCK;*/
01dac67e 142
a1fa407d
JSP
143 if (cnp->cn_consume != 0) {
144 *ap->a_vpp = uppervp;
01dac67e
JSP
145 if (!lockparent)
146 cnp->cn_flags &= ~LOCKPARENT;
a1fa407d
JSP
147 return (uerror);
148 }
a1fa407d
JSP
149 } else {
150 uerror = ENOENT;
151 }
152
153 /*
154 * in a similar way to the upper layer, do the lookup
155 * in the lower layer. this time, if there is some
156 * component magic going on, then vput whatever we got
157 * back from the upper layer and return the lower vnode
158 * instead.
159 */
a1fa407d 160 if (lowerdvp) {
e2a2f3a7
JSP
161 int nameiop;
162
01dac67e 163 VOP_LOCK(lowerdvp);
e2a2f3a7
JSP
164
165 /*
166 * Only do a LOOKUP on the bottom node, since
167 * we won't be making changes to it anyway.
168 */
169 nameiop = cnp->cn_nameiop;
170 cnp->cn_nameiop = LOOKUP;
3b293975 171 lerror = union_lookup1(um->um_lowervp, lowerdvp,
e2a2f3a7
JSP
172 &lowervp, cnp);
173 cnp->cn_nameiop = nameiop;
174
79f80c71
JSP
175 if (lowervp != lowerdvp)
176 VOP_UNLOCK(lowerdvp);
01dac67e 177
a1fa407d
JSP
178 if (cnp->cn_consume != 0) {
179 if (uppervp) {
e2a2f3a7
JSP
180 if (uppervp == upperdvp)
181 vrele(uppervp);
182 else
183 vput(uppervp);
3b293975 184 uppervp = NULLVP;
a1fa407d
JSP
185 }
186 *ap->a_vpp = lowervp;
01dac67e
JSP
187 if (!lockparent)
188 cnp->cn_flags &= ~LOCKPARENT;
a1fa407d
JSP
189 return (lerror);
190 }
a1fa407d
JSP
191 } else {
192 lerror = ENOENT;
193 }
194
01dac67e
JSP
195 if (!lockparent)
196 cnp->cn_flags &= ~LOCKPARENT;
197
a1fa407d
JSP
198 /*
199 * at this point, we have uerror and lerror indicating
200 * possible errors with the lookups in the upper and lower
201 * layers. additionally, uppervp and lowervp are (locked)
202 * references to existing vnodes in the upper and lower layers.
203 *
204 * there are now three cases to consider.
205 * 1. if both layers returned an error, then return whatever
206 * error the upper layer generated.
207 *
208 * 2. if the top layer failed and the bottom layer succeeded
209 * then two subcases occur.
210 * a. the bottom vnode is not a directory, in which
211 * case just return a new union vnode referencing
212 * an empty top layer and the existing bottom layer.
213 * b. the bottom vnode is a directory, in which case
214 * create a new directory in the top-level and
215 * continue as in case 3.
216 *
217 * 3. if the top layer succeeded then return a new union
218 * vnode referencing whatever the new top layer and
219 * whatever the bottom layer returned.
220 */
221
ed5969c8
JSP
222 *ap->a_vpp = NULLVP;
223
a1fa407d
JSP
224 /* case 1. */
225 if ((uerror != 0) && (lerror != 0)) {
a1fa407d
JSP
226 return (uerror);
227 }
228
229 /* case 2. */
230 if (uerror != 0 /* && (lerror == 0) */ ) {
231 if (lowervp->v_type == VDIR) { /* case 2b. */
e2a2f3a7
JSP
232 dun->un_flags &= ~UN_ULOCK;
233 VOP_UNLOCK(upperdvp);
3b293975 234 uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
e2a2f3a7
JSP
235 VOP_LOCK(upperdvp);
236 dun->un_flags |= UN_ULOCK;
237
a1fa407d
JSP
238 if (uerror) {
239 if (lowervp) {
240 vput(lowervp);
3b293975 241 lowervp = NULLVP;
a1fa407d
JSP
242 }
243 return (uerror);
244 }
245 }
246 }
247
01dac67e
JSP
248 if (lowervp)
249 VOP_UNLOCK(lowervp);
250
3b293975
JSP
251 error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
252 uppervp, lowervp);
253
01dac67e
JSP
254 if (error) {
255 if (uppervp)
e2a2f3a7 256 vput(uppervp);
01dac67e
JSP
257 if (lowervp)
258 vrele(lowervp);
259 } else {
81be6ee0
JSP
260 if (*ap->a_vpp != dvp)
261 if (!lockparent || !(cnp->cn_flags & ISLASTCN))
262 VOP_UNLOCK(dvp);
01dac67e
JSP
263 }
264
265 return (error);
a1fa407d
JSP
266}
267
12abe7b1
JSP
268int
269union_create(ap)
270 struct vop_create_args /* {
271 struct vnode *a_dvp;
272 struct vnode **a_vpp;
273 struct componentname *a_cnp;
274 struct vattr *a_vap;
275 } */ *ap;
276{
277 struct union_node *un = VTOUNION(ap->a_dvp);
278 struct vnode *dvp = un->un_uppervp;
279
280 if (dvp) {
281 int error;
282 struct vnode *vp;
12abe7b1
JSP
283
284 VREF(dvp);
e2a2f3a7 285 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
286 vput(ap->a_dvp);
287 error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap);
288 if (error)
289 return (error);
290
291 error = union_allocvp(
292 ap->a_vpp,
79f80c71
JSP
293 ap->a_dvp->v_mount,
294 ap->a_dvp,
01dac67e 295 NULLVP,
12abe7b1
JSP
296 ap->a_cnp,
297 vp,
298 NULLVP);
01dac67e 299 if (error)
e2a2f3a7 300 vput(vp);
12abe7b1
JSP
301 return (error);
302 }
303
304 vput(ap->a_dvp);
305 return (EROFS);
306}
307
308int
309union_mknod(ap)
310 struct vop_mknod_args /* {
311 struct vnode *a_dvp;
312 struct vnode **a_vpp;
313 struct componentname *a_cnp;
314 struct vattr *a_vap;
315 } */ *ap;
316{
317 struct union_node *un = VTOUNION(ap->a_dvp);
318 struct vnode *dvp = un->un_uppervp;
319
320 if (dvp) {
321 int error;
322 struct vnode *vp;
12abe7b1
JSP
323
324 VREF(dvp);
e2a2f3a7 325 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
326 vput(ap->a_dvp);
327 error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap);
328 if (error)
329 return (error);
330
01dac67e
JSP
331 if (vp) {
332 error = union_allocvp(
333 ap->a_vpp,
79f80c71
JSP
334 ap->a_dvp->v_mount,
335 ap->a_dvp,
01dac67e
JSP
336 NULLVP,
337 ap->a_cnp,
338 vp,
339 NULLVP);
01dac67e 340 if (error)
e2a2f3a7 341 vput(vp);
01dac67e 342 }
12abe7b1
JSP
343 return (error);
344 }
345
346 vput(ap->a_dvp);
347 return (EROFS);
348}
349
a1fa407d
JSP
350int
351union_open(ap)
352 struct vop_open_args /* {
353 struct vnodeop_desc *a_desc;
354 struct vnode *a_vp;
355 int a_mode;
356 struct ucred *a_cred;
357 struct proc *a_p;
358 } */ *ap;
359{
360 struct union_node *un = VTOUNION(ap->a_vp);
01dac67e 361 struct vnode *tvp;
a1fa407d
JSP
362 int mode = ap->a_mode;
363 struct ucred *cred = ap->a_cred;
364 struct proc *p = ap->a_p;
01dac67e 365 int error;
a1fa407d
JSP
366
367 /*
368 * If there is an existing upper vp then simply open that.
369 */
01dac67e
JSP
370 tvp = un->un_uppervp;
371 if (tvp == NULLVP) {
a1fa407d 372 /*
01dac67e
JSP
373 * If the lower vnode is being opened for writing, then
374 * copy the file contents to the upper vnode and open that,
375 * otherwise can simply open the lower vnode.
a1fa407d 376 */
01dac67e
JSP
377 tvp = un->un_lowervp;
378 if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
81be6ee0 379 struct vnode *vp;
3b293975 380 int i;
01dac67e
JSP
381
382 /*
383 * Open the named file in the upper layer. Note that
384 * the file may have come into existence *since* the
385 * lookup was done, since the upper layer may really
386 * be a loopback mount of some other filesystem...
387 * so open the file with exclusive create and barf if
388 * it already exists.
ed5969c8 389 * XXX - perhaps should re-lookup the node (once more
01dac67e
JSP
390 * with feeling) and simply open that. Who knows.
391 */
3b293975 392 error = union_vn_create(&vp, un, p);
01dac67e
JSP
393 if (error)
394 return (error);
e2a2f3a7 395
01dac67e 396 /* at this point, uppervp is locked */
e2a2f3a7
JSP
397 un->un_uppervp = vp; /* XXX */
398 un->un_flags |= UN_ULOCK;
01dac67e
JSP
399
400 /*
401 * Now, if the file is being opened with truncation,
402 * then the (new) upper vnode is ready to fly,
403 * otherwise the data from the lower vnode must be
404 * copied to the upper layer first. This only works
405 * for regular files (check is made above).
406 */
407 if ((mode & O_TRUNC) == 0) {
408 /*
409 * XXX - should not ignore errors
410 * from VOP_CLOSE
411 */
81be6ee0 412 VOP_LOCK(tvp);
01dac67e
JSP
413 error = VOP_OPEN(tvp, FREAD, cred, p);
414 if (error == 0) {
415 error = union_copyfile(p, cred,
416 tvp, un->un_uppervp);
417 VOP_UNLOCK(tvp);
418 (void) VOP_CLOSE(tvp, FREAD);
419 } else {
420 VOP_UNLOCK(tvp);
421 }
e2a2f3a7
JSP
422
423 un->un_flags &= ~UN_ULOCK;
01dac67e 424 VOP_UNLOCK(un->un_uppervp);
15a86f7e 425 union_vn_close(un->un_uppervp, FWRITE, cred, p);
01dac67e 426 VOP_LOCK(un->un_uppervp);
e2a2f3a7
JSP
427 un->un_flags |= UN_ULOCK;
428
3b293975 429 if (!error)
ed5969c8 430 uprintf("union: copied up %s\n",
3b293975
JSP
431 un->un_path);
432 }
433
434 /*
435 * Subsequent IOs will go to the top layer, so
436 * call close on the lower vnode and open on the
437 * upper vnode to ensure that the filesystem keeps
438 * its references counts right. This doesn't do
439 * the right thing with (cred) and (FREAD) though.
440 * Ignoring error returns is not righ, either.
441 */
ed5969c8 442 for (i = 0; i < un->un_openl; i++) {
3b293975
JSP
443 (void) VOP_CLOSE(tvp, FREAD);
444 (void) VOP_OPEN(un->un_uppervp, FREAD, cred, p);
a1fa407d 445 }
ed5969c8 446 un->un_openl = 0;
3b293975 447
01dac67e
JSP
448 if (error == 0)
449 error = VOP_OPEN(un->un_uppervp, mode, cred, p);
01dac67e 450 return (error);
a1fa407d 451 }
e2a2f3a7
JSP
452
453 /*
454 * Just open the lower vnode
455 */
ed5969c8 456 un->un_openl++;
e2a2f3a7
JSP
457 VOP_LOCK(tvp);
458 error = VOP_OPEN(tvp, mode, cred, p);
459 VOP_UNLOCK(tvp);
460
461 return (error);
a1fa407d
JSP
462 }
463
01dac67e 464 error = VOP_OPEN(tvp, mode, cred, p);
01dac67e
JSP
465
466 return (error);
a1fa407d
JSP
467}
468
12abe7b1
JSP
469int
470union_close(ap)
471 struct vop_close_args /* {
472 struct vnode *a_vp;
473 int a_fflag;
474 struct ucred *a_cred;
475 struct proc *a_p;
476 } */ *ap;
477{
3b293975
JSP
478 struct union_node *un = VTOUNION(ap->a_vp);
479 struct vnode *vp;
12abe7b1 480
3b293975
JSP
481 if (un->un_uppervp) {
482 vp = un->un_uppervp;
483 } else {
ed5969c8
JSP
484#ifdef UNION_DIAGNOSTIC
485 if (un->un_openl <= 0)
486 panic("union: un_openl cnt");
3b293975 487#endif
ed5969c8 488 --un->un_openl;
3b293975
JSP
489 vp = un->un_lowervp;
490 }
ed5969c8 491
3b293975 492 return (VOP_CLOSE(vp, ap->a_fflag, ap->a_cred, ap->a_p));
12abe7b1
JSP
493}
494
495/*
496 * Check access permission on the union vnode.
497 * The access check being enforced is to check
498 * against both the underlying vnode, and any
499 * copied vnode. This ensures that no additional
500 * file permissions are given away simply because
501 * the user caused an implicit file copy.
502 */
503int
504union_access(ap)
505 struct vop_access_args /* {
506 struct vnodeop_desc *a_desc;
507 struct vnode *a_vp;
508 int a_mode;
509 struct ucred *a_cred;
510 struct proc *a_p;
511 } */ *ap;
512{
513 struct union_node *un = VTOUNION(ap->a_vp);
01dac67e 514 int error = 0;
12abe7b1
JSP
515 struct vnode *vp;
516
517 if (vp = un->un_lowervp) {
01dac67e 518 VOP_LOCK(vp);
12abe7b1 519 error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);
01dac67e 520 VOP_UNLOCK(vp);
12abe7b1
JSP
521 if (error)
522 return (error);
523 }
524
e2a2f3a7 525 if (vp = un->un_uppervp)
01dac67e 526 error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);
01dac67e
JSP
527
528 return (error);
12abe7b1
JSP
529}
530
a1fa407d
JSP
531/*
532 * We handle getattr only to change the fsid.
533 */
534int
535union_getattr(ap)
536 struct vop_getattr_args /* {
537 struct vnode *a_vp;
538 struct vattr *a_vap;
539 struct ucred *a_cred;
540 struct proc *a_p;
541 } */ *ap;
542{
543 int error;
01dac67e 544 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 545 int dolock = (vp == LOWERVP(ap->a_vp));
01dac67e 546
e2a2f3a7
JSP
547 if (dolock)
548 VOP_LOCK(vp);
01dac67e 549 error = VOP_GETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p);
e2a2f3a7
JSP
550 if (dolock)
551 VOP_UNLOCK(vp);
a1fa407d 552
a1fa407d
JSP
553 /* Requires that arguments be restored. */
554 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
555 return (0);
556}
557
a1fa407d 558int
01dac67e 559union_setattr(ap)
12abe7b1 560 struct vop_setattr_args /* {
a1fa407d 561 struct vnode *a_vp;
12abe7b1 562 struct vattr *a_vap;
a1fa407d 563 struct ucred *a_cred;
12abe7b1 564 struct proc *a_p;
a1fa407d
JSP
565 } */ *ap;
566{
567 struct union_node *un = VTOUNION(ap->a_vp);
12abe7b1 568 int error;
a1fa407d 569
12abe7b1 570 if (un->un_uppervp) {
12abe7b1
JSP
571 error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
572 ap->a_cred, ap->a_p);
12abe7b1
JSP
573 } else {
574 /*
575 * XXX should do a copyfile (perhaps only if
576 * the file permission change, which would not
577 * track va_ctime correctly).
578 */
579 error = EROFS;
580 }
a1fa407d 581
12abe7b1 582 return (error);
a1fa407d
JSP
583}
584
585int
12abe7b1
JSP
586union_read(ap)
587 struct vop_read_args /* {
a1fa407d 588 struct vnode *a_vp;
12abe7b1
JSP
589 struct uio *a_uio;
590 int a_ioflag;
591 struct ucred *a_cred;
a1fa407d
JSP
592 } */ *ap;
593{
12abe7b1
JSP
594 int error;
595 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 596 int dolock = (vp == LOWERVP(ap->a_vp));
a1fa407d 597
e2a2f3a7
JSP
598 if (dolock)
599 VOP_LOCK(vp);
12abe7b1 600 error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
e2a2f3a7
JSP
601 if (dolock)
602 VOP_UNLOCK(vp);
12abe7b1
JSP
603
604 return (error);
a1fa407d
JSP
605}
606
607int
12abe7b1
JSP
608union_write(ap)
609 struct vop_read_args /* {
a1fa407d 610 struct vnode *a_vp;
12abe7b1
JSP
611 struct uio *a_uio;
612 int a_ioflag;
613 struct ucred *a_cred;
a1fa407d
JSP
614 } */ *ap;
615{
12abe7b1
JSP
616 int error;
617 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 618 int dolock = (vp == LOWERVP(ap->a_vp));
a1fa407d 619
e2a2f3a7
JSP
620 if (dolock)
621 VOP_LOCK(vp);
12abe7b1 622 error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
e2a2f3a7
JSP
623 if (dolock)
624 VOP_UNLOCK(vp);
a1fa407d 625
12abe7b1
JSP
626 return (error);
627}
a1fa407d
JSP
628
629int
12abe7b1
JSP
630union_ioctl(ap)
631 struct vop_ioctl_args /* {
a1fa407d 632 struct vnode *a_vp;
12abe7b1
JSP
633 int a_command;
634 caddr_t a_data;
635 int a_fflag;
636 struct ucred *a_cred;
637 struct proc *a_p;
a1fa407d
JSP
638 } */ *ap;
639{
a1fa407d 640
12abe7b1
JSP
641 return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data,
642 ap->a_fflag, ap->a_cred, ap->a_p));
a1fa407d
JSP
643}
644
a1fa407d 645int
12abe7b1
JSP
646union_select(ap)
647 struct vop_select_args /* {
648 struct vnode *a_vp;
649 int a_which;
650 int a_fflags;
651 struct ucred *a_cred;
652 struct proc *a_p;
653 } */ *ap;
654{
655
656 return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags,
657 ap->a_cred, ap->a_p));
658}
659
660int
661union_mmap(ap)
662 struct vop_mmap_args /* {
663 struct vnode *a_vp;
664 int a_fflags;
665 struct ucred *a_cred;
666 struct proc *a_p;
667 } */ *ap;
668{
669
670 return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags,
671 ap->a_cred, ap->a_p));
672}
673
674int
675union_fsync(ap)
676 struct vop_fsync_args /* {
677 struct vnode *a_vp;
678 struct ucred *a_cred;
679 int a_waitfor;
680 struct proc *a_p;
681 } */ *ap;
682{
683 int error = 0;
684 struct vnode *targetvp = OTHERVP(ap->a_vp);
685
686 if (targetvp) {
e2a2f3a7
JSP
687 int dolock = (targetvp == LOWERVP(ap->a_vp));
688
689 if (dolock)
690 VOP_LOCK(targetvp);
12abe7b1
JSP
691 error = VOP_FSYNC(targetvp, ap->a_cred,
692 ap->a_waitfor, ap->a_p);
e2a2f3a7
JSP
693 if (dolock)
694 VOP_UNLOCK(targetvp);
12abe7b1
JSP
695 }
696
697 return (error);
698}
699
700int
701union_seek(ap)
702 struct vop_seek_args /* {
703 struct vnode *a_vp;
704 off_t a_oldoff;
705 off_t a_newoff;
706 struct ucred *a_cred;
707 } */ *ap;
708{
709
710 return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred));
711}
712
713int
714union_remove(ap)
715 struct vop_remove_args /* {
716 struct vnode *a_dvp;
717 struct vnode *a_vp;
718 struct componentname *a_cnp;
a1fa407d
JSP
719 } */ *ap;
720{
a1fa407d 721 int error;
12abe7b1
JSP
722 struct union_node *dun = VTOUNION(ap->a_dvp);
723 struct union_node *un = VTOUNION(ap->a_vp);
a1fa407d 724
12abe7b1
JSP
725 if (dun->un_uppervp && un->un_uppervp) {
726 struct vnode *dvp = dun->un_uppervp;
727 struct vnode *vp = un->un_uppervp;
a1fa407d 728
12abe7b1 729 VREF(dvp);
e2a2f3a7 730 dun->un_flags |= UN_KLOCK;
12abe7b1
JSP
731 vput(ap->a_dvp);
732 VREF(vp);
e2a2f3a7 733 un->un_flags |= UN_KLOCK;
12abe7b1 734 vput(ap->a_vp);
a1fa407d 735
12abe7b1 736 error = VOP_REMOVE(dvp, vp, ap->a_cnp);
ed5969c8
JSP
737 if (!error)
738 union_removed_upper(un);
739
740 /*
741 * XXX: should create a whiteout here
742 */
12abe7b1
JSP
743 } else {
744 /*
745 * XXX: should create a whiteout here
746 */
747 vput(ap->a_dvp);
748 vput(ap->a_vp);
749 error = EROFS;
750 }
751
752 return (error);
753}
754
755int
756union_link(ap)
757 struct vop_link_args /* {
758 struct vnode *a_vp;
759 struct vnode *a_tdvp;
760 struct componentname *a_cnp;
761 } */ *ap;
762{
763 int error;
764 struct union_node *dun = VTOUNION(ap->a_vp);
765 struct union_node *un = VTOUNION(ap->a_tdvp);
766
767 if (dun->un_uppervp && un->un_uppervp) {
768 struct vnode *dvp = dun->un_uppervp;
769 struct vnode *vp = un->un_uppervp;
770
771 VREF(dvp);
e2a2f3a7 772 dun->un_flags |= UN_KLOCK;
12abe7b1
JSP
773 vput(ap->a_vp);
774 VREF(vp);
775 vrele(ap->a_tdvp);
776
777 error = VOP_LINK(dvp, vp, ap->a_cnp);
778 } else {
779 /*
780 * XXX: need to copy to upper layer
781 * and do the link there.
782 */
783 vput(ap->a_vp);
784 vrele(ap->a_tdvp);
785 error = EROFS;
786 }
a1fa407d
JSP
787
788 return (error);
789}
790
12abe7b1
JSP
791int
792union_rename(ap)
793 struct vop_rename_args /* {
794 struct vnode *a_fdvp;
795 struct vnode *a_fvp;
796 struct componentname *a_fcnp;
797 struct vnode *a_tdvp;
798 struct vnode *a_tvp;
799 struct componentname *a_tcnp;
800 } */ *ap;
801{
802 int error;
803
804 struct vnode *fdvp = ap->a_fdvp;
805 struct vnode *fvp = ap->a_fvp;
806 struct vnode *tdvp = ap->a_tdvp;
807 struct vnode *tvp = ap->a_tvp;
808
809 if (fdvp->v_op == union_vnodeop_p) { /* always true */
810 struct union_node *un = VTOUNION(fdvp);
3b293975 811 if (un->un_uppervp == NULLVP) {
12abe7b1
JSP
812 error = EROFS;
813 goto bad;
814 }
815
816 fdvp = un->un_uppervp;
817 VREF(fdvp);
818 vrele(ap->a_fdvp);
819 }
820
821 if (fvp->v_op == union_vnodeop_p) { /* always true */
822 struct union_node *un = VTOUNION(fvp);
3b293975 823 if (un->un_uppervp == NULLVP) {
12abe7b1
JSP
824 error = EROFS;
825 goto bad;
826 }
827
828 fvp = un->un_uppervp;
829 VREF(fvp);
830 vrele(ap->a_fvp);
831 }
832
833 if (tdvp->v_op == union_vnodeop_p) {
834 struct union_node *un = VTOUNION(tdvp);
3b293975 835 if (un->un_uppervp == NULLVP) {
12abe7b1
JSP
836 error = EROFS;
837 goto bad;
838 }
839
840 tdvp = un->un_uppervp;
841 VREF(tdvp);
e2a2f3a7 842 un->un_flags |= UN_KLOCK;
3b293975 843 vput(ap->a_tdvp);
12abe7b1
JSP
844 }
845
846 if (tvp && tvp->v_op == union_vnodeop_p) {
847 struct union_node *un = VTOUNION(tvp);
3b293975 848 if (un->un_uppervp == NULLVP) {
12abe7b1
JSP
849 error = EROFS;
850 goto bad;
851 }
852
853 tvp = un->un_uppervp;
854 VREF(tvp);
e2a2f3a7 855 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
856 vput(ap->a_tvp);
857 }
858
859 return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
860
861bad:
862 vrele(fdvp);
863 vrele(fvp);
864 vput(tdvp);
865 if (tvp)
866 vput(tvp);
867
868 return (error);
869}
870
871int
872union_mkdir(ap)
873 struct vop_mkdir_args /* {
874 struct vnode *a_dvp;
875 struct vnode **a_vpp;
876 struct componentname *a_cnp;
877 struct vattr *a_vap;
878 } */ *ap;
879{
880 struct union_node *un = VTOUNION(ap->a_dvp);
881 struct vnode *dvp = un->un_uppervp;
882
883 if (dvp) {
884 int error;
885 struct vnode *vp;
12abe7b1
JSP
886
887 VREF(dvp);
e2a2f3a7 888 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
889 vput(ap->a_dvp);
890 error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap);
891 if (error)
892 return (error);
893
894 error = union_allocvp(
895 ap->a_vpp,
79f80c71
JSP
896 ap->a_dvp->v_mount,
897 ap->a_dvp,
01dac67e 898 NULLVP,
12abe7b1
JSP
899 ap->a_cnp,
900 vp,
901 NULLVP);
01dac67e 902 if (error)
e2a2f3a7 903 vput(vp);
12abe7b1
JSP
904 return (error);
905 }
906
907 vput(ap->a_dvp);
908 return (EROFS);
909}
910
911int
912union_rmdir(ap)
913 struct vop_rmdir_args /* {
914 struct vnode *a_dvp;
915 struct vnode *a_vp;
916 struct componentname *a_cnp;
917 } */ *ap;
918{
919 int error;
920 struct union_node *dun = VTOUNION(ap->a_dvp);
921 struct union_node *un = VTOUNION(ap->a_vp);
922
923 if (dun->un_uppervp && un->un_uppervp) {
924 struct vnode *dvp = dun->un_uppervp;
925 struct vnode *vp = un->un_uppervp;
926
927 VREF(dvp);
e2a2f3a7 928 dun->un_flags |= UN_KLOCK;
12abe7b1
JSP
929 vput(ap->a_dvp);
930 VREF(vp);
e2a2f3a7 931 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
932 vput(ap->a_vp);
933
e2a2f3a7 934 error = VOP_RMDIR(dvp, vp, ap->a_cnp);
ed5969c8
JSP
935 if (!error)
936 union_removed_upper(un);
937
938 /*
939 * XXX: should create a whiteout here
940 */
12abe7b1
JSP
941 } else {
942 /*
943 * XXX: should create a whiteout here
944 */
945 vput(ap->a_dvp);
946 vput(ap->a_vp);
947 error = EROFS;
948 }
949
950 return (error);
951}
952
953int
954union_symlink(ap)
955 struct vop_symlink_args /* {
956 struct vnode *a_dvp;
957 struct vnode **a_vpp;
958 struct componentname *a_cnp;
959 struct vattr *a_vap;
960 char *a_target;
961 } */ *ap;
962{
963 struct union_node *un = VTOUNION(ap->a_dvp);
964 struct vnode *dvp = un->un_uppervp;
965
966 if (dvp) {
967 int error;
968 struct vnode *vp;
969 struct mount *mp = ap->a_dvp->v_mount;
970
971 VREF(dvp);
e2a2f3a7 972 un->un_flags |= UN_KLOCK;
12abe7b1
JSP
973 vput(ap->a_dvp);
974 error = VOP_SYMLINK(dvp, &vp, ap->a_cnp,
975 ap->a_vap, ap->a_target);
3b293975 976 *ap->a_vpp = NULLVP;
12abe7b1
JSP
977 return (error);
978 }
979
980 vput(ap->a_dvp);
981 return (EROFS);
982}
a1fa407d
JSP
983
984/*
12abe7b1
JSP
985 * union_readdir works in concert with getdirentries and
986 * readdir(3) to provide a list of entries in the unioned
987 * directories. getdirentries is responsible for walking
988 * down the union stack. readdir(3) is responsible for
989 * eliminating duplicate names from the returned data stream.
a1fa407d
JSP
990 */
991int
12abe7b1
JSP
992union_readdir(ap)
993 struct vop_readdir_args /* {
994 struct vnodeop_desc *a_desc;
995 struct vnode *a_vp;
996 struct uio *a_uio;
997 struct ucred *a_cred;
998 } */ *ap;
999{
1000 int error = 0;
1001 struct union_node *un = VTOUNION(ap->a_vp);
1002
e2a2f3a7
JSP
1003 if (un->un_uppervp)
1004 error = VOP_READDIR(un->un_uppervp, ap->a_uio, ap->a_cred);
12abe7b1
JSP
1005
1006 return (error);
1007}
1008
1009int
1010union_readlink(ap)
1011 struct vop_readlink_args /* {
1012 struct vnode *a_vp;
1013 struct uio *a_uio;
1014 struct ucred *a_cred;
a1fa407d
JSP
1015 } */ *ap;
1016{
a1fa407d 1017 int error;
12abe7b1 1018 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 1019 int dolock = (vp == LOWERVP(ap->a_vp));
a1fa407d 1020
e2a2f3a7
JSP
1021 if (dolock)
1022 VOP_LOCK(vp);
12abe7b1 1023 error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
e2a2f3a7
JSP
1024 if (dolock)
1025 VOP_UNLOCK(vp);
a1fa407d 1026
12abe7b1
JSP
1027 return (error);
1028}
a1fa407d 1029
12abe7b1
JSP
1030int
1031union_abortop(ap)
1032 struct vop_abortop_args /* {
1033 struct vnode *a_dvp;
1034 struct componentname *a_cnp;
1035 } */ *ap;
1036{
1037 int error;
01dac67e 1038 struct vnode *vp = OTHERVP(ap->a_dvp);
12abe7b1
JSP
1039 struct union_node *un = VTOUNION(ap->a_dvp);
1040 int islocked = un->un_flags & UN_LOCKED;
e2a2f3a7 1041 int dolock = (vp == LOWERVP(ap->a_dvp));
a1fa407d 1042
e2a2f3a7 1043 if (islocked && dolock)
12abe7b1
JSP
1044 VOP_LOCK(vp);
1045 error = VOP_ABORTOP(vp, ap->a_cnp);
e2a2f3a7 1046 if (islocked && dolock)
12abe7b1 1047 VOP_UNLOCK(vp);
a1fa407d
JSP
1048
1049 return (error);
1050}
1051
12abe7b1
JSP
1052int
1053union_inactive(ap)
1054 struct vop_inactive_args /* {
1055 struct vnode *a_vp;
1056 } */ *ap;
1057{
1058
1059 /*
1060 * Do nothing (and _don't_ bypass).
1061 * Wait to vrele lowervp until reclaim,
1062 * so that until then our union_node is in the
1063 * cache and reusable.
1064 *
1065 * NEEDSWORK: Someday, consider inactive'ing
1066 * the lowervp and then trying to reactivate it
1067 * with capabilities (v_id)
1068 * like they do in the name lookup cache code.
1069 * That's too much work for now.
1070 */
79f80c71 1071
ed5969c8 1072#ifdef UNION_DIAGNOSTIC
79f80c71
JSP
1073 struct union_node *un = VTOUNION(ap->a_vp);
1074
1075 if (un->un_flags & UN_LOCKED)
1076 panic("union: inactivating locked node");
1077#endif
1078
12abe7b1
JSP
1079 return (0);
1080}
1081
1082int
1083union_reclaim(ap)
1084 struct vop_reclaim_args /* {
1085 struct vnode *a_vp;
1086 } */ *ap;
1087{
1088 struct vnode *vp = ap->a_vp;
1089 struct union_node *un = VTOUNION(vp);
1090 struct vnode *uppervp = un->un_uppervp;
1091 struct vnode *lowervp = un->un_lowervp;
1092 struct vnode *dirvp = un->un_dirvp;
1093 char *path = un->un_path;
1094
1095 /*
1096 * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p,
1097 * so we can't call VOPs on ourself.
1098 */
1099 /* After this assignment, this node will not be re-used. */
3b293975
JSP
1100 un->un_uppervp = NULLVP;
1101 un->un_lowervp = NULLVP;
1102 un->un_dirvp = NULLVP;
12abe7b1
JSP
1103 un->un_path = NULL;
1104 union_freevp(vp);
1105 if (uppervp)
1106 vrele(uppervp);
1107 if (lowervp)
1108 vrele(lowervp);
1109 if (dirvp)
1110 vrele(dirvp);
1111 if (path)
1112 free(path, M_TEMP);
1113 return (0);
1114}
1115
a1fa407d
JSP
1116int
1117union_lock(ap)
1118 struct vop_lock_args *ap;
1119{
1120 struct union_node *un = VTOUNION(ap->a_vp);
1121
e2a2f3a7
JSP
1122 if (un->un_uppervp) {
1123 if ((un->un_flags & UN_ULOCK) == 0) {
1124 VOP_LOCK(un->un_uppervp);
1125 un->un_flags |= UN_ULOCK;
1126 }
1127#ifdef DIAGNOSTIC
1128 if (un->un_flags & UN_KLOCK)
1129 panic("union: dangling upper lock");
1130#endif
1131 }
1132
01dac67e 1133 while (un->un_flags & UN_LOCKED) {
a1fa407d 1134#ifdef DIAGNOSTIC
79f80c71
JSP
1135 if (curproc && un->un_pid == curproc->p_pid &&
1136 un->un_pid > -1 && curproc->p_pid > -1)
1137 panic("union: locking against myself");
a1fa407d 1138#endif
a1fa407d
JSP
1139 un->un_flags |= UN_WANT;
1140 sleep((caddr_t) &un->un_flags, PINOD);
1141 }
1142 un->un_flags |= UN_LOCKED;
79f80c71 1143
a1fa407d 1144#ifdef DIAGNOSTIC
79f80c71
JSP
1145 if (curproc)
1146 un->un_pid = curproc->p_pid;
1147 else
1148 un->un_pid = -1;
a1fa407d 1149#endif
15a86f7e
JSP
1150
1151 return (0);
a1fa407d
JSP
1152}
1153
1154int
1155union_unlock(ap)
1156 struct vop_lock_args *ap;
1157{
1158 struct union_node *un = VTOUNION(ap->a_vp);
1159
1160#ifdef DIAGNOSTIC
a1fa407d
JSP
1161 if ((un->un_flags & UN_LOCKED) == 0)
1162 panic("union: unlock unlocked node");
79f80c71
JSP
1163 if (curproc && un->un_pid != curproc->p_pid &&
1164 curproc->p_pid > -1 && un->un_pid > -1)
01dac67e 1165 panic("union: unlocking other process's union node");
a1fa407d
JSP
1166#endif
1167
a1fa407d 1168 un->un_flags &= ~UN_LOCKED;
e2a2f3a7
JSP
1169
1170 if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK)
1171 VOP_UNLOCK(un->un_uppervp);
1172
1173 un->un_flags &= ~(UN_ULOCK|UN_KLOCK);
1174
a1fa407d
JSP
1175 if (un->un_flags & UN_WANT) {
1176 un->un_flags &= ~UN_WANT;
1177 wakeup((caddr_t) &un->un_flags);
1178 }
1179
1180#ifdef DIAGNOSTIC
1181 un->un_pid = 0;
1182#endif
15a86f7e
JSP
1183
1184 return (0);
a1fa407d
JSP
1185}
1186
12abe7b1
JSP
1187int
1188union_bmap(ap)
1189 struct vop_bmap_args /* {
1190 struct vnode *a_vp;
1191 daddr_t a_bn;
1192 struct vnode **a_vpp;
1193 daddr_t *a_bnp;
1194 int *a_runp;
1195 } */ *ap;
1196{
1197 int error;
1198 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 1199 int dolock = (vp == LOWERVP(ap->a_vp));
12abe7b1 1200
e2a2f3a7
JSP
1201 if (dolock)
1202 VOP_LOCK(vp);
12abe7b1 1203 error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp);
e2a2f3a7
JSP
1204 if (dolock)
1205 VOP_UNLOCK(vp);
12abe7b1
JSP
1206
1207 return (error);
1208}
1209
1210int
1211union_print(ap)
1212 struct vop_print_args /* {
1213 struct vnode *a_vp;
1214 } */ *ap;
1215{
1216 struct vnode *vp = ap->a_vp;
1217
1218 printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n",
1219 vp, UPPERVP(vp), LOWERVP(vp));
1220 return (0);
1221}
1222
1223int
1224union_islocked(ap)
1225 struct vop_islocked_args /* {
1226 struct vnode *a_vp;
1227 } */ *ap;
1228{
1229
1230 return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0);
1231}
1232
1233int
1234union_pathconf(ap)
1235 struct vop_pathconf_args /* {
1236 struct vnode *a_vp;
1237 int a_name;
1238 int *a_retval;
1239 } */ *ap;
1240{
1241 int error;
1242 struct vnode *vp = OTHERVP(ap->a_vp);
e2a2f3a7 1243 int dolock = (vp == LOWERVP(ap->a_vp));
12abe7b1 1244
e2a2f3a7
JSP
1245 if (dolock)
1246 VOP_LOCK(vp);
12abe7b1 1247 error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval);
e2a2f3a7
JSP
1248 if (dolock)
1249 VOP_UNLOCK(vp);
12abe7b1
JSP
1250
1251 return (error);
1252}
1253
1254int
1255union_advlock(ap)
1256 struct vop_advlock_args /* {
1257 struct vnode *a_vp;
1258 caddr_t a_id;
1259 int a_op;
1260 struct flock *a_fl;
1261 int a_flags;
1262 } */ *ap;
1263{
1264
1265 return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op,
1266 ap->a_fl, ap->a_flags));
1267}
1268
1269
a1fa407d 1270/*
12abe7b1
JSP
1271 * XXX - vop_strategy must be hand coded because it has no
1272 * vnode in its arguments.
1273 * This goes away with a merged VM/buffer cache.
a1fa407d 1274 */
12abe7b1
JSP
1275int
1276union_strategy(ap)
1277 struct vop_strategy_args /* {
1278 struct buf *a_bp;
1279 } */ *ap;
1280{
1281 struct buf *bp = ap->a_bp;
1282 int error;
1283 struct vnode *savedvp;
1284
1285 savedvp = bp->b_vp;
1286 bp->b_vp = OTHERVP(bp->b_vp);
a1fa407d 1287
12abe7b1 1288#ifdef DIAGNOSTIC
3b293975 1289 if (bp->b_vp == NULLVP)
12abe7b1
JSP
1290 panic("union_strategy: nil vp");
1291 if (((bp->b_flags & B_READ) == 0) &&
1292 (bp->b_vp == LOWERVP(savedvp)))
1293 panic("union_strategy: writing to lowervp");
1294#endif
a1fa407d 1295
12abe7b1
JSP
1296 error = VOP_STRATEGY(bp);
1297 bp->b_vp = savedvp;
a1fa407d 1298
12abe7b1
JSP
1299 return (error);
1300}
a1fa407d 1301
12abe7b1
JSP
1302/*
1303 * Global vfs data structures
1304 */
1305int (**union_vnodeop_p)();
01dac67e 1306struct vnodeopv_entry_desc union_vnodeop_entries[] = {
12abe7b1
JSP
1307 { &vop_default_desc, vn_default_error },
1308 { &vop_lookup_desc, union_lookup }, /* lookup */
1309 { &vop_create_desc, union_create }, /* create */
1310 { &vop_mknod_desc, union_mknod }, /* mknod */
1311 { &vop_open_desc, union_open }, /* open */
1312 { &vop_close_desc, union_close }, /* close */
1313 { &vop_access_desc, union_access }, /* access */
1314 { &vop_getattr_desc, union_getattr }, /* getattr */
1315 { &vop_setattr_desc, union_setattr }, /* setattr */
1316 { &vop_read_desc, union_read }, /* read */
1317 { &vop_write_desc, union_write }, /* write */
1318 { &vop_ioctl_desc, union_ioctl }, /* ioctl */
1319 { &vop_select_desc, union_select }, /* select */
1320 { &vop_mmap_desc, union_mmap }, /* mmap */
1321 { &vop_fsync_desc, union_fsync }, /* fsync */
1322 { &vop_seek_desc, union_seek }, /* seek */
1323 { &vop_remove_desc, union_remove }, /* remove */
1324 { &vop_link_desc, union_link }, /* link */
1325 { &vop_rename_desc, union_rename }, /* rename */
1326 { &vop_mkdir_desc, union_mkdir }, /* mkdir */
1327 { &vop_rmdir_desc, union_rmdir }, /* rmdir */
1328 { &vop_symlink_desc, union_symlink }, /* symlink */
1329 { &vop_readdir_desc, union_readdir }, /* readdir */
1330 { &vop_readlink_desc, union_readlink }, /* readlink */
1331 { &vop_abortop_desc, union_abortop }, /* abortop */
1332 { &vop_inactive_desc, union_inactive }, /* inactive */
1333 { &vop_reclaim_desc, union_reclaim }, /* reclaim */
1334 { &vop_lock_desc, union_lock }, /* lock */
1335 { &vop_unlock_desc, union_unlock }, /* unlock */
1336 { &vop_bmap_desc, union_bmap }, /* bmap */
1337 { &vop_strategy_desc, union_strategy }, /* strategy */
1338 { &vop_print_desc, union_print }, /* print */
1339 { &vop_islocked_desc, union_islocked }, /* islocked */
1340 { &vop_pathconf_desc, union_pathconf }, /* pathconf */
1341 { &vop_advlock_desc, union_advlock }, /* advlock */
1342#ifdef notdef
1343 { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */
1344 { &vop_valloc_desc, union_valloc }, /* valloc */
1345 { &vop_vfree_desc, union_vfree }, /* vfree */
1346 { &vop_truncate_desc, union_truncate }, /* truncate */
1347 { &vop_update_desc, union_update }, /* update */
1348 { &vop_bwrite_desc, union_bwrite }, /* bwrite */
1349#endif
a1fa407d
JSP
1350 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
1351};
1352struct vnodeopv_desc union_vnodeop_opv_desc =
1353 { &union_vnodeop_p, union_vnodeop_entries };