Skip to content

Commit

Permalink
Merge tag 'mem-2022-10-28' of https://github.com/davidhildenbrand/qemu
Browse files Browse the repository at this point in the history
…into staging

Hi,

"Host Memory Backends" and "Memory devices" queue ("mem"):
- Fix NVDIMM error message
- Add ThreadContext user-creatable object and wire it up for NUMA-aware
  hostmem preallocation

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEEG9nKrXNcTDpGDfzKTd4Q9wD/g1oFAmNbpHARHGRhdmlkQHJl
# ZGhhdC5jb20ACgkQTd4Q9wD/g1pDpw//bG9cyIlzTzDnU5pbQiXyLm0nF9tW/tli
# npGPSbFFYz/72XD9VJSVLhbNHoQSmFcMK5m/DA4WAMdOc5zF7lP3XdZcj72pDyxu
# 31hJRvuRhxNb09jhEdWRfX5+Jg9UyYXuIvtKXHSWgrtaYDtHBdTXq/ojZlvlo/rr
# 36v0jaVaTNRs7dKQL2oaN+DSMiPXHxBzA6FABqYmJNNwuMJT0kkX8pfz0OFwkRn+
# iqf9uRhM6b/fNNB0+ReA7FfGL+hzU6Uv8AvAL3orXUqjwPMRe9Fz2gE7HpFnE6DD
# dOP4Xk2iSSJ5XQA8HwtvrQfrGPh4gPYE80ziK/+8boy3alVeGYbYbvWVtdsNju41
# Cq9kM1wDyjZf6SSUIAbjOrNPdbhwyK4GviVBR1zh+/gA3uF5MhrDtZh4h3mWX2if
# ijmT9mfte4NwF3K1MvckAl7IHRb8nxmr7wjjhJ26JwpD+76lfAcmXC2YOlFGHCMi
# 028mjvThf3HW7BD2LjlQSX4UkHmM2vUBrgMGQKyeMham1VmMfSK32wzvUNfF7xSz
# o9k0loBh7unGcUsv3EbqUGswV5F6AgjK3vWRkDql8dNrdIoapDfaejPCd58kVM98
# 5N/aEoha4bAeJ6NGIKzD+4saiMxUqJ0y2NjSrE8iO4HszXgZW5e1Gbkn4Ae6d37D
# QSSqyfasVHY=
# =bLuc
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 28 Oct 2022 05:44:16 EDT
# gpg:                using RSA key 1BD9CAAD735C4C3A460DFCCA4DDE10F700FF835A
# gpg:                issuer "david@redhat.com"
# gpg: Good signature from "David Hildenbrand <david@redhat.com>" [unknown]
# gpg:                 aka "David Hildenbrand <davidhildenbrand@gmail.com>" [full]
# gpg:                 aka "David Hildenbrand <hildenbr@in.tum.de>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 1BD9 CAAD 735C 4C3A 460D  FCCA 4DDE 10F7 00FF 835A

* tag 'mem-2022-10-28' of https://github.com/davidhildenbrand/qemu:
  vl: Allow ThreadContext objects to be created before the sandbox option
  hostmem: Allow for specifying a ThreadContext for preallocation
  util: Make qemu_prealloc_mem() optionally consume a ThreadContext
  util: Add write-only "node-affinity" property for ThreadContext
  util: Introduce ThreadContext user-creatable object
  util: Introduce qemu_thread_set_affinity() and qemu_thread_get_affinity()
  util: Cleanup and rename os_mem_prealloc()
  hw/mem/nvdimm: fix error message for 'unarmed' flag

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
  • Loading branch information
stefanhaRH committed Oct 30, 2022
2 parents 5eff7ba + bd77c30 commit 7208429
Show file tree
Hide file tree
Showing 17 changed files with 642 additions and 31 deletions.
13 changes: 10 additions & 3 deletions backends/hostmem.c
Expand Up @@ -232,7 +232,8 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
void *ptr = memory_region_get_ram_ptr(&backend->mr);
uint64_t sz = memory_region_size(&backend->mr);

