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