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