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