add union_revoke operator
[unix-history] / usr / src / sys / miscfs / union / union_vnops.c
index fa576fb..2de83d4 100644 (file)
@@ -1,14 +1,14 @@
 /*
 /*
- * Copyright (c) 1992, 1993, 1994 The Regents of the University of California.
- * Copyright (c) 1992, 1993, 1994 Jan-Simon Pendry.
- * All rights reserved.
+ * Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
+ * Copyright (c) 1992, 1993, 1994, 1995
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Jan-Simon Pendry.
  *
  * %sccs.include.redist.c%
  *
  *
  * This code is derived from software contributed to Berkeley by
  * Jan-Simon Pendry.
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union_vnops.c       8.19 (Berkeley) %G%
+ *     @(#)union_vnops.c       8.26 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -311,7 +311,7 @@ union_lookup(ap)
                VOP_UNLOCK(lowervp);
 
        error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
                VOP_UNLOCK(lowervp);
 
        error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
-                             uppervp, lowervp);
+                             uppervp, lowervp, 1);
 
        if (error) {
                if (uppervp != NULLVP)
 
        if (error) {
                if (uppervp != NULLVP)
@@ -342,11 +342,13 @@ union_create(ap)
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
+               struct mount *mp;
 
                FIXUP(un);
 
                VREF(dvp);
                un->un_flags |= UN_KLOCK;
 
                FIXUP(un);
 
                VREF(dvp);
                un->un_flags |= UN_KLOCK;
+               mp = ap->a_dvp->v_mount;
                vput(ap->a_dvp);
                error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap);
                if (error)
                vput(ap->a_dvp);
                error = VOP_CREATE(dvp, &vp, ap->a_cnp, ap->a_vap);
                if (error)
@@ -354,12 +356,13 @@ union_create(ap)
 
                error = union_allocvp(
                                ap->a_vpp,
 
                error = union_allocvp(
                                ap->a_vpp,
-                               ap->a_dvp->v_mount,
-                               ap->a_dvp,
+                               mp,
+                               NULLVP,
                                NULLVP,
                                ap->a_cnp,
                                vp,
                                NULLVP,
                                ap->a_cnp,
                                vp,
-                               NULLVP);
+                               NULLVP,
+                               1);
                if (error)
                        vput(vp);
                return (error);
                if (error)
                        vput(vp);
                return (error);
@@ -401,11 +404,13 @@ union_mknod(ap)
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
        if (dvp != NULLVP) {
                int error;
                struct vnode *vp;
+               struct mount *mp;
 
                FIXUP(un);
 
                VREF(dvp);
                un->un_flags |= UN_KLOCK;
 
                FIXUP(un);
 
                VREF(dvp);
                un->un_flags |= UN_KLOCK;
+               mp = ap->a_dvp->v_mount;
                vput(ap->a_dvp);
                error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap);
                if (error)
                vput(ap->a_dvp);
                error = VOP_MKNOD(dvp, &vp, ap->a_cnp, ap->a_vap);
                if (error)
@@ -414,12 +419,13 @@ union_mknod(ap)
                if (vp != NULLVP) {
                        error = union_allocvp(
                                        ap->a_vpp,
                if (vp != NULLVP) {
                        error = union_allocvp(
                                        ap->a_vpp,
-                                       ap->a_dvp->v_mount,
-                                       ap->a_dvp,
+                                       mp,
+                                       NULLVP,
                                        NULLVP,
                                        ap->a_cnp,
                                        vp,
                                        NULLVP,
                                        ap->a_cnp,
                                        vp,
-                                       NULLVP);
+                                       NULLVP,
+                                       1);
                        if (error)
                                vput(vp);
                }
                        if (error)
                                vput(vp);
                }
@@ -614,9 +620,7 @@ union_getattr(ap)
        }
 
        if (vp != NULLVP) {
        }
 
        if (vp != NULLVP) {
-               VOP_LOCK(vp);
                error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
                error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
-               VOP_UNLOCK(vp);
                if (error)
                        return (error);
                union_newsize(ap->a_vp, VNOVAL, vap->va_size);
                if (error)
                        return (error);
                union_newsize(ap->a_vp, VNOVAL, vap->va_size);
@@ -749,6 +753,18 @@ union_write(ap)
        return (error);
 }
 
        return (error);
 }
 
+union_lease(ap)
+       struct vop_lease_args /* {
+               struct vnode *a_vp;
+               struct proc *a_p;
+               struct ucred *a_cred;
+               int a_flag;
+       } */ *ap;
+{
+
+       return (VOP_LEASE(OTHERVP(ap->a_vp), ap->a_p, ap->a_cred, ap->a_flag));
+}
+
 int
 union_ioctl(ap)
        struct vop_ioctl_args /* {
 int
 union_ioctl(ap)
        struct vop_ioctl_args /* {
@@ -780,6 +796,22 @@ union_select(ap)
                                ap->a_cred, ap->a_p));
 }
 
                                ap->a_cred, ap->a_p));
 }
 
+int
+union_revoke(ap)
+       struct vop_revoke_args /* {
+               struct vnode *a_vp;
+               int a_flags;
+       } */ *ap;
+{
+       struct vnode *vp = ap->a_vp;
+
+       if (UPPERVP(vp))
+               VOP_REVOKE(UPPERVP(vp), ap->a_flags);
+       if (LOWERVP(vp))
+               VOP_REVOKE(UPPERVP(vp), ap->a_flags);
+       vgone(vp);
+}
+
 int
 union_mmap(ap)
        struct vop_mmap_args /* {
 int
 union_mmap(ap)
        struct vop_mmap_args /* {
@@ -853,6 +885,7 @@ union_remove(ap)
        if (un->un_uppervp != NULLVP) {
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
        if (un->un_uppervp != NULLVP) {
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
+               struct componentname *cnp = ap->a_cnp;
 
                FIXUP(dun);
                VREF(dvp);
 
                FIXUP(dun);
                VREF(dvp);
@@ -863,9 +896,9 @@ union_remove(ap)
                un->un_flags |= UN_KLOCK;
                vput(ap->a_vp);
 
                un->un_flags |= UN_KLOCK;
                vput(ap->a_vp);
 
-               if (un->un_lowervp != NULLVP)
-                       ap->a_cnp->cn_flags |= DOWHITEOUT;
-               error = VOP_REMOVE(dvp, vp, ap->a_cnp);
+               if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
+                       cnp->cn_flags |= DOWHITEOUT;
+               error = VOP_REMOVE(dvp, vp, cnp);
                if (!error)
                        union_removed_upper(un);
        } else {
                if (!error)
                        union_removed_upper(un);
        } else {
@@ -893,42 +926,42 @@ union_link(ap)
        struct vnode *vp;
        struct vnode *tdvp;
 
        struct vnode *vp;
        struct vnode *tdvp;
 
-       un = VTOUNION(ap->a_vp);
+       un = VTOUNION(ap->a_tdvp);
 
 
-       if (ap->a_vp->v_op != ap->a_tdvp->v_op) {
-               tdvp = ap->a_tdvp;
+       if (ap->a_tdvp->v_op != ap->a_vp->v_op) {
+               vp = ap->a_vp;
        } else {
        } else {
-               struct union_node *tdun = VTOUNION(ap->a_tdvp);
-               if (tdun->un_uppervp == NULLVP) {
-                       VOP_LOCK(ap->a_tdvp);
-                       if (un->un_uppervp == tdun->un_dirvp) {
+               struct union_node *tun = VTOUNION(ap->a_vp);
+               if (tun->un_uppervp == NULLVP) {
+                       VOP_LOCK(ap->a_vp);
+                       if (un->un_uppervp == tun->un_dirvp) {
                                un->un_flags &= ~UN_ULOCK;
                                VOP_UNLOCK(un->un_uppervp);
                        }
                                un->un_flags &= ~UN_ULOCK;
                                VOP_UNLOCK(un->un_uppervp);
                        }
-                       error = union_copyup(tdun, 1, ap->a_cnp->cn_cred,
+                       error = union_copyup(tun, 1, ap->a_cnp->cn_cred,
                                                ap->a_cnp->cn_proc);
                                                ap->a_cnp->cn_proc);
-                       if (un->un_uppervp == tdun->un_dirvp) {
+                       if (un->un_uppervp == tun->un_dirvp) {
                                VOP_LOCK(un->un_uppervp);
                                un->un_flags |= UN_ULOCK;
                        }
                                VOP_LOCK(un->un_uppervp);
                                un->un_flags |= UN_ULOCK;
                        }
-                       VOP_UNLOCK(ap->a_tdvp);
+                       VOP_UNLOCK(ap->a_vp);
                }
                }
-               tdvp = tdun->un_uppervp;
+               vp = tun->un_uppervp;
        }
 
        }
 
-       vp = un->un_uppervp;
-       if (vp == NULLVP)
+       tdvp = un->un_uppervp;
+       if (tdvp == NULLVP)
                error = EROFS;
 
        if (error) {
                error = EROFS;
 
        if (error) {
-               vput(ap->a_vp);
+               vput(ap->a_tdvp);
                return (error);
        }
 
        FIXUP(un);
                return (error);
        }
 
        FIXUP(un);
-       VREF(vp);
+       VREF(tdvp);
        un->un_flags |= UN_KLOCK;
        un->un_flags |= UN_KLOCK;
-       vput(ap->a_vp);
+       vput(ap->a_tdvp);
 
        return (VOP_LINK(vp, tdvp, ap->a_cnp));
 }
 
        return (VOP_LINK(vp, tdvp, ap->a_cnp));
 }
@@ -1046,10 +1079,12 @@ union_mkdir(ap)
                FIXUP(un);
                VREF(dvp);
                un->un_flags |= UN_KLOCK;
                FIXUP(un);
                VREF(dvp);
                un->un_flags |= UN_KLOCK;
-               vput(ap->a_dvp);
+               VOP_UNLOCK(ap->a_dvp);
                error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap);
                error = VOP_MKDIR(dvp, &vp, ap->a_cnp, ap->a_vap);
-               if (error)
+               if (error) {
+                       vrele(ap->a_dvp);
                        return (error);
                        return (error);
+               }
 
                error = union_allocvp(
                                ap->a_vpp,
 
                error = union_allocvp(
                                ap->a_vpp,
@@ -1058,7 +1093,9 @@ union_mkdir(ap)
                                NULLVP,
                                ap->a_cnp,
                                vp,
                                NULLVP,
                                ap->a_cnp,
                                vp,
-                               NULLVP);
+                               NULLVP,
+                               1);
+               vrele(ap->a_dvp);
                if (error)
                        vput(vp);
                return (error);
                if (error)
                        vput(vp);
                return (error);
@@ -1086,6 +1123,7 @@ union_rmdir(ap)
        if (un->un_uppervp != NULLVP) {
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
        if (un->un_uppervp != NULLVP) {
                struct vnode *dvp = dun->un_uppervp;
                struct vnode *vp = un->un_uppervp;
+               struct componentname *cnp = ap->a_cnp;
 
                FIXUP(dun);
                VREF(dvp);
 
                FIXUP(dun);
                VREF(dvp);
@@ -1096,8 +1134,8 @@ union_rmdir(ap)
                un->un_flags |= UN_KLOCK;
                vput(ap->a_vp);
 
                un->un_flags |= UN_KLOCK;
                vput(ap->a_vp);
 
-               if (un->un_lowervp != NULLVP)
-                       ap->a_cnp->cn_flags |= DOWHITEOUT;
+               if (union_dowhiteout(un, cnp->cn_cred, cnp->cn_proc))
+                       cnp->cn_flags |= DOWHITEOUT;
                error = VOP_RMDIR(dvp, vp, ap->a_cnp);
                if (!error)
                        union_removed_upper(un);
                error = VOP_RMDIR(dvp, vp, ap->a_cnp);
                if (!error)
                        union_removed_upper(un);
@@ -1231,6 +1269,7 @@ union_inactive(ap)
        } */ *ap;
 {
        struct union_node *un = VTOUNION(ap->a_vp);
        } */ *ap;
 {
        struct union_node *un = VTOUNION(ap->a_vp);
+       struct vnode **vpp;
 
        /*
         * Do nothing (and _don't_ bypass).
 
        /*
         * Do nothing (and _don't_ bypass).
@@ -1252,6 +1291,13 @@ union_inactive(ap)
                panic("union: inactivating w/locked upper node");
 #endif
 
                panic("union: inactivating w/locked upper node");
 #endif
 
+       if (un->un_dircache != 0) {
+               for (vpp = un->un_dircache; *vpp != NULLVP; vpp++)
+                       vrele(*vpp);
+               free(un->un_dircache, M_TEMP);
+               un->un_dircache = 0;
+       }
+
        if ((un->un_flags & UN_CACHED) == 0)
                vgone(ap->a_vp);
 
        if ((un->un_flags & UN_CACHED) == 0)
                vgone(ap->a_vp);
 
@@ -1288,12 +1334,14 @@ start:
        if (un->un_uppervp != NULLVP) {
                if (((un->un_flags & UN_ULOCK) == 0) &&
                    (vp->v_usecount != 0)) {
        if (un->un_uppervp != NULLVP) {
                if (((un->un_flags & UN_ULOCK) == 0) &&
                    (vp->v_usecount != 0)) {
-                       un->un_flags |= UN_ULOCK;
                        VOP_LOCK(un->un_uppervp);
                        VOP_LOCK(un->un_uppervp);
+                       un->un_flags |= UN_ULOCK;
                }
 #ifdef DIAGNOSTIC
                }
 #ifdef DIAGNOSTIC
-               if (un->un_flags & UN_KLOCK)
-                       panic("union: dangling upper lock");
+               if (un->un_flags & UN_KLOCK) {
+                       vprint("union: dangling klock", vp);
+                       panic("union: dangling upper lock (%lx)", vp);
+               }
 #endif
        }
 
 #endif
        }
 
@@ -1319,6 +1367,17 @@ start:
        return (0);
 }
 
        return (0);
 }
 
+/*
+ * When operations want to vput() a union node yet retain a lock on
+ * the upper vnode (say, to do some further operations like link(),
+ * mkdir(), ...), they set UN_KLOCK on the union node, then call
+ * vput() which calls VOP_UNLOCK() and comes here.  union_unlock()
+ * unlocks the union node (leaving the upper vnode alone), clears the
+ * KLOCK flag, and then returns to vput().  The caller then does whatever
+ * is left to do with the upper vnode, and ensures that it gets unlocked.
+ *
+ * If UN_KLOCK isn't set, then the upper vnode is unlocked here.
+ */
 int
 union_unlock(ap)
        struct vop_lock_args *ap;
 int
 union_unlock(ap)
        struct vop_lock_args *ap;
@@ -1387,6 +1446,11 @@ union_print(ap)
 
        printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n",
                        vp, UPPERVP(vp), LOWERVP(vp));
 
        printf("\ttag VT_UNION, vp=%x, uppervp=%x, lowervp=%x\n",
                        vp, UPPERVP(vp), LOWERVP(vp));