os_mem_prealloc(fd, ptr, sz, backend->prealloc_threads, &local_err);
qemu_prealloc_mem(fd, ptr, sz, backend->prealloc_threads,
backend->prealloc_context, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
Expand Down Expand Up @@ -383,8 +384,9 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
* specified NUMA policy in place.
*/
if (backend->prealloc) {
os_mem_prealloc(memory_region_get_fd(&backend->mr), ptr, sz,
backend->prealloc_threads, &local_err);
qemu_prealloc_mem(memory_region_get_fd(&backend->mr), ptr, sz,
backend->prealloc_threads,
backend->prealloc_context, &local_err);
if (local_err) {
goto out;
}
Expand Down Expand Up @@ -492,6 +494,11 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
NULL, NULL);
object_class_property_set_description(oc, "prealloc-threads",
"Number of CPU threads to use for prealloc");
object_class_property_add_link(oc, "prealloc-context",
TYPE_THREAD_CONTEXT, offsetof(HostMemoryBackend, prealloc_context),
object_property_allow_set_link, OBJ_PROP_LINK_STRONG);
object_class_property_set_description(oc, "prealloc-context",
"Context to use for creating CPU threads for preallocation");
object_class_property_add(oc, "size", "int",
host_memory_backend_get_size,
host_memory_backend_set_size,
Expand Down
2 changes: 1 addition & 1 deletion hw/mem/nvdimm.c
Expand Up @@ -149,7 +149,7 @@ static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp)
if (!nvdimm->unarmed && memory_region_is_rom(mr)) {
HostMemoryBackend *hostmem = dimm->hostmem;

error_setg(errp, "'unarmed' property must be off since memdev %s "
error_setg(errp, "'unarmed' property must be 'on' since memdev %s "
"is read-only",
object_get_canonical_path_component(OBJECT(hostmem)));
return;
Expand Down
2 changes: 1 addition & 1 deletion hw/virtio/virtio-mem.c
Expand Up @@ -467,7 +467,7 @@ static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa,
int fd = memory_region_get_fd(&vmem->memdev->mr);
Error *local_err = NULL;

os_mem_prealloc(fd, area, size, 1, &local_err);
qemu_prealloc_mem(fd, area, size, 1, NULL, &local_err);
if (local_err) {
static bool warned;

Expand Down
19 changes: 17 additions & 2 deletions include/qemu/osdep.h
Expand Up @@ -576,8 +576,23 @@ unsigned long qemu_getauxval(unsigned long type);

void qemu_set_tty_echo(int fd, bool echo);

void os_mem_prealloc(int fd, char *area, size_t sz, int smp_cpus,
Error **errp);
typedef struct ThreadContext ThreadContext;

/**
* qemu_prealloc_mem:
* @fd: the fd mapped into the area, -1 for anonymous memory
* @area: start address of the are to preallocate
* @sz: the size of the area to preallocate
* @max_threads: maximum number of threads to use
* @errp: returns an error if this function fails
*
* Preallocate memory (populate/prefault page tables writable) for the virtual
* memory area starting at @area with the size of @sz. After a successful call,
* each page in the area was faulted in writable at least once, for example,
* after allocating file blocks for mapped files.
*/
void qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
ThreadContext *tc, Error **errp);

/**
* qemu_get_pid_name:
Expand Down
57 changes: 57 additions & 0 deletions include/qemu/thread-context.h
@@ -0,0 +1,57 @@
/*
* QEMU Thread Context
*
* Copyright Red Hat Inc., 2022
*
* Authors:
* David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/

#ifndef SYSEMU_THREAD_CONTEXT_H
#define SYSEMU_THREAD_CONTEXT_H

#include "qapi/qapi-types-machine.h"
#include "qemu/thread.h"
#include "qom/object.h"

#define TYPE_THREAD_CONTEXT "thread-context"
OBJECT_DECLARE_TYPE(ThreadContext, ThreadContextClass,
THREAD_CONTEXT)

struct ThreadContextClass {
ObjectClass parent_class;
};

struct ThreadContext {
/* private */
Object parent;

/* private */
unsigned int thread_id;
QemuThread thread;

/* Semaphore to wait for context thread action. */
QemuSemaphore sem;
/* Semaphore to wait for action in context thread. */
QemuSemaphore sem_thread;
/* Mutex to synchronize requests. */
QemuMutex mutex;

/* Commands for the thread to execute. */
int thread_cmd;
void *thread_cmd_data;

/* CPU affinity bitmap used for initialization. */
unsigned long *init_cpu_bitmap;
int init_cpu_nbits;
};

void thread_context_create_thread(ThreadContext *tc, QemuThread *thread,
const char *name,
void *(*start_routine)(void *), void *arg,
int mode);

#endif /* SYSEMU_THREAD_CONTEXT_H */
4 changes: 4 additions & 0 deletions include/qemu/thread.h
Expand Up @@ -185,6 +185,10 @@ void qemu_event_destroy(QemuEvent *ev);
void qemu_thread_create(QemuThread *thread, const char *name,
void *(*start_routine)(void *),
void *arg, int mode);
int qemu_thread_set_affinity(QemuThread *thread, unsigned long *host_cpus,
unsigned long nbits);
int qemu_thread_get_affinity(QemuThread *thread, unsigned long **host_cpus,
unsigned long *nbits);
void *qemu_thread_join(QemuThread *thread);
void qemu_thread_get_self(QemuThread *thread);
bool qemu_thread_is_self(QemuThread *thread);
Expand Down
2 changes: 2 additions & 0 deletions include/sysemu/hostmem.h
Expand Up @@ -18,6 +18,7 @@
#include "qom/object.h"
#include "exec/memory.h"
#include "qemu/bitmap.h"
#include "qemu/thread-context.h"

#define TYPE_MEMORY_BACKEND "memory-backend"
OBJECT_DECLARE_TYPE(HostMemoryBackend, HostMemoryBackendClass,
Expand Down Expand Up @@ -66,6 +67,7 @@ struct HostMemoryBackend {
bool merge, dump, use_canonical_path;
bool prealloc, is_mapped, share, reserve;
uint32_t prealloc_threads;
ThreadContext *prealloc_context;
DECLARE_BITMAP(host_nodes, MAX_NODES + 1);
HostMemPolicy policy;

Expand Down
16 changes: 16 additions & 0 deletions meson.build
Expand Up @@ -2130,7 +2130,23 @@ config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_pre
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
return 0;
}''', dependencies: threads))
config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + '''
#include <pthread.h>
static void *f(void *p) { return NULL; }
int main(void)
{
int setsize = CPU_ALLOC_SIZE(64);
pthread_t thread;
cpu_set_t *cpuset;
pthread_create(&thread, 0, f, 0);
cpuset = CPU_ALLOC(64);
CPU_ZERO_S(setsize, cpuset);
pthread_setaffinity_np(thread, setsize, cpuset);
pthread_getaffinity_np(thread, setsize, cpuset);
CPU_FREE(cpuset);
return 0;
}''', dependencies: threads))
config_host_data.set('CONFIG_SIGNALFD', cc.links(gnu_source_prefix + '''
#include <sys/signalfd.h>
#include <stddef.h>
Expand Down
28 changes: 28 additions & 0 deletions qapi/qom.json
Expand Up @@ -578,6 +578,9 @@
#
# @prealloc-threads: number of CPU threads to use for prealloc (default: 1)
#
# @prealloc-context: thread context to use for creation of preallocation threads
# (default: none) (since 7.2)
#
# @share: if false, the memory is private to QEMU; if true, it is shared
# (default: false)
#
Expand Down Expand Up @@ -608,6 +611,7 @@
'*policy': 'HostMemPolicy',
'*prealloc': 'bool',
'*prealloc-threads': 'uint32',
'*prealloc-context': 'str',
'*share': 'bool',
'*reserve': 'bool',
'size': 'size',
Expand Down Expand Up @@ -830,6 +834,28 @@
'reduced-phys-bits': 'uint32',
'*kernel-hashes': 'bool' } }

##
# @ThreadContextProperties:
#
# Properties for thread context objects.
#
# @cpu-affinity: the list of host CPU numbers used as CPU affinity for all
# threads created in the thread context (default: QEMU main
# thread CPU affinity)
#
# @node-affinity: the list of host node numbers that will be resolved to a
# list of host CPU numbers used as CPU affinity. This is a
# shortcut for specifying the list of host CPU numbers
# belonging to the host nodes manually by setting
# @cpu-affinity. (default: QEMU main thread affinity)
#
# Since: 7.2
##
{ 'struct': 'ThreadContextProperties',
'data': { '*cpu-affinity': ['uint16'],
'*node-affinity': ['uint16'] } }


##
# @ObjectType:
#
Expand Down Expand Up @@ -882,6 +908,7 @@
{ 'name': 'secret_keyring',
'if': 'CONFIG_SECRET_KEYRING' },
'sev-guest',
'thread-context',
's390-pv-guest',
'throttle-group',
'tls-creds-anon',
Expand Down Expand Up @@ -948,6 +975,7 @@
'secret_keyring': { 'type': 'SecretKeyringProperties',
'if': 'CONFIG_SECRET_KEYRING' },
'sev-guest': 'SevGuestProperties',
'thread-context': 'ThreadContextProperties',
'throttle-group': 'ThrottleGroupProperties',
'tls-creds-anon': 'TlsCredsAnonProperties',
'tls-creds-psk': 'TlsCredsPskProperties',
Expand Down
2 changes: 1 addition & 1 deletion softmmu/cpus.c
Expand Up @@ -354,7 +354,7 @@ static void qemu_init_sigbus(void)

/*
* ALERT: when modifying this, take care that SIGBUS forwarding in
* os_mem_prealloc() will continue working as expected.
* qemu_prealloc_mem() will continue working as expected.
*/
memset(&action, 0, sizeof(action));
action.sa_flags = SA_SIGINFO;
Expand Down
36 changes: 32 additions & 4 deletions softmmu/vl.c
Expand Up @@ -1759,6 +1759,27 @@ static void object_option_parse(const char *optarg)
visit_free(v);
}

/*
* Very early object creation, before the sandbox options have been activated.
*/
static bool object_create_pre_sandbox(const char *type)
{
/*
* Objects should in general not get initialized "too early" without
* a reason. If you add one, state the reason in a comment!
*/

/*
* Reason: -sandbox on,resourcecontrol=deny disallows setting CPU
* affinity of threads.
*/
if (g_str_equal(type, "thread-context")) {
return true;
}

return false;
}

/*
* Initial object creation happens before all other
* QEMU data types are created. The majority of objects
Expand All @@ -1773,6 +1794,11 @@ static bool object_create_early(const char *type)
* add one, state the reason in a comment!
*/

/* Reason: already created. */
if (object_create_pre_sandbox(type)) {
return false;
}

/* Reason: property "chardev" */
if (g_str_equal(type, "rng-egd") ||
g_str_equal(type, "qtest")) {
Expand Down Expand Up @@ -1895,7 +1921,7 @@ static void qemu_create_early_backends(void)
*/
static bool object_create_late(const char *type)
{
return !object_create_early(type);
return !object_create_early(type) && !object_create_pre_sandbox(type);
}

static void qemu_create_late_backends(void)
Expand Down Expand Up @@ -2351,16 +2377,18 @@ static int process_runstate_actions(void *opaque, QemuOpts *opts, Error **errp)

static void qemu_process_early_options(void)
{
qemu_opts_foreach(qemu_find_opts("name"),
parse_name, NULL, &error_fatal);

object_option_foreach_add(object_create_pre_sandbox);

#ifdef CONFIG_SECCOMP
QemuOptsList *olist = qemu_find_opts_err("sandbox", NULL);
if (olist) {
qemu_opts_foreach(olist, parse_sandbox, NULL, &error_fatal);
}
#endif

qemu_opts_foreach(qemu_find_opts("name"),
parse_name, NULL, &error_fatal);

if (qemu_opts_foreach(qemu_find_opts("action"),
process_runstate_actions, NULL, &error_fatal)) {
exit(1);
Expand Down
1 change: 1 addition & 0 deletions util/meson.build
@@ -1,4 +1,5 @@
util_ss.add(files('osdep.c', 'cutils.c', 'unicode.c', 'qemu-timer-common.c'))
util_ss.add(files('thread-context.c'), numa)
if not config_host_data.get('CONFIG_ATOMIC64')
util_ss.add(files('atomic64.c'))
endif
Expand Down

0 comments on commit 7208429

Please sign in to comment.