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