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:
Igor Mammedov 2016-07-20 11:54:03 +02:00 committed by Paolo Bonzini
parent 0b21757124
commit 056b68af77
5 changed files with 38 additions and 22 deletions

View file

@ -318,7 +318,7 @@ static void sigbus_handler(int signal)
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;
struct sigaction act, oldact;
@ -330,8 +330,9 @@ void os_mem_prealloc(int fd, char *area, size_t memory)
ret = sigaction(SIGBUS, &act, &oldact);
if (ret) {
perror("os_mem_prealloc: failed to install signal handler");
exit(1);
error_setg_errno(errp, errno,
"os_mem_prealloc: failed to install signal handler");
return;
}
/* unblock SIGBUS */
@ -340,9 +341,8 @@ void os_mem_prealloc(int fd, char *area, size_t memory)
pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
if (sigsetjmp(sigjump, 1)) {
fprintf(stderr, "os_mem_prealloc: Insufficient free host memory "
"pages available to allocate guest RAM\n");
exit(1);
error_setg(errp, "os_mem_prealloc: Insufficient free host memory "
"pages available to allocate guest RAM\n");
} else {
int i;
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++) {
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);
}
ret = sigaction(SIGBUS, &oldact, NULL);
if (ret) {
/* Terminate QEMU since it can't recover from error */
perror("os_mem_prealloc: failed to reinstall signal handler");
exit(1);
}
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
}