165935Spendry /* 265935Spendry * Copyright (c) 1992, 1993, 1994 The Regents of the University of California. 365935Spendry * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry. 465935Spendry * 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*65994Spendry * @(#)union_vnops.c 1.5 (Berkeley) 02/03/94 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/filedesc.h> 1965935Spendry #include <sys/time.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> 2665935Spendry #include "union.h" 2765935Spendry 2865965Spendry /* 2965965Spendry * Create a shadow directory in the upper layer. 3065965Spendry * The new vnode is returned locked. 3165965Spendry */ 3265935Spendry static int 3365935Spendry union_mkshadow(dvp, cnp, vpp) 3465935Spendry struct vnode *dvp; 3565935Spendry struct componentname *cnp; 3665935Spendry struct vnode *vpp; 3765935Spendry { 3865935Spendry int error; 3965935Spendry struct vattr va; 4065935Spendry struct proc *p = cnp->cn_proc; 41*65994Spendry struct componentname cn; 4265935Spendry 4365935Spendry /* 4465935Spendry * policy: when creating the shadow directory in the 4565935Spendry * upper layer, create it owned by the current user, 4665935Spendry * group from parent directory, and mode 777 modified 4765935Spendry * by umask (ie mostly identical to the mkdir syscall). 4865935Spendry * (jsp, kb) 4965935Spendry * TODO: create the directory owned by the user who 5065935Spendry * did the mount (um->um_cred). 5165935Spendry */ 5265935Spendry 53*65994Spendry /* 54*65994Spendry * A new componentname structure must be faked up because 55*65994Spendry * there is no way to know where the upper level cnp came 56*65994Spendry * from or what it is being used for. This must duplicate 57*65994Spendry * some of the work done by NDINIT, some of the work done 58*65994Spendry * by namei, some of the work done by lookup and some of 59*65994Spendry * the work done by VOP_LOOKUP when given a CREATE flag. 60*65994Spendry * Conclusion: Horrible. 61*65994Spendry * 62*65994Spendry * The pathname buffer will be FREEed by VOP_MKDIR. 63*65994Spendry */ 64*65994Spendry cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK); 65*65994Spendry bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen+1); 66*65994Spendry 67*65994Spendry cn.cn_nameiop = CREATE; 68*65994Spendry cn.cn_flags = HASBUF | SAVENAME | ISLASTCN; 69*65994Spendry cn.cn_proc = cnp->cn_proc; 70*65994Spendry cn.cn_cred = cnp->cn_cred; 71*65994Spendry cn.cn_nameptr = cn.cn_pnbuf; 72*65994Spendry cn.cn_namelen = cnp->cn_namelen; 73*65994Spendry cn.cn_hash = cnp->cn_hash; 74*65994Spendry cn.cn_consume = cnp->cn_consume; 75*65994Spendry 7665935Spendry VATTR_NULL(&va); 7765935Spendry va.va_type = VDIR; 7865935Spendry va.va_mode = UN_DIRMODE &~ p->p_fd->fd_cmask; 79*65994Spendry 80*65994Spendry /* LEASE_CHECK: dvp is locked */ 8165935Spendry LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE); 82*65994Spendry 8365965Spendry VREF(dvp); 84*65994Spendry error = VOP_MKDIR(dvp, vpp, &cn, &va); 8565935Spendry VOP_LOCK(dvp); 8665935Spendry return (error); 8765935Spendry } 8865935Spendry 8965935Spendry static int 9065989Spendry union_lookup1(udvp, dvp, vpp, cnp) 9165989Spendry struct vnode *udvp; 9265935Spendry struct vnode *dvp; 9365935Spendry struct vnode **vpp; 9465935Spendry struct componentname *cnp; 9565935Spendry { 9665935Spendry int error; 9765935Spendry struct vnode *tdvp; 9865935Spendry struct mount *mp; 9965935Spendry 100*65994Spendry /* 101*65994Spendry * If stepping up the directory tree, check for going 102*65994Spendry * back across the mount point, in which case do what 103*65994Spendry * lookup would do by stepping back down the mount 104*65994Spendry * hierarchy. 105*65994Spendry */ 10665935Spendry if (cnp->cn_flags & ISDOTDOT) { 10765935Spendry for (;;) { 10865935Spendry if ((dvp->v_flag & VROOT) == 0 || 10965935Spendry (cnp->cn_flags & NOCROSSMOUNT)) 11065935Spendry break; 11165935Spendry 11265935Spendry tdvp = dvp; 11365935Spendry dvp = dvp->v_mount->mnt_vnodecovered; 11465935Spendry vput(tdvp); 11565935Spendry VREF(dvp); 11665935Spendry VOP_LOCK(dvp); 11765935Spendry } 11865935Spendry } 11965935Spendry 12065935Spendry error = VOP_LOOKUP(dvp, &tdvp, cnp); 12165935Spendry if (error) 12265935Spendry return (error); 12365935Spendry 124*65994Spendry /* 125*65994Spendry * If going back up the directory tree, then the parent directory 126*65994Spendry * will have been unlocked, unless lookup found the last 127*65994Spendry * component. In which case, re-lock the node here to allow 128*65994Spendry * it to be unlocked again (phew) in union_lookup. 129*65994Spendry */ 130*65994Spendry if ((cnp->cn_flags & ISDOTDOT) && !(cnp->cn_flags & ISLASTCN)) 131*65994Spendry VOP_LOCK(dvp); 132*65994Spendry 13365935Spendry dvp = tdvp; 134*65994Spendry 135*65994Spendry /* 136*65994Spendry * Lastly check if the current node is a mount point in 137*65994Spendry * which cse walk up the mount hierarchy making sure not to 138*65994Spendry * bump into the root of the mount tree (ie. dvp != udvp). 139*65994Spendry */ 14065989Spendry while (dvp != udvp && (dvp->v_type == VDIR) && 14165989Spendry (mp = dvp->v_mountedhere) && 14265935Spendry (cnp->cn_flags & NOCROSSMOUNT) == 0) { 14365935Spendry 14465935Spendry if (mp->mnt_flag & MNT_MLOCK) { 14565935Spendry mp->mnt_flag |= MNT_MWAIT; 14665935Spendry sleep((caddr_t) mp, PVFS); 14765935Spendry continue; 14865935Spendry } 14965935Spendry 15065935Spendry if (error = VFS_ROOT(mp, &tdvp)) { 15165935Spendry vput(dvp); 15265935Spendry return (error); 15365935Spendry } 15465935Spendry 15565965Spendry vput(dvp); 15665935Spendry dvp = tdvp; 15765935Spendry } 15865935Spendry 15965935Spendry *vpp = dvp; 16065935Spendry return (0); 16165935Spendry } 16265935Spendry 16365935Spendry int 16465935Spendry union_lookup(ap) 16565935Spendry struct vop_lookup_args /* { 16665935Spendry struct vnodeop_desc *a_desc; 16765935Spendry struct vnode *a_dvp; 16865935Spendry struct vnode **a_vpp; 16965935Spendry struct componentname *a_cnp; 17065935Spendry } */ *ap; 17165935Spendry { 17265965Spendry int error; 17365935Spendry int uerror, lerror; 17465935Spendry struct vnode *uppervp, *lowervp; 17565935Spendry struct vnode *upperdvp, *lowerdvp; 17665935Spendry struct vnode *dvp = ap->a_dvp; 17765989Spendry struct union_node *dun = VTOUNION(dvp); 17865935Spendry struct componentname *cnp = ap->a_cnp; 17965935Spendry int lockparent = cnp->cn_flags & LOCKPARENT; 180*65994Spendry int rdonly = cnp->cn_flags & RDONLY; 18165935Spendry 18265965Spendry cnp->cn_flags |= LOCKPARENT; 18365965Spendry 18465935Spendry upperdvp = dun->un_uppervp; 18565935Spendry lowerdvp = dun->un_lowervp; 18665965Spendry uppervp = 0; 18765965Spendry lowervp = 0; 18865935Spendry 18965935Spendry /* 19065935Spendry * do the lookup in the upper level. 19165935Spendry * if that level comsumes additional pathnames, 19265935Spendry * then assume that something special is going 19365935Spendry * on and just return that vnode. 19465935Spendry */ 19565935Spendry if (upperdvp) { 19665965Spendry VOP_LOCK(upperdvp); 19765989Spendry uerror = union_lookup1( 19865989Spendry MOUNTTOUNIONMOUNT(dvp->v_mount)->um_uppervp, 19965989Spendry upperdvp, &uppervp, cnp); 20065989Spendry if (uppervp != upperdvp) 20165989Spendry VOP_UNLOCK(upperdvp); 20265965Spendry 20365935Spendry if (cnp->cn_consume != 0) { 20465935Spendry *ap->a_vpp = uppervp; 20565965Spendry if (!lockparent) 20665965Spendry cnp->cn_flags &= ~LOCKPARENT; 20765935Spendry return (uerror); 20865935Spendry } 20965935Spendry } else { 21065935Spendry uerror = ENOENT; 21165935Spendry } 21265935Spendry 21365935Spendry /* 21465935Spendry * in a similar way to the upper layer, do the lookup 21565935Spendry * in the lower layer. this time, if there is some 21665935Spendry * component magic going on, then vput whatever we got 21765935Spendry * back from the upper layer and return the lower vnode 21865935Spendry * instead. 21965935Spendry */ 22065935Spendry if (lowerdvp) { 22165965Spendry VOP_LOCK(lowerdvp); 22265989Spendry lerror = union_lookup1( 22365989Spendry MOUNTTOUNIONMOUNT(dvp->v_mount)->um_lowervp, 22465989Spendry lowerdvp, &lowervp, cnp); 22565989Spendry if (lowervp != lowerdvp) 22665989Spendry VOP_UNLOCK(lowerdvp); 22765965Spendry 22865935Spendry if (cnp->cn_consume != 0) { 22965935Spendry if (uppervp) { 23065935Spendry vput(uppervp); 23165935Spendry uppervp = 0; 23265935Spendry } 23365935Spendry *ap->a_vpp = lowervp; 23465965Spendry if (!lockparent) 23565965Spendry cnp->cn_flags &= ~LOCKPARENT; 23665935Spendry return (lerror); 23765935Spendry } 23865935Spendry } else { 23965935Spendry lerror = ENOENT; 24065935Spendry } 24165935Spendry 24265965Spendry if (!lockparent) 24365965Spendry cnp->cn_flags &= ~LOCKPARENT; 24465965Spendry 24565935Spendry /* 24665935Spendry * at this point, we have uerror and lerror indicating 24765935Spendry * possible errors with the lookups in the upper and lower 24865935Spendry * layers. additionally, uppervp and lowervp are (locked) 24965935Spendry * references to existing vnodes in the upper and lower layers. 25065935Spendry * 25165935Spendry * there are now three cases to consider. 25265935Spendry * 1. if both layers returned an error, then return whatever 25365935Spendry * error the upper layer generated. 25465935Spendry * 25565935Spendry * 2. if the top layer failed and the bottom layer succeeded 25665935Spendry * then two subcases occur. 25765935Spendry * a. the bottom vnode is not a directory, in which 25865935Spendry * case just return a new union vnode referencing 25965935Spendry * an empty top layer and the existing bottom layer. 26065935Spendry * b. the bottom vnode is a directory, in which case 26165935Spendry * create a new directory in the top-level and 26265935Spendry * continue as in case 3. 26365935Spendry * 26465935Spendry * 3. if the top layer succeeded then return a new union 26565935Spendry * vnode referencing whatever the new top layer and 26665935Spendry * whatever the bottom layer returned. 26765935Spendry */ 26865935Spendry 26965935Spendry /* case 1. */ 27065935Spendry if ((uerror != 0) && (lerror != 0)) { 27165935Spendry *ap->a_vpp = 0; 27265935Spendry return (uerror); 27365935Spendry } 27465935Spendry 27565935Spendry /* case 2. */ 27665935Spendry if (uerror != 0 /* && (lerror == 0) */ ) { 27765935Spendry if (lowervp->v_type == VDIR) { /* case 2b. */ 278*65994Spendry VOP_LOCK(upperdvp); 27965935Spendry uerror = union_mkshadow(upperdvp, cnp, &uppervp); 28065989Spendry if (uppervp != upperdvp) 28165989Spendry VOP_UNLOCK(upperdvp); 28265935Spendry if (uerror) { 28365935Spendry if (lowervp) { 28465935Spendry vput(lowervp); 28565935Spendry lowervp = 0; 28665935Spendry } 28765935Spendry return (uerror); 28865935Spendry } 28965935Spendry } 29065935Spendry } 29165935Spendry 29265989Spendry error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp, 29365965Spendry uppervp, lowervp); 29465965Spendry 29565965Spendry if (uppervp) 29665965Spendry VOP_UNLOCK(uppervp); 29765965Spendry if (lowervp) 29865965Spendry VOP_UNLOCK(lowervp); 29965965Spendry 30065965Spendry if (error) { 30165965Spendry if (uppervp) 30265965Spendry vrele(uppervp); 30365965Spendry if (lowervp) 30465965Spendry vrele(lowervp); 30565965Spendry } else { 306*65994Spendry if (*ap->a_vpp != dvp) 307*65994Spendry if (!lockparent || !(cnp->cn_flags & ISLASTCN)) 308*65994Spendry VOP_UNLOCK(dvp); 30965965Spendry } 31065965Spendry 31165965Spendry return (error); 31265935Spendry } 31365935Spendry 31465963Spendry int 31565963Spendry union_create(ap) 31665963Spendry struct vop_create_args /* { 31765963Spendry struct vnode *a_dvp; 31865963Spendry struct vnode **a_vpp; 31965963Spendry struct componentname *a_cnp; 32065963Spendry struct vattr *a_vap; 32165963Spendry } */ *ap; 32265963Spendry { 32365963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 32465963Spendry struct vnode *dvp = un->un_uppervp; 32565963Spendry 32665963Spendry if (dvp) { 32765963Spendry int error; 32865963Spendry struct vnode *vp; 32965963Spendry 33065963Spendry VREF(dvp); 33165963Spendry VOP_LOCK(dvp); 33265963Spendry vput(ap->a_dvp); 33365963Spendry error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap); 33465963Spendry if (error) 33565963Spendry return (error); 33665963Spendry 33765963Spendry error = union_allocvp( 33865963Spendry ap->a_vpp, 33965989Spendry ap->a_dvp->v_mount, 34065989Spendry ap->a_dvp, 34165965Spendry NULLVP, 34265963Spendry ap->a_cnp, 34365963Spendry vp, 34465963Spendry NULLVP); 34565965Spendry VOP_UNLOCK(vp); 34665965Spendry if (error) 34765965Spendry vrele(vp); 34865963Spendry return (error); 34965963Spendry } 35065963Spendry 35165963Spendry vput(ap->a_dvp); 35265963Spendry return (EROFS); 35365963Spendry } 35465963Spendry 35565963Spendry int 35665963Spendry union_mknod(ap) 35765963Spendry struct vop_mknod_args /* { 35865963Spendry struct vnode *a_dvp; 35965963Spendry struct vnode **a_vpp; 36065963Spendry struct componentname *a_cnp; 36165963Spendry struct vattr *a_vap; 36265963Spendry } */ *ap; 36365963Spendry { 36465963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 36565963Spendry struct vnode *dvp = un->un_uppervp; 36665963Spendry 36765963Spendry if (dvp) { 36865963Spendry int error; 36965963Spendry struct vnode *vp; 37065963Spendry 37165963Spendry VREF(dvp); 37265963Spendry VOP_LOCK(dvp); 37365963Spendry vput(ap->a_dvp); 37465963Spendry error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap); 37565963Spendry if (error) 37665963Spendry return (error); 37765963Spendry 37865965Spendry if (vp) { 37965965Spendry error = union_allocvp( 38065965Spendry ap->a_vpp, 38165989Spendry ap->a_dvp->v_mount, 38265989Spendry ap->a_dvp, 38365965Spendry NULLVP, 38465965Spendry ap->a_cnp, 38565965Spendry vp, 38665965Spendry NULLVP); 38765965Spendry VOP_UNLOCK(vp); 38865965Spendry if (error) 38965965Spendry vrele(vp); 39065965Spendry } 39165963Spendry return (error); 39265963Spendry } 39365963Spendry 39465963Spendry vput(ap->a_dvp); 39565963Spendry return (EROFS); 39665963Spendry } 39765963Spendry 39865935Spendry int 39965935Spendry union_open(ap) 40065935Spendry struct vop_open_args /* { 40165935Spendry struct vnodeop_desc *a_desc; 40265935Spendry struct vnode *a_vp; 40365935Spendry int a_mode; 40465935Spendry struct ucred *a_cred; 40565935Spendry struct proc *a_p; 40665935Spendry } */ *ap; 40765935Spendry { 40865935Spendry struct union_node *un = VTOUNION(ap->a_vp); 40965965Spendry struct vnode *tvp; 41065935Spendry int mode = ap->a_mode; 41165935Spendry struct ucred *cred = ap->a_cred; 41265935Spendry struct proc *p = ap->a_p; 41365965Spendry int error; 41465935Spendry 41565935Spendry /* 41665935Spendry * If there is an existing upper vp then simply open that. 41765935Spendry */ 41865965Spendry tvp = un->un_uppervp; 41965965Spendry if (tvp == NULLVP) { 42065935Spendry /* 42165965Spendry * If the lower vnode is being opened for writing, then 42265965Spendry * copy the file contents to the upper vnode and open that, 42365965Spendry * otherwise can simply open the lower vnode. 42465935Spendry */ 42565965Spendry tvp = un->un_lowervp; 42665965Spendry if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { 42765965Spendry struct nameidata nd; 42865965Spendry struct filedesc *fdp = p->p_fd; 429*65994Spendry struct vnode *vp; 430*65994Spendry /*int fmode;*/ 43165965Spendry int cmode; 43265963Spendry 43365965Spendry /* 43465965Spendry * Open the named file in the upper layer. Note that 43565965Spendry * the file may have come into existence *since* the 43665965Spendry * lookup was done, since the upper layer may really 43765965Spendry * be a loopback mount of some other filesystem... 43865965Spendry * so open the file with exclusive create and barf if 43965965Spendry * it already exists. 44065965Spendry * XXX - perhaps shoudl re-lookup the node (once more 44165965Spendry * with feeling) and simply open that. Who knows. 44265965Spendry */ 443*65994Spendry /* 44465965Spendry NDINIT(&nd, CREATE, 0, UIO_SYSSPACE, un->un_path, p); 44565965Spendry fmode = (O_CREAT|O_TRUNC|O_EXCL); 446*65994Spendry */ 44765965Spendry cmode = UN_FILEMODE & ~fdp->fd_cmask; 448*65994Spendry error = union_vn_create(&vp, un, cmode, p); 44965965Spendry if (error) 45065965Spendry return (error); 451*65994Spendry un->un_uppervp = vp; /* XXX */ 45265965Spendry /* at this point, uppervp is locked */ 45365965Spendry 45465965Spendry /* 45565965Spendry * Now, if the file is being opened with truncation, 45665965Spendry * then the (new) upper vnode is ready to fly, 45765965Spendry * otherwise the data from the lower vnode must be 45865965Spendry * copied to the upper layer first. This only works 45965965Spendry * for regular files (check is made above). 46065965Spendry */ 46165965Spendry if ((mode & O_TRUNC) == 0) { 46265965Spendry /* 46365965Spendry * XXX - should not ignore errors 46465965Spendry * from VOP_CLOSE 46565965Spendry */ 466*65994Spendry VOP_LOCK(tvp); 46765965Spendry error = VOP_OPEN(tvp, FREAD, cred, p); 46865965Spendry if (error == 0) { 46965965Spendry error = union_copyfile(p, cred, 47065965Spendry tvp, un->un_uppervp); 47165965Spendry VOP_UNLOCK(tvp); 47265965Spendry (void) VOP_CLOSE(tvp, FREAD); 47365965Spendry } else { 47465965Spendry VOP_UNLOCK(tvp); 47565965Spendry } 47665965Spendry VOP_UNLOCK(un->un_uppervp); 47765965Spendry (void) VOP_CLOSE(un->un_uppervp, FWRITE); 47865965Spendry VOP_LOCK(un->un_uppervp); 47965935Spendry } 48065965Spendry if (error == 0) 48165965Spendry error = VOP_OPEN(un->un_uppervp, mode, cred, p); 48265963Spendry VOP_UNLOCK(un->un_uppervp); 48365965Spendry return (error); 48465935Spendry } 48565935Spendry } 48665935Spendry 48765965Spendry VOP_LOCK(tvp); 48865965Spendry error = VOP_OPEN(tvp, mode, cred, p); 48965965Spendry VOP_UNLOCK(tvp); 49065965Spendry 49165965Spendry return (error); 49265935Spendry } 49365935Spendry 49465963Spendry int 49565963Spendry union_close(ap) 49665963Spendry struct vop_close_args /* { 49765963Spendry struct vnode *a_vp; 49865963Spendry int a_fflag; 49965963Spendry struct ucred *a_cred; 50065963Spendry struct proc *a_p; 50165963Spendry } */ *ap; 50265963Spendry { 50365963Spendry 50465963Spendry return (VOP_CLOSE(OTHERVP(ap->a_vp), ap->a_fflag, ap->a_cred, ap->a_p)); 50565963Spendry } 50665963Spendry 50765935Spendry /* 50865963Spendry * Check access permission on the union vnode. 50965963Spendry * The access check being enforced is to check 51065963Spendry * against both the underlying vnode, and any 51165963Spendry * copied vnode. This ensures that no additional 51265963Spendry * file permissions are given away simply because 51365963Spendry * the user caused an implicit file copy. 51465963Spendry */ 51565963Spendry int 51665963Spendry union_access(ap) 51765963Spendry struct vop_access_args /* { 51865963Spendry struct vnodeop_desc *a_desc; 51965963Spendry struct vnode *a_vp; 52065963Spendry int a_mode; 52165963Spendry struct ucred *a_cred; 52265963Spendry struct proc *a_p; 52365963Spendry } */ *ap; 52465963Spendry { 52565963Spendry struct union_node *un = VTOUNION(ap->a_vp); 52665965Spendry int error = 0; 52765963Spendry struct vnode *vp; 52865963Spendry 52965963Spendry if (vp = un->un_lowervp) { 53065965Spendry VOP_LOCK(vp); 53165963Spendry error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); 53265965Spendry VOP_UNLOCK(vp); 53365963Spendry if (error) 53465963Spendry return (error); 53565963Spendry } 53665963Spendry 53765965Spendry if (vp = un->un_uppervp) { 53865965Spendry VOP_LOCK(vp); 53965965Spendry error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); 54065965Spendry VOP_UNLOCK(vp); 54165965Spendry } 54265965Spendry 54365965Spendry return (error); 54465963Spendry } 54565963Spendry 54665963Spendry /* 54765935Spendry * We handle getattr only to change the fsid. 54865935Spendry */ 54965935Spendry int 55065935Spendry union_getattr(ap) 55165935Spendry struct vop_getattr_args /* { 55265935Spendry struct vnode *a_vp; 55365935Spendry struct vattr *a_vap; 55465935Spendry struct ucred *a_cred; 55565935Spendry struct proc *a_p; 55665935Spendry } */ *ap; 55765935Spendry { 55865935Spendry int error; 55965965Spendry struct vnode *vp = OTHERVP(ap->a_vp); 56065935Spendry 56165965Spendry VOP_LOCK(vp); 56265965Spendry error = VOP_GETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p); 56365965Spendry VOP_UNLOCK(vp); 56465965Spendry 56565935Spendry /* Requires that arguments be restored. */ 56665935Spendry ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 56765935Spendry return (0); 56865935Spendry } 56965935Spendry 57065963Spendry int 57165965Spendry union_setattr(ap) 57265963Spendry struct vop_setattr_args /* { 57365963Spendry struct vnode *a_vp; 57465963Spendry struct vattr *a_vap; 57565963Spendry struct ucred *a_cred; 57665963Spendry struct proc *a_p; 57765963Spendry } */ *ap; 57865963Spendry { 57965963Spendry struct union_node *un = VTOUNION(ap->a_vp); 58065963Spendry int error; 58165963Spendry 58265963Spendry if (un->un_uppervp) { 58365963Spendry VOP_LOCK(un->un_uppervp); 58465963Spendry error = VOP_SETATTR(un->un_uppervp, ap->a_vap, 58565963Spendry ap->a_cred, ap->a_p); 58665963Spendry VOP_UNLOCK(un->un_uppervp); 58765963Spendry } else { 58865963Spendry /* 58965963Spendry * XXX should do a copyfile (perhaps only if 59065963Spendry * the file permission change, which would not 59165963Spendry * track va_ctime correctly). 59265963Spendry */ 59365963Spendry error = EROFS; 59465963Spendry } 59565963Spendry 59665963Spendry return (error); 59765963Spendry } 59865963Spendry 59965963Spendry int 60065963Spendry union_read(ap) 60165963Spendry struct vop_read_args /* { 60265963Spendry struct vnode *a_vp; 60365963Spendry struct uio *a_uio; 60465963Spendry int a_ioflag; 60565963Spendry struct ucred *a_cred; 60665963Spendry } */ *ap; 60765963Spendry { 60865963Spendry int error; 60965963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 61065963Spendry 61165965Spendry VOP_LOCK(vp); 61265963Spendry error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 61365965Spendry VOP_UNLOCK(vp); 61465963Spendry 61565963Spendry return (error); 61665963Spendry } 61765963Spendry 61865963Spendry int 61965963Spendry union_write(ap) 62065963Spendry struct vop_read_args /* { 62165963Spendry struct vnode *a_vp; 62265963Spendry struct uio *a_uio; 62365963Spendry int a_ioflag; 62465963Spendry struct ucred *a_cred; 62565963Spendry } */ *ap; 62665963Spendry { 62765963Spendry int error; 62865963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 62965963Spendry 63065963Spendry VOP_LOCK(vp); 63165963Spendry error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 63265963Spendry VOP_UNLOCK(vp); 63365963Spendry 63465963Spendry return (error); 63565963Spendry } 63665963Spendry 63765963Spendry int 63865963Spendry union_ioctl(ap) 63965963Spendry struct vop_ioctl_args /* { 64065963Spendry struct vnode *a_vp; 64165963Spendry int a_command; 64265963Spendry caddr_t a_data; 64365963Spendry int a_fflag; 64465963Spendry struct ucred *a_cred; 64565963Spendry struct proc *a_p; 64665963Spendry } */ *ap; 64765963Spendry { 64865963Spendry 64965963Spendry return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data, 65065963Spendry ap->a_fflag, ap->a_cred, ap->a_p)); 65165963Spendry } 65265963Spendry 65365963Spendry int 65465963Spendry union_select(ap) 65565963Spendry struct vop_select_args /* { 65665963Spendry struct vnode *a_vp; 65765963Spendry int a_which; 65865963Spendry int a_fflags; 65965963Spendry struct ucred *a_cred; 66065963Spendry struct proc *a_p; 66165963Spendry } */ *ap; 66265963Spendry { 66365963Spendry 66465963Spendry return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags, 66565963Spendry ap->a_cred, ap->a_p)); 66665963Spendry } 66765963Spendry 66865963Spendry int 66965963Spendry union_mmap(ap) 67065963Spendry struct vop_mmap_args /* { 67165963Spendry struct vnode *a_vp; 67265963Spendry int a_fflags; 67365963Spendry struct ucred *a_cred; 67465963Spendry struct proc *a_p; 67565963Spendry } */ *ap; 67665963Spendry { 67765963Spendry 67865963Spendry return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags, 67965963Spendry ap->a_cred, ap->a_p)); 68065963Spendry } 68165963Spendry 68265963Spendry int 68365963Spendry union_fsync(ap) 68465963Spendry struct vop_fsync_args /* { 68565963Spendry struct vnode *a_vp; 68665963Spendry struct ucred *a_cred; 68765963Spendry int a_waitfor; 68865963Spendry struct proc *a_p; 68965963Spendry } */ *ap; 69065963Spendry { 69165963Spendry int error = 0; 69265963Spendry struct vnode *targetvp = OTHERVP(ap->a_vp); 69365963Spendry 69465963Spendry if (targetvp) { 69565963Spendry VOP_LOCK(targetvp); 69665963Spendry error = VOP_FSYNC(targetvp, ap->a_cred, 69765963Spendry ap->a_waitfor, ap->a_p); 69865963Spendry VOP_UNLOCK(targetvp); 69965963Spendry } 70065963Spendry 70165963Spendry return (error); 70265963Spendry } 70365963Spendry 70465963Spendry int 70565963Spendry union_seek(ap) 70665963Spendry struct vop_seek_args /* { 70765963Spendry struct vnode *a_vp; 70865963Spendry off_t a_oldoff; 70965963Spendry off_t a_newoff; 71065963Spendry struct ucred *a_cred; 71165963Spendry } */ *ap; 71265963Spendry { 71365963Spendry 71465963Spendry return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred)); 71565963Spendry } 71665963Spendry 71765963Spendry int 71865963Spendry union_remove(ap) 71965963Spendry struct vop_remove_args /* { 72065963Spendry struct vnode *a_dvp; 72165963Spendry struct vnode *a_vp; 72265963Spendry struct componentname *a_cnp; 72365963Spendry } */ *ap; 72465963Spendry { 72565963Spendry int error; 72665963Spendry struct union_node *dun = VTOUNION(ap->a_dvp); 72765963Spendry struct union_node *un = VTOUNION(ap->a_vp); 72865963Spendry 72965963Spendry if (dun->un_uppervp && un->un_uppervp) { 73065963Spendry struct vnode *dvp = dun->un_uppervp; 73165963Spendry struct vnode *vp = un->un_uppervp; 73265963Spendry 73365963Spendry VREF(dvp); 73465963Spendry VOP_LOCK(dvp); 73565963Spendry vput(ap->a_dvp); 73665963Spendry VREF(vp); 73765963Spendry VOP_LOCK(vp); 73865963Spendry vput(ap->a_vp); 73965963Spendry 74065963Spendry error = VOP_REMOVE(dvp, vp, ap->a_cnp); 74165963Spendry } else { 74265963Spendry /* 74365963Spendry * XXX: should create a whiteout here 74465963Spendry */ 74565963Spendry vput(ap->a_dvp); 74665963Spendry vput(ap->a_vp); 74765963Spendry error = EROFS; 74865963Spendry } 74965963Spendry 75065963Spendry return (error); 75165963Spendry } 75265963Spendry 75365963Spendry int 75465963Spendry union_link(ap) 75565963Spendry struct vop_link_args /* { 75665963Spendry struct vnode *a_vp; 75765963Spendry struct vnode *a_tdvp; 75865963Spendry struct componentname *a_cnp; 75965963Spendry } */ *ap; 76065963Spendry { 76165963Spendry int error; 76265963Spendry struct union_node *dun = VTOUNION(ap->a_vp); 76365963Spendry struct union_node *un = VTOUNION(ap->a_tdvp); 76465963Spendry 76565963Spendry if (dun->un_uppervp && un->un_uppervp) { 76665963Spendry struct vnode *dvp = dun->un_uppervp; 76765963Spendry struct vnode *vp = un->un_uppervp; 76865963Spendry 76965963Spendry VREF(dvp); 77065963Spendry VOP_LOCK(dvp); 77165963Spendry vput(ap->a_vp); 77265963Spendry VREF(vp); 77365963Spendry vrele(ap->a_tdvp); 77465963Spendry 77565963Spendry error = VOP_LINK(dvp, vp, ap->a_cnp); 77665963Spendry } else { 77765963Spendry /* 77865963Spendry * XXX: need to copy to upper layer 77965963Spendry * and do the link there. 78065963Spendry */ 78165963Spendry vput(ap->a_vp); 78265963Spendry vrele(ap->a_tdvp); 78365963Spendry error = EROFS; 78465963Spendry } 78565963Spendry 78665963Spendry return (error); 78765963Spendry } 78865963Spendry 78965963Spendry int 79065963Spendry union_rename(ap) 79165963Spendry struct vop_rename_args /* { 79265963Spendry struct vnode *a_fdvp; 79365963Spendry struct vnode *a_fvp; 79465963Spendry struct componentname *a_fcnp; 79565963Spendry struct vnode *a_tdvp; 79665963Spendry struct vnode *a_tvp; 79765963Spendry struct componentname *a_tcnp; 79865963Spendry } */ *ap; 79965963Spendry { 80065963Spendry int error; 80165963Spendry 80265963Spendry struct vnode *fdvp = ap->a_fdvp; 80365963Spendry struct vnode *fvp = ap->a_fvp; 80465963Spendry struct vnode *tdvp = ap->a_tdvp; 80565963Spendry struct vnode *tvp = ap->a_tvp; 80665963Spendry 80765963Spendry if (fdvp->v_op == union_vnodeop_p) { /* always true */ 80865963Spendry struct union_node *un = VTOUNION(fdvp); 80965963Spendry if (un->un_uppervp == 0) { 81065963Spendry error = EROFS; 81165963Spendry goto bad; 81265963Spendry } 81365963Spendry 81465963Spendry fdvp = un->un_uppervp; 81565963Spendry VREF(fdvp); 81665963Spendry vrele(ap->a_fdvp); 81765963Spendry } 81865963Spendry 81965963Spendry if (fvp->v_op == union_vnodeop_p) { /* always true */ 82065963Spendry struct union_node *un = VTOUNION(fvp); 82165963Spendry if (un->un_uppervp == 0) { 82265963Spendry error = EROFS; 82365963Spendry goto bad; 82465963Spendry } 82565963Spendry 82665963Spendry fvp = un->un_uppervp; 82765963Spendry VREF(fvp); 82865963Spendry vrele(ap->a_fvp); 82965963Spendry } 83065963Spendry 83165963Spendry if (tdvp->v_op == union_vnodeop_p) { 83265963Spendry struct union_node *un = VTOUNION(tdvp); 83365963Spendry if (un->un_uppervp == 0) { 83465963Spendry error = EROFS; 83565963Spendry goto bad; 83665963Spendry } 83765963Spendry 83865963Spendry tdvp = un->un_uppervp; 83965963Spendry VREF(tdvp); 84065963Spendry VOP_LOCK(tdvp); 84165963Spendry vput(ap->a_fdvp); 84265963Spendry } 84365963Spendry 84465963Spendry if (tvp && tvp->v_op == union_vnodeop_p) { 84565963Spendry struct union_node *un = VTOUNION(tvp); 84665963Spendry if (un->un_uppervp == 0) { 84765963Spendry error = EROFS; 84865963Spendry goto bad; 84965963Spendry } 85065963Spendry 85165963Spendry tvp = un->un_uppervp; 85265963Spendry VREF(tvp); 85365963Spendry VOP_LOCK(tvp); 85465963Spendry vput(ap->a_tvp); 85565963Spendry } 85665963Spendry 85765963Spendry return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); 85865963Spendry 85965963Spendry bad: 86065963Spendry vrele(fdvp); 86165963Spendry vrele(fvp); 86265963Spendry vput(tdvp); 86365963Spendry if (tvp) 86465963Spendry vput(tvp); 86565963Spendry 86665963Spendry return (error); 86765963Spendry } 86865963Spendry 86965963Spendry int 87065963Spendry union_mkdir(ap) 87165963Spendry struct vop_mkdir_args /* { 87265963Spendry struct vnode *a_dvp; 87365963Spendry struct vnode **a_vpp; 87465963Spendry struct componentname *a_cnp; 87565963Spendry struct vattr *a_vap; 87665963Spendry } */ *ap; 87765963Spendry { 87865963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 87965963Spendry struct vnode *dvp = un->un_uppervp; 88065963Spendry 88165963Spendry if (dvp) { 88265963Spendry int error; 88365963Spendry struct vnode *vp; 88465963Spendry 88565963Spendry VREF(dvp); 88665963Spendry VOP_LOCK(dvp); 88765963Spendry vput(ap->a_dvp); 88865963Spendry error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); 88965963Spendry if (error) 89065963Spendry return (error); 89165963Spendry 89265963Spendry error = union_allocvp( 89365963Spendry ap->a_vpp, 89465989Spendry ap->a_dvp->v_mount, 89565989Spendry ap->a_dvp, 89665965Spendry NULLVP, 89765963Spendry ap->a_cnp, 89865963Spendry vp, 89965963Spendry NULLVP); 90065965Spendry VOP_UNLOCK(vp); 90165965Spendry if (error) 90265965Spendry vrele(vp); 90365963Spendry return (error); 90465963Spendry } 90565963Spendry 90665963Spendry vput(ap->a_dvp); 90765963Spendry return (EROFS); 90865963Spendry } 90965963Spendry 91065963Spendry int 91165963Spendry union_rmdir(ap) 91265963Spendry struct vop_rmdir_args /* { 91365963Spendry struct vnode *a_dvp; 91465963Spendry struct vnode *a_vp; 91565963Spendry struct componentname *a_cnp; 91665963Spendry } */ *ap; 91765963Spendry { 91865963Spendry int error; 91965963Spendry struct union_node *dun = VTOUNION(ap->a_dvp); 92065963Spendry struct union_node *un = VTOUNION(ap->a_vp); 92165963Spendry 92265963Spendry if (dun->un_uppervp && un->un_uppervp) { 92365963Spendry struct vnode *dvp = dun->un_uppervp; 92465963Spendry struct vnode *vp = un->un_uppervp; 92565963Spendry 92665963Spendry VREF(dvp); 92765963Spendry VOP_LOCK(dvp); 92865963Spendry vput(ap->a_dvp); 92965963Spendry VREF(vp); 93065963Spendry VOP_LOCK(vp); 93165963Spendry vput(ap->a_vp); 93265963Spendry 93365963Spendry error = VOP_REMOVE(dvp, vp, ap->a_cnp); 93465963Spendry } else { 93565963Spendry /* 93665963Spendry * XXX: should create a whiteout here 93765963Spendry */ 93865963Spendry vput(ap->a_dvp); 93965963Spendry vput(ap->a_vp); 94065963Spendry error = EROFS; 94165963Spendry } 94265963Spendry 94365963Spendry return (error); 94465963Spendry } 94565963Spendry 94665963Spendry int 94765963Spendry union_symlink(ap) 94865963Spendry struct vop_symlink_args /* { 94965963Spendry struct vnode *a_dvp; 95065963Spendry struct vnode **a_vpp; 95165963Spendry struct componentname *a_cnp; 95265963Spendry struct vattr *a_vap; 95365963Spendry char *a_target; 95465963Spendry } */ *ap; 95565963Spendry { 95665963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 95765963Spendry struct vnode *dvp = un->un_uppervp; 95865963Spendry 95965963Spendry if (dvp) { 96065963Spendry int error; 96165963Spendry struct vnode *vp; 96265963Spendry struct mount *mp = ap->a_dvp->v_mount; 96365963Spendry 96465963Spendry VREF(dvp); 96565963Spendry VOP_LOCK(dvp); 96665963Spendry vput(ap->a_dvp); 96765963Spendry error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, 96865963Spendry ap->a_vap, ap->a_target); 96965965Spendry *ap->a_vpp = 0; 97065963Spendry return (error); 97165963Spendry } 97265963Spendry 97365963Spendry vput(ap->a_dvp); 97465963Spendry return (EROFS); 97565963Spendry } 97665963Spendry 97765935Spendry /* 97865935Spendry * union_readdir works in concert with getdirentries and 97965935Spendry * readdir(3) to provide a list of entries in the unioned 98065935Spendry * directories. getdirentries is responsible for walking 98165935Spendry * down the union stack. readdir(3) is responsible for 98265935Spendry * eliminating duplicate names from the returned data stream. 98365935Spendry */ 98465935Spendry int 98565935Spendry union_readdir(ap) 98665935Spendry struct vop_readdir_args /* { 98765935Spendry struct vnodeop_desc *a_desc; 98865935Spendry struct vnode *a_vp; 98965935Spendry struct uio *a_uio; 99065935Spendry struct ucred *a_cred; 99165935Spendry } */ *ap; 99265935Spendry { 99365963Spendry int error = 0; 99465935Spendry struct union_node *un = VTOUNION(ap->a_vp); 99565935Spendry 99665963Spendry if (un->un_uppervp) { 99765963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 99865935Spendry 99965963Spendry VOP_LOCK(vp); 100065963Spendry error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 100165963Spendry VOP_UNLOCK(vp); 100265963Spendry } 100365963Spendry 100465963Spendry return (error); 100565935Spendry } 100665935Spendry 100765935Spendry int 100865963Spendry union_readlink(ap) 100965963Spendry struct vop_readlink_args /* { 101065963Spendry struct vnode *a_vp; 101165963Spendry struct uio *a_uio; 101265963Spendry struct ucred *a_cred; 101365963Spendry } */ *ap; 101465963Spendry { 101565963Spendry int error; 101665963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 101765963Spendry 101865963Spendry VOP_LOCK(vp); 101965963Spendry error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 102065963Spendry VOP_UNLOCK(vp); 102165963Spendry 102265963Spendry return (error); 102365963Spendry } 102465963Spendry 102565963Spendry int 102665963Spendry union_abortop(ap) 102765963Spendry struct vop_abortop_args /* { 102865963Spendry struct vnode *a_dvp; 102965963Spendry struct componentname *a_cnp; 103065963Spendry } */ *ap; 103165963Spendry { 103265963Spendry int error; 103365965Spendry struct vnode *vp = OTHERVP(ap->a_dvp); 103465963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 103565963Spendry int islocked = un->un_flags & UN_LOCKED; 103665963Spendry 103765963Spendry if (islocked) 103865963Spendry VOP_LOCK(vp); 103965963Spendry error = VOP_ABORTOP(vp, ap->a_cnp); 104065963Spendry if (islocked) 104165963Spendry VOP_UNLOCK(vp); 104265963Spendry 104365963Spendry return (error); 104465963Spendry } 104565963Spendry 104665963Spendry int 104765935Spendry union_inactive(ap) 104865935Spendry struct vop_inactive_args /* { 104965935Spendry struct vnode *a_vp; 105065935Spendry } */ *ap; 105165935Spendry { 105265935Spendry 105365935Spendry /* 105465935Spendry * Do nothing (and _don't_ bypass). 105565935Spendry * Wait to vrele lowervp until reclaim, 105665935Spendry * so that until then our union_node is in the 105765935Spendry * cache and reusable. 105865935Spendry * 105965935Spendry * NEEDSWORK: Someday, consider inactive'ing 106065935Spendry * the lowervp and then trying to reactivate it 106165935Spendry * with capabilities (v_id) 106265935Spendry * like they do in the name lookup cache code. 106365935Spendry * That's too much work for now. 106465935Spendry */ 106565989Spendry 106665989Spendry #ifdef DIAGNOSTIC 106765989Spendry struct union_node *un = VTOUNION(ap->a_vp); 106865989Spendry 106965989Spendry if (un->un_flags & UN_LOCKED) 107065989Spendry panic("union: inactivating locked node"); 107165989Spendry #endif 107265989Spendry 107365935Spendry return (0); 107465935Spendry } 107565935Spendry 107665935Spendry int 107765935Spendry union_reclaim(ap) 107865935Spendry struct vop_reclaim_args /* { 107965935Spendry struct vnode *a_vp; 108065935Spendry } */ *ap; 108165935Spendry { 108265935Spendry struct vnode *vp = ap->a_vp; 108365935Spendry struct union_node *un = VTOUNION(vp); 108465935Spendry struct vnode *uppervp = un->un_uppervp; 108565935Spendry struct vnode *lowervp = un->un_lowervp; 108665935Spendry struct vnode *dirvp = un->un_dirvp; 108765935Spendry char *path = un->un_path; 108865935Spendry 108965935Spendry /* 109065935Spendry * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p, 109165935Spendry * so we can't call VOPs on ourself. 109265935Spendry */ 109365935Spendry /* After this assignment, this node will not be re-used. */ 109465935Spendry un->un_uppervp = 0; 109565935Spendry un->un_lowervp = 0; 109665935Spendry un->un_dirvp = 0; 109765935Spendry un->un_path = NULL; 109865935Spendry union_freevp(vp); 109965935Spendry if (uppervp) 110065935Spendry vrele(uppervp); 110165935Spendry if (lowervp) 110265935Spendry vrele(lowervp); 110365935Spendry if (dirvp) 110465935Spendry vrele(dirvp); 110565935Spendry if (path) 110665935Spendry free(path, M_TEMP); 110765935Spendry return (0); 110865935Spendry } 110965935Spendry 111065963Spendry int 111165963Spendry union_lock(ap) 111265963Spendry struct vop_lock_args *ap; 111365963Spendry { 111465963Spendry struct union_node *un = VTOUNION(ap->a_vp); 111565935Spendry 111665965Spendry while (un->un_flags & UN_LOCKED) { 111765963Spendry #ifdef DIAGNOSTIC 111865989Spendry if (curproc && un->un_pid == curproc->p_pid && 111965989Spendry un->un_pid > -1 && curproc->p_pid > -1) 112065989Spendry panic("union: locking against myself"); 112165963Spendry #endif 112265963Spendry un->un_flags |= UN_WANT; 112365963Spendry sleep((caddr_t) &un->un_flags, PINOD); 112465963Spendry } 112565963Spendry un->un_flags |= UN_LOCKED; 112665989Spendry 112765963Spendry #ifdef DIAGNOSTIC 112865989Spendry if (curproc) 112965989Spendry un->un_pid = curproc->p_pid; 113065989Spendry else 113165989Spendry un->un_pid = -1; 113265963Spendry #endif 113365963Spendry } 113465963Spendry 113565935Spendry int 113665963Spendry union_unlock(ap) 113765963Spendry struct vop_lock_args *ap; 113865963Spendry { 113965963Spendry struct union_node *un = VTOUNION(ap->a_vp); 114065963Spendry 114165963Spendry #ifdef DIAGNOSTIC 114265965Spendry if ((un->un_flags & UN_LOCKED) == 0) 114365965Spendry panic("union: unlock unlocked node"); 114465989Spendry if (curproc && un->un_pid != curproc->p_pid && 114565989Spendry curproc->p_pid > -1 && un->un_pid > -1) 114665963Spendry panic("union: unlocking other process's union node"); 114765963Spendry #endif 114865963Spendry 114965963Spendry un->un_flags &= ~UN_LOCKED; 115065963Spendry if (un->un_flags & UN_WANT) { 115165963Spendry un->un_flags &= ~UN_WANT; 115265963Spendry wakeup((caddr_t) &un->un_flags); 115365963Spendry } 115465963Spendry 115565963Spendry #ifdef DIAGNOSTIC 115665963Spendry un->un_pid = 0; 115765963Spendry #endif 115865963Spendry } 115965963Spendry 116065963Spendry int 116165963Spendry union_bmap(ap) 116265963Spendry struct vop_bmap_args /* { 116365963Spendry struct vnode *a_vp; 116465963Spendry daddr_t a_bn; 116565963Spendry struct vnode **a_vpp; 116665963Spendry daddr_t *a_bnp; 116765963Spendry int *a_runp; 116865963Spendry } */ *ap; 116965963Spendry { 117065963Spendry int error; 117165963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 117265963Spendry 117365963Spendry VOP_LOCK(vp); 117465963Spendry error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp); 117565963Spendry VOP_UNLOCK(vp); 117665963Spendry 117765963Spendry return (error); 117865963Spendry } 117965963Spendry 118065963Spendry int 118165935Spendry union_print(ap) 118265935Spendry struct vop_print_args /* { 118365935Spendry struct vnode *a_vp; 118465935Spendry } */ *ap; 118565935Spendry { 118665935Spendry struct vnode *vp = ap->a_vp; 118765935Spendry 118865935Spendry printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n", 118965935Spendry vp, UPPERVP(vp), LOWERVP(vp)); 119065935Spendry return (0); 119165935Spendry } 119265935Spendry 119365963Spendry int 119465963Spendry union_islocked(ap) 119565963Spendry struct vop_islocked_args /* { 119665963Spendry struct vnode *a_vp; 119765963Spendry } */ *ap; 119865963Spendry { 119965935Spendry 120065963Spendry return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0); 120165963Spendry } 120265963Spendry 120365935Spendry int 120465963Spendry union_pathconf(ap) 120565963Spendry struct vop_pathconf_args /* { 120665963Spendry struct vnode *a_vp; 120765963Spendry int a_name; 120865963Spendry int *a_retval; 120965935Spendry } */ *ap; 121065935Spendry { 121165935Spendry int error; 121265963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 121365935Spendry 121465963Spendry VOP_LOCK(vp); 121565963Spendry error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval); 121665963Spendry VOP_UNLOCK(vp); 121765935Spendry 121865963Spendry return (error); 121965963Spendry } 122065935Spendry 122165963Spendry int 122265963Spendry union_advlock(ap) 122365963Spendry struct vop_advlock_args /* { 122465963Spendry struct vnode *a_vp; 122565963Spendry caddr_t a_id; 122665963Spendry int a_op; 122765963Spendry struct flock *a_fl; 122865963Spendry int a_flags; 122965963Spendry } */ *ap; 123065963Spendry { 123165935Spendry 123265963Spendry return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op, 123365963Spendry ap->a_fl, ap->a_flags)); 123465935Spendry } 123565935Spendry 123665935Spendry 123765935Spendry /* 123865963Spendry * XXX - vop_strategy must be hand coded because it has no 123965935Spendry * vnode in its arguments. 124065935Spendry * This goes away with a merged VM/buffer cache. 124165935Spendry */ 124265935Spendry int 124365963Spendry union_strategy(ap) 124465963Spendry struct vop_strategy_args /* { 124565935Spendry struct buf *a_bp; 124665935Spendry } */ *ap; 124765935Spendry { 124865935Spendry struct buf *bp = ap->a_bp; 124965935Spendry int error; 125065935Spendry struct vnode *savedvp; 125165935Spendry 125265935Spendry savedvp = bp->b_vp; 125365963Spendry bp->b_vp = OTHERVP(bp->b_vp); 125465935Spendry 125565935Spendry #ifdef DIAGNOSTIC 125665935Spendry if (bp->b_vp == 0) 125765963Spendry panic("union_strategy: nil vp"); 125865963Spendry if (((bp->b_flags & B_READ) == 0) && 125965963Spendry (bp->b_vp == LOWERVP(savedvp))) 126065963Spendry panic("union_strategy: writing to lowervp"); 126165935Spendry #endif 126265935Spendry 126365963Spendry error = VOP_STRATEGY(bp); 126465935Spendry bp->b_vp = savedvp; 126565935Spendry 126665935Spendry return (error); 126765935Spendry } 126865935Spendry 126965935Spendry /* 127065935Spendry * Global vfs data structures 127165935Spendry */ 127265935Spendry int (**union_vnodeop_p)(); 127365965Spendry struct vnodeopv_entry_desc union_vnodeop_entries[] = { 127465963Spendry { &vop_default_desc, vn_default_error }, 127565963Spendry { &vop_lookup_desc, union_lookup }, /* lookup */ 127665963Spendry { &vop_create_desc, union_create }, /* create */ 127765963Spendry { &vop_mknod_desc, union_mknod }, /* mknod */ 127865963Spendry { &vop_open_desc, union_open }, /* open */ 127965963Spendry { &vop_close_desc, union_close }, /* close */ 128065963Spendry { &vop_access_desc, union_access }, /* access */ 128165963Spendry { &vop_getattr_desc, union_getattr }, /* getattr */ 128265963Spendry { &vop_setattr_desc, union_setattr }, /* setattr */ 128365963Spendry { &vop_read_desc, union_read }, /* read */ 128465963Spendry { &vop_write_desc, union_write }, /* write */ 128565963Spendry { &vop_ioctl_desc, union_ioctl }, /* ioctl */ 128665963Spendry { &vop_select_desc, union_select }, /* select */ 128765963Spendry { &vop_mmap_desc, union_mmap }, /* mmap */ 128865963Spendry { &vop_fsync_desc, union_fsync }, /* fsync */ 128965963Spendry { &vop_seek_desc, union_seek }, /* seek */ 129065963Spendry { &vop_remove_desc, union_remove }, /* remove */ 129165963Spendry { &vop_link_desc, union_link }, /* link */ 129265963Spendry { &vop_rename_desc, union_rename }, /* rename */ 129365963Spendry { &vop_mkdir_desc, union_mkdir }, /* mkdir */ 129465963Spendry { &vop_rmdir_desc, union_rmdir }, /* rmdir */ 129565963Spendry { &vop_symlink_desc, union_symlink }, /* symlink */ 129665963Spendry { &vop_readdir_desc, union_readdir }, /* readdir */ 129765963Spendry { &vop_readlink_desc, union_readlink }, /* readlink */ 129865963Spendry { &vop_abortop_desc, union_abortop }, /* abortop */ 129965963Spendry { &vop_inactive_desc, union_inactive }, /* inactive */ 130065963Spendry { &vop_reclaim_desc, union_reclaim }, /* reclaim */ 130165963Spendry { &vop_lock_desc, union_lock }, /* lock */ 130265963Spendry { &vop_unlock_desc, union_unlock }, /* unlock */ 130365963Spendry { &vop_bmap_desc, union_bmap }, /* bmap */ 130465963Spendry { &vop_strategy_desc, union_strategy }, /* strategy */ 130565963Spendry { &vop_print_desc, union_print }, /* print */ 130665963Spendry { &vop_islocked_desc, union_islocked }, /* islocked */ 130765963Spendry { &vop_pathconf_desc, union_pathconf }, /* pathconf */ 130865963Spendry { &vop_advlock_desc, union_advlock }, /* advlock */ 130965963Spendry #ifdef notdef 131065963Spendry { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */ 131165963Spendry { &vop_valloc_desc, union_valloc }, /* valloc */ 131265963Spendry { &vop_vfree_desc, union_vfree }, /* vfree */ 131365963Spendry { &vop_truncate_desc, union_truncate }, /* truncate */ 131465963Spendry { &vop_update_desc, union_update }, /* update */ 131565963Spendry { &vop_bwrite_desc, union_bwrite }, /* bwrite */ 131665963Spendry #endif 131765935Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 131865935Spendry }; 131965935Spendry struct vnodeopv_desc union_vnodeop_opv_desc = 132065935Spendry { &union_vnodeop_p, union_vnodeop_entries }; 1321