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; }