In hwpmc, do not double-close the logging file.

hwpmc(4) must not voluntarily call fo_close(), doing this causes
double-close of the file.  It seems to almost avoid bad consequences
for pipes, but other types of files demonstrate random memory access.

To fix, remove fo_close() calls, which also do not provide the
declared wake-up of waiters consistently.  Instead, send a signal to
the logger and configure the logger process to not block it.  Since
logger never returns to userspace, the signal only causes termination
of the interruptible sleeps in fo_write().

Reported and tested by:	pho
Reviewed by:	markj
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
X-Differential revision:	https://reviews.freebsd.org/D12882
This commit is contained in:
Konstantin Belousov 2017-11-01 11:32:52 +00:00
parent bd63e82975
commit ea4d25f90b

View File

@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/pmclog.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/uio.h>
@ -250,6 +251,7 @@ pmclog_loop(void *arg)
struct ucred *ownercred;
struct ucred *mycred;
struct thread *td;
sigset_t unb;
struct uio auio;
struct iovec aiov;
size_t nbytes;
@ -257,6 +259,11 @@ pmclog_loop(void *arg)
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);
mycred = td->td_ucred;
PROC_LOCK(p);
@ -291,16 +298,8 @@ pmclog_loop(void *arg)
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 +540,16 @@ pmclog_schedule_io(struct pmc_owner *po)
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)
msleep(po->po_kthread, &pmc_kthread_mtx, PPAUSE, "pmckstp", 0);
mtx_unlock(&pmc_kthread_mtx);
}