-
-int union_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
-
-/*
- * This is the 10-Apr-92 bypass routine.
- * This version has been optimized for speed, throwing away some
- * safety checks. It should still always work, but it's not as
- * robust to programmer errors.
- * Define SAFETY to include some error checking code.
- *
- * In general, we map all vnodes going down and unmap them on the way back.
- * As an exception to this, vnodes can be marked "unmapped" by setting
- * the Nth bit in operation's vdesc_flags.
- *
- * Also, some BSD vnode operations have the side effect of vrele'ing
- * their arguments. With stacking, the reference counts are held
- * by the upper node, not the lower one, so we must handle these
- * side-effects here. This is not of concern in Sun-derived systems
- * since there are no such side-effects.
- *
- * This makes the following assumptions:
- * - only one returned vpp
- * - no INOUT vpp's (Sun's vop_open has one of these)
- * - the vnode operation vector of the first vnode should be used
- * to determine what implementation of the op should be invoked
- * - all mapped vnodes are of our vnode-type (NEEDSWORK:
- * problems on rmdir'ing mount points and renaming?)
- */
-int
-union_bypass(ap)
- struct vop_generic_args /* {
- struct vnodeop_desc *a_desc;
- <other random data follows, presumably>
- } */ *ap;
-{
- struct vnode **this_vp_p;
- int error;
- struct vnode *old_vps[VDESC_MAX_VPS];
- struct vnode **vps_p[VDESC_MAX_VPS];
- struct vnode ***vppp;
- struct vnodeop_desc *descp = ap->a_desc;
- int reles, i;
-
- if (union_bug_bypass)
- printf ("union_bypass: %s\n", descp->vdesc_name);
-
-#ifdef SAFETY
- /*
- * We require at least one vp.
- */
- if (descp->vdesc_vp_offsets == NULL ||
- descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
- panic ("union_bypass: no vp's in map.\n");
-#endif
-
- /*
- * Map the vnodes going in.
- * Later, we'll invoke the operation based on
- * the first mapped vnode's operation vector.
- */
- reles = descp->vdesc_flags;
- for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
- if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
- break; /* bail out at end of list */
- vps_p[i] = this_vp_p =
- VOPARG_OFFSETTO(struct vnode **, descp->vdesc_vp_offsets[i],ap);
- /*
- * We're not guaranteed that any but the first vnode
- * are of our type. Check for and don't map any
- * that aren't. (We must always map first vp or vclean fails.)
- */
- if (i && (*this_vp_p)->v_op != union_vnodeop_p) {
- old_vps[i] = NULL;
- } else {
- old_vps[i] = *this_vp_p;
- *(vps_p[i]) = OTHERVP(*this_vp_p);
- /*
- * XXX - Several operations have the side effect
- * of vrele'ing their vp's. We must account for
- * that. (This should go away in the future.)
- */
- if (reles & 1)
- VREF(*this_vp_p);
- }
-
- }
-
- /*
- * Call the operation on the lower layer
- * with the modified argument structure.
- */
- error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
-
- /*
- * Maintain the illusion of call-by-value
- * by restoring vnodes in the argument structure
- * to their original value.
- */
- reles = descp->vdesc_flags;
- for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
- if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
- break; /* bail out at end of list */
- if (old_vps[i]) {
- *(vps_p[i]) = old_vps[i];
- if (reles & 1)
- vrele(*(vps_p[i]));
- }
- }
-
- /*
- * Map the possible out-going vpp
- * (Assumes that the lower layer always returns
- * a VREF'ed vpp unless it gets an error.)
- */
- if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
- !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
- !error) {
- /*
- * XXX - even though some ops have vpp returned vp's,
- * several ops actually vrele this before returning.
- * We must avoid these ops.
- * (This should go away when these ops are regularized.)
- */
- if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
- goto out;
- vppp = VOPARG_OFFSETTO(struct vnode***,
- descp->vdesc_vpp_offset,ap);
- panic("union: failed to handled returned vnode");
- error = union_allocvp(0, 0, 0, 0, 0, 0);
- }
-
-out:
- return (error);
-}
-
-/*
- * Check access permission on the union vnode.
- * The access check being enforced is to check
- * against both the underlying vnode, and any
- * copied vnode. This ensures that no additional
- * file permissions are given away simply because
- * the user caused an implicit file copy.
- */
-int
-union_access(ap)
- struct vop_access_args /* {
- struct vnodeop_desc *a_desc;
- struct vnode *a_vp;
- int a_mode;
- struct ucred *a_cred;
- struct proc *a_p;
- } */ *ap;
-{
- struct union_node *un = VTOUNION(ap->a_vp);
- struct vnode *vp;
-
- if (vp = un->un_lowervp) {
- int error;
-
- error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);
- if (error)
- return (error);
- }
-
- if (vp = un->un_uppervp)
- return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p));
-
- return (0);