static void *file_ram_alloc(RAMBlock *block, ram_addr_t memory, const char *path) { char *filename; char *sanitized_name; char *c; void *area; int fd; unsigned long hpagesize; hpagesize = gethugepagesize(path); if (!hpagesize) { return NULL; } if (memory < hpagesize) { return NULL; } if (kvm_enabled() && !kvm_has_sync_mmu()) { fprintf(stderr, "host lacks kvm mmu notifiers, -mem-path unsupported\n"); return NULL; } /* Make name safe to use with mkstemp by replacing '/' with '_'. */ sanitized_name = g_strdup(block->mr->name); for (c = sanitized_name; *c != '\0'; c++) { if (*c == '/') *c = '_'; } filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path, sanitized_name); g_free(sanitized_name); fd = mkstemp(filename); if (fd < 0) { perror("unable to create backing store for hugepages"); g_free(filename); return NULL; } unlink(filename); g_free(filename); memory = (memory+hpagesize-1) & ~(hpagesize-1); /* * ftruncate is not supported by hugetlbfs in older * hosts, so don't bother bailing out on errors. * If anything goes wrong with it under other filesystems, * mmap will fail. */ if (ftruncate(fd, memory)) perror("ftruncate"); area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (area == MAP_FAILED) { perror("file_ram_alloc: can't mmap RAM pages"); close(fd); return (NULL); } 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)-1; 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); } block->fd = fd; return area; }