*
* %sccs.include.redist.c%
*
- * @(#)union_vnops.c 2.2 (Berkeley) %G%
+ * @(#)union_vnops.c 8.18 (Berkeley) %G%
*/
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/queue.h>
-#include "union.h"
+#include <miscfs/union/union.h>
+
+#define FIXUP(un) { \
+ if (((un)->un_flags & UN_ULOCK) == 0) { \
+ union_fixup(un); \
+ } \
+}
+
+static void
+union_fixup(un)
+ struct union_node *un;
+{
+
+ VOP_LOCK(un->un_uppervp);
+ un->un_flags |= UN_ULOCK;
+}
static int
-union_lookup1(udvp, dvp, vpp, cnp)
+union_lookup1(udvp, dvpp, vpp, cnp)
struct vnode *udvp;
- struct vnode *dvp;
+ struct vnode **dvpp;
struct vnode **vpp;
struct componentname *cnp;
{
int error;
struct vnode *tdvp;
+ struct vnode *dvp;
struct mount *mp;
+ dvp = *dvpp;
+
/*
* If stepping up the directory tree, check for going
* back across the mount point, in which case do what
* hierarchy.
*/
if (cnp->cn_flags & ISDOTDOT) {
- for (;;) {
+ while ((dvp != udvp) && (dvp->v_flag & VROOT)) {
/*
* Don't do the NOCROSSMOUNT check
* at this level. By definition,
* union fs deals with namespaces, not
* filesystems.
*/
- if ((dvp->v_flag & VROOT) == 0)
- break;
-
tdvp = dvp;
- dvp = dvp->v_mount->mnt_vnodecovered;
+ *dvpp = dvp = dvp->v_mount->mnt_vnodecovered;
vput(tdvp);
VREF(dvp);
VOP_LOCK(dvp);
int lockparent = cnp->cn_flags & LOCKPARENT;
int rdonly = cnp->cn_flags & RDONLY;
struct union_mount *um = MOUNTTOUNIONMOUNT(dvp->v_mount);
+ struct ucred *saved_cred;
+
+#ifdef notyet
+ if (cnp->cn_namelen == 3 &&
+ cnp->cn_nameptr[2] == '.' &&
+ cnp->cn_nameptr[1] == '.' &&
+ cnp->cn_nameptr[0] == '.') {
+ dvp = *ap->a_vpp = LOWERVP(ap->a_dvp);
+ if (dvp == NULLVP)
+ return (ENOENT);
+ VREF(dvp);
+ VOP_LOCK(dvp);
+ if (!lockparent || !(cnp->cn_flags & ISLASTCN))
+ VOP_UNLOCK(ap->a_dvp);
+ return (0);
+ }
+#endif
cnp->cn_flags |= LOCKPARENT;
* then assume that something special is going
* on and just return that vnode.
*/
- if (upperdvp) {
- uerror = union_lookup1(um->um_uppervp, upperdvp,
+ if (upperdvp != NULLVP) {
+ FIXUP(dun);
+ uerror = union_lookup1(um->um_uppervp, &upperdvp,
&uppervp, cnp);
/*if (uppervp == upperdvp)
dun->un_flags |= UN_KLOCK;*/
* back from the upper layer and return the lower vnode
* instead.
*/
- if (lowerdvp) {
+ if (lowerdvp != NULLVP) {
int nameiop;
VOP_LOCK(lowerdvp);
*/
nameiop = cnp->cn_nameiop;
cnp->cn_nameiop = LOOKUP;
- lerror = union_lookup1(um->um_lowervp, lowerdvp,
+ if (um->um_op == UNMNT_BELOW) {
+ saved_cred = cnp->cn_cred;
+ cnp->cn_cred = um->um_cred;
+ }
+ lerror = union_lookup1(um->um_lowervp, &lowerdvp,
&lowervp, cnp);
+ if (um->um_op == UNMNT_BELOW)
+ cnp->cn_cred = saved_cred;
cnp->cn_nameiop = nameiop;
if (lowervp != lowerdvp)
VOP_UNLOCK(lowerdvp);
if (cnp->cn_consume != 0) {
- if (uppervp) {
+ if (uppervp != NULLVP) {
if (uppervp == upperdvp)
vrele(uppervp);
else
}
} else {
lerror = ENOENT;
+ if ((cnp->cn_flags & ISDOTDOT) && dun->un_pvp != NULLVP) {
+ lowervp = LOWERVP(dun->un_pvp);
+ if (lowervp != NULLVP) {
+ VREF(lowervp);
+ VOP_LOCK(lowervp);
+ lerror = 0;
+ }
+ }
}
if (!lockparent)
dun->un_flags |= UN_ULOCK;
if (uerror) {
- if (lowervp) {
+ if (lowervp != NULLVP) {
vput(lowervp);
lowervp = NULLVP;
}
}
}
- if (lowervp)
+ if (lowervp != NULLVP)
VOP_UNLOCK(lowervp);
error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
uppervp, lowervp);
if (error) {
- if (uppervp)
+ if (uppervp != NULLVP)
vput(uppervp);
- if (lowervp)
+ if (lowervp != NULLVP)
vrele(lowervp);
} else {
if (*ap->a_vpp != dvp)
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
- if (dvp) {
+ if (dvp != NULLVP) {
int error;
struct vnode *vp;
+ FIXUP(un);
+
VREF(dvp);
un->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
- if (dvp) {
+ if (dvp != NULLVP) {
int error;
struct vnode *vp;
+ FIXUP(un);
+
VREF(dvp);
un->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
if (error)
return (error);
- if (vp) {
+ if (vp != NULLVP) {
error = union_allocvp(
ap->a_vpp,
ap->a_dvp->v_mount,
*/
tvp = un->un_lowervp;
if ((ap->a_mode & FWRITE) && (tvp->v_type == VREG)) {
- struct vnode *vp;
- int i;
-
- /*
- * 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 should re-lookup the node (once more
- * with feeling) and simply open that. Who knows.
- */
- error = union_vn_create(&vp, un, p);
- if (error)
- return (error);
-
- /* at this point, uppervp is locked */
- union_newupper(un, vp);
- un->un_flags |= UN_ULOCK;
-
- /*
- * 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(tvp);
- 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);
- }
-
- un->un_flags &= ~UN_ULOCK;
- VOP_UNLOCK(un->un_uppervp);
- union_vn_close(un->un_uppervp, FWRITE, cred, p);
- VOP_LOCK(un->un_uppervp);
- un->un_flags |= UN_ULOCK;
-
- if (!error)
- uprintf("union: copied up %s\n",
- un->un_path);
- }
-
- /*
- * Subsequent IOs will go to the top layer, so
- * call close on the lower vnode and open on the
- * upper vnode to ensure that the filesystem keeps
- * its references counts right. This doesn't do
- * the right thing with (cred) and (FREAD) though.
- * Ignoring error returns is not righ, either.
- */
- for (i = 0; i < un->un_openl; i++) {
- (void) VOP_CLOSE(tvp, FREAD);
- (void) VOP_OPEN(un->un_uppervp, FREAD, cred, p);
- }
- un->un_openl = 0;
-
+ error = union_copyup(un, (mode&O_TRUNC) == 0, cred, p);
if (error == 0)
error = VOP_OPEN(un->un_uppervp, mode, cred, p);
return (error);
return (error);
}
+ FIXUP(un);
+
error = VOP_OPEN(tvp, mode, cred, p);
return (error);
struct union_node *un = VTOUNION(ap->a_vp);
struct vnode *vp;
- if (un->un_uppervp) {
+ if (un->un_uppervp != NULLVP) {
vp = un->un_uppervp;
} else {
#ifdef UNION_DIAGNOSTIC
} */ *ap;
{
struct union_node *un = VTOUNION(ap->a_vp);
- int error = 0;
+ int error = EACCES;
struct vnode *vp;
- if (vp = un->un_lowervp) {
+ if ((vp = un->un_uppervp) != NULLVP) {
+ FIXUP(un);
+ return (VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p));
+ }
+
+ if ((vp = un->un_lowervp) != NULLVP) {
VOP_LOCK(vp);
error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);
+ if (error == 0) {
+ struct union_mount *um = MOUNTTOUNIONMOUNT(vp->v_mount);
+
+ if (um->um_op == UNMNT_BELOW)
+ error = VOP_ACCESS(vp, ap->a_mode,
+ um->um_cred, ap->a_p);
+ }
VOP_UNLOCK(vp);
if (error)
return (error);
}
- if (vp = un->un_uppervp)
- error = VOP_ACCESS(vp, ap->a_mode, ap->a_cred, ap->a_p);
-
return (error);
}
/*
- * We handle getattr only to change the fsid.
+ * We handle getattr only to change the fsid and
+ * track object sizes
*/
int
union_getattr(ap)
} */ *ap;
{
int error;
- struct vnode *vp = OTHERVP(ap->a_vp);
- int dolock = (vp == LOWERVP(ap->a_vp));
+ struct union_node *un = VTOUNION(ap->a_vp);
+ struct vnode *vp = un->un_uppervp;
+ struct vattr *vap;
+ struct vattr va;
- if (dolock)
+
+ /*
+ * Some programs walk the filesystem hierarchy by counting
+ * links to directories to avoid stat'ing all the time.
+ * This means the link count on directories needs to be "correct".
+ * The only way to do that is to call getattr on both layers
+ * and fix up the link count. The link count will not necessarily
+ * be accurate but will be large enough to defeat the tree walkers.
+ */
+
+ vap = ap->a_vap;
+
+ vp = un->un_uppervp;
+ if (vp != NULLVP) {
+ /*
+ * It's not clear whether VOP_GETATTR is to be
+ * called with the vnode locked or not. stat() calls
+ * it with (vp) locked, and fstat calls it with
+ * (vp) unlocked.
+ * In the mean time, compensate here by checking
+ * the union_node's lock flag.
+ */
+ if (un->un_flags & UN_LOCKED)
+ FIXUP(un);
+
+ error = VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
+ if (error)
+ return (error);
+ union_newsize(ap->a_vp, vap->va_size, VNOVAL);
+ }
+
+ if (vp == NULLVP) {
+ vp = un->un_lowervp;
+ } else if (vp->v_type == VDIR) {
+ vp = un->un_lowervp;
+ vap = &va;
+ } else {
+ vp = NULLVP;
+ }
+
+ if (vp != NULLVP) {
VOP_LOCK(vp);
- error = VOP_GETATTR(vp, ap->a_vap, ap->a_cred, ap->a_p);
- if (dolock)
+ 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 ((vap != ap->a_vap) && (vap->va_type == VDIR))
+ ap->a_vap->va_nlink += vap->va_nlink;
- /* Requires that arguments be restored. */
ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
return (0);
}
struct union_node *un = VTOUNION(ap->a_vp);
int error;
- if (un->un_uppervp) {
+ /*
+ * Handle case of truncating lower object to zero size,
+ * by creating a zero length upper object. This is to
+ * handle the case of open with O_TRUNC and O_CREAT.
+ */
+ if ((un->un_uppervp == NULLVP) &&
+ /* assert(un->un_lowervp != NULLVP) */
+ (un->un_lowervp->v_type == VREG) &&
+ (ap->a_vap->va_size == 0)) {
+ struct vnode *vp;
+
+ error = union_vn_create(&vp, un, ap->a_p);
+ if (error)
+ return (error);
+
+ /* at this point, uppervp is locked */
+ union_newupper(un, vp);
+
+ VOP_UNLOCK(vp);
+ union_vn_close(un->un_uppervp, FWRITE, ap->a_cred, ap->a_p);
+ VOP_LOCK(vp);
+ un->un_flags |= UN_ULOCK;
+ }
+
+ /*
+ * Try to set attributes in upper layer,
+ * otherwise return read-only filesystem error.
+ */
+ if (un->un_uppervp != NULLVP) {
+ FIXUP(un);
error = VOP_SETATTR(un->un_uppervp, ap->a_vap,
ap->a_cred, ap->a_p);
+ if ((error == 0) && (ap->a_vap->va_size != VNOVAL))
+ union_newsize(ap->a_vp, ap->a_vap->va_size, VNOVAL);
} else {
- /*
- * XXX should do a copyfile (perhaps only if
- * the file permission change, which would not
- * track va_ctime correctly).
- */
error = EROFS;
}
if (dolock)
VOP_LOCK(vp);
+ else
+ FIXUP(VTOUNION(ap->a_vp));
error = VOP_READ(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
if (dolock)
VOP_UNLOCK(vp);
+ /*
+ * XXX
+ * perhaps the size of the underlying object has changed under
+ * our feet. take advantage of the offset information present
+ * in the uio structure.
+ */
+ if (error == 0) {
+ struct union_node *un = VTOUNION(ap->a_vp);
+ off_t cur = ap->a_uio->uio_offset;
+
+ if (vp == un->un_uppervp) {
+ if (cur > un->un_uppersz)
+ union_newsize(ap->a_vp, cur, VNOVAL);
+ } else {
+ if (cur > un->un_lowersz)
+ union_newsize(ap->a_vp, VNOVAL, cur);
+ }
+ }
+
return (error);
}
if (dolock)
VOP_LOCK(vp);
+ else
+ FIXUP(VTOUNION(ap->a_vp));
error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred);
if (dolock)
VOP_UNLOCK(vp);
+ /*
+ * the size of the underlying object may be changed by the
+ * write.
+ */
+ if (error == 0) {
+ struct union_node *un = VTOUNION(ap->a_vp);
+ off_t cur = ap->a_uio->uio_offset;
+
+ if (vp == un->un_uppervp) {
+ if (cur > un->un_uppersz)
+ union_newsize(ap->a_vp, cur, VNOVAL);
+ } else {
+ if (cur > un->un_lowersz)
+ union_newsize(ap->a_vp, VNOVAL, cur);
+ }
+ }
+
return (error);
}
int error = 0;
struct vnode *targetvp = OTHERVP(ap->a_vp);
- if (targetvp) {
+ if (targetvp != NULLVP) {
int dolock = (targetvp == LOWERVP(ap->a_vp));
if (dolock)
VOP_LOCK(targetvp);
+ else
+ FIXUP(VTOUNION(ap->a_vp));
error = VOP_FSYNC(targetvp, ap->a_cred,
ap->a_waitfor, ap->a_p);
if (dolock)
struct union_node *dun = VTOUNION(ap->a_dvp);
struct union_node *un = VTOUNION(ap->a_vp);
- if (dun->un_uppervp && un->un_uppervp) {
+ if (dun->un_uppervp != NULLVP && un->un_uppervp != NULLVP) {
struct vnode *dvp = dun->un_uppervp;
struct vnode *vp = un->un_uppervp;
+ FIXUP(dun);
VREF(dvp);
dun->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
+ FIXUP(un);
VREF(vp);
un->un_flags |= UN_KLOCK;
vput(ap->a_vp);
struct componentname *a_cnp;
} */ *ap;
{
- int error;
- struct union_node *dun = VTOUNION(ap->a_vp);
- struct union_node *un = VTOUNION(ap->a_tdvp);
-
- if (dun->un_uppervp && un->un_uppervp) {
- struct vnode *dvp = dun->un_uppervp;
- struct vnode *vp = un->un_uppervp;
+ int error = 0;
+ struct union_node *un;
+ struct vnode *vp;
+ struct vnode *tdvp;
- VREF(dvp);
- dun->un_flags |= UN_KLOCK;
- vput(ap->a_vp);
- VREF(vp);
- vrele(ap->a_tdvp);
+ un = VTOUNION(ap->a_vp);
- error = VOP_LINK(dvp, vp, ap->a_cnp);
+ if (ap->a_vp->v_op != ap->a_tdvp->v_op) {
+ tdvp = ap->a_tdvp;
} else {
- /*
- * XXX: need to copy to upper layer
- * and do the link there.
- */
- vput(ap->a_vp);
- vrele(ap->a_tdvp);
+ 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) {
+ un->un_flags &= ~UN_ULOCK;
+ VOP_UNLOCK(un->un_uppervp);
+ }
+ error = union_copyup(tdun, 1, ap->a_cnp->cn_cred,
+ ap->a_cnp->cn_proc);
+ if (un->un_uppervp == tdun->un_dirvp) {
+ VOP_LOCK(un->un_uppervp);
+ un->un_flags |= UN_ULOCK;
+ }
+ VOP_UNLOCK(ap->a_tdvp);
+ }
+ tdvp = tdun->un_uppervp;
+ }
+
+ vp = un->un_uppervp;
+ if (vp == NULLVP)
error = EROFS;
+
+ if (error) {
+ vput(ap->a_vp);
+ return (error);
}
- return (error);
+ FIXUP(un);
+ VREF(vp);
+ un->un_flags |= UN_KLOCK;
+ vput(ap->a_vp);
+
+ return (VOP_LINK(vp, tdvp, ap->a_cnp));
}
int
if (tdvp->v_op == union_vnodeop_p) {
struct union_node *un = VTOUNION(tdvp);
if (un->un_uppervp == NULLVP) {
+ /*
+ * this should never happen in normal
+ * operation but might if there was
+ * a problem creating the top-level shadow
+ * directory.
+ */
error = EROFS;
goto bad;
}
vput(ap->a_tdvp);
}
- if (tvp && tvp->v_op == union_vnodeop_p) {
+ if (tvp != NULLVP && tvp->v_op == union_vnodeop_p) {
struct union_node *un = VTOUNION(tvp);
- if (un->un_uppervp == NULLVP) {
- error = EROFS;
- goto bad;
- }
tvp = un->un_uppervp;
- VREF(tvp);
- un->un_flags |= UN_KLOCK;
+ if (tvp != NULLVP) {
+ VREF(tvp);
+ un->un_flags |= UN_KLOCK;
+ }
vput(ap->a_tvp);
}
vrele(fdvp);
vrele(fvp);
vput(tdvp);
- if (tvp)
+ if (tvp != NULLVP)
vput(tvp);
return (error);
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
- if (dvp) {
+ if (dvp != NULLVP) {
int error;
struct vnode *vp;
+ FIXUP(un);
VREF(dvp);
un->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
struct union_node *dun = VTOUNION(ap->a_dvp);
struct union_node *un = VTOUNION(ap->a_vp);
- if (dun->un_uppervp && un->un_uppervp) {
+ if (dun->un_uppervp != NULLVP && un->un_uppervp != NULLVP) {
struct vnode *dvp = dun->un_uppervp;
struct vnode *vp = un->un_uppervp;
+ FIXUP(dun);
VREF(dvp);
dun->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
+ FIXUP(un);
VREF(vp);
un->un_flags |= UN_KLOCK;
vput(ap->a_vp);
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
- if (dvp) {
+ if (dvp != NULLVP) {
int error;
struct vnode *vp;
struct mount *mp = ap->a_dvp->v_mount;
+ FIXUP(un);
VREF(dvp);
un->un_flags |= UN_KLOCK;
vput(ap->a_dvp);
struct vnode *a_vp;
struct uio *a_uio;
struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
} */ *ap;
{
- int error = 0;
- struct union_node *un = VTOUNION(ap->a_vp);
+ register struct union_node *un = VTOUNION(ap->a_vp);
+ register struct vnode *uvp = un->un_uppervp;
- if (un->un_uppervp)
- error = VOP_READDIR(un->un_uppervp, ap->a_uio, ap->a_cred);
+ if (uvp == NULLVP)
+ return (0);
- return (error);
+ FIXUP(un);
+ ap->a_vp = uvp;
+ return (VOCALL(uvp->v_op, VOFFSET(vop_readdir), ap));
}
int
if (dolock)
VOP_LOCK(vp);
+ else
+ FIXUP(VTOUNION(ap->a_vp));
error = VOP_READLINK(vp, ap->a_uio, ap->a_cred);
if (dolock)
VOP_UNLOCK(vp);
int islocked = un->un_flags & UN_LOCKED;
int dolock = (vp == LOWERVP(ap->a_dvp));
- if (islocked && dolock)
- VOP_LOCK(vp);
+ if (islocked) {
+ if (dolock)
+ VOP_LOCK(vp);
+ else
+ FIXUP(VTOUNION(ap->a_dvp));
+ }
error = VOP_ABORTOP(vp, ap->a_cnp);
if (islocked && dolock)
VOP_UNLOCK(vp);
struct vnode *a_vp;
} */ *ap;
{
+ struct union_node *un = VTOUNION(ap->a_vp);
/*
* Do nothing (and _don't_ bypass).
*/
#ifdef UNION_DIAGNOSTIC
- struct union_node *un = VTOUNION(ap->a_vp);
-
if (un->un_flags & UN_LOCKED)
panic("union: inactivating locked node");
+ if (un->un_flags & UN_ULOCK)
+ panic("union: inactivating w/locked upper node");
#endif
+ if ((un->un_flags & UN_CACHED) == 0)
+ vgone(ap->a_vp);
+
return (0);
}
union_lock(ap)
struct vop_lock_args *ap;
{
- struct union_node *un = VTOUNION(ap->a_vp);
+ struct vnode *vp = ap->a_vp;
+ struct union_node *un;
- if (un->un_uppervp) {
- if ((un->un_flags & UN_ULOCK) == 0) {
- VOP_LOCK(un->un_uppervp);
+start:
+ while (vp->v_flag & VXLOCK) {
+ vp->v_flag |= VXWANT;
+ sleep((caddr_t)vp, PINOD);
+ }
+
+ un = VTOUNION(vp);
+
+ 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);
}
#ifdef DIAGNOSTIC
if (un->un_flags & UN_KLOCK)
#endif
}
- while (un->un_flags & UN_LOCKED) {
+ if (un->un_flags & UN_LOCKED) {
#ifdef DIAGNOSTIC
if (curproc && un->un_pid == curproc->p_pid &&
un->un_pid > -1 && curproc->p_pid > -1)
#endif
un->un_flags |= UN_WANT;
sleep((caddr_t) &un->un_flags, PINOD);
+ goto start;
}
- un->un_flags |= UN_LOCKED;
#ifdef DIAGNOSTIC
if (curproc)
un->un_pid = -1;
#endif
+ un->un_flags |= UN_LOCKED;
return (0);
}
if (dolock)
VOP_LOCK(vp);
+ else
+ FIXUP(VTOUNION(ap->a_vp));
error = VOP_BMAP(vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp);
if (dolock)
VOP_UNLOCK(vp);
if (dolock)
VOP_LOCK(vp);
+ else
+ FIXUP(VTOUNION(ap->a_vp));
error = VOP_PATHCONF(vp, ap->a_name, ap->a_retval);
if (dolock)
VOP_UNLOCK(vp);