165935Spendry /*
268590Spendry * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
368590Spendry * Copyright (c) 1992, 1993, 1994, 1995
468590Spendry * The Regents of the University of California. All rights reserved.
565935Spendry *
665935Spendry * This code is derived from software contributed to Berkeley by
765963Spendry * Jan-Simon Pendry.
865935Spendry *
965935Spendry * %sccs.include.redist.c%
1065935Spendry *
11*69978Spendry * @(#)union_vnops.c 8.32 (Berkeley) 06/23/95
1265935Spendry */
1365935Spendry
1465935Spendry #include <sys/param.h>
1565935Spendry #include <sys/systm.h>
1665935Spendry #include <sys/proc.h>
1765935Spendry #include <sys/file.h>
1865935Spendry #include <sys/time.h>
1967575Spendry #include <sys/stat.h>
2065935Spendry #include <sys/types.h>
2165935Spendry #include <sys/vnode.h>
2265935Spendry #include <sys/mount.h>
2365935Spendry #include <sys/namei.h>
2465935Spendry #include <sys/malloc.h>
2565935Spendry #include <sys/buf.h>
2666053Spendry #include <sys/queue.h>
2769447Smckusick #include <sys/lock.h>
2866055Spendry #include <miscfs/union/union.h>
2965935Spendry
3069447Smckusick #define FIXUP(un, p) { \
3166152Spendry if (((un)->un_flags & UN_ULOCK) == 0) { \
3269447Smckusick union_fixup(un, p); \
3366152Spendry } \
3466152Spendry }
3566152Spendry
3666152Spendry static void
union_fixup(un,p)3769447Smckusick union_fixup(un, p)
3866152Spendry struct union_node *un;
3969447Smckusick struct proc *p;
4066152Spendry {
4166152Spendry
4269447Smckusick vn_lock(un->un_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
4366152Spendry un->un_flags |= UN_ULOCK;
4466152Spendry }
4566152Spendry
4665935Spendry static int
union_lookup1(udvp,dvpp,vpp,cnp)4767064Spendry union_lookup1(udvp, dvpp, vpp, cnp)
4865989Spendry struct vnode *udvp;
4967064Spendry struct vnode **dvpp;
5065935Spendry struct vnode **vpp;
5165935Spendry struct componentname *cnp;
5265935Spendry {
5365935Spendry int error;
5469447Smckusick struct proc *p = cnp->cn_proc;
5565935Spendry struct vnode *tdvp;
5667064Spendry struct vnode *dvp;
5765935Spendry struct mount *mp;
5865935Spendry
5967064Spendry dvp = *dvpp;
6067064Spendry
6165994Spendry /*
6265994Spendry * If stepping up the directory tree, check for going
6365994Spendry * back across the mount point, in which case do what
6465994Spendry * lookup would do by stepping back down the mount
6565994Spendry * hierarchy.
6665994Spendry */
6765935Spendry if (cnp->cn_flags & ISDOTDOT) {
6867064Spendry while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
6966034Spendry /*
7066034Spendry * Don't do the NOCROSSMOUNT check
7166034Spendry * at this level. By definition,
7266034Spendry * union fs deals with namespaces, not
7366034Spendry * filesystems.
7466034Spendry */
7565935Spendry tdvp = dvp;
7667064Spendry *dvpp = dvp = dvp->v_mount->mnt_vnodecovered;
7765935Spendry vput(tdvp);
7865935Spendry VREF(dvp);
7969447Smckusick vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
8065935Spendry }
8165935Spendry }
8266027Spendry
8365935Spendry error = VOP_LOOKUP(dvp, &tdvp, cnp);
8465935Spendry if (error)
8565935Spendry return (error);
8665935Spendry
8765994Spendry /*
8866027Spendry * The parent directory will have been unlocked, unless lookup
8966027Spendry * found the last component. In which case, re-lock the node
9066027Spendry * here to allow it to be unlocked again (phew) in union_lookup.
9165994Spendry */
9266027Spendry if (dvp != tdvp && !(cnp->cn_flags & ISLASTCN))
9369447Smckusick vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
9465994Spendry
9565935Spendry dvp = tdvp;
9665994Spendry
9765994Spendry /*
9865994Spendry * Lastly check if the current node is a mount point in
9966034Spendry * which case walk up the mount hierarchy making sure not to
10065994Spendry * bump into the root of the mount tree (ie. dvp != udvp).
10165994Spendry */
10265989Spendry while (dvp != udvp && (dvp->v_type == VDIR) &&
10366034Spendry (mp = dvp->v_mountedhere)) {
10465935Spendry
10569572Smckusick if (vfs_busy(mp, 0, 0, p))
10665935Spendry continue;
10765935Spendry
10869572Smckusick error = VFS_ROOT(mp, &tdvp);
10969572Smckusick vfs_unbusy(mp, p);
11069572Smckusick if (error) {
11165935Spendry vput(dvp);
11265935Spendry return (error);
11365935Spendry }
11465935Spendry
11565965Spendry vput(dvp);
11665935Spendry dvp = tdvp;
11765935Spendry }
11865935Spendry
11965935Spendry *vpp = dvp;
12065935Spendry return (0);
12165935Spendry }
12265935Spendry
12365935Spendry int
union_lookup(ap)12465935Spendry union_lookup(ap)
12565935Spendry struct vop_lookup_args /* {
12665935Spendry struct vnodeop_desc *a_desc;
12765935Spendry struct vnode *a_dvp;
12865935Spendry struct vnode **a_vpp;
12965935Spendry struct componentname *a_cnp;
13065935Spendry } */ *ap;
13165935Spendry {
13265965Spendry int error;
13365935Spendry int uerror, lerror;
13465935Spendry struct vnode *uppervp, *lowervp;
13565935Spendry struct vnode *upperdvp, *lowerdvp;
13665935Spendry struct vnode *dvp = ap->a_dvp;
13765989Spendry struct union_node *dun = VTOUNION(dvp);
13865935Spendry struct componentname *cnp = ap->a_cnp;
13969447Smckusick struct proc *p = cnp->cn_proc;
14065935Spendry int lockparent = cnp->cn_flags & LOCKPARENT;
14165994Spendry int rdonly = cnp->cn_flags & RDONLY;
14265997Spendry struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
14366152Spendry struct ucred *saved_cred;
14467575Spendry int iswhiteout;
14567575Spendry struct vattr va;
14665935Spendry
14767446Spendry #ifdef notyet
14867446Spendry if (cnp->cn_namelen == 3 &&
14967446Spendry cnp->cn_nameptr[2] == '.' &&
15067446Spendry cnp->cn_nameptr[1] == '.' &&
15167446Spendry cnp->cn_nameptr[0] == '.') {
15267446Spendry dvp = *ap->a_vpp = LOWERVP(ap->a_dvp);
15367446Spendry if (dvp == NULLVP)
15467446Spendry return (ENOENT);
15567446Spendry VREF(dvp);
15669447Smckusick vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
15767446Spendry if (!lockparent || !(cnp->cn_flags & ISLASTCN))
15869447Smckusick VOP_UNLOCK(ap->a_dvp, 0, p);
15967446Spendry return (0);
16067446Spendry }
16167446Spendry #endif
16267446Spendry
16365965Spendry cnp->cn_flags |= LOCKPARENT;
16465965Spendry
16565935Spendry upperdvp = dun->un_uppervp;
16665935Spendry lowerdvp = dun->un_lowervp;
16765997Spendry uppervp = NULLVP;
16865997Spendry lowervp = NULLVP;
16967575Spendry iswhiteout = 0;
17065935Spendry
17165935Spendry /*
17265935Spendry * do the lookup in the upper level.
17365935Spendry * if that level comsumes additional pathnames,
17465935Spendry * then assume that something special is going
17565935Spendry * on and just return that vnode.
17665935Spendry */
17767076Spendry if (upperdvp != NULLVP) {
17869447Smckusick FIXUP(dun, p);
17967064Spendry uerror = union_lookup1(um->um_uppervp, &upperdvp,
18065997Spendry &uppervp, cnp);
18166051Spendry /*if (uppervp == upperdvp)
18266051Spendry dun->un_flags |= UN_KLOCK;*/
18365965Spendry
18465935Spendry if (cnp->cn_consume != 0) {
18565935Spendry *ap->a_vpp = uppervp;
18665965Spendry if (!lockparent)
18765965Spendry cnp->cn_flags &= ~LOCKPARENT;
18865935Spendry return (uerror);
18965935Spendry }
19067575Spendry if (uerror == ENOENT || uerror == EJUSTRETURN) {
19167575Spendry if (cnp->cn_flags & ISWHITEOUT) {
19267575Spendry iswhiteout = 1;
19367575Spendry } else if (lowerdvp != NULLVP) {
19467575Spendry lerror = VOP_GETATTR(upperdvp, &va,
19567575Spendry cnp->cn_cred, cnp->cn_proc);
19667575Spendry if (lerror == 0 && (va.va_flags & OPAQUE))
19767575Spendry iswhiteout = 1;
19867575Spendry }
19967575Spendry }
20065935Spendry } else {
20165935Spendry uerror = ENOENT;
20265935Spendry }
20365935Spendry
20465935Spendry /*
20565935Spendry * in a similar way to the upper layer, do the lookup
20665935Spendry * in the lower layer. this time, if there is some
20765935Spendry * component magic going on, then vput whatever we got
20865935Spendry * back from the upper layer and return the lower vnode
20965935Spendry * instead.
21065935Spendry */
21167575Spendry if (lowerdvp != NULLVP && !iswhiteout) {
21266051Spendry int nameiop;
21366051Spendry
21469447Smckusick vn_lock(lowerdvp, LK_EXCLUSIVE | LK_RETRY, p);
21566051Spendry
21666051Spendry /*
21766051Spendry * Only do a LOOKUP on the bottom node, since
21866051Spendry * we won't be making changes to it anyway.
21966051Spendry */
22066051Spendry nameiop = cnp->cn_nameiop;
22166051Spendry cnp->cn_nameiop = LOOKUP;
22266152Spendry if (um->um_op == UNMNT_BELOW) {
22366152Spendry saved_cred = cnp->cn_cred;
22466152Spendry cnp->cn_cred = um->um_cred;
22566152Spendry }
22667064Spendry lerror = union_lookup1(um->um_lowervp, &lowerdvp,
22766051Spendry &lowervp, cnp);
22866152Spendry if (um->um_op == UNMNT_BELOW)
22966152Spendry cnp->cn_cred = saved_cred;
23066051Spendry cnp->cn_nameiop = nameiop;
23166051Spendry
23265989Spendry if (lowervp != lowerdvp)
23369447Smckusick VOP_UNLOCK(lowerdvp, 0, p);
23465965Spendry
23565935Spendry if (cnp->cn_consume != 0) {
23667076Spendry if (uppervp != NULLVP) {
23766051Spendry if (uppervp == upperdvp)
23866051Spendry vrele(uppervp);
23966051Spendry else
24066051Spendry vput(uppervp);
24165997Spendry uppervp = NULLVP;
24265935Spendry }
24365935Spendry *ap->a_vpp = lowervp;
24465965Spendry if (!lockparent)
24565965Spendry cnp->cn_flags &= ~LOCKPARENT;
24665935Spendry return (lerror);
24765935Spendry }
24865935Spendry } else {
24965935Spendry lerror = ENOENT;
25067416Spendry if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
25167416Spendry lowervp = LOWERVP(dun->un_pvp);
25267416Spendry if (lowervp != NULLVP) {
25367416Spendry VREF(lowervp);
25469447Smckusick vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY, p);
25567416Spendry lerror = 0;
25667416Spendry }
25767416Spendry }
25865935Spendry }
25965935Spendry
26065965Spendry if (!lockparent)
26165965Spendry cnp->cn_flags &= ~LOCKPARENT;
26265965Spendry
26365935Spendry /*
26465935Spendry * at this point, we have uerror and lerror indicating
26565935Spendry * possible errors with the lookups in the upper and lower
26665935Spendry * layers. additionally, uppervp and lowervp are (locked)
26765935Spendry * references to existing vnodes in the upper and lower layers.
26865935Spendry *
26965935Spendry * there are now three cases to consider.
27065935Spendry * 1. if both layers returned an error, then return whatever
27165935Spendry * error the upper layer generated.
27265935Spendry *
27365935Spendry * 2. if the top layer failed and the bottom layer succeeded
27465935Spendry * then two subcases occur.
27565935Spendry * a. the bottom vnode is not a directory, in which
27665935Spendry * case just return a new union vnode referencing
27765935Spendry * an empty top layer and the existing bottom layer.
27865935Spendry * b. the bottom vnode is a directory, in which case
27965935Spendry * create a new directory in the top-level and
28065935Spendry * continue as in case 3.
28165935Spendry *
28265935Spendry * 3. if the top layer succeeded then return a new union
28365935Spendry * vnode referencing whatever the new top layer and
28465935Spendry * whatever the bottom layer returned.
28565935Spendry */
28665935Spendry
28766027Spendry *ap->a_vpp = NULLVP;
28866027Spendry
28965935Spendry /* case 1. */
29065935Spendry if ((uerror != 0) && (lerror != 0)) {
29165935Spendry return (uerror);
29265935Spendry }
29365935Spendry
29465935Spendry /* case 2. */
29565935Spendry if (uerror != 0 /* && (lerror == 0) */ ) {
29665935Spendry if (lowervp->v_type == VDIR) { /* case 2b. */
29766051Spendry dun->un_flags &= ~UN_ULOCK;
29869447Smckusick VOP_UNLOCK(upperdvp, 0, p);
29965997Spendry uerror = union_mkshadow(um, upperdvp, cnp, &uppervp);
30069447Smckusick vn_lock(upperdvp, LK_EXCLUSIVE | LK_RETRY, p);
30166051Spendry dun->un_flags |= UN_ULOCK;
30266051Spendry
30365935Spendry if (uerror) {
30467076Spendry if (lowervp != NULLVP) {
30565935Spendry vput(lowervp);
30665997Spendry lowervp = NULLVP;
30765935Spendry }
30865935Spendry return (uerror);
30965935Spendry }
31065935Spendry }
31165935Spendry }
31265935Spendry
31367076Spendry if (lowervp != NULLVP)
31469447Smckusick VOP_UNLOCK(lowervp, 0, p);
31565965Spendry
31665997Spendry error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
31768078Spendry uppervp, lowervp, 1);
31865997Spendry
31965965Spendry if (error) {
32067076Spendry if (uppervp != NULLVP)
32166051Spendry vput(uppervp);
32267076Spendry if (lowervp != NULLVP)
32365965Spendry vrele(lowervp);
32465965Spendry } else {
32565994Spendry if (*ap->a_vpp != dvp)
32665994Spendry if (!lockparent || !(cnp->cn_flags & ISLASTCN))
32769447Smckusick VOP_UNLOCK(dvp, 0, p);
32865965Spendry }
32965965Spendry
33065965Spendry return (error);
33165935Spendry }
33265935Spendry
33365963Spendry int
union_create(ap)33465963Spendry union_create(ap)
33565963Spendry struct vop_create_args /* {
33665963Spendry struct vnode *a_dvp;
33765963Spendry struct vnode **a_vpp;
33865963Spendry struct componentname *a_cnp;
33965963Spendry struct vattr *a_vap;
34065963Spendry } */ *ap;
34165963Spendry {
34265963Spendry struct union_node *un = VTOUNION(ap->a_dvp);
34365963Spendry struct vnode *dvp = un->un_uppervp;
34469447Smckusick struct componentname *cnp = ap->a_cnp;
34569447Smckusick struct proc *p = cnp->cn_proc;
34665963Spendry
34767076Spendry if (dvp != NULLVP) {
34865963Spendry int error;
34965963Spendry struct vnode *vp;
35068078Spendry struct mount *mp;
35165963Spendry
35269447Smckusick FIXUP(un, p);
35366152Spendry
35465963Spendry VREF(dvp);
35566051Spendry un->un_flags |= UN_KLOCK;
35668078Spendry mp = ap->a_dvp->v_mount;
35765963Spendry vput(ap->a_dvp);
35869447Smckusick error = VOP_CREATE(dvp, &vp, cnp, ap->a_vap);
35965963Spendry if (error)
36065963Spendry return (error);
36165963Spendry
36269447Smckusick error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP, cnp, vp,
36369447Smckusick NULLVP, 1);
36465965Spendry if (error)
36566051Spendry vput(vp);
36665963Spendry return (error);
36765963Spendry }
36865963Spendry
36965963Spendry vput(ap->a_dvp);
37065963Spendry return (EROFS);
37165963Spendry }
37265963Spendry
37365963Spendry int
union_whiteout(ap)37467575Spendry union_whiteout(ap)
37567575Spendry struct vop_whiteout_args /* {
37667575Spendry struct vnode *a_dvp;
37767575Spendry struct componentname *a_cnp;
37867575Spendry int a_flags;
37967575Spendry } */ *ap;
38067575Spendry {
38167575Spendry struct union_node *un = VTOUNION(ap->a_dvp);
38269447Smckusick struct componentname *cnp = ap->a_cnp;
38369447Smckusick struct proc *p = cnp->cn_proc;
38467575Spendry
38567575Spendry if (un->un_uppervp == NULLVP)
38667575Spendry return (EOPNOTSUPP);
38767575Spendry
38869447Smckusick FIXUP(un, p);
38969447Smckusick return (VOP_WHITEOUT(un->un_uppervp, cnp, ap->a_flags));
39067575Spendry }
39167575Spendry
39267575Spendry int
union_mknod(ap)39365963Spendry union_mknod(ap)
39465963Spendry struct vop_mknod_args /* {
39565963Spendry struct vnode *a_dvp;
39665963Spendry struct vnode **a_vpp;
39765963Spendry struct componentname *a_cnp;
39865963Spendry struct vattr *a_vap;
39965963Spendry } */ *ap;
40065963Spendry {
40165963Spendry struct union_node *un = VTOUNION(ap->a_dvp);
40265963Spendry struct vnode *dvp = un->un_uppervp;
40369447Smckusick struct componentname *cnp = ap->a_cnp;
40469447Smckusick struct proc *p = cnp->cn_proc;
40565963Spendry
40667076Spendry if (dvp != NULLVP) {
40765963Spendry int error;
40865963Spendry struct vnode *vp;
40968078Spendry struct mount *mp;
41065963Spendry
41169447Smckusick FIXUP(un, p);
41266152Spendry
41365963Spendry VREF(dvp);
41466051Spendry un->un_flags |= UN_KLOCK;
41568078Spendry mp = ap->a_dvp->v_mount;
41665963Spendry vput(ap->a_dvp);
41769447Smckusick error = VOP_MKNOD(dvp, &vp, cnp, ap->a_vap);
41865963Spendry if (error)
41965963Spendry return (error);
42065963Spendry
42167076Spendry if (vp != NULLVP) {
42269447Smckusick error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
42369447Smckusick cnp, vp, NULLVP, 1);
42465965Spendry if (error)
42566051Spendry vput(vp);
42665965Spendry }
42765963Spendry return (error);
42865963Spendry }
42965963Spendry
43065963Spendry vput(ap->a_dvp);
43165963Spendry return (EROFS);
43265963Spendry }
43365963Spendry
43465935Spendry int
union_open(ap)43565935Spendry union_open(ap)
43665935Spendry struct vop_open_args /* {
43765935Spendry struct vnodeop_desc *a_desc;
43865935Spendry struct vnode *a_vp;
43965935Spendry int a_mode;
44065935Spendry struct ucred *a_cred;
44165935Spendry struct proc *a_p;
44265935Spendry } */ *ap;
44365935Spendry {
44465935Spendry struct union_node *un = VTOUNION(ap->a_vp);
44565965Spendry struct vnode *tvp;
44665935Spendry int mode = ap->a_mode;
44765935Spendry struct ucred *cred = ap->a_cred;
44865935Spendry struct proc *p = ap->a_p;
44965965Spendry int error;
45065935Spendry
45165935Spendry /*
45265935Spendry * If there is an existing upper vp then simply open that.
45365935Spendry */
45465965Spendry tvp = un->un_uppervp;
45565965Spendry if (tvp == NULLVP) {
45665935Spendry /*
45765965Spendry * If the lower vnode is being opened for writing, then
45865965Spendry * copy the file contents to the upper vnode and open that,
45965965Spendry * otherwise can simply open the lower vnode.
46065935Spendry */
46165965Spendry tvp = un->un_lowervp;
46265965Spendry if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
46367169Spendry error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
46465965Spendry if (error == 0)
46565965Spendry error = VOP_OPEN(un->un_uppervp, mode, cred, p);
46665965Spendry return (error);
46765935Spendry }
46866051Spendry
46966051Spendry /*
47066051Spendry * Just open the lower vnode
47166051Spendry */
47266027Spendry un->un_openl++;
47369447Smckusick vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);
47466051Spendry error = VOP_OPEN(tvp, mode, cred, p);
47569447Smckusick VOP_UNLOCK(tvp, 0, p);
47666051Spendry
47766051Spendry return (error);
47865935Spendry }
47965935Spendry
48069447Smckusick FIXUP(un, p);
48166152Spendry
48265965Spendry error = VOP_OPEN(tvp, mode, cred, p);
48365965Spendry
48465965Spendry return (error);
48565935Spendry }
48665935Spendry
48765963Spendry int
union_close(ap)48865963Spendry union_close(ap)
48965963Spendry struct vop_close_args /* {
49065963Spendry struct vnode *a_vp;
49165963Spendry int a_fflag;
49265963Spendry struct ucred *a_cred;
49365963Spendry struct proc *a_p;
49465963Spendry } */ *ap;
49565963Spendry {
49665997Spendry struct union_node *un = VTOUNION(ap->a_vp);
49765997Spendry struct vnode *vp;
49865963Spendry
49969590Smckusick if ((vp = un->un_uppervp) == NULLVP) {
50066027Spendry #ifdef UNION_DIAGNOSTIC
50166027Spendry if (un->un_openl <= 0)
50266027Spendry panic("union: un_openl cnt");
50365997Spendry #endif
50466027Spendry --un->un_openl;
50565997Spendry vp = un->un_lowervp;
50665997Spendry }
50766027Spendry
50869590Smckusick ap->a_vp = vp;
50969590Smckusick return (VCALL(vp, VOFFSET(vop_close), ap));
51065963Spendry }
51165963Spendry
51265935Spendry /*
51365963Spendry * Check access permission on the union vnode.
51465963Spendry * The access check being enforced is to check
51565963Spendry * against both the underlying vnode, and any
51665963Spendry * copied vnode. This ensures that no additional
51765963Spendry * file permissions are given away simply because
51865963Spendry * the user caused an implicit file copy.
51965963Spendry */
52065963Spendry int
union_access(ap)52165963Spendry union_access(ap)
52265963Spendry struct vop_access_args /* {
52365963Spendry struct vnodeop_desc *a_desc;
52465963Spendry struct vnode *a_vp;
52565963Spendry int a_mode;
52665963Spendry struct ucred *a_cred;
52765963Spendry struct proc *a_p;
52865963Spendry } */ *ap;
52965963Spendry {
53065963Spendry struct union_node *un = VTOUNION(ap->a_vp);
53169447Smckusick struct proc *p = ap->a_p;
53266149Spendry int error = EACCES;
53365963Spendry struct vnode *vp;
53465963Spendry
53567076Spendry if ((vp = un->un_uppervp) != NULLVP) {
53669447Smckusick FIXUP(un, p);
53769590Smckusick ap->a_vp = vp;
53869590Smckusick return (VCALL(vp, VOFFSET(vop_access), ap));
53966152Spendry }
54066152Spendry
54167076Spendry if ((vp = un->un_lowervp) != NULLVP) {
54269447Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
54369590Smckusick ap->a_vp = vp;
54469590Smckusick error = VCALL(vp, VOFFSET(vop_access), ap);
54566152Spendry if (error == 0) {
54666152Spendry struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);
54766152Spendry
54869590Smckusick if (um->um_op == UNMNT_BELOW) {
54969590Smckusick ap->a_cred = um->um_cred;
55069590Smckusick error = VCALL(vp, VOFFSET(vop_access), ap);
55169590Smckusick }
55266152Spendry }
55369447Smckusick VOP_UNLOCK(vp, 0, p);
55465963Spendry if (error)
55565963Spendry return (error);
55665963Spendry }
55765963Spendry
55865965Spendry return (error);
55965963Spendry }
56065963Spendry
56165963Spendry /*
56267109Spendry * We handle getattr only to change the fsid and
56367109Spendry * track object sizes
56465935Spendry */
56565935Spendry int
union_getattr(ap)56665935Spendry union_getattr(ap)
56765935Spendry struct vop_getattr_args /* {
56865935Spendry struct vnode *a_vp;
56965935Spendry struct vattr *a_vap;
57065935Spendry struct ucred *a_cred;
57165935Spendry struct proc *a_p;
57265935Spendry } */ *ap;
57365935Spendry {
57465935Spendry int error;
57566062Spendry struct union_node *un = VTOUNION(ap->a_vp);
57666062Spendry struct vnode *vp = un->un_uppervp;
57769447Smckusick struct proc *p = ap->a_p;
57866062Spendry struct vattr *vap;
57966062Spendry struct vattr va;
58065935Spendry
58166062Spendry
58266062Spendry /*
58366062Spendry * Some programs walk the filesystem hierarchy by counting
58466062Spendry * links to directories to avoid stat'ing all the time.
58566062Spendry * This means the link count on directories needs to be "correct".
58666062Spendry * The only way to do that is to call getattr on both layers
58766062Spendry * and fix up the link count. The link count will not necessarily
58866062Spendry * be accurate but will be large enough to defeat the tree walkers.
58966062Spendry */
59066062Spendry
59166062Spendry vap = ap->a_vap;
59266062Spendry
59366062Spendry vp = un->un_uppervp;
59466062Spendry if (vp != NULLVP) {
59567073Spendry /*
59667073Spendry * It's not clear whether VOP_GETATTR is to be
59767073Spendry * called with the vnode locked or not. stat() calls
59867073Spendry * it with (vp) locked, and fstat calls it with
59967073Spendry * (vp) unlocked.
60067073Spendry * In the mean time, compensate here by checking
60167073Spendry * the union_node's lock flag.
60267073Spendry */
60367073Spendry if (un->un_flags & UN_LOCKED)
60469447Smckusick FIXUP(un, p);
60567073Spendry
60666062Spendry error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
60766062Spendry if (error)
60866062Spendry return (error);
60967109Spendry union_newsize(ap->a_vp, vap->va_size, VNOVAL);
61066062Spendry }
61166062Spendry
61266062Spendry if (vp == NULLVP) {
61366062Spendry vp = un->un_lowervp;
61466062Spendry } else if (vp->v_type == VDIR) {
61566062Spendry vp = un->un_lowervp;
61666062Spendry vap = &va;
61766062Spendry } else {
61866062Spendry vp = NULLVP;
61966062Spendry }
62066062Spendry
62166062Spendry if (vp != NULLVP) {
62266062Spendry error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
62366062Spendry if (error)
62466062Spendry return (error);
62567109Spendry union_newsize(ap->a_vp, VNOVAL, vap->va_size);
62666062Spendry }
62765965Spendry
62866062Spendry if ((vap != ap->a_vap) && (vap->va_type == VDIR))
62966062Spendry ap->a_vap->va_nlink += vap->va_nlink;
63066062Spendry
63167400Spendry ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
63265935Spendry return (0);
63365935Spendry }
63465935Spendry
63565963Spendry int
union_setattr(ap)63665965Spendry union_setattr(ap)
63765963Spendry struct vop_setattr_args /* {
63865963Spendry struct vnode *a_vp;
63965963Spendry struct vattr *a_vap;
64065963Spendry struct ucred *a_cred;
64165963Spendry struct proc *a_p;
64265963Spendry } */ *ap;
64365963Spendry {
64465963Spendry struct union_node *un = VTOUNION(ap->a_vp);
64569447Smckusick struct proc *p = ap->a_p;
64665963Spendry int error;
64765963Spendry
64866057Spendry /*
64966057Spendry * Handle case of truncating lower object to zero size,
65066057Spendry * by creating a zero length upper object. This is to
65166057Spendry * handle the case of open with O_TRUNC and O_CREAT.
65266057Spendry */
65366057Spendry if ((un->un_uppervp == NULLVP) &&
65466057Spendry /* assert(un->un_lowervp != NULLVP) */
65567575Spendry (un->un_lowervp->v_type == VREG)) {
65667575Spendry error = union_copyup(un, (ap->a_vap->va_size != 0),
65767575Spendry ap->a_cred, ap->a_p);
65866057Spendry if (error)
65966057Spendry return (error);
66066057Spendry }
66166057Spendry
66266057Spendry /*
66366057Spendry * Try to set attributes in upper layer,
66466057Spendry * otherwise return read-only filesystem error.
66566057Spendry */
66666057Spendry if (un->un_uppervp != NULLVP) {
66769447Smckusick FIXUP(un, p);
66865963Spendry error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
66965963Spendry ap->a_cred, ap->a_p);
67067109Spendry if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
67167109Spendry union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
67265963Spendry } else {
67365963Spendry error = EROFS;
67465963Spendry }
67565963Spendry
67665963Spendry return (error);
67765963Spendry }
67865963Spendry
67965963Spendry int
union_read(ap)68065963Spendry union_read(ap)
68165963Spendry struct vop_read_args /* {
68265963Spendry struct vnode *a_vp;
68365963Spendry struct uio *a_uio;
68465963Spendry int a_ioflag;
68565963Spendry struct ucred *a_cred;
68665963Spendry } */ *ap;
68765963Spendry {
68865963Spendry int error;
68969447Smckusick struct proc *p = ap->a_uio->uio_procp;
69065963Spendry struct vnode *vp = OTHERVP(ap->a_vp);
69166051Spendry int dolock = (vp == LOWERVP(ap->a_vp));
69265963Spendry
69366051Spendry if (dolock)
69469447Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
69566152Spendry else
69669447Smckusick FIXUP(VTOUNION(ap->a_vp), p);
69765963Spendry error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
69866051Spendry if (dolock)
69969447Smckusick VOP_UNLOCK(vp, 0, p);
70065963Spendry
70167109Spendry /*
70267109Spendry * XXX
70367109Spendry * perhaps the size of the underlying object has changed under
70467109Spendry * our feet. take advantage of the offset information present
70567109Spendry * in the uio structure.
70667109Spendry */
70767109Spendry if (error == 0) {
70867109Spendry struct union_node *un = VTOUNION(ap->a_vp);
70967109Spendry off_t cur = ap->a_uio->uio_offset;
71067109Spendry
71167109Spendry if (vp == un->un_uppervp) {
71267109Spendry if (cur > un->un_uppersz)
71367109Spendry union_newsize(ap->a_vp, cur, VNOVAL);
71467109Spendry } else {
71567109Spendry if (cur > un->un_lowersz)
71667109Spendry union_newsize(ap->a_vp, VNOVAL, cur);
71767109Spendry }
71867109Spendry }
71967109Spendry
72065963Spendry return (error);
72165963Spendry }
72265963Spendry
72365963Spendry int
union_write(ap)72465963Spendry union_write(ap)
72565963Spendry struct vop_read_args /* {
72665963Spendry struct vnode *a_vp;
72765963Spendry struct uio *a_uio;
72865963Spendry int a_ioflag;
72965963Spendry struct ucred *a_cred;
73065963Spendry } */ *ap;
73165963Spendry {
73265963Spendry int error;
73367575Spendry struct vnode *vp;
73467575Spendry struct union_node *un = VTOUNION(ap->a_vp);
73569447Smckusick struct proc *p = ap->a_uio->uio_procp;
73665963Spendry
73767575Spendry vp = UPPERVP(ap->a_vp);
73867575Spendry if (vp == NULLVP)
73967575Spendry panic("union: missing upper layer in write");
74067575Spendry
74169447Smckusick FIXUP(un, p);
74265963Spendry error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
74365963Spendry
74467109Spendry /*
74567109Spendry * the size of the underlying object may be changed by the
74667109Spendry * write.
74767109Spendry */
74867109Spendry if (error == 0) {
74967109Spendry off_t cur = ap->a_uio->uio_offset;
75067109Spendry
75167575Spendry if (cur > un->un_uppersz)
75267575Spendry union_newsize(ap->a_vp, cur, VNOVAL);
75367109Spendry }
75467109Spendry
75565963Spendry return (error);
75665963Spendry }
75765963Spendry
75867751Spendry union_lease(ap)
75967751Spendry struct vop_lease_args /* {
76067751Spendry struct vnode *a_vp;
76167751Spendry struct proc *a_p;
76267751Spendry struct ucred *a_cred;
76367751Spendry int a_flag;
76467751Spendry } */ *ap;
76567751Spendry {
76669590Smckusick register struct vnode *ovp = OTHERVP(ap->a_vp);
76767751Spendry
76869590Smckusick ap->a_vp = ovp;
76969590Smckusick return (VCALL(ovp, VOFFSET(vop_lease), ap));
77067751Spendry }
77167751Spendry
77265963Spendry int
union_ioctl(ap)77365963Spendry union_ioctl(ap)
77465963Spendry struct vop_ioctl_args /* {
77565963Spendry struct vnode *a_vp;
77665963Spendry int a_command;
77765963Spendry caddr_t a_data;
77865963Spendry int a_fflag;
77965963Spendry struct ucred *a_cred;
78065963Spendry struct proc *a_p;
78165963Spendry } */ *ap;
78265963Spendry {
78369590Smckusick register struct vnode *ovp = OTHERVP(ap->a_vp);
78465963Spendry
78569590Smckusick ap->a_vp = ovp;
78669590Smckusick return (VCALL(ovp, VOFFSET(vop_ioctl), ap));
78765963Spendry }
78865963Spendry
78965963Spendry int
union_select(ap)79065963Spendry union_select(ap)
79165963Spendry struct vop_select_args /* {
79265963Spendry struct vnode *a_vp;
79365963Spendry int a_which;
79465963Spendry int a_fflags;
79565963Spendry struct ucred *a_cred;
79665963Spendry struct proc *a_p;
79765963Spendry } */ *ap;
79865963Spendry {
79969590Smckusick register struct vnode *ovp = OTHERVP(ap->a_vp);
80065963Spendry
80169590Smckusick ap->a_vp = ovp;
80269590Smckusick return (VCALL(ovp, VOFFSET(vop_select), ap));
80365963Spendry }
80465963Spendry
80565963Spendry int
union_revoke(ap)80669389Spendry union_revoke(ap)
80769389Spendry struct vop_revoke_args /* {
80869389Spendry struct vnode *a_vp;
80969389Spendry int a_flags;
81069447Smckusick struct proc *a_p;
81169389Spendry } */ *ap;
81269389Spendry {
81369389Spendry struct vnode *vp = ap->a_vp;
81469389Spendry
81569389Spendry if (UPPERVP(vp))
81669389Spendry VOP_REVOKE(UPPERVP(vp), ap->a_flags);
81769389Spendry if (LOWERVP(vp))
81869447Smckusick VOP_REVOKE(LOWERVP(vp), ap->a_flags);
81969389Spendry vgone(vp);
82069389Spendry }
82169389Spendry
82269389Spendry int
union_mmap(ap)82365963Spendry union_mmap(ap)
82465963Spendry struct vop_mmap_args /* {
82565963Spendry struct vnode *a_vp;
82665963Spendry int a_fflags;
82765963Spendry struct ucred *a_cred;
82865963Spendry struct proc *a_p;
82965963Spendry } */ *ap;
83065963Spendry {
83169590Smckusick register struct vnode *ovp = OTHERVP(ap->a_vp);
83265963Spendry
83369590Smckusick ap->a_vp = ovp;
83469590Smckusick return (VCALL(ovp, VOFFSET(vop_mmap), ap));
83565963Spendry }
83665963Spendry
83765963Spendry int
union_fsync(ap)83865963Spendry union_fsync(ap)
83965963Spendry struct vop_fsync_args /* {
84065963Spendry struct vnode *a_vp;
84165963Spendry struct ucred *a_cred;
84265963Spendry int a_waitfor;
84365963Spendry struct proc *a_p;
84465963Spendry } */ *ap;
84565963Spendry {
84665963Spendry int error = 0;
84769447Smckusick struct proc *p = ap->a_p;
84865963Spendry struct vnode *targetvp = OTHERVP(ap->a_vp);
84965963Spendry
85067076Spendry if (targetvp != NULLVP) {
85166051Spendry int dolock = (targetvp == LOWERVP(ap->a_vp));
85266051Spendry
85366051Spendry if (dolock)
85469447Smckusick vn_lock(targetvp, LK_EXCLUSIVE | LK_RETRY, p);
85566152Spendry else
85669447Smckusick FIXUP(VTOUNION(ap->a_vp), p);
85769447Smckusick error = VOP_FSYNC(targetvp, ap->a_cred, ap->a_waitfor, p);
85866051Spendry if (dolock)
85969447Smckusick VOP_UNLOCK(targetvp, 0, p);
86065963Spendry }
86165963Spendry
86265963Spendry return (error);
86365963Spendry }
86465963Spendry
86565963Spendry int
union_seek(ap)86665963Spendry union_seek(ap)
86765963Spendry struct vop_seek_args /* {
86865963Spendry struct vnode *a_vp;
86965963Spendry off_t a_oldoff;
87065963Spendry off_t a_newoff;
87165963Spendry struct ucred *a_cred;
87265963Spendry } */ *ap;
87365963Spendry {
87469590Smckusick register struct vnode *ovp = OTHERVP(ap->a_vp);
87565963Spendry
87669590Smckusick ap->a_vp = ovp;
87769590Smckusick return (VCALL(ovp, VOFFSET(vop_seek), ap));
87865963Spendry }
87965963Spendry
88065963Spendry int
union_remove(ap)88165963Spendry union_remove(ap)
88265963Spendry struct vop_remove_args /* {
88365963Spendry struct vnode *a_dvp;
88465963Spendry struct vnode *a_vp;
88565963Spendry struct componentname *a_cnp;
88665963Spendry } */ *ap;
88765963Spendry {
88865963Spendry int error;
88965963Spendry struct union_node *dun = VTOUNION(ap->a_dvp);
89065963Spendry struct union_node *un = VTOUNION(ap->a_vp);
89169447Smckusick struct componentname *cnp = ap->a_cnp;
89269447Smckusick struct proc *p = cnp->cn_proc;
89365963Spendry
89467575Spendry if (dun->un_uppervp == NULLVP)
89567575Spendry panic("union remove: null upper vnode");
89667575Spendry
89767575Spendry if (un->un_uppervp != NULLVP) {
89865963Spendry struct vnode *dvp = dun->un_uppervp;
89965963Spendry struct vnode *vp = un->un_uppervp;
90065963Spendry
90169447Smckusick FIXUP(dun, p);
90265963Spendry VREF(dvp);
90366051Spendry dun->un_flags |= UN_KLOCK;
90465963Spendry vput(ap->a_dvp);
90569447Smckusick FIXUP(un, p);
90665963Spendry VREF(vp);
90766051Spendry un->un_flags |= UN_KLOCK;
90865963Spendry vput(ap->a_vp);
90965963Spendry
91067784Spendry if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
91167784Spendry cnp->cn_flags |= DOWHITEOUT;
91267784Spendry error = VOP_REMOVE(dvp, vp, cnp);
91366027Spendry if (!error)
91466027Spendry union_removed_upper(un);
91565963Spendry } else {
91669447Smckusick FIXUP(dun, p);
91767575Spendry error = union_mkwhiteout(
91867575Spendry MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
91967575Spendry dun->un_uppervp, ap->a_cnp, un->un_path);
92065963Spendry vput(ap->a_dvp);
92165963Spendry vput(ap->a_vp);
92265963Spendry }
92365963Spendry
92465963Spendry return (error);
92565963Spendry }
92665963Spendry
92765963Spendry int
union_link(ap)92865963Spendry union_link(ap)
92965963Spendry struct vop_link_args /* {
93065963Spendry struct vnode *a_vp;
93165963Spendry struct vnode *a_tdvp;
93265963Spendry struct componentname *a_cnp;
93365963Spendry } */ *ap;
93465963Spendry {
93567169Spendry int error = 0;
93669447Smckusick struct componentname *cnp = ap->a_cnp;
93769447Smckusick struct proc *p = cnp->cn_proc;
93867169Spendry struct union_node *un;
93967169Spendry struct vnode *vp;
94067169Spendry struct vnode *tdvp;
94165963Spendry
94268535Smckusick un = VTOUNION(ap->a_tdvp);
94365963Spendry
94468535Smckusick if (ap->a_tdvp->v_op != ap->a_vp->v_op) {
94568535Smckusick vp = ap->a_vp;
94667169Spendry } else {
94768535Smckusick struct union_node *tun = VTOUNION(ap->a_vp);
94868535Smckusick if (tun->un_uppervp == NULLVP) {
94969447Smckusick vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
95068535Smckusick if (un->un_uppervp == tun->un_dirvp) {
95167169Spendry un->un_flags &= ~UN_ULOCK;
95269447Smckusick VOP_UNLOCK(un->un_uppervp, 0, p);
95367169Spendry }
95469447Smckusick error = union_copyup(tun, 1, cnp->cn_cred, p);
95568535Smckusick if (un->un_uppervp == tun->un_dirvp) {
95669447Smckusick vn_lock(un->un_uppervp,
95769447Smckusick LK_EXCLUSIVE | LK_RETRY, p);
95867169Spendry un->un_flags |= UN_ULOCK;
95967169Spendry }
96069447Smckusick VOP_UNLOCK(ap->a_vp, 0, p);
96167169Spendry }
96268535Smckusick vp = tun->un_uppervp;
96367169Spendry }
96465963Spendry
96568535Smckusick tdvp = un->un_uppervp;
96668535Smckusick if (tdvp == NULLVP)
96767169Spendry error = EROFS;
96867169Spendry
96967169Spendry if (error) {
97068535Smckusick vput(ap->a_tdvp);
97167169Spendry return (error);
97265963Spendry }
97365963Spendry
97469447Smckusick FIXUP(un, p);
97568535Smckusick VREF(tdvp);
97667169Spendry un->un_flags |= UN_KLOCK;
97768535Smckusick vput(ap->a_tdvp);
97867169Spendry
97969447Smckusick return (VOP_LINK(vp, tdvp, cnp));
98065963Spendry }
98165963Spendry
98265963Spendry int
union_rename(ap)98365963Spendry union_rename(ap)
98465963Spendry struct vop_rename_args /* {
98565963Spendry struct vnode *a_fdvp;
98665963Spendry struct vnode *a_fvp;
98765963Spendry struct componentname *a_fcnp;
98865963Spendry struct vnode *a_tdvp;
98965963Spendry struct vnode *a_tvp;
99065963Spendry struct componentname *a_tcnp;
99165963Spendry } */ *ap;
99265963Spendry {
99365963Spendry int error;
99465963Spendry
99565963Spendry struct vnode *fdvp = ap->a_fdvp;
99665963Spendry struct vnode *fvp = ap->a_fvp;
99765963Spendry struct vnode *tdvp = ap->a_tdvp;
99865963Spendry struct vnode *tvp = ap->a_tvp;
99965963Spendry
100065963Spendry if (fdvp->v_op == union_vnodeop_p) { /* always true */
100165963Spendry struct union_node *un = VTOUNION(fdvp);
100265997Spendry if (un->un_uppervp == NULLVP) {
100367575Spendry /*
100467575Spendry * this should never happen in normal
100567575Spendry * operation but might if there was
100667575Spendry * a problem creating the top-level shadow
100767575Spendry * directory.
100867575Spendry */
100967575Spendry error = EXDEV;
101065963Spendry goto bad;
101165963Spendry }
101265963Spendry
101365963Spendry fdvp = un->un_uppervp;
101465963Spendry VREF(fdvp);
101565963Spendry vrele(ap->a_fdvp);
101665963Spendry }
101765963Spendry
101865963Spendry if (fvp->v_op == union_vnodeop_p) { /* always true */
101965963Spendry struct union_node *un = VTOUNION(fvp);
102065997Spendry if (un->un_uppervp == NULLVP) {
102167575Spendry /* XXX: should do a copyup */
102267575Spendry error = EXDEV;
102365963Spendry goto bad;
102465963Spendry }
102565963Spendry
102667575Spendry if (un->un_lowervp != NULLVP)
102767575Spendry ap->a_fcnp->cn_flags |= DOWHITEOUT;
102867575Spendry
102965963Spendry fvp = un->un_uppervp;
103065963Spendry VREF(fvp);
103165963Spendry vrele(ap->a_fvp);
103265963Spendry }
103365963Spendry
103465963Spendry if (tdvp->v_op == union_vnodeop_p) {
103565963Spendry struct union_node *un = VTOUNION(tdvp);
103665997Spendry if (un->un_uppervp == NULLVP) {
103767076Spendry /*
103867076Spendry * this should never happen in normal
103967076Spendry * operation but might if there was
104067076Spendry * a problem creating the top-level shadow
104167076Spendry * directory.
104267076Spendry */
104367575Spendry error = EXDEV;
104465963Spendry goto bad;
104565963Spendry }
104665963Spendry
104765963Spendry tdvp = un->un_uppervp;
104865963Spendry VREF(tdvp);
104966051Spendry un->un_flags |= UN_KLOCK;
105065997Spendry vput(ap->a_tdvp);
105165963Spendry }
105265963Spendry
105367076Spendry if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
105465963Spendry struct union_node *un = VTOUNION(tvp);
105565963Spendry
105665963Spendry tvp = un->un_uppervp;
105767076Spendry if (tvp != NULLVP) {
105867076Spendry VREF(tvp);
105967076Spendry un->un_flags |= UN_KLOCK;
106067076Spendry }
106165963Spendry vput(ap->a_tvp);
106265963Spendry }
106365963Spendry
106465963Spendry return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
106565963Spendry
106665963Spendry bad:
106765963Spendry vrele(fdvp);
106865963Spendry vrele(fvp);
106965963Spendry vput(tdvp);
107067076Spendry if (tvp != NULLVP)
107165963Spendry vput(tvp);
107265963Spendry
107365963Spendry return (error);
107465963Spendry }
107565963Spendry
107665963Spendry int
union_mkdir(ap)107765963Spendry union_mkdir(ap)
107865963Spendry struct vop_mkdir_args /* {
107965963Spendry struct vnode *a_dvp;
108065963Spendry struct vnode **a_vpp;
108165963Spendry struct componentname *a_cnp;
108265963Spendry struct vattr *a_vap;
108365963Spendry } */ *ap;
108465963Spendry {
108565963Spendry struct union_node *un = VTOUNION(ap->a_dvp);
108665963Spendry struct vnode *dvp = un->un_uppervp;
108769447Smckusick struct componentname *cnp = ap->a_cnp;
108869447Smckusick struct proc *p = cnp->cn_proc;
108965963Spendry
109067076Spendry if (dvp != NULLVP) {
109165963Spendry int error;
109265963Spendry struct vnode *vp;
109365963Spendry
109469447Smckusick FIXUP(un, p);
109565963Spendry VREF(dvp);
109666051Spendry un->un_flags |= UN_KLOCK;
109769447Smckusick VOP_UNLOCK(ap->a_dvp, 0, p);
109869447Smckusick error = VOP_MKDIR(dvp, &vp, cnp, ap->a_vap);
109968078Spendry if (error) {
110068078Spendry vrele(ap->a_dvp);
110165963Spendry return (error);
110268078Spendry }
110365963Spendry
110469447Smckusick error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount, ap->a_dvp,
110569447Smckusick NULLVP, cnp, vp, NULLVP, 1);
110668078Spendry vrele(ap->a_dvp);
110765965Spendry if (error)
110866051Spendry vput(vp);
110965963Spendry return (error);
111065963Spendry }
111165963Spendry
111265963Spendry vput(ap->a_dvp);
111365963Spendry return (EROFS);
111465963Spendry }
111565963Spendry
111665963Spendry int
union_rmdir(ap)111765963Spendry union_rmdir(ap)
111865963Spendry struct vop_rmdir_args /* {
111965963Spendry struct vnode *a_dvp;
112065963Spendry struct vnode *a_vp;
112165963Spendry struct componentname *a_cnp;
112265963Spendry } */ *ap;
112365963Spendry {
112465963Spendry int error;
112565963Spendry struct union_node *dun = VTOUNION(ap->a_dvp);
112665963Spendry struct union_node *un = VTOUNION(ap->a_vp);
112769447Smckusick struct componentname *cnp = ap->a_cnp;
112869447Smckusick struct proc *p = cnp->cn_proc;
112965963Spendry
113067575Spendry if (dun->un_uppervp == NULLVP)
113167575Spendry panic("union rmdir: null upper vnode");
113267575Spendry
113367575Spendry if (un->un_uppervp != NULLVP) {
113465963Spendry struct vnode *dvp = dun->un_uppervp;
113565963Spendry struct vnode *vp = un->un_uppervp;
113665963Spendry
113769447Smckusick FIXUP(dun, p);
113865963Spendry VREF(dvp);
113966051Spendry dun->un_flags |= UN_KLOCK;
114065963Spendry vput(ap->a_dvp);
114169447Smckusick FIXUP(un, p);
114265963Spendry VREF(vp);
114366051Spendry un->un_flags |= UN_KLOCK;
114465963Spendry vput(ap->a_vp);
114565963Spendry
114667784Spendry if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
114767784Spendry cnp->cn_flags |= DOWHITEOUT;
114866051Spendry error = VOP_RMDIR(dvp, vp, ap->a_cnp);
114966027Spendry if (!error)
115066027Spendry union_removed_upper(un);
115165963Spendry } else {
115269447Smckusick FIXUP(dun, p);
115367575Spendry error = union_mkwhiteout(
115467575Spendry MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
115567575Spendry dun->un_uppervp, ap->a_cnp, un->un_path);
115665963Spendry vput(ap->a_dvp);
115765963Spendry vput(ap->a_vp);
115865963Spendry }
115965963Spendry
116065963Spendry return (error);
116165963Spendry }
116265963Spendry
116365963Spendry int
union_symlink(ap)116465963Spendry union_symlink(ap)
116565963Spendry struct vop_symlink_args /* {
116665963Spendry struct vnode *a_dvp;
116765963Spendry struct vnode **a_vpp;
116865963Spendry struct componentname *a_cnp;
116965963Spendry struct vattr *a_vap;
117065963Spendry char *a_target;
117165963Spendry } */ *ap;
117265963Spendry {
117365963Spendry struct union_node *un = VTOUNION(ap->a_dvp);
117465963Spendry struct vnode *dvp = un->un_uppervp;
117569447Smckusick struct componentname *cnp = ap->a_cnp;
117669447Smckusick struct proc *p = cnp->cn_proc;
117765963Spendry
117867076Spendry if (dvp != NULLVP) {
117965963Spendry int error;
118065963Spendry struct vnode *vp;
118165963Spendry struct mount *mp = ap->a_dvp->v_mount;
118265963Spendry
118369447Smckusick FIXUP(un, p);
118465963Spendry VREF(dvp);
118566051Spendry un->un_flags |= UN_KLOCK;
118665963Spendry vput(ap->a_dvp);
118769447Smckusick error = VOP_SYMLINK(dvp, &vp, cnp, ap->a_vap, ap->a_target);
118865997Spendry *ap->a_vpp = NULLVP;
118965963Spendry return (error);
119065963Spendry }
119165963Spendry
119265963Spendry vput(ap->a_dvp);
119365963Spendry return (EROFS);
119465963Spendry }
119565963Spendry
119665935Spendry /*
119765935Spendry * union_readdir works in concert with getdirentries and
119865935Spendry * readdir(3) to provide a list of entries in the unioned
119965935Spendry * directories. getdirentries is responsible for walking
120065935Spendry * down the union stack. readdir(3) is responsible for
120165935Spendry * eliminating duplicate names from the returned data stream.
120265935Spendry */
120365935Spendry int
union_readdir(ap)120465935Spendry union_readdir(ap)
120565935Spendry struct vop_readdir_args /* {
120665935Spendry struct vnodeop_desc *a_desc;
120765935Spendry struct vnode *a_vp;
120865935Spendry struct uio *a_uio;
120965935Spendry struct ucred *a_cred;
121067369Smckusick int *a_eofflag;
121167369Smckusick u_long *a_cookies;
121267369Smckusick int a_ncookies;
121365935Spendry } */ *ap;
121465935Spendry {
121569447Smckusick struct union_node *un = VTOUNION(ap->a_vp);
121669447Smckusick struct vnode *uvp = un->un_uppervp;
121769447Smckusick struct proc *p = ap->a_uio->uio_procp;
121865935Spendry
121967369Smckusick if (uvp == NULLVP)
122067369Smckusick return (0);
122165935Spendry
122269447Smckusick FIXUP(un, p);
122367369Smckusick ap->a_vp = uvp;
122469590Smckusick return (VCALL(uvp, VOFFSET(vop_readdir), ap));
122565935Spendry }
122665935Spendry
122765935Spendry int
union_readlink(ap)122865963Spendry union_readlink(ap)
122965963Spendry struct vop_readlink_args /* {
123065963Spendry struct vnode *a_vp;
123165963Spendry struct uio *a_uio;
123265963Spendry struct ucred *a_cred;
123365963Spendry } */ *ap;
123465963Spendry {
123565963Spendry int error;
123669447Smckusick struct uio *uio = ap->a_uio;
123769447Smckusick struct proc *p = uio->uio_procp;
123865963Spendry struct vnode *vp = OTHERVP(ap->a_vp);
123966051Spendry int dolock = (vp == LOWERVP(ap->a_vp));
124065963Spendry
124166051Spendry if (dolock)
124269447Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
124366152Spendry else
124469447Smckusick FIXUP(VTOUNION(ap->a_vp), p);
124569590Smckusick ap->a_vp = vp;
124669590Smckusick error = VCALL(vp, VOFFSET(vop_readlink), ap);
124766051Spendry if (dolock)
124869447Smckusick VOP_UNLOCK(vp, 0, p);
124965963Spendry
125065963Spendry return (error);
125165963Spendry }
125265963Spendry
125365963Spendry int
union_abortop(ap)125465963Spendry union_abortop(ap)
125565963Spendry struct vop_abortop_args /* {
125665963Spendry struct vnode *a_dvp;
125765963Spendry struct componentname *a_cnp;
125865963Spendry } */ *ap;
125965963Spendry {
126065963Spendry int error;
126169447Smckusick struct componentname *cnp = ap->a_cnp;
126269447Smckusick struct proc *p = cnp->cn_proc;
126365965Spendry struct vnode *vp = OTHERVP(ap->a_dvp);
126465963Spendry struct union_node *un = VTOUNION(ap->a_dvp);
126565963Spendry int islocked = un->un_flags & UN_LOCKED;
126666051Spendry int dolock = (vp == LOWERVP(ap->a_dvp));
126765963Spendry
126866152Spendry if (islocked) {
126966152Spendry if (dolock)
127069447Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
127166152Spendry else
127269447Smckusick FIXUP(VTOUNION(ap->a_dvp), p);
127366152Spendry }
127469590Smckusick ap->a_dvp = vp;
127569590Smckusick error = VCALL(vp, VOFFSET(vop_abortop), ap);
127666051Spendry if (islocked && dolock)
127769447Smckusick VOP_UNLOCK(vp, 0, p);
127865963Spendry
127965963Spendry return (error);
128065963Spendry }
128165963Spendry
128265963Spendry int
union_inactive(ap)128365935Spendry union_inactive(ap)
128465935Spendry struct vop_inactive_args /* {
128565935Spendry struct vnode *a_vp;
128669447Smckusick struct proc *a_p;
128765935Spendry } */ *ap;
128865935Spendry {
128969588Spendry struct vnode *vp = ap->a_vp;
129069588Spendry struct proc *p = ap->a_p;
129169588Spendry struct union_node *un = VTOUNION(vp);
129268078Spendry struct vnode **vpp;
129365935Spendry
129465935Spendry /*
129565935Spendry * Do nothing (and _don't_ bypass).
129665935Spendry * Wait to vrele lowervp until reclaim,
129765935Spendry * so that until then our union_node is in the
129865935Spendry * cache and reusable.
129965935Spendry *
130065935Spendry * NEEDSWORK: Someday, consider inactive'ing
130165935Spendry * the lowervp and then trying to reactivate it
130265935Spendry * with capabilities (v_id)
130365935Spendry * like they do in the name lookup cache code.
130465935Spendry * That's too much work for now.
130565935Spendry */
130665989Spendry
130768078Spendry if (un->un_dircache != 0) {
130868078Spendry for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
130968078Spendry vrele(*vpp);
131068078Spendry free(un->un_dircache, M_TEMP);
131168078Spendry un->un_dircache = 0;
131268078Spendry }
131368078Spendry
131469588Spendry VOP_UNLOCK(vp, 0, p);
131569588Spendry
131667073Spendry if ((un->un_flags & UN_CACHED) == 0)
131769588Spendry vgone(vp);
131867073Spendry
131965935Spendry return (0);
132065935Spendry }
132165935Spendry
132265935Spendry int
union_reclaim(ap)132365935Spendry union_reclaim(ap)
132465935Spendry struct vop_reclaim_args /* {
132565935Spendry struct vnode *a_vp;
132665935Spendry } */ *ap;
132765935Spendry {
132865935Spendry
132966053Spendry union_freevp(ap->a_vp);
133066053Spendry
133165935Spendry return (0);
133265935Spendry }
133365935Spendry
133465963Spendry int
union_lock(ap)133565963Spendry union_lock(ap)
133665963Spendry struct vop_lock_args *ap;
133765963Spendry {
133866149Spendry struct vnode *vp = ap->a_vp;
133969447Smckusick struct proc *p = ap->a_p;
134069447Smckusick int flags = ap->a_flags;
134166149Spendry struct union_node *un;
134269588Spendry int error;
134365935Spendry
134469588Spendry
134569616Smckusick vop_nolock(ap);
1346*69978Spendry /*
1347*69978Spendry * Need to do real lockmgr-style locking here.
1348*69978Spendry * in the mean time, draining won't work quite right,
1349*69978Spendry * which could lead to a few race conditions.
1350*69978Spendry * the following test was here, but is not quite right, we
1351*69978Spendry * still need to take the lock:
135269616Smckusick if ((flags & LK_TYPE_MASK) == LK_DRAIN)
135369616Smckusick return (0);
1354*69978Spendry */
135569616Smckusick flags &= ~LK_INTERLOCK;
135666149Spendry
135769616Smckusick start:
135866149Spendry un = VTOUNION(vp);
135966149Spendry
136067076Spendry if (un->un_uppervp != NULLVP) {
136167230Spendry if (((un->un_flags & UN_ULOCK) == 0) &&
136267230Spendry (vp->v_usecount != 0)) {
136369588Spendry error = vn_lock(un->un_uppervp, flags, p);
136469588Spendry if (error)
136569588Spendry return (error);
136666149Spendry un->un_flags |= UN_ULOCK;
136766051Spendry }
136866051Spendry #ifdef DIAGNOSTIC
136969389Spendry if (un->un_flags & UN_KLOCK) {
137068590Spendry vprint("union: dangling klock", vp);
137168590Spendry panic("union: dangling upper lock (%lx)", vp);
137269389Spendry }
137366051Spendry #endif
137466051Spendry }
137566051Spendry
137666149Spendry if (un->un_flags & UN_LOCKED) {
137765963Spendry #ifdef DIAGNOSTIC
137865989Spendry if (curproc && un->un_pid == curproc->p_pid &&
137965989Spendry un->un_pid > -1 && curproc->p_pid > -1)
138065989Spendry panic("union: locking against myself");
138165963Spendry #endif
138265963Spendry un->un_flags |= UN_WANT;
138369447Smckusick tsleep((caddr_t)&un->un_flags, PINOD, "unionlk2", 0);
138466149Spendry goto start;
138565963Spendry }
138665989Spendry
138765963Spendry #ifdef DIAGNOSTIC
138865989Spendry if (curproc)
138965989Spendry un->un_pid = curproc->p_pid;
139065989Spendry else
139165989Spendry un->un_pid = -1;
139265963Spendry #endif
139366028Spendry
139466149Spendry un->un_flags |= UN_LOCKED;
139566028Spendry return (0);
139665963Spendry }
139765963Spendry
139868590Spendry /*
139968590Spendry * When operations want to vput() a union node yet retain a lock on
140068590Spendry * the upper vnode (say, to do some further operations like link(),
140168590Spendry * mkdir(), ...), they set UN_KLOCK on the union node, then call
140268590Spendry * vput() which calls VOP_UNLOCK() and comes here. union_unlock()
140368590Spendry * unlocks the union node (leaving the upper vnode alone), clears the
140468590Spendry * KLOCK flag, and then returns to vput(). The caller then does whatever
140568590Spendry * is left to do with the upper vnode, and ensures that it gets unlocked.
140668590Spendry *
140768590Spendry * If UN_KLOCK isn't set, then the upper vnode is unlocked here.
140868590Spendry */
140965935Spendry int
union_unlock(ap)141065963Spendry union_unlock(ap)
141169588Spendry struct vop_unlock_args /* {
141269588Spendry struct vnode *a_vp;
141369588Spendry int a_flags;
141469588Spendry struct proc *a_p;
141569588Spendry } */ *ap;
141665963Spendry {
141765963Spendry struct union_node *un = VTOUNION(ap->a_vp);
141869447Smckusick struct proc *p = ap->a_p;
141965963Spendry
142065963Spendry #ifdef DIAGNOSTIC
142165965Spendry if ((un->un_flags & UN_LOCKED) == 0)
142265965Spendry panic("union: unlock unlocked node");
142365989Spendry if (curproc && un->un_pid != curproc->p_pid &&
142465989Spendry curproc->p_pid > -1 && un->un_pid > -1)
142565963Spendry panic("union: unlocking other process's union node");
142665963Spendry #endif
142765963Spendry
142865963Spendry un->un_flags &= ~UN_LOCKED;
142966051Spendry
143066051Spendry if ((un->un_flags & (UN_ULOCK|UN_KLOCK)) == UN_ULOCK)
143169447Smckusick VOP_UNLOCK(un->un_uppervp, 0, p);
143266051Spendry
143366051Spendry un->un_flags &= ~(UN_ULOCK|UN_KLOCK);
143466051Spendry
143565963Spendry if (un->un_flags & UN_WANT) {
143665963Spendry un->un_flags &= ~UN_WANT;
143765963Spendry wakeup((caddr_t) &un->un_flags);
143865963Spendry }
143965963Spendry
144065963Spendry #ifdef DIAGNOSTIC
144165963Spendry un->un_pid = 0;
144265963Spendry #endif
144369616Smckusick vop_nounlock(ap);
144466028Spendry
144566028Spendry return (0);
144665963Spendry }
144765963Spendry
144865963Spendry int
union_bmap(ap)144965963Spendry union_bmap(ap)
145065963Spendry struct vop_bmap_args /* {
145165963Spendry struct vnode *a_vp;
145265963Spendry daddr_t a_bn;
145365963Spendry struct vnode **a_vpp;
145465963Spendry daddr_t *a_bnp;
145565963Spendry int *a_runp;
145665963Spendry } */ *ap;
145765963Spendry {
145865963Spendry int error;
145969447Smckusick struct proc *p = curproc; /* XXX */
146065963Spendry struct vnode *vp = OTHERVP(ap->a_vp);
146166051Spendry int dolock = (vp == LOWERVP(ap->a_vp));
146265963Spendry
146366051Spendry if (dolock)
146469447Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
146566152Spendry else
146669447Smckusick FIXUP(VTOUNION(ap->a_vp), p);
146769590Smckusick ap->a_vp = vp;
146869590Smckusick error = VCALL(vp, VOFFSET(vop_bmap), ap);
146966051Spendry if (dolock)
147069447Smckusick VOP_UNLOCK(vp, 0, p);
147165963Spendry
147265963Spendry return (error);
147365963Spendry }
147465963Spendry
147565963Spendry int
union_print(ap)147665935Spendry union_print(ap)
147765935Spendry struct vop_print_args /* {
147865935Spendry struct vnode *a_vp;
147965935Spendry } */ *ap;
148065935Spendry {
148165935Spendry struct vnode *vp = ap->a_vp;
148265935Spendry
148365935Spendry printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n",
148465935Spendry vp, UPPERVP(vp), LOWERVP(vp));
148568590Spendry if (UPPERVP(vp) != NULLVP)
148668590Spendry vprint("union: upper", UPPERVP(vp));
148768590Spendry if (LOWERVP(vp) != NULLVP)
148868590Spendry vprint("union: lower", LOWERVP(vp));
148968590Spendry
149065935Spendry return (0);
149165935Spendry }
149265935Spendry
149365963Spendry int
union_islocked(ap)149465963Spendry union_islocked(ap)
149565963Spendry struct vop_islocked_args /* {
149665963Spendry struct vnode *a_vp;
149765963Spendry } */ *ap;
149865963Spendry {
149965935Spendry
150065963Spendry return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0);
150165963Spendry }
150265963Spendry
150365935Spendry int
union_pathconf(ap)150465963Spendry union_pathconf(ap)
150565963Spendry struct vop_pathconf_args /* {
150665963Spendry struct vnode *a_vp;
150765963Spendry int a_name;
150865963Spendry int *a_retval;
150965935Spendry } */ *ap;
151065935Spendry {
151165935Spendry int error;
151269447Smckusick struct proc *p = curproc; /* XXX */
151365963Spendry struct vnode *vp = OTHERVP(ap->a_vp);
151466051Spendry int dolock = (vp == LOWERVP(ap->a_vp));
151565935Spendry
151666051Spendry if (dolock)
151769447Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
151866152Spendry else
151969447Smckusick FIXUP(VTOUNION(ap->a_vp), p);
152069590Smckusick ap->a_vp = vp;
152169590Smckusick error = VCALL(vp, VOFFSET(vop_pathconf), ap);
152266051Spendry if (dolock)
152369447Smckusick VOP_UNLOCK(vp, 0, p);
152465935Spendry
152565963Spendry return (error);
152665963Spendry }
152765935Spendry
152865963Spendry int
union_advlock(ap)152965963Spendry union_advlock(ap)
153065963Spendry struct vop_advlock_args /* {
153165963Spendry struct vnode *a_vp;
153265963Spendry caddr_t a_id;
153365963Spendry int a_op;
153465963Spendry struct flock *a_fl;
153565963Spendry int a_flags;
153665963Spendry } */ *ap;
153765963Spendry {
153869590Smckusick register struct vnode *ovp = OTHERVP(ap->a_vp);
153965935Spendry
154069590Smckusick ap->a_vp = ovp;
154169590Smckusick return (VCALL(ovp, VOFFSET(vop_advlock), ap));
154265935Spendry }
154365935Spendry
154465935Spendry
154565935Spendry /*
154665963Spendry * XXX - vop_strategy must be hand coded because it has no
154765935Spendry * vnode in its arguments.
154865935Spendry * This goes away with a merged VM/buffer cache.
154965935Spendry */
155065935Spendry int
union_strategy(ap)155165963Spendry union_strategy(ap)
155265963Spendry struct vop_strategy_args /* {
155365935Spendry struct buf *a_bp;
155465935Spendry } */ *ap;
155565935Spendry {
155665935Spendry struct buf *bp = ap->a_bp;
155765935Spendry int error;
155865935Spendry struct vnode *savedvp;
155965935Spendry
156065935Spendry savedvp = bp->b_vp;
156165963Spendry bp->b_vp = OTHERVP(bp->b_vp);
156265935Spendry
156365935Spendry #ifdef DIAGNOSTIC
156465997Spendry if (bp->b_vp == NULLVP)
156565963Spendry panic("union_strategy: nil vp");
156665963Spendry if (((bp->b_flags & B_READ) == 0) &&
156765963Spendry (bp->b_vp == LOWERVP(savedvp)))
156865963Spendry panic("union_strategy: writing to lowervp");
156965935Spendry #endif
157065935Spendry
157165963Spendry error = VOP_STRATEGY(bp);
157265935Spendry bp->b_vp = savedvp;
157365935Spendry
157465935Spendry return (error);
157565935Spendry }
157665935Spendry
157765935Spendry /*
157865935Spendry * Global vfs data structures
157965935Spendry */
158065935Spendry int (**union_vnodeop_p)();
158165965Spendry struct vnodeopv_entry_desc union_vnodeop_entries[] = {
158265963Spendry { &vop_default_desc, vn_default_error },
158365963Spendry { &vop_lookup_desc, union_lookup }, /* lookup */
158465963Spendry { &vop_create_desc, union_create }, /* create */
158567575Spendry { &vop_whiteout_desc, union_whiteout }, /* whiteout */
158665963Spendry { &vop_mknod_desc, union_mknod }, /* mknod */
158765963Spendry { &vop_open_desc, union_open }, /* open */
158865963Spendry { &vop_close_desc, union_close }, /* close */
158965963Spendry { &vop_access_desc, union_access }, /* access */
159065963Spendry { &vop_getattr_desc, union_getattr }, /* getattr */
159165963Spendry { &vop_setattr_desc, union_setattr }, /* setattr */
159265963Spendry { &vop_read_desc, union_read }, /* read */
159365963Spendry { &vop_write_desc, union_write }, /* write */
159467751Spendry { &vop_lease_desc, union_lease }, /* lease */
159565963Spendry { &vop_ioctl_desc, union_ioctl }, /* ioctl */
159665963Spendry { &vop_select_desc, union_select }, /* select */
159769389Spendry { &vop_revoke_desc, union_revoke }, /* revoke */
159865963Spendry { &vop_mmap_desc, union_mmap }, /* mmap */
159965963Spendry { &vop_fsync_desc, union_fsync }, /* fsync */
160065963Spendry { &vop_seek_desc, union_seek }, /* seek */
160165963Spendry { &vop_remove_desc, union_remove }, /* remove */
160265963Spendry { &vop_link_desc, union_link }, /* link */
160365963Spendry { &vop_rename_desc, union_rename }, /* rename */
160465963Spendry { &vop_mkdir_desc, union_mkdir }, /* mkdir */
160565963Spendry { &vop_rmdir_desc, union_rmdir }, /* rmdir */
160665963Spendry { &vop_symlink_desc, union_symlink }, /* symlink */
160765963Spendry { &vop_readdir_desc, union_readdir }, /* readdir */
160865963Spendry { &vop_readlink_desc, union_readlink }, /* readlink */
160965963Spendry { &vop_abortop_desc, union_abortop }, /* abortop */
161065963Spendry { &vop_inactive_desc, union_inactive }, /* inactive */
161165963Spendry { &vop_reclaim_desc, union_reclaim }, /* reclaim */
161265963Spendry { &vop_lock_desc, union_lock }, /* lock */
161365963Spendry { &vop_unlock_desc, union_unlock }, /* unlock */
161465963Spendry { &vop_bmap_desc, union_bmap }, /* bmap */
161565963Spendry { &vop_strategy_desc, union_strategy }, /* strategy */
161665963Spendry { &vop_print_desc, union_print }, /* print */
161765963Spendry { &vop_islocked_desc, union_islocked }, /* islocked */
161865963Spendry { &vop_pathconf_desc, union_pathconf }, /* pathconf */
161965963Spendry { &vop_advlock_desc, union_advlock }, /* advlock */
162065963Spendry #ifdef notdef
162165963Spendry { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */
162265963Spendry { &vop_valloc_desc, union_valloc }, /* valloc */
162365963Spendry { &vop_vfree_desc, union_vfree }, /* vfree */
162465963Spendry { &vop_truncate_desc, union_truncate }, /* truncate */
162565963Spendry { &vop_update_desc, union_update }, /* update */
162665963Spendry { &vop_bwrite_desc, union_bwrite }, /* bwrite */
162765963Spendry #endif
162865935Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL }
162965935Spendry };
163065935Spendry struct vnodeopv_desc union_vnodeop_opv_desc =
163165935Spendry { &union_vnodeop_p, union_vnodeop_entries };
1632