Index: sys/dev/hwpmc/hwpmc_logging.c =================================================================== --- sys/dev/hwpmc/hwpmc_logging.c +++ sys/dev/hwpmc/hwpmc_logging.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -234,6 +235,54 @@ return (plb ? 0 : ENOMEM); } +struct pmclog_proc_init_args { + struct proc *kthr; + struct pmc_owner *po; + bool exit; + bool acted; +}; + +int +pmclog_proc_create(struct thread *td, void **handlep) +{ + struct pmclog_proc_init_args *ia; + int error; + + ia = malloc(sizeof(*ia), M_TEMP, M_WAITOK | M_ZERO); + error = kproc_create(pmclog_loop, ia, &ia->kthr, + RFHIGHPID, 0, "hwpmc: proc(%d)", td->td_proc->p_pid); + if (error == 0) + *handlep = ia; + return (error); +} + +void +pmclog_proc_ignite(void *handle, struct pmc_owner *po) +{ + struct pmclog_proc_init_args *ia; + + ia = handle; + mtx_lock(&pmc_kthread_mtx); + MPASS(!ia->acted); + MPASS(ia->po == NULL); + MPASS(!ia->exit); + MPASS(ia->kthr != NULL); + if (po == NULL) { + ia->exit = true; + } else { + ia->po = po; + KASSERT(po->po_kthread == NULL, + ("[pmclog,%d] po=%p kthread (%p) already present", + __LINE__, po, po->po_kthread)); + po->po_kthread = ia->kthr; + } + wakeup(ia); + while (!ia->acted) + msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogw", 0); + mtx_unlock(&pmc_kthread_mtx); + free(ia, M_TEMP); +} + /* * Log handler loop. * @@ -243,20 +292,44 @@ static void pmclog_loop(void *arg) { - int error; + struct pmclog_proc_init_args *ia; struct pmc_owner *po; struct pmclog_buffer *lb; struct proc *p; struct ucred *ownercred; struct ucred *mycred; struct thread *td; + sigset_t unb; struct uio auio; struct iovec aiov; size_t nbytes; + int error; - po = (struct pmc_owner *) arg; - p = po->po_owner; td = curthread; + + SIGEMPTYSET(unb); + SIGADDSET(unb, SIGHUP); + (void)kern_sigprocmask(td, SIG_UNBLOCK, &unb, NULL, 0); + + ia = arg; + MPASS(ia->kthr == curproc); + MPASS(!ia->acted); + mtx_lock(&pmc_kthread_mtx); + while (ia->po == NULL && !ia->exit) + msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogi", 0); + if (ia->exit) { + ia->acted = true; + wakeup(ia); + mtx_unlock(&pmc_kthread_mtx); + kproc_exit(0); + } + MPASS(ia->po != NULL); + po = ia->po; + ia->acted = true; + wakeup(ia); + mtx_unlock(&pmc_kthread_mtx); + + p = po->po_owner; mycred = td->td_ucred; PROC_LOCK(p); @@ -291,16 +364,8 @@ mtx_unlock_spin(&po->po_mtx); /* No more buffers and shutdown required. */ - if (po->po_flags & PMC_PO_SHUTDOWN) { - mtx_unlock(&pmc_kthread_mtx); - /* - * Close the file to get PMCLOG_EOF - * error in pmclog(3). - */ - fo_close(po->po_file, curthread); - mtx_lock(&pmc_kthread_mtx); + if (po->po_flags & PMC_PO_SHUTDOWN) break; - } (void) msleep(po, &pmc_kthread_mtx, PWAIT, "pmcloop", 0); @@ -541,19 +606,16 @@ static void pmclog_stop_kthread(struct pmc_owner *po) { - /* - * Close the file to force the thread out of fo_write, - * unset flag, wakeup the helper thread, - * wait for it to exit - */ - - if (po->po_file != NULL) - fo_close(po->po_file, curthread); mtx_lock(&pmc_kthread_mtx); po->po_flags &= ~PMC_PO_OWNS_LOGFILE; + if (po->po_kthread != NULL) { + PROC_LOCK(po->po_kthread); + kern_psignal(po->po_kthread, SIGHUP); + PROC_UNLOCK(po->po_kthread); + } wakeup_one(po); - if (po->po_kthread) + while (po->po_kthread != NULL) msleep(po->po_kthread, &pmc_kthread_mtx, PPAUSE, "pmckstp", 0); mtx_unlock(&pmc_kthread_mtx); } @@ -572,15 +634,16 @@ int pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) { - int error; struct proc *p; cap_rights_t rights; + int error; + /* * As long as it is possible to get a LOR between pmc_sx lock and * proctree/allproc sx locks used for adding a new process, assure * the former is not held here. */ - sx_assert(&pmc_sx, SA_UNLOCKED); + sx_assert(&pmc_sx, SA_XLOCKED); PMCDBG2(LOG,CFG,1, "config po=%p logfd=%d", po, logfd); p = po->po_owner; @@ -589,9 +652,6 @@ if (po->po_flags & PMC_PO_OWNS_LOGFILE) return (EBUSY); - KASSERT(po->po_kthread == NULL, - ("[pmclog,%d] po=%p kthread (%p) already present", __LINE__, po, - po->po_kthread)); KASSERT(po->po_file == NULL, ("[pmclog,%d] po=%p file (%p) already present", __LINE__, po, po->po_file)); @@ -604,10 +664,6 @@ /* mark process as owning a log file */ po->po_flags |= PMC_PO_OWNS_LOGFILE; - error = kproc_create(pmclog_loop, po, &po->po_kthread, - RFHIGHPID, 0, "hwpmc: proc(%d)", p->p_pid); - if (error) - goto error; /* mark process as using HWPMCs */ PROC_LOCK(p); @@ -624,10 +680,6 @@ return (0); error: - /* shutdown the thread */ - if (po->po_kthread) - pmclog_stop_kthread(po); - KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not " "stopped", __LINE__, po)); @@ -685,8 +737,11 @@ } /* drop a reference to the fd */ - error = fdrop(po->po_file, curthread); - po->po_file = NULL; + if (po->po_file != NULL) { + error = fdrop(po->po_file, curthread); + po->po_file = NULL; + } else + error = 0; po->po_error = 0; return (error); Index: sys/dev/hwpmc/hwpmc_mod.c =================================================================== --- sys/dev/hwpmc/hwpmc_mod.c +++ sys/dev/hwpmc/hwpmc_mod.c @@ -311,27 +311,23 @@ /* The `sysent' for the new syscall */ static struct sysent pmc_sysent = { - 2, /* sy_narg */ - pmc_syscall_handler /* sy_call */ + .sy_narg = 2, + .sy_call = pmc_syscall_handler, }; static struct syscall_module_data pmc_syscall_mod = { - load, - NULL, - &pmc_syscall_num, - &pmc_sysent, -#if (__FreeBSD_version >= 1100000) - { 0, NULL }, - SY_THR_STATIC_KLD, -#else - { 0, NULL } -#endif + .chainevh = load, + .chainarg = NULL, + .offset = &pmc_syscall_num, + .new_sysent = &pmc_sysent, + .old_sysent = { .sy_narg = 0, .sy_call = NULL }, + .flags = SY_THR_STATIC_KLD, }; static moduledata_t pmc_mod = { - PMC_MODULE_NAME, - syscall_module_handler, - &pmc_syscall_mod + .name = PMC_MODULE_NAME, + .evhand = syscall_module_handler, + .priv = &pmc_syscall_mod, }; #ifdef EARLY_AP_STARTUP @@ -2858,21 +2854,30 @@ static int pmc_syscall_handler(struct thread *td, void *syscall_args) { - int error, is_sx_downgraded, is_sx_locked, op; + int error, is_sx_downgraded, op; struct pmc_syscall_args *c; + void *pmclog_proc_handle; void *arg; - PMC_GET_SX_XLOCK(ENOSYS); - - DROP_GIANT(); - - is_sx_downgraded = 0; - is_sx_locked = 1; - - c = (struct pmc_syscall_args *) syscall_args; - + c = (struct pmc_syscall_args *)syscall_args; op = c->pmop_code; arg = c->pmop_data; + if (op == PMC_OP_CONFIGURELOG) { + /* + * We cannot create the logging process inside + * pmclog_configure_log() because there is a LOR + * between pmc_sx and process structure locks. + * Instead, pre-create the process and ignite the loop + * if everything is fine, otherwise direct the process + * to exit. + */ + error = pmclog_proc_create(td, &pmclog_proc_handle); + if (error != 0) + goto done_syscall; + } + + PMC_GET_SX_XLOCK(ENOSYS); + is_sx_downgraded = 0; PMCDBG3(MOD,PMS,1, "syscall op=%d \"%s\" arg=%p", op, pmc_op_to_name[op], arg); @@ -2880,8 +2885,7 @@ error = 0; atomic_add_int(&pmc_stats.pm_syscalls, 1); - switch(op) - { + switch (op) { /* @@ -2897,15 +2901,16 @@ struct pmc_owner *po; struct pmc_op_configurelog cl; - sx_assert(&pmc_sx, SX_XLOCKED); - - if ((error = copyin(arg, &cl, sizeof(cl))) != 0) + if ((error = copyin(arg, &cl, sizeof(cl))) != 0) { + pmclog_proc_ignite(pmclog_proc_handle, NULL); break; + } /* mark this process as owning a log file */ p = td->td_proc; if ((po = pmc_find_owner_descriptor(p)) == NULL) if ((po = pmc_allocate_owner_descriptor(p)) == NULL) { + pmclog_proc_ignite(pmclog_proc_handle, NULL); error = ENOMEM; break; } @@ -2917,10 +2922,11 @@ * de-configure it. */ if (cl.pm_logfd >= 0) { - sx_xunlock(&pmc_sx); - is_sx_locked = 0; error = pmclog_configure_log(md, po, cl.pm_logfd); + pmclog_proc_ignite(pmclog_proc_handle, error == 0 ? + po : NULL); } else if (po->po_flags & PMC_PO_OWNS_LOGFILE) { + pmclog_proc_ignite(pmclog_proc_handle, NULL); pmclog_process_closelog(po); error = pmclog_close(po); if (error == 0) { @@ -2930,11 +2936,10 @@ pmc_stop(pm); error = pmclog_deconfigure_log(po); } - } else + } else { + pmclog_proc_ignite(pmclog_proc_handle, NULL); error = EINVAL; - - if (error) - break; + } } break; @@ -4029,19 +4034,15 @@ break; } - if (is_sx_locked != 0) { - if (is_sx_downgraded) - sx_sunlock(&pmc_sx); - else - sx_xunlock(&pmc_sx); - } - + if (is_sx_downgraded) + sx_sunlock(&pmc_sx); + else + sx_xunlock(&pmc_sx); +done_syscall: if (error) atomic_add_int(&pmc_stats.pm_syscall_errors, 1); - PICKUP_GIANT(); - - return error; + return (error); } /* Index: sys/sys/pmclog.h =================================================================== --- sys/sys/pmclog.h +++ sys/sys/pmclog.h @@ -260,6 +260,8 @@ int pmclog_flush(struct pmc_owner *_po); int pmclog_close(struct pmc_owner *_po); void pmclog_initialize(void); +int pmclog_proc_create(struct thread *td, void **handlep); +void pmclog_proc_ignite(void *handle, struct pmc_owner *po); void pmclog_process_callchain(struct pmc *_pm, struct pmc_sample *_ps); void pmclog_process_closelog(struct pmc_owner *po); void pmclog_process_dropnotify(struct pmc_owner *po);