Page MenuHomeFreeBSD

D51338.id158587.diff
No OneTemporary

D51338.id158587.diff

diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -68,6 +68,7 @@
#include <sys/posix4.h>
#include <sys/racct.h>
#include <sys/resourcevar.h>
+#include <sys/rmlock.h>
#include <sys/sdt.h>
#include <sys/sbuf.h>
#include <sys/sleepqueue.h>
@@ -102,6 +103,14 @@
SDT_PROBE_DEFINE3(proc, , , signal__discard,
"struct thread *", "struct proc *", "int");
+static SLIST_HEAD(, coredumper) coredumpers = \
+ SLIST_HEAD_INITIALIZER(coredumpers);
+static struct rmlock coredump_rmlock;
+RM_SYSINIT(coredump_lock, &coredump_rmlock, "coredump_lock");
+
+static coredumper_handle_fn coredump_vnode;
+COREDUMP_HANDLER(coredump_vnode, NULL, coredump_vnode);
+
static int coredump(struct thread *);
static int killpg1(struct thread *td, int sig, int pgid, int all,
ksiginfo_t *ksi);
@@ -4131,16 +4140,15 @@
return (0);
}
-/*
- * Dump a process' core. The main routine does some
- * policy checking, and creates the name of the coredump;
- * then it passes on a vnode and a size limit to the process-specific
- * coredump routine if there is one; if there _is not_ one, it returns
- * ENOSYS; otherwise it returns the error from the process-specific routine.
+ /*
+ * The vnode dumper is the traditional coredump handler. Our policy and limits
+ * are generally checked already, so it creates the coredump name and passes on
+ * a vnode and a size limit to the process-specific coredump routine if there is
+ * one. If there _is not_ one, it returns ENOSYS; otherwise it returns the
+ * error from the process-specific routine.
*/
-
static int
-coredump(struct thread *td)
+coredump_vnode(struct thread *td, off_t limit)
{
struct proc *p = td->td_proc;
struct ucred *cred = td->td_ucred;
@@ -4153,33 +4161,9 @@
int error, error1, jid, locked, ppid, sig;
char *name; /* name of corefile */
void *rl_cookie;
- off_t limit;
char *fullpath, *freepath = NULL;
struct sbuf *sb;
- PROC_LOCK_ASSERT(p, MA_OWNED);
- MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
-
- if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) ||
- (p->p_flag2 & P2_NOTRACE) != 0) {
- PROC_UNLOCK(p);
- return (EFAULT);
- }
-
- /*
- * Note that the bulk of limit checking is done after
- * the corefile is created. The exception is if the limit
- * for corefiles is 0, in which case we don't bother
- * creating the corefile at all. This layout means that
- * a corefile is truncated instead of not being created,
- * if it is larger than the limit.
- */
- limit = (off_t)lim_cur(td, RLIMIT_CORE);
- if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) {
- PROC_UNLOCK(p);
- return (EFBIG);
- }
-
ppid = p->p_oppid;
sig = p->p_sig;
jid = p->p_ucred->cr_prison->pr_id;
@@ -4293,6 +4277,107 @@
return (error);
}
+void
+coredumper_register(struct coredumper *cd)
+{
+
+ rm_wlock(&coredump_rmlock);
+ SLIST_INSERT_HEAD(&coredumpers, cd, cd_entry);
+ rm_wunlock(&coredump_rmlock);
+}
+
+void
+coredumper_unregister(struct coredumper *cd)
+{
+
+ rm_wlock(&coredump_rmlock);
+ SLIST_REMOVE(&coredumpers, cd, coredumper, cd_entry);
+ rm_wunlock(&coredump_rmlock);
+}
+
+/*
+ * Dump a process' core. The main routine does some policy checking, then does
+ * a search for an appropriate coredumper to use. It is expected that the
+ * dumper implementations will call into the process images' dumper routines
+ * if there is one, and return ENOSYS if there is not. We don't handle the
+ * latter bit here in case one wants to add a pluggable coredumper that can
+ * encode a dump of those processes in some other way that's helpful to them.
+ *
+ * By default, we will use coredump_vnode() above if a custom coredump module
+ * has not been loaded.
+ */
+static int
+coredump(struct thread *td)
+{
+ struct coredumper *iter, *chosen;
+ struct proc *p = td->td_proc;
+ struct rm_priotracker tracker;
+ off_t limit;
+ int error, priority;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
+
+ if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) ||
+ (p->p_flag2 & P2_NOTRACE) != 0) {
+ PROC_UNLOCK(p);
+ return (EFAULT);
+ }
+
+ /*
+ * Note that the bulk of limit checking is done after
+ * the corefile is created. The exception is if the limit
+ * for corefiles is 0, in which case we don't bother
+ * creating the corefile at all. This layout means that
+ * a corefile is truncated instead of not being created,
+ * if it is larger than the limit.
+ */
+ limit = (off_t)lim_cur(td, RLIMIT_CORE);
+ if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) {
+ PROC_UNLOCK(p);
+ return (EFBIG);
+ }
+
+ rm_rlock(&coredump_rmlock, &tracker);
+ priority = -1;
+ chosen = NULL;
+ SLIST_FOREACH(iter, &coredumpers, cd_entry) {
+ if (iter->cd_probe == NULL) {
+ /*
+ * If we haven't found anything of a higher priority
+ * yet, we'll call this a GENERIC. Ideally, we want
+ * coredumper modules to include a probe function.
+ */
+ if (priority < 0) {
+ priority = COREDUMPER_GENERIC;
+ chosen = iter;
+ }
+
+ continue;
+ }
+
+ error = (*iter->cd_probe)(td);
+ if (error < 0)
+ continue;
+
+ /*
+ * Higher priority than previous options.
+ */
+ if (error > priority) {
+ priority = error;
+ chosen = iter;
+ }
+ }
+ rm_runlock(&coredump_rmlock, &tracker);
+
+ /* Currently, we always have the vnode dumper built in. */
+ MPASS(chosen != NULL);
+ error = ((*chosen->cd_handle)(td, limit));
+ PROC_LOCK_ASSERT(p, MA_NOTOWNED);
+
+ return (error);
+}
+
/*
* Nonexistent system call-- signal process (may want to handle it). Flag
* error in case process won't see signal immediately (blocked or ignored).
diff --git a/sys/sys/exec.h b/sys/sys/exec.h
--- a/sys/sys/exec.h
+++ b/sys/sys/exec.h
@@ -38,6 +38,7 @@
#define _SYS_EXEC_H_
#include <sys/_uio.h>
+#include <sys/queue.h>
/*
* Before ps_args existed, the following structure, found at the top of
@@ -90,6 +91,45 @@
struct compressor *comp;
};
+typedef int coredumper_probe_fn(struct thread *);
+/*
+ * Some arbitrary values for coredumper probes to return. The highest priority
+ * we can find wins. It's somewhat expected that a coredumper may want to bid
+ * differently based on the process in question. Note that probe functions will
+ * be called with the proc lock held, so they must not sleep.
+ */
+#define COREDUMPER_NOMATCH (-1) /* Decline to touch it */
+#define COREDUMPER_GENERIC (0) /* I handle coredumps */
+#define COREDUMPER_SPECIAL (50) /* Special handler */
+#define COREDUMPER_HIGH_PRIORITY (100) /* High-priority handler */
+
+/*
+ * The handle functions will be called with the proc lock held, and should
+ * return with the proc lock dropped.
+ */
+typedef int coredumper_handle_fn(struct thread *, off_t);
+
+struct coredumper {
+ SLIST_ENTRY(coredumper) cd_entry;
+ const char *cd_name;
+ coredumper_probe_fn *cd_probe;
+ coredumper_handle_fn *cd_handle;
+};
+
+void coredumper_register(struct coredumper *);
+void coredumper_unregister(struct coredumper *);
+
+#define COREDUMP_HANDLER(name, probe, handle) \
+ static struct coredumper name##_coredumper = { \
+ .cd_name = #name, \
+ .cd_probe = probe, \
+ .cd_handle = handle, \
+ }; \
+ SYSINIT(name##_register, SI_SUB_EXEC, SI_ORDER_ANY, \
+ coredumper_register, &name##_coredumper); \
+ SYSUNINIT(name##_unregister, SI_SUB_EXEC, SI_ORDER_ANY, \
+ coredumper_unregister, &name##_coredumper); \
+
struct image_params;
struct execsw {

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 9, 9:33 AM (8 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28563885
Default Alt Text
D51338.id158587.diff (7 KB)

Event Timeline