mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-18 10:35:55 +00:00
- Added support for vfs_cache on unionfs. As a result, you can use
applications that use procfs on unionfs. - Removed unionfs internal cache mechanism because it has vfs_cache support instead. As a result, it just simplified code of unionfs. - Fixed kern/111262 issue. Submitted by: Masanori Ozawa <ozawa@ongs.co.jp> (unionfs developer) Reviewed by: jeff, kensmith Approved by: re (kensmith) MFC after: 1 week
This commit is contained in:
parent
5adc408078
commit
dc2dd18518
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=172637
@ -72,7 +72,6 @@ struct unionfs_node_status {
|
||||
|
||||
/* A cache of vnode references */
|
||||
struct unionfs_node {
|
||||
LIST_ENTRY(unionfs_node) un_hash; /* Hash list */
|
||||
struct vnode *un_lowervp; /* lower side vnode */
|
||||
struct vnode *un_uppervp; /* upper side vnode */
|
||||
struct vnode *un_dvp; /* parent unionfs vnode */
|
||||
@ -82,10 +81,12 @@ struct unionfs_node {
|
||||
int un_flag; /* unionfs node flag */
|
||||
};
|
||||
|
||||
/* unionfs node flags */
|
||||
#define UNIONFS_CACHED 0x01 /* is cached */
|
||||
#define UNIONFS_OPENEXTL 0x02 /* openextattr (lower) */
|
||||
#define UNIONFS_OPENEXTU 0x04 /* openextattr (upper) */
|
||||
/*
|
||||
* unionfs node flags
|
||||
* It needs the vnode with exclusive lock, when changing the un_flag variable.
|
||||
*/
|
||||
#define UNIONFS_OPENEXTL 0x01 /* openextattr (lower) */
|
||||
#define UNIONFS_OPENEXTU 0x02 /* openextattr (upper) */
|
||||
|
||||
#define MOUNTTOUNIONFSMOUNT(mp) ((struct unionfs_mount *)((mp)->mnt_data))
|
||||
#define VTOUNIONFS(vp) ((struct unionfs_node *)(vp)->v_data)
|
||||
@ -94,7 +95,7 @@ struct unionfs_node {
|
||||
int unionfs_init(struct vfsconf *vfsp);
|
||||
int unionfs_uninit(struct vfsconf *vfsp);
|
||||
int unionfs_nodeget(struct mount *mp, struct vnode *uppervp, struct vnode *lowervp, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct thread *td);
|
||||
void unionfs_hashrem(struct vnode *vp, struct thread *td);
|
||||
void unionfs_noderem(struct vnode *vp, struct thread *td);
|
||||
void unionfs_get_node_status(struct unionfs_node *unp, struct thread *td, struct unionfs_node_status **unspp);
|
||||
void unionfs_tryrem_node_status(struct unionfs_node *unp, struct thread *td, struct unionfs_node_status *unsp);
|
||||
|
||||
|
@ -60,134 +60,28 @@
|
||||
|
||||
#include <fs/unionfs/union.h>
|
||||
|
||||
#define NUNIONFSNODECACHE 32
|
||||
|
||||
#define UNIONFS_NHASH(upper, lower) \
|
||||
(&unionfs_node_hashtbl[(((uintptr_t)upper + (uintptr_t)lower) >> 8) & unionfs_node_hash])
|
||||
|
||||
static LIST_HEAD(unionfs_node_hashhead, unionfs_node) *unionfs_node_hashtbl;
|
||||
static u_long unionfs_node_hash;
|
||||
struct mtx unionfs_hashmtx;
|
||||
|
||||
static MALLOC_DEFINE(M_UNIONFSHASH, "UNIONFS hash", "UNIONFS hash table");
|
||||
MALLOC_DEFINE(M_UNIONFSNODE, "UNIONFS node", "UNIONFS vnode private part");
|
||||
MALLOC_DEFINE(M_UNIONFSPATH, "UNIONFS path", "UNIONFS path private part");
|
||||
|
||||
/*
|
||||
* Initialize cache headers
|
||||
* Initialize
|
||||
*/
|
||||
int
|
||||
unionfs_init(struct vfsconf *vfsp)
|
||||
{
|
||||
UNIONFSDEBUG("unionfs_init\n"); /* printed during system boot */
|
||||
unionfs_node_hashtbl = hashinit(NUNIONFSNODECACHE, M_UNIONFSHASH, &unionfs_node_hash);
|
||||
mtx_init(&unionfs_hashmtx, "unionfs", NULL, MTX_DEF);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy cache headers
|
||||
* Uninitialize
|
||||
*/
|
||||
int
|
||||
unionfs_uninit(struct vfsconf *vfsp)
|
||||
{
|
||||
mtx_destroy(&unionfs_hashmtx);
|
||||
free(unionfs_node_hashtbl, M_UNIONFSHASH);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a VREF'ed alias for unionfs vnode if already exists, else 0.
|
||||
*/
|
||||
static struct vnode *
|
||||
unionfs_hashget(struct mount *mp, struct vnode *uppervp,
|
||||
struct vnode *lowervp, struct vnode *dvp, char *path,
|
||||
int lkflags, struct thread *td)
|
||||
{
|
||||
struct unionfs_node_hashhead *hd;
|
||||
struct unionfs_node *unp;
|
||||
struct vnode *vp;
|
||||
int error;
|
||||
|
||||
if (lkflags & LK_TYPE_MASK)
|
||||
lkflags |= LK_RETRY;
|
||||
hd = UNIONFS_NHASH(uppervp, lowervp);
|
||||
|
||||
mtx_lock(&unionfs_hashmtx);
|
||||
LIST_FOREACH(unp, hd, un_hash) {
|
||||
if (unp->un_uppervp == uppervp &&
|
||||
unp->un_lowervp == lowervp &&
|
||||
unp->un_dvp == dvp &&
|
||||
UNIONFSTOV(unp)->v_mount == mp &&
|
||||
(!path || !(unp->un_path) || !strcmp(unp->un_path, path))) {
|
||||
vp = UNIONFSTOV(unp);
|
||||
VI_LOCK(vp);
|
||||
mtx_unlock(&unionfs_hashmtx);
|
||||
/*
|
||||
* We need to clear the OWEINACT flag here as this
|
||||
* may lead vget() to try to lock our vnode which is
|
||||
* already locked via vp.
|
||||
*/
|
||||
vp->v_iflag &= ~VI_OWEINACT;
|
||||
error = vget(vp, LK_INTERLOCK, td);
|
||||
if (error != 0)
|
||||
panic("unionfs_hashget: vget error %d", error);
|
||||
if (lkflags & LK_TYPE_MASK)
|
||||
vn_lock(vp, lkflags, td);
|
||||
return (vp);
|
||||
}
|
||||
}
|
||||
|
||||
mtx_unlock(&unionfs_hashmtx);
|
||||
|
||||
return (NULLVP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Act like unionfs_hashget, but add passed unionfs_node to hash if no existing
|
||||
* node found.
|
||||
*/
|
||||
static struct vnode *
|
||||
unionfs_hashins(struct mount *mp, struct unionfs_node *uncp,
|
||||
char *path, int lkflags, struct thread *td)
|
||||
{
|
||||
struct unionfs_node_hashhead *hd;
|
||||
struct unionfs_node *unp;
|
||||
struct vnode *vp;
|
||||
int error;
|
||||
|
||||
if (lkflags & LK_TYPE_MASK)
|
||||
lkflags |= LK_RETRY;
|
||||
hd = UNIONFS_NHASH(uncp->un_uppervp, uncp->un_lowervp);
|
||||
|
||||
mtx_lock(&unionfs_hashmtx);
|
||||
LIST_FOREACH(unp, hd, un_hash) {
|
||||
if (unp->un_uppervp == uncp->un_uppervp &&
|
||||
unp->un_lowervp == uncp->un_lowervp &&
|
||||
unp->un_dvp == uncp->un_dvp &&
|
||||
UNIONFSTOV(unp)->v_mount == mp &&
|
||||
(!path || !(unp->un_path) || !strcmp(unp->un_path, path))) {
|
||||
vp = UNIONFSTOV(unp);
|
||||
VI_LOCK(vp);
|
||||
mtx_unlock(&unionfs_hashmtx);
|
||||
vp->v_iflag &= ~VI_OWEINACT;
|
||||
error = vget(vp, LK_INTERLOCK, td);
|
||||
if (error)
|
||||
panic("unionfs_hashins: vget error %d", error);
|
||||
if (lkflags & LK_TYPE_MASK)
|
||||
vn_lock(vp, lkflags, td);
|
||||
return (vp);
|
||||
}
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(hd, uncp, un_hash);
|
||||
uncp->un_flag |= UNIONFS_CACHED;
|
||||
mtx_unlock(&unionfs_hashmtx);
|
||||
|
||||
return (NULLVP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a new or get existing unionfs node.
|
||||
*
|
||||
@ -210,20 +104,15 @@ unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
|
||||
|
||||
ump = MOUNTTOUNIONFSMOUNT(mp);
|
||||
lkflags = (cnp ? cnp->cn_lkflags : 0);
|
||||
path = (cnp ? cnp->cn_nameptr : "");
|
||||
path = (cnp ? cnp->cn_nameptr : NULL);
|
||||
|
||||
if (uppervp == NULLVP && lowervp == NULLVP)
|
||||
panic("unionfs_nodeget: upper and lower is null");
|
||||
|
||||
/* If it has no ISLASTCN flag, path check is skipped. */
|
||||
if (!cnp || !(cnp->cn_flags & ISLASTCN))
|
||||
if (cnp && !(cnp->cn_flags & ISLASTCN))
|
||||
path = NULL;
|
||||
|
||||
/* Lookup the hash first. */
|
||||
*vpp = unionfs_hashget(mp, uppervp, lowervp, dvp, path, lkflags, td);
|
||||
if (*vpp != NULLVP)
|
||||
return (0);
|
||||
|
||||
if ((uppervp == NULLVP || ump->um_uppervp != uppervp) ||
|
||||
(lowervp == NULLVP || ump->um_lowervp != lowervp)) {
|
||||
if (dvp == NULLVP)
|
||||
@ -239,7 +128,7 @@ unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
|
||||
M_UNIONFSNODE, M_WAITOK | M_ZERO);
|
||||
|
||||
error = getnewvnode("unionfs", mp, &unionfs_vnodeops, &vp);
|
||||
if (error) {
|
||||
if (error != 0) {
|
||||
FREE(unp, M_UNIONFSNODE);
|
||||
return (error);
|
||||
}
|
||||
@ -264,9 +153,9 @@ unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
|
||||
else
|
||||
vp->v_vnlock = lowervp->v_vnlock;
|
||||
|
||||
if (cnp) {
|
||||
if (path != NULL) {
|
||||
unp->un_path = (char *)
|
||||
malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK | M_ZERO);
|
||||
malloc(cnp->cn_namelen +1, M_UNIONFSPATH, M_WAITOK|M_ZERO);
|
||||
bcopy(cnp->cn_nameptr, unp->un_path, cnp->cn_namelen);
|
||||
unp->un_path[cnp->cn_namelen] = '\0';
|
||||
}
|
||||
@ -277,23 +166,6 @@ unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
|
||||
(lowervp != NULLVP && ump->um_lowervp == lowervp))
|
||||
vp->v_vflag |= VV_ROOT;
|
||||
|
||||
*vpp = unionfs_hashins(mp, unp, path, lkflags, td);
|
||||
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);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (lkflags & LK_TYPE_MASK)
|
||||
vn_lock(vp, lkflags | LK_RETRY, td);
|
||||
|
||||
@ -303,10 +175,10 @@ unionfs_nodeget(struct mount *mp, struct vnode *uppervp,
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove node from hash.
|
||||
* Clean up the unionfs node.
|
||||
*/
|
||||
void
|
||||
unionfs_hashrem(struct vnode *vp, struct thread *td)
|
||||
unionfs_noderem(struct vnode *vp, struct thread *td)
|
||||
{
|
||||
int vfslocked;
|
||||
struct unionfs_node *unp;
|
||||
@ -331,13 +203,6 @@ unionfs_hashrem(struct vnode *vp, struct thread *td)
|
||||
VOP_UNLOCK(lvp, 0, td);
|
||||
if (uvp != NULLVP)
|
||||
VOP_UNLOCK(uvp, 0, td);
|
||||
|
||||
mtx_lock(&unionfs_hashmtx);
|
||||
if (unp->un_flag & UNIONFS_CACHED) {
|
||||
LIST_REMOVE(unp, un_hash);
|
||||
unp->un_flag &= ~UNIONFS_CACHED;
|
||||
}
|
||||
mtx_unlock(&unionfs_hashmtx);
|
||||
vp->v_object = NULL;
|
||||
|
||||
if (lvp != NULLVP) {
|
||||
@ -692,16 +557,6 @@ unionfs_node_update(struct unionfs_node *unp, struct vnode *uvp,
|
||||
VI_UNLOCK(vp);
|
||||
for (count = 1; count < lockcnt; count++)
|
||||
vn_lock(uvp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY, td);
|
||||
|
||||
/*
|
||||
* cache update
|
||||
*/
|
||||
mtx_lock(&unionfs_hashmtx);
|
||||
if (unp->un_flag & UNIONFS_CACHED)
|
||||
LIST_REMOVE(unp, un_hash);
|
||||
LIST_INSERT_HEAD(UNIONFS_NHASH(uvp, lvp), unp, un_hash);
|
||||
unp->un_flag |= UNIONFS_CACHED;
|
||||
mtx_unlock(&unionfs_hashmtx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -88,7 +88,7 @@ static struct lk_lr_table un_llt[] = {
|
||||
|
||||
|
||||
static int
|
||||
unionfs_lookup(struct vop_lookup_args *ap)
|
||||
unionfs_lookup(struct vop_cachedlookup_args *ap)
|
||||
{
|
||||
int iswhiteout;
|
||||
int lockflag;
|
||||
@ -171,7 +171,9 @@ unionfs_lookup(struct vop_lookup_args *ap)
|
||||
vn_lock(dunp->un_dvp, cnp->cn_lkflags | LK_RETRY, td);
|
||||
|
||||
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
}
|
||||
} else if (error == ENOENT && (cnflags & MAKEENTRY) &&
|
||||
nameiop != CREATE)
|
||||
cache_enter(dvp, NULLVP, cnp);
|
||||
|
||||
UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
|
||||
|
||||
@ -318,12 +320,18 @@ unionfs_lookup(struct vop_lookup_args *ap)
|
||||
|
||||
*(ap->a_vpp) = vp;
|
||||
|
||||
if (cnflags & MAKEENTRY)
|
||||
cache_enter(dvp, vp, cnp);
|
||||
|
||||
unionfs_lookup_out:
|
||||
if (uvp != NULLVP)
|
||||
vrele(uvp);
|
||||
if (lvp != NULLVP)
|
||||
vrele(lvp);
|
||||
|
||||
if (error == ENOENT && (cnflags & MAKEENTRY) && nameiop != CREATE)
|
||||
cache_enter(dvp, NULLVP, cnp);
|
||||
|
||||
UNIONFS_INTERNAL_DEBUG("unionfs_lookup: leave (%d)\n", error);
|
||||
|
||||
return (error);
|
||||
@ -1178,6 +1186,13 @@ unionfs_rename(struct vop_rename_args *ap)
|
||||
|
||||
error = VOP_RENAME(rfdvp, rfvp, fcnp, rtdvp, rtvp, tcnp);
|
||||
|
||||
if (error == 0) {
|
||||
if (rtvp != NULLVP && rtvp->v_type == VDIR)
|
||||
cache_purge(tdvp);
|
||||
if (fvp->v_type == VDIR && fdvp != tdvp)
|
||||
cache_purge(fdvp);
|
||||
}
|
||||
|
||||
if (fdvp != rfdvp)
|
||||
vrele(fdvp);
|
||||
if (fvp != rfvp)
|
||||
@ -1310,6 +1325,11 @@ unionfs_rmdir(struct vop_rmdir_args *ap)
|
||||
else if (lvp != NULLVP)
|
||||
error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path);
|
||||
|
||||
if (error == 0) {
|
||||
cache_purge(ap->a_dvp);
|
||||
cache_purge(ap->a_vp);
|
||||
}
|
||||
|
||||
UNIONFS_INTERNAL_DEBUG("unionfs_rmdir: leave (%d)\n", error);
|
||||
|
||||
return (error);
|
||||
@ -1564,13 +1584,8 @@ unionfs_getwritemount(struct vop_getwritemount_args *ap)
|
||||
static int
|
||||
unionfs_inactive(struct vop_inactive_args *ap)
|
||||
{
|
||||
struct unionfs_node *unp;
|
||||
|
||||
unp = VTOUNIONFS(ap->a_vp);
|
||||
|
||||
if (unp == NULL || !(unp->un_flag & UNIONFS_CACHED))
|
||||
vgone(ap->a_vp);
|
||||
|
||||
ap->a_vp->v_object = NULL;
|
||||
vrecycle(ap->a_vp, ap->a_td);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1579,7 +1594,7 @@ unionfs_reclaim(struct vop_reclaim_args *ap)
|
||||
{
|
||||
/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: enter\n"); */
|
||||
|
||||
unionfs_hashrem(ap->a_vp, ap->a_td);
|
||||
unionfs_noderem(ap->a_vp, ap->a_td);
|
||||
|
||||
/* UNIONFS_INTERNAL_DEBUG("unionfs_reclaim: leave\n"); */
|
||||
|
||||
@ -2240,6 +2255,7 @@ struct vop_vector unionfs_vnodeops = {
|
||||
.vop_aclcheck = unionfs_aclcheck,
|
||||
.vop_advlock = unionfs_advlock,
|
||||
.vop_bmap = VOP_EOPNOTSUPP,
|
||||
.vop_cachedlookup = unionfs_lookup,
|
||||
.vop_close = unionfs_close,
|
||||
.vop_closeextattr = unionfs_closeextattr,
|
||||
.vop_create = unionfs_create,
|
||||
@ -2255,7 +2271,7 @@ struct vop_vector unionfs_vnodeops = {
|
||||
.vop_link = unionfs_link,
|
||||
.vop_listextattr = unionfs_listextattr,
|
||||
.vop_lock1 = unionfs_lock,
|
||||
.vop_lookup = unionfs_lookup,
|
||||
.vop_lookup = vfs_cache_lookup,
|
||||
.vop_mkdir = unionfs_mkdir,
|
||||
.vop_mknod = unionfs_mknod,
|
||||
.vop_open = unionfs_open,
|
||||
|
Loading…
Reference in New Issue
Block a user