diff options
| author | hannken <hannken@NetBSD.org> | 2018-04-07 13:42:42 +0000 |
|---|---|---|
| committer | hannken <hannken@NetBSD.org> | 2018-04-07 13:42:42 +0000 |
| commit | fac3e23086de4eee2004ef7058f660248dad2e1b (patch) | |
| tree | 7a9784465bf02bd97ee797d6e69c7e369ac61a74 /sys | |
| parent | 7f131eafb3d811a4b5a14fc925deb6042f1ee1fc (diff) | |
Lock the target cwdi and take an additional reference to the
vnode we are interested in to prevent it from disappearing
before getcwd_common().
Should fix PR kern/53096 (netbsd-8 crash on heavy disk I/O)
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/miscfs/procfs/procfs_vnops.c | 36 |
1 files changed, 23 insertions, 13 deletions
diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c index 0311cd9e98b..b518fb48899 100644 --- a/sys/miscfs/procfs/procfs_vnops.c +++ b/sys/miscfs/procfs/procfs_vnops.c @@ -1,4 +1,4 @@ -/* $NetBSD: procfs_vnops.c,v 1.202 2017/12/31 03:02:23 christos Exp $ */ +/* $NetBSD: procfs_vnops.c,v 1.203 2018/04/07 13:42:42 hannken Exp $ */ /*- * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -105,7 +105,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.202 2017/12/31 03:02:23 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.203 2018/04/07 13:42:42 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -545,11 +545,10 @@ procfs_symlink(void *v) } /* - * Works out the path to (and vnode of) the target process's current + * Works out the path to the target process's current * working directory or chroot. If the caller is in a chroot and * can't "reach" the target's cwd or root (or some other error - * occurs), a "/" is returned for the path and a NULL pointer is - * returned for the vnode. + * occurs), a "/" is returned for the path. */ static void procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp, @@ -559,12 +558,12 @@ procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp, struct vnode *vp, *rvp; char *bp; - cwdi = caller->l_proc->p_cwdi; - rw_enter(&cwdi->cwdi_lock, RW_READER); - - rvp = cwdi->cwdi_rdir; - bp = bpp ? *bpp : NULL; - + /* + * Lock target cwdi and take a reference to the vnode + * we are interested in to prevent it from disappearing + * before getcwd_common() below. + */ + rw_enter(&target->p_cwdi->cwdi_lock, RW_READER); switch (t) { case PFScwd: vp = target->p_cwdi->cwdi_cdir; @@ -573,9 +572,18 @@ procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp, vp = target->p_cwdi->cwdi_rdir; break; default: - rw_exit(&cwdi->cwdi_lock); + rw_exit(&target->p_cwdi->cwdi_lock); return; } + if (vp != NULL) + vref(vp); + rw_exit(&target->p_cwdi->cwdi_lock); + + cwdi = caller->l_proc->p_cwdi; + rw_enter(&cwdi->cwdi_lock, RW_READER); + + rvp = cwdi->cwdi_rdir; + bp = bpp ? *bpp : NULL; /* * XXX: this horrible kludge avoids locking panics when @@ -586,6 +594,7 @@ procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp, *--bp = '/'; *bpp = bp; } + vrele(vp); rw_exit(&cwdi->cwdi_lock); return; } @@ -594,7 +603,6 @@ procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp, rvp = rootvnode; if (vp == NULL || getcwd_common(vp, rvp, bp ? &bp : NULL, path, len / 2, 0, caller) != 0) { - vp = NULL; if (bpp) { bp = *bpp; *--bp = '/'; @@ -604,6 +612,8 @@ procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp, if (bpp) *bpp = bp; + if (vp != NULL) + vrele(vp); rw_exit(&cwdi->cwdi_lock); } |
