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