checkpoint
[unix-history] / usr / src / sys / miscfs / union / union_subr.c
index 9199dcd..a963d7d 100644 (file)
@@ -8,7 +8,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)union_subr.c        1.1 (Berkeley) %G%
+ *     @(#)union_subr.c        1.4 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
 #include <sys/malloc.h>
 #include "union.h" /*<miscfs/union/union.h>*/
 
 #include <sys/malloc.h>
 #include "union.h" /*<miscfs/union/union.h>*/
 
+#ifdef DIAGNOSTIC
+#include <sys/proc.h>
+#endif
+
 static struct union_node *unhead;
 static int unvplock;
 
 static struct union_node *unhead;
 static int unvplock;
 
@@ -33,7 +37,14 @@ union_init()
 
 /*
  * allocate a union_node/vnode pair.  the vnode is
 
 /*
  * 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
  *
  * all union_nodes are maintained on a singly-linked
  * list.  new nodes are only allocated when they cannot
@@ -53,9 +64,10 @@ union_init()
  * the vnode free list.
  */
 int
  * the vnode free list.
  */
 int
-union_allocvp(vpp, mp, dvp, cnp, uppervp, lowervp)
+union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
        struct vnode **vpp;
        struct mount *mp;
        struct vnode **vpp;
        struct mount *mp;
+       struct vnode *undvp;
        struct vnode *dvp;              /* may be null */
        struct componentname *cnp;      /* may be null */
        struct vnode *uppervp;          /* may be null */
        struct vnode *dvp;              /* may be null */
        struct componentname *cnp;      /* may be null */
        struct vnode *uppervp;          /* may be null */
@@ -64,6 +76,15 @@ union_allocvp(vpp, mp, dvp, cnp, uppervp, lowervp)
        int error;
        struct union_node *un;
        struct union_node **pp;
        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) {
 
 loop:
        for (un = unhead; un != 0; un = un->un_next) {
@@ -72,11 +93,21 @@ loop:
                    (un->un_uppervp == uppervp ||
                     un->un_uppervp == 0) &&
                    (UNIONTOV(un)->v_mount == mp)) {
                    (un->un_uppervp == uppervp ||
                     un->un_uppervp == 0) &&
                    (UNIONTOV(un)->v_mount == mp)) {
-                       if (vget(un->un_vnode, 1))
+                       if (vget(UNIONTOV(un), 0))
                                goto loop;
                                goto loop;
-                       un->un_lowervp = lowervp;
-                       un->un_uppervp = uppervp;
-                       *vpp = un->un_vnode;
+                       if (UNIONTOV(un) != undvp)
+                               VOP_LOCK(UNIONTOV(un));
+                       if (uppervp != un->un_uppervp) {
+                               if (un->un_uppervp)
+                                       vrele(un->un_uppervp);
+                               un->un_uppervp = uppervp;
+                       }
+                       if (lowervp != un->un_lowervp) {
+                               if (un->un_lowervp)
+                                       vrele(un->un_lowervp);
+                               un->un_lowervp = lowervp;
+                       }
+                       *vpp = UNIONTOV(un);
                        return (0);
                }
        }
                        return (0);
                }
        }
@@ -99,30 +130,41 @@ loop:
        MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),
                M_TEMP, M_WAITOK);
 
        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 = VTOUNION(*vpp);
+       un->un_vnode = *vpp;
        un->un_next = 0;
        un->un_next = 0;
-       un->un_dirvp = dvp;
        un->un_uppervp = uppervp;
        un->un_lowervp = lowervp;
        un->un_uppervp = uppervp;
        un->un_lowervp = lowervp;
-       un->un_vnode = *vpp;
        un->un_flags = 0;
        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';
                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;
        } else {
                un->un_path = 0;
+               un->un_dirvp = 0;
        }
 
        }
 
-#ifdef DIAGNOSTIC
-       un->un_pid = 0;
-#endif
-
        /* add to union vnode list */
        for (pp = &unhead; *pp; pp = &(*pp)->un_next)
                continue;
        *pp = un;
 
        /* add to union vnode list */
        for (pp = &unhead; *pp; pp = &(*pp)->un_next)
                continue;
        *pp = un;
 
+       un->un_flags |= UN_LOCKED;
+
+#ifdef DIAGNOSTIC
+       un->un_pid = curproc->p_pid;
+#endif
+
+       if (xlowervp)
+               vrele(xlowervp);
+
 out:
        unvplock &= ~UN_LOCKED;
 
 out:
        unvplock &= ~UN_LOCKED;
 
@@ -131,9 +173,6 @@ out:
                wakeup((caddr_t) &unvplock);
        }
 
                wakeup((caddr_t) &unvplock);
        }
 
-       if (un)
-               VOP_LOCK(UNIONTOV(un));
-
        return (error);
 }
 
        return (error);
 }