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