Index: sys/compat/linprocfs/linprocfs.c =================================================================== --- sys/compat/linprocfs/linprocfs.c +++ sys/compat/linprocfs/linprocfs.c @@ -2033,7 +2033,8 @@ NULL, NULL, NULL, PFS_RD); /* /proc//... */ - dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); + dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, + PFS_PROCDEP | PFS_ZOMBIE); pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, NULL, NULL, NULL, PFS_RD); pfs_create_link(dir, "cwd", &linprocfs_doproccwd, @@ -2057,7 +2058,7 @@ pfs_create_file(dir, "statm", &linprocfs_doprocstatm, NULL, NULL, NULL, PFS_RD); pfs_create_file(dir, "status", &linprocfs_doprocstatus, - NULL, NULL, NULL, PFS_RD); + NULL, NULL, NULL, PFS_RD | PFS_ZOMBIE); pfs_create_link(dir, "fd", &linprocfs_dofdescfs, NULL, NULL, NULL, 0); pfs_create_file(dir, "auxv", &linprocfs_doauxv, Index: sys/fs/pseudofs/pseudofs.h =================================================================== --- sys/fs/pseudofs/pseudofs.h +++ sys/fs/pseudofs/pseudofs.h @@ -79,6 +79,7 @@ #define PFS_PROCDEP 0x0010 /* process-dependent */ #define PFS_NOWAIT 0x0020 /* allow malloc to fail */ #define PFS_AUTODRAIN 0x0040 /* sbuf_print can sleep to drain */ +#define PFS_ZOMBIE 0x0080 /* zombie visibility */ /* * Data structures Index: sys/fs/pseudofs/pseudofs_internal.h =================================================================== --- sys/fs/pseudofs/pseudofs_internal.h +++ sys/fs/pseudofs/pseudofs_internal.h @@ -94,6 +94,45 @@ return (err) #endif +#define PFS_VISIBILITY(x) (x->pn_flags & PFS_ZOMBIE) + +#define PFS_PROC_ASSERT_HELD(pn, p) \ + do { \ + if (PFS_VISIBILITY(pn)) \ + KASSERT((p)->p_lockreap > 0, \ + ("process %p not held", p)); \ + else \ + PROC_ASSERT_HELD(p); \ + } while (0) +#define _PFS_PHOLD(pn, p) \ + do { \ + if (PFS_VISIBILITY(pn)) { \ + PROC_LOCK_ASSERT((p), MA_OWNED); \ + (p)->p_lockreap++; \ + } else \ + _PHOLD(p); \ + } while (0) +#define _PFS_PRELE(pn, p) \ + do { \ + if (PFS_VISIBILITY(pn)) { \ + PROC_LOCK_ASSERT((p), MA_OWNED); \ + PFS_PROC_ASSERT_HELD(pn, p); \ + (--(p)->p_lockreap); \ + if ((p)->p_lockreap == 0) \ + wakeup(&(p)->p_lockreap); \ + } else \ + _PRELE(p); \ + } while (0) +#define PFS_PRELE(pn, p) \ + do { \ + if (PFS_VISIBILITY(pn)) { \ + PROC_LOCK(p); \ + _PFS_PRELE(pn, p); \ + PROC_UNLOCK(p); \ + } else \ + PRELE(p); \ + } while (0) + /* * Inline helpers for locking */ @@ -133,7 +172,7 @@ KASSERT(pn->pn_fill != NULL, ("%s(): no callback", __func__)); if (p != NULL) { PROC_LOCK_ASSERT(p, MA_NOTOWNED); - PROC_ASSERT_HELD(p); + PFS_PROC_ASSERT_HELD(pn, p); } pfs_assert_not_owned(pn); return ((pn->pn_fill)(PFS_FILL_ARGNAMES)); Index: sys/fs/pseudofs/pseudofs_vnops.c =================================================================== --- sys/fs/pseudofs/pseudofs_vnops.c +++ sys/fs/pseudofs/pseudofs_vnops.c @@ -84,6 +84,13 @@ return (pn->pn_fileno); } +static struct proc * +pfs_pfind(pid_t pid, struct pfs_node *pn) +{ + + return (PFS_VISIBILITY(pn) ? pfind_any(pid) : pfind(pid)); +} + /* * Returns non-zero if given file is visible to given thread. */ @@ -97,7 +104,9 @@ PROC_LOCK_ASSERT(proc, MA_OWNED); - visible = ((proc->p_flag & P_WEXIT) == 0); + visible = PFS_VISIBILITY(pn); + if (!visible) + visible = ((proc->p_flag & P_WEXIT) == 0); if (visible) visible = (p_cansee(td, proc) == 0); if (visible && pn->pn_vis != NULL) @@ -120,7 +129,7 @@ *p = NULL; if (pid == NO_PID) PFS_RETURN (1); - proc = pfind(pid); + proc = pfs_pfind(pid, pn); if (proc == NULL) PFS_RETURN (0); if (pfs_visible_proc(td, pn, proc)) { @@ -135,18 +144,14 @@ } static int -pfs_lookup_proc(pid_t pid, struct proc **p) +pfs_lookup_proc(struct pfs_node *pn, pid_t pid, struct proc **p) { struct proc *proc; - proc = pfind(pid); + proc = pfs_pfind(pid, pn); if (proc == NULL) return (0); - if ((proc->p_flag & P_WEXIT) != 0) { - PROC_UNLOCK(proc); - return (0); - } - _PHOLD(proc); + _PFS_PHOLD(pn, proc); PROC_UNLOCK(proc); *p = proc; return (1); @@ -197,7 +202,7 @@ PFS_RETURN (0); if (pvd->pvd_pid != NO_PID) { - proc = pfind(pvd->pvd_pid); + proc = pfs_pfind(pvd->pvd_pid, pn); } else { proc = NULL; } @@ -703,7 +708,7 @@ if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) PFS_RETURN (EIO); if (proc != NULL) { - _PHOLD(proc); + _PFS_PHOLD(pn, proc); PROC_UNLOCK(proc); } @@ -781,7 +786,7 @@ vn_lock(vn, locked | LK_RETRY); vdrop(vn); if (proc != NULL) - PRELE(proc); + PFS_PRELE(pn, proc); PFS_RETURN (error); } @@ -881,7 +886,7 @@ PFS_RETURN (0); proc = NULL; - if (pid != NO_PID && !pfs_lookup_proc(pid, &proc)) + if (pid != NO_PID && !pfs_lookup_proc(pd, pid, &proc)) PFS_RETURN (ENOENT); sx_slock(&allproc_lock); @@ -895,7 +900,7 @@ /* check if the directory is visible to the caller */ if (!pfs_visible_proc(curthread, pd, proc)) { - _PRELE(proc); + _PFS_PRELE(pd, proc); PROC_UNLOCK(proc); sx_sunlock(&allproc_lock); pfs_unlock(pd); @@ -908,7 +913,7 @@ if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) { /* nothing left... */ if (proc != NULL) { - _PRELE(proc); + _PFS_PRELE(pd, proc); PROC_UNLOCK(proc); } pfs_unlock(pd); @@ -962,7 +967,7 @@ resid -= PFS_DELEN; } if (proc != NULL) { - _PRELE(proc); + _PFS_PRELE(pd, proc); PROC_UNLOCK(proc); } pfs_unlock(pd); @@ -1004,13 +1009,9 @@ PFS_RETURN (EIO); if (pvd->pvd_pid != NO_PID) { - if ((proc = pfind(pvd->pvd_pid)) == NULL) + if ((proc = pfs_pfind(pvd->pvd_pid, pn)) == NULL) PFS_RETURN (EIO); - if (proc->p_flag & P_WEXIT) { - PROC_UNLOCK(proc); - PFS_RETURN (EIO); - } - _PHOLD(proc); + _PFS_PHOLD(pn, proc); PROC_UNLOCK(proc); } vhold(vn); @@ -1023,7 +1024,7 @@ error = pn_fill(curthread, proc, pn, &sb, NULL); if (proc != NULL) - PRELE(proc); + PFS_PRELE(pn, proc); vn_lock(vn, locked | LK_RETRY); vdrop(vn); @@ -1112,29 +1113,26 @@ if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) PFS_RETURN (EIO); if (proc != NULL) { - _PHOLD(proc); + _PFS_PHOLD(pn, proc); PROC_UNLOCK(proc); } if (pn->pn_flags & PFS_RAWWR) { error = pn_fill(curthread, proc, pn, NULL, uio); - if (proc != NULL) - PRELE(proc); - PFS_RETURN (error); + goto out; } sbuf_uionew(&sb, uio, &error); - if (error) { - if (proc != NULL) - PRELE(proc); - PFS_RETURN (error); - } + if (error) + goto out; error = pn_fill(curthread, proc, pn, &sb, uio); sbuf_delete(&sb); + +out: if (proc != NULL) - PRELE(proc); + PFS_PRELE(pn, proc); PFS_RETURN (error); } Index: sys/kern/kern_exit.c =================================================================== --- sys/kern/kern_exit.c +++ sys/kern/kern_exit.c @@ -931,6 +931,13 @@ return; } + /* + * Wait for any processes that have a hold on our vmspace to + * release their reference. + */ + while (p->p_lockreap > 0) + msleep(&p->p_lockreap, &p->p_mtx, PWAIT, "reaphold", 0); + PROC_LOCK(q); sigqueue_take(p->p_ksi); PROC_UNLOCK(q); Index: sys/kern/kern_thread.c =================================================================== --- sys/kern/kern_thread.c +++ sys/kern/kern_thread.c @@ -117,11 +117,11 @@ "struct proc KBI p_flag"); _Static_assert(offsetof(struct proc, p_pid) == 0x78, "struct proc KBI p_pid"); -_Static_assert(offsetof(struct proc, p_filemon) == 0x270, +_Static_assert(offsetof(struct proc, p_filemon) == 0x274, "struct proc KBI p_filemon"); -_Static_assert(offsetof(struct proc, p_comm) == 0x284, +_Static_assert(offsetof(struct proc, p_comm) == 0x288, "struct proc KBI p_comm"); -_Static_assert(offsetof(struct proc, p_emuldata) == 0x310, +_Static_assert(offsetof(struct proc, p_emuldata) == 0x314, "struct proc KBI p_emuldata"); #endif Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -675,6 +675,7 @@ struct vnode *p_textdvp; /* (b) Dir containing textvp. */ char *p_binname; /* (b) Binary hardlink name. */ u_int p_lock; /* (c) Proclock (prevent swap) count. */ + u_int p_lockreap; /* (c) Proclock (prevent reap) count. */ struct sigiolst p_sigiolst; /* (c) List of sigio sources. */ int p_sigparent; /* (c) Signal to parent on exit. */ int p_sig; /* (n) For core dump/debugger XXX. */