diff options
Diffstat (limited to 'util/oslib-posix.c')
-rw-r--r-- | util/oslib-posix.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 8e9c770..1524ead 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -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("os_mem_prealloc: 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, "os_mem_prealloc: 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("os_mem_prealloc: failed to reinstall signal handler"); + exit(1); + } + + pthread_sigmask(SIG_SETMASK, &oldset, NULL); +} |