Author: fabient
Date: Tue Nov 24 19:26:53 2009
New Revision: 199763
URL: http://svn.freebsd.org/changeset/base/199763

Log:
  - 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

Modified:
  head/sys/dev/hwpmc/hwpmc_logging.c

Modified: head/sys/dev/hwpmc/hwpmc_logging.c
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_logging.c  Tue Nov 24 18:34:47 2009        
(r199762)
+++ head/sys/dev/hwpmc/hwpmc_logging.c  Tue Nov 24 19:26:53 2009        
(r199763)
@@ -240,6 +240,7 @@ pmclog_loop(void *arg)
        int error;
        struct pmc_owner *po;
        struct pmclog_buffer *lb;
+       struct proc *p;
        struct ucred *ownercred;
        struct ucred *mycred;
        struct thread *td;
@@ -248,12 +249,13 @@ pmclog_loop(void *arg)
        size_t nbytes;
 
        po = (struct pmc_owner *) arg;
+       p = po->po_owner;
        td = curthread;
        mycred = td->td_ucred;
 
-       PROC_LOCK(po->po_owner);
-       ownercred = crhold(po->po_owner->p_ucred);
-       PROC_UNLOCK(po->po_owner);
+       PROC_LOCK(p);
+       ownercred = crhold(p->p_ucred);
+       PROC_UNLOCK(p);
 
        PMCDBG(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread);
        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);
                td->td_ucred = mycred;
 
-               mtx_lock(&pmc_kthread_mtx);
-
                if (error) {
                        /* XXX some errors are recoverable */
                        /* XXX also check for SIGPIPE if a socket */
 
                        /* send a SIGIO to the owner and exit */
-                       PROC_LOCK(po->po_owner);
-                       psignal(po->po_owner, SIGIO);
-                       PROC_UNLOCK(po->po_owner);
+                       PROC_LOCK(p);
+                       psignal(p, SIGIO);
+                       PROC_UNLOCK(p);
+
+                       mtx_lock(&pmc_kthread_mtx);
 
                        po->po_error = error; /* save for flush log */
 
@@ -342,6 +344,8 @@ pmclog_loop(void *arg)
                        break;
                }
 
+               mtx_lock(&pmc_kthread_mtx);
+
                /* put the used buffer back into the global pool */
                PMCLOG_INIT_BUFFER_DESCRIPTOR(lb);
 
@@ -525,15 +529,20 @@ static void
 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
         */
 
-       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;
        wakeup_one(po);
        if (po->po_kthread)
                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
 
  error:
        /* shutdown the thread */
-       mtx_lock(&pmc_kthread_mtx);
        if (po->po_kthread)
                pmclog_stop_kthread(po);
-       mtx_unlock(&pmc_kthread_mtx);
 
        KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not "
            "stopped", __LINE__, po));
@@ -641,10 +648,8 @@ pmclog_deconfigure_log(struct pmc_owner 
            ("[pmclog,%d] po=%p no log file", __LINE__, po));
 
        /* stop the kthread, this will reset the 'OWNS_LOGFILE' flag */
-       mtx_lock(&pmc_kthread_mtx);
        if (po->po_kthread)
                pmclog_stop_kthread(po);
-       mtx_unlock(&pmc_kthread_mtx);
 
        KASSERT(po->po_kthread == NULL,
            ("[pmclog,%d] po=%p kthread not stopped", __LINE__, po));
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to