diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 96bc585..60883b7 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -3004,7 +3004,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) struct tty *tp; name = (int *)arg1; - error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); + error = pget((pid_t)name[0], PGET_WANTREAD | PGET_LOCK, &p); if (error != 0) return (error); fdp = fdhold(p); @@ -3189,6 +3189,7 @@ sysctl_kern_proc_ofiledesc(SYSCTL_HANDLER_ARGS) } FILEDESC_SUNLOCK(fdp); fddrop(fdp); + PROC_LETGO(p); free(kif, M_TEMP); return (0); } @@ -3477,6 +3478,7 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen) FILEDESC_SUNLOCK(fdp); fddrop(fdp); fail: + PROC_LETGO(p); free(efbuf, M_TEMP); return (error); } @@ -3497,7 +3499,7 @@ sysctl_kern_proc_filedesc(SYSCTL_HANDLER_ARGS) name = (int *)arg1; sbuf_new_for_sysctl(&sb, NULL, FILEDESC_SBUF_SIZE, req); - error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p); + error = pget((pid_t)name[0], PGET_WANTREAD | PGET_LOCK, &p); if (error != 0) { sbuf_delete(&sb); return (error); diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 489096b..5afd744 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -374,6 +374,7 @@ do_execve(td, args, mac_p) KASSERT((p->p_flag & P_INEXEC) == 0, ("%s(): process already has P_INEXEC flag", __func__)); p->p_flag |= P_INEXEC; + proc_wait_kept(p); PROC_UNLOCK(p); /* diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 9efaac2..9042b9d 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -215,6 +215,7 @@ exit1(struct thread *td, int rv) */ while (p->p_lock > 0) msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0); + proc_wait_kept(p); p->p_xstat = rv; /* Let event handler change exit status */ PROC_UNLOCK(p); diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 3163622..0d188d6 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -259,6 +259,14 @@ proc_fini(void *mem, int size) #endif } +void +proc_wait_kept(struct proc *p) +{ + + while (p->p_keeplock > 0) + msleep(&p->p_keeplock, &p->p_mtx, PWAIT, "keeplock", 0); +} + /* * Is p an inferior of the current process? */ @@ -402,10 +410,20 @@ pget(pid_t pid, int flags, struct proc **pp) error = ESRCH; goto errout; } + if ((flags & PGET_KEEP) != 0) { + MPASS((flags & PGET_NOTWEXIT)); + PROC_KEEP(p); + if ((flags & PGET_LOCK) == 0) { + PROC_UNLOCK(p); + goto out; + } + } if ((flags & PGET_HOLD) != 0) { + MPASS((flags & PGET_LOCK) == 0); _PHOLD(p); PROC_UNLOCK(p); } +out: *pp = p; return (0); errout: diff --git a/sys/sys/proc.h b/sys/sys/proc.h index fbd064c..929523c 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -532,6 +532,7 @@ struct proc { struct ucred *p_tracecred; /* (o) Credentials to trace with. */ struct vnode *p_textvp; /* (b) Vnode of executable. */ u_int p_lock; /* (c) Proclock (prevent swap) count. */ + u_int p_keeplock; 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. */ @@ -791,6 +792,35 @@ extern pid_t pid_max; KASSERT((p)->p_lock == 0, ("process held")); \ } while (0) + +/* Prevent the process from execing or exiting */ +#define PROC_KEEP(p) do { \ + PROC_LOCK_ASSERT((p), MA_OWNED); \ + KASSERT(!((p)->p_flag & P_WEXIT), \ + ("PROC_KEEP of exiting process")); \ + KASSERT(!((p)->p_flag & P_INEXEC), \ + ("PROC_KEEP of execing process")); \ + (p)->p_keeplock++; \ +} while (0) +#define PROC_ASSERT_KEPT(p) do { \ + KASSERT((p)->p_keeplock > 0, ("process not kept")); \ +} while (0) + +#define PROC_LETGO(p) do { \ + PROC_LOCK(p); \ + _PROC_LETGO(p); \ + PROC_UNLOCK(p); \ +} while (0) +#define _PROC_LETGO(p) do { \ + PROC_LOCK_ASSERT((p), MA_OWNED); \ + PROC_ASSERT_KEPT(p); \ + (p)->p_keeplock--; \ + if (((p)->p_flag & (P_WEXIT|P_INEXEC)) && (p)->p_keeplock == 0) \ + wakeup(&(p)->p_keeplock); \ +} while (0) + +void proc_wait_kept(struct proc *p); + /* Check whether a thread is safe to be swapped out. */ #define thread_safetoswapout(td) ((td)->td_flags & TDF_CANSWAP) @@ -849,8 +879,10 @@ struct proc *zpfind(pid_t); /* Find zombie process by id. */ #define PGET_NOTWEXIT 0x00010 /* Check that the process is not in P_WEXIT. */ #define PGET_NOTINEXEC 0x00020 /* Check that the process is not in P_INEXEC. */ #define PGET_NOTID 0x00040 /* Do not assume tid if pid > PID_MAX. */ +#define PGET_KEEP 0x00080 +#define PGET_LOCK 0x00100 /* force taking a lock even with PGET_KEEP */ -#define PGET_WANTREAD (PGET_HOLD | PGET_CANDEBUG | PGET_NOTWEXIT) +#define PGET_WANTREAD (PGET_CANDEBUG | PGET_NOTWEXIT | PGET_KEEP) int pget(pid_t pid, int flags, struct proc **pp);