tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: In-kernel process exit hooks?
The saga continues! :)
I previously posted one set of patches that changes filemon to use
fd_{get,put}file() only when the activity-log file is actually being
accessed. This works, but doesn't prevent or detect when the
application program closes-and-reopens that fd.
Attached to this Email is a separate patch, using exithooks. The
current exithook implementation is extended to have an additional
"phase" argument, with values of EXITHOOK_BEFORE_CLOSE and
EXITHOOK_AFTER_CLOSE. (Existing uses of exithooks in sys_aio, sysv_sem,
and rump are updated to use EXITHOOK_AFTER_CLOSE.)
Filemon(4) now establishes an EXITHOOK_BEFORE_CLOSE which searches the
process's file descriptor table for entries to /dev/filemon. If any are
found, the associated activity-log file is disassociated from the
filemon fd and the extra reference is released.
(Note that establishing the exithook is actually done through a config
finalizer routine, since the built-in MODULE_CLASS_DRIVER modules are
initialized before the exithook stuff in exec_init().)
This exithook approach also works. There is still one problem, however.
If the application program attempts to explicitly close the log-file fd
while it is still associated with the filemon, we get the same hang.
Next, I'm going to have a look at fd_getfile2()/fclose() and see if that
is a viable approach.
+------------------+--------------------------+------------------------+
| Paul Goyette | PGP Key fingerprint: | E-mail addresses: |
| (Retired) | FA29 0E3B 35AF E8AE 6651 | paul at whooppee.com |
| Kernel Developer | 0786 F758 55DE 53BA 7731 | pgoyette at netbsd.org |
+------------------+--------------------------+------------------------+
Index: dev/filemon/filemon.c
===================================================================
RCS file: /cvsroot/src/sys/dev/filemon/filemon.c,v
retrieving revision 1.24
diff -u -p -r1.24 filemon.c
--- dev/filemon/filemon.c 5 Jan 2016 22:08:54 -0000 1.24
+++ dev/filemon/filemon.c 7 Jan 2016 23:54:37 -0000
@@ -43,6 +43,8 @@ __KERNEL_RCSID(0, "$NetBSD: filemon.c,v
#include <sys/kmem.h>
#include <sys/syslog.h>
#include <sys/kauth.h>
+#include <sys/device.h>
+#include <sys/errno.h>
#include "filemon.h"
#include "ioconf.h"
@@ -89,6 +91,75 @@ static TAILQ_HEAD(, filemon) filemons_in
static int logLevel = LOG_DEBUG;
#endif
+/*
+ * Use an exithook to make sure that the filemon device is closed and
+ * our additional reference to the output file is released before the
+ * normal closure of open files. The extra reference would otherwise
+ * cause process exit to hang indefinitely.
+ *
+ * We need to use a config_finalize() routine to register the hook
+ * due to system initialization sequence.
+ */
+void *hook = NULL; /* cookie from exithook_establish() */
+
+static int filemon_register_hook(device_t dev __unused);
+static void filemon_exithook(struct proc *p, void *arg);
+
+static int
+filemon_register_hook(device_t dev __unused)
+{
+
+ if (hook == NULL)
+ hook = exithook_establish(filemon_exithook, hook,
+ EXITHOOK_BEFORE_CLOSE);
+printf("%s: hook %p\n", __func__, hook);
+ if (hook != NULL)
+ return 0;
+ return ENXIO;
+}
+
+static void
+filemon_exithook(struct proc *p, void *arg)
+{
+ int fd;
+ struct filemon *filemon;
+ fdfile_t *ff;
+ filedesc_t *fdp;
+ fdtab_t *dt;
+
+ fdp = p->p_fd;
+ dt = fdp->fd_dt;
+ for (fd = 0; fd < dt->dt_nfiles; fd++) {
+ ff = dt->dt_ff[fd];
+ KASSERT(fd >= NDFDFILE ||
+ ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
+ if (ff == NULL || ff->ff_file == NULL)
+ continue;
+ if (ff->ff_file->f_type != DTYPE_MISC ||
+ ff->ff_file->f_ops != &filemon_fileops)
+ continue;
+printf("%s: found pid %d fd %d\n", __func__, p->p_pid, fd);
+ rw_enter(&filemon_mtx, RW_WRITER);
+ filemon = ff->ff_file->f_data;
+ if (filemon != NULL) {
+
+ /*
+ * If we have an output file, release our
+ * reference to it.
+ */
+ rw_enter(&filemon->fm_mtx, RW_WRITER);
+ if (filemon->fm_fp) {
+printf("%s: releasing %d\n", __func__, filemon->fm_fd);
+ KASSERT(p == curproc);
+ fd_putfile(filemon->fm_fd);
+ filemon->fm_fp = NULL;
+ }
+ rw_exit(&filemon->fm_mtx);
+ }
+ rw_exit(&filemon_mtx);
+ }
+}
+
void
filemon_output(struct filemon * filemon, char *msg, size_t len)
{
@@ -216,6 +287,9 @@ filemon_open(dev_t dev, int oflags __unu
struct file *fp;
int error, fd;
+ if (hook == NULL)
+ return ENXIO;
+
/* falloc() will fill in the descriptor for us. */
if ((error = fd_allocfile(&fp, &fd)) != 0)
return error;
@@ -265,6 +339,7 @@ filemon_close(struct file * fp)
*/
rw_enter(&filemon->fm_mtx, RW_WRITER);
if (filemon->fm_fp) {
+printf("%s: releasing %d\n", __func__, filemon->fm_fd);
fd_putfile(filemon->fm_fd); /* release our reference */
filemon->fm_fp = NULL;
}
@@ -399,19 +474,35 @@ filemon_modcmd(modcmd_t cmd, void *data)
switch (cmd) {
case MODULE_CMD_INIT:
+ KASSERT(hook == NULL);
#ifdef DEBUG
logLevel = LOG_INFO;
#endif
error = filemon_load(data);
+ if (error != 0)
+ break;
#ifdef _MODULE
- if (!error)
- error = devsw_attach("filemon", NULL, &bmajor,
- &filemon_cdevsw, &cmajor);
+ error = devsw_attach("filemon", NULL, &bmajor,
+ &filemon_cdevsw, &cmajor);
+ if (error != 0) {
+ filemon_unload();
+ break;
+ }
#endif
+ error = config_finalize_register(NULL, filemon_register_hook);
+ if (error != 0) {
+ devsw_detach(NULL, &filemon_cdevsw);
+ filemon_unload();
+ break;
+ }
break;
case MODULE_CMD_FINI:
+ if (hook != NULL) {
+ exithook_disestablish(hook, EXITHOOK_BEFORE_CLOSE);
+ hook = NULL;
+ }
error = filemon_unload();
#ifdef _MODULE
if (!error)
Index: kern/kern_exit.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_exit.c,v
retrieving revision 1.248
diff -u -p -r1.248 kern_exit.c
--- kern/kern_exit.c 13 Oct 2015 06:47:21 -0000 1.248
+++ kern/kern_exit.c 7 Jan 2016 23:55:02 -0000
@@ -279,10 +279,11 @@ exit1(struct lwp *l, int rv)
* Close open files, release open-file table and free signal
* actions. This may block!
*/
+ doexithooks(p, EXITHOOK_BEFORE_CLOSE);
fd_free();
cwdfree(p->p_cwdi);
p->p_cwdi = NULL;
- doexithooks(p);
+ doexithooks(p, EXITHOOK_AFTER_CLOSE);
sigactsfree(p->p_sigacts);
/*
Index: kern/kern_hook.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_hook.c,v
retrieving revision 1.6
diff -u -p -r1.6 kern_hook.c
--- kern/kern_hook.c 22 Nov 2013 21:04:11 -0000 1.6
+++ kern/kern_hook.c 7 Jan 2016 23:55:13 -0000
@@ -219,26 +219,33 @@ doexechooks(struct proc *p)
hook_proc_run(&exechook_list, p);
}
-static hook_list_t exithook_list = LIST_HEAD_INITIALIZER(exithook_list);
+static hook_list_t exithook_list0 = LIST_HEAD_INITIALIZER(exithook_list0);
+static hook_list_t exithook_list1 = LIST_HEAD_INITIALIZER(exithook_list1);
+static hook_list_t *exithook_table[] = {
+ &exithook_list0, /* EXITHOOK_BEFORE_CLOSE */
+ &exithook_list1, /* EXITHOOK_AFTER_CLOSE */
+};
extern krwlock_t exec_lock;
void *
-exithook_establish(void (*fn)(struct proc *, void *), void *arg)
+exithook_establish(void (*fn)(struct proc *, void *), void *arg, int ph)
{
void *rv;
+ KASSERT(ph >= 0 && ph < __arraycount(exithook_table));
rw_enter(&exec_lock, RW_WRITER);
- rv = hook_establish(&exithook_list, (void (*)(void *))fn, arg);
+ rv = hook_establish(exithook_table[ph], (void (*)(void *))fn, arg);
rw_exit(&exec_lock);
return rv;
}
void
-exithook_disestablish(void *vhook)
+exithook_disestablish(void *vhook, int ph)
{
+ KASSERT(ph >= 0 && ph < __arraycount(exithook_table));
rw_enter(&exec_lock, RW_WRITER);
- hook_disestablish(&exithook_list, vhook);
+ hook_disestablish(exithook_table[ph], vhook);
rw_exit(&exec_lock);
}
@@ -246,9 +253,11 @@ exithook_disestablish(void *vhook)
* Run exit hooks.
*/
void
-doexithooks(struct proc *p)
+doexithooks(struct proc *p, int ph)
{
- hook_proc_run(&exithook_list, p);
+
+ KASSERT(ph >= 0 && ph < __arraycount(exithook_table));
+ hook_proc_run(exithook_table[ph], p);
}
static hook_list_t forkhook_list = LIST_HEAD_INITIALIZER(forkhook_list);
Index: kern/sys_aio.c
===================================================================
RCS file: /cvsroot/src/sys/kern/sys_aio.c,v
retrieving revision 1.40
diff -u -p -r1.40 sys_aio.c
--- kern/sys_aio.c 5 Sep 2014 09:20:59 -0000 1.40
+++ kern/sys_aio.c 7 Jan 2016 23:55:29 -0000
@@ -131,7 +131,7 @@ aio_fini(bool interface)
sysctl_teardown(&aio_sysctl);
KASSERT(aio_jobs_count == 0);
- exithook_disestablish(aio_ehook);
+ exithook_disestablish(aio_ehook, EXITHOOK_AFTER_CLOSE);
pool_destroy(&aio_job_pool);
pool_destroy(&aio_lio_pool);
return 0;
@@ -149,7 +149,7 @@ aio_init(void)
"aio_jobs_pool", &pool_allocator_nointr, IPL_NONE);
pool_init(&aio_lio_pool, sizeof(struct lio_req), 0, 0, 0,
"aio_lio_pool", &pool_allocator_nointr, IPL_NONE);
- aio_ehook = exithook_establish(aio_exit, NULL);
+ aio_ehook = exithook_establish(aio_exit, NULL, EXITHOOK_AFTER_CLOSE);
error = sysctl_aio_init();
if (error != 0) {
Index: kern/sysv_sem.c
===================================================================
RCS file: /cvsroot/src/sys/kern/sysv_sem.c,v
retrieving revision 1.95
diff -u -p -r1.95 sysv_sem.c
--- kern/sysv_sem.c 6 Nov 2015 02:26:42 -0000 1.95
+++ kern/sysv_sem.c 7 Jan 2016 23:55:46 -0000
@@ -153,7 +153,7 @@ static int
seminit_exithook(void)
{
- hook = exithook_establish(semexit, NULL);
+ hook = exithook_establish(semexit, NULL, EXITHOOK_AFTER_CLOSE);
return 0;
}
@@ -172,7 +172,7 @@ semfini(void)
/* Remove the exit hook */
if (hook)
- exithook_disestablish(hook);
+ exithook_disestablish(hook, EXITHOOK_AFTER_CLOSE);
/* Destroy all our condvars */
for (i = 0; i < seminfo.semmni; i++) {
Index: rump/librump/rumpkern/lwproc.c
===================================================================
RCS file: /cvsroot/src/sys/rump/librump/rumpkern/lwproc.c,v
retrieving revision 1.35
diff -u -p -r1.35 lwproc.c
--- rump/librump/rumpkern/lwproc.c 18 Apr 2015 15:49:18 -0000 1.35
+++ rump/librump/rumpkern/lwproc.c 7 Jan 2016 23:56:08 -0000
@@ -117,7 +117,8 @@ lwproc_proc_free(struct proc *p)
chgproccnt(kauth_cred_getuid(cred), -1);
rump_proc_vfs_release(p);
- doexithooks(p);
+ doexithooks(p, EXITHOOK_BEFORE_CLOSE);
+ doexithooks(p, EXITHOOK_AFTER_CLOSE);
lim_free(p->p_limit);
pstatsfree(p->p_stats);
kauth_cred_free(p->p_cred);
Index: sys/systm.h
===================================================================
RCS file: /cvsroot/src/sys/sys/systm.h,v
retrieving revision 1.269
diff -u -p -r1.269 systm.h
--- sys/systm.h 29 Oct 2015 00:27:08 -0000 1.269
+++ sys/systm.h 7 Jan 2016 23:56:23 -0000
@@ -375,9 +375,11 @@ void doexechooks(struct proc *);
/*
* Exit hooks. Subsystems may want to do cleanup when a process exits.
*/
-void *exithook_establish(void (*)(struct proc *, void *), void *);
-void exithook_disestablish(void *);
-void doexithooks(struct proc *);
+#define EXITHOOK_BEFORE_CLOSE 0
+#define EXITHOOK_AFTER_CLOSE 1
+void *exithook_establish(void (*)(struct proc *, void *), void *, int);
+void exithook_disestablish(void *, int);
+void doexithooks(struct proc *, int);
/*
* Fork hooks. Subsystems may want to do special processing when a process
Home |
Main Index |
Thread Index |
Old Index