@@ -1012,13 +1012,6 @@ static long gethugepagesize(const char *path)
return fs.f_bsize;
}
-static sigjmp_buf sigjump;
-
-static void sigbus_handler(int signal)
-{
- siglongjmp(sigjump, 1);
-}
-
static void *file_ram_alloc(RAMBlock *block,
ram_addr_t memory,
const char *path,
@@ -1088,42 +1081,7 @@ static void *file_ram_alloc(RAMBlock *block,
}
if (mem_prealloc) {
- int ret, i;
- struct sigaction act, oldact;
- sigset_t set, oldset;
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = &sigbus_handler;
- act.sa_flags = 0;
-
- ret = sigaction(SIGBUS, &act, &oldact);
- if (ret) {
- perror("file_ram_alloc: failed to install signal handler");
- exit(1);
- }
-
- /* unblock SIGBUS */
- sigemptyset(&set);
- sigaddset(&set, SIGBUS);
- pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
-
- if (sigsetjmp(sigjump, 1)) {
- fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n");
- exit(1);
- }
-
- /* MAP_POPULATE silently ignores failures */
- for (i = 0; i < (memory/hpagesize); i++) {
- memset(area + (hpagesize*i), 0, 1);
- }
-
- ret = sigaction(SIGBUS, &oldact, NULL);
- if (ret) {
- perror("file_ram_alloc: failed to reinstall signal handler");
- exit(1);
- }
-
- pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ os_mem_prealloc(fd, area, memory);
}
block->fd = fd;
@@ -251,4 +251,6 @@ void qemu_init_auxval(char **envp);
void qemu_set_tty_echo(int fd, bool echo);
+void os_mem_prealloc(int fd, char *area, size_t sz);
+
#endif
@@ -46,6 +46,7 @@ extern int daemon(int, int);
#else
# define QEMU_VMALLOC_ALIGN getpagesize()
#endif
+#define HUGETLBFS_MAGIC 0x958458f6
#include <termios.h>
#include <unistd.h>
@@ -58,9 +59,12 @@ extern int daemon(int, int);
#include "qemu/sockets.h"
#include <sys/mman.h>
#include <libgen.h>
+#include <setjmp.h>
+#include <sys/signal.h>
#ifdef CONFIG_LINUX
#include <sys/syscall.h>
+#include <sys/vfs.h>
#endif
#ifdef __FreeBSD__
@@ -332,3 +336,72 @@ char *qemu_get_exec_dir(void)
{
return g_strdup(exec_dir);
}
+
+static sigjmp_buf sigjump;
+
+static void sigbus_handler(int signal)
+{
+ siglongjmp(sigjump, 1);
+}
+
+static size_t fd_getpagesize(int fd)
+{
+#ifdef CONFIG_LINUX
+ struct statfs fs;
+ int ret;
+
+ if (fd != -1) {
+ do {
+ ret = fstatfs(fd, &fs);
+ } while (ret != 0 && errno == EINTR);
+
+ if (ret == 0 && fs.f_type == HUGETLBFS_MAGIC) {
+ return fs.f_bsize;
+ }
+ }
+#endif
+
+ return getpagesize();
+}
+
+void os_mem_prealloc(int fd, char *area, size_t memory)
+{
+ int ret, i;
+ struct sigaction act, oldact;
+ sigset_t set, oldset;
+ size_t hpagesize = fd_getpagesize(fd);
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = &sigbus_handler;
+ act.sa_flags = 0;
+
+ ret = sigaction(SIGBUS, &act, &oldact);
+ if (ret) {
+ perror("file_ram_alloc: failed to install signal handler");
+ exit(1);
+ }
+
+ /* unblock SIGBUS */
+ sigemptyset(&set);
+ sigaddset(&set, SIGBUS);
+ pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
+
+ if (sigsetjmp(sigjump, 1)) {
+ fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n");
+ exit(1);
+ }
+
+ /* MAP_POPULATE silently ignores failures */
+ memory = (memory + hpagesize - 1) & -hpagesize;
+ for (i = 0; i < (memory/hpagesize); i++) {
+ memset(area + (hpagesize*i), 0, 1);
+ }
+
+ ret = sigaction(SIGBUS, &oldact, NULL);
+ if (ret) {
+ perror("file_ram_alloc: failed to reinstall signal handler");
+ exit(1);
+ }
+
+ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+}