exec: split file_ram_alloc()

Move file opening part in a seperate function, file_ram_open(). This
allows for reuse of file_ram_alloc() with a given fd.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20170602141229.15326-3-marcandre.lureau@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Marc-André Lureau 2017-06-02 18:12:22 +04:00 committed by Paolo Bonzini
parent e45e7ae281
commit 8d37b030fe

83
exec.c
View File

@ -1482,19 +1482,17 @@ static int64_t get_file_size(int fd)
return size; return size;
} }
static void *file_ram_alloc(RAMBlock *block, static int file_ram_open(const char *path,
ram_addr_t memory, const char *region_name,
const char *path, bool *created,
Error **errp) Error **errp)
{ {
bool unlink_on_error = false;
char *filename; char *filename;
char *sanitized_name; char *sanitized_name;
char *c; char *c;
void *area = MAP_FAILED;
int fd = -1; int fd = -1;
int64_t file_size;
*created = false;
for (;;) { for (;;) {
fd = open(path, O_RDWR); fd = open(path, O_RDWR);
if (fd >= 0) { if (fd >= 0) {
@ -1505,13 +1503,13 @@ static void *file_ram_alloc(RAMBlock *block,
/* @path names a file that doesn't exist, create it */ /* @path names a file that doesn't exist, create it */
fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644); fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644);
if (fd >= 0) { if (fd >= 0) {
unlink_on_error = true; *created = true;
break; break;
} }
} else if (errno == EISDIR) { } else if (errno == EISDIR) {
/* @path names a directory, create a file there */ /* @path names a directory, create a file there */
/* Make name safe to use with mkstemp by replacing '/' with '_'. */ /* Make name safe to use with mkstemp by replacing '/' with '_'. */
sanitized_name = g_strdup(memory_region_name(block->mr)); sanitized_name = g_strdup(region_name);
for (c = sanitized_name; *c != '\0'; c++) { for (c = sanitized_name; *c != '\0'; c++) {
if (*c == '/') { if (*c == '/') {
*c = '_'; *c = '_';
@ -1534,7 +1532,7 @@ static void *file_ram_alloc(RAMBlock *block,
error_setg_errno(errp, errno, error_setg_errno(errp, errno,
"can't open backing store %s for guest RAM", "can't open backing store %s for guest RAM",
path); path);
goto error; return -1;
} }
/* /*
* Try again on EINTR and EEXIST. The latter happens when * Try again on EINTR and EEXIST. The latter happens when
@ -1542,6 +1540,17 @@ static void *file_ram_alloc(RAMBlock *block,
*/ */
} }
return fd;
}
static void *file_ram_alloc(RAMBlock *block,
ram_addr_t memory,
int fd,
bool truncate,
Error **errp)
{
void *area;
block->page_size = qemu_fd_getpagesize(fd); block->page_size = qemu_fd_getpagesize(fd);
block->mr->align = block->page_size; block->mr->align = block->page_size;
#if defined(__s390x__) #if defined(__s390x__)
@ -1550,20 +1559,11 @@ static void *file_ram_alloc(RAMBlock *block,
} }
#endif #endif
file_size = get_file_size(fd);
if (memory < block->page_size) { if (memory < block->page_size) {
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to " error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
"or larger than page size 0x%zx", "or larger than page size 0x%zx",
memory, block->page_size); memory, block->page_size);
goto error; return NULL;
}
if (file_size > 0 && file_size < memory) {
error_setg(errp, "backing store %s size 0x%" PRIx64
" does not match 'size' option 0x" RAM_ADDR_FMT,
path, file_size, memory);
goto error;
} }
memory = ROUND_UP(memory, block->page_size); memory = ROUND_UP(memory, block->page_size);
@ -1582,7 +1582,7 @@ static void *file_ram_alloc(RAMBlock *block,
* those labels. Therefore, extending the non-empty backend file * those labels. Therefore, extending the non-empty backend file
* is disabled as well. * is disabled as well.
*/ */
if (!file_size && ftruncate(fd, memory)) { if (truncate && ftruncate(fd, memory)) {
perror("ftruncate"); perror("ftruncate");
} }
@ -1591,30 +1591,19 @@ static void *file_ram_alloc(RAMBlock *block,
if (area == MAP_FAILED) { if (area == MAP_FAILED) {
error_setg_errno(errp, errno, error_setg_errno(errp, errno,
"unable to map backing store for guest RAM"); "unable to map backing store for guest RAM");
goto error; return NULL;
} }
if (mem_prealloc) { if (mem_prealloc) {
os_mem_prealloc(fd, area, memory, smp_cpus, errp); os_mem_prealloc(fd, area, memory, smp_cpus, errp);
if (errp && *errp) { if (errp && *errp) {
goto error; qemu_ram_munmap(area, memory);
return NULL;
} }
} }
block->fd = fd; block->fd = fd;
return area; return area;
error:
if (area != MAP_FAILED) {
qemu_ram_munmap(area, memory);
}
if (unlink_on_error) {
unlink(path);
}
if (fd != -1) {
close(fd);
}
return NULL;
} }
#endif #endif
@ -1931,6 +1920,9 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
{ {
RAMBlock *new_block; RAMBlock *new_block;
Error *local_err = NULL; Error *local_err = NULL;
int fd;
bool created;
int64_t file_size;
if (xen_enabled()) { if (xen_enabled()) {
error_setg(errp, "-mem-path not supported with Xen"); error_setg(errp, "-mem-path not supported with Xen");
@ -1954,15 +1946,32 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
return NULL; return NULL;
} }
fd = file_ram_open(mem_path, memory_region_name(mr), &created, errp);
if (fd < 0) {
return NULL;
}
size = HOST_PAGE_ALIGN(size); size = HOST_PAGE_ALIGN(size);
file_size = get_file_size(fd);
if (file_size > 0 && file_size < size) {
error_setg(errp, "backing store %s size 0x%" PRIx64
" does not match 'size' option 0x" RAM_ADDR_FMT,
mem_path, file_size, size);
close(fd);
return NULL;
}
new_block = g_malloc0(sizeof(*new_block)); new_block = g_malloc0(sizeof(*new_block));
new_block->mr = mr; new_block->mr = mr;
new_block->used_length = size; new_block->used_length = size;
new_block->max_length = size; new_block->max_length = size;
new_block->flags = share ? RAM_SHARED : 0; new_block->flags = share ? RAM_SHARED : 0;
new_block->host = file_ram_alloc(new_block, size, new_block->host = file_ram_alloc(new_block, size, fd, !file_size, errp);
mem_path, errp);
if (!new_block->host) { if (!new_block->host) {
if (created) {
unlink(mem_path);
}
close(fd);
g_free(new_block); g_free(new_block);
return NULL; return NULL;
} }