|
@@ -35,6 +35,7 @@
|
|
#include "sysemu/sysemu.h"
|
|
#include "sysemu/sysemu.h"
|
|
#include "trace.h"
|
|
#include "trace.h"
|
|
#include "qapi/error.h"
|
|
#include "qapi/error.h"
|
|
|
|
+#include "qemu/error-report.h"
|
|
#include "qemu/sockets.h"
|
|
#include "qemu/sockets.h"
|
|
#include "qemu/thread.h"
|
|
#include "qemu/thread.h"
|
|
#include <libgen.h>
|
|
#include <libgen.h>
|
|
@@ -95,6 +96,7 @@ typedef struct MemsetThread MemsetThread;
|
|
|
|
|
|
/* used by sigbus_handler() */
|
|
/* used by sigbus_handler() */
|
|
static MemsetContext *sigbus_memset_context;
|
|
static MemsetContext *sigbus_memset_context;
|
|
|
|
+struct sigaction sigbus_oldact;
|
|
static QemuMutex sigbus_mutex;
|
|
static QemuMutex sigbus_mutex;
|
|
|
|
|
|
static QemuMutex page_mutex;
|
|
static QemuMutex page_mutex;
|
|
@@ -446,7 +448,11 @@ const char *qemu_get_exec_dir(void)
|
|
return exec_dir;
|
|
return exec_dir;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef CONFIG_LINUX
|
|
|
|
+static void sigbus_handler(int signal, siginfo_t *siginfo, void *ctx)
|
|
|
|
+#else /* CONFIG_LINUX */
|
|
static void sigbus_handler(int signal)
|
|
static void sigbus_handler(int signal)
|
|
|
|
+#endif /* CONFIG_LINUX */
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
|
|
|
|
@@ -459,6 +465,26 @@ static void sigbus_handler(int signal)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_LINUX
|
|
|
|
+ /*
|
|
|
|
+ * We assume that the MCE SIGBUS handler could have been registered. We
|
|
|
|
+ * should never receive BUS_MCEERR_AO on any of our threads, but only on
|
|
|
|
+ * the main thread registered for PR_MCE_KILL_EARLY. Further, we should not
|
|
|
|
+ * receive BUS_MCEERR_AR triggered by action of other threads on one of
|
|
|
|
+ * our threads. So, no need to check for unrelated SIGBUS when seeing one
|
|
|
|
+ * for our threads.
|
|
|
|
+ *
|
|
|
|
+ * We will forward to the MCE handler, which will either handle the SIGBUS
|
|
|
|
+ * or reinstall the default SIGBUS handler and reraise the SIGBUS. The
|
|
|
|
+ * default SIGBUS handler will crash the process, so we don't care.
|
|
|
|
+ */
|
|
|
|
+ if (sigbus_oldact.sa_flags & SA_SIGINFO) {
|
|
|
|
+ sigbus_oldact.sa_sigaction(signal, siginfo, ctx);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+#endif /* CONFIG_LINUX */
|
|
|
|
+ warn_report("os_mem_prealloc: unrelated SIGBUS detected and ignored");
|
|
}
|
|
}
|
|
|
|
|
|
static void *do_touch_pages(void *arg)
|
|
static void *do_touch_pages(void *arg)
|
|
@@ -628,10 +654,10 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
|
|
{
|
|
{
|
|
static gsize initialized;
|
|
static gsize initialized;
|
|
int ret;
|
|
int ret;
|
|
- struct sigaction act, oldact;
|
|
|
|
size_t hpagesize = qemu_fd_getpagesize(fd);
|
|
size_t hpagesize = qemu_fd_getpagesize(fd);
|
|
size_t numpages = DIV_ROUND_UP(memory, hpagesize);
|
|
size_t numpages = DIV_ROUND_UP(memory, hpagesize);
|
|
bool use_madv_populate_write;
|
|
bool use_madv_populate_write;
|
|
|
|
+ struct sigaction act;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Sense on every invocation, as MADV_POPULATE_WRITE cannot be used for
|
|
* Sense on every invocation, as MADV_POPULATE_WRITE cannot be used for
|
|
@@ -647,10 +673,15 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
|
|
|
|
|
|
qemu_mutex_lock(&sigbus_mutex);
|
|
qemu_mutex_lock(&sigbus_mutex);
|
|
memset(&act, 0, sizeof(act));
|
|
memset(&act, 0, sizeof(act));
|
|
|
|
+#ifdef CONFIG_LINUX
|
|
|
|
+ act.sa_sigaction = &sigbus_handler;
|
|
|
|
+ act.sa_flags = SA_SIGINFO;
|
|
|
|
+#else /* CONFIG_LINUX */
|
|
act.sa_handler = &sigbus_handler;
|
|
act.sa_handler = &sigbus_handler;
|
|
act.sa_flags = 0;
|
|
act.sa_flags = 0;
|
|
|
|
+#endif /* CONFIG_LINUX */
|
|
|
|
|
|
- ret = sigaction(SIGBUS, &act, &oldact);
|
|
|
|
|
|
+ ret = sigaction(SIGBUS, &act, &sigbus_oldact);
|
|
if (ret) {
|
|
if (ret) {
|
|
error_setg_errno(errp, errno,
|
|
error_setg_errno(errp, errno,
|
|
"os_mem_prealloc: failed to install signal handler");
|
|
"os_mem_prealloc: failed to install signal handler");
|
|
@@ -667,7 +698,7 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
|
|
}
|
|
}
|
|
|
|
|
|
if (!use_madv_populate_write) {
|
|
if (!use_madv_populate_write) {
|
|
- ret = sigaction(SIGBUS, &oldact, NULL);
|
|
|
|
|
|
+ ret = sigaction(SIGBUS, &sigbus_oldact, NULL);
|
|
if (ret) {
|
|
if (ret) {
|
|
/* Terminate QEMU since it can't recover from error */
|
|
/* Terminate QEMU since it can't recover from error */
|
|
perror("os_mem_prealloc: failed to reinstall signal handler");
|
|
perror("os_mem_prealloc: failed to reinstall signal handler");
|