+       if (UPPERVP(vp) != NULLVP)
+               vprint("union: upper", UPPERVP(vp));
+       if (LOWERVP(vp) != NULLVP)
+               vprint("union: lower", LOWERVP(vp));
+
        return (0);
 }
 
        return (0);
 }
 
@@ -1488,8 +1552,10 @@ struct vnodeopv_entry_desc union_vnodeop_entries[] = {
        { &vop_setattr_desc, union_setattr },           /* setattr */
        { &vop_read_desc, union_read },                 /* read */
        { &vop_write_desc, union_write },               /* write */
        { &vop_setattr_desc, union_setattr },           /* setattr */
        { &vop_read_desc, union_read },                 /* read */
        { &vop_write_desc, union_write },               /* write */
+       { &vop_lease_desc, union_lease },               /* lease */
        { &vop_ioctl_desc, union_ioctl },               /* ioctl */
        { &vop_select_desc, union_select },             /* select */
        { &vop_ioctl_desc, union_ioctl },               /* ioctl */
        { &vop_select_desc, union_select },             /* select */
+       { &vop_revoke_desc, union_revoke },             /* revoke */
        { &vop_mmap_desc, union_mmap },                 /* mmap */
        { &vop_fsync_desc, union_fsync },               /* fsync */
        { &vop_seek_desc, union_seek },                 /* seek */
        { &vop_mmap_desc, union_mmap },                 /* mmap */
        { &vop_fsync_desc, union_fsync },               /* fsync */
        { &vop_seek_desc, union_seek },                 /* seek */