- fix a LOR between process lock and pmc thread mutex

- fix a system deadlock on process exit when the sample buffer
is full (pmclog_loop blocked in fo_write) and pmcstat exit.

Reviewed by: jkoshy
MFC after: 3 weeks
This commit is contained in:
Fabien Thomas 2009-11-24 19:26:53 +00:00
parent 31e119ed7d
commit 5eaf27d8ff

View File

@ -240,6 +240,7 @@ pmclog_loop(void *arg)
int error; int error;
struct pmc_owner *po; struct pmc_owner *po;
struct pmclog_buffer *lb; struct pmclog_buffer *lb;
struct proc *p;
struct ucred *ownercred; struct ucred *ownercred;
struct ucred *mycred; struct ucred *mycred;
struct thread *td; struct thread *td;
@ -248,12 +249,13 @@ pmclog_loop(void *arg)
size_t nbytes; size_t nbytes;
po = (struct pmc_owner *) arg; po = (struct pmc_owner *) arg;
p = po->po_owner;
td = curthread; td = curthread;
mycred = td->td_ucred; mycred = td->td_ucred;
PROC_LOCK(po->po_owner); PROC_LOCK(p);
ownercred = crhold(po->po_owner->p_ucred); ownercred = crhold(p->p_ucred);
PROC_UNLOCK(po->po_owner); PROC_UNLOCK(p);
PMCDBG(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread); PMCDBG(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread);
KASSERT(po->po_kthread == curthread->td_proc, KASSERT(po->po_kthread == curthread->td_proc,
@ -324,16 +326,16 @@ pmclog_loop(void *arg)
error = fo_write(po->po_file, &auio, ownercred, 0, td); error = fo_write(po->po_file, &auio, ownercred, 0, td);
td->td_ucred = mycred; td->td_ucred = mycred;
mtx_lock(&pmc_kthread_mtx);
if (error) { if (error) {
/* XXX some errors are recoverable */ /* XXX some errors are recoverable */
/* XXX also check for SIGPIPE if a socket */ /* XXX also check for SIGPIPE if a socket */
/* send a SIGIO to the owner and exit */ /* send a SIGIO to the owner and exit */
PROC_LOCK(po->po_owner); PROC_LOCK(p);
psignal(po->po_owner, SIGIO); psignal(p, SIGIO);
PROC_UNLOCK(po->po_owner); PROC_UNLOCK(p);
mtx_lock(&pmc_kthread_mtx);
po->po_error = error; /* save for flush log */ po->po_error = error; /* save for flush log */
@ -342,6 +344,8 @@ pmclog_loop(void *arg)
break; break;
} }
mtx_lock(&pmc_kthread_mtx);
/* put the used buffer back into the global pool */ /* put the used buffer back into the global pool */
PMCLOG_INIT_BUFFER_DESCRIPTOR(lb); PMCLOG_INIT_BUFFER_DESCRIPTOR(lb);
@ -525,15 +529,20 @@ static void
pmclog_stop_kthread(struct pmc_owner *po) pmclog_stop_kthread(struct pmc_owner *po)
{ {
/* /*
* Unset flag, wakeup the helper thread, * Close the file to force the thread out of fo_write,
* unset flag, wakeup the helper thread,
* wait for it to exit * wait for it to exit
*/ */
mtx_assert(&pmc_kthread_mtx, MA_OWNED); if (po->po_file != NULL)
fo_close(po->po_file, curthread);
mtx_lock(&pmc_kthread_mtx);
po->po_flags &= ~PMC_PO_OWNS_LOGFILE; po->po_flags &= ~PMC_PO_OWNS_LOGFILE;
wakeup_one(po); wakeup_one(po);
if (po->po_kthread) if (po->po_kthread)
msleep(po->po_kthread, &pmc_kthread_mtx, PPAUSE, "pmckstp", 0); msleep(po->po_kthread, &pmc_kthread_mtx, PPAUSE, "pmckstp", 0);
mtx_unlock(&pmc_kthread_mtx);
} }
/* /*
@ -602,10 +611,8 @@ pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd)
error: error:
/* shutdown the thread */ /* shutdown the thread */
mtx_lock(&pmc_kthread_mtx);
if (po->po_kthread) if (po->po_kthread)
pmclog_stop_kthread(po); pmclog_stop_kthread(po);
mtx_unlock(&pmc_kthread_mtx);
KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not " KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not "
"stopped", __LINE__, po)); "stopped", __LINE__, po));
@ -641,10 +648,8 @@ pmclog_deconfigure_log(struct pmc_owner *po)
("[pmclog,%d] po=%p no log file", __LINE__, po)); ("[pmclog,%d] po=%p no log file", __LINE__, po));
/* stop the kthread, this will reset the 'OWNS_LOGFILE' flag */ /* stop the kthread, this will reset the 'OWNS_LOGFILE' flag */
mtx_lock(&pmc_kthread_mtx);
if (po->po_kthread) if (po->po_kthread)
pmclog_stop_kthread(po); pmclog_stop_kthread(po);
mtx_unlock(&pmc_kthread_mtx);
KASSERT(po->po_kthread == NULL, KASSERT(po->po_kthread == NULL,
("[pmclog,%d] po=%p kthread not stopped", __LINE__, po)); ("[pmclog,%d] po=%p kthread not stopped", __LINE__, po));