summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/alpha/alpha/machdep.c27
-rw-r--r--sys/alpha/alpha/trap.c4
-rw-r--r--sys/arm/arm/machdep.c16
-rw-r--r--sys/arm/arm/undefined.c4
-rw-r--r--sys/fs/pseudofs/pseudofs_vnops.c8
-rw-r--r--sys/i386/linux/linux_ptrace.c6
-rw-r--r--sys/ia64/ia64/machdep.c2
-rw-r--r--sys/kern/kern_exit.c27
-rw-r--r--sys/kern/kern_kse.c18
-rw-r--r--sys/kern/sys_process.c164
-rw-r--r--sys/sys/proc.h3
11 files changed, 164 insertions, 115 deletions
diff --git a/sys/alpha/alpha/machdep.c b/sys/alpha/alpha/machdep.c
index 0a279bb..519126b 100644
--- a/sys/alpha/alpha/machdep.c
+++ b/sys/alpha/alpha/machdep.c
@@ -1756,6 +1756,8 @@ ptrace_read_int(struct thread *td, vm_offset_t addr, u_int32_t *v)
{
struct iovec iov;
struct uio uio;
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
iov.iov_base = (caddr_t) v;
iov.iov_len = sizeof(u_int32_t);
uio.uio_iov = &iov;
@@ -1773,6 +1775,8 @@ ptrace_write_int(struct thread *td, vm_offset_t addr, u_int32_t v)
{
struct iovec iov;
struct uio uio;
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
iov.iov_base = (caddr_t) &v;
iov.iov_len = sizeof(u_int32_t);
uio.uio_iov = &iov;
@@ -1836,6 +1840,8 @@ ptrace_read_register(struct thread *td, int regno)
static int
ptrace_clear_bpt(struct thread *td, struct mdbpt *bpt)
{
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
return ptrace_write_int(td, bpt->addr, bpt->contents);
}
@@ -1844,6 +1850,8 @@ ptrace_set_bpt(struct thread *td, struct mdbpt *bpt)
{
int error;
u_int32_t bpins = 0x00000080;
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
error = ptrace_read_int(td, bpt->addr, &bpt->contents);
if (error)
return error;
@@ -1853,12 +1861,20 @@ ptrace_set_bpt(struct thread *td, struct mdbpt *bpt)
int
ptrace_clear_single_step(struct thread *td)
{
+ struct proc *p;
+
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
if (td->td_md.md_flags & MDTD_STEP2) {
+ PROC_UNLOCK(p);
ptrace_clear_bpt(td, &td->td_md.md_sstep[1]);
ptrace_clear_bpt(td, &td->td_md.md_sstep[0]);
+ PROC_LOCK(p);
td->td_md.md_flags &= ~MDTD_STEP2;
} else if (td->td_md.md_flags & MDTD_STEP1) {
+ PROC_UNLOCK(p);
ptrace_clear_bpt(td, &td->td_md.md_sstep[0]);
+ PROC_LOCK(p);
td->td_md.md_flags &= ~MDTD_STEP1;
}
return 0;
@@ -1867,6 +1883,7 @@ ptrace_clear_single_step(struct thread *td)
int
ptrace_single_step(struct thread *td)
{
+ struct proc *p;
int error;
vm_offset_t pc = td->td_frame->tf_regs[FRAME_PC];
alpha_instruction ins;
@@ -1876,9 +1893,11 @@ ptrace_single_step(struct thread *td)
if (td->td_md.md_flags & (MDTD_STEP1|MDTD_STEP2))
panic("ptrace_single_step: step breakpoints not removed");
+ p = td->td_proc;
+ PROC_UNLOCK(p);
error = ptrace_read_int(td, pc, &ins.bits);
if (error)
- return (error);
+ goto out;
switch (ins.branch_format.opcode) {
@@ -1918,18 +1937,20 @@ ptrace_single_step(struct thread *td)
td->td_md.md_sstep[0].addr = addr[0];
error = ptrace_set_bpt(td, &td->td_md.md_sstep[0]);
if (error)
- return (error);
+ goto out;
if (count == 2) {
td->td_md.md_sstep[1].addr = addr[1];
error = ptrace_set_bpt(td, &td->td_md.md_sstep[1]);
if (error) {
ptrace_clear_bpt(td, &td->td_md.md_sstep[0]);
- return (error);
+ goto out;
}
td->td_md.md_flags |= MDTD_STEP2;
} else
td->td_md.md_flags |= MDTD_STEP1;
+out:
+ PROC_LOCK(p);
return (error);
}
diff --git a/sys/alpha/alpha/trap.c b/sys/alpha/alpha/trap.c
index a3a47cd..33b4826 100644
--- a/sys/alpha/alpha/trap.c
+++ b/sys/alpha/alpha/trap.c
@@ -403,8 +403,12 @@ trap(a0, a1, a2, entry, framep)
case ALPHA_IF_CODE_BUGCHK:
if (td->td_md.md_flags & (MDTD_STEP1|MDTD_STEP2)) {
mtx_lock(&Giant);
+ PROC_LOCK(p);
+ _PHOLD(p);
ptrace_clear_single_step(td);
td->td_frame->tf_regs[FRAME_PC] -= 4;
+ _PRELE(p);
+ PROC_UNLOCK(p);
mtx_unlock(&Giant);
}
ucode = a0; /* trap type */
diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c
index 45806ee..4e0e188 100644
--- a/sys/arm/arm/machdep.c
+++ b/sys/arm/arm/machdep.c
@@ -327,6 +327,8 @@ ptrace_read_int(struct thread *td, vm_offset_t addr, u_int32_t *v)
{
struct iovec iov;
struct uio uio;
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
iov.iov_base = (caddr_t) v;
iov.iov_len = sizeof(u_int32_t);
uio.uio_iov = &iov;
@@ -344,6 +346,8 @@ ptrace_write_int(struct thread *td, vm_offset_t addr, u_int32_t v)
{
struct iovec iov;
struct uio uio;
+
+ PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
iov.iov_base = (caddr_t) &v;
iov.iov_len = sizeof(u_int32_t);
uio.uio_iov = &iov;
@@ -359,28 +363,38 @@ ptrace_write_int(struct thread *td, vm_offset_t addr, u_int32_t v)
int
ptrace_single_step(struct thread *td)
{
+ struct proc *p;
int error;
KASSERT(td->td_md.md_ptrace_instr == 0,
("Didn't clear single step"));
+ p = td->td_proc;
+ PROC_UNLOCK(p);
error = ptrace_read_int(td, td->td_frame->tf_pc + 4,
&td->td_md.md_ptrace_instr);
if (error)
- return (error);
+ goto out;
error = ptrace_write_int(td, td->td_frame->tf_pc + 4,
PTRACE_BREAKPOINT);
if (error)
td->td_md.md_ptrace_instr = 0;
td->td_md.md_ptrace_addr = td->td_frame->tf_pc + 4;
+out:
+ PROC_LOCK(p);
return (error);
}
int
ptrace_clear_single_step(struct thread *td)
{
+ struct proc *p;
+
if (td->td_md.md_ptrace_instr) {
+ p = td->td_proc;
+ PROC_UNLOCK(p);
ptrace_write_int(td, td->td_md.md_ptrace_addr,
td->td_md.md_ptrace_instr);
+ PROC_LOCK(p);
td->td_md.md_ptrace_instr = 0;
}
return (0);
diff --git a/sys/arm/arm/undefined.c b/sys/arm/arm/undefined.c
index 58820aa..d6275e8 100644
--- a/sys/arm/arm/undefined.c
+++ b/sys/arm/arm/undefined.c
@@ -261,7 +261,11 @@ undefinedinstruction(trapframe_t *frame)
break;
if (fault_code & FAULT_USER && fault_instruction == PTRACE_BREAKPOINT) {
+ PROC_LOCK(td->td_proc);
+ _PHOLD(td->td_proc);
ptrace_clear_single_step(td);
+ _PRELE(td->td_proc);
+ PROC_UNLOCK(td->td_proc);
return;
}
diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c
index 556707c..9482db7 100644
--- a/sys/fs/pseudofs/pseudofs_vnops.c
+++ b/sys/fs/pseudofs/pseudofs_vnops.c
@@ -99,6 +99,10 @@ pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, struct proc **p)
if (pid != NO_PID) {
if ((proc = pfind(pid)) == NULL)
PFS_RETURN (0);
+ if (proc->p_flag & P_WEXIT) {
+ PROC_UNLOCK(proc);
+ PFS_RETURN (0);
+ }
if (p_cansee(td, proc) != 0 ||
(pn->pn_vis != NULL && !(pn->pn_vis)(td, proc, pn))) {
PROC_UNLOCK(proc);
@@ -706,6 +710,10 @@ pfs_readlink(struct vop_readlink_args *va)
if (pvd->pvd_pid != NO_PID) {
if ((proc = pfind(pvd->pvd_pid)) == NULL)
PFS_RETURN (EIO);
+ if (proc->p_flag & P_WEXIT) {
+ PROC_UNLOCK(proc);
+ PFS_RETURN (EIO);
+ }
_PHOLD(proc);
PROC_UNLOCK(proc);
}
diff --git a/sys/i386/linux/linux_ptrace.c b/sys/i386/linux/linux_ptrace.c
index 9445028..68532e2 100644
--- a/sys/i386/linux/linux_ptrace.c
+++ b/sys/i386/linux/linux_ptrace.c
@@ -356,6 +356,12 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
break;
}
+ /* Exiting processes can't be debugged. */
+ if ((p->p_flag & P_WEXIT) != 0) {
+ error = ESRCH;
+ goto fail;
+ }
+
if ((error = p_candebug(td, p)) != 0)
goto fail;
diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c
index e9521be..22d5e72 100644
--- a/sys/ia64/ia64/machdep.c
+++ b/sys/ia64/ia64/machdep.c
@@ -1097,6 +1097,7 @@ ia64_flush_dirty(struct thread *td, struct _special *r)
r->rnat = (bspst > kstk && (bspst & 0x1ffL) < (kstk & 0x1ffL))
? *(uint64_t*)(kstk | 0x1f8L) : rnat;
} else {
+ PHOLD(td->td_proc);
iov.iov_base = (void*)(uintptr_t)kstk;
iov.iov_len = r->ndirty;
uio.uio_iov = &iov;
@@ -1114,6 +1115,7 @@ ia64_flush_dirty(struct thread *td, struct _special *r)
*/
if (uio.uio_resid != 0 && error == 0)
error = ENOSPC;
+ PRELE(td->td_proc);
}
r->bspstore += r->ndirty;
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 5785e0b..0738e69 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -175,7 +175,29 @@ retry:
*/
}
+ /*
+ * Wakeup anyone in procfs' PIOCWAIT. They should have a hold
+ * on our vmspace, so we should block below until they have
+ * released their reference to us. Note that if they have
+ * requested S_EXIT stops we will block here until they ack
+ * via PIOCCONT.
+ */
+ _STOPEVENT(p, S_EXIT, rv);
+
+ /*
+ * Note that we are exiting and do another wakeup of anyone in
+ * PIOCWAIT in case they aren't listening for S_EXIT stops or
+ * decided to wait again after we told them we are exiting.
+ */
p->p_flag |= P_WEXIT;
+ wakeup(&p->p_stype);
+
+ /*
+ * Wait for any processes that have a hold on our vmspace to
+ * release their reference.
+ */
+ while (p->p_lock > 0)
+ msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0);
PROC_LOCK(p->p_pptr);
sigqueue_take(p->p_ksi);
@@ -209,11 +231,6 @@ retry:
mtx_unlock(&ppeers_lock);
}
- PROC_LOCK(p);
- _STOPEVENT(p, S_EXIT, rv);
- wakeup(&p->p_stype); /* Wakeup anyone in procfs' PIOCWAIT */
- PROC_UNLOCK(p);
-
/*
* Check if any loadable modules need anything done at process exit.
* E.g. SYSV IPC stuff
diff --git a/sys/kern/kern_kse.c b/sys/kern/kern_kse.c
index e5ae121..8f8585c 100644
--- a/sys/kern/kern_kse.c
+++ b/sys/kern/kern_kse.c
@@ -148,7 +148,9 @@ kse_switchin(struct thread *td, struct kse_switchin_args *uap)
td->td_mailbox = uap->tmbx;
td->td_pflags |= TDP_CAN_UNBIND;
}
+ PROC_LOCK(td->td_proc);
if (td->td_proc->p_flag & P_TRACED) {
+ _PHOLD(td->td_proc);
if (tmbx.tm_dflags & TMDF_SSTEP)
ptrace_single_step(td);
else
@@ -160,7 +162,9 @@ kse_switchin(struct thread *td, struct kse_switchin_args *uap)
ku->ku_flags |= KUF_DOUPCALL;
mtx_unlock_spin(&sched_lock);
}
+ _PRELE(td->td_proc);
}
+ PROC_UNLOCK(td->td_proc);
}
return ((error == 0) ? EJUSTRETURN : error);
}
@@ -782,8 +786,13 @@ kse_create(struct thread *td, struct kse_create_args *uap)
*/
cpu_set_upcall_kse(newtd, newku->ku_func,
newku->ku_mailbox, &newku->ku_stack);
- if (p->p_flag & P_TRACED)
+ PROC_LOCK(p);
+ if (p->p_flag & P_TRACED) {
+ _PHOLD(p);
ptrace_clear_single_step(newtd);
+ _PRELE(p);
+ }
+ PROC_UNLOCK(p);
}
}
@@ -1376,8 +1385,13 @@ thread_userret(struct thread *td, struct trapframe *frame)
if (!(ku->ku_mflags & KMF_NOUPCALL)) {
cpu_set_upcall_kse(td, ku->ku_func, ku->ku_mailbox,
&ku->ku_stack);
- if (p->p_flag & P_TRACED)
+ PROC_LOCK(p);
+ if (p->p_flag & P_TRACED) {
+ _PHOLD(p);
ptrace_clear_single_step(td);
+ _PRELE(p);
+ }
+ PROC_UNLOCK(p);
error = suword32(&ku->ku_mailbox->km_lwp,
td->td_tid);
if (error)
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index eeb56a4..9c128be 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -212,30 +212,24 @@ proc_sstep(struct thread *td)
int
proc_rwmem(struct proc *p, struct uio *uio)
{
- struct vmspace *vm;
vm_map_t map;
vm_object_t backing_object, object = NULL;
vm_offset_t pageno = 0; /* page number */
vm_prot_t reqprot;
- int error, refcnt, writing;
+ int error, writing;
/*
- * if the vmspace is in the midst of being deallocated or the
- * process is exiting, don't try to grab anything. The page table
- * usage in that process can be messed up.
+ * Assert that someone has locked this vmspace. (Should be
+ * curthread but we can't assert that.) This keeps the process
+ * from exiting out from under us until this operation completes.
*/
- vm = p->p_vmspace;
- if ((p->p_flag & P_WEXIT))
- return (EFAULT);
- do {
- if ((refcnt = vm->vm_refcnt) < 1)
- return (EFAULT);
- } while (!atomic_cmpset_int(&vm->vm_refcnt, refcnt, refcnt + 1));
+ KASSERT(p->p_lock >= 1, ("%s: process %p (pid %d) not held", __func__,
+ p, p->p_pid));
/*
* The map we want...
*/
- map = &vm->vm_map;
+ map = &p->p_vmspace->vm_map;
writing = uio->uio_rw == UIO_WRITE;
reqprot = writing ? (VM_PROT_WRITE | VM_PROT_OVERRIDE_WRITE) :
@@ -338,7 +332,6 @@ proc_rwmem(struct proc *p, struct uio *uio)
} while (error == 0 && uio->uio_resid > 0);
- vmspace_free(vm);
return (error);
}
@@ -558,6 +551,11 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
}
AUDIT_ARG(process, p);
+
+ if ((p->p_flag & P_WEXIT) != 0) {
+ error = ESRCH;
+ goto fail;
+ }
if ((error = p_cansee(td, p)) != 0)
goto fail;
@@ -665,11 +663,14 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
break;
}
+ /* Keep this process around until we finish this request. */
+ _PHOLD(p);
+
#ifdef FIX_SSTEP
/*
* Single step fixup ala procfs
*/
- FIX_SSTEP(td2); /* XXXKSE */
+ FIX_SSTEP(td2);
#endif
/*
@@ -683,9 +684,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
/* set my trace flag and "owner" so it can read/write me */
p->p_flag |= P_TRACED;
p->p_oppid = p->p_pptr->p_pid;
- PROC_UNLOCK(p);
- sx_xunlock(&proctree_lock);
- return (0);
+ break;
case PT_ATTACH:
/* security check done above */
@@ -701,40 +700,24 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
goto sendsig; /* in PT_CONTINUE below */
case PT_CLEARSTEP:
- _PHOLD(p);
error = ptrace_clear_single_step(td2);
- _PRELE(p);
- if (error)
- goto fail;
- PROC_UNLOCK(p);
- return (0);
+ break;
case PT_SETSTEP:
- _PHOLD(p);
error = ptrace_single_step(td2);
- _PRELE(p);
- if (error)
- goto fail;
- PROC_UNLOCK(p);
- return (0);
+ break;
case PT_SUSPEND:
- _PHOLD(p);
mtx_lock_spin(&sched_lock);
td2->td_flags |= TDF_DBSUSPEND;
mtx_unlock_spin(&sched_lock);
- _PRELE(p);
- PROC_UNLOCK(p);
- return (0);
+ break;
case PT_RESUME:
- _PHOLD(p);
mtx_lock_spin(&sched_lock);
td2->td_flags &= ~TDF_DBSUSPEND;
mtx_unlock_spin(&sched_lock);
- _PRELE(p);
- PROC_UNLOCK(p);
- return (0);
+ break;
case PT_STEP:
case PT_CONTINUE:
@@ -745,20 +728,14 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
/* Zero means do not send any signal */
if (data < 0 || data > _SIG_MAXSIG) {
error = EINVAL;
- goto fail;
+ break;
}
- _PHOLD(p);
-
switch (req) {
case PT_STEP:
- PROC_UNLOCK(p);
error = ptrace_single_step(td2);
- if (error) {
- PRELE(p);
- goto fail_noproc;
- }
- PROC_LOCK(p);
+ if (error)
+ goto out;
break;
case PT_TO_SCE:
p->p_stops |= S_PT_SCE;
@@ -772,15 +749,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
if (addr != (void *)1) {
- PROC_UNLOCK(p);
error = ptrace_set_pc(td2, (u_long)(uintfptr_t)addr);
- if (error) {
- PRELE(p);
- goto fail_noproc;
- }
- PROC_LOCK(p);
+ if (error)
+ break;
}
- _PRELE(p);
if (req == PT_DETACH) {
/* reset process parent */
@@ -810,8 +782,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
sendsig:
- if (proctree_locked)
+ if (proctree_locked) {
sx_xunlock(&proctree_lock);
+ proctree_locked = 0;
+ }
/* deliver or queue signal */
mtx_lock_spin(&sched_lock);
td2->td_flags &= ~TDF_XSIG;
@@ -842,8 +816,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
if (data)
psignal(p, data);
- PROC_UNLOCK(p);
- return (0);
+ break;
case PT_WRITE_I:
case PT_WRITE_D:
@@ -879,10 +852,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
if (!write)
td->td_retval[0] = tmp;
- return (error);
+ PROC_LOCK(p);
+ break;
case PT_IO:
- PROC_UNLOCK(p);
#ifdef COMPAT_IA32
if (wrap32) {
piod32 = addr;
@@ -918,8 +891,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
uio.uio_rw = UIO_WRITE;
break;
default:
- return (EINVAL);
+ error = EINVAL;
+ goto out;
}
+ PROC_UNLOCK(p);
error = proc_rwmem(p, &uio);
#ifdef COMPAT_IA32
if (wrap32)
@@ -927,59 +902,43 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
else
#endif
piod->piod_len -= uio.uio_resid;
- return (error);
+ PROC_LOCK(p);
+ break;
case PT_KILL:
data = SIGKILL;
goto sendsig; /* in PT_CONTINUE above */
case PT_SETREGS:
- _PHOLD(p);
error = PROC_WRITE(regs, td2, addr);
- _PRELE(p);
- PROC_UNLOCK(p);
- return (error);
+ break;
case PT_GETREGS:
- _PHOLD(p);
error = PROC_READ(regs, td2, addr);
- _PRELE(p);
- PROC_UNLOCK(p);
- return (error);
+ break;
case PT_SETFPREGS:
- _PHOLD(p);
error = PROC_WRITE(fpregs, td2, addr);
- _PRELE(p);
- PROC_UNLOCK(p);
- return (error);
+ break;
case PT_GETFPREGS:
- _PHOLD(p);
error = PROC_READ(fpregs, td2, addr);
- _PRELE(p);
- PROC_UNLOCK(p);
- return (error);
+ break;
case PT_SETDBREGS:
- _PHOLD(p);
error = PROC_WRITE(dbregs, td2, addr);
- _PRELE(p);
- PROC_UNLOCK(p);
- return (error);
+ break;
case PT_GETDBREGS:
- _PHOLD(p);
error = PROC_READ(dbregs, td2, addr);
- _PRELE(p);
- PROC_UNLOCK(p);
- return (error);
+ break;
case PT_LWPINFO:
- if (data == 0 || data > sizeof(*pl))
- return (EINVAL);
+ if (data == 0 || data > sizeof(*pl)) {
+ error = EINVAL;
+ break;
+ }
pl = addr;
- _PHOLD(p);
pl->pl_lwpid = td2->td_tid;
if (td2->td_flags & TDF_XSIG)
pl->pl_event = PL_EVENT_SIGNAL;
@@ -994,19 +953,16 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
pl->pl_sigmask = td2->td_sigmask;
pl->pl_siglist = td2->td_siglist;
- _PRELE(p);
- PROC_UNLOCK(p);
- return (0);
+ break;
case PT_GETNUMLWPS:
td->td_retval[0] = p->p_numthreads;
- PROC_UNLOCK(p);
- return (0);
+ break;
case PT_GETLWPLIST:
if (data <= 0) {
- PROC_UNLOCK(p);
- return (EINVAL);
+ error = EINVAL;
+ break;
}
num = imin(p->p_numthreads, data);
PROC_UNLOCK(p);
@@ -1025,27 +981,27 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
free(buf, M_TEMP);
if (!error)
td->td_retval[0] = num;
- return (error);
+ PROC_LOCK(p);
+ break;
default:
#ifdef __HAVE_PTRACE_MACHDEP
if (req >= PT_FIRSTMACH) {
- _PHOLD(p);
PROC_UNLOCK(p);
error = cpu_ptrace(td2, req, addr, data);
- PRELE(p);
- return (error);
- }
+ PROC_LOCK(p);
+ } else
#endif
+ /* Unknown request. */
+ error = EINVAL;
break;
}
- /* Unknown request. */
- error = EINVAL;
-
+out:
+ /* Drop our hold on this process now that the request has completed. */
+ _PRELE(p);
fail:
PROC_UNLOCK(p);
-fail_noproc:
if (proctree_locked)
sx_xunlock(&proctree_lock);
return (error);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 5de9b97..d21a3e6 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -792,6 +792,7 @@ MALLOC_DECLARE(M_ZOMBIE);
} while (0)
#define _PHOLD(p) do { \
PROC_LOCK_ASSERT((p), MA_OWNED); \
+ KASSERT(!((p)->p_flag & P_WEXIT), ("PHOLD of exiting process"));\
(p)->p_lock++; \
if (((p)->p_sflag & PS_INMEM) == 0) \
faultin((p)); \
@@ -805,6 +806,8 @@ MALLOC_DECLARE(M_ZOMBIE);
#define _PRELE(p) do { \
PROC_LOCK_ASSERT((p), MA_OWNED); \
(--(p)->p_lock); \
+ if (((p)->p_flag & P_WEXIT) && (p)->p_lock == 0) \
+ wakeup(&(p)->p_lock); \
} while (0)
/* Check whether a thread is safe to be swapped out. */
OpenPOWER on IntegriCloud