2005-01-06 18:10:42 +00:00
|
|
|
/*-
|
1994-05-24 10:09:53 +00:00
|
|
|
* Copyright (c) 1994 Jan-Simon Pendry
|
|
|
|
* Copyright (c) 1994
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
2006-12-02 19:35:56 +00:00
|
|
|
* Copyright (c) 2005, 2006 Masanori Ozawa <ozawa@ongs.co.jp>, ONGS Inc.
|
|
|
|
* Copyright (c) 2006 Daichi Goto <daichi@freebsd.org>
|
1994-05-24 10:09:53 +00:00
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* Jan-Simon Pendry.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1997-02-10 02:22:35 +00:00
|
|
|
* @(#)union_subr.c 8.20 (Berkeley) 5/20/95
|
1999-08-28 01:08:13 +00:00
|
|
|
* $FreeBSD$
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
2001-05-01 08:13:21 +00:00
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/lock.h>
|
2006-12-02 19:35:56 +00:00
|
|
|
#include <sys/mutex.h>
|
2001-05-01 08:13:21 +00:00
|
|
|
#include <sys/malloc.h>
|
1997-02-10 02:22:35 +00:00
|
|
|
#include <sys/mount.h>
|
2001-05-01 08:13:21 +00:00
|
|
|
#include <sys/namei.h>
|
2006-12-02 19:35:56 +00:00
|
|
|
#include <sys/proc.h>
|
2001-05-01 08:13:21 +00:00
|
|
|
#include <sys/vnode.h>
|
2006-12-02 19:35:56 +00:00
|
|
|
#include <sys/dirent.h>
|
|
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <sys/filedesc.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/resourcevar.h>
|
|
|
|
|
|
|
|
#ifdef MAC
|
|
|
|
#include <sys/mac.h>
|
|
|
|
#endif
|
2001-05-01 08:13:21 +00:00
|
|
|
|
2002-04-08 06:57:43 +00:00
|
|
|
#include <vm/uma.h>
|
2001-05-01 08:13:21 +00:00
|
|
|
|
2001-05-23 09:42:29 +00:00
|
|
|
#include <fs/unionfs/union.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2008-04-25 09:38:48 +00:00
|
|
|
#define NUNIONFSNODECACHE 16
|
|
|
|
|
|
|
|
static MALLOC_DEFINE(M_UNIONFSHASH, "UNIONFS hash", "UNIONFS hash table");
|
2006-12-02 19:35:56 +00:00
|
|
|
MALLOC_DEFINE(M_UNIONFSNODE, "UNIONFS node", "UNIONFS vnode private part");
|
|
|
|
MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
|
|
|
|
|
|
|
|
/*
|
2007-10-14 13:46:11 +00:00
|
|
|
* Initialize
|
2006-12-02 19:35:56 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
unionfs_init(struct vfsconf *vfsp)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */
|
1994-05-25 09:21:21 +00:00
|
|
|
return (0);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
2007-10-14 13:46:11 +00:00
|
|
|
* Uninitialize
|
2006-12-02 19:35:56 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
unionfs_uninit(struct vfsconf *vfsp)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2008-04-25 09:38:48 +00:00
|
|
|
static struct unionfs_node_hashhead *
|
|
|
|
unionfs_get_hashhead(struct vnode *dvp, char *path)
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
char hash;
|
|
|
|
struct unionfs_node *unp;
|
|
|
|
|
|
|
|
hash = 0;
|
|
|
|
unp = VTOUNIONFS(dvp);
|
|
|
|
if (path != NULL) {
|
|
|
|
for (count = 0; path[count]; count++)
|
|
|
|
hash += path[count];
|
|
|
|
}
|
|
|
|
|
|
|
|
return (&(unp->un_hashtbl[hash & (unp->un_hashmask)]));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the cached vnode. (only VDIR)
|
|
|
|
*/
|
|
|
|
static struct vnode *
|
|
|
|
unionfs_get_cached_vdir(struct vnode *uvp, struct vnode *lvp,
|
|
|
|
struct vnode *dvp, char *path)
|
|
|
|
{
|
|
|
|
struct unionfs_node_hashhead *hd;
|
|
|
|
struct unionfs_node *unp;
|
|
|
|
struct vnode *vp;
|
|
|
|
|
|
|
|
KASSERT((uvp == NULLVP || uvp->v_type == VDIR),
|
|
|
|
("unionfs_get_cached_vdir: v_type != VDIR"));
|
|
|
|
KASSERT((lvp == NULLVP || lvp->v_type == VDIR),
|
|
|
|
("unionfs_get_cached_vdir: v_type != VDIR"));
|
|
|
|
|
|
|
|
VI_LOCK(dvp);
|
|
|
|
hd = unionfs_get_hashhead(dvp, path);
|
|
|
|
LIST_FOREACH(unp, hd, un_hash) {
|
|
|
|
if (!strcmp(unp->un_path, path)) {
|
|
|
|
vp = UNIONFSTOV(unp);
|
|
|
|
VI_LOCK_FLAGS(vp, MTX_DUPOK);
|
|
|
|
VI_UNLOCK(dvp);
|
|
|
|
vp->v_iflag &= ~VI_OWEINACT;
|
|
|
|
if ((vp->v_iflag & (VI_DOOMED | VI_DOINGINACT)) != 0) {
|
|
|
|
VI_UNLOCK(vp);
|
|
|
|
vp = NULLVP;
|
|
|
|
} else
|
|
|
|
VI_UNLOCK(vp);
|
|
|
|
return (vp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VI_UNLOCK(dvp);
|
|
|
|
|
|
|
|
return (NULLVP);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the new vnode into cache. (only VDIR)
|
|
|
|
*/
|
|
|
|
static struct vnode *
|
|
|
|
unionfs_ins_cached_vdir(struct unionfs_node *uncp,
|
|
|
|
struct vnode *dvp, char *path)
|
|
|
|
{
|
|
|
|
struct unionfs_node_hashhead *hd;
|
|
|
|
struct unionfs_node *unp;
|
|
|
|
struct vnode *vp;
|
|
|
|
|
|
|
|
KASSERT((uncp->un_uppervp==NULLVP || uncp->un_uppervp->v_type==VDIR),
|
|
|
|
("unionfs_ins_cached_vdir: v_type != VDIR"));
|
|
|
|
KASSERT((uncp->un_lowervp==NULLVP || uncp->un_lowervp->v_type==VDIR),
|
|
|
|
("unionfs_ins_cached_vdir: v_type != VDIR"));
|
|
|
|
|
|
|
|
VI_LOCK(dvp);
|
|
|
|
hd = unionfs_get_hashhead(dvp, path);
|
|
|
|
LIST_FOREACH(unp, hd, un_hash) {
|
|
|
|
if (!strcmp(unp->un_path, path)) {
|
|
|
|
vp = UNIONFSTOV(unp);
|
|
|
|
VI_LOCK_FLAGS(vp, MTX_DUPOK);
|
|
|
|
vp->v_iflag &= ~VI_OWEINACT;
|
|
|
|
if ((vp->v_iflag & (VI_DOOMED | VI_DOINGINACT)) != 0) {
|
|
|
|
LIST_INSERT_HEAD(hd, uncp, un_hash);
|
|
|
|
VI_UNLOCK(vp);
|
|
|
|
vp = NULLVP;
|
|
|
|
} else
|
|
|
|
VI_UNLOCK(vp);
|
|
|
|
VI_UNLOCK(dvp);
|
|
|
|
return (vp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LIST_INSERT_HEAD(hd, uncp, un_hash);
|
|
|
|
VI_UNLOCK(dvp);
|
|
|
|
|
|
|
|
return (NULLVP);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove the vnode. (only VDIR)
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
unionfs_rem_cached_vdir(struct unionfs_node *unp, struct vnode *dvp)
|
|
|
|
{
|
|
|
|
KASSERT((unp != NULL), ("unionfs_rem_cached_vdir: null node"));
|
|
|
|
KASSERT((dvp != NULLVP),
|
|
|
|
("unionfs_rem_cached_vdir: null parent vnode"));
|
|
|
|
KASSERT((unp->un_hash.le_prev != NULL),
|
|
|
|
("unionfs_rem_cached_vdir: null hash"));
|
|
|
|
|
|
|
|
VI_LOCK(dvp);
|
|
|
|
LIST_REMOVE(unp, un_hash);
|
|
|
|
VI_UNLOCK(dvp);
|
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Make a new or get existing unionfs node.
|
|
|
|
*
|
|
|
|
* uppervp and lowervp should be unlocked. Because if new unionfs vnode is
|
|
|
|
* locked, uppervp or lowervp is locked too. In order to prevent dead lock,
|
|
|
|
* you should not lock plurality simultaneously.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
|
|
|
|
struct vnode *lowervp, struct vnode *dvp,
|
|
|
|
struct vnode **vpp, struct componentname *cnp,
|
|
|
|
struct thread *td)
|
|
|
|
{
|
|
|
|
struct unionfs_mount *ump;
|
|
|
|
struct unionfs_node *unp;
|
|
|
|
struct vnode *vp;
|
|
|
|
int error;
|
|
|
|
int lkflags;
|
2008-04-25 09:38:48 +00:00
|
|
|
enum vtype vt;
|
2006-12-02 19:35:56 +00:00
|
|
|
char *path;
|
|
|
|
|
|
|
|
ump = MOUNTTOUNIONFSMOUNT(mp);
|
|
|
|
lkflags = (cnp ? cnp->cn_lkflags : 0);
|
2007-10-14 13:46:11 +00:00
|
|
|
path = (cnp ? cnp->cn_nameptr : NULL);
|
2008-04-25 09:38:48 +00:00
|
|
|
*vpp = NULLVP;
|
2006-12-02 19:35:56 +00:00
|
|
|
|
|
|
|
if (uppervp == NULLVP && lowervp == NULLVP)
|
|
|
|
panic("unionfs_nodeget: upper and lower is null");
|
|
|
|
|
2008-04-25 09:38:48 +00:00
|
|
|
vt = (uppervp != NULLVP ? uppervp->v_type : lowervp->v_type);
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/* If it has no ISLASTCN flag, path check is skipped. */
|
2007-10-14 13:46:11 +00:00
|
|
|
if (cnp && !(cnp->cn_flags & ISLASTCN))
|
2006-12-02 19:35:56 +00:00
|
|
|
path = NULL;
|
|
|
|
|
2008-04-25 09:38:48 +00:00
|
|
|
/* check the vdir cache */
|
|
|
|
if (path != NULL && dvp != NULLVP && vt == VDIR) {
|
|
|
|
vp = unionfs_get_cached_vdir(uppervp, lowervp, dvp, path);
|
|
|
|
if (vp != NULLVP) {
|
|
|
|
vref(vp);
|
|
|
|
*vpp = vp;
|
|
|
|
goto unionfs_nodeget_out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
|
|
|
|
(lowervp == NULLVP || ump->um_lowervp != lowervp)) {
|
2008-04-25 09:38:48 +00:00
|
|
|
/* dvp will be NULLVP only in case of root vnode. */
|
2006-12-02 19:35:56 +00:00
|
|
|
if (dvp == NULLVP)
|
|
|
|
return (EINVAL);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Do the MALLOC before the getnewvnode since doing so afterward
|
|
|
|
* might cause a bogus v_data pointer to get dereferenced elsewhere
|
|
|
|
* if MALLOC should block.
|
|
|
|
*/
|
|
|
|
MALLOC(unp, struct unionfs_node *, sizeof(struct unionfs_node),
|
|
|
|
M_UNIONFSNODE, M_WAITOK | M_ZERO);
|
|
|
|
|
|
|
|
error = getnewvnode("unionfs", mp, &unionfs_vnodeops, &vp);
|
2007-10-14 13:46:11 +00:00
|
|
|
if (error != 0) {
|
2006-12-02 19:35:56 +00:00
|
|
|
FREE(unp, M_UNIONFSNODE);
|
|
|
|
return (error);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
2007-03-13 01:50:27 +00:00
|
|
|
error = insmntque(vp, mp); /* XXX: Too early for mpsafe fs */
|
|
|
|
if (error != 0) {
|
|
|
|
FREE(unp, M_UNIONFSNODE);
|
|
|
|
return (error);
|
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
if (dvp != NULLVP)
|
|
|
|
vref(dvp);
|
|
|
|
if (uppervp != NULLVP)
|
|
|
|
vref(uppervp);
|
|
|
|
if (lowervp != NULLVP)
|
|
|
|
vref(lowervp);
|
|
|
|
|
2008-04-25 09:38:48 +00:00
|
|
|
if (vt == VDIR)
|
|
|
|
unp->un_hashtbl = hashinit(NUNIONFSNODECACHE, M_UNIONFSHASH,
|
|
|
|
&(unp->un_hashmask));
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
unp->un_vnode = vp;
|
|
|
|
unp->un_uppervp = uppervp;
|
|
|
|
unp->un_lowervp = lowervp;
|
|
|
|
unp->un_dvp = dvp;
|
|
|
|
if (uppervp != NULLVP)
|
|
|
|
vp->v_vnlock = uppervp->v_vnlock;
|
|
|
|
else
|
|
|
|
vp->v_vnlock = lowervp->v_vnlock;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2007-10-14 13:46:11 +00:00
|
|
|
if (path != NULL) {
|
2006-12-02 19:35:56 +00:00
|
|
|
unp->un_path = (char *)
|
2007-10-14 13:46:11 +00:00
|
|
|
malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
|
2006-12-02 19:35:56 +00:00
|
|
|
bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen);
|
|
|
|
unp->un_path[cnp->cn_namelen] = '\0';
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
2008-04-25 09:38:48 +00:00
|
|
|
vp->v_type = vt;
|
2006-12-02 19:35:56 +00:00
|
|
|
vp->v_data = unp;
|
|
|
|
|
|
|
|
if ((uppervp != NULLVP && ump->um_uppervp == uppervp) &&
|
|
|
|
(lowervp != NULLVP && ump->um_lowervp == lowervp))
|
|
|
|
vp->v_vflag |= VV_ROOT;
|
|
|
|
|
2008-04-25 09:38:48 +00:00
|
|
|
if (path != NULL && dvp != NULLVP && vt == VDIR)
|
|
|
|
*vpp = unionfs_ins_cached_vdir(unp, dvp, path);
|
|
|
|
if ((*vpp) != NULLVP) {
|
|
|
|
if (dvp != NULLVP)
|
|
|
|
vrele(dvp);
|
|
|
|
if (uppervp != NULLVP)
|
|
|
|
vrele(uppervp);
|
|
|
|
if (lowervp != NULLVP)
|
|
|
|
vrele(lowervp);
|
|
|
|
|
|
|
|
unp->un_uppervp = NULLVP;
|
|
|
|
unp->un_lowervp = NULLVP;
|
|
|
|
unp->un_dvp = NULLVP;
|
|
|
|
vrele(vp);
|
|
|
|
vp = *vpp;
|
|
|
|
vref(vp);
|
|
|
|
} else
|
|
|
|
*vpp = vp;
|
|
|
|
|
|
|
|
unionfs_nodeget_out:
|
2006-12-02 19:35:56 +00:00
|
|
|
if (lkflags & LK_TYPE_MASK)
|
2008-01-10 01:10:58 +00:00
|
|
|
vn_lock(vp, lkflags | LK_RETRY);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
return (0);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
/*
|
2007-10-14 13:46:11 +00:00
|
|
|
* Clean up the unionfs node.
|
1997-02-10 02:22:35 +00:00
|
|
|
*/
|
|
|
|
void
|
2007-10-14 13:46:11 +00:00
|
|
|
unionfs_noderem(struct vnode *vp, struct thread *td)
|
1997-02-10 02:22:35 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int vfslocked;
|
|
|
|
struct unionfs_node *unp;
|
2006-12-09 16:27:50 +00:00
|
|
|
struct unionfs_node_status *unsp, *unsp_tmp;
|
2006-12-02 19:35:56 +00:00
|
|
|
struct vnode *lvp;
|
|
|
|
struct vnode *uvp;
|
2008-04-25 09:38:48 +00:00
|
|
|
struct vnode *dvp;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Use the interlock to protect the clearing of v_data to
|
|
|
|
* prevent faults in unionfs_lock().
|
|
|
|
*/
|
|
|
|
VI_LOCK(vp);
|
|
|
|
unp = VTOUNIONFS(vp);
|
|
|
|
lvp = unp->un_lowervp;
|
|
|
|
uvp = unp->un_uppervp;
|
2008-04-25 09:38:48 +00:00
|
|
|
dvp = unp->un_dvp;
|
2006-12-02 19:35:56 +00:00
|
|
|
unp->un_lowervp = unp->un_uppervp = NULLVP;
|
|
|
|
|
|
|
|
vp->v_vnlock = &(vp->v_lock);
|
|
|
|
vp->v_data = NULL;
|
2008-01-24 12:34:30 +00:00
|
|
|
lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_INTERLOCK, VI_MTX(vp));
|
2006-12-02 19:35:56 +00:00
|
|
|
if (lvp != NULLVP)
|
2008-01-13 14:44:15 +00:00
|
|
|
VOP_UNLOCK(lvp, 0);
|
2006-12-02 19:35:56 +00:00
|
|
|
if (uvp != NULLVP)
|
2008-01-13 14:44:15 +00:00
|
|
|
VOP_UNLOCK(uvp, 0);
|
2006-12-02 19:35:56 +00:00
|
|
|
vp->v_object = NULL;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2008-04-25 09:38:48 +00:00
|
|
|
if (unp->un_path != NULL && dvp != NULLVP && vp->v_type == VDIR)
|
|
|
|
unionfs_rem_cached_vdir(unp, dvp);
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (lvp != NULLVP) {
|
|
|
|
vfslocked = VFS_LOCK_GIANT(lvp->v_mount);
|
|
|
|
vrele(lvp);
|
|
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
if (uvp != NULLVP) {
|
|
|
|
vfslocked = VFS_LOCK_GIANT(uvp->v_mount);
|
|
|
|
vrele(uvp);
|
|
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
2008-04-25 09:38:48 +00:00
|
|
|
if (dvp != NULLVP) {
|
|
|
|
vfslocked = VFS_LOCK_GIANT(dvp->v_mount);
|
|
|
|
vrele(dvp);
|
2006-12-02 19:35:56 +00:00
|
|
|
VFS_UNLOCK_GIANT(vfslocked);
|
|
|
|
unp->un_dvp = NULLVP;
|
|
|
|
}
|
2008-04-25 09:38:48 +00:00
|
|
|
if (unp->un_path != NULL) {
|
2006-12-02 19:35:56 +00:00
|
|
|
free(unp->un_path, M_UNIONFSPATH);
|
|
|
|
unp->un_path = NULL;
|
|
|
|
}
|
2006-12-09 16:27:50 +00:00
|
|
|
|
2008-04-25 09:38:48 +00:00
|
|
|
if (unp->un_hashtbl != NULL)
|
|
|
|
hashdestroy(unp->un_hashtbl, M_UNIONFSHASH, unp->un_hashmask);
|
|
|
|
|
2006-12-09 16:27:50 +00:00
|
|
|
LIST_FOREACH_SAFE(unsp, &(unp->un_unshead), uns_list, unsp_tmp) {
|
2006-12-02 19:35:56 +00:00
|
|
|
LIST_REMOVE(unsp, uns_list);
|
|
|
|
free(unsp, M_TEMP);
|
|
|
|
}
|
|
|
|
FREE(unp, M_UNIONFSNODE);
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Get the unionfs node status.
|
|
|
|
* You need exclusive lock this vnode.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
2006-12-02 19:35:56 +00:00
|
|
|
void
|
|
|
|
unionfs_get_node_status(struct unionfs_node *unp, struct thread *td,
|
|
|
|
struct unionfs_node_status **unspp)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
struct unionfs_node_status *unsp;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
KASSERT(NULL != unspp, ("null pointer"));
|
|
|
|
ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
LIST_FOREACH(unsp, &(unp->un_unshead), uns_list) {
|
|
|
|
if (unsp->uns_tid == td->td_tid) {
|
|
|
|
*unspp = unsp;
|
|
|
|
return;
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/* create a new unionfs node status */
|
|
|
|
MALLOC(unsp, struct unionfs_node_status *,
|
|
|
|
sizeof(struct unionfs_node_status), M_TEMP, M_WAITOK | M_ZERO);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
unsp->uns_tid = td->td_tid;
|
|
|
|
LIST_INSERT_HEAD(&(unp->un_unshead), unsp, uns_list);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
*unspp = unsp;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Remove the unionfs node status, if you can.
|
|
|
|
* You need exclusive lock this vnode.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
unionfs_tryrem_node_status(struct unionfs_node *unp, struct thread *td,
|
|
|
|
struct unionfs_node_status *unsp)
|
|
|
|
{
|
|
|
|
KASSERT(NULL != unsp, ("null pointer"));
|
|
|
|
ASSERT_VOP_ELOCKED(UNIONFSTOV(unp), "unionfs_get_node_status");
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (0 < unsp->uns_lower_opencnt || 0 < unsp->uns_upper_opencnt)
|
|
|
|
return;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
LIST_REMOVE(unsp, uns_list);
|
|
|
|
free(unsp, M_TEMP);
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Create upper node attr.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
unionfs_create_uppervattr_core(struct unionfs_mount *ump,
|
|
|
|
struct vattr *lva,
|
|
|
|
struct vattr *uva,
|
|
|
|
struct thread *td)
|
|
|
|
{
|
|
|
|
VATTR_NULL(uva);
|
|
|
|
uva->va_type = lva->va_type;
|
|
|
|
uva->va_atime = lva->va_atime;
|
|
|
|
uva->va_mtime = lva->va_mtime;
|
|
|
|
uva->va_ctime = lva->va_ctime;
|
|
|
|
|
|
|
|
switch (ump->um_copymode) {
|
|
|
|
case UNIONFS_TRANSPARENT:
|
|
|
|
uva->va_mode = lva->va_mode;
|
|
|
|
uva->va_uid = lva->va_uid;
|
|
|
|
uva->va_gid = lva->va_gid;
|
|
|
|
break;
|
|
|
|
case UNIONFS_MASQUERADE:
|
|
|
|
if (ump->um_uid == lva->va_uid) {
|
|
|
|
uva->va_mode = lva->va_mode & 077077;
|
|
|
|
uva->va_mode |= (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile) & 0700;
|
|
|
|
uva->va_uid = lva->va_uid;
|
|
|
|
uva->va_gid = lva->va_gid;
|
1994-05-24 10:09:53 +00:00
|
|
|
} else {
|
2006-12-02 19:35:56 +00:00
|
|
|
uva->va_mode = (lva->va_type == VDIR ? ump->um_udir : ump->um_ufile);
|
|
|
|
uva->va_uid = ump->um_uid;
|
|
|
|
uva->va_gid = ump->um_gid;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
break;
|
|
|
|
default: /* UNIONFS_TRADITIONAL */
|
Replace custom file descriptor array sleep lock constructed using a mutex
and flags with an sxlock. This leads to a significant and measurable
performance improvement as a result of access to shared locking for
frequent lookup operations, reduced general overhead, and reduced overhead
in the event of contention. All of these are imported for threaded
applications where simultaneous access to a shared file descriptor array
occurs frequently. Kris has reported 2x-4x transaction rate improvements
on 8-core MySQL benchmarks; smaller improvements can be expected for many
workloads as a result of reduced overhead.
- Generally eliminate the distinction between "fast" and regular
acquisisition of the filedesc lock; the plan is that they will now all
be fast. Change all locking instances to either shared or exclusive
locks.
- Correct a bug (pointed out by kib) in fdfree() where previously msleep()
was called without the mutex held; sx_sleep() is now always called with
the sxlock held exclusively.
- Universally hold the struct file lock over changes to struct file,
rather than the filedesc lock or no lock. Always update the f_ops
field last. A further memory barrier is required here in the future
(discussed with jhb).
- Improve locking and reference management in linux_at(), which fails to
properly acquire vnode references before using vnode pointers. Annotate
improper use of vn_fullpath(), which will be replaced at a future date.
In fcntl(), we conservatively acquire an exclusive lock, even though in
some cases a shared lock may be sufficient, which should be revisited.
The dropping of the filedesc lock in fdgrowtable() is no longer required
as the sxlock can be held over the sleep operation; we should consider
removing that (pointed out by attilio).
Tested by: kris
Discussed with: jhb, kris, attilio, jeff
2007-04-04 09:11:34 +00:00
|
|
|
FILEDESC_SLOCK(td->td_proc->p_fd);
|
2006-12-02 19:35:56 +00:00
|
|
|
uva->va_mode = 0777 & ~td->td_proc->p_fd->fd_cmask;
|
Replace custom file descriptor array sleep lock constructed using a mutex
and flags with an sxlock. This leads to a significant and measurable
performance improvement as a result of access to shared locking for
frequent lookup operations, reduced general overhead, and reduced overhead
in the event of contention. All of these are imported for threaded
applications where simultaneous access to a shared file descriptor array
occurs frequently. Kris has reported 2x-4x transaction rate improvements
on 8-core MySQL benchmarks; smaller improvements can be expected for many
workloads as a result of reduced overhead.
- Generally eliminate the distinction between "fast" and regular
acquisisition of the filedesc lock; the plan is that they will now all
be fast. Change all locking instances to either shared or exclusive
locks.
- Correct a bug (pointed out by kib) in fdfree() where previously msleep()
was called without the mutex held; sx_sleep() is now always called with
the sxlock held exclusively.
- Universally hold the struct file lock over changes to struct file,
rather than the filedesc lock or no lock. Always update the f_ops
field last. A further memory barrier is required here in the future
(discussed with jhb).
- Improve locking and reference management in linux_at(), which fails to
properly acquire vnode references before using vnode pointers. Annotate
improper use of vn_fullpath(), which will be replaced at a future date.
In fcntl(), we conservatively acquire an exclusive lock, even though in
some cases a shared lock may be sufficient, which should be revisited.
The dropping of the filedesc lock in fdgrowtable() is no longer required
as the sxlock can be held over the sleep operation; we should consider
removing that (pointed out by attilio).
Tested by: kris
Discussed with: jhb, kris, attilio, jeff
2007-04-04 09:11:34 +00:00
|
|
|
FILEDESC_SUNLOCK(td->td_proc->p_fd);
|
2006-12-02 19:35:56 +00:00
|
|
|
uva->va_uid = ump->um_uid;
|
|
|
|
uva->va_gid = ump->um_gid;
|
|
|
|
break;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* Create upper node attr.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
unionfs_create_uppervattr(struct unionfs_mount *ump,
|
|
|
|
struct vnode *lvp,
|
|
|
|
struct vattr *uva,
|
|
|
|
struct ucred *cred,
|
|
|
|
struct thread *td)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
struct vattr lva;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((error = VOP_GETATTR(lvp, &lva, cred, td)))
|
|
|
|
return (error);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_create_uppervattr_core(ump, &lva, uva, td);
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
return (error);
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* relookup
|
|
|
|
*
|
|
|
|
* dvp should be locked on entry and will be locked on return.
|
|
|
|
*
|
|
|
|
* If an error is returned, *vpp will be invalid, otherwise it will hold a
|
|
|
|
* locked, referenced vnode. If *vpp == dvp then remember that only one
|
|
|
|
* LK_EXCLUSIVE lock is held.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
unionfs_relookup(struct vnode *dvp, struct vnode **vpp,
|
|
|
|
struct componentname *cnp, struct componentname *cn,
|
|
|
|
struct thread *td, char *path, int pathlen, u_long nameiop)
|
|
|
|
{
|
|
|
|
int error;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
cn->cn_namelen = pathlen;
|
|
|
|
cn->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
|
|
|
|
bcopy(path, cn->cn_pnbuf, pathlen);
|
|
|
|
cn->cn_pnbuf[pathlen] = '\0';
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
cn->cn_nameiop = nameiop;
|
|
|
|
cn->cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
|
|
|
|
cn->cn_lkflags = LK_EXCLUSIVE;
|
|
|
|
cn->cn_thread = td;
|
|
|
|
cn->cn_cred = cnp->cn_cred;
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
cn->cn_nameptr = cn->cn_pnbuf;
|
|
|
|
cn->cn_consume = cnp->cn_consume;
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (nameiop == DELETE)
|
|
|
|
cn->cn_flags |= (cnp->cn_flags & (DOWHITEOUT | SAVESTART));
|
|
|
|
else if (RENAME == nameiop)
|
|
|
|
cn->cn_flags |= (cnp->cn_flags & SAVESTART);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
vref(dvp);
|
2008-01-13 14:44:15 +00:00
|
|
|
VOP_UNLOCK(dvp, 0);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((error = relookup(dvp, vpp, cn))) {
|
|
|
|
uma_zfree(namei_zone, cn->cn_pnbuf);
|
|
|
|
cn->cn_flags &= ~HASBUF;
|
2008-01-10 01:10:58 +00:00
|
|
|
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
|
2006-12-02 19:35:56 +00:00
|
|
|
} else
|
|
|
|
vrele(dvp);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* relookup for CREATE namei operation.
|
|
|
|
*
|
|
|
|
* dvp is unionfs vnode. dvp should be locked.
|
|
|
|
*
|
|
|
|
* If it called 'unionfs_copyfile' function by unionfs_link etc,
|
|
|
|
* VOP_LOOKUP information is broken.
|
|
|
|
* So it need relookup in order to create link etc.
|
|
|
|
*/
|
1994-05-24 10:09:53 +00:00
|
|
|
int
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_relookup_for_create(struct vnode *dvp, struct componentname *cnp,
|
|
|
|
struct thread *td)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int error;
|
|
|
|
struct vnode *udvp;
|
|
|
|
struct vnode *vp;
|
|
|
|
struct componentname cn;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
udvp = UNIONFSVPTOUPPERVP(dvp);
|
|
|
|
vp = NULLVP;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
|
|
|
|
strlen(cnp->cn_nameptr), CREATE);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
if (vp != NULLVP) {
|
|
|
|
if (udvp == vp)
|
|
|
|
vrele(vp);
|
|
|
|
else
|
|
|
|
vput(vp);
|
|
|
|
|
|
|
|
error = EEXIST;
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
|
|
|
|
if (cn.cn_flags & HASBUF) {
|
|
|
|
uma_zfree(namei_zone, cn.cn_pnbuf);
|
|
|
|
cn.cn_flags &= ~HASBUF;
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (!error) {
|
|
|
|
cn.cn_flags |= (cnp->cn_flags & HASBUF);
|
|
|
|
cnp->cn_flags = cn.cn_flags;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
return (error);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* relookup for DELETE namei operation.
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
*
|
2006-12-02 19:35:56 +00:00
|
|
|
* dvp is unionfs vnode. dvp should be locked.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
2006-12-02 19:35:56 +00:00
|
|
|
int
|
|
|
|
unionfs_relookup_for_delete(struct vnode *dvp, struct componentname *cnp,
|
|
|
|
struct thread *td)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int error;
|
|
|
|
struct vnode *udvp;
|
|
|
|
struct vnode *vp;
|
|
|
|
struct componentname cn;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
udvp = UNIONFSVPTOUPPERVP(dvp);
|
|
|
|
vp = NULLVP;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
|
|
|
|
strlen(cnp->cn_nameptr), DELETE);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (vp == NULLVP)
|
|
|
|
error = ENOENT;
|
|
|
|
else {
|
|
|
|
if (udvp == vp)
|
|
|
|
vrele(vp);
|
|
|
|
else
|
|
|
|
vput(vp);
|
|
|
|
}
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (cn.cn_flags & HASBUF) {
|
|
|
|
uma_zfree(namei_zone, cn.cn_pnbuf);
|
|
|
|
cn.cn_flags &= ~HASBUF;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (!error) {
|
|
|
|
cn.cn_flags |= (cnp->cn_flags & HASBUF);
|
|
|
|
cnp->cn_flags = cn.cn_flags;
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* relookup for RENAME namei operation.
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
*
|
2006-12-02 19:35:56 +00:00
|
|
|
* dvp is unionfs vnode. dvp should be locked.
|
1997-02-10 02:22:35 +00:00
|
|
|
*/
|
|
|
|
int
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_relookup_for_rename(struct vnode *dvp, struct componentname *cnp,
|
|
|
|
struct thread *td)
|
1997-02-10 02:22:35 +00:00
|
|
|
{
|
|
|
|
int error;
|
2006-12-02 19:35:56 +00:00
|
|
|
struct vnode *udvp;
|
|
|
|
struct vnode *vp;
|
|
|
|
struct componentname cn;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
udvp = UNIONFSVPTOUPPERVP(dvp);
|
|
|
|
vp = NULLVP;
|
|
|
|
|
|
|
|
error = unionfs_relookup(udvp, &vp, cnp, &cn, td, cnp->cn_nameptr,
|
|
|
|
strlen(cnp->cn_nameptr), RENAME);
|
1997-08-14 03:57:46 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (vp != NULLVP) {
|
|
|
|
if (udvp == vp)
|
|
|
|
vrele(vp);
|
|
|
|
else
|
|
|
|
vput(vp);
|
2000-07-11 22:07:57 +00:00
|
|
|
}
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (cn.cn_flags & HASBUF) {
|
|
|
|
uma_zfree(namei_zone, cn.cn_pnbuf);
|
|
|
|
cn.cn_flags &= ~HASBUF;
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (!error) {
|
|
|
|
cn.cn_flags |= (cnp->cn_flags & HASBUF);
|
|
|
|
cnp->cn_flags = cn.cn_flags;
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Update the unionfs_node.
|
|
|
|
*
|
|
|
|
* uvp is new locked upper vnode. unionfs vnode's lock will be exchanged to the
|
|
|
|
* uvp's lock and lower's lock will be unlocked.
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
*/
|
2006-12-02 19:35:56 +00:00
|
|
|
static void
|
|
|
|
unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp,
|
|
|
|
struct thread *td)
|
1997-02-10 02:22:35 +00:00
|
|
|
{
|
Optimize lockmgr in order to get rid of the pool mutex interlock, of the
state transitioning flags and of msleep(9) callings.
Use, instead, an algorithm very similar to what sx(9) and rwlock(9)
alredy do and direct accesses to the sleepqueue(9) primitive.
In order to avoid writer starvation a mechanism very similar to what
rwlock(9) uses now is implemented, with the correspective per-thread
shared lockmgrs counter.
This patch also adds 2 new functions to lockmgr KPI: lockmgr_rw() and
lockmgr_args_rw(). These two are like the 2 "normal" versions, but they
both accept a rwlock as interlock. In order to realize this, the general
lockmgr manager function "__lockmgr_args()" has been implemented through
the generic lock layer. It supports all the blocking primitives, but
currently only these 2 mappers live.
The patch drops the support for WITNESS atm, but it will be probabilly
added soon. Also, there is a little race in the draining code which is
also present in the current CVS stock implementation: if some sharers,
once they wakeup, are in the runqueue they can contend the lock with
the exclusive drainer. This is hard to be fixed but the now committed
code mitigate this issue a lot better than the (past) CVS version.
In addition assertive KA_HELD and KA_UNHELD have been made mute
assertions because they are dangerous and they will be nomore supported
soon.
In order to avoid namespace pollution, stack.h is splitted into two
parts: one which includes only the "struct stack" definition (_stack.h)
and one defining the KPI. In this way, newly added _lockmgr.h can
just include _stack.h.
Kernel ABI results heavilly changed by this commit (the now committed
version of "struct lock" is a lot smaller than the previous one) and
KPI results broken by lockmgr_rw() / lockmgr_args_rw() introduction,
so manpages and __FreeBSD_version will be updated accordingly.
Tested by: kris, pho, jeff, danger
Reviewed by: jeff
Sponsored by: Google, Summer of Code program 2007
2008-04-06 20:08:51 +00:00
|
|
|
unsigned count, lockrec;
|
2006-12-02 19:35:56 +00:00
|
|
|
struct vnode *vp;
|
|
|
|
struct vnode *lvp;
|
2008-04-25 09:38:48 +00:00
|
|
|
struct vnode *dvp;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
vp = UNIONFSTOV(unp);
|
|
|
|
lvp = unp->un_lowervp;
|
Optimize lockmgr in order to get rid of the pool mutex interlock, of the
state transitioning flags and of msleep(9) callings.
Use, instead, an algorithm very similar to what sx(9) and rwlock(9)
alredy do and direct accesses to the sleepqueue(9) primitive.
In order to avoid writer starvation a mechanism very similar to what
rwlock(9) uses now is implemented, with the correspective per-thread
shared lockmgrs counter.
This patch also adds 2 new functions to lockmgr KPI: lockmgr_rw() and
lockmgr_args_rw(). These two are like the 2 "normal" versions, but they
both accept a rwlock as interlock. In order to realize this, the general
lockmgr manager function "__lockmgr_args()" has been implemented through
the generic lock layer. It supports all the blocking primitives, but
currently only these 2 mappers live.
The patch drops the support for WITNESS atm, but it will be probabilly
added soon. Also, there is a little race in the draining code which is
also present in the current CVS stock implementation: if some sharers,
once they wakeup, are in the runqueue they can contend the lock with
the exclusive drainer. This is hard to be fixed but the now committed
code mitigate this issue a lot better than the (past) CVS version.
In addition assertive KA_HELD and KA_UNHELD have been made mute
assertions because they are dangerous and they will be nomore supported
soon.
In order to avoid namespace pollution, stack.h is splitted into two
parts: one which includes only the "struct stack" definition (_stack.h)
and one defining the KPI. In this way, newly added _lockmgr.h can
just include _stack.h.
Kernel ABI results heavilly changed by this commit (the now committed
version of "struct lock" is a lot smaller than the previous one) and
KPI results broken by lockmgr_rw() / lockmgr_args_rw() introduction,
so manpages and __FreeBSD_version will be updated accordingly.
Tested by: kris, pho, jeff, danger
Reviewed by: jeff
Sponsored by: Google, Summer of Code program 2007
2008-04-06 20:08:51 +00:00
|
|
|
ASSERT_VOP_ELOCKED(lvp, "unionfs_node_update");
|
2008-04-25 09:38:48 +00:00
|
|
|
dvp = unp->un_dvp;
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* lock update
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
*/
|
2006-12-02 19:35:56 +00:00
|
|
|
VI_LOCK(vp);
|
|
|
|
unp->un_uppervp = uvp;
|
|
|
|
vp->v_vnlock = uvp->v_vnlock;
|
|
|
|
VI_UNLOCK(vp);
|
Optimize lockmgr in order to get rid of the pool mutex interlock, of the
state transitioning flags and of msleep(9) callings.
Use, instead, an algorithm very similar to what sx(9) and rwlock(9)
alredy do and direct accesses to the sleepqueue(9) primitive.
In order to avoid writer starvation a mechanism very similar to what
rwlock(9) uses now is implemented, with the correspective per-thread
shared lockmgrs counter.
This patch also adds 2 new functions to lockmgr KPI: lockmgr_rw() and
lockmgr_args_rw(). These two are like the 2 "normal" versions, but they
both accept a rwlock as interlock. In order to realize this, the general
lockmgr manager function "__lockmgr_args()" has been implemented through
the generic lock layer. It supports all the blocking primitives, but
currently only these 2 mappers live.
The patch drops the support for WITNESS atm, but it will be probabilly
added soon. Also, there is a little race in the draining code which is
also present in the current CVS stock implementation: if some sharers,
once they wakeup, are in the runqueue they can contend the lock with
the exclusive drainer. This is hard to be fixed but the now committed
code mitigate this issue a lot better than the (past) CVS version.
In addition assertive KA_HELD and KA_UNHELD have been made mute
assertions because they are dangerous and they will be nomore supported
soon.
In order to avoid namespace pollution, stack.h is splitted into two
parts: one which includes only the "struct stack" definition (_stack.h)
and one defining the KPI. In this way, newly added _lockmgr.h can
just include _stack.h.
Kernel ABI results heavilly changed by this commit (the now committed
version of "struct lock" is a lot smaller than the previous one) and
KPI results broken by lockmgr_rw() / lockmgr_args_rw() introduction,
so manpages and __FreeBSD_version will be updated accordingly.
Tested by: kris, pho, jeff, danger
Reviewed by: jeff
Sponsored by: Google, Summer of Code program 2007
2008-04-06 20:08:51 +00:00
|
|
|
lockrec = lvp->v_vnlock->lk_recurse;
|
|
|
|
for (count = 0; count < lockrec; count++)
|
2008-01-10 01:10:58 +00:00
|
|
|
vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY);
|
2008-04-25 09:38:48 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* cache update
|
|
|
|
*/
|
|
|
|
if (unp->un_path != NULL && dvp != NULLVP && vp->v_type == VDIR) {
|
|
|
|
static struct unionfs_node_hashhead *hd;
|
|
|
|
|
|
|
|
VI_LOCK(dvp);
|
|
|
|
hd = unionfs_get_hashhead(dvp, unp->un_path);
|
|
|
|
LIST_REMOVE(unp, un_hash);
|
|
|
|
LIST_INSERT_HEAD(hd, unp, un_hash);
|
|
|
|
VI_UNLOCK(dvp);
|
|
|
|
}
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Create a new shadow dir.
|
|
|
|
*
|
|
|
|
* udvp should be locked on entry and will be locked on return.
|
|
|
|
*
|
|
|
|
* If no error returned, unp will be updated.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
int
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp,
|
|
|
|
struct unionfs_node *unp, struct componentname *cnp,
|
|
|
|
struct thread *td)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int error;
|
|
|
|
struct vnode *lvp;
|
|
|
|
struct vnode *uvp;
|
|
|
|
struct vattr va;
|
|
|
|
struct vattr lva;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct componentname cn;
|
2006-12-02 19:35:56 +00:00
|
|
|
struct mount *mp;
|
|
|
|
struct ucred *cred;
|
|
|
|
struct ucred *credbk;
|
|
|
|
struct uidinfo *rootinfo;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (unp->un_uppervp != NULLVP)
|
|
|
|
return (EEXIST);
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
lvp = unp->un_lowervp;
|
|
|
|
uvp = NULLVP;
|
|
|
|
credbk = cnp->cn_cred;
|
|
|
|
|
|
|
|
/* Authority change to root */
|
|
|
|
rootinfo = uifind((uid_t)0);
|
|
|
|
cred = crdup(cnp->cn_cred);
|
|
|
|
chgproccnt(cred->cr_ruidinfo, 1, 0);
|
|
|
|
change_euid(cred, rootinfo);
|
|
|
|
change_ruid(cred, rootinfo);
|
|
|
|
change_svuid(cred, (uid_t)0);
|
|
|
|
uifree(rootinfo);
|
|
|
|
cnp->cn_cred = cred;
|
|
|
|
|
|
|
|
memset(&cn, 0, sizeof(cn));
|
|
|
|
|
|
|
|
if ((error = VOP_GETATTR(lvp, &lva, cnp->cn_cred, td)))
|
|
|
|
goto unionfs_mkshadowdir_abort;
|
|
|
|
|
|
|
|
if ((error = unionfs_relookup(udvp, &uvp, cnp, &cn, td, cnp->cn_nameptr, cnp->cn_namelen, CREATE)))
|
|
|
|
goto unionfs_mkshadowdir_abort;
|
|
|
|
if (uvp != NULLVP) {
|
|
|
|
if (udvp == uvp)
|
|
|
|
vrele(uvp);
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
else
|
2006-12-02 19:35:56 +00:00
|
|
|
vput(uvp);
|
|
|
|
|
|
|
|
error = EEXIST;
|
|
|
|
goto unionfs_mkshadowdir_free_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)))
|
|
|
|
goto unionfs_mkshadowdir_free_out;
|
|
|
|
if ((error = VOP_LEASE(udvp, td, cn.cn_cred, LEASE_WRITE))) {
|
2000-07-11 22:07:57 +00:00
|
|
|
vn_finished_write(mp);
|
2006-12-02 19:35:56 +00:00
|
|
|
goto unionfs_mkshadowdir_free_out;
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_create_uppervattr_core(ump, &lva, &va, td);
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
error = VOP_MKDIR(udvp, &uvp, &cn, &va);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (!error) {
|
|
|
|
unionfs_node_update(unp, uvp, td);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* XXX The bug which cannot set uid/gid was corrected.
|
|
|
|
* Ignore errors.
|
|
|
|
*/
|
|
|
|
va.va_type = VNON;
|
|
|
|
VOP_SETATTR(uvp, &va, cn.cn_cred, td);
|
|
|
|
}
|
|
|
|
vn_finished_write(mp);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_mkshadowdir_free_out:
|
1999-12-15 23:02:35 +00:00
|
|
|
if (cn.cn_flags & HASBUF) {
|
2002-04-08 06:57:43 +00:00
|
|
|
uma_zfree(namei_zone, cn.cn_pnbuf);
|
1999-12-15 23:02:35 +00:00
|
|
|
cn.cn_flags &= ~HASBUF;
|
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
|
|
|
|
unionfs_mkshadowdir_abort:
|
|
|
|
cnp->cn_cred = credbk;
|
|
|
|
chgproccnt(cred->cr_ruidinfo, -1, 0);
|
|
|
|
crfree(cred);
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Create a new whiteout.
|
|
|
|
*
|
|
|
|
* dvp should be locked on entry and will be locked on return.
|
1997-02-10 02:22:35 +00:00
|
|
|
*/
|
|
|
|
int
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_mkwhiteout(struct vnode *dvp, struct componentname *cnp,
|
|
|
|
struct thread *td, char *path)
|
1997-02-10 02:22:35 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int error;
|
|
|
|
struct vnode *wvp;
|
1997-02-10 02:22:35 +00:00
|
|
|
struct componentname cn;
|
2006-12-02 19:35:56 +00:00
|
|
|
struct mount *mp;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (path == NULL)
|
|
|
|
path = cnp->cn_nameptr;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
wvp = NULLVP;
|
|
|
|
if ((error = unionfs_relookup(dvp, &wvp, cnp, &cn, td, path, strlen(path), CREATE)))
|
|
|
|
return (error);
|
|
|
|
if (wvp != NULLVP) {
|
1999-12-15 23:02:35 +00:00
|
|
|
if (cn.cn_flags & HASBUF) {
|
2002-04-08 06:57:43 +00:00
|
|
|
uma_zfree(namei_zone, cn.cn_pnbuf);
|
1999-12-15 23:02:35 +00:00
|
|
|
cn.cn_flags &= ~HASBUF;
|
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
if (dvp == wvp)
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
vrele(wvp);
|
|
|
|
else
|
|
|
|
vput(wvp);
|
2006-12-02 19:35:56 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
return (EEXIST);
|
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((error = vn_start_write(dvp, &mp, V_WAIT | PCATCH)))
|
|
|
|
goto unionfs_mkwhiteout_free_out;
|
|
|
|
if (!(error = VOP_LEASE(dvp, td, td->td_ucred, LEASE_WRITE)))
|
|
|
|
error = VOP_WHITEOUT(dvp, &cn, CREATE);
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
vn_finished_write(mp);
|
|
|
|
|
|
|
|
unionfs_mkwhiteout_free_out:
|
1999-12-15 23:02:35 +00:00
|
|
|
if (cn.cn_flags & HASBUF) {
|
2002-04-08 06:57:43 +00:00
|
|
|
uma_zfree(namei_zone, cn.cn_pnbuf);
|
1999-12-15 23:02:35 +00:00
|
|
|
cn.cn_flags &= ~HASBUF;
|
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Create a new vnode for create a new shadow file.
|
|
|
|
*
|
|
|
|
* If an error is returned, *vpp will be invalid, otherwise it will hold a
|
|
|
|
* locked, referenced and opened vnode.
|
|
|
|
*
|
|
|
|
* unp is never updated.
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
1997-11-18 15:07:35 +00:00
|
|
|
static int
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_vn_create_on_upper(struct vnode **vpp, struct vnode *udvp,
|
|
|
|
struct unionfs_node *unp, struct vattr *uvap,
|
|
|
|
struct thread *td)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
struct unionfs_mount *ump;
|
|
|
|
struct vnode *vp;
|
|
|
|
struct vnode *lvp;
|
|
|
|
struct ucred *cred;
|
|
|
|
struct vattr lva;
|
|
|
|
int fmode;
|
|
|
|
int error;
|
1994-05-24 10:09:53 +00:00
|
|
|
struct componentname cn;
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
ump = MOUNTTOUNIONFSMOUNT(UNIONFSTOV(unp)->v_mount);
|
|
|
|
vp = NULLVP;
|
|
|
|
lvp = unp->un_lowervp;
|
|
|
|
cred = td->td_ucred;
|
|
|
|
fmode = FFLAGS(O_WRONLY | O_CREAT | O_TRUNC | O_EXCL);
|
|
|
|
error = 0;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((error = VOP_GETATTR(lvp, &lva, cred, td)) != 0)
|
|
|
|
return (error);
|
|
|
|
unionfs_create_uppervattr_core(ump, &lva, uvap, td);
|
|
|
|
|
|
|
|
if (unp->un_path == NULL)
|
|
|
|
panic("unionfs: un_path is null");
|
|
|
|
|
|
|
|
cn.cn_namelen = strlen(unp->un_path);
|
2003-02-19 05:47:46 +00:00
|
|
|
cn.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
|
2006-12-02 19:35:56 +00:00
|
|
|
bcopy(unp->un_path, cn.cn_pnbuf, cn.cn_namelen + 1);
|
1994-05-24 10:09:53 +00:00
|
|
|
cn.cn_nameiop = CREATE;
|
2006-12-02 19:35:56 +00:00
|
|
|
cn.cn_flags = (LOCKPARENT | LOCKLEAF | HASBUF | SAVENAME | ISLASTCN);
|
|
|
|
cn.cn_lkflags = LK_EXCLUSIVE;
|
2001-09-12 08:38:13 +00:00
|
|
|
cn.cn_thread = td;
|
2006-12-02 19:35:56 +00:00
|
|
|
cn.cn_cred = cred;
|
1994-05-24 10:09:53 +00:00
|
|
|
cn.cn_nameptr = cn.cn_pnbuf;
|
|
|
|
cn.cn_consume = 0;
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
vref(udvp);
|
|
|
|
if ((error = relookup(udvp, &vp, &cn)) != 0)
|
|
|
|
goto unionfs_vn_create_on_upper_free_out2;
|
|
|
|
vrele(udvp);
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (vp != NULLVP) {
|
|
|
|
if (vp == udvp)
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
vrele(vp);
|
1994-05-24 10:09:53 +00:00
|
|
|
else
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
vput(vp);
|
2006-12-02 19:35:56 +00:00
|
|
|
error = EEXIST;
|
|
|
|
goto unionfs_vn_create_on_upper_free_out1;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((error = VOP_LEASE(udvp, td, cred, LEASE_WRITE)) != 0)
|
|
|
|
goto unionfs_vn_create_on_upper_free_out1;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((error = VOP_CREATE(udvp, &vp, &cn, uvap)) != 0)
|
|
|
|
goto unionfs_vn_create_on_upper_free_out1;
|
|
|
|
|
2007-05-31 11:51:53 +00:00
|
|
|
if ((error = VOP_OPEN(vp, fmode, cred, td, NULL)) != 0) {
|
1994-05-24 10:09:53 +00:00
|
|
|
vput(vp);
|
2006-12-02 19:35:56 +00:00
|
|
|
goto unionfs_vn_create_on_upper_free_out1;
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
vp->v_writecount++;
|
|
|
|
*vpp = vp;
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_vn_create_on_upper_free_out1:
|
2008-01-13 14:44:15 +00:00
|
|
|
VOP_UNLOCK(udvp, 0);
|
2006-12-02 19:35:56 +00:00
|
|
|
|
|
|
|
unionfs_vn_create_on_upper_free_out2:
|
|
|
|
if (cn.cn_flags & HASBUF) {
|
|
|
|
uma_zfree(namei_zone, cn.cn_pnbuf);
|
|
|
|
cn.cn_flags &= ~HASBUF;
|
|
|
|
}
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
return (error);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Copy from lvp to uvp.
|
|
|
|
*
|
|
|
|
* lvp and uvp should be locked and opened on entry and will be locked and
|
|
|
|
* opened on return.
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
*/
|
2006-12-02 19:35:56 +00:00
|
|
|
static int
|
|
|
|
unionfs_copyfile_core(struct vnode *lvp, struct vnode *uvp,
|
|
|
|
struct ucred *cred, struct thread *td)
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int error;
|
|
|
|
off_t offset;
|
|
|
|
int count;
|
|
|
|
int bufoffset;
|
|
|
|
char *buf;
|
|
|
|
struct uio uio;
|
|
|
|
struct iovec iov;
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
memset(&uio, 0, sizeof(uio));
|
|
|
|
|
|
|
|
uio.uio_td = td;
|
|
|
|
uio.uio_segflg = UIO_SYSSPACE;
|
|
|
|
uio.uio_offset = 0;
|
|
|
|
|
|
|
|
if ((error = VOP_LEASE(lvp, td, cred, LEASE_READ)) != 0)
|
|
|
|
return (error);
|
|
|
|
if ((error = VOP_LEASE(uvp, td, cred, LEASE_WRITE)) != 0)
|
|
|
|
return (error);
|
|
|
|
buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);
|
|
|
|
|
|
|
|
while (error == 0) {
|
|
|
|
offset = uio.uio_offset;
|
|
|
|
|
|
|
|
uio.uio_iov = &iov;
|
|
|
|
uio.uio_iovcnt = 1;
|
|
|
|
iov.iov_base = buf;
|
|
|
|
iov.iov_len = MAXBSIZE;
|
|
|
|
uio.uio_resid = iov.iov_len;
|
|
|
|
uio.uio_rw = UIO_READ;
|
|
|
|
|
|
|
|
if ((error = VOP_READ(lvp, &uio, 0, cred)) != 0)
|
|
|
|
break;
|
|
|
|
if ((count = MAXBSIZE - uio.uio_resid) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
bufoffset = 0;
|
|
|
|
while (bufoffset < count) {
|
|
|
|
uio.uio_iov = &iov;
|
|
|
|
uio.uio_iovcnt = 1;
|
|
|
|
iov.iov_base = buf + bufoffset;
|
|
|
|
iov.iov_len = count - bufoffset;
|
|
|
|
uio.uio_offset = offset + bufoffset;
|
|
|
|
uio.uio_resid = iov.iov_len;
|
|
|
|
uio.uio_rw = UIO_WRITE;
|
|
|
|
|
|
|
|
if ((error = VOP_WRITE(uvp, &uio, 0, cred)) != 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
bufoffset += (count - bufoffset) - uio.uio_resid;
|
|
|
|
}
|
|
|
|
|
|
|
|
uio.uio_offset = offset + bufoffset;
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
|
|
|
|
free(buf, M_TEMP);
|
|
|
|
|
|
|
|
return (error);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
1997-02-10 02:22:35 +00:00
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* Copy file from lower to upper.
|
|
|
|
*
|
|
|
|
* If you need copy of the contents, set 1 to docopy. Otherwise, set 0 to
|
|
|
|
* docopy.
|
|
|
|
*
|
|
|
|
* If no error returned, unp will be updated.
|
1997-02-10 02:22:35 +00:00
|
|
|
*/
|
|
|
|
int
|
2006-12-02 19:35:56 +00:00
|
|
|
unionfs_copyfile(struct unionfs_node *unp, int docopy, struct ucred *cred,
|
|
|
|
struct thread *td)
|
1997-02-10 02:22:35 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int error;
|
|
|
|
struct mount *mp;
|
|
|
|
struct vnode *udvp;
|
|
|
|
struct vnode *lvp;
|
|
|
|
struct vnode *uvp;
|
|
|
|
struct vattr uva;
|
|
|
|
|
|
|
|
lvp = unp->un_lowervp;
|
|
|
|
uvp = NULLVP;
|
|
|
|
|
|
|
|
if ((UNIONFSTOV(unp)->v_mount->mnt_flag & MNT_RDONLY))
|
|
|
|
return (EROFS);
|
|
|
|
if (unp->un_dvp == NULLVP)
|
|
|
|
return (EINVAL);
|
|
|
|
if (unp->un_uppervp != NULLVP)
|
|
|
|
return (EEXIST);
|
|
|
|
udvp = VTOUNIONFS(unp->un_dvp)->un_uppervp;
|
|
|
|
if (udvp == NULLVP)
|
|
|
|
return (EROFS);
|
|
|
|
if ((udvp->v_mount->mnt_flag & MNT_RDONLY))
|
|
|
|
return (EROFS);
|
|
|
|
|
|
|
|
error = VOP_ACCESS(lvp, VREAD, cred, td);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if ((error = vn_start_write(udvp, &mp, V_WAIT | PCATCH)) != 0)
|
|
|
|
return (error);
|
|
|
|
error = unionfs_vn_create_on_upper(&uvp, udvp, unp, &uva, td);
|
|
|
|
if (error != 0) {
|
|
|
|
vn_finished_write(mp);
|
|
|
|
return (error);
|
|
|
|
}
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (docopy != 0) {
|
2007-05-31 11:51:53 +00:00
|
|
|
error = VOP_OPEN(lvp, FREAD, cred, td, NULL);
|
2006-12-02 19:35:56 +00:00
|
|
|
if (error == 0) {
|
|
|
|
error = unionfs_copyfile_core(lvp, uvp, cred, td);
|
|
|
|
VOP_CLOSE(lvp, FREAD, cred, td);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOP_CLOSE(uvp, FWRITE, cred, td);
|
|
|
|
uvp->v_writecount--;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
vn_finished_write(mp);
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (error == 0) {
|
|
|
|
/* Reset the attributes. Ignore errors. */
|
|
|
|
uva.va_type = VNON;
|
|
|
|
VOP_SETATTR(uvp, &uva, cred, td);
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
|
|
|
|
unionfs_node_update(unp, uvp, td);
|
|
|
|
|
|
|
|
return (error);
|
1997-02-10 02:22:35 +00:00
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* It checks whether vp can rmdir. (check empty)
|
|
|
|
*
|
|
|
|
* vp is unionfs vnode.
|
|
|
|
* vp should be locked.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
unionfs_check_rmdir(struct vnode *vp, struct ucred *cred, struct thread *td)
|
1997-02-10 02:22:35 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
int error;
|
|
|
|
int eofflag;
|
|
|
|
int lookuperr;
|
|
|
|
struct vnode *uvp;
|
|
|
|
struct vnode *lvp;
|
|
|
|
struct vnode *tvp;
|
|
|
|
struct vattr va;
|
|
|
|
struct componentname cn;
|
|
|
|
/*
|
|
|
|
* The size of buf needs to be larger than DIRBLKSIZ.
|
|
|
|
*/
|
|
|
|
char buf[256 * 6];
|
|
|
|
struct dirent *dp;
|
|
|
|
struct dirent *edp;
|
|
|
|
struct uio uio;
|
|
|
|
struct iovec iov;
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
ASSERT_VOP_ELOCKED(vp, "unionfs_check_rmdir");
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
eofflag = 0;
|
|
|
|
uvp = UNIONFSVPTOUPPERVP(vp);
|
|
|
|
lvp = UNIONFSVPTOLOWERVP(vp);
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/* check opaque */
|
|
|
|
if ((error = VOP_GETATTR(uvp, &va, cred, td)) != 0)
|
|
|
|
return (error);
|
|
|
|
if (va.va_flags & OPAQUE)
|
|
|
|
return (0);
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/* open vnode */
|
2007-10-14 13:37:52 +00:00
|
|
|
#ifdef MAC
|
2007-10-24 19:04:04 +00:00
|
|
|
if ((error = mac_vnode_check_open(cred, vp, VEXEC|VREAD)) != 0)
|
2007-10-14 13:37:52 +00:00
|
|
|
return (error);
|
|
|
|
#endif
|
|
|
|
if ((error = VOP_ACCESS(vp, VEXEC|VREAD, cred, td)) != 0)
|
|
|
|
return (error);
|
2007-05-31 11:51:53 +00:00
|
|
|
if ((error = VOP_OPEN(vp, FREAD, cred, td, NULL)) != 0)
|
2006-12-02 19:35:56 +00:00
|
|
|
return (error);
|
1997-02-10 02:22:35 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
uio.uio_rw = UIO_READ;
|
|
|
|
uio.uio_segflg = UIO_SYSSPACE;
|
|
|
|
uio.uio_td = td;
|
|
|
|
uio.uio_offset = 0;
|
2003-06-13 08:59:37 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
#ifdef MAC
|
2007-10-24 19:04:04 +00:00
|
|
|
error = mac_vnode_check_readdir(td->td_ucred, lvp);
|
2006-12-02 19:35:56 +00:00
|
|
|
#endif
|
|
|
|
while (!error && !eofflag) {
|
|
|
|
iov.iov_base = buf;
|
|
|
|
iov.iov_len = sizeof(buf);
|
|
|
|
uio.uio_iov = &iov;
|
|
|
|
uio.uio_iovcnt = 1;
|
|
|
|
uio.uio_resid = iov.iov_len;
|
1998-11-03 08:01:48 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
error = VOP_READDIR(lvp, &uio, cred, &eofflag, NULL, NULL);
|
2008-04-25 07:58:19 +00:00
|
|
|
if (error != 0)
|
2006-12-02 19:35:56 +00:00
|
|
|
break;
|
2008-04-25 07:58:19 +00:00
|
|
|
if (eofflag == 0 && uio.uio_resid == sizeof(buf)) {
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
panic("bad readdir response from lower FS.");
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
2003-06-14 23:27:29 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
edp = (struct dirent*)&buf[sizeof(buf) - uio.uio_resid];
|
|
|
|
for (dp = (struct dirent*)buf; !error && dp < edp;
|
|
|
|
dp = (struct dirent*)((caddr_t)dp + dp->d_reclen)) {
|
|
|
|
if (dp->d_type == DT_WHT ||
|
|
|
|
(dp->d_namlen == 1 && dp->d_name[0] == '.') ||
|
|
|
|
(dp->d_namlen == 2 && !bcmp(dp->d_name, "..", 2)))
|
|
|
|
continue;
|
2003-06-14 23:27:29 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
cn.cn_namelen = dp->d_namlen;
|
|
|
|
cn.cn_pnbuf = NULL;
|
|
|
|
cn.cn_nameptr = dp->d_name;
|
|
|
|
cn.cn_nameiop = LOOKUP;
|
|
|
|
cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
|
|
|
|
cn.cn_lkflags = LK_EXCLUSIVE;
|
|
|
|
cn.cn_thread = td;
|
|
|
|
cn.cn_cred = cred;
|
|
|
|
cn.cn_consume = 0;
|
1998-11-03 08:01:48 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
/*
|
|
|
|
* check entry in lower.
|
|
|
|
* Sometimes, readdir function returns
|
|
|
|
* wrong entry.
|
|
|
|
*/
|
|
|
|
lookuperr = VOP_LOOKUP(lvp, &tvp, &cn);
|
1998-11-03 08:01:48 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (!lookuperr)
|
|
|
|
vput(tvp);
|
|
|
|
else
|
|
|
|
continue; /* skip entry */
|
1998-11-03 08:01:48 +00:00
|
|
|
|
|
|
|
/*
|
2006-12-02 19:35:56 +00:00
|
|
|
* check entry
|
|
|
|
* If it has no exist/whiteout entry in upper,
|
|
|
|
* directory is not empty.
|
1998-11-03 08:01:48 +00:00
|
|
|
*/
|
2006-12-02 19:35:56 +00:00
|
|
|
cn.cn_flags = (LOCKPARENT | LOCKLEAF | SAVENAME | RDONLY | ISLASTCN);
|
|
|
|
lookuperr = VOP_LOOKUP(uvp, &tvp, &cn);
|
1998-11-03 08:01:48 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
if (!lookuperr)
|
|
|
|
vput(tvp);
|
|
|
|
|
|
|
|
/* ignore exist or whiteout entry */
|
|
|
|
if (!lookuperr ||
|
|
|
|
(lookuperr == ENOENT && (cn.cn_flags & ISWHITEOUT)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
error = ENOTEMPTY;
|
1998-11-03 08:01:48 +00:00
|
|
|
}
|
|
|
|
}
|
2006-12-02 19:35:56 +00:00
|
|
|
|
|
|
|
/* close vnode */
|
|
|
|
VOP_CLOSE(vp, FREAD, cred, td);
|
|
|
|
|
|
|
|
return (error);
|
1998-11-03 08:01:48 +00:00
|
|
|
}
|
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
|
|
|
|
struct vnode *
|
|
|
|
unionfs_checkuppervp(struct vnode *vp, char *fil, int lno)
|
1998-11-03 08:01:48 +00:00
|
|
|
{
|
2006-12-02 19:35:56 +00:00
|
|
|
struct unionfs_node *unp;
|
|
|
|
|
|
|
|
unp = VTOUNIONFS(vp);
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
if (vp->v_op != unionfs_vnodeop_p) {
|
|
|
|
printf("unionfs_checkuppervp: on non-unionfs-node.\n");
|
|
|
|
#ifdef KDB
|
2007-12-25 17:52:02 +00:00
|
|
|
kdb_enter(KDB_WHY_UNIONFS,
|
|
|
|
"unionfs_checkuppervp: on non-unionfs-node.\n");
|
2006-12-02 19:35:56 +00:00
|
|
|
#endif
|
|
|
|
panic("unionfs_checkuppervp");
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
return (unp->un_uppervp);
|
1998-11-03 08:01:48 +00:00
|
|
|
}
|
This is a major fixup of unionfs. At least 30 serious bugs have been
fixed (many due to changing semantics in other parts of the kernel and not
the original author's fault), including one critical one: unionfs could
cause UFS corruption in the fronting store due to calling VOP_OPEN for
writing without turning on vmio for the UFS vnode.
Most of the bugs were related to semantics changes in VOP calls, lock
ordering problems (causing deadlocks), improper handling of a read-only
backing store (such as an NFS mount), improper referencing and locking
of vnodes, not using real struct locks for vnode locking, not using
recursive locks when accessing the fronting store, and things like that.
New functionality has been added: unionfs now has mmap() support, but
only partially tested, and rename has been enhanced considerably.
There are still some things that unionfs cannot do. You cannot
rename a directory without confusing unionfs, and there are issues
with softlinks, hardlinks, and special files. unionfs mostly doesn't
understand them (and never did).
There are probably still panic situations, but hopefully no where near
as many as before this commit.
The unionfs in this commit has been tested overlayed on /usr/src
(backing /usr/src being a read-only NFS mount, fronting /usr/src being
a local filesystem). kernel builds have been tested, buildworld is
undergoing testing. More testing is necessary.
1999-09-26 20:52:41 +00:00
|
|
|
|
2006-12-02 19:35:56 +00:00
|
|
|
struct vnode *
|
|
|
|
unionfs_checklowervp(struct vnode *vp, char *fil, int lno)
|
|
|
|
{
|
|
|
|
struct unionfs_node *unp;
|
|
|
|
|
|
|
|
unp = VTOUNIONFS(vp);
|
|
|
|
|
|
|
|
#ifdef notyet
|
|
|
|
if (vp->v_op != unionfs_vnodeop_p) {
|
|
|
|
printf("unionfs_checklowervp: on non-unionfs-node.\n");
|
|
|
|
#ifdef KDB
|
2007-12-25 17:52:02 +00:00
|
|
|
kdb_enter(KDB_WHY_UNIONFS,
|
|
|
|
"unionfs_checklowervp: on non-unionfs-node.\n");
|
2006-12-02 19:35:56 +00:00
|
|
|
#endif
|
|
|
|
panic("unionfs_checklowervp");
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
return (unp->un_lowervp);
|
|
|
|
}
|
|
|
|
#endif
|