Module Name: src Committed By: martin Date: Thu Aug 27 09:08:39 UTC 2020
Modified Files: src/sys/fs/union [netbsd-9]: union.h union_subr.c union_vnops.c Log Message: Pull up following revision(s) (requested by hannken in ticket #1062): sys/fs/union/union.h: revision 1.30 sys/fs/union/union_subr.c: revision 1.79 sys/fs/union/union_vnops.c: revision 1.74 Operation union_readdirhook() stores the lower directory as un_uppervp. This breaks the assumption that un_uppervp->v_mount is the upper mount. Fix by storing the directory as un_lowervp and adapt union_readdir(). Should fix PR kern/55552: panic with union mount To generate a diff of this commit: cvs rdiff -u -r1.29 -r1.29.10.1 src/sys/fs/union/union.h cvs rdiff -u -r1.77 -r1.77.8.1 src/sys/fs/union/union_subr.c cvs rdiff -u -r1.70 -r1.70.14.1 src/sys/fs/union/union_vnops.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.29 src/sys/fs/union/union.h:1.29.10.1 --- src/sys/fs/union/union.h:1.29 Mon Jul 17 09:22:36 2017 +++ src/sys/fs/union/union.h Thu Aug 27 09:08:39 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: union.h,v 1.29 2017/07/17 09:22:36 hannken Exp $ */ +/* $NetBSD: union.h,v 1.29.10.1 2020/08/27 09:08:39 martin Exp $ */ /* * Copyright (c) 1994 The Regents of the University of California. @@ -130,6 +130,7 @@ struct union_node { char *un_path; /* v: saved component name */ int un_openl; /* v: # of opens on lowervp */ unsigned int un_cflags; /* c: cache flags */ + bool un_hooknode; /* :: from union_readdirhook */ struct vnode **un_dircache; /* v: cached union stack */ off_t un_uppersz; /* l: size of upper object */ off_t un_lowersz; /* l: size of lower object */ Index: src/sys/fs/union/union_subr.c diff -u src/sys/fs/union/union_subr.c:1.77 src/sys/fs/union/union_subr.c:1.77.8.1 --- src/sys/fs/union/union_subr.c:1.77 Sun Jan 28 15:48:44 2018 +++ src/sys/fs/union/union_subr.c Thu Aug 27 09:08:39 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: union_subr.c,v 1.77 2018/01/28 15:48:44 christos Exp $ */ +/* $NetBSD: union_subr.c,v 1.77.8.1 2020/08/27 09:08:39 martin Exp $ */ /* * Copyright (c) 1994 @@ -72,7 +72,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.77 2018/01/28 15:48:44 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.77.8.1 2020/08/27 09:08:39 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -479,6 +479,7 @@ found: un->un_dircache = 0; un->un_openl = 0; un->un_cflags = 0; + un->un_hooknode = false; un->un_uppersz = VNOVAL; un->un_lowersz = VNOVAL; @@ -1065,7 +1066,7 @@ union_dircache(struct vnode *vp, struct } else { vpp = dircache; do { - if (*vpp++ == VTOUNION(vp)->un_uppervp) + if (*vpp++ == VTOUNION(vp)->un_lowervp) break; } while (*vpp != NULLVP); } @@ -1074,10 +1075,12 @@ union_dircache(struct vnode *vp, struct goto out; vref(*vpp); - error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, *vpp, NULLVP, 0); + error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, 0, + NULLVP, *vpp, 0); if (!error) { vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY); VTOUNION(vp)->un_dircache = 0; + VTOUNION(nvp)->un_hooknode = true; VTOUNION(nvp)->un_dircache = dircache; } Index: src/sys/fs/union/union_vnops.c diff -u src/sys/fs/union/union_vnops.c:1.70 src/sys/fs/union/union_vnops.c:1.70.14.1 --- src/sys/fs/union/union_vnops.c:1.70 Fri May 26 14:21:01 2017 +++ src/sys/fs/union/union_vnops.c Thu Aug 27 09:08:39 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: union_vnops.c,v 1.70 2017/05/26 14:21:01 riastradh Exp $ */ +/* $NetBSD: union_vnops.c,v 1.70.14.1 2020/08/27 09:08:39 martin Exp $ */ /* * Copyright (c) 1992, 1993, 1994, 1995 @@ -72,7 +72,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.70 2017/05/26 14:21:01 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.70.14.1 2020/08/27 09:08:39 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -1492,13 +1492,29 @@ union_readdir(void *v) int a_ncookies; } */ *ap = v; struct union_node *un = VTOUNION(ap->a_vp); - struct vnode *uvp = un->un_uppervp; + struct vnode *vp; + int dolock, error; - if (uvp == NULLVP) - return (0); + if (un->un_hooknode) { + KASSERT(un->un_uppervp == NULLVP); + KASSERT(un->un_lowervp != NULLVP); + vp = un->un_lowervp; + dolock = 1; + } else { + vp = un->un_uppervp; + dolock = 0; + } + if (vp == NULLVP) + return 0; - ap->a_vp = uvp; - return (VCALL(uvp, VOFFSET(vop_readdir), ap)); + if (dolock) + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + ap->a_vp = vp; + error = VCALL(vp, VOFFSET(vop_readdir), ap); + if (dolock) + VOP_UNLOCK(vp); + + return error; } int