Module Name: src
Committed By: snj
Date: Tue Jul 25 02:04:43 UTC 2017
Modified Files:
src/sys/fs/union [netbsd-8]: union.h union_subr.c
Log Message:
Pull up following revision(s) (requested by hannken in ticket #145):
sys/fs/union/union.h: revision 1.29
sys/fs/union/union_subr.c: revision 1.76
Make union_newlower() ans union_newupper() local to union_subr.c,
expand and remove union_updatevp() and take care to transfer the
vnode lock from the union vnode to its new upper vnode without
breaking the fstrans state.
Add assertions that un_lowervp and un_uppervp never change from
non-NULL to non-NULL.
To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.28.10.1 src/sys/fs/union/union.h
cvs rdiff -u -r1.75 -r1.75.2.1 src/sys/fs/union/union_subr.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/fs/union/union.h
diff -u src/sys/fs/union/union.h:1.28 src/sys/fs/union/union.h:1.28.10.1
--- src/sys/fs/union/union.h:1.28 Mon Feb 16 10:22:00 2015
+++ src/sys/fs/union/union.h Tue Jul 25 02:04:42 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: union.h,v 1.28 2015/02/16 10:22:00 hannken Exp $ */
+/* $NetBSD: union.h,v 1.28.10.1 2017/07/25 02:04:42 snj Exp $ */
/*
* Copyright (c) 1994 The Regents of the University of California.
@@ -158,8 +158,6 @@ extern int union_cn_close(struct vnode *
struct lwp *);
extern void union_removed_upper(struct union_node *un);
extern struct vnode *union_lowervp(struct vnode *);
-extern void union_newlower(struct union_node *, struct vnode *);
-extern void union_newupper(struct union_node *, struct vnode *);
extern void union_newsize(struct vnode *, off_t, off_t);
int union_readdirhook(struct vnode **, struct file *, struct lwp *);
Index: src/sys/fs/union/union_subr.c
diff -u src/sys/fs/union/union_subr.c:1.75 src/sys/fs/union/union_subr.c:1.75.2.1
--- src/sys/fs/union/union_subr.c:1.75 Thu Jun 1 02:45:13 2017
+++ src/sys/fs/union/union_subr.c Tue Jul 25 02:04:42 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: union_subr.c,v 1.75 2017/06/01 02:45:13 chs Exp $ */
+/* $NetBSD: union_subr.c,v 1.75.2.1 2017/07/25 02:04:42 snj Exp $ */
/*
* Copyright (c) 1994
@@ -72,7 +72,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.75 2017/06/01 02:45:13 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.75.2.1 2017/07/25 02:04:42 snj Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -104,7 +104,8 @@ static u_long uhash_mask; /* size of ha
static kmutex_t uhash_lock;
-void union_updatevp(struct union_node *, struct vnode *, struct vnode *);
+static void union_newupper(struct union_node *, struct vnode *);
+static void union_newlower(struct union_node *, struct vnode *);
static void union_ref(struct union_node *);
static void union_rele(struct union_node *);
static int union_do_lookup(struct vnode *, struct componentname *, kauth_cred_t, const char *);
@@ -160,71 +161,28 @@ union_done(void)
}
void
-union_updatevp(struct union_node *un, struct vnode *uppervp,
- struct vnode *lowervp)
+union_newlower(struct union_node *un, struct vnode *lowervp)
{
int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
- int nhash = UNION_HASH(uppervp, lowervp);
- int docache = (lowervp != NULLVP || uppervp != NULLVP);
- bool un_unlock;
+ int nhash = UNION_HASH(un->un_uppervp, lowervp);
+
+ if (un->un_lowervp == lowervp)
+ return;
KASSERT(VOP_ISLOCKED(UNIONTOV(un)) == LK_EXCLUSIVE);
+ KASSERT(un->un_lowervp == NULL);
mutex_enter(&uhash_lock);
- if (!docache || ohash != nhash) {
- if (un->un_cflags & UN_CACHED) {
- un->un_cflags &= ~UN_CACHED;
- LIST_REMOVE(un, un_cache);
- }
- }
-
- if (un->un_lowervp != lowervp) {
- if (un->un_lowervp) {
- vrele(un->un_lowervp);
- if (un->un_path) {
- free(un->un_path, M_TEMP);
- un->un_path = 0;
- }
- if (un->un_dirvp) {
- vrele(un->un_dirvp);
- un->un_dirvp = NULLVP;
- }
- }
- un->un_lowervp = lowervp;
- mutex_enter(&un->un_lock);
- un->un_lowersz = VNOVAL;
- mutex_exit(&un->un_lock);
- }
-
- if (un->un_uppervp != uppervp) {
- if (un->un_uppervp) {
- un_unlock = false;
- vrele(un->un_uppervp);
- } else
- un_unlock = true;
-
- mutex_enter(&un->un_lock);
- un->un_uppervp = uppervp;
- mutex_exit(&un->un_lock);
- if (un_unlock) {
- struct vop_unlock_args ap;
-
- ap.a_vp = UNIONTOV(un);
- genfs_unlock(&ap);
- }
- mutex_enter(&un->un_lock);
- un->un_uppersz = VNOVAL;
- mutex_exit(&un->un_lock);
- /* Update union vnode interlock. */
- if (uppervp != NULL) {
- mutex_obj_hold(uppervp->v_interlock);
- uvm_obj_setlock(&UNIONTOV(un)->v_uobj,
- uppervp->v_interlock);
- }
+ if (ohash != nhash && (un->un_cflags & UN_CACHED)) {
+ un->un_cflags &= ~UN_CACHED;
+ LIST_REMOVE(un, un_cache);
}
-
- if (docache && (ohash != nhash)) {
+ mutex_enter(&un->un_lock);
+ un->un_lowervp = lowervp;
+ un->un_lowersz = VNOVAL;
+ mutex_exit(&un->un_lock);
+ if (ohash != nhash) {
LIST_INSERT_HEAD(&uhashtbl[nhash], un, un_cache);
un->un_cflags |= UN_CACHED;
}
@@ -233,17 +191,57 @@ union_updatevp(struct union_node *un, st
}
void
-union_newlower(struct union_node *un, struct vnode *lowervp)
+union_newupper(struct union_node *un, struct vnode *uppervp)
{
+ int ohash = UNION_HASH(un->un_uppervp, un->un_lowervp);
+ int nhash = UNION_HASH(uppervp, un->un_lowervp);
+ struct vop_lock_args lock_ap;
+ struct vop_unlock_args unlock_ap;
+ int error __diagused;
- union_updatevp(un, un->un_uppervp, lowervp);
-}
+ if (un->un_uppervp == uppervp)
+ return;
-void
-union_newupper(struct union_node *un, struct vnode *uppervp)
-{
+ KASSERT(VOP_ISLOCKED(UNIONTOV(un)) == LK_EXCLUSIVE);
+ KASSERT(un->un_uppervp == NULL);
- union_updatevp(un, uppervp, un->un_lowervp);
+ /*
+ * We have to transfer the vnode lock from the union vnode to
+ * the upper vnode. Lock the upper vnode first. We cannot use
+ * VOP_LOCK() here as it would break the fstrans state.
+ */
+ lock_ap.a_desc = VDESC(vop_lock);
+ lock_ap.a_vp = uppervp;
+ lock_ap.a_flags = LK_EXCLUSIVE;
+ error = VCALL(lock_ap.a_vp, VOFFSET(vop_lock), &lock_ap);
+ KASSERT(error == 0);
+
+ mutex_enter(&uhash_lock);
+
+ if (ohash != nhash && (un->un_cflags & UN_CACHED)) {
+ un->un_cflags &= ~UN_CACHED;
+ LIST_REMOVE(un, un_cache);
+ }
+ mutex_enter(&un->un_lock);
+ un->un_uppervp = uppervp;
+ un->un_uppersz = VNOVAL;
+ /*
+ * With the upper vnode in place unlock the union vnode to
+ * finalize the lock transfer.
+ */
+ unlock_ap.a_desc = VDESC(vop_unlock);
+ unlock_ap.a_vp = UNIONTOV(un);
+ genfs_unlock(&unlock_ap);
+ /* Update union vnode interlock. */
+ mutex_obj_hold(uppervp->v_interlock);
+ uvm_obj_setlock(&UNIONTOV(un)->v_uobj, uppervp->v_interlock);
+ mutex_exit(&un->un_lock);
+ if (ohash != nhash) {
+ LIST_INSERT_HEAD(&uhashtbl[nhash], un, un_cache);
+ un->un_cflags |= UN_CACHED;
+ }
+
+ mutex_exit(&uhash_lock);
}
/*
@@ -694,7 +692,6 @@ union_copyup(struct union_node *un, int
if (error)
return (error);
- KASSERT(VOP_ISLOCKED(uvp) == LK_EXCLUSIVE);
union_newupper(un, uvp);
lvp = un->un_lowervp;
@@ -934,6 +931,7 @@ union_vn_create(struct vnode **vpp, stru
}
vp->v_writecount++;
+ VOP_UNLOCK(vp);
*vpp = vp;
return 0;
}