physmem: qemu_ram_alloc_from_fd extensions

Extend qemu_ram_alloc_from_fd to support resizable ram, and define
qemu_ram_resize_cb to clean up the API.

Add a grow parameter to extend the file if necessary.  However, if
grow is false, a zero-sized file is always extended.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Link: https://lore.kernel.org/r/1736967650-129648-4-git-send-email-steven.sistare@oracle.com
Signed-off-by: Fabiano Rosas <farosas@suse.de>
This commit is contained in:
Steve Sistare 2025-01-15 11:00:29 -08:00 committed by Fabiano Rosas
parent 719168fba7
commit 3ec0214816
3 changed files with 31 additions and 21 deletions

View file

@ -111,23 +111,30 @@ long qemu_maxrampagesize(void);
* *
* Parameters: * Parameters:
* @size: the size in bytes of the ram block * @size: the size in bytes of the ram block
* @max_size: the maximum size of the block after resizing
* @mr: the memory region where the ram block is * @mr: the memory region where the ram block is
* @resized: callback after calls to qemu_ram_resize
* @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM, * @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
* RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY, * RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
* RAM_READONLY_FD, RAM_GUEST_MEMFD * RAM_READONLY_FD, RAM_GUEST_MEMFD
* @mem_path or @fd: specify the backing file or device * @mem_path or @fd: specify the backing file or device
* @offset: Offset into target file * @offset: Offset into target file
* @grow: extend file if necessary (but an empty file is always extended).
* @errp: pointer to Error*, to store an error if it happens * @errp: pointer to Error*, to store an error if it happens
* *
* Return: * Return:
* On success, return a pointer to the ram block. * On success, return a pointer to the ram block.
* On failure, return NULL. * On failure, return NULL.
*/ */
typedef void (*qemu_ram_resize_cb)(const char *, uint64_t length, void *host);
RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr, RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
uint32_t ram_flags, const char *mem_path, uint32_t ram_flags, const char *mem_path,
off_t offset, Error **errp); off_t offset, Error **errp);
RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, ram_addr_t max_size,
qemu_ram_resize_cb resized, MemoryRegion *mr,
uint32_t ram_flags, int fd, off_t offset, uint32_t ram_flags, int fd, off_t offset,
bool grow,
Error **errp); Error **errp);
RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
@ -135,9 +142,7 @@ RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags, MemoryRegion *mr, RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags, MemoryRegion *mr,
Error **errp); Error **errp);
RAMBlock *qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t max_size, RAMBlock *qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t max_size,
void (*resized)(const char*, qemu_ram_resize_cb resized,
uint64_t length,
void *host),
MemoryRegion *mr, Error **errp); MemoryRegion *mr, Error **errp);
void qemu_ram_free(RAMBlock *block); void qemu_ram_free(RAMBlock *block);

View file

@ -1680,8 +1680,8 @@ bool memory_region_init_ram_from_fd(MemoryRegion *mr,
mr->readonly = !!(ram_flags & RAM_READONLY); mr->readonly = !!(ram_flags & RAM_READONLY);
mr->terminates = true; mr->terminates = true;
mr->destructor = memory_region_destructor_ram; mr->destructor = memory_region_destructor_ram;
mr->ram_block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, offset, mr->ram_block = qemu_ram_alloc_from_fd(size, size, NULL, mr, ram_flags, fd,
&err); offset, false, &err);
if (err) { if (err) {
mr->size = int128_zero(); mr->size = int128_zero();
object_unparent(OBJECT(mr)); object_unparent(OBJECT(mr));

View file

@ -1942,8 +1942,10 @@ out_free:
} }
#ifdef CONFIG_POSIX #ifdef CONFIG_POSIX
RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, ram_addr_t max_size,
qemu_ram_resize_cb resized, MemoryRegion *mr,
uint32_t ram_flags, int fd, off_t offset, uint32_t ram_flags, int fd, off_t offset,
bool grow,
Error **errp) Error **errp)
{ {
RAMBlock *new_block; RAMBlock *new_block;
@ -1953,7 +1955,9 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
/* Just support these ram flags by now. */ /* Just support these ram flags by now. */
assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE | assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
RAM_PROTECTED | RAM_NAMED_FILE | RAM_READONLY | RAM_PROTECTED | RAM_NAMED_FILE | RAM_READONLY |
RAM_READONLY_FD | RAM_GUEST_MEMFD)) == 0); RAM_READONLY_FD | RAM_GUEST_MEMFD |
RAM_RESIZEABLE)) == 0);
assert(max_size >= 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");
@ -1968,13 +1972,15 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
size = TARGET_PAGE_ALIGN(size); size = TARGET_PAGE_ALIGN(size);
size = REAL_HOST_PAGE_ALIGN(size); size = REAL_HOST_PAGE_ALIGN(size);
max_size = TARGET_PAGE_ALIGN(max_size);
max_size = REAL_HOST_PAGE_ALIGN(max_size);
file_size = get_file_size(fd); file_size = get_file_size(fd);
if (file_size && file_size < offset + size) { if (file_size && file_size < offset + max_size && !grow) {
error_setg(errp, "%s backing store size 0x%" PRIx64 error_setg(errp, "%s backing store size 0x%" PRIx64
" is too small for 'size' option 0x" RAM_ADDR_FMT " is too small for 'size' option 0x" RAM_ADDR_FMT
" plus 'offset' option 0x%" PRIx64, " plus 'offset' option 0x%" PRIx64,
memory_region_name(mr), file_size, size, memory_region_name(mr), file_size, max_size,
(uint64_t)offset); (uint64_t)offset);
return NULL; return NULL;
} }
@ -1990,11 +1996,13 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
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 = max_size;
new_block->resized = resized;
new_block->flags = ram_flags; new_block->flags = ram_flags;
new_block->guest_memfd = -1; new_block->guest_memfd = -1;
new_block->host = file_ram_alloc(new_block, size, fd, !file_size, offset, new_block->host = file_ram_alloc(new_block, max_size, fd,
errp); file_size < offset + max_size,
offset, errp);
if (!new_block->host) { if (!new_block->host) {
g_free(new_block); g_free(new_block);
return NULL; return NULL;
@ -2046,7 +2054,8 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
return NULL; return NULL;
} }
block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, offset, errp); block = qemu_ram_alloc_from_fd(size, size, NULL, mr, ram_flags, fd, offset,
false, errp);
if (!block) { if (!block) {
if (created) { if (created) {
unlink(mem_path); unlink(mem_path);
@ -2061,9 +2070,7 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
static static
RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size, RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
void (*resized)(const char*, qemu_ram_resize_cb resized,
uint64_t length,
void *host),
void *host, uint32_t ram_flags, void *host, uint32_t ram_flags,
MemoryRegion *mr, Error **errp) MemoryRegion *mr, Error **errp)
{ {
@ -2115,10 +2122,8 @@ RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags,
} }
RAMBlock *qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t maxsz, RAMBlock *qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t maxsz,
void (*resized)(const char*, qemu_ram_resize_cb resized,
uint64_t length, MemoryRegion *mr, Error **errp)
void *host),
MemoryRegion *mr, Error **errp)
{ {
return qemu_ram_alloc_internal(size, maxsz, resized, NULL, return qemu_ram_alloc_internal(size, maxsz, resized, NULL,
RAM_RESIZEABLE, mr, errp); RAM_RESIZEABLE, mr, errp);