diff options
author | daichi <daichi@FreeBSD.org> | 2007-10-14 13:46:11 +0000 |
---|---|---|
committer | daichi <daichi@FreeBSD.org> | 2007-10-14 13:46:11 +0000 |
commit | a009cf6b3cb242d382411f28b524c2271f3eae0a (patch) | |
tree | d179467b6c3f66e075aa75cdd47a26a6ef2ef6cd | |
parent | 4aad1608ad423bcbfccc18e26294a44fdedd723a (diff) | |
download | FreeBSD-src-a009cf6b3cb242d382411f28b524c2271f3eae0a.zip FreeBSD-src-a009cf6b3cb242d382411f28b524c2271f3eae0a.tar.gz |
- 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
-rw-r--r-- | sys/fs/unionfs/union.h | 13 | ||||
-rw-r--r-- | sys/fs/unionfs/union_subr.c | 163 | ||||
-rw-r--r-- | sys/fs/unionfs/union_vnops.c | 38 |
3 files changed, 43 insertions, 171 deletions
diff --git a/sys/fs/unionfs/union.h b/sys/fs/unionfs/union.h index e2df553..302b384 100644 --- a/sys/fs/unionfs/union.h +++ b/sys/fs/unionfs/union.h @@ -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); diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c index 6156da6..fc5e27c 100644 --- a/sys/fs/unionfs/union_subr.c +++ b/sys/fs/unionfs/union_subr.c @@ -60,135 +60,29 @@ #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. * * uppervp and lowervp should be unlocked. Because if new unionfs vnode is @@ -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); } /* diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c index 3d46ab8..cd6663f 100644 --- a/sys/fs/unionfs/union_vnops.c +++ b/sys/fs/unionfs/union_vnops.c @@ -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, |