Merge update from JSP.
This commit is contained in:
parent
117527f322
commit
82ac72f664
|
@ -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 $
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue