summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Tu <u9012063@gmail.com>2020-03-23 07:44:48 -0700
committerWilliam Tu <u9012063@gmail.com>2020-03-23 09:43:06 -0700
commitecd4a8fcdff2ebf35cdb36355167d34e99df6dd5 (patch)
treecd8b56bce4e2543e26bc403d711d1a0928b2cd7a
parentc59922767ea3812763686613444a342e5daa67f7 (diff)
downloadopenvswitch-ecd4a8fcdff2ebf35cdb36355167d34e99df6dd5.tar.gz
fatal-signal: Log backtrace when no monitor daemon.
Currently the backtrace logging is only available when monitor daemon is running. This patch enables backtrace logging when no monitor daemon exists. At signal handling context, it detects whether monitor daemon exists. If not, write directly the backtrace to the vlog fd. Note that using VLOG_* macro doesn't work due to it's buffer I/O, so this patch directly issue write() syscall to the file descriptor. For some system we stop using monitor daemon and use systemd to monitor ovs-vswitchd, thus need this patch. Example of ovs-vswitchd.log (note that there is no timestamp printed): 2020-03-23T14:42:12.949Z|00049|memory|INFO|175332 kB peak resident 2020-03-23T14:42:12.949Z|00050|memory|INFO|handlers:2 ports:3 reva SIGSEGV detected, backtrace: 0x0000000000486969 <fatal_signal_handler+0x49> 0x00007f7f5e57f4b0 <killpg+0x40> 0x000000000047daa8 <pmd_thread_main+0x238> 0x0000000000504edd <ovsthread_wrapper+0x7d> 0x00007f7f5f0476ba <start_thread+0xca> 0x00007f7f5e65141d <clone+0x6d> 0x0000000000000000 <+0x0> Acked-by: Ben Pfaff <blp@ovn.org> Signed-off-by: William Tu <u9012063@gmail.com>
-rw-r--r--include/openvswitch/vlog.h3
-rw-r--r--lib/daemon-private.h1
-rw-r--r--lib/daemon-unix.c2
-rw-r--r--lib/fatal-signal.c27
-rw-r--r--lib/vlog.c6
5 files changed, 37 insertions, 2 deletions
diff --git a/include/openvswitch/vlog.h b/include/openvswitch/vlog.h
index 19da4ab62..476bf3d6d 100644
--- a/include/openvswitch/vlog.h
+++ b/include/openvswitch/vlog.h
@@ -143,6 +143,9 @@ void vlog_set_syslog_method(const char *method);
/* Configure syslog target. */
void vlog_set_syslog_target(const char *target);
+/* Return the log_fd. */
+int vlog_get_fd(void);
+
/* Initialization. */
void vlog_init(void);
void vlog_enable_async(void);
diff --git a/lib/daemon-private.h b/lib/daemon-private.h
index 4e0667601..2b90e0042 100644
--- a/lib/daemon-private.h
+++ b/lib/daemon-private.h
@@ -20,6 +20,7 @@
extern bool detach;
extern char *pidfile;
extern int daemonize_fd;
+extern bool monitor;
char *make_pidfile_name(const char *name);
diff --git a/lib/daemon-unix.c b/lib/daemon-unix.c
index 6b2a5b9bd..ae59ecf2c 100644
--- a/lib/daemon-unix.c
+++ b/lib/daemon-unix.c
@@ -80,7 +80,7 @@ int daemonize_fd = -1;
/* --monitor: Should a supervisory process monitor the daemon and restart it if
* it dies due to an error signal? */
-static bool monitor;
+bool monitor;
/* --user: Only root can use this option. Switch to new uid:gid after
* initially running as root. */
diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c
index ba7f5bfd3..4965c1ae8 100644
--- a/lib/fatal-signal.c
+++ b/lib/fatal-signal.c
@@ -187,7 +187,32 @@ send_backtrace_to_monitor(void) {
dep++;
}
- ignore(write(daemonize_fd, unw_bt, dep * sizeof(struct unw_backtrace)));
+ if (monitor) {
+ ignore(write(daemonize_fd, unw_bt,
+ dep * sizeof(struct unw_backtrace)));
+ } else {
+ /* Since there is no monitor daemon running, write backtrace
+ * in current process. This is not asyn-signal-safe due to
+ * use of snprintf().
+ */
+ char str[] = "SIGSEGV detected, backtrace:\n";
+
+ if (vlog_get_fd() < 0) {
+ return;
+ }
+
+ ignore(write(vlog_get_fd(), str, strlen(str)));
+
+ for (int i = 0; i < dep; i++) {
+ char line[64];
+
+ snprintf(line, 64, "0x%016"PRIxPTR" <%s+0x%"PRIxPTR">\n",
+ unw_bt[i].ip,
+ unw_bt[i].func,
+ unw_bt[i].offset);
+ ignore(write(vlog_get_fd(), line, strlen(line)));
+ }
+ }
}
#else
static inline void
diff --git a/lib/vlog.c b/lib/vlog.c
index 559943d87..502b33fc8 100644
--- a/lib/vlog.c
+++ b/lib/vlog.c
@@ -612,6 +612,12 @@ vlog_set_syslog_target(const char *target)
ovs_rwlock_unlock(&pattern_rwlock);
}
+int
+vlog_get_fd(void)
+{
+ return log_fd;
+}
+
/* Returns 'false' if 'facility' is not a valid string. If 'facility'
* is a valid string, sets 'value' with the integer value of 'facility'
* and returns 'true'. */