Merge update from JSP.

This commit is contained in:
mycroft 1994-06-15 23:07:54 +00:00
parent 117527f322
commit 82ac72f664
6 changed files with 337 additions and 192 deletions

View File

@ -4,4 +4,5 @@ in this directory. The replacement version of opendir() automatically
removes duplicate names when a union stack is encountered. You will
then need to rebuild the C library and all commands.
@(#)README 8.1 (Berkeley) 2/15/94
from: @(#)README 8.1 (Berkeley) 2/15/94
$Id: README,v 1.2 1994/06/15 23:07:54 mycroft Exp $

View File

@ -33,8 +33,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char orig_sccsid[] = "from: @(#)opendir.c 8.2 (Berkeley) 2/12/94";*/
/*static char sccsid[] = "from: @(#)libc.opendir.c 8.1 (Berkeley) 2/15/94";*/
static char *rcsid = "$Id: libc.opendir.c,v 1.1 1994/06/08 11:33:57 mycroft Exp $";
/*static char sccsid[] = "from: @(#)libc.opendir.c 8.2 (Berkeley) 6/15/94";*/
static char *rcsid = "$Id: libc.opendir.c,v 1.2 1994/06/15 23:07:56 mycroft Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
@ -167,10 +167,9 @@ opendir(name)
struct dirent *xp;
/*
* If and when whiteouts happen,
* this sort would need to be stable.
* This sort must be stable.
*/
heapsort(dpv, n, sizeof(*dpv), alphasort);
mergesort(dpv, n, sizeof(*dpv), alphasort);
dpv[n] = NULL;
xp = NULL;

View File

@ -34,8 +34,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)union.h 8.2 (Berkeley) 2/17/94
* $Id: union.h,v 1.1 1994/06/08 11:33:58 mycroft Exp $
* from: @(#)union.h 8.5 (Berkeley) 5/17/94
* $Id: union.h,v 1.2 1994/06/15 23:07:58 mycroft Exp $
*/
struct union_args {
@ -78,7 +78,9 @@ struct union_node {
char *un_path; /* saved component name */
int un_hash; /* saved un_path hash value */
int un_openl; /* # of opens on lowervp */
int un_flags;
unsigned int un_flags;
off_t un_uppersz; /* size of upper object */
off_t un_lowersz; /* size of lower object */
#ifdef DIAGNOSTIC
pid_t un_pid;
#endif
@ -88,13 +90,16 @@ struct union_node {
#define UN_LOCKED 0x02
#define UN_ULOCK 0x04 /* Upper node is locked */
#define UN_KLOCK 0x08 /* Keep upper node locked on vput */
#define UN_CACHED 0x10 /* In union cache */
extern int union_allocvp __P((struct vnode **, struct mount *,
struct vnode *, struct vnode *,
struct componentname *, struct vnode *,
struct vnode *));
extern int union_copyfile __P((struct proc *, struct ucred *,
struct vnode *, struct vnode *));
extern int union_copyfile __P((struct vnode *, struct vnode *,
struct ucred *, struct proc *));
extern int union_copyup __P((struct union_node *, int, struct ucred *,
struct proc *));
extern int union_mkshadow __P((struct union_mount *, struct vnode *,
struct componentname *, struct vnode **));
extern int union_vn_create __P((struct vnode **, struct union_node *,
@ -105,6 +110,7 @@ extern void union_removed_upper __P((struct union_node *un));
extern struct vnode *union_lowervp __P((struct vnode *));
extern void union_newlower __P((struct union_node *, struct vnode *));
extern void union_newupper __P((struct union_node *, struct vnode *));
extern void union_newsize __P((struct vnode *, off_t, off_t));
#define MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data))
#define VTOUNION(vp) ((struct union_node *)(vp)->v_data)

View File

@ -34,8 +34,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)union_subr.c 8.4 (Berkeley) 2/17/94
* $Id: union_subr.c,v 1.1 1994/06/08 11:34:00 mycroft Exp $
* from: @(#)union_subr.c 8.9 (Berkeley) 5/17/94
* $Id: union_subr.c,v 1.2 1994/06/15 23:07:59 mycroft Exp $
*/
#include <sys/param.h>
@ -49,6 +49,8 @@
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/queue.h>
#include <sys/mount.h>
#include <vm/vm.h> /* for vnode_pager_setsize */
#include <miscfs/union/union.h>
/* must be power of two, otherwise change UNION_HASH() */
@ -108,31 +110,35 @@ union_updatevp(un, uppervp, lowervp)
{
int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
int nhash = UNION_HASH(uppervp, lowervp);
int docache = (lowervp != NULLVP || uppervp != NULLVP);
if (ohash != nhash) {
/*
* Ensure locking is ordered from lower to higher
* to avoid deadlocks.
*/
if (nhash < ohash) {
int t = ohash;
ohash = nhash;
nhash = t;
}
/*
* Ensure locking is ordered from lower to higher
* to avoid deadlocks.
*/
if (nhash < ohash) {
int t = ohash;
ohash = nhash;
nhash = t;
}
if (ohash != nhash)
while (union_list_lock(ohash))
continue;
while (union_list_lock(nhash))
continue;
while (union_list_lock(nhash))
continue;
LIST_REMOVE(un, un_cache);
union_list_unlock(ohash);
} else {
while (union_list_lock(nhash))
continue;
if (ohash != nhash || !docache) {
if (un->un_flags & UN_CACHED) {
LIST_REMOVE(un, un_cache);
un->un_flags &= ~UN_CACHED;
}
}
if (ohash != nhash)
union_list_unlock(ohash);
if (un->un_lowervp != lowervp) {
if (un->un_lowervp) {
vrele(un->un_lowervp);
@ -146,6 +152,7 @@ union_updatevp(un, uppervp, lowervp)
}
}
un->un_lowervp = lowervp;
un->un_lowersz = VNOVAL;
}
if (un->un_uppervp != uppervp) {
@ -153,10 +160,13 @@ union_updatevp(un, uppervp, lowervp)
vrele(un->un_uppervp);
un->un_uppervp = uppervp;
un->un_uppersz = VNOVAL;
}
if (ohash != nhash)
if (docache && (ohash != nhash)) {
LIST_INSERT_HEAD(&unhead[nhash], un, un_cache);
un->un_flags |= UN_CACHED;
}
union_list_unlock(nhash);
}
@ -179,6 +189,47 @@ union_newupper(un, uppervp)
union_updatevp(un, uppervp, un->un_lowervp);
}
/*
* Keep track of size changes in the underlying vnodes.
* If the size changes, then callback to the vm layer
* giving priority to the upper layer size.
*/
void
union_newsize(vp, uppersz, lowersz)
struct vnode *vp;
off_t uppersz, lowersz;
{
struct union_node *un;
off_t sz;
/* only interested in regular files */
if (vp->v_type != VREG)
return;
un = VTOUNION(vp);
sz = VNOVAL;
if ((uppersz != VNOVAL) && (un->un_uppersz != uppersz)) {
un->un_uppersz = uppersz;
if (sz == VNOVAL)
sz = un->un_uppersz;
}
if ((lowersz != VNOVAL) && (un->un_lowersz != lowersz)) {
un->un_lowersz = lowersz;
if (sz == VNOVAL)
sz = un->un_lowersz;
}
if (sz != VNOVAL) {
#ifdef UNION_DIAGNOSTIC
printf("union: %s size now %ld\n",
uppersz != VNOVAL ? "upper" : "lower", (long) sz);
#endif
vnode_pager_setsize(vp, sz);
}
}
/*
* allocate a union_node/vnode pair. the vnode is
* referenced and locked. the new vnode is returned
@ -224,7 +275,9 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
struct union_node *un;
struct union_node **pp;
struct vnode *xlowervp = NULLVP;
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
int hash;
int vflag;
int try;
if (uppervp == NULLVP && lowervp == NULLVP)
@ -235,6 +288,18 @@ union_allocvp(vpp, mp, undvp, dvp, cnp, uppervp, lowervp)
lowervp = NULLVP;
}
/* detect the root vnode (and aliases) */
vflag = 0;
if ((uppervp == um->um_uppervp) &&
((lowervp == NULLVP) || lowervp == um->um_lowervp)) {
if (lowervp == NULLVP) {
lowervp = um->um_lowervp;
if (lowervp != NULLVP)
VREF(lowervp);
}
vflag = VROOT;
}
loop:
for (try = 0; try < 3; try++) {
switch (try) {
@ -394,6 +459,7 @@ loop:
MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),
M_TEMP, M_WAITOK);
(*vpp)->v_flag |= vflag;
if (uppervp)
(*vpp)->v_type = uppervp->v_type;
else
@ -401,7 +467,9 @@ loop:
un = VTOUNION(*vpp);
un->un_vnode = *vpp;
un->un_uppervp = uppervp;
un->un_uppersz = VNOVAL;
un->un_lowervp = lowervp;
un->un_lowersz = VNOVAL;
un->un_openl = 0;
un->un_flags = UN_LOCKED;
if (un->un_uppervp)
@ -426,6 +494,7 @@ loop:
}
LIST_INSERT_HEAD(&unhead[hash], un, un_cache);
un->un_flags |= UN_CACHED;
if (xlowervp)
vrele(xlowervp);
@ -442,13 +511,16 @@ union_freevp(vp)
{
struct union_node *un = VTOUNION(vp);
LIST_REMOVE(un, un_cache);
if (un->un_flags & UN_CACHED) {
LIST_REMOVE(un, un_cache);
un->un_flags &= ~UN_CACHED;
}
if (un->un_uppervp)
if (un->un_uppervp != NULLVP)
vrele(un->un_uppervp);
if (un->un_lowervp)
if (un->un_lowervp != NULLVP)
vrele(un->un_lowervp);
if (un->un_dirvp)
if (un->un_dirvp != NULLVP)
vrele(un->un_dirvp);
if (un->un_path)
free(un->un_path, M_TEMP);
@ -465,11 +537,11 @@ union_freevp(vp)
* and (tvp) are locked on entry and exit.
*/
int
union_copyfile(p, cred, fvp, tvp)
struct proc *p;
struct ucred *cred;
union_copyfile(fvp, tvp, cred, p)
struct vnode *fvp;
struct vnode *tvp;
struct ucred *cred;
struct proc *p;
{
char *buf;
struct uio uio;
@ -532,6 +604,76 @@ union_copyfile(p, cred, fvp, tvp)
return (error);
}
/*
* (un) is assumed to be locked on entry and remains
* locked on exit.
*/
int
union_copyup(un, docopy, cred, p)
struct union_node *un;
int docopy;
struct ucred *cred;
struct proc *p;
{
int error;
struct vnode *lvp, *uvp;
error = union_vn_create(&uvp, un, p);
if (error)
return (error);
/* at this point, uppervp is locked */
union_newupper(un, uvp);
un->un_flags |= UN_ULOCK;
lvp = un->un_lowervp;
if (docopy) {
/*
* XX - should not ignore errors
* from VOP_CLOSE
*/
VOP_LOCK(lvp);
error = VOP_OPEN(lvp, FREAD, cred, p);
if (error == 0) {
error = union_copyfile(lvp, uvp, cred, p);
VOP_UNLOCK(lvp);
(void) VOP_CLOSE(lvp, FREAD);
}
#ifdef UNION_DIAGNOSTIC
if (error == 0)
uprintf("union: copied up %s\n", un->un_path);
#endif
}
un->un_flags &= ~UN_ULOCK;
VOP_UNLOCK(uvp);
union_vn_close(uvp, FWRITE, cred, p);
VOP_LOCK(uvp);
un->un_flags |= UN_ULOCK;
/*
* 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 right, either.
*/
if (error == 0) {
int i;
for (i = 0; i < un->un_openl; i++) {
(void) VOP_CLOSE(lvp, FREAD);
(void) VOP_OPEN(uvp, FREAD, cred, p);
}
un->un_openl = 0;
}
return (error);
}
/*
* Create a shadow directory in the upper layer.
* The new vnode is returned locked.
@ -733,10 +875,11 @@ union_lowervp(vp)
{
struct union_node *un = VTOUNION(vp);
if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) {
if (vget(un->un_lowervp, 0))
return (NULLVP);
if ((un->un_lowervp != NULLVP) &&
(vp->v_type == un->un_lowervp->v_type)) {
if (vget(un->un_lowervp, 0) == 0)
return (un->un_lowervp);
}
return (un->un_lowervp);
return (NULLVP);
}

View File

@ -34,8 +34,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)union_vfsops.c 8.7 (Berkeley) 3/5/94
* $Id: union_vfsops.c,v 1.1 1994/06/08 11:34:02 mycroft Exp $
* from: @(#)union_vfsops.c 8.10 (Berkeley) 5/24/94
* $Id: union_vfsops.c,v 1.2 1994/06/15 23:08:02 mycroft Exp $
*/
/*
@ -236,10 +236,10 @@ union_mount(mp, path, data, ndp, p)
switch (um->um_op) {
case UNMNT_ABOVE:
cp = "<above>";
cp = "<above>:";
break;
case UNMNT_BELOW:
cp = "<below>";
cp = "<below>:";
break;
case UNMNT_REPLACE:
cp = "";
@ -362,12 +362,6 @@ union_root(mp, vpp)
int error;
int loselock;
#ifdef UNION_DIAGNOSTIC
printf("union_root(mp = %x, lvp = %x, uvp = %x)\n", mp,
um->um_lowervp,
um->um_uppervp);
#endif
/*
* Return locked reference to root.
*/
@ -395,7 +389,6 @@ union_root(mp, vpp)
if (um->um_lowervp)
vrele(um->um_lowervp);
} else {
(*vpp)->v_flag |= VROOT;
if (loselock)
VTOUNION(*vpp)->un_flags &= ~UN_ULOCK;
}

View File

@ -34,8 +34,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)union_vnops.c 8.6 (Berkeley) 2/17/94
* $Id: union_vnops.c,v 1.1 1994/06/08 11:34:03 mycroft Exp $
* from: @(#)union_vnops.c 8.15 (Berkeley) 6/4/94
* $Id: union_vnops.c,v 1.2 1994/06/15 23:08:04 mycroft Exp $
*/
#include <sys/param.h>
@ -68,16 +68,19 @@ union_fixup(un)
}
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
@ -85,18 +88,15 @@ union_lookup1(udvp, dvp, vpp, cnp)
* 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);
@ -178,9 +178,9 @@ union_lookup(ap)
* then assume that something special is going
* on and just return that vnode.
*/
if (upperdvp) {
if (upperdvp != NULLVP) {
FIXUP(dun);
uerror = union_lookup1(um->um_uppervp, upperdvp,
uerror = union_lookup1(um->um_uppervp, &upperdvp,
&uppervp, cnp);
/*if (uppervp == upperdvp)
dun->un_flags |= UN_KLOCK;*/
@ -202,7 +202,7 @@ union_lookup(ap)
* back from the upper layer and return the lower vnode
* instead.
*/
if (lowerdvp) {
if (lowerdvp != NULLVP) {
int nameiop;
VOP_LOCK(lowerdvp);
@ -217,7 +217,7 @@ union_lookup(ap)
saved_cred = cnp->cn_cred;
cnp->cn_cred = um->um_cred;
}
lerror = union_lookup1(um->um_lowervp, lowerdvp,
lerror = union_lookup1(um->um_lowervp, &lowerdvp,
&lowervp, cnp);
if (um->um_op == UNMNT_BELOW)
cnp->cn_cred = saved_cred;
@ -227,7 +227,7 @@ union_lookup(ap)
VOP_UNLOCK(lowerdvp);
if (cnp->cn_consume != 0) {
if (uppervp) {
if (uppervp != NULLVP) {
if (uppervp == upperdvp)
vrele(uppervp);
else
@ -287,7 +287,7 @@ union_lookup(ap)
dun->un_flags |= UN_ULOCK;
if (uerror) {
if (lowervp) {
if (lowervp != NULLVP) {
vput(lowervp);
lowervp = NULLVP;
}
@ -296,16 +296,16 @@ union_lookup(ap)
}
}
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)
@ -328,7 +328,7 @@ union_create(ap)
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
if (dvp) {
if (dvp != NULLVP) {
int error;
struct vnode *vp;
@ -370,7 +370,7 @@ union_mknod(ap)
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
if (dvp) {
if (dvp != NULLVP) {
int error;
struct vnode *vp;
@ -383,7 +383,7 @@ union_mknod(ap)
if (error)
return (error);
if (vp) {
if (vp != NULLVP) {
error = union_allocvp(
ap->a_vpp,
ap->a_dvp->v_mount,
@ -431,77 +431,7 @@ union_open(ap)
*/
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);
}
#ifdef UNION_DIAGNOSTIC
if (!error)
uprintf("union: copied up %s\n",
un->un_path);
#endif
}
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;
/*
* 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);
@ -537,7 +467,7 @@ union_close(ap)
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
@ -573,12 +503,12 @@ union_access(ap)
int error = EACCES;
struct vnode *vp;
if (vp = un->un_uppervp) {
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) {
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) {
@ -597,7 +527,8 @@ union_access(ap)
}
/*
* We handle getattr only to change the fsid.
* We handle getattr only to change the fsid and
* track object sizes
*/
int
union_getattr(ap)
@ -628,10 +559,21 @@ union_getattr(ap)
vp = un->un_uppervp;
if (vp != NULLVP) {
FIXUP(un);
/*
* 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) {
@ -649,6 +591,7 @@ union_getattr(ap)
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))
@ -702,6 +645,8 @@ union_setattr(ap)
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 {
error = EROFS;
}
@ -730,6 +675,25 @@ union_read(ap)
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);
}
@ -754,6 +718,23 @@ union_write(ap)
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);
}
@ -814,7 +795,7 @@ union_fsync(ap)
int error = 0;
struct vnode *targetvp = OTHERVP(ap->a_vp);
if (targetvp) {
if (targetvp != NULLVP) {
int dolock = (targetvp == LOWERVP(ap->a_vp));
if (dolock)
@ -855,7 +836,7 @@ union_remove(ap)
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;
@ -895,34 +876,49 @@ union_link(ap)
struct componentname *a_cnp;
} */ *ap;
{
int error;
struct union_node *dun = VTOUNION(ap->a_vp);
struct union_node *un = VTOUNION(ap->a_tdvp);
int error = 0;
struct union_node *un;
struct vnode *vp;
struct vnode *tdvp;
if (dun->un_uppervp && un->un_uppervp) {
struct vnode *dvp = dun->un_uppervp;
struct vnode *vp = un->un_uppervp;
un = VTOUNION(ap->a_vp);
FIXUP(dun);
VREF(dvp);
dun->un_flags |= UN_KLOCK;
vput(ap->a_vp);
FIXUP(un);
VREF(vp);
vrele(ap->a_tdvp);
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);
error = EROFS;
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;
}
return (error);
vp = un->un_uppervp;
if (vp == NULLVP)
error = EROFS;
if (error) {
vput(ap->a_vp);
return (error);
}
FIXUP(un);
VREF(vp);
un->un_flags |= UN_KLOCK;
vput(ap->a_vp);
return (VOP_LINK(vp, tdvp, ap->a_cnp));
}
int
@ -950,7 +946,6 @@ union_rename(ap)
goto bad;
}
FIXUP(un);
fdvp = un->un_uppervp;
VREF(fdvp);
vrele(ap->a_fdvp);
@ -963,7 +958,6 @@ union_rename(ap)
goto bad;
}
FIXUP(un);
fvp = un->un_uppervp;
VREF(fvp);
vrele(ap->a_fvp);
@ -972,6 +966,12 @@ union_rename(ap)
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;
}
@ -982,16 +982,14 @@ union_rename(ap)
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);
}
@ -1001,7 +999,7 @@ bad:
vrele(fdvp);
vrele(fvp);
vput(tdvp);
if (tvp)
if (tvp != NULLVP)
vput(tvp);
return (error);
@ -1019,7 +1017,7 @@ union_mkdir(ap)
struct union_node *un = VTOUNION(ap->a_dvp);
struct vnode *dvp = un->un_uppervp;
if (dvp) {
if (dvp != NULLVP) {
int error;
struct vnode *vp;
@ -1060,7 +1058,7 @@ union_rmdir(ap)
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;
@ -1105,7 +1103,7 @@ union_symlink(ap)
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;
@ -1209,6 +1207,7 @@ union_inactive(ap)
struct vnode *a_vp;
} */ *ap;
{
struct union_node *un = VTOUNION(ap->a_vp);
/*
* Do nothing (and _don't_ bypass).
@ -1224,12 +1223,15 @@ union_inactive(ap)
*/
#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);
}
@ -1260,8 +1262,9 @@ start:
un = VTOUNION(vp);
if (un->un_uppervp) {
if ((un->un_flags & UN_ULOCK) == 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);
}