From: Jan-Simon Pendry Date: Wed, 2 Feb 1994 12:45:36 +0000 (-0800) Subject: checkpoint X-Git-Tag: BSD-4_4_Lite1-Snapshot-Development~595 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/01dac67ecdefb2cd035518aee003b76c609a4865?hp=1bc31a3501b8f735c3f2e721aad70741b59c8baf checkpoint SCCS-vsn: sys/miscfs/union/union.h 1.3 SCCS-vsn: sys/miscfs/union/union_subr.c 1.3 SCCS-vsn: sys/miscfs/union/union_vnops.c 1.3 SCCS-vsn: sys/miscfs/union/union_vfsops.c 1.3 --- diff --git a/usr/src/sys/miscfs/union/union.h b/usr/src/sys/miscfs/union/union.h index b082a8eda5..74522c1447 100644 --- a/usr/src/sys/miscfs/union/union.h +++ b/usr/src/sys/miscfs/union/union.h @@ -8,7 +8,7 @@ * * %sccs.include.redist.c% * - * @(#)union.h 1.2 (Berkeley) %G% + * @(#)union.h 1.3 (Berkeley) %G% */ struct union_args { @@ -59,7 +59,7 @@ extern int union_node_create __P((struct mount *mp, struct vnode *target, struct #define VTOUNION(vp) ((struct union_node *)(vp)->v_data) #define UNIONTOV(un) ((un)->un_vnode) #define LOWERVP(vp) (VTOUNION(vp)->un_lowervp) -#define UPPERVP(vp) (VTOUNION(vp)->un_lowervp) +#define UPPERVP(vp) (VTOUNION(vp)->un_uppervp) #define OTHERVP(vp) (UPPERVP(vp) ? UPPERVP(vp) : LOWERVP(vp)) extern int (**union_vnodeop_p)(); diff --git a/usr/src/sys/miscfs/union/union_subr.c b/usr/src/sys/miscfs/union/union_subr.c index 3b77769ee2..71c7f1344f 100644 --- a/usr/src/sys/miscfs/union/union_subr.c +++ b/usr/src/sys/miscfs/union/union_subr.c @@ -8,7 +8,7 @@ * * %sccs.include.redist.c% * - * @(#)union_subr.c 1.2 (Berkeley) %G% + * @(#)union_subr.c 1.3 (Berkeley) %G% */ #include @@ -33,7 +33,14 @@ union_init() /* * allocate a union_node/vnode pair. the vnode is - * referenced and locked. + * referenced and locked. the new vnode is returned + * via (vpp). (mp) is the mountpoint of the union filesystem, + * (dvp) is the parent directory where the upper layer object + * should exist (but doesn't) and (cnp) is the componentname + * information which is partially copied to allow the upper + * layer object to be created at a later time. (uppervp) + * and (lowervp) reference the upper and lower layer objects + * being mapped. either, but not both, can be nil. * * all union_nodes are maintained on a singly-linked * list. new nodes are only allocated when they cannot @@ -64,6 +71,15 @@ union_allocvp(vpp, mp, dvp, cnp, uppervp, lowervp) int error; struct union_node *un; struct union_node **pp; + struct vnode *xlowervp = 0; + + if (uppervp == 0 && lowervp == 0) + panic("union: unidentifiable allocation"); + + if (uppervp && lowervp && (uppervp->v_type != lowervp->v_type)) { + xlowervp = lowervp; + lowervp = 0; + } loop: for (un = unhead; un != 0; un = un->un_next) { @@ -74,8 +90,10 @@ loop: (UNIONTOV(un)->v_mount == mp)) { if (vget(un->un_vnode, 1)) goto loop; - un->un_lowervp = lowervp; un->un_uppervp = uppervp; + if ((lowervp == 0) && un->un_lowervp) + vrele(un->un_lowervp); + un->un_lowervp = lowervp; *vpp = un->un_vnode; return (0); } @@ -99,19 +117,25 @@ loop: MALLOC((*vpp)->v_data, void *, sizeof(struct union_node), M_TEMP, M_WAITOK); + if (uppervp) + (*vpp)->v_type = uppervp->v_type; + else + (*vpp)->v_type = lowervp->v_type; un = VTOUNION(*vpp); un->un_next = 0; - un->un_dirvp = dvp; un->un_uppervp = uppervp; un->un_lowervp = lowervp; un->un_vnode = *vpp; un->un_flags = 0; - if (cnp) { + if (uppervp == 0 && cnp) { un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen); un->un_path[cnp->cn_namelen] = '\0'; + VREF(dvp); + un->un_dirvp = dvp; } else { un->un_path = 0; + un->un_dirvp = 0; } #ifdef DIAGNOSTIC @@ -123,6 +147,12 @@ loop: continue; *pp = un; + if (un) + un->un_flags |= UN_LOCKED; + + if (xlowervp) + vrele(xlowervp); + out: unvplock &= ~UN_LOCKED; @@ -131,9 +161,6 @@ out: wakeup((caddr_t) &unvplock); } - if (un) - VOP_LOCK(UNIONTOV(un)); - return (error); } diff --git a/usr/src/sys/miscfs/union/union_vfsops.c b/usr/src/sys/miscfs/union/union_vfsops.c index cc52f9e31c..2a5d97ebaf 100644 --- a/usr/src/sys/miscfs/union/union_vfsops.c +++ b/usr/src/sys/miscfs/union/union_vfsops.c @@ -8,7 +8,7 @@ * * %sccs.include.redist.c% * - * @(#)union_vfsops.c 1.2 (Berkeley) %G% + * @(#)union_vfsops.c 1.3 (Berkeley) %G% */ /* @@ -161,10 +161,14 @@ union_unmount(mp, mntflags, p) if (error = union_root(mp, &um_rootvp)) return (error); - if (um_rootvp->v_usecount > 1) + if (um_rootvp->v_usecount > 1) { + vput(um_rootvp); return (EBUSY); - if (error = vflush(mp, um_rootvp, flags)) + } + if (error = vflush(mp, um_rootvp, flags)) { + vput(um_rootvp); return (error); + } #ifdef UNION_DIAGNOSTIC vprint("alias root of lower", um_rootvp); @@ -178,7 +182,7 @@ union_unmount(mp, mntflags, p) /* * Release reference on underlying root vnode */ - vrele(um_rootvp); + vput(um_rootvp); /* * And blow it away for future re-use */ @@ -208,12 +212,19 @@ union_root(mp, vpp) /* * Return locked reference to root. */ + VREF(um->um_uppervp); + VREF(um->um_lowervp); error = union_allocvp(vpp, mp, (struct vnode *) 0, (struct componentname *) 0, um->um_uppervp, um->um_lowervp); - if (error == 0) + + if (error) { + vrele(um->um_uppervp); + vrele(um->um_lowervp); + } else { (*vpp)->v_flag |= VROOT; + } return (error); } diff --git a/usr/src/sys/miscfs/union/union_vnops.c b/usr/src/sys/miscfs/union/union_vnops.c index acde16cfd7..413e3be610 100644 --- a/usr/src/sys/miscfs/union/union_vnops.c +++ b/usr/src/sys/miscfs/union/union_vnops.c @@ -8,7 +8,7 @@ * * %sccs.include.redist.c% * - * @(#)union_vnops.c 1.2 (Berkeley) %G% + * @(#)union_vnops.c 1.3 (Berkeley) %G% */ #include @@ -25,6 +25,10 @@ #include #include "union.h" +/* + * Create a shadow directory in the upper layer. + * The new vnode is returned locked. + */ static int union_mkshadow(dvp, cnp, vpp) struct vnode *dvp; @@ -34,7 +38,6 @@ union_mkshadow(dvp, cnp, vpp) int error; struct vattr va; struct proc *p = cnp->cn_proc; - int lockparent = (cnp->cn_flags & LOCKPARENT); /* * policy: when creating the shadow directory in the @@ -49,13 +52,12 @@ union_mkshadow(dvp, cnp, vpp) VATTR_NULL(&va); va.va_type = VDIR; va.va_mode = UN_DIRMODE &~ p->p_fd->fd_cmask; - if (lockparent) - VOP_UNLOCK(dvp); + VOP_UNLOCK(dvp); LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE); + VREF(dvp); VOP_LOCK(dvp); error = VOP_MKDIR(dvp, vpp, cnp, &va); - if (lockparent) - VOP_LOCK(dvp); + VOP_LOCK(dvp); return (error); } @@ -102,7 +104,7 @@ union_lookup1(dvp, vpp, cnp) return (error); } - vput(tdvp); + vput(dvp); dvp = tdvp; } @@ -119,6 +121,7 @@ union_lookup(ap) struct componentname *a_cnp; } */ *ap; { + int error; int uerror, lerror; struct vnode *uppervp, *lowervp; struct vnode *upperdvp, *lowerdvp; @@ -127,8 +130,12 @@ union_lookup(ap) struct componentname *cnp = ap->a_cnp; int lockparent = cnp->cn_flags & LOCKPARENT; + cnp->cn_flags |= LOCKPARENT; + upperdvp = dun->un_uppervp; lowerdvp = dun->un_lowervp; + uppervp = 0; + lowervp = 0; /* * do the lookup in the upper level. @@ -138,13 +145,16 @@ union_lookup(ap) */ uppervp = 0; if (upperdvp) { + VOP_LOCK(upperdvp); uerror = union_lookup1(upperdvp, &uppervp, cnp); + VOP_UNLOCK(upperdvp); + if (cnp->cn_consume != 0) { *ap->a_vpp = uppervp; + if (!lockparent) + cnp->cn_flags &= ~LOCKPARENT; return (uerror); } - if (!lockparent) - VOP_LOCK(upperdvp); } else { uerror = ENOENT; } @@ -158,21 +168,27 @@ union_lookup(ap) */ lowervp = 0; if (lowerdvp) { + VOP_LOCK(lowerdvp); lerror = union_lookup1(lowerdvp, &lowervp, cnp); + VOP_UNLOCK(lowerdvp); + if (cnp->cn_consume != 0) { if (uppervp) { vput(uppervp); uppervp = 0; } *ap->a_vpp = lowervp; + if (!lockparent) + cnp->cn_flags &= ~LOCKPARENT; return (lerror); } - if (!lockparent) - VOP_LOCK(lowerdvp); } else { lerror = ENOENT; } + if (!lockparent) + cnp->cn_flags &= ~LOCKPARENT; + /* * at this point, we have uerror and lerror indicating * possible errors with the lookups in the upper and lower @@ -206,7 +222,9 @@ union_lookup(ap) /* case 2. */ if (uerror != 0 /* && (lerror == 0) */ ) { if (lowervp->v_type == VDIR) { /* case 2b. */ + VOP_LOCK(upperdvp); uerror = union_mkshadow(upperdvp, cnp, &uppervp); + VOP_UNLOCK(upperdvp); if (uerror) { if (lowervp) { vput(lowervp); @@ -217,8 +235,25 @@ union_lookup(ap) } } - return (union_allocvp(ap->a_vpp, dvp->v_mount, dvp, cnp, - uppervp, lowervp)); + error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, cnp, + uppervp, lowervp); + + if (uppervp) + VOP_UNLOCK(uppervp); + if (lowervp) + VOP_UNLOCK(lowervp); + + if (error) { + if (uppervp) + vrele(uppervp); + if (lowervp) + vrele(lowervp); + } else { + if (!lockparent) + VOP_UNLOCK(*ap->a_vpp); + } + + return (error); } int @@ -248,10 +283,13 @@ union_create(ap) error = union_allocvp( ap->a_vpp, mp, - un->un_uppervp, + NULLVP, ap->a_cnp, vp, NULLVP); + VOP_UNLOCK(vp); + if (error) + vrele(vp); return (error); } @@ -283,13 +321,18 @@ union_mknod(ap) if (error) return (error); - error = union_allocvp( - ap->a_vpp, - mp, - un->un_uppervp, - ap->a_cnp, - vp, - NULLVP); + if (vp) { + error = union_allocvp( + ap->a_vpp, + mp, + NULLVP, + ap->a_cnp, + vp, + NULLVP); + VOP_UNLOCK(vp); + if (error) + vrele(vp); + } return (error); } @@ -377,81 +420,86 @@ union_open(ap) } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + struct vnode *tvp; int mode = ap->a_mode; struct ucred *cred = ap->a_cred; struct proc *p = ap->a_p; + int error; /* * If there is an existing upper vp then simply open that. */ - if (un->un_uppervp) { - int error; - - VOP_LOCK(un->un_uppervp); - error = VOP_OPEN(un->un_uppervp, mode, cred, p); - VOP_UNLOCK(un->un_lowervp); - - return (error); - } - - /* - * If the lower vnode is being opened for writing, then - * copy the file contents to the upper vnode and open that, - * otherwise can simply open the lower vnode. - */ - if ((ap->a_mode & FWRITE) && (un->un_lowervp->v_type == VREG)) { - int error; - struct nameidata nd; - struct filedesc *fdp = p->p_fd; - int fmode; - int cmode; - - /* - * Open the named file in the upper layer. Note that - * the file may have come into existence *since* the lookup - * was done, since the upper layer may really be a - * loopback mount of some other filesystem... so open - * the file with exclusive create and barf if it already - * exists. - * XXX - perhaps shoudl re-lookup the node (once more with - * feeling) and simply open that. Who knows. - */ - NDINIT(&nd, CREATE, 0, UIO_SYSSPACE, un->un_path, p); - fmode = (O_CREAT|O_TRUNC|O_EXCL); - cmode = UN_FILEMODE & ~fdp->fd_cmask; - error = vn_open(&nd, fmode, cmode); - if (error) - return (error); - un->un_uppervp = nd.ni_vp; /* XXX */ - /* at this point, uppervp is locked */ - + tvp = un->un_uppervp; + if (tvp == NULLVP) { /* - * Now, if the file is being opened with truncation, then - * the (new) upper vnode is ready to fly, otherwise the - * data from the lower vnode must be copied to the upper - * layer first. This only works for regular files (check - * is made above). + * If the lower vnode is being opened for writing, then + * copy the file contents to the upper vnode and open that, + * otherwise can simply open the lower vnode. */ - if ((mode & O_TRUNC) == 0) { - /* XXX - should not ignore errors from VOP_CLOSE */ - VOP_LOCK(un->un_lowervp); - error = VOP_OPEN(un->un_lowervp, FREAD, cred, p); - if (error == 0) { - error = union_copyfile(p, cred, - un->un_lowervp, un->un_uppervp); - (void) VOP_CLOSE(un->un_lowervp, FREAD); + tvp = un->un_lowervp; + if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) { + struct nameidata nd; + struct filedesc *fdp = p->p_fd; + int fmode; + int cmode; + + /* + * Open the named file in the upper layer. Note that + * the file may have come into existence *since* the + * lookup was done, since the upper layer may really + * be a loopback mount of some other filesystem... + * so open the file with exclusive create and barf if + * it already exists. + * XXX - perhaps shoudl re-lookup the node (once more + * with feeling) and simply open that. Who knows. + */ + NDINIT(&nd, CREATE, 0, UIO_SYSSPACE, un->un_path, p); + fmode = (O_CREAT|O_TRUNC|O_EXCL); + cmode = UN_FILEMODE & ~fdp->fd_cmask; + error = vn_open(&nd, fmode, cmode); + if (error) + return (error); + un->un_uppervp = nd.ni_vp; /* XXX */ + /* at this point, uppervp is locked */ + + /* + * Now, if the file is being opened with truncation, + * then the (new) upper vnode is ready to fly, + * otherwise the data from the lower vnode must be + * copied to the upper layer first. This only works + * for regular files (check is made above). + */ + if ((mode & O_TRUNC) == 0) { + /* + * XXX - should not ignore errors + * from VOP_CLOSE + */ + VOP_LOCK(un->un_lowervp); + error = VOP_OPEN(tvp, FREAD, cred, p); + if (error == 0) { + error = union_copyfile(p, cred, + tvp, un->un_uppervp); + VOP_UNLOCK(tvp); + (void) VOP_CLOSE(tvp, FREAD); + } else { + VOP_UNLOCK(tvp); + } + VOP_UNLOCK(un->un_uppervp); + (void) VOP_CLOSE(un->un_uppervp, FWRITE); + VOP_LOCK(un->un_uppervp); } - VOP_UNLOCK(un->un_lowervp); + if (error == 0) + error = VOP_OPEN(un->un_uppervp, mode, cred, p); VOP_UNLOCK(un->un_uppervp); - (void) VOP_CLOSE(un->un_uppervp, FWRITE); - VOP_LOCK(un->un_uppervp); + return (error); } - if (error == 0) - error = VOP_OPEN(un->un_uppervp, FREAD, cred, p); - return (error); } - return (VOP_OPEN(un->un_lowervp, mode, cred, p)); + VOP_LOCK(tvp); + error = VOP_OPEN(tvp, mode, cred, p); + VOP_UNLOCK(tvp); + + return (error); } int @@ -486,20 +534,24 @@ union_access(ap) } */ *ap; { struct union_node *un = VTOUNION(ap->a_vp); + int error = 0; struct vnode *vp; if (vp = un->un_lowervp) { - int error; - + VOP_LOCK(vp); error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); + VOP_UNLOCK(vp); if (error) return (error); } - if (vp = un->un_uppervp) - return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p)); - - return (0); + if (vp = un->un_uppervp) { + VOP_LOCK(vp); + error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p); + VOP_UNLOCK(vp); + } + + return (error); } /* @@ -515,16 +567,19 @@ union_getattr(ap) } */ *ap; { int error; + struct vnode *vp = OTHERVP(ap->a_vp); + + VOP_LOCK(vp); + error = VOP_GETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p); + VOP_UNLOCK(vp); - if (error = union_bypass(ap)) - return (error); /* Requires that arguments be restored. */ ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; return (0); } int -lofs_setattr(ap) +union_setattr(ap) struct vop_setattr_args /* { struct vnode *a_vp; struct vattr *a_vap; @@ -564,9 +619,9 @@ union_read(ap) int error; struct vnode *vp = OTHERVP(ap->a_vp); - VOP_LOCKvp); + VOP_LOCK(vp); error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); - VOP_UNLOCKvp); + VOP_UNLOCK(vp); return (error); } @@ -849,10 +904,13 @@ union_mkdir(ap) error = union_allocvp( ap->a_vpp, mp, - un->un_uppervp, + NULLVP, ap->a_cnp, vp, NULLVP); + VOP_UNLOCK(vp); + if (error) + vrele(vp); return (error); } @@ -919,17 +977,7 @@ union_symlink(ap) vput(ap->a_dvp); error = VOP_SYMLINK(dvp, &vp, ap->a_cnp, ap->a_vap, ap->a_target); - if (error) - return (error); - - error = union_allocvp( - ap->a_vpp, - mp, - un->un_uppervp, - ap->a_cnp, - vp, - NULLVP); - vput(*ap->a_vpp); + *ap->a_vpp = 0; return (error); } @@ -993,7 +1041,7 @@ union_abortop(ap) } */ *ap; { int error; - struct vnode *vp = OTHERVP(a->a_dvp); + struct vnode *vp = OTHERVP(ap->a_dvp); struct union_node *un = VTOUNION(ap->a_dvp); int islocked = un->un_flags & UN_LOCKED; @@ -1068,11 +1116,11 @@ union_lock(ap) { struct union_node *un = VTOUNION(ap->a_vp); + while (un->un_flags & UN_LOCKED) { #ifdef DIAGNOSTIC - if (un->un_pid == curproc->p_pid) - panic("union: locking agsinst myself"); + if (un->un_pid == curproc->p_pid) + panic("union: locking agsinst myself"); #endif - while (un->un_flags & UN_LOCKED) { un->un_flags |= UN_WANT; sleep((caddr_t) &un->un_flags, PINOD); } @@ -1089,10 +1137,10 @@ union_unlock(ap) struct union_node *un = VTOUNION(ap->a_vp); #ifdef DIAGNOSTIC - if (un->un_pid != curproc->p_pid) - panic("union: unlocking other process's union node"); if ((un->un_flags & UN_LOCKED) == 0) panic("union: unlock unlocked node"); + if (un->un_pid != curproc->p_pid) + panic("union: unlocking other process's union node"); #endif un->un_flags &= ~UN_LOCKED; @@ -1219,7 +1267,7 @@ union_strategy(ap) * Global vfs data structures */ int (**union_vnodeop_p)(); -struct vnodeopv_entry_desc lofs_vnodeop_entries[] = { +struct vnodeopv_entry_desc union_vnodeop_entries[] = { { &vop_default_desc, vn_default_error }, { &vop_lookup_desc, union_lookup }, /* lookup */ { &vop_create_desc, union_create }, /* create */