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*65965Spendry * @(#)union_vnops.c 1.3 (Berkeley) 02/01/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 28*65965Spendry /* 29*65965Spendry * Create a shadow directory in the upper layer. 30*65965Spendry * The new vnode is returned locked. 31*65965Spendry */ 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; 4165935Spendry 4265935Spendry /* 4365935Spendry * policy: when creating the shadow directory in the 4465935Spendry * upper layer, create it owned by the current user, 4565935Spendry * group from parent directory, and mode 777 modified 4665935Spendry * by umask (ie mostly identical to the mkdir syscall). 4765935Spendry * (jsp, kb) 4865935Spendry * TODO: create the directory owned by the user who 4965935Spendry * did the mount (um->um_cred). 5065935Spendry */ 5165935Spendry 5265935Spendry VATTR_NULL(&va); 5365935Spendry va.va_type = VDIR; 5465935Spendry va.va_mode = UN_DIRMODE &~ p->p_fd->fd_cmask; 55*65965Spendry VOP_UNLOCK(dvp); 5665935Spendry LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE); 57*65965Spendry VREF(dvp); 5865935Spendry VOP_LOCK(dvp); 5965935Spendry error = VOP_MKDIR(dvp, vpp, cnp, &va); 60*65965Spendry VOP_LOCK(dvp); 6165935Spendry return (error); 6265935Spendry } 6365935Spendry 6465935Spendry static int 6565935Spendry union_lookup1(dvp, vpp, cnp) 6665935Spendry struct vnode *dvp; 6765935Spendry struct vnode **vpp; 6865935Spendry struct componentname *cnp; 6965935Spendry { 7065935Spendry int error; 7165935Spendry struct vnode *tdvp; 7265935Spendry struct mount *mp; 7365935Spendry 7465935Spendry if (cnp->cn_flags & ISDOTDOT) { 7565935Spendry for (;;) { 7665935Spendry if ((dvp->v_flag & VROOT) == 0 || 7765935Spendry (cnp->cn_flags & NOCROSSMOUNT)) 7865935Spendry break; 7965935Spendry 8065935Spendry tdvp = dvp; 8165935Spendry dvp = dvp->v_mount->mnt_vnodecovered; 8265935Spendry vput(tdvp); 8365935Spendry VREF(dvp); 8465935Spendry VOP_LOCK(dvp); 8565935Spendry } 8665935Spendry } 8765935Spendry 8865935Spendry error = VOP_LOOKUP(dvp, &tdvp, cnp); 8965935Spendry if (error) 9065935Spendry return (error); 9165935Spendry 9265935Spendry dvp = tdvp; 9365935Spendry while ((dvp->v_type == VDIR) && (mp = dvp->v_mountedhere) && 9465935Spendry (cnp->cn_flags & NOCROSSMOUNT) == 0) { 9565935Spendry 9665935Spendry if (mp->mnt_flag & MNT_MLOCK) { 9765935Spendry mp->mnt_flag |= MNT_MWAIT; 9865935Spendry sleep((caddr_t) mp, PVFS); 9965935Spendry continue; 10065935Spendry } 10165935Spendry 10265935Spendry if (error = VFS_ROOT(mp, &tdvp)) { 10365935Spendry vput(dvp); 10465935Spendry return (error); 10565935Spendry } 10665935Spendry 107*65965Spendry vput(dvp); 10865935Spendry dvp = tdvp; 10965935Spendry } 11065935Spendry 11165935Spendry *vpp = dvp; 11265935Spendry return (0); 11365935Spendry } 11465935Spendry 11565935Spendry int 11665935Spendry union_lookup(ap) 11765935Spendry struct vop_lookup_args /* { 11865935Spendry struct vnodeop_desc *a_desc; 11965935Spendry struct vnode *a_dvp; 12065935Spendry struct vnode **a_vpp; 12165935Spendry struct componentname *a_cnp; 12265935Spendry } */ *ap; 12365935Spendry { 124*65965Spendry int error; 12565935Spendry int uerror, lerror; 12665935Spendry struct vnode *uppervp, *lowervp; 12765935Spendry struct vnode *upperdvp, *lowerdvp; 12865935Spendry struct vnode *dvp = ap->a_dvp; 12965935Spendry struct union_node *dun = VTOUNION(ap->a_dvp); 13065935Spendry struct componentname *cnp = ap->a_cnp; 13165935Spendry int lockparent = cnp->cn_flags & LOCKPARENT; 13265935Spendry 133*65965Spendry cnp->cn_flags |= LOCKPARENT; 134*65965Spendry 13565935Spendry upperdvp = dun->un_uppervp; 13665935Spendry lowerdvp = dun->un_lowervp; 137*65965Spendry uppervp = 0; 138*65965Spendry lowervp = 0; 13965935Spendry 14065935Spendry /* 14165935Spendry * do the lookup in the upper level. 14265935Spendry * if that level comsumes additional pathnames, 14365935Spendry * then assume that something special is going 14465935Spendry * on and just return that vnode. 14565935Spendry */ 14665935Spendry uppervp = 0; 14765935Spendry if (upperdvp) { 148*65965Spendry VOP_LOCK(upperdvp); 14965935Spendry uerror = union_lookup1(upperdvp, &uppervp, cnp); 150*65965Spendry VOP_UNLOCK(upperdvp); 151*65965Spendry 15265935Spendry if (cnp->cn_consume != 0) { 15365935Spendry *ap->a_vpp = uppervp; 154*65965Spendry if (!lockparent) 155*65965Spendry cnp->cn_flags &= ~LOCKPARENT; 15665935Spendry return (uerror); 15765935Spendry } 15865935Spendry } else { 15965935Spendry uerror = ENOENT; 16065935Spendry } 16165935Spendry 16265935Spendry /* 16365935Spendry * in a similar way to the upper layer, do the lookup 16465935Spendry * in the lower layer. this time, if there is some 16565935Spendry * component magic going on, then vput whatever we got 16665935Spendry * back from the upper layer and return the lower vnode 16765935Spendry * instead. 16865935Spendry */ 16965935Spendry lowervp = 0; 17065935Spendry if (lowerdvp) { 171*65965Spendry VOP_LOCK(lowerdvp); 17265935Spendry lerror = union_lookup1(lowerdvp, &lowervp, cnp); 173*65965Spendry VOP_UNLOCK(lowerdvp); 174*65965Spendry 17565935Spendry if (cnp->cn_consume != 0) { 17665935Spendry if (uppervp) { 17765935Spendry vput(uppervp); 17865935Spendry uppervp = 0; 17965935Spendry } 18065935Spendry *ap->a_vpp = lowervp; 181*65965Spendry if (!lockparent) 182*65965Spendry cnp->cn_flags &= ~LOCKPARENT; 18365935Spendry return (lerror); 18465935Spendry } 18565935Spendry } else { 18665935Spendry lerror = ENOENT; 18765935Spendry } 18865935Spendry 189*65965Spendry if (!lockparent) 190*65965Spendry cnp->cn_flags &= ~LOCKPARENT; 191*65965Spendry 19265935Spendry /* 19365935Spendry * at this point, we have uerror and lerror indicating 19465935Spendry * possible errors with the lookups in the upper and lower 19565935Spendry * layers. additionally, uppervp and lowervp are (locked) 19665935Spendry * references to existing vnodes in the upper and lower layers. 19765935Spendry * 19865935Spendry * there are now three cases to consider. 19965935Spendry * 1. if both layers returned an error, then return whatever 20065935Spendry * error the upper layer generated. 20165935Spendry * 20265935Spendry * 2. if the top layer failed and the bottom layer succeeded 20365935Spendry * then two subcases occur. 20465935Spendry * a. the bottom vnode is not a directory, in which 20565935Spendry * case just return a new union vnode referencing 20665935Spendry * an empty top layer and the existing bottom layer. 20765935Spendry * b. the bottom vnode is a directory, in which case 20865935Spendry * create a new directory in the top-level and 20965935Spendry * continue as in case 3. 21065935Spendry * 21165935Spendry * 3. if the top layer succeeded then return a new union 21265935Spendry * vnode referencing whatever the new top layer and 21365935Spendry * whatever the bottom layer returned. 21465935Spendry */ 21565935Spendry 21665935Spendry /* case 1. */ 21765935Spendry if ((uerror != 0) && (lerror != 0)) { 21865935Spendry *ap->a_vpp = 0; 21965935Spendry return (uerror); 22065935Spendry } 22165935Spendry 22265935Spendry /* case 2. */ 22365935Spendry if (uerror != 0 /* && (lerror == 0) */ ) { 22465935Spendry if (lowervp->v_type == VDIR) { /* case 2b. */ 225*65965Spendry VOP_LOCK(upperdvp); 22665935Spendry uerror = union_mkshadow(upperdvp, cnp, &uppervp); 227*65965Spendry VOP_UNLOCK(upperdvp); 22865935Spendry if (uerror) { 22965935Spendry if (lowervp) { 23065935Spendry vput(lowervp); 23165935Spendry lowervp = 0; 23265935Spendry } 23365935Spendry return (uerror); 23465935Spendry } 23565935Spendry } 23665935Spendry } 23765935Spendry 238*65965Spendry error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, cnp, 239*65965Spendry uppervp, lowervp); 240*65965Spendry 241*65965Spendry if (uppervp) 242*65965Spendry VOP_UNLOCK(uppervp); 243*65965Spendry if (lowervp) 244*65965Spendry VOP_UNLOCK(lowervp); 245*65965Spendry 246*65965Spendry if (error) { 247*65965Spendry if (uppervp) 248*65965Spendry vrele(uppervp); 249*65965Spendry if (lowervp) 250*65965Spendry vrele(lowervp); 251*65965Spendry } else { 252*65965Spendry if (!lockparent) 253*65965Spendry VOP_UNLOCK(*ap->a_vpp); 254*65965Spendry } 255*65965Spendry 256*65965Spendry return (error); 25765935Spendry } 25865935Spendry 25965963Spendry int 26065963Spendry union_create(ap) 26165963Spendry struct vop_create_args /* { 26265963Spendry struct vnode *a_dvp; 26365963Spendry struct vnode **a_vpp; 26465963Spendry struct componentname *a_cnp; 26565963Spendry struct vattr *a_vap; 26665963Spendry } */ *ap; 26765963Spendry { 26865963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 26965963Spendry struct vnode *dvp = un->un_uppervp; 27065963Spendry 27165963Spendry if (dvp) { 27265963Spendry int error; 27365963Spendry struct vnode *vp; 27465963Spendry struct mount *mp = ap->a_dvp->v_mount; 27565963Spendry 27665963Spendry VREF(dvp); 27765963Spendry VOP_LOCK(dvp); 27865963Spendry vput(ap->a_dvp); 27965963Spendry error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap); 28065963Spendry if (error) 28165963Spendry return (error); 28265963Spendry 28365963Spendry error = union_allocvp( 28465963Spendry ap->a_vpp, 28565963Spendry mp, 286*65965Spendry NULLVP, 28765963Spendry ap->a_cnp, 28865963Spendry vp, 28965963Spendry NULLVP); 290*65965Spendry VOP_UNLOCK(vp); 291*65965Spendry if (error) 292*65965Spendry vrele(vp); 29365963Spendry return (error); 29465963Spendry } 29565963Spendry 29665963Spendry vput(ap->a_dvp); 29765963Spendry return (EROFS); 29865963Spendry } 29965963Spendry 30065963Spendry int 30165963Spendry union_mknod(ap) 30265963Spendry struct vop_mknod_args /* { 30365963Spendry struct vnode *a_dvp; 30465963Spendry struct vnode **a_vpp; 30565963Spendry struct componentname *a_cnp; 30665963Spendry struct vattr *a_vap; 30765963Spendry } */ *ap; 30865963Spendry { 30965963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 31065963Spendry struct vnode *dvp = un->un_uppervp; 31165963Spendry 31265963Spendry if (dvp) { 31365963Spendry int error; 31465963Spendry struct vnode *vp; 31565963Spendry struct mount *mp = ap->a_dvp->v_mount; 31665963Spendry 31765963Spendry VREF(dvp); 31865963Spendry VOP_LOCK(dvp); 31965963Spendry vput(ap->a_dvp); 32065963Spendry error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap); 32165963Spendry if (error) 32265963Spendry return (error); 32365963Spendry 324*65965Spendry if (vp) { 325*65965Spendry error = union_allocvp( 326*65965Spendry ap->a_vpp, 327*65965Spendry mp, 328*65965Spendry NULLVP, 329*65965Spendry ap->a_cnp, 330*65965Spendry vp, 331*65965Spendry NULLVP); 332*65965Spendry VOP_UNLOCK(vp); 333*65965Spendry if (error) 334*65965Spendry vrele(vp); 335*65965Spendry } 33665963Spendry return (error); 33765963Spendry } 33865963Spendry 33965963Spendry vput(ap->a_dvp); 34065963Spendry return (EROFS); 34165963Spendry } 34265963Spendry 34365935Spendry /* 34465935Spendry * copyfile. copy the vnode (fvp) to the vnode (tvp) 34565963Spendry * using a sequence of reads and writes. both (fvp) 34665963Spendry * and (tvp) are locked on entry and exit. 34765935Spendry */ 34865935Spendry static int 34965935Spendry union_copyfile(p, cred, fvp, tvp) 35065935Spendry struct proc *p; 35165935Spendry struct ucred *cred; 35265935Spendry struct vnode *fvp; 35365935Spendry struct vnode *tvp; 35465935Spendry { 35565935Spendry char *buf; 35665935Spendry struct uio uio; 35765935Spendry struct iovec iov; 35865935Spendry int error = 0; 35965935Spendry off_t offset; 36065935Spendry 36165935Spendry /* 36265935Spendry * strategy: 36365935Spendry * allocate a buffer of size MAXBSIZE. 36465935Spendry * loop doing reads and writes, keeping track 36565935Spendry * of the current uio offset. 36665935Spendry * give up at the first sign of trouble. 36765935Spendry */ 36865935Spendry 36965935Spendry uio.uio_procp = p; 37065935Spendry uio.uio_segflg = UIO_SYSSPACE; 37165935Spendry offset = 0; 37265935Spendry 37365935Spendry VOP_UNLOCK(fvp); /* XXX */ 37465935Spendry LEASE_CHECK(fvp, p, cred, LEASE_READ); 37565935Spendry VOP_LOCK(fvp); /* XXX */ 37665935Spendry VOP_UNLOCK(tvp); /* XXX */ 37765935Spendry LEASE_CHECK(tvp, p, cred, LEASE_WRITE); 37865935Spendry VOP_LOCK(tvp); /* XXX */ 37965935Spendry 38065935Spendry buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK); 38165935Spendry do { 38265935Spendry uio.uio_iov = &iov; 38365935Spendry uio.uio_iovcnt = 1; 38465935Spendry iov.iov_base = buf; 38565935Spendry iov.iov_len = MAXBSIZE; 38665935Spendry uio.uio_resid = iov.iov_len; 38765935Spendry uio.uio_offset = offset; 38865935Spendry uio.uio_rw = UIO_READ; 38965935Spendry error = VOP_READ(fvp, &uio, 0, cred); 39065935Spendry 39165935Spendry if (error == 0) { 39265935Spendry uio.uio_iov = &iov; 39365935Spendry uio.uio_iovcnt = 1; 39465935Spendry iov.iov_base = buf; 39565935Spendry iov.iov_len = MAXBSIZE - uio.uio_resid; 39665935Spendry uio.uio_rw = UIO_WRITE; 39765935Spendry uio.uio_resid = iov.iov_len; 39865935Spendry uio.uio_offset = offset; 39965935Spendry 40065935Spendry do { 40165935Spendry error = VOP_WRITE(tvp, &uio, 0, cred); 40265935Spendry } while (error == 0 && uio.uio_resid > 0); 40365935Spendry if (error == 0) 40465935Spendry offset = uio.uio_offset; 40565935Spendry } 40665935Spendry } while ((uio.uio_resid == 0) && (error == 0)); 40765935Spendry 40865935Spendry free(buf, M_TEMP); 40965935Spendry return (error); 41065935Spendry } 41165935Spendry 41265935Spendry int 41365935Spendry union_open(ap) 41465935Spendry struct vop_open_args /* { 41565935Spendry struct vnodeop_desc *a_desc; 41665935Spendry struct vnode *a_vp; 41765935Spendry int a_mode; 41865935Spendry struct ucred *a_cred; 41965935Spendry struct proc *a_p; 42065935Spendry } */ *ap; 42165935Spendry { 42265935Spendry struct union_node *un = VTOUNION(ap->a_vp); 423*65965Spendry struct vnode *tvp; 42465935Spendry int mode = ap->a_mode; 42565935Spendry struct ucred *cred = ap->a_cred; 42665935Spendry struct proc *p = ap->a_p; 427*65965Spendry int error; 42865935Spendry 42965935Spendry /* 43065935Spendry * If there is an existing upper vp then simply open that. 43165935Spendry */ 432*65965Spendry tvp = un->un_uppervp; 433*65965Spendry if (tvp == NULLVP) { 43465935Spendry /* 435*65965Spendry * If the lower vnode is being opened for writing, then 436*65965Spendry * copy the file contents to the upper vnode and open that, 437*65965Spendry * otherwise can simply open the lower vnode. 43865935Spendry */ 439*65965Spendry tvp = un->un_lowervp; 440*65965Spendry if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { 441*65965Spendry struct nameidata nd; 442*65965Spendry struct filedesc *fdp = p->p_fd; 443*65965Spendry int fmode; 444*65965Spendry int cmode; 44565963Spendry 446*65965Spendry /* 447*65965Spendry * Open the named file in the upper layer. Note that 448*65965Spendry * the file may have come into existence *since* the 449*65965Spendry * lookup was done, since the upper layer may really 450*65965Spendry * be a loopback mount of some other filesystem... 451*65965Spendry * so open the file with exclusive create and barf if 452*65965Spendry * it already exists. 453*65965Spendry * XXX - perhaps shoudl re-lookup the node (once more 454*65965Spendry * with feeling) and simply open that. Who knows. 455*65965Spendry */ 456*65965Spendry NDINIT(&nd, CREATE, 0, UIO_SYSSPACE, un->un_path, p); 457*65965Spendry fmode = (O_CREAT|O_TRUNC|O_EXCL); 458*65965Spendry cmode = UN_FILEMODE & ~fdp->fd_cmask; 459*65965Spendry error = vn_open(&nd, fmode, cmode); 460*65965Spendry if (error) 461*65965Spendry return (error); 462*65965Spendry un->un_uppervp = nd.ni_vp; /* XXX */ 463*65965Spendry /* at this point, uppervp is locked */ 464*65965Spendry 465*65965Spendry /* 466*65965Spendry * Now, if the file is being opened with truncation, 467*65965Spendry * then the (new) upper vnode is ready to fly, 468*65965Spendry * otherwise the data from the lower vnode must be 469*65965Spendry * copied to the upper layer first. This only works 470*65965Spendry * for regular files (check is made above). 471*65965Spendry */ 472*65965Spendry if ((mode & O_TRUNC) == 0) { 473*65965Spendry /* 474*65965Spendry * XXX - should not ignore errors 475*65965Spendry * from VOP_CLOSE 476*65965Spendry */ 477*65965Spendry VOP_LOCK(un->un_lowervp); 478*65965Spendry error = VOP_OPEN(tvp, FREAD, cred, p); 479*65965Spendry if (error == 0) { 480*65965Spendry error = union_copyfile(p, cred, 481*65965Spendry tvp, un->un_uppervp); 482*65965Spendry VOP_UNLOCK(tvp); 483*65965Spendry (void) VOP_CLOSE(tvp, FREAD); 484*65965Spendry } else { 485*65965Spendry VOP_UNLOCK(tvp); 486*65965Spendry } 487*65965Spendry VOP_UNLOCK(un->un_uppervp); 488*65965Spendry (void) VOP_CLOSE(un->un_uppervp, FWRITE); 489*65965Spendry VOP_LOCK(un->un_uppervp); 49065935Spendry } 491*65965Spendry if (error == 0) 492*65965Spendry error = VOP_OPEN(un->un_uppervp, mode, cred, p); 49365963Spendry VOP_UNLOCK(un->un_uppervp); 494*65965Spendry return (error); 49565935Spendry } 49665935Spendry } 49765935Spendry 498*65965Spendry VOP_LOCK(tvp); 499*65965Spendry error = VOP_OPEN(tvp, mode, cred, p); 500*65965Spendry VOP_UNLOCK(tvp); 501*65965Spendry 502*65965Spendry return (error); 50365935Spendry } 50465935Spendry 50565963Spendry int 50665963Spendry union_close(ap) 50765963Spendry struct vop_close_args /* { 50865963Spendry struct vnode *a_vp; 50965963Spendry int a_fflag; 51065963Spendry struct ucred *a_cred; 51165963Spendry struct proc *a_p; 51265963Spendry } */ *ap; 51365963Spendry { 51465963Spendry 51565963Spendry return (VOP_CLOSE(OTHERVP(ap->a_vp), ap->a_fflag, ap->a_cred, ap->a_p)); 51665963Spendry } 51765963Spendry 51865935Spendry /* 51965963Spendry * Check access permission on the union vnode. 52065963Spendry * The access check being enforced is to check 52165963Spendry * against both the underlying vnode, and any 52265963Spendry * copied vnode. This ensures that no additional 52365963Spendry * file permissions are given away simply because 52465963Spendry * the user caused an implicit file copy. 52565963Spendry */ 52665963Spendry int 52765963Spendry union_access(ap) 52865963Spendry struct vop_access_args /* { 52965963Spendry struct vnodeop_desc *a_desc; 53065963Spendry struct vnode *a_vp; 53165963Spendry int a_mode; 53265963Spendry struct ucred *a_cred; 53365963Spendry struct proc *a_p; 53465963Spendry } */ *ap; 53565963Spendry { 53665963Spendry struct union_node *un = VTOUNION(ap->a_vp); 537*65965Spendry int error = 0; 53865963Spendry struct vnode *vp; 53965963Spendry 54065963Spendry if (vp = un->un_lowervp) { 541*65965Spendry VOP_LOCK(vp); 54265963Spendry error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); 543*65965Spendry VOP_UNLOCK(vp); 54465963Spendry if (error) 54565963Spendry return (error); 54665963Spendry } 54765963Spendry 548*65965Spendry if (vp = un->un_uppervp) { 549*65965Spendry VOP_LOCK(vp); 550*65965Spendry error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); 551*65965Spendry VOP_UNLOCK(vp); 552*65965Spendry } 553*65965Spendry 554*65965Spendry return (error); 55565963Spendry } 55665963Spendry 55765963Spendry /* 55865935Spendry * We handle getattr only to change the fsid. 55965935Spendry */ 56065935Spendry int 56165935Spendry union_getattr(ap) 56265935Spendry struct vop_getattr_args /* { 56365935Spendry struct vnode *a_vp; 56465935Spendry struct vattr *a_vap; 56565935Spendry struct ucred *a_cred; 56665935Spendry struct proc *a_p; 56765935Spendry } */ *ap; 56865935Spendry { 56965935Spendry int error; 570*65965Spendry struct vnode *vp = OTHERVP(ap->a_vp); 57165935Spendry 572*65965Spendry VOP_LOCK(vp); 573*65965Spendry error = VOP_GETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p); 574*65965Spendry VOP_UNLOCK(vp); 575*65965Spendry 57665935Spendry /* Requires that arguments be restored. */ 57765935Spendry ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 57865935Spendry return (0); 57965935Spendry } 58065935Spendry 58165963Spendry int 582*65965Spendry union_setattr(ap) 58365963Spendry struct vop_setattr_args /* { 58465963Spendry struct vnode *a_vp; 58565963Spendry struct vattr *a_vap; 58665963Spendry struct ucred *a_cred; 58765963Spendry struct proc *a_p; 58865963Spendry } */ *ap; 58965963Spendry { 59065963Spendry struct union_node *un = VTOUNION(ap->a_vp); 59165963Spendry int error; 59265963Spendry 59365963Spendry if (un->un_uppervp) { 59465963Spendry VOP_LOCK(un->un_uppervp); 59565963Spendry error = VOP_SETATTR(un->un_uppervp, ap->a_vap, 59665963Spendry ap->a_cred, ap->a_p); 59765963Spendry VOP_UNLOCK(un->un_uppervp); 59865963Spendry } else { 59965963Spendry /* 60065963Spendry * XXX should do a copyfile (perhaps only if 60165963Spendry * the file permission change, which would not 60265963Spendry * track va_ctime correctly). 60365963Spendry */ 60465963Spendry error = EROFS; 60565963Spendry } 60665963Spendry 60765963Spendry return (error); 60865963Spendry } 60965963Spendry 61065963Spendry int 61165963Spendry union_read(ap) 61265963Spendry struct vop_read_args /* { 61365963Spendry struct vnode *a_vp; 61465963Spendry struct uio *a_uio; 61565963Spendry int a_ioflag; 61665963Spendry struct ucred *a_cred; 61765963Spendry } */ *ap; 61865963Spendry { 61965963Spendry int error; 62065963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 62165963Spendry 622*65965Spendry VOP_LOCK(vp); 62365963Spendry error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 624*65965Spendry VOP_UNLOCK(vp); 62565963Spendry 62665963Spendry return (error); 62765963Spendry } 62865963Spendry 62965963Spendry int 63065963Spendry union_write(ap) 63165963Spendry struct vop_read_args /* { 63265963Spendry struct vnode *a_vp; 63365963Spendry struct uio *a_uio; 63465963Spendry int a_ioflag; 63565963Spendry struct ucred *a_cred; 63665963Spendry } */ *ap; 63765963Spendry { 63865963Spendry int error; 63965963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 64065963Spendry 64165963Spendry VOP_LOCK(vp); 64265963Spendry error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); 64365963Spendry VOP_UNLOCK(vp); 64465963Spendry 64565963Spendry return (error); 64665963Spendry } 64765963Spendry 64865963Spendry int 64965963Spendry union_ioctl(ap) 65065963Spendry struct vop_ioctl_args /* { 65165963Spendry struct vnode *a_vp; 65265963Spendry int a_command; 65365963Spendry caddr_t a_data; 65465963Spendry int a_fflag; 65565963Spendry struct ucred *a_cred; 65665963Spendry struct proc *a_p; 65765963Spendry } */ *ap; 65865963Spendry { 65965963Spendry 66065963Spendry return (VOP_IOCTL(OTHERVP(ap->a_vp), ap->a_command, ap->a_data, 66165963Spendry ap->a_fflag, ap->a_cred, ap->a_p)); 66265963Spendry } 66365963Spendry 66465963Spendry int 66565963Spendry union_select(ap) 66665963Spendry struct vop_select_args /* { 66765963Spendry struct vnode *a_vp; 66865963Spendry int a_which; 66965963Spendry int a_fflags; 67065963Spendry struct ucred *a_cred; 67165963Spendry struct proc *a_p; 67265963Spendry } */ *ap; 67365963Spendry { 67465963Spendry 67565963Spendry return (VOP_SELECT(OTHERVP(ap->a_vp), ap->a_which, ap->a_fflags, 67665963Spendry ap->a_cred, ap->a_p)); 67765963Spendry } 67865963Spendry 67965963Spendry int 68065963Spendry union_mmap(ap) 68165963Spendry struct vop_mmap_args /* { 68265963Spendry struct vnode *a_vp; 68365963Spendry int a_fflags; 68465963Spendry struct ucred *a_cred; 68565963Spendry struct proc *a_p; 68665963Spendry } */ *ap; 68765963Spendry { 68865963Spendry 68965963Spendry return (VOP_MMAP(OTHERVP(ap->a_vp), ap->a_fflags, 69065963Spendry ap->a_cred, ap->a_p)); 69165963Spendry } 69265963Spendry 69365963Spendry int 69465963Spendry union_fsync(ap) 69565963Spendry struct vop_fsync_args /* { 69665963Spendry struct vnode *a_vp; 69765963Spendry struct ucred *a_cred; 69865963Spendry int a_waitfor; 69965963Spendry struct proc *a_p; 70065963Spendry } */ *ap; 70165963Spendry { 70265963Spendry int error = 0; 70365963Spendry struct vnode *targetvp = OTHERVP(ap->a_vp); 70465963Spendry 70565963Spendry if (targetvp) { 70665963Spendry VOP_LOCK(targetvp); 70765963Spendry error = VOP_FSYNC(targetvp, ap->a_cred, 70865963Spendry ap->a_waitfor, ap->a_p); 70965963Spendry VOP_UNLOCK(targetvp); 71065963Spendry } 71165963Spendry 71265963Spendry return (error); 71365963Spendry } 71465963Spendry 71565963Spendry int 71665963Spendry union_seek(ap) 71765963Spendry struct vop_seek_args /* { 71865963Spendry struct vnode *a_vp; 71965963Spendry off_t a_oldoff; 72065963Spendry off_t a_newoff; 72165963Spendry struct ucred *a_cred; 72265963Spendry } */ *ap; 72365963Spendry { 72465963Spendry 72565963Spendry return (VOP_SEEK(OTHERVP(ap->a_vp), ap->a_oldoff, ap->a_newoff, ap->a_cred)); 72665963Spendry } 72765963Spendry 72865963Spendry int 72965963Spendry union_remove(ap) 73065963Spendry struct vop_remove_args /* { 73165963Spendry struct vnode *a_dvp; 73265963Spendry struct vnode *a_vp; 73365963Spendry struct componentname *a_cnp; 73465963Spendry } */ *ap; 73565963Spendry { 73665963Spendry int error; 73765963Spendry struct union_node *dun = VTOUNION(ap->a_dvp); 73865963Spendry struct union_node *un = VTOUNION(ap->a_vp); 73965963Spendry 74065963Spendry if (dun->un_uppervp && un->un_uppervp) { 74165963Spendry struct vnode *dvp = dun->un_uppervp; 74265963Spendry struct vnode *vp = un->un_uppervp; 74365963Spendry 74465963Spendry VREF(dvp); 74565963Spendry VOP_LOCK(dvp); 74665963Spendry vput(ap->a_dvp); 74765963Spendry VREF(vp); 74865963Spendry VOP_LOCK(vp); 74965963Spendry vput(ap->a_vp); 75065963Spendry 75165963Spendry error = VOP_REMOVE(dvp, vp, ap->a_cnp); 75265963Spendry } else { 75365963Spendry /* 75465963Spendry * XXX: should create a whiteout here 75565963Spendry */ 75665963Spendry vput(ap->a_dvp); 75765963Spendry vput(ap->a_vp); 75865963Spendry error = EROFS; 75965963Spendry } 76065963Spendry 76165963Spendry return (error); 76265963Spendry } 76365963Spendry 76465963Spendry int 76565963Spendry union_link(ap) 76665963Spendry struct vop_link_args /* { 76765963Spendry struct vnode *a_vp; 76865963Spendry struct vnode *a_tdvp; 76965963Spendry struct componentname *a_cnp; 77065963Spendry } */ *ap; 77165963Spendry { 77265963Spendry int error; 77365963Spendry struct union_node *dun = VTOUNION(ap->a_vp); 77465963Spendry struct union_node *un = VTOUNION(ap->a_tdvp); 77565963Spendry 77665963Spendry if (dun->un_uppervp && un->un_uppervp) { 77765963Spendry struct vnode *dvp = dun->un_uppervp; 77865963Spendry struct vnode *vp = un->un_uppervp; 77965963Spendry 78065963Spendry VREF(dvp); 78165963Spendry VOP_LOCK(dvp); 78265963Spendry vput(ap->a_vp); 78365963Spendry VREF(vp); 78465963Spendry vrele(ap->a_tdvp); 78565963Spendry 78665963Spendry error = VOP_LINK(dvp, vp, ap->a_cnp); 78765963Spendry } else { 78865963Spendry /* 78965963Spendry * XXX: need to copy to upper layer 79065963Spendry * and do the link there. 79165963Spendry */ 79265963Spendry vput(ap->a_vp); 79365963Spendry vrele(ap->a_tdvp); 79465963Spendry error = EROFS; 79565963Spendry } 79665963Spendry 79765963Spendry return (error); 79865963Spendry } 79965963Spendry 80065963Spendry int 80165963Spendry union_rename(ap) 80265963Spendry struct vop_rename_args /* { 80365963Spendry struct vnode *a_fdvp; 80465963Spendry struct vnode *a_fvp; 80565963Spendry struct componentname *a_fcnp; 80665963Spendry struct vnode *a_tdvp; 80765963Spendry struct vnode *a_tvp; 80865963Spendry struct componentname *a_tcnp; 80965963Spendry } */ *ap; 81065963Spendry { 81165963Spendry int error; 81265963Spendry 81365963Spendry struct vnode *fdvp = ap->a_fdvp; 81465963Spendry struct vnode *fvp = ap->a_fvp; 81565963Spendry struct vnode *tdvp = ap->a_tdvp; 81665963Spendry struct vnode *tvp = ap->a_tvp; 81765963Spendry 81865963Spendry if (fdvp->v_op == union_vnodeop_p) { /* always true */ 81965963Spendry struct union_node *un = VTOUNION(fdvp); 82065963Spendry if (un->un_uppervp == 0) { 82165963Spendry error = EROFS; 82265963Spendry goto bad; 82365963Spendry } 82465963Spendry 82565963Spendry fdvp = un->un_uppervp; 82665963Spendry VREF(fdvp); 82765963Spendry vrele(ap->a_fdvp); 82865963Spendry } 82965963Spendry 83065963Spendry if (fvp->v_op == union_vnodeop_p) { /* always true */ 83165963Spendry struct union_node *un = VTOUNION(fvp); 83265963Spendry if (un->un_uppervp == 0) { 83365963Spendry error = EROFS; 83465963Spendry goto bad; 83565963Spendry } 83665963Spendry 83765963Spendry fvp = un->un_uppervp; 83865963Spendry VREF(fvp); 83965963Spendry vrele(ap->a_fvp); 84065963Spendry } 84165963Spendry 84265963Spendry if (tdvp->v_op == union_vnodeop_p) { 84365963Spendry struct union_node *un = VTOUNION(tdvp); 84465963Spendry if (un->un_uppervp == 0) { 84565963Spendry error = EROFS; 84665963Spendry goto bad; 84765963Spendry } 84865963Spendry 84965963Spendry tdvp = un->un_uppervp; 85065963Spendry VREF(tdvp); 85165963Spendry VOP_LOCK(tdvp); 85265963Spendry vput(ap->a_fdvp); 85365963Spendry } 85465963Spendry 85565963Spendry if (tvp && tvp->v_op == union_vnodeop_p) { 85665963Spendry struct union_node *un = VTOUNION(tvp); 85765963Spendry if (un->un_uppervp == 0) { 85865963Spendry error = EROFS; 85965963Spendry goto bad; 86065963Spendry } 86165963Spendry 86265963Spendry tvp = un->un_uppervp; 86365963Spendry VREF(tvp); 86465963Spendry VOP_LOCK(tvp); 86565963Spendry vput(ap->a_tvp); 86665963Spendry } 86765963Spendry 86865963Spendry return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp)); 86965963Spendry 87065963Spendry bad: 87165963Spendry vrele(fdvp); 87265963Spendry vrele(fvp); 87365963Spendry vput(tdvp); 87465963Spendry if (tvp) 87565963Spendry vput(tvp); 87665963Spendry 87765963Spendry return (error); 87865963Spendry } 87965963Spendry 88065963Spendry int 88165963Spendry union_mkdir(ap) 88265963Spendry struct vop_mkdir_args /* { 88365963Spendry struct vnode *a_dvp; 88465963Spendry struct vnode **a_vpp; 88565963Spendry struct componentname *a_cnp; 88665963Spendry struct vattr *a_vap; 88765963Spendry } */ *ap; 88865963Spendry { 88965963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 89065963Spendry struct vnode *dvp = un->un_uppervp; 89165963Spendry 89265963Spendry if (dvp) { 89365963Spendry int error; 89465963Spendry struct vnode *vp; 89565963Spendry struct mount *mp = ap->a_dvp->v_mount; 89665963Spendry 89765963Spendry VREF(dvp); 89865963Spendry VOP_LOCK(dvp); 89965963Spendry vput(ap->a_dvp); 90065963Spendry error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap); 90165963Spendry if (error) 90265963Spendry return (error); 90365963Spendry 90465963Spendry error = union_allocvp( 90565963Spendry ap->a_vpp, 90665963Spendry mp, 907*65965Spendry NULLVP, 90865963Spendry ap->a_cnp, 90965963Spendry vp, 91065963Spendry NULLVP); 911*65965Spendry VOP_UNLOCK(vp); 912*65965Spendry if (error) 913*65965Spendry vrele(vp); 91465963Spendry return (error); 91565963Spendry } 91665963Spendry 91765963Spendry vput(ap->a_dvp); 91865963Spendry return (EROFS); 91965963Spendry } 92065963Spendry 92165963Spendry int 92265963Spendry union_rmdir(ap) 92365963Spendry struct vop_rmdir_args /* { 92465963Spendry struct vnode *a_dvp; 92565963Spendry struct vnode *a_vp; 92665963Spendry struct componentname *a_cnp; 92765963Spendry } */ *ap; 92865963Spendry { 92965963Spendry int error; 93065963Spendry struct union_node *dun = VTOUNION(ap->a_dvp); 93165963Spendry struct union_node *un = VTOUNION(ap->a_vp); 93265963Spendry 93365963Spendry if (dun->un_uppervp && un->un_uppervp) { 93465963Spendry struct vnode *dvp = dun->un_uppervp; 93565963Spendry struct vnode *vp = un->un_uppervp; 93665963Spendry 93765963Spendry VREF(dvp); 93865963Spendry VOP_LOCK(dvp); 93965963Spendry vput(ap->a_dvp); 94065963Spendry VREF(vp); 94165963Spendry VOP_LOCK(vp); 94265963Spendry vput(ap->a_vp); 94365963Spendry 94465963Spendry error = VOP_REMOVE(dvp, vp, ap->a_cnp); 94565963Spendry } else { 94665963Spendry /* 94765963Spendry * XXX: should create a whiteout here 94865963Spendry */ 94965963Spendry vput(ap->a_dvp); 95065963Spendry vput(ap->a_vp); 95165963Spendry error = EROFS; 95265963Spendry } 95365963Spendry 95465963Spendry return (error); 95565963Spendry } 95665963Spendry 95765963Spendry int 95865963Spendry union_symlink(ap) 95965963Spendry struct vop_symlink_args /* { 96065963Spendry struct vnode *a_dvp; 96165963Spendry struct vnode **a_vpp; 96265963Spendry struct componentname *a_cnp; 96365963Spendry struct vattr *a_vap; 96465963Spendry char *a_target; 96565963Spendry } */ *ap; 96665963Spendry { 96765963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 96865963Spendry struct vnode *dvp = un->un_uppervp; 96965963Spendry 97065963Spendry if (dvp) { 97165963Spendry int error; 97265963Spendry struct vnode *vp; 97365963Spendry struct mount *mp = ap->a_dvp->v_mount; 97465963Spendry 97565963Spendry VREF(dvp); 97665963Spendry VOP_LOCK(dvp); 97765963Spendry vput(ap->a_dvp); 97865963Spendry error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, 97965963Spendry ap->a_vap, ap->a_target); 980*65965Spendry *ap->a_vpp = 0; 98165963Spendry return (error); 98265963Spendry } 98365963Spendry 98465963Spendry vput(ap->a_dvp); 98565963Spendry return (EROFS); 98665963Spendry } 98765963Spendry 98865935Spendry /* 98965935Spendry * union_readdir works in concert with getdirentries and 99065935Spendry * readdir(3) to provide a list of entries in the unioned 99165935Spendry * directories. getdirentries is responsible for walking 99265935Spendry * down the union stack. readdir(3) is responsible for 99365935Spendry * eliminating duplicate names from the returned data stream. 99465935Spendry */ 99565935Spendry int 99665935Spendry union_readdir(ap) 99765935Spendry struct vop_readdir_args /* { 99865935Spendry struct vnodeop_desc *a_desc; 99965935Spendry struct vnode *a_vp; 100065935Spendry struct uio *a_uio; 100165935Spendry struct ucred *a_cred; 100265935Spendry } */ *ap; 100365935Spendry { 100465963Spendry int error = 0; 100565935Spendry struct union_node *un = VTOUNION(ap->a_vp); 100665935Spendry 100765963Spendry if (un->un_uppervp) { 100865963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 100965935Spendry 101065963Spendry VOP_LOCK(vp); 101165963Spendry error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 101265963Spendry VOP_UNLOCK(vp); 101365963Spendry } 101465963Spendry 101565963Spendry return (error); 101665935Spendry } 101765935Spendry 101865935Spendry int 101965963Spendry union_readlink(ap) 102065963Spendry struct vop_readlink_args /* { 102165963Spendry struct vnode *a_vp; 102265963Spendry struct uio *a_uio; 102365963Spendry struct ucred *a_cred; 102465963Spendry } */ *ap; 102565963Spendry { 102665963Spendry int error; 102765963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 102865963Spendry 102965963Spendry VOP_LOCK(vp); 103065963Spendry error = VOP_READLINK(vp, ap->a_uio, ap->a_cred); 103165963Spendry VOP_UNLOCK(vp); 103265963Spendry 103365963Spendry return (error); 103465963Spendry } 103565963Spendry 103665963Spendry int 103765963Spendry union_abortop(ap) 103865963Spendry struct vop_abortop_args /* { 103965963Spendry struct vnode *a_dvp; 104065963Spendry struct componentname *a_cnp; 104165963Spendry } */ *ap; 104265963Spendry { 104365963Spendry int error; 1044*65965Spendry struct vnode *vp = OTHERVP(ap->a_dvp); 104565963Spendry struct union_node *un = VTOUNION(ap->a_dvp); 104665963Spendry int islocked = un->un_flags & UN_LOCKED; 104765963Spendry 104865963Spendry if (islocked) 104965963Spendry VOP_LOCK(vp); 105065963Spendry error = VOP_ABORTOP(vp, ap->a_cnp); 105165963Spendry if (islocked) 105265963Spendry VOP_UNLOCK(vp); 105365963Spendry 105465963Spendry return (error); 105565963Spendry } 105665963Spendry 105765963Spendry int 105865935Spendry union_inactive(ap) 105965935Spendry struct vop_inactive_args /* { 106065935Spendry struct vnode *a_vp; 106165935Spendry } */ *ap; 106265935Spendry { 106365935Spendry 106465935Spendry /* 106565935Spendry * Do nothing (and _don't_ bypass). 106665935Spendry * Wait to vrele lowervp until reclaim, 106765935Spendry * so that until then our union_node is in the 106865935Spendry * cache and reusable. 106965935Spendry * 107065935Spendry * NEEDSWORK: Someday, consider inactive'ing 107165935Spendry * the lowervp and then trying to reactivate it 107265935Spendry * with capabilities (v_id) 107365935Spendry * like they do in the name lookup cache code. 107465935Spendry * That's too much work for now. 107565935Spendry */ 107665935Spendry return (0); 107765935Spendry } 107865935Spendry 107965935Spendry int 108065935Spendry union_reclaim(ap) 108165935Spendry struct vop_reclaim_args /* { 108265935Spendry struct vnode *a_vp; 108365935Spendry } */ *ap; 108465935Spendry { 108565935Spendry struct vnode *vp = ap->a_vp; 108665935Spendry struct union_node *un = VTOUNION(vp); 108765935Spendry struct vnode *uppervp = un->un_uppervp; 108865935Spendry struct vnode *lowervp = un->un_lowervp; 108965935Spendry struct vnode *dirvp = un->un_dirvp; 109065935Spendry char *path = un->un_path; 109165935Spendry 109265935Spendry /* 109365935Spendry * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p, 109465935Spendry * so we can't call VOPs on ourself. 109565935Spendry */ 109665935Spendry /* After this assignment, this node will not be re-used. */ 109765935Spendry un->un_uppervp = 0; 109865935Spendry un->un_lowervp = 0; 109965935Spendry un->un_dirvp = 0; 110065935Spendry un->un_path = NULL; 110165935Spendry union_freevp(vp); 110265935Spendry if (uppervp) 110365935Spendry vrele(uppervp); 110465935Spendry if (lowervp) 110565935Spendry vrele(lowervp); 110665935Spendry if (dirvp) 110765935Spendry vrele(dirvp); 110865935Spendry if (path) 110965935Spendry free(path, M_TEMP); 111065935Spendry return (0); 111165935Spendry } 111265935Spendry 111365963Spendry int 111465963Spendry union_lock(ap) 111565963Spendry struct vop_lock_args *ap; 111665963Spendry { 111765963Spendry struct union_node *un = VTOUNION(ap->a_vp); 111865935Spendry 1119*65965Spendry while (un->un_flags & UN_LOCKED) { 112065963Spendry #ifdef DIAGNOSTIC 1121*65965Spendry if (un->un_pid == curproc->p_pid) 1122*65965Spendry panic("union: locking agsinst myself"); 112365963Spendry #endif 112465963Spendry un->un_flags |= UN_WANT; 112565963Spendry sleep((caddr_t) &un->un_flags, PINOD); 112665963Spendry } 112765963Spendry un->un_flags |= UN_LOCKED; 112865963Spendry #ifdef DIAGNOSTIC 112965963Spendry un->un_pid = curproc->p_pid; 113065963Spendry #endif 113165963Spendry } 113265963Spendry 113365935Spendry int 113465963Spendry union_unlock(ap) 113565963Spendry struct vop_lock_args *ap; 113665963Spendry { 113765963Spendry struct union_node *un = VTOUNION(ap->a_vp); 113865963Spendry 113965963Spendry #ifdef DIAGNOSTIC 1140*65965Spendry if ((un->un_flags & UN_LOCKED) == 0) 1141*65965Spendry panic("union: unlock unlocked node"); 114265963Spendry if (un->un_pid != curproc->p_pid) 114365963Spendry panic("union: unlocking other process's union node"); 114465963Spendry #endif 114565963Spendry 114665963Spendry un->un_flags &= ~UN_LOCKED; 114765963Spendry if (un->un_flags & UN_WANT) { 114865963Spendry un->un_flags &= ~UN_WANT; 114965963Spendry wakeup((caddr_t) &un->un_flags); 115065963Spendry } 115165963Spendry 115265963Spendry #ifdef DIAGNOSTIC 115365963Spendry un->un_pid = 0; 115465963Spendry #endif 115565963Spendry } 115665963Spendry 115765963Spendry int 115865963Spendry union_bmap(ap) 115965963Spendry struct vop_bmap_args /* { 116065963Spendry struct vnode *a_vp; 116165963Spendry daddr_t a_bn; 116265963Spendry struct vnode **a_vpp; 116365963Spendry daddr_t *a_bnp; 116465963Spendry int *a_runp; 116565963Spendry } */ *ap; 116665963Spendry { 116765963Spendry int error; 116865963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 116965963Spendry 117065963Spendry VOP_LOCK(vp); 117165963Spendry error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp); 117265963Spendry VOP_UNLOCK(vp); 117365963Spendry 117465963Spendry return (error); 117565963Spendry } 117665963Spendry 117765963Spendry int 117865935Spendry union_print(ap) 117965935Spendry struct vop_print_args /* { 118065935Spendry struct vnode *a_vp; 118165935Spendry } */ *ap; 118265935Spendry { 118365935Spendry struct vnode *vp = ap->a_vp; 118465935Spendry 118565935Spendry printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n", 118665935Spendry vp, UPPERVP(vp), LOWERVP(vp)); 118765935Spendry return (0); 118865935Spendry } 118965935Spendry 119065963Spendry int 119165963Spendry union_islocked(ap) 119265963Spendry struct vop_islocked_args /* { 119365963Spendry struct vnode *a_vp; 119465963Spendry } */ *ap; 119565963Spendry { 119665935Spendry 119765963Spendry return ((VTOUNION(ap->a_vp)->un_flags & UN_LOCKED) ? 1 : 0); 119865963Spendry } 119965963Spendry 120065935Spendry int 120165963Spendry union_pathconf(ap) 120265963Spendry struct vop_pathconf_args /* { 120365963Spendry struct vnode *a_vp; 120465963Spendry int a_name; 120565963Spendry int *a_retval; 120665935Spendry } */ *ap; 120765935Spendry { 120865935Spendry int error; 120965963Spendry struct vnode *vp = OTHERVP(ap->a_vp); 121065935Spendry 121165963Spendry VOP_LOCK(vp); 121265963Spendry error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval); 121365963Spendry VOP_UNLOCK(vp); 121465935Spendry 121565963Spendry return (error); 121665963Spendry } 121765935Spendry 121865963Spendry int 121965963Spendry union_advlock(ap) 122065963Spendry struct vop_advlock_args /* { 122165963Spendry struct vnode *a_vp; 122265963Spendry caddr_t a_id; 122365963Spendry int a_op; 122465963Spendry struct flock *a_fl; 122565963Spendry int a_flags; 122665963Spendry } */ *ap; 122765963Spendry { 122865935Spendry 122965963Spendry return (VOP_ADVLOCK(OTHERVP(ap->a_vp), ap->a_id, ap->a_op, 123065963Spendry ap->a_fl, ap->a_flags)); 123165935Spendry } 123265935Spendry 123365935Spendry 123465935Spendry /* 123565963Spendry * XXX - vop_strategy must be hand coded because it has no 123665935Spendry * vnode in its arguments. 123765935Spendry * This goes away with a merged VM/buffer cache. 123865935Spendry */ 123965935Spendry int 124065963Spendry union_strategy(ap) 124165963Spendry struct vop_strategy_args /* { 124265935Spendry struct buf *a_bp; 124365935Spendry } */ *ap; 124465935Spendry { 124565935Spendry struct buf *bp = ap->a_bp; 124665935Spendry int error; 124765935Spendry struct vnode *savedvp; 124865935Spendry 124965935Spendry savedvp = bp->b_vp; 125065963Spendry bp->b_vp = OTHERVP(bp->b_vp); 125165935Spendry 125265935Spendry #ifdef DIAGNOSTIC 125365935Spendry if (bp->b_vp == 0) 125465963Spendry panic("union_strategy: nil vp"); 125565963Spendry if (((bp->b_flags & B_READ) == 0) && 125665963Spendry (bp->b_vp == LOWERVP(savedvp))) 125765963Spendry panic("union_strategy: writing to lowervp"); 125865935Spendry #endif 125965935Spendry 126065963Spendry error = VOP_STRATEGY(bp); 126165935Spendry bp->b_vp = savedvp; 126265935Spendry 126365935Spendry return (error); 126465935Spendry } 126565935Spendry 126665935Spendry /* 126765935Spendry * Global vfs data structures 126865935Spendry */ 126965935Spendry int (**union_vnodeop_p)(); 1270*65965Spendry struct vnodeopv_entry_desc union_vnodeop_entries[] = { 127165963Spendry { &vop_default_desc, vn_default_error }, 127265963Spendry { &vop_lookup_desc, union_lookup }, /* lookup */ 127365963Spendry { &vop_create_desc, union_create }, /* create */ 127465963Spendry { &vop_mknod_desc, union_mknod }, /* mknod */ 127565963Spendry { &vop_open_desc, union_open }, /* open */ 127665963Spendry { &vop_close_desc, union_close }, /* close */ 127765963Spendry { &vop_access_desc, union_access }, /* access */ 127865963Spendry { &vop_getattr_desc, union_getattr }, /* getattr */ 127965963Spendry { &vop_setattr_desc, union_setattr }, /* setattr */ 128065963Spendry { &vop_read_desc, union_read }, /* read */ 128165963Spendry { &vop_write_desc, union_write }, /* write */ 128265963Spendry { &vop_ioctl_desc, union_ioctl }, /* ioctl */ 128365963Spendry { &vop_select_desc, union_select }, /* select */ 128465963Spendry { &vop_mmap_desc, union_mmap }, /* mmap */ 128565963Spendry { &vop_fsync_desc, union_fsync }, /* fsync */ 128665963Spendry { &vop_seek_desc, union_seek }, /* seek */ 128765963Spendry { &vop_remove_desc, union_remove }, /* remove */ 128865963Spendry { &vop_link_desc, union_link }, /* link */ 128965963Spendry { &vop_rename_desc, union_rename }, /* rename */ 129065963Spendry { &vop_mkdir_desc, union_mkdir }, /* mkdir */ 129165963Spendry { &vop_rmdir_desc, union_rmdir }, /* rmdir */ 129265963Spendry { &vop_symlink_desc, union_symlink }, /* symlink */ 129365963Spendry { &vop_readdir_desc, union_readdir }, /* readdir */ 129465963Spendry { &vop_readlink_desc, union_readlink }, /* readlink */ 129565963Spendry { &vop_abortop_desc, union_abortop }, /* abortop */ 129665963Spendry { &vop_inactive_desc, union_inactive }, /* inactive */ 129765963Spendry { &vop_reclaim_desc, union_reclaim }, /* reclaim */ 129865963Spendry { &vop_lock_desc, union_lock }, /* lock */ 129965963Spendry { &vop_unlock_desc, union_unlock }, /* unlock */ 130065963Spendry { &vop_bmap_desc, union_bmap }, /* bmap */ 130165963Spendry { &vop_strategy_desc, union_strategy }, /* strategy */ 130265963Spendry { &vop_print_desc, union_print }, /* print */ 130365963Spendry { &vop_islocked_desc, union_islocked }, /* islocked */ 130465963Spendry { &vop_pathconf_desc, union_pathconf }, /* pathconf */ 130565963Spendry { &vop_advlock_desc, union_advlock }, /* advlock */ 130665963Spendry #ifdef notdef 130765963Spendry { &vop_blkatoff_desc, union_blkatoff }, /* blkatoff */ 130865963Spendry { &vop_valloc_desc, union_valloc }, /* valloc */ 130965963Spendry { &vop_vfree_desc, union_vfree }, /* vfree */ 131065963Spendry { &vop_truncate_desc, union_truncate }, /* truncate */ 131165963Spendry { &vop_update_desc, union_update }, /* update */ 131265963Spendry { &vop_bwrite_desc, union_bwrite }, /* bwrite */ 131365963Spendry #endif 131465935Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 131565935Spendry }; 131665935Spendry struct vnodeopv_desc union_vnodeop_opv_desc = 131765935Spendry { &union_vnodeop_p, union_vnodeop_entries }; 1318