Deleted Added
sdiff udiff text old ( 22521 ) new ( 22582 )
full compact
1/*
2 * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
3 * Copyright (c) 1992, 1993, 1994, 1995
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95
38 * $FreeBSD: head/sys/fs/unionfs/union_vnops.c 22582 1997-02-12 07:54:22Z mpp $
39 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/proc.h>
44#include <sys/file.h>
45#include <sys/time.h>
46#include <sys/stat.h>
47#include <sys/types.h>
48#include <sys/vnode.h>
49#include <sys/mount.h>
50#include <sys/namei.h>
51#include <sys/malloc.h>
52#include <sys/buf.h>
53#include <sys/queue.h>
54#include <sys/lock.h>
55#include <miscfs/union/union.h>
56
57#define FIXUP(un, p) { \
58 if (((un)->un_flags & UN_ULOCK) == 0) { \
59 union_fixup(un, p); \
60 } \
61}
62
63extern int union_abortop __P((struct vop_abortop_args *ap));
64extern int union_access __P((struct vop_access_args *ap));
65extern int union_advlock __P((struct vop_advlock_args *ap));
66extern int union_bmap __P((struct vop_bmap_args *ap));
67extern int union_close __P((struct vop_close_args *ap));
68extern int union_create __P((struct vop_create_args *ap));
69static void union_fixup __P((struct union_node *un, struct proc *p));
70extern int union_fsync __P((struct vop_fsync_args *ap));
71extern int union_getattr __P((struct vop_getattr_args *ap));
72extern int union_inactive __P((struct vop_inactive_args *ap));
73extern int union_ioctl __P((struct vop_ioctl_args *ap));
74extern int union_islocked __P((struct vop_islocked_args *ap));
75extern int union_lease __P((struct vop_lease_args *ap));
76extern int union_link __P((struct vop_link_args *ap));
77extern int union_lock __P((struct vop_lock_args *ap));
78extern int union_lookup __P((struct vop_lookup_args *ap));
79static int union_lookup1 __P((struct vnode *udvp, struct vnode **dvpp,
80 struct vnode **vpp,
81 struct componentname *cnp));
82extern int union_mkdir __P((struct vop_mkdir_args *ap));
83extern int union_mknod __P((struct vop_mknod_args *ap));
84extern int union_mmap __P((struct vop_mmap_args *ap));
85extern int union_open __P((struct vop_open_args *ap));
86extern int union_pathconf __P((struct vop_pathconf_args *ap));
87extern int union_print __P((struct vop_print_args *ap));
88extern int union_read __P((struct vop_read_args *ap));
89extern int union_readdir __P((struct vop_readdir_args *ap));
90extern int union_readlink __P((struct vop_readlink_args *ap));
91extern int union_reclaim __P((struct vop_reclaim_args *ap));
92extern int union_remove __P((struct vop_remove_args *ap));
93extern int union_rename __P((struct vop_rename_args *ap));
94extern int union_revoke __P((struct vop_revoke_args *ap));
95extern int union_rmdir __P((struct vop_rmdir_args *ap));
96extern int union_seek __P((struct vop_seek_args *ap));
97extern int union_select __P((struct vop_select_args *ap));
98extern int union_setattr __P((struct vop_setattr_args *ap));
99extern int union_strategy __P((struct vop_strategy_args *ap));
100extern int union_symlink __P((struct vop_symlink_args *ap));
101extern int union_unlock __P((struct vop_unlock_args *ap));
102extern int union_whiteout __P((struct vop_whiteout_args *ap));
103extern int union_write __P((struct vop_read_args *ap));
104
105static void
106union_fixup(un, p)
107 struct union_node *un;
108 struct proc *p;
109{
110
111 vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
112 un->un_flags |= UN_ULOCK;
113}
114
115static int
116union_lookup1(udvp, dvpp, vpp, cnp)
117 struct vnode *udvp;
118 struct vnode **dvpp;
119 struct vnode **vpp;
120 struct componentname *cnp;
121{
122 int error;
123 struct proc *p = cnp->cn_proc;
124 struct vnode *tdvp;
125 struct vnode *dvp;
126 struct mount *mp;
127
128 dvp = *dvpp;
129
130 /*
131 * If stepping up the directory tree, check for going
132 * back across the mount point, in which case do what
133 * lookup would do by stepping back down the mount
134 * hierarchy.
135 */
136 if (cnp->cn_flags & ISDOTDOT) {
137 while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
138 /*
139 * Don't do the NOCROSSMOUNT check
140 * at this level. By definition,
141 * union fs deals with namespaces, not
142 * filesystems.
143 */
144 tdvp = dvp;
145 *dvpp = dvp = dvp->v_mount->mnt_vnodecovered;
146 vput(tdvp);
147 VREF(dvp);
148 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
149 }
150 }
151
152 error = VOP_LOOKUP(dvp, &tdvp, cnp);
153 if (error)
154 return (error);
155
156 /*
157 * The parent directory will have been unlocked, unless lookup
158 * found the last component. In which case, re-lock the node
159 * here to allow it to be unlocked again (phew) in union_lookup.
160 */
161 if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN))
162 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
163
164 dvp = tdvp;
165
166 /*
167 * Lastly check if the current node is a mount point in
168 * which case walk up the mount hierarchy making sure not to
169 * bump into the root of the mount tree (ie. dvp != udvp).
170 */
171 while (dvp != udvp && (dvp->v_type == VDIR) &&
172 (mp = dvp->v_mountedhere)) {
173
174 if (vfs_busy(mp, 0, 0, p))
175 continue;
176
177 error = VFS_ROOT(mp, &tdvp);
178 vfs_unbusy(mp, p);
179 if (error) {
180 vput(dvp);
181 return (error);
182 }
183
184 vput(dvp);
185 dvp = tdvp;
186 }
187
188 *vpp = dvp;
189 return (0);
190}
191
192int
193union_lookup(ap)
194 struct vop_lookup_args /* {
195 struct vnodeop_desc *a_desc;
196 struct vnode *a_dvp;
197 struct vnode **a_vpp;
198 struct componentname *a_cnp;
199 } */ *ap;
200{
201 int error;
202 int uerror, lerror;
203 struct vnode *uppervp, *lowervp;
204 struct vnode *upperdvp, *lowerdvp;
205 struct vnode *dvp = ap->a_dvp;
206 struct union_node *dun = VTOUNION(dvp);
207 struct componentname *cnp = ap->a_cnp;
208 struct proc *p = cnp->cn_proc;
209 int lockparent = cnp->cn_flags & LOCKPARENT;
210 struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
211 struct ucred *saved_cred;
212 int iswhiteout;
213 struct vattr va;
214
215#ifdef notyet
216 if (cnp->cn_namelen == 3 &&
217 cnp->cn_nameptr[2] == '.' &&
218 cnp->cn_nameptr[1] == '.' &&
219 cnp->cn_nameptr[0] == '.') {
220 dvp = *ap->a_vpp = LOWERVP(ap->a_dvp);
221 if (dvp == NULLVP)
222 return (ENOENT);
223 VREF(dvp);
224 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
225 if (!lockparent || !(cnp->cn_flags & ISLASTCN))
226 VOP_UNLOCK(ap->a_dvp, 0, p);
227 return (0);
228 }
229#endif
230
231 cnp->cn_flags |= LOCKPARENT;
232
233 upperdvp = dun->un_uppervp;
234 lowerdvp = dun->un_lowervp;
235 uppervp = NULLVP;
236 lowervp = NULLVP;
237 iswhiteout = 0;
238
239 /*
240 * do the lookup in the upper level.
241 * if that level comsumes additional pathnames,
242 * then assume that something special is going
243 * on and just return that vnode.
244 */
245 if (upperdvp != NULLVP) {
246 FIXUP(dun, p);
247 uerror = union_lookup1(um->um_uppervp, &upperdvp,
248 &uppervp, cnp);
249 /*if (uppervp == upperdvp)
250 dun->un_flags |= UN_KLOCK;*/
251
252 if (cnp->cn_consume != 0) {
253 *ap->a_vpp = uppervp;
254 if (!lockparent)
255 cnp->cn_flags &= ~LOCKPARENT;
256 return (uerror);
257 }
258 if (uerror == ENOENT || uerror == EJUSTRETURN) {
259 if (cnp->cn_flags & ISWHITEOUT) {
260 iswhiteout = 1;
261 } else if (lowerdvp != NULLVP) {
262 lerror = VOP_GETATTR(upperdvp, &va,
263 cnp->cn_cred, cnp->cn_proc);
264 if (lerror == 0 && (va.va_flags & OPAQUE))
265 iswhiteout = 1;
266 }
267 }
268 } else {
269 uerror = ENOENT;
270 }
271
272 /*
273 * in a similar way to the upper layer, do the lookup
274 * in the lower layer. this time, if there is some
275 * component magic going on, then vput whatever we got
276 * back from the upper layer and return the lower vnode
277 * instead.
278 */
279 if (lowerdvp != NULLVP && !iswhiteout) {
280 int nameiop;
281
282 vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p);
283
284 /*
285 * Only do a LOOKUP on the bottom node, since
286 * we won't be making changes to it anyway.
287 */
288 nameiop = cnp->cn_nameiop;
289 cnp->cn_nameiop = LOOKUP;
290 if (um->um_op == UNMNT_BELOW) {
291 saved_cred = cnp->cn_cred;
292 cnp->cn_cred = um->um_cred;
293 }
294 lerror = union_lookup1(um->um_lowervp, &lowerdvp,
295 &lowervp, cnp);
296 if (um->um_op == UNMNT_BELOW)
297 cnp->cn_cred = saved_cred;
298 cnp->cn_nameiop = nameiop;
299
300 if (lowervp != lowerdvp)
301 VOP_UNLOCK(lowerdvp, 0, p);
302
303 if (cnp->cn_consume != 0) {
304 if (uppervp != NULLVP) {
305 if (uppervp == upperdvp)
306 vrele(uppervp);
307 else
308 vput(uppervp);
309 uppervp = NULLVP;
310 }
311 *ap->a_vpp = lowervp;
312 if (!lockparent)
313 cnp->cn_flags &= ~LOCKPARENT;
314 return (lerror);
315 }
316 } else {
317 lerror = ENOENT;
318 if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
319 lowervp = LOWERVP(dun->un_pvp);
320 if (lowervp != NULLVP) {
321 VREF(lowervp);
322 vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p);
323 lerror = 0;
324 }
325 }
326 }
327
328 if (!lockparent)
329 cnp->cn_flags &= ~LOCKPARENT;
330
331 /*
332 * at this point, we have uerror and lerror indicating
333 * possible errors with the lookups in the upper and lower
334 * layers. additionally, uppervp and lowervp are (locked)
335 * references to existing vnodes in the upper and lower layers.
336 *
337 * there are now three cases to consider.
338 * 1. if both layers returned an error, then return whatever
339 * error the upper layer generated.
340 *
341 * 2. if the top layer failed and the bottom layer succeeded
342 * then two subcases occur.
343 * a. the bottom vnode is not a directory, in which
344 * case just return a new union vnode referencing
345 * an empty top layer and the existing bottom layer.
346 * b. the bottom vnode is a directory, in which case
347 * create a new directory in the top-level and
348 * continue as in case 3.
349 *
350 * 3. if the top layer succeeded then return a new union
351 * vnode referencing whatever the new top layer and
352 * whatever the bottom layer returned.
353 */
354
355 *ap->a_vpp = NULLVP;
356
357 /* case 1. */
358 if ((uerror != 0) && (lerror != 0)) {
359 return (uerror);
360 }
361
362 /* case 2. */
363 if (uerror != 0 /* && (lerror == 0) */ ) {
364 if (lowervp->v_type == VDIR) { /* case 2b. */
365 dun->un_flags &= ~UN_ULOCK;
366 VOP_UNLOCK(upperdvp, 0, p);
367 uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
368 vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p);
369 dun->un_flags |= UN_ULOCK;
370
371 if (uerror) {
372 if (lowervp != NULLVP) {
373 vput(lowervp);
374 lowervp = NULLVP;
375 }
376 return (uerror);
377 }
378 }
379 }
380
381 if (lowervp != NULLVP)
382 VOP_UNLOCK(lowervp, 0, p);
383
384 error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
385 uppervp, lowervp, 1);
386
387 if (error) {
388 if (uppervp != NULLVP)
389 vput(uppervp);
390 if (lowervp != NULLVP)
391 vrele(lowervp);
392 } else {
393 if (*ap->a_vpp != dvp)
394 if (!lockparent || !(cnp->cn_flags & ISLASTCN))
395 VOP_UNLOCK(dvp, 0, p);
396 }
397
398 return (error);
399}
400
401int
402union_create(ap)
403 struct vop_create_args /* {
404 struct vnode *a_dvp;
405 struct vnode **a_vpp;
406 struct componentname *a_cnp;
407 struct vattr *a_vap;
408 } */ *ap;
409{
410 struct union_node *un = VTOUNION(ap->a_dvp);
411 struct vnode *dvp = un->un_uppervp;
412 struct componentname *cnp = ap->a_cnp;
413 struct proc *p = cnp->cn_proc;
414
415 if (dvp != NULLVP) {
416 int error;
417 struct vnode *vp;
418 struct mount *mp;
419
420 FIXUP(un, p);
421
422 VREF(dvp);
423 un->un_flags |= UN_KLOCK;
424 mp = ap->a_dvp->v_mount;
425 vput(ap->a_dvp);
426 error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap);
427 if (error)
428 return (error);
429
430 error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp,
431 NULLVP, 1);
432 if (error)
433 vput(vp);
434 return (error);
435 }
436
437 vput(ap->a_dvp);
438 return (EROFS);
439}
440
441int
442union_whiteout(ap)
443 struct vop_whiteout_args /* {
444 struct vnode *a_dvp;
445 struct componentname *a_cnp;
446 int a_flags;
447 } */ *ap;
448{
449 struct union_node *un = VTOUNION(ap->a_dvp);
450 struct componentname *cnp = ap->a_cnp;
451 struct proc *p = cnp->cn_proc;
452
453 if (un->un_uppervp == NULLVP)
454 return (EOPNOTSUPP);
455
456 FIXUP(un, p);
457 return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags));
458}
459
460int
461union_mknod(ap)
462 struct vop_mknod_args /* {
463 struct vnode *a_dvp;
464 struct vnode **a_vpp;
465 struct componentname *a_cnp;
466 struct vattr *a_vap;
467 } */ *ap;
468{
469 struct union_node *un = VTOUNION(ap->a_dvp);
470 struct vnode *dvp = un->un_uppervp;
471 struct componentname *cnp = ap->a_cnp;
472 struct proc *p = cnp->cn_proc;
473
474 if (dvp != NULLVP) {
475 int error;
476 struct vnode *vp;
477 struct mount *mp;
478
479 FIXUP(un, p);
480
481 VREF(dvp);
482 un->un_flags |= UN_KLOCK;
483 mp = ap->a_dvp->v_mount;
484 vput(ap->a_dvp);
485 error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap);
486 if (error)
487 return (error);
488
489 if (vp != NULLVP) {
490 error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
491 cnp, vp, NULLVP, 1);
492 if (error)
493 vput(vp);
494 }
495 return (error);
496 }
497
498 vput(ap->a_dvp);
499 return (EROFS);
500}
501
502int
503union_open(ap)
504 struct vop_open_args /* {
505 struct vnodeop_desc *a_desc;
506 struct vnode *a_vp;
507 int a_mode;
508 struct ucred *a_cred;
509 struct proc *a_p;
510 } */ *ap;
511{
512 struct union_node *un = VTOUNION(ap->a_vp);
513 struct vnode *tvp;
514 int mode = ap->a_mode;
515 struct ucred *cred = ap->a_cred;
516 struct proc *p = ap->a_p;
517 int error;
518
519 /*
520 * If there is an existing upper vp then simply open that.
521 */
522 tvp = un->un_uppervp;
523 if (tvp == NULLVP) {
524 /*
525 * If the lower vnode is being opened for writing, then
526 * copy the file contents to the upper vnode and open that,
527 * otherwise can simply open the lower vnode.
528 */
529 tvp = un->un_lowervp;
530 if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
531 error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
532 if (error == 0)
533 error = VOP_OPEN(un->un_uppervp, mode, cred, p);
534 return (error);
535 }
536
537 /*
538 * Just open the lower vnode
539 */
540 un->un_openl++;
541 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);
542 error = VOP_OPEN(tvp, mode, cred, p);
543 VOP_UNLOCK(tvp, 0, p);
544
545 return (error);
546 }
547
548 FIXUP(un, p);
549
550 error = VOP_OPEN(tvp, mode, cred, p);
551
552 return (error);
553}
554
555int
556union_close(ap)
557 struct vop_close_args /* {
558 struct vnode *a_vp;
559 int a_fflag;
560 struct ucred *a_cred;
561 struct proc *a_p;
562 } */ *ap;
563{
564 struct union_node *un = VTOUNION(ap->a_vp);
565 struct vnode *vp;
566
567 if ((vp = un->un_uppervp) == NULLVP) {
568#ifdef UNION_DIAGNOSTIC
569 if (un->un_openl <= 0)
570 panic("union: un_openl cnt");
571#endif
572 --un->un_openl;
573 vp = un->un_lowervp;
574 }
575
576 ap->a_vp = vp;
577 return (VCALL(vp, VOFFSET(vop_close), ap));
578}
579
580/*
581 * Check access permission on the union vnode.
582 * The access check being enforced is to check
583 * against both the underlying vnode, and any
584 * copied vnode. This ensures that no additional
585 * file permissions are given away simply because
586 * the user caused an implicit file copy.
587 */
588int
589union_access(ap)
590 struct vop_access_args /* {
591 struct vnodeop_desc *a_desc;
592 struct vnode *a_vp;
593 int a_mode;
594 struct ucred *a_cred;
595 struct proc *a_p;
596 } */ *ap;
597{
598 struct union_node *un = VTOUNION(ap->a_vp);
599 struct proc *p = ap->a_p;
600 int error = EACCES;
601 struct vnode *vp;
602
603 if ((vp = un->un_uppervp) != NULLVP) {
604 FIXUP(un, p);
605 ap->a_vp = vp;
606 return (VCALL(vp, VOFFSET(vop_access), ap));
607 }
608
609 if ((vp = un->un_lowervp) != NULLVP) {
610 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
611 ap->a_vp = vp;
612 error = VCALL(vp, VOFFSET(vop_access), ap);
613 if (error == 0) {
614 struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);
615
616 if (um->um_op == UNMNT_BELOW) {
617 ap->a_cred = um->um_cred;
618 error = VCALL(vp, VOFFSET(vop_access), ap);
619 }
620 }
621 VOP_UNLOCK(vp, 0, p);
622 if (error)
623 return (error);
624 }
625
626 return (error);
627}
628
629/*
630 * We handle getattr only to change the fsid and
631 * track object sizes
632 */
633int
634union_getattr(ap)
635 struct vop_getattr_args /* {
636 struct vnode *a_vp;
637 struct vattr *a_vap;
638 struct ucred *a_cred;
639 struct proc *a_p;
640 } */ *ap;
641{
642 int error;
643 struct union_node *un = VTOUNION(ap->a_vp);
644 struct vnode *vp = un->un_uppervp;
645 struct proc *p = ap->a_p;
646 struct vattr *vap;
647 struct vattr va;
648
649
650 /*
651 * Some programs walk the filesystem hierarchy by counting
652 * links to directories to avoid stat'ing all the time.
653 * This means the link count on directories needs to be "correct".
654 * The only way to do that is to call getattr on both layers
655 * and fix up the link count. The link count will not necessarily
656 * be accurate but will be large enough to defeat the tree walkers.
657 */
658
659 vap = ap->a_vap;
660
661 vp = un->un_uppervp;
662 if (vp != NULLVP) {
663 /*
664 * It's not clear whether VOP_GETATTR is to be
665 * called with the vnode locked or not. stat() calls
666 * it with (vp) locked, and fstat calls it with
667 * (vp) unlocked.
668 * In the mean time, compensate here by checking
669 * the union_node's lock flag.
670 */
671 if (un->un_flags & UN_LOCKED)
672 FIXUP(un, p);
673
674 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
675 if (error)
676 return (error);
677 union_newsize(ap->a_vp, vap->va_size, VNOVAL);
678 }
679
680 if (vp == NULLVP) {
681 vp = un->un_lowervp;
682 } else if (vp->v_type == VDIR) {
683 vp = un->un_lowervp;
684 vap = &va;
685 } else {
686 vp = NULLVP;
687 }
688
689 if (vp != NULLVP) {
690 error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
691 if (error)
692 return (error);
693 union_newsize(ap->a_vp, VNOVAL, vap->va_size);
694 }
695
696 if ((vap != ap->a_vap) && (vap->va_type == VDIR))
697 ap->a_vap->va_nlink += vap->va_nlink;
698
699 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
700 return (0);
701}
702
703int
704union_setattr(ap)
705 struct vop_setattr_args /* {
706 struct vnode *a_vp;
707 struct vattr *a_vap;
708 struct ucred *a_cred;
709 struct proc *a_p;
710 } */ *ap;
711{
712 struct union_node *un = VTOUNION(ap->a_vp);
713 struct proc *p = ap->a_p;
714 int error;
715
716 /*
717 * Handle case of truncating lower object to zero size,
718 * by creating a zero length upper object. This is to
719 * handle the case of open with O_TRUNC and O_CREAT.
720 */
721 if ((un->un_uppervp == NULLVP) &&
722 /* assert(un->un_lowervp != NULLVP) */
723 (un->un_lowervp->v_type == VREG)) {
724 error = union_copyup(un, (ap->a_vap->va_size != 0),
725 ap->a_cred, ap->a_p);
726 if (error)
727 return (error);
728 }
729
730 /*
731 * Try to set attributes in upper layer,
732 * otherwise return read-only filesystem error.
733 */
734 if (un->un_uppervp != NULLVP) {
735 FIXUP(un, p);
736 error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
737 ap->a_cred, ap->a_p);
738 if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
739 union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
740 } else {
741 error = EROFS;
742 }
743
744 return (error);
745}
746
747int
748union_read(ap)
749 struct vop_read_args /* {
750 struct vnode *a_vp;
751 struct uio *a_uio;
752 int a_ioflag;
753 struct ucred *a_cred;
754 } */ *ap;
755{
756 int error;
757 struct proc *p = ap->a_uio->uio_procp;
758 struct vnode *vp = OTHERVP(ap->a_vp);
759 int dolock = (vp == LOWERVP(ap->a_vp));
760
761 if (dolock)
762 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
763 else
764 FIXUP(VTOUNION(ap->a_vp), p);
765 error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
766 if (dolock)
767 VOP_UNLOCK(vp, 0, p);
768
769 /*
770 * XXX
771 * perhaps the size of the underlying object has changed under
772 * our feet. take advantage of the offset information present
773 * in the uio structure.
774 */
775 if (error == 0) {
776 struct union_node *un = VTOUNION(ap->a_vp);
777 off_t cur = ap->a_uio->uio_offset;
778
779 if (vp == un->un_uppervp) {
780 if (cur > un->un_uppersz)
781 union_newsize(ap->a_vp, cur, VNOVAL);
782 } else {
783 if (cur > un->un_lowersz)
784 union_newsize(ap->a_vp, VNOVAL, cur);
785 }
786 }
787
788 return (error);
789}
790
791int
792union_write(ap)
793 struct vop_read_args /* {
794 struct vnode *a_vp;
795 struct uio *a_uio;
796 int a_ioflag;
797 struct ucred *a_cred;
798 } */ *ap;
799{
800 int error;
801 struct vnode *vp;
802 struct union_node *un = VTOUNION(ap->a_vp);
803 struct proc *p = ap->a_uio->uio_procp;
804
805 vp = UPPERVP(ap->a_vp);
806 if (vp == NULLVP)
807 panic("union: missing upper layer in write");
808
809 FIXUP(un, p);
810 error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
811
812 /*
813 * the size of the underlying object may be changed by the
814 * write.
815 */
816 if (error == 0) {
817 off_t cur = ap->a_uio->uio_offset;
818
819 if (cur > un->un_uppersz)
820 union_newsize(ap->a_vp, cur, VNOVAL);
821 }
822
823 return (error);
824}
825
826int
827union_lease(ap)
828 struct vop_lease_args /* {
829 struct vnode *a_vp;
830 struct proc *a_p;
831 struct ucred *a_cred;
832 int a_flag;
833 } */ *ap;
834{
835 register struct vnode *ovp = OTHERVP(ap->a_vp);
836
837 ap->a_vp = ovp;
838 return (VCALL(ovp, VOFFSET(vop_lease), ap));
839}
840
841int
842union_ioctl(ap)
843 struct vop_ioctl_args /* {
844 struct vnode *a_vp;
845 int a_command;
846 caddr_t a_data;
847 int a_fflag;
848 struct ucred *a_cred;
849 struct proc *a_p;
850 } */ *ap;
851{
852 register struct vnode *ovp = OTHERVP(ap->a_vp);
853
854 ap->a_vp = ovp;
855 return (VCALL(ovp, VOFFSET(vop_ioctl), ap));
856}
857
858int
859union_select(ap)
860 struct vop_select_args /* {
861 struct vnode *a_vp;
862 int a_which;
863 int a_fflags;
864 struct ucred *a_cred;
865 struct proc *a_p;
866 } */ *ap;
867{
868 register struct vnode *ovp = OTHERVP(ap->a_vp);
869
870 ap->a_vp = ovp;
871 return (VCALL(ovp, VOFFSET(vop_select), ap));
872}
873
874int
875union_revoke(ap)
876 struct vop_revoke_args /* {
877 struct vnode *a_vp;
878 int a_flags;
879 struct proc *a_p;
880 } */ *ap;
881{
882 struct vnode *vp = ap->a_vp;
883
884 if (UPPERVP(vp))
885 VOP_REVOKE(UPPERVP(vp), ap->a_flags);
886 if (LOWERVP(vp))
887 VOP_REVOKE(LOWERVP(vp), ap->a_flags);
888 vgone(vp);
889 return (0);
890}
891
892int
893union_mmap(ap)
894 struct vop_mmap_args /* {
895 struct vnode *a_vp;
896 int a_fflags;
897 struct ucred *a_cred;
898 struct proc *a_p;
899 } */ *ap;
900{
901 register struct vnode *ovp = OTHERVP(ap->a_vp);
902
903 ap->a_vp = ovp;
904 return (VCALL(ovp, VOFFSET(vop_mmap), ap));
905}
906
907int
908union_fsync(ap)
909 struct vop_fsync_args /* {
910 struct vnode *a_vp;
911 struct ucred *a_cred;
912 int a_waitfor;
913 struct proc *a_p;
914 } */ *ap;
915{
916 int error = 0;
917 struct proc *p = ap->a_p;
918 struct vnode *targetvp = OTHERVP(ap->a_vp);
919
920 if (targetvp != NULLVP) {
921 int dolock = (targetvp == LOWERVP(ap->a_vp));
922
923 if (dolock)
924 vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p);
925 else
926 FIXUP(VTOUNION(ap->a_vp), p);
927 error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p);
928 if (dolock)
929 VOP_UNLOCK(targetvp, 0, p);
930 }
931
932 return (error);
933}
934
935int
936union_seek(ap)
937 struct vop_seek_args /* {
938 struct vnode *a_vp;
939 off_t a_oldoff;
940 off_t a_newoff;
941 struct ucred *a_cred;
942 } */ *ap;
943{
944 register struct vnode *ovp = OTHERVP(ap->a_vp);
945
946 ap->a_vp = ovp;
947 return (VCALL(ovp, VOFFSET(vop_seek), ap));
948}
949
950int
951union_remove(ap)
952 struct vop_remove_args /* {
953 struct vnode *a_dvp;
954 struct vnode *a_vp;
955 struct componentname *a_cnp;
956 } */ *ap;
957{
958 int error;
959 struct union_node *dun = VTOUNION(ap->a_dvp);
960 struct union_node *un = VTOUNION(ap->a_vp);
961 struct componentname *cnp = ap->a_cnp;
962 struct proc *p = cnp->cn_proc;
963
964 if (dun->un_uppervp == NULLVP)
965 panic("union remove: null upper vnode");
966
967 if (un->un_uppervp != NULLVP) {
968 struct vnode *dvp = dun->un_uppervp;
969 struct vnode *vp = un->un_uppervp;
970
971 FIXUP(dun, p);
972 VREF(dvp);
973 dun->un_flags |= UN_KLOCK;
974 vput(ap->a_dvp);
975 FIXUP(un, p);
976 VREF(vp);
977 un->un_flags |= UN_KLOCK;
978 vput(ap->a_vp);
979
980 if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
981 cnp->cn_flags |= DOWHITEOUT;
982 error = VOP_REMOVE(dvp, vp, cnp);
983 if (!error)
984 union_removed_upper(un);
985 } else {
986 FIXUP(dun, p);
987 error = union_mkwhiteout(
988 MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
989 dun->un_uppervp, ap->a_cnp, un->un_path);
990 vput(ap->a_dvp);
991 vput(ap->a_vp);
992 }
993
994 return (error);
995}
996
997int
998union_link(ap)
999 struct vop_link_args /* {
1000 struct vnode *a_tdvp;
1001 struct vnode *a_vp;
1002 struct componentname *a_cnp;
1003 } */ *ap;
1004{
1005 int error = 0;
1006 struct componentname *cnp = ap->a_cnp;
1007 struct proc *p = cnp->cn_proc;
1008 struct union_node *un;
1009 struct vnode *vp;
1010 struct vnode *tdvp;
1011
1012 un = VTOUNION(ap->a_tdvp);
1013
1014 if (ap->a_tdvp->v_op != ap->a_vp->v_op) {
1015 vp = ap->a_vp;
1016 } else {
1017 struct union_node *tun = VTOUNION(ap->a_vp);
1018 if (tun->un_uppervp == NULLVP) {
1019 vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
1020 if (un->un_uppervp == tun->un_dirvp) {
1021 un->un_flags &= ~UN_ULOCK;
1022 VOP_UNLOCK(un->un_uppervp, 0, p);
1023 }
1024 error = union_copyup(tun, 1, cnp->cn_cred, p);
1025 if (un->un_uppervp == tun->un_dirvp) {
1026 vn_lock(un->un_uppervp,
1027 LK_EXCLUSIVE | LK_RETRY, p);
1028 un->un_flags |= UN_ULOCK;
1029 }
1030 VOP_UNLOCK(ap->a_vp, 0, p);
1031 }
1032 vp = tun->un_uppervp;
1033 }
1034
1035 tdvp = un->un_uppervp;
1036 if (tdvp == NULLVP)
1037 error = EROFS;
1038
1039 if (error) {
1040 vput(ap->a_tdvp);
1041 return (error);
1042 }
1043
1044 FIXUP(un, p);
1045 VREF(tdvp);
1046 un->un_flags |= UN_KLOCK;
1047 vput(ap->a_tdvp);
1048
1049 return (VOP_LINK(vp, tdvp, cnp));
1050}
1051
1052int
1053union_rename(ap)
1054 struct vop_rename_args /* {
1055 struct vnode *a_fdvp;
1056 struct vnode *a_fvp;
1057 struct componentname *a_fcnp;
1058 struct vnode *a_tdvp;
1059 struct vnode *a_tvp;
1060 struct componentname *a_tcnp;
1061 } */ *ap;
1062{
1063 int error;
1064
1065 struct vnode *fdvp = ap->a_fdvp;
1066 struct vnode *fvp = ap->a_fvp;
1067 struct vnode *tdvp = ap->a_tdvp;
1068 struct vnode *tvp = ap->a_tvp;
1069
1070 if (fdvp->v_op == union_vnodeop_p) { /* always true */
1071 struct union_node *un = VTOUNION(fdvp);
1072 if (un->un_uppervp == NULLVP) {
1073 /*
1074 * this should never happen in normal
1075 * operation but might if there was
1076 * a problem creating the top-level shadow
1077 * directory.
1078 */
1079 error = EXDEV;
1080 goto bad;
1081 }
1082
1083 fdvp = un->un_uppervp;
1084 VREF(fdvp);
1085 vrele(ap->a_fdvp);
1086 }
1087
1088 if (fvp->v_op == union_vnodeop_p) { /* always true */
1089 struct union_node *un = VTOUNION(fvp);
1090 if (un->un_uppervp == NULLVP) {
1091 /* XXX: should do a copyup */
1092 error = EXDEV;
1093 goto bad;
1094 }
1095
1096 if (un->un_lowervp != NULLVP)
1097 ap->a_fcnp->cn_flags |= DOWHITEOUT;
1098
1099 fvp = un->un_uppervp;
1100 VREF(fvp);
1101 vrele(ap->a_fvp);
1102 }
1103
1104 if (tdvp->v_op == union_vnodeop_p) {
1105 struct union_node *un = VTOUNION(tdvp);
1106 if (un->un_uppervp == NULLVP) {
1107 /*
1108 * this should never happen in normal
1109 * operation but might if there was
1110 * a problem creating the top-level shadow
1111 * directory.
1112 */
1113 error = EXDEV;
1114 goto bad;
1115 }
1116
1117 tdvp = un->un_uppervp;
1118 VREF(tdvp);
1119 un->un_flags |= UN_KLOCK;
1120 vput(ap->a_tdvp);
1121 }
1122
1123 if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
1124 struct union_node *un = VTOUNION(tvp);
1125
1126 tvp = un->un_uppervp;
1127 if (tvp != NULLVP) {
1128 VREF(tvp);
1129 un->un_flags |= UN_KLOCK;
1130 }
1131 vput(ap->a_tvp);
1132 }
1133
1134 return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
1135
1136bad:
1137 vrele(fdvp);
1138 vrele(fvp);
1139 vput(tdvp);
1140 if (tvp != NULLVP)
1141 vput(tvp);
1142
1143 return (error);
1144}
1145
1146int
1147union_mkdir(ap)
1148 struct vop_mkdir_args /* {
1149 struct vnode *a_dvp;
1150 struct vnode **a_vpp;
1151 struct componentname *a_cnp;
1152 struct vattr *a_vap;
1153 } */ *ap;
1154{
1155 struct union_node *un = VTOUNION(ap->a_dvp);
1156 struct vnode *dvp = un->un_uppervp;
1157 struct componentname *cnp = ap->a_cnp;
1158 struct proc *p = cnp->cn_proc;
1159
1160 if (dvp != NULLVP) {
1161 int error;
1162 struct vnode *vp;
1163
1164 FIXUP(un, p);
1165 VREF(dvp);
1166 un->un_flags |= UN_KLOCK;
1167 VOP_UNLOCK(ap->a_dvp, 0, p);
1168 error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap);
1169 if (error) {
1170 vrele(ap->a_dvp);
1171 return (error);
1172 }
1173
1174 error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp,
1175 NULLVP, cnp, vp, NULLVP, 1);
1176 vrele(ap->a_dvp);
1177 if (error)
1178 vput(vp);
1179 return (error);
1180 }
1181
1182 vput(ap->a_dvp);
1183 return (EROFS);
1184}
1185
1186int
1187union_rmdir(ap)
1188 struct vop_rmdir_args /* {
1189 struct vnode *a_dvp;
1190 struct vnode *a_vp;
1191 struct componentname *a_cnp;
1192 } */ *ap;
1193{
1194 int error;
1195 struct union_node *dun = VTOUNION(ap->a_dvp);
1196 struct union_node *un = VTOUNION(ap->a_vp);
1197 struct componentname *cnp = ap->a_cnp;
1198 struct proc *p = cnp->cn_proc;
1199
1200 if (dun->un_uppervp == NULLVP)
1201 panic("union rmdir: null upper vnode");
1202
1203 if (un->un_uppervp != NULLVP) {
1204 struct vnode *dvp = dun->un_uppervp;
1205 struct vnode *vp = un->un_uppervp;
1206
1207 FIXUP(dun, p);
1208 VREF(dvp);
1209 dun->un_flags |= UN_KLOCK;
1210 vput(ap->a_dvp);
1211 FIXUP(un, p);
1212 VREF(vp);
1213 un->un_flags |= UN_KLOCK;
1214 vput(ap->a_vp);
1215
1216 if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
1217 cnp->cn_flags |= DOWHITEOUT;
1218 error = VOP_RMDIR(dvp, vp, ap->a_cnp);
1219 if (!error)
1220 union_removed_upper(un);
1221 } else {
1222 FIXUP(dun, p);
1223 error = union_mkwhiteout(
1224 MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
1225 dun->un_uppervp, ap->a_cnp, un->un_path);
1226 vput(ap->a_dvp);
1227 vput(ap->a_vp);
1228 }
1229
1230 return (error);
1231}
1232
1233int
1234union_symlink(ap)
1235 struct vop_symlink_args /* {
1236 struct vnode *a_dvp;
1237 struct vnode **a_vpp;
1238 struct componentname *a_cnp;
1239 struct vattr *a_vap;
1240 char *a_target;
1241 } */ *ap;
1242{
1243 struct union_node *un = VTOUNION(ap->a_dvp);
1244 struct vnode *dvp = un->un_uppervp;
1245 struct componentname *cnp = ap->a_cnp;
1246 struct proc *p = cnp->cn_proc;
1247
1248 if (dvp != NULLVP) {
1249 int error;
1250 struct vnode *vp;
1251
1252 FIXUP(un, p);
1253 VREF(dvp);
1254 un->un_flags |= UN_KLOCK;
1255 vput(ap->a_dvp);
1256 error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target);
1257 *ap->a_vpp = NULLVP;
1258 return (error);
1259 }
1260
1261 vput(ap->a_dvp);
1262 return (EROFS);
1263}
1264
1265/*
1266 * union_readdir works in concert with getdirentries and
1267 * readdir(3) to provide a list of entries in the unioned
1268 * directories. getdirentries is responsible for walking
1269 * down the union stack. readdir(3) is responsible for
1270 * eliminating duplicate names from the returned data stream.
1271 */
1272int
1273union_readdir(ap)
1274 struct vop_readdir_args /* {
1275 struct vnode *a_vp;
1276 struct uio *a_uio;
1277 struct ucred *a_cred;
1278 int *a_eofflag;
1279 u_long *a_cookies;
1280 int a_ncookies;
1281 } */ *ap;
1282{
1283 struct union_node *un = VTOUNION(ap->a_vp);
1284 struct vnode *uvp = un->un_uppervp;
1285 struct proc *p = ap->a_uio->uio_procp;
1286
1287 if (uvp == NULLVP)
1288 return (0);
1289
1290 FIXUP(un, p);
1291 ap->a_vp = uvp;
1292 return (VCALL(uvp, VOFFSET(vop_readdir), ap));
1293}
1294
1295int
1296union_readlink(ap)
1297 struct vop_readlink_args /* {
1298 struct vnode *a_vp;
1299 struct uio *a_uio;
1300 struct ucred *a_cred;
1301 } */ *ap;
1302{
1303 int error;
1304 struct uio *uio = ap->a_uio;
1305 struct proc *p = uio->uio_procp;
1306 struct vnode *vp = OTHERVP(ap->a_vp);
1307 int dolock = (vp == LOWERVP(ap->a_vp));
1308
1309 if (dolock)
1310 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1311 else
1312 FIXUP(VTOUNION(ap->a_vp), p);
1313 ap->a_vp = vp;
1314 error = VCALL(vp, VOFFSET(vop_readlink), ap);
1315 if (dolock)
1316 VOP_UNLOCK(vp, 0, p);
1317
1318 return (error);
1319}
1320
1321int
1322union_abortop(ap)
1323 struct vop_abortop_args /* {
1324 struct vnode *a_dvp;
1325 struct componentname *a_cnp;
1326 } */ *ap;
1327{
1328 int error;
1329 struct componentname *cnp = ap->a_cnp;
1330 struct proc *p = cnp->cn_proc;
1331 struct vnode *vp = OTHERVP(ap->a_dvp);
1332 struct union_node *un = VTOUNION(ap->a_dvp);
1333 int islocked = un->un_flags & UN_LOCKED;
1334 int dolock = (vp == LOWERVP(ap->a_dvp));
1335
1336 if (islocked) {
1337 if (dolock)
1338 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1339 else
1340 FIXUP(VTOUNION(ap->a_dvp), p);
1341 }
1342 ap->a_dvp = vp;
1343 error = VCALL(vp, VOFFSET(vop_abortop), ap);
1344 if (islocked && dolock)
1345 VOP_UNLOCK(vp, 0, p);
1346
1347 return (error);
1348}
1349
1350int
1351union_inactive(ap)
1352 struct vop_inactive_args /* {
1353 struct vnode *a_vp;
1354 struct proc *a_p;
1355 } */ *ap;
1356{
1357 struct vnode *vp = ap->a_vp;
1358 struct proc *p = ap->a_p;
1359 struct union_node *un = VTOUNION(vp);
1360 struct vnode **vpp;
1361
1362 /*
1363 * Do nothing (and _don't_ bypass).
1364 * Wait to vrele lowervp until reclaim,
1365 * so that until then our union_node is in the
1366 * cache and reusable.
1367 *
1368 * NEEDSWORK: Someday, consider inactive'ing
1369 * the lowervp and then trying to reactivate it
1370 * with capabilities (v_id)
1371 * like they do in the name lookup cache code.
1372 * That's too much work for now.
1373 */
1374
1375 if (un->un_dircache != 0) {
1376 for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
1377 vrele(*vpp);
1378 free(un->un_dircache, M_TEMP);
1379 un->un_dircache = 0;
1380 }
1381
1382 VOP_UNLOCK(vp, 0, p);
1383
1384 if ((un->un_flags & UN_CACHED) == 0)
1385 vgone(vp);
1386
1387 return (0);
1388}
1389
1390int
1391union_reclaim(ap)
1392 struct vop_reclaim_args /* {
1393 struct vnode *a_vp;
1394 } */ *ap;
1395{
1396
1397 union_freevp(ap->a_vp);
1398
1399 return (0);
1400}
1401
1402int
1403union_lock(ap)
1404 struct vop_lock_args *ap;
1405{
1406 struct vnode *vp = ap->a_vp;
1407 struct proc *p = ap->a_p;
1408 int flags = ap->a_flags;
1409 struct union_node *un;
1410 int error;
1411
1412 vop_nolock(ap);
1413 /*
1414 * Need to do real lockmgr-style locking here.
1415 * in the mean time, draining won't work quite right,
1416 * which could lead to a few race conditions.
1417 * the following test was here, but is not quite right, we
1418 * still need to take the lock:
1419 if ((flags & LK_TYPE_MASK) == LK_DRAIN)
1420 return (0);
1421 */
1422 flags &= ~LK_INTERLOCK;
1423
1424start:
1425 un = VTOUNION(vp);
1426
1427 if (un->un_uppervp != NULLVP) {
1428 if (((un->un_flags & UN_ULOCK) == 0) &&
1429 (vp->v_usecount != 0)) {
1430 error = vn_lock(un->un_uppervp, flags, p);
1431 if (error)
1432 return (error);
1433 un->un_flags |= UN_ULOCK;
1434 }
1435#ifdef DIAGNOSTIC
1436 if (un->un_flags & UN_KLOCK) {
1437 vprint("union: dangling klock", vp);
1438 panic("union: dangling upper lock (%lx)", vp);
1439 }
1440#endif
1441 }
1442
1443 if (un->un_flags & UN_LOCKED) {
1444#ifdef DIAGNOSTIC
1445 if (curproc && un->un_pid == curproc->p_pid &&
1446 un->un_pid > -1 && curproc->p_pid > -1)
1447 panic("union: locking against myself");
1448#endif
1449 un->un_flags |= UN_WANT;
1450 tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0);
1451 goto start;
1452 }
1453
1454#ifdef DIAGNOSTIC
1455 if (curproc)
1456 un->un_pid = curproc->p_pid;
1457 else
1458 un->un_pid = -1;
1459#endif
1460
1461 un->un_flags |= UN_LOCKED;
1462 return (0);
1463}
1464
1465/*
1466 * When operations want to vput() a union node yet retain a lock on
1467 * the upper vnode (say, to do some further operations like link(),
1468 * mkdir(), ...), they set UN_KLOCK on the union node, then call
1469 * vput() which calls VOP_UNLOCK() and comes here. union_unlock()
1470 * unlocks the union node (leaving the upper vnode alone), clears the
1471 * KLOCK flag, and then returns to vput(). The caller then does whatever
1472 * is left to do with the upper vnode, and ensures that it gets unlocked.
1473 *
1474 * If UN_KLOCK isn't set, then the upper vnode is unlocked here.
1475 */
1476int
1477union_unlock(ap)
1478 struct vop_unlock_args /* {
1479 struct vnode *a_vp;
1480 int a_flags;
1481 struct proc *a_p;
1482 } */ *ap;
1483{
1484 struct union_node *un = VTOUNION(ap->a_vp);
1485 struct proc *p = ap->a_p;
1486
1487#ifdef DIAGNOSTIC
1488 if ((un->un_flags & UN_LOCKED) == 0)
1489 panic("union: unlock unlocked node");
1490 if (curproc && un->un_pid != curproc->p_pid &&
1491 curproc->p_pid > -1 && un->un_pid > -1)
1492 panic("union: unlocking other process's union node");
1493#endif
1494
1495 un->un_flags &= ~UN_LOCKED;
1496
1497 if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK)
1498 VOP_UNLOCK(un->un_uppervp, 0, p);
1499
1500 un->un_flags &= ~(UN_ULOCK|UN_KLOCK);
1501
1502 if (un->un_flags & UN_WANT) {
1503 un->un_flags &= ~UN_WANT;
1504 wakeup((caddr_t) &un->un_flags);
1505 }
1506
1507#ifdef DIAGNOSTIC
1508 un->un_pid = 0;
1509#endif
1510 vop_nounlock(ap);
1511
1512 return (0);
1513}
1514
1515int
1516union_bmap(ap)
1517 struct vop_bmap_args /* {
1518 struct vnode *a_vp;
1519 daddr_t a_bn;
1520 struct vnode **a_vpp;
1521 daddr_t *a_bnp;
1522 int *a_runp;
1523 int *a_runb;
1524 } */ *ap;
1525{
1526 int error;
1527 struct proc *p = curproc; /* XXX */
1528 struct vnode *vp = OTHERVP(ap->a_vp);
1529 int dolock = (vp == LOWERVP(ap->a_vp));
1530
1531 if (dolock)
1532 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1533 else
1534 FIXUP(VTOUNION(ap->a_vp), p);
1535 ap->a_vp = vp;
1536 error = VCALL(vp, VOFFSET(vop_bmap), ap);
1537 if (dolock)
1538 VOP_UNLOCK(vp, 0, p);
1539
1540 return (error);
1541}
1542
1543int
1544union_print(ap)
1545 struct vop_print_args /* {
1546 struct vnode *a_vp;
1547 } */ *ap;
1548{
1549 struct vnode *vp = ap->a_vp;
1550
1551 printf("\ttag VT_UNION, vp=%p, uppervp=%p, lowervp=%p\n",
1552 vp, UPPERVP(vp), LOWERVP(vp));
1553 if (UPPERVP(vp) != NULLVP)
1554 vprint("union: upper", UPPERVP(vp));
1555 if (LOWERVP(vp) != NULLVP)
1556 vprint("union: lower", LOWERVP(vp));
1557
1558 return (0);
1559}
1560
1561int
1562union_islocked(ap)
1563 struct vop_islocked_args /* {
1564 struct vnode *a_vp;
1565 } */ *ap;
1566{
1567
1568 return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0);
1569}
1570
1571int
1572union_pathconf(ap)
1573 struct vop_pathconf_args /* {
1574 struct vnode *a_vp;
1575 int a_name;
1576 int *a_retval;
1577 } */ *ap;
1578{
1579 int error;
1580 struct proc *p = curproc; /* XXX */
1581 struct vnode *vp = OTHERVP(ap->a_vp);
1582 int dolock = (vp == LOWERVP(ap->a_vp));
1583
1584 if (dolock)
1585 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1586 else
1587 FIXUP(VTOUNION(ap->a_vp), p);
1588 ap->a_vp = vp;
1589 error = VCALL(vp, VOFFSET(vop_pathconf), ap);
1590 if (dolock)
1591 VOP_UNLOCK(vp, 0, p);
1592
1593 return (error);
1594}
1595
1596int
1597union_advlock(ap)
1598 struct vop_advlock_args /* {
1599 struct vnode *a_vp;
1600 caddr_t a_id;
1601 int a_op;
1602 struct flock *a_fl;
1603 int a_flags;
1604 } */ *ap;
1605{
1606 register struct vnode *ovp = OTHERVP(ap->a_vp);
1607
1608 ap->a_vp = ovp;
1609 return (VCALL(ovp, VOFFSET(vop_advlock), ap));
1610}
1611
1612
1613/*
1614 * XXX - vop_strategy must be hand coded because it has no
1615 * vnode in its arguments.
1616 * This goes away with a merged VM/buffer cache.
1617 */
1618int
1619union_strategy(ap)
1620 struct vop_strategy_args /* {
1621 struct buf *a_bp;
1622 } */ *ap;
1623{
1624 struct buf *bp = ap->a_bp;
1625 int error;
1626 struct vnode *savedvp;
1627
1628 savedvp = bp->b_vp;
1629 bp->b_vp = OTHERVP(bp->b_vp);
1630
1631#ifdef DIAGNOSTIC
1632 if (bp->b_vp == NULLVP)
1633 panic("union_strategy: nil vp");
1634 if (((bp->b_flags & B_READ) == 0) &&
1635 (bp->b_vp == LOWERVP(savedvp)))
1636 panic("union_strategy: writing to lowervp");
1637#endif
1638
1639 error = VOP_STRATEGY(bp);
1640 bp->b_vp = savedvp;
1641
1642 return (error);
1643}
1644
1645/*
1646 * Global vfs data structures
1647 */
1648vop_t **union_vnodeop_p;
1649struct vnodeopv_entry_desc union_vnodeop_entries[] = {
1650 { &vop_default_desc, (vop_t *)vn_default_error },
1651 { &vop_lookup_desc, (vop_t *)union_lookup }, /* lookup */
1652 { &vop_create_desc, (vop_t *)union_create }, /* create */
1653 { &vop_whiteout_desc, (vop_t *)union_whiteout }, /* whiteout */
1654 { &vop_mknod_desc, (vop_t *)union_mknod }, /* mknod */
1655 { &vop_open_desc, (vop_t *)union_open }, /* open */
1656 { &vop_close_desc, (vop_t *)union_close }, /* close */
1657 { &vop_access_desc, (vop_t *)union_access }, /* access */
1658 { &vop_getattr_desc, (vop_t *)union_getattr }, /* getattr */
1659 { &vop_setattr_desc, (vop_t *)union_setattr }, /* setattr */
1660 { &vop_read_desc, (vop_t *)union_read }, /* read */
1661 { &vop_write_desc, (vop_t *)union_write }, /* write */
1662 { &vop_lease_desc, (vop_t *)union_lease }, /* lease */
1663 { &vop_ioctl_desc, (vop_t *)union_ioctl }, /* ioctl */
1664 { &vop_select_desc, (vop_t *)union_select }, /* select */
1665 { &vop_revoke_desc, (vop_t *)union_revoke }, /* revoke */
1666 { &vop_mmap_desc, (vop_t *)union_mmap }, /* mmap */
1667 { &vop_fsync_desc, (vop_t *)union_fsync }, /* fsync */
1668 { &vop_seek_desc, (vop_t *)union_seek }, /* seek */
1669 { &vop_remove_desc, (vop_t *)union_remove }, /* remove */
1670 { &vop_link_desc, (vop_t *)union_link }, /* link */
1671 { &vop_rename_desc, (vop_t *)union_rename }, /* rename */
1672 { &vop_mkdir_desc, (vop_t *)union_mkdir }, /* mkdir */
1673 { &vop_rmdir_desc, (vop_t *)union_rmdir }, /* rmdir */
1674 { &vop_symlink_desc, (vop_t *)union_symlink }, /* symlink */
1675 { &vop_readdir_desc, (vop_t *)union_readdir }, /* readdir */
1676 { &vop_readlink_desc, (vop_t *)union_readlink }, /* readlink */
1677 { &vop_abortop_desc, (vop_t *)union_abortop }, /* abortop */
1678 { &vop_inactive_desc, (vop_t *)union_inactive }, /* inactive */
1679 { &vop_reclaim_desc, (vop_t *)union_reclaim }, /* reclaim */
1680 { &vop_lock_desc, (vop_t *)union_lock }, /* lock */
1681 { &vop_unlock_desc, (vop_t *)union_unlock }, /* unlock */
1682 { &vop_bmap_desc, (vop_t *)union_bmap }, /* bmap */
1683 { &vop_strategy_desc, (vop_t *)union_strategy }, /* strategy */
1684 { &vop_print_desc, (vop_t *)union_print }, /* print */
1685 { &vop_islocked_desc, (vop_t *)union_islocked }, /* islocked */
1686 { &vop_pathconf_desc, (vop_t *)union_pathconf }, /* pathconf */
1687 { &vop_advlock_desc, (vop_t *)union_advlock }, /* advlock */
1688#ifdef notdef
1689 { &vop_blkatoff_desc, (vop_t *)union_blkatoff }, /* blkatoff */
1690 { &vop_valloc_desc, (vop_t *)union_valloc }, /* valloc */
1691 { &vop_vfree_desc, (vop_t *)union_vfree }, /* vfree */
1692 { &vop_truncate_desc, (vop_t *)union_truncate }, /* truncate */
1693 { &vop_update_desc, (vop_t *)union_update }, /* update */
1694 { &vop_bwrite_desc, (vop_t *)union_bwrite }, /* bwrite */
1695#endif
1696 { NULL, NULL }
1697};
1698struct vnodeopv_desc union_vnodeop_opv_desc =
1699 { &union_vnodeop_p, union_vnodeop_entries };
1700
1701VNODEOP_SET(union_vnodeop_opv_desc);