Skip to content

Commit

Permalink
Merge tag 'mem-next-pull-request' of https://gitlab.com/peterx/qemu i…
Browse files Browse the repository at this point in the history
…nto staging

Memory pull request for 10.0

v2 changelog:

- Fix Mac (and possibly some other) build issues for two patches
  - os: add an ability to lock memory on_fault
  - memory: pass MemTxAttrs to memory_access_is_direct()

List of features:

- William's fix on ram hole punching when with file offset
- Daniil's patchset to introduce mem-lock=on-fault
- William's hugetlb hwpoison fix for size report & remap
- David's series to allow qemu debug writes to MMIOs

# -----BEGIN PGP SIGNATURE-----
#
# iIgEABYKADAWIQS5GE3CDMRX2s990ak7X8zN86vXBgUCZ6zcQBIccGV0ZXJ4QHJl
# ZGhhdC5jb20ACgkQO1/MzfOr1wbL3wEAqx94NpB/tEEBj6WXE3uV9LqQ0GCTYmV+
# MbM51Vep8ksA/35yFn3ltM2yoSnUf9WJW6LXEEKhQlwswI0vChQERgkE
# =++O1
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 13 Feb 2025 01:37:04 HKT
# gpg:                using EDDSA key B9184DC20CC457DACF7DD1A93B5FCCCDF3ABD706
# gpg:                issuer "[email protected]"
# gpg: Good signature from "Peter Xu <[email protected]>" [full]
# gpg:                 aka "Peter Xu <[email protected]>" [full]
# Primary key fingerprint: B918 4DC2 0CC4 57DA CF7D  D1A9 3B5F CCCD F3AB D706

* tag 'mem-next-pull-request' of https://gitlab.com/peterx/qemu:
  overcommit: introduce mem-lock=on-fault
  system: introduce a new MlockState enum
  system/vl: extract overcommit option parsing into a helper
  os: add an ability to lock memory on_fault
  system/physmem: poisoned memory discard on reboot
  system/physmem: handle hugetlb correctly in qemu_ram_remap()
  physmem: teach cpu_memory_rw_debug() to write to more memory regions
  hmp: use cpu_get_phys_page_debug() in hmp_gva2gpa()
  memory: pass MemTxAttrs to memory_access_is_direct()
  physmem: disallow direct access to RAM DEVICE in address_space_write_rom()
  physmem: factor out direct access check into memory_region_supports_direct_access()
  physmem: factor out RAM/ROMD check in memory_access_is_direct()
  physmem: factor out memory_region_is_ram_device() check in memory_access_is_direct()
  system/physmem: take into account fd_offset for file fallocate

Signed-off-by: Stefan Hajnoczi <[email protected]>
  • Loading branch information
stefanhaRH committed Feb 19, 2025
2 parents e020929 + 13057e0 commit 7389992
Show file tree
Hide file tree
Showing 21 changed files with 229 additions and 98 deletions.
2 changes: 1 addition & 1 deletion accel/kvm/kvm-all.c
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ static void kvm_unpoison_all(void *param)

QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) {
QLIST_REMOVE(page, list);
qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE);
qemu_ram_remap(page->ram_addr);
g_free(page);
}
}
Expand Down
13 changes: 9 additions & 4 deletions hw/core/cpu-system.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,18 @@ hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
hwaddr paddr;

if (cc->sysemu_ops->get_phys_page_attrs_debug) {
return cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr, attrs);
paddr = cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr, attrs);
} else {
/* Fallback for CPUs which don't implement the _attrs_ hook */
*attrs = MEMTXATTRS_UNSPECIFIED;
paddr = cc->sysemu_ops->get_phys_page_debug(cpu, addr);
}
/* Fallback for CPUs which don't implement the _attrs_ hook */
*attrs = MEMTXATTRS_UNSPECIFIED;
return cc->sysemu_ops->get_phys_page_debug(cpu, addr);
/* Indicate that this is a debug access. */
attrs->debug = 1;
return paddr;
}

hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr)
Expand Down
2 changes: 1 addition & 1 deletion hw/core/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ ssize_t load_image_mr(const char *filename, MemoryRegion *mr)
{
ssize_t size;

if (!memory_access_is_direct(mr, false)) {
if (!memory_access_is_direct(mr, false, MEMTXATTRS_UNSPECIFIED)) {
/* Can only load an image into RAM or ROM */
return -1;
}
Expand Down
3 changes: 2 additions & 1 deletion hw/display/apple-gfx.m
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ static void apple_gfx_destroy_task(AppleGFXState *s, PGTask_t *task)
MEMTXATTRS_UNSPECIFIED);

if (!ram_region || ram_region_length < length ||
!memory_access_is_direct(ram_region, !read_only)) {
!memory_access_is_direct(ram_region, !read_only,
MEMTXATTRS_UNSPECIFIED)) {
return NULL;
}

Expand Down
2 changes: 1 addition & 1 deletion hw/remote/vfio-user-obj.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset,
int access_size;
uint64_t val;

if (memory_access_is_direct(mr, is_write)) {
if (memory_access_is_direct(mr, is_write, MEMTXATTRS_UNSPECIFIED)) {
/**
* Some devices expose a PCI expansion ROM, which could be buffer
* based as compared to other regions which are primarily based on
Expand Down
2 changes: 1 addition & 1 deletion hw/virtio/virtio-mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
return;
}

if (enable_mlock) {
if (should_mlock(mlock_state)) {
error_setg(errp, "Incompatible with mlock");
return;
}
Expand Down
2 changes: 1 addition & 1 deletion include/exec/cpu-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ typedef uintptr_t ram_addr_t;

/* memory API */

void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
void qemu_ram_remap(ram_addr_t addr);
/* This should not be used by devices. */
ram_addr_t qemu_ram_addr_from_host(void *ptr);
ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
Expand Down
5 changes: 4 additions & 1 deletion include/exec/memattrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ typedef struct MemTxAttrs {
* (see MEMTX_ACCESS_ERROR).
*/
unsigned int memory:1;
/* Debug access that can even write to ROM. */
unsigned int debug:1;
/* Requester ID (for MSI for example) */
unsigned int requester_id:16;

Expand All @@ -56,7 +58,8 @@ typedef struct MemTxAttrs {
* Bus masters which don't specify any attributes will get this
* (via the MEMTXATTRS_UNSPECIFIED constant), so that we can
* distinguish "all attributes deliberately clear" from
* "didn't specify" if necessary.
* "didn't specify" if necessary. "debug" can be set alongside
* "unspecified".
*/
bool unspecified;

Expand Down
35 changes: 27 additions & 8 deletions include/exec/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -2995,15 +2995,34 @@ MemTxResult address_space_write_cached_slow(MemoryRegionCache *cache,
int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr);
bool prepare_mmio_access(MemoryRegion *mr);

static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
static inline bool memory_region_supports_direct_access(MemoryRegion *mr)
{
if (is_write) {
return memory_region_is_ram(mr) && !mr->readonly &&
!mr->rom_device && !memory_region_is_ram_device(mr);
} else {
return (memory_region_is_ram(mr) && !memory_region_is_ram_device(mr)) ||
memory_region_is_romd(mr);
/* ROM DEVICE regions only allow direct access if in ROMD mode. */
if (memory_region_is_romd(mr)) {
return true;
}
if (!memory_region_is_ram(mr)) {
return false;
}
/*
* RAM DEVICE regions can be accessed directly using memcpy, but it might
* be MMIO and access using mempy can be wrong (e.g., using instructions not
* intended for MMIO access). So we treat this as IO.
*/
return !memory_region_is_ram_device(mr);
}

static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write,
MemTxAttrs attrs)
{
if (!memory_region_supports_direct_access(mr)) {
return false;
}
/* Debug access can write to ROM. */
if (is_write && !attrs.debug) {
return !mr->readonly && !mr->rom_device;
}
return true;
}

/**
Expand Down Expand Up @@ -3036,7 +3055,7 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr,
fv = address_space_to_flatview(as);
l = len;
mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
if (len == l && memory_access_is_direct(mr, false)) {
if (len == l && memory_access_is_direct(mr, false, attrs)) {
ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
memcpy(buf, ptr, len);
} else {
Expand Down
2 changes: 1 addition & 1 deletion include/system/os-posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ bool os_set_runas(const char *user_id);
void os_set_chroot(const char *path);
void os_setup_limits(void);
void os_setup_post(void);
int os_mlock(void);
int os_mlock(bool on_fault);

/**
* qemu_alloc_stack:
Expand Down
2 changes: 1 addition & 1 deletion include/system/os-win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ static inline bool is_daemonized(void)
return false;
}

static inline int os_mlock(void)
static inline int os_mlock(bool on_fault G_GNUC_UNUSED)
{
return -ENOSYS;
}
Expand Down
12 changes: 11 additions & 1 deletion include/system/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,20 @@ extern int display_opengl;
extern const char *keyboard_layout;
extern int old_param;
extern uint8_t *boot_splash_filedata;
extern bool enable_mlock;
extern bool enable_cpu_pm;
extern QEMUClockType rtc_clock;

typedef enum {
MLOCK_OFF = 0,
MLOCK_ON,
MLOCK_ON_FAULT,
} MlockState;

bool should_mlock(MlockState);
bool is_mlock_on_fault(MlockState);

extern MlockState mlock_state;

#define MAX_OPTION_ROMS 16
typedef struct QEMUOptionRom {
const char *name;
Expand Down
6 changes: 6 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2885,6 +2885,12 @@ config_host_data.set('HAVE_MLOCKALL', cc.links(gnu_source_prefix + '''
return mlockall(MCL_FUTURE);
}'''))

config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(gnu_source_prefix + '''
#include <sys/mman.h>
int main(void) {
return mlockall(MCL_FUTURE | MCL_ONFAULT);
}'''))

have_l2tpv3 = false
if get_option('l2tpv3').allowed() and have_system
have_l2tpv3 = cc.has_type('struct mmsghdr',
Expand Down
4 changes: 2 additions & 2 deletions migration/postcopy-ram.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,8 @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)
mis->have_fault_thread = false;
}

if (enable_mlock) {
if (os_mlock() < 0) {
if (should_mlock(mlock_state)) {
if (os_mlock(is_mlock_on_fault(mlock_state)) < 0) {
error_report("mlock: %s", strerror(errno));
/*
* It doesn't feel right to fail at this point, we have a valid
Expand Down
3 changes: 1 addition & 2 deletions monitor/hmp-cmds-target.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ void hmp_gpa2hva(Monitor *mon, const QDict *qdict)
void hmp_gva2gpa(Monitor *mon, const QDict *qdict)
{
target_ulong addr = qdict_get_int(qdict, "addr");
MemTxAttrs attrs;
CPUState *cs = mon_get_cpu(mon);
hwaddr gpa;

Expand All @@ -310,7 +309,7 @@ void hmp_gva2gpa(Monitor *mon, const QDict *qdict)
return;
}

gpa = cpu_get_phys_page_attrs_debug(cs, addr & TARGET_PAGE_MASK, &attrs);
gpa = cpu_get_phys_page_debug(cs, addr & TARGET_PAGE_MASK);
if (gpa == -1) {
monitor_printf(mon, "Unmapped\n");
} else {
Expand Down
15 changes: 13 additions & 2 deletions os-posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,18 +327,29 @@ void os_set_line_buffering(void)
setvbuf(stdout, NULL, _IOLBF, 0);
}

int os_mlock(void)
int os_mlock(bool on_fault)
{
#ifdef HAVE_MLOCKALL
int ret = 0;
int flags = MCL_CURRENT | MCL_FUTURE;

ret = mlockall(MCL_CURRENT | MCL_FUTURE);
if (on_fault) {
#ifdef HAVE_MLOCK_ONFAULT
flags |= MCL_ONFAULT;
#else
error_report("mlockall: on_fault not supported");
return -EINVAL;
#endif
}

ret = mlockall(flags);
if (ret < 0) {
error_report("mlockall: %s", strerror(errno));
}

return ret;
#else
(void)on_fault;
return -ENOSYS;
#endif
}
14 changes: 9 additions & 5 deletions qemu-options.hx
Original file line number Diff line number Diff line change
Expand Up @@ -4632,21 +4632,25 @@ SRST
ERST

DEF("overcommit", HAS_ARG, QEMU_OPTION_overcommit,
"-overcommit [mem-lock=on|off][cpu-pm=on|off]\n"
"-overcommit [mem-lock=on|off|on-fault][cpu-pm=on|off]\n"
" run qemu with overcommit hints\n"
" mem-lock=on|off controls memory lock support (default: off)\n"
" mem-lock=on|off|on-fault controls memory lock support (default: off)\n"
" cpu-pm=on|off controls cpu power management (default: off)\n",
QEMU_ARCH_ALL)
SRST
``-overcommit mem-lock=on|off``
``-overcommit mem-lock=on|off|on-fault``
\
``-overcommit cpu-pm=on|off``
Run qemu with hints about host resource overcommit. The default is
to assume that host overcommits all resources.
Locking qemu and guest memory can be enabled via ``mem-lock=on``
(disabled by default). This works when host memory is not
overcommitted and reduces the worst-case latency for guest.
or ``mem-lock=on-fault`` (disabled by default). This works when
host memory is not overcommitted and reduces the worst-case latency for
guest. The on-fault option is better for reducing the memory footprint
since it makes allocations lazy, but the pages still get locked in place
once faulted by the guest or QEMU. Note that the two options are mutually
exclusive.
Guest ability to manage power state of host cpus (increasing latency
for other processes on the same host cpu, but decreasing latency for
Expand Down
12 changes: 11 additions & 1 deletion system/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,20 @@
#include "system/cpus.h"
#include "system/system.h"

bool should_mlock(MlockState state)
{
return state == MLOCK_ON || state == MLOCK_ON_FAULT;
}

bool is_mlock_on_fault(MlockState state)
{
return state == MLOCK_ON_FAULT;
}

enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
int display_opengl;
const char* keyboard_layout;
bool enable_mlock;
MlockState mlock_state;
bool enable_cpu_pm;
int autostart = 1;
int vga_interface_type = VGA_NONE;
Expand Down
18 changes: 9 additions & 9 deletions system/memory_ldst.c.inc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, false, attrs);
if (l < 4 || !memory_access_is_direct(mr, false)) {
if (l < 4 || !memory_access_is_direct(mr, false, attrs)) {
release_lock |= prepare_mmio_access(mr);

/* I/O case */
Expand Down Expand Up @@ -103,7 +103,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, false, attrs);
if (l < 8 || !memory_access_is_direct(mr, false)) {
if (l < 8 || !memory_access_is_direct(mr, false, attrs)) {
release_lock |= prepare_mmio_access(mr);

/* I/O case */
Expand Down Expand Up @@ -170,7 +170,7 @@ uint8_t glue(address_space_ldub, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, false, attrs);
if (!memory_access_is_direct(mr, false)) {
if (!memory_access_is_direct(mr, false, attrs)) {
release_lock |= prepare_mmio_access(mr);

/* I/O case */
Expand Down Expand Up @@ -207,7 +207,7 @@ static inline uint16_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, false, attrs);
if (l < 2 || !memory_access_is_direct(mr, false)) {
if (l < 2 || !memory_access_is_direct(mr, false, attrs)) {
release_lock |= prepare_mmio_access(mr);

/* I/O case */
Expand Down Expand Up @@ -277,7 +277,7 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 4 || !memory_access_is_direct(mr, true)) {
if (l < 4 || !memory_access_is_direct(mr, true, attrs)) {
release_lock |= prepare_mmio_access(mr);

r = memory_region_dispatch_write(mr, addr1, val, MO_32, attrs);
Expand Down Expand Up @@ -314,7 +314,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 4 || !memory_access_is_direct(mr, true)) {
if (l < 4 || !memory_access_is_direct(mr, true, attrs)) {
release_lock |= prepare_mmio_access(mr);
r = memory_region_dispatch_write(mr, addr1, val,
MO_32 | devend_memop(endian), attrs);
Expand Down Expand Up @@ -377,7 +377,7 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (!memory_access_is_direct(mr, true)) {
if (!memory_access_is_direct(mr, true, attrs)) {
release_lock |= prepare_mmio_access(mr);
r = memory_region_dispatch_write(mr, addr1, val, MO_8, attrs);
} else {
Expand Down Expand Up @@ -410,7 +410,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 2 || !memory_access_is_direct(mr, true)) {
if (l < 2 || !memory_access_is_direct(mr, true, attrs)) {
release_lock |= prepare_mmio_access(mr);
r = memory_region_dispatch_write(mr, addr1, val,
MO_16 | devend_memop(endian), attrs);
Expand Down Expand Up @@ -474,7 +474,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,

RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true, attrs);
if (l < 8 || !memory_access_is_direct(mr, true)) {
if (l < 8 || !memory_access_is_direct(mr, true, attrs)) {
release_lock |= prepare_mmio_access(mr);
r = memory_region_dispatch_write(mr, addr1, val,
MO_64 | devend_memop(endian), attrs);
Expand Down
Loading

0 comments on commit 7389992

Please sign in to comment.