fix qemu exit on memory hotplug when allocation fails at prealloc time
When adding hostmem backend at runtime, QEMU might exit with error: "os_mem_prealloc: Insufficient free host memory pages available to allocate guest RAM" It happens due to os_mem_prealloc() not handling errors gracefully. Fix it by passing errp argument so that os_mem_prealloc() could report error to callers and undo performed allocation when os_mem_prealloc() fails. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Message-Id: <1469008443-72059-1-git-send-email-imammedo@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
0b21757124
commit
056b68af77
@ -203,6 +203,7 @@ static bool host_memory_backend_get_prealloc(Object *obj, Error **errp)
|
|||||||
static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
Error *local_err = NULL;
|
||||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||||
|
|
||||||
if (backend->force_prealloc) {
|
if (backend->force_prealloc) {
|
||||||
@ -223,7 +224,11 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
|||||||
void *ptr = memory_region_get_ram_ptr(&backend->mr);
|
void *ptr = memory_region_get_ram_ptr(&backend->mr);
|
||||||
uint64_t sz = memory_region_size(&backend->mr);
|
uint64_t sz = memory_region_size(&backend->mr);
|
||||||
|
|
||||||
os_mem_prealloc(fd, ptr, sz);
|
os_mem_prealloc(fd, ptr, sz, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
backend->prealloc = true;
|
backend->prealloc = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,8 +291,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
|
|||||||
if (bc->alloc) {
|
if (bc->alloc) {
|
||||||
bc->alloc(backend, &local_err);
|
bc->alloc(backend, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
error_propagate(errp, local_err);
|
goto out;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = memory_region_get_ram_ptr(&backend->mr);
|
ptr = memory_region_get_ram_ptr(&backend->mr);
|
||||||
@ -343,9 +347,15 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
|
|||||||
* specified NUMA policy in place.
|
* specified NUMA policy in place.
|
||||||
*/
|
*/
|
||||||
if (backend->prealloc) {
|
if (backend->prealloc) {
|
||||||
os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz);
|
os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz,
|
||||||
|
&local_err);
|
||||||
|
if (local_err) {
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
10
exec.c
10
exec.c
@ -1226,7 +1226,7 @@ static void *file_ram_alloc(RAMBlock *block,
|
|||||||
char *filename;
|
char *filename;
|
||||||
char *sanitized_name;
|
char *sanitized_name;
|
||||||
char *c;
|
char *c;
|
||||||
void *area;
|
void *area = MAP_FAILED;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
int64_t page_size;
|
int64_t page_size;
|
||||||
|
|
||||||
@ -1314,13 +1314,19 @@ static void *file_ram_alloc(RAMBlock *block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mem_prealloc) {
|
if (mem_prealloc) {
|
||||||
os_mem_prealloc(fd, area, memory);
|
os_mem_prealloc(fd, area, memory, errp);
|
||||||
|
if (errp && *errp) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
block->fd = fd;
|
block->fd = fd;
|
||||||
return area;
|
return area;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
if (area != MAP_FAILED) {
|
||||||
|
qemu_ram_munmap(area, memory);
|
||||||
|
}
|
||||||
if (unlink_on_error) {
|
if (unlink_on_error) {
|
||||||
unlink(path);
|
unlink(path);
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,7 @@ unsigned long qemu_getauxval(unsigned long type);
|
|||||||
|
|
||||||
void qemu_set_tty_echo(int fd, bool echo);
|
void qemu_set_tty_echo(int fd, bool echo);
|
||||||
|
|
||||||
void os_mem_prealloc(int fd, char *area, size_t sz);
|
void os_mem_prealloc(int fd, char *area, size_t sz, Error **errp);
|
||||||
|
|
||||||
int qemu_read_password(char *buf, int buf_size);
|
int qemu_read_password(char *buf, int buf_size);
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ static void sigbus_handler(int signal)
|
|||||||
siglongjmp(sigjump, 1);
|
siglongjmp(sigjump, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void os_mem_prealloc(int fd, char *area, size_t memory)
|
void os_mem_prealloc(int fd, char *area, size_t memory, Error **errp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct sigaction act, oldact;
|
struct sigaction act, oldact;
|
||||||
@ -330,8 +330,9 @@ void os_mem_prealloc(int fd, char *area, size_t memory)
|
|||||||
|
|
||||||
ret = sigaction(SIGBUS, &act, &oldact);
|
ret = sigaction(SIGBUS, &act, &oldact);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
perror("os_mem_prealloc: failed to install signal handler");
|
error_setg_errno(errp, errno,
|
||||||
exit(1);
|
"os_mem_prealloc: failed to install signal handler");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unblock SIGBUS */
|
/* unblock SIGBUS */
|
||||||
@ -340,9 +341,8 @@ void os_mem_prealloc(int fd, char *area, size_t memory)
|
|||||||
pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
|
pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
|
||||||
|
|
||||||
if (sigsetjmp(sigjump, 1)) {
|
if (sigsetjmp(sigjump, 1)) {
|
||||||
fprintf(stderr, "os_mem_prealloc: Insufficient free host memory "
|
error_setg(errp, "os_mem_prealloc: Insufficient free host memory "
|
||||||
"pages available to allocate guest RAM\n");
|
"pages available to allocate guest RAM\n");
|
||||||
exit(1);
|
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
size_t hpagesize = qemu_fd_getpagesize(fd);
|
size_t hpagesize = qemu_fd_getpagesize(fd);
|
||||||
@ -352,15 +352,15 @@ void os_mem_prealloc(int fd, char *area, size_t memory)
|
|||||||
for (i = 0; i < numpages; i++) {
|
for (i = 0; i < numpages; i++) {
|
||||||
memset(area + (hpagesize * i), 0, 1);
|
memset(area + (hpagesize * i), 0, 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = sigaction(SIGBUS, &oldact, NULL);
|
ret = sigaction(SIGBUS, &oldact, NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
/* 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");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -539,7 +539,7 @@ int getpagesize(void)
|
|||||||
return system_info.dwPageSize;
|
return system_info.dwPageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void os_mem_prealloc(int fd, char *area, size_t memory)
|
void os_mem_prealloc(int fd, char *area, size_t memory, Error **errp)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
size_t pagesize = getpagesize();
|
size_t pagesize = getpagesize();
|
||||||
|
Loading…
Reference in New Issue
Block a user