[libvirt PATCH v2 00/17] cgroup and thread management in ch driver

I addressed all the open comments on the v1 patch set. In places where indentaion was hard to manage, I created explicit commits to apply correct indentation on files. Compared to v1, this version applies 2 code refactors: 1) some cgroup methods in src/qemu/qemu_cgroup.c were moved to src/hypervisor and shared with ch driver. 2) virProcessGetStatInfo, virProcessGetSchedInfo which were copied from qemu driver are moved to util and shared between qemu and ch drviers. Praveen K Paladugu (9): util: fix indentation in virprocess.c util: Helper functions to get process info ch_domain: fix indentation in ch_domain ch_driver: fix indentation in ch_driver ch_driver,ch_domain: vcpu info getter callbacks ch_monitor: fix indentation in ch_monitor.c qemu,hypervisor: refactor some cgroup mgmt methods ch_process: Setup emulator and iothread settings ch_driver: emulator threadinfo & pinning callbacks Vineeth Pillai (8): ch_domain: add virCHDomainGetMonitor helper method ch_domain: add methods to manage private vcpu data ch_driver: domainGetVcpuPinInfo and nodeGetCPUMap ch_monitor: Get nicindexes in prep for cgroup mgmt ch: methods for cgroup mgmt in ch driver ch_driver,ch_domain: vcpupin callback in ch driver ch_driver: enable typed param string for numatune ch_driver: add numatune callbacks for CH driver src/ch/ch_conf.c | 2 + src/ch/ch_conf.h | 6 +- src/ch/ch_domain.c | 302 ++++++--- src/ch/ch_domain.h | 32 +- src/ch/ch_driver.c | 1045 ++++++++++++++++++++++++++++---- src/ch/ch_monitor.c | 533 +++++++++++----- src/ch/ch_monitor.h | 60 +- src/ch/ch_process.c | 386 +++++++++++- src/ch/ch_process.h | 3 + src/ch/meson.build | 1 + src/hypervisor/domain_cgroup.c | 426 ++++++++++++- src/hypervisor/domain_cgroup.h | 52 ++ src/libvirt_private.syms | 12 + src/qemu/qemu_cgroup.c | 410 +------------ src/qemu/qemu_cgroup.h | 11 - src/qemu/qemu_driver.c | 130 +--- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 17 +- src/util/virprocess.c | 609 +++++++++++-------- src/util/virprocess.h | 5 + 20 files changed, 2905 insertions(+), 1141 deletions(-) -- 2.27.0

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/util/virprocess.c | 501 +++++++++++++++++++++--------------------- 1 file changed, 249 insertions(+), 252 deletions(-) diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 7b0ad9c97b..8288e71f67 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -25,36 +25,36 @@ #include <fcntl.h> #include <signal.h> #ifndef WIN32 -# include <sys/wait.h> +#include <sys/wait.h> #endif #include <unistd.h> #if WITH_SYS_MOUNT_H -# include <sys/mount.h> +#include <sys/mount.h> #endif #if WITH_SETRLIMIT -# include <sys/time.h> -# include <sys/resource.h> +#include <sys/time.h> +#include <sys/resource.h> #endif #if WITH_SCHED_H -# include <sched.h> +#include <sched.h> #endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || WITH_BSD_CPU_AFFINITY -# include <sys/param.h> +#include <sys/param.h> #endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -# include <sys/sysctl.h> -# include <sys/user.h> +#include <sys/sysctl.h> +#include <sys/user.h> #endif #if WITH_BSD_CPU_AFFINITY -# include <sys/cpuset.h> +#include <sys/cpuset.h> #endif #ifdef WIN32 -# define WIN32_LEAN_AND_MEAN -# include <windows.h> +#define WIN32_LEAN_AND_MEAN +#include <windows.h> #endif #include "virprocess.h" @@ -71,41 +71,44 @@ VIR_LOG_INIT("util.process"); #ifdef __linux__ + /* * Workaround older glibc. While kernel may support the setns * syscall, the glibc wrapper might not exist. If that's the * case, use our own. */ -# ifndef __NR_setns -# if defined(__x86_64__) -# define __NR_setns 308 -# elif defined(__i386__) -# define __NR_setns 346 -# elif defined(__arm__) -# define __NR_setns 375 -# elif defined(__aarch64__) -# define __NR_setns 375 -# elif defined(__powerpc__) -# define __NR_setns 350 -# elif defined(__s390__) -# define __NR_setns 339 -# endif -# endif - -# ifndef WITH_SETNS -# if defined(__NR_setns) -# include <sys/syscall.h> - -static inline int setns(int fd, int nstype) +#ifndef __NR_setns +#if defined(__x86_64__) +#define __NR_setns 308 +#elif defined(__i386__) +#define __NR_setns 346 +#elif defined(__arm__) +#define __NR_setns 375 +#elif defined(__aarch64__) +#define __NR_setns 375 +#elif defined(__powerpc__) +#define __NR_setns 350 +#elif defined(__s390__) +#define __NR_setns 339 +#endif +#endif + +#ifndef WITH_SETNS +#if defined(__NR_setns) +#include <sys/syscall.h> + +static inline int +setns(int fd, int nstype) { return syscall(__NR_setns, fd, nstype); } -# else /* !__NR_setns */ -# error Please determine the syscall number for setns on your architecture -# endif -# endif +#else /* !__NR_setns */ +#error Please determine the syscall number for setns on your architecture +#endif +#endif #else /* !__linux__ */ -static inline int setns(int fd G_GNUC_UNUSED, int nstype G_GNUC_UNUSED) +static inline int +setns(int fd G_GNUC_UNUSED, int nstype G_GNUC_UNUSED) { virReportSystemError(ENOSYS, "%s", _("Namespaces are not supported on this platform.")); @@ -115,15 +118,11 @@ static inline int setns(int fd G_GNUC_UNUSED, int nstype G_GNUC_UNUSED) VIR_ENUM_IMPL(virProcessSchedPolicy, VIR_PROC_POLICY_LAST, - "none", - "batch", - "idle", - "fifo", - "rr", -); + "none", "batch", "idle", "fifo", "rr",); #ifndef WIN32 + /** * virProcessTranslateStatus: * @status: child exit status to translate @@ -136,12 +135,11 @@ char * virProcessTranslateStatus(int status) { char *buf; + if (WIFEXITED(status)) { - buf = g_strdup_printf(_("exit status %d"), - WEXITSTATUS(status)); + buf = g_strdup_printf(_("exit status %d"), WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { - buf = g_strdup_printf(_("fatal signal %d"), - WTERMSIG(status)); + buf = g_strdup_printf(_("fatal signal %d"), WTERMSIG(status)); } else { buf = g_strdup_printf(_("invalid value %d"), status); } @@ -175,8 +173,7 @@ virProcessAbort(pid_t pid) */ saved_errno = errno; VIR_DEBUG("aborting child process %d", pid); - while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -185,8 +182,7 @@ virProcessAbort(pid_t pid) VIR_DEBUG("trying SIGTERM to child process %d", pid); kill(pid, SIGTERM); g_usleep(10 * 1000); - while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -194,8 +190,7 @@ virProcessAbort(pid_t pid) } else if (ret == 0) { VIR_DEBUG("trying SIGKILL to child process %d", pid); kill(pid, SIGKILL); - while ((ret = waitpid(pid, &status, 0)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, 0)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -246,8 +241,7 @@ virProcessWait(pid_t pid, int *exitstatus, bool raw) } /* Wait for intermediate process to exit */ - while ((ret = waitpid(pid, &status, 0)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, 0)) == -1 && errno == EINTR); if (ret == -1) { virReportSystemError(errno, _("unable to wait for process %lld"), @@ -289,7 +283,7 @@ void virProcessAbort(pid_t pid) { /* Not yet ported to mingw. Any volunteers? */ - VIR_DEBUG("failed to reap child %lld, abandoning it", (long long)pid); + VIR_DEBUG("failed to reap child %lld, abandoning it", (long long) pid); } @@ -305,7 +299,8 @@ virProcessWait(pid_t pid, int *exitstatus G_GNUC_UNUSED, bool raw G_GNUC_UNUSED) /* send signal to a single process */ -int virProcessKill(pid_t pid, int sig) +int +virProcessKill(pid_t pid, int sig) { if (pid <= 1) { errno = ESRCH; @@ -315,44 +310,45 @@ int virProcessKill(pid_t pid, int sig) #ifdef WIN32 /* Mingw / Windows don't have many signals (AFAIK) */ switch (sig) { - case SIGINT: - /* This does a Ctrl+C equiv */ - if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)) { - errno = ESRCH; - return -1; - } - break; + case SIGINT: + /* This does a Ctrl+C equiv */ + if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)) { + errno = ESRCH; + return -1; + } + break; + + case SIGTERM: + /* Since TerminateProcess is closer to SIG_KILL, we do + * a Ctrl+Break equiv which is more pleasant like the + * good old unix SIGTERM/HUP + */ + if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid)) { + errno = ESRCH; + return -1; + } + break; - case SIGTERM: - /* Since TerminateProcess is closer to SIG_KILL, we do - * a Ctrl+Break equiv which is more pleasant like the - * good old unix SIGTERM/HUP - */ - if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid)) { - errno = ESRCH; - return -1; - } - break; - - default: - { - HANDLE proc; - proc = OpenProcess(PROCESS_TERMINATE, FALSE, pid); - if (!proc) { - errno = ESRCH; /* Not entirely accurate, but close enough */ - return -1; - } + default: + { + HANDLE proc; - /* - * TerminateProcess is more or less equiv to SIG_KILL, in that - * a process can't trap / block it - */ - if (sig != 0 && !TerminateProcess(proc, sig)) { - errno = ESRCH; - return -1; - } - CloseHandle(proc); - } + proc = OpenProcess(PROCESS_TERMINATE, FALSE, pid); + if (!proc) { + errno = ESRCH; /* Not entirely accurate, but close enough */ + return -1; + } + + /* + * TerminateProcess is more or less equiv to SIG_KILL, in that + * a process can't trap / block it + */ + if (sig != 0 && !TerminateProcess(proc, sig)) { + errno = ESRCH; + return -1; + } + CloseHandle(proc); + } } return 0; #else @@ -362,7 +358,8 @@ int virProcessKill(pid_t pid, int sig) /* send signal to a process group */ -int virProcessGroupKill(pid_t pid, int sig G_GNUC_UNUSED) +int +virProcessGroupKill(pid_t pid, int sig G_GNUC_UNUSED) { if (pid <= 1) { errno = ESRCH; @@ -379,7 +376,8 @@ int virProcessGroupKill(pid_t pid, int sig G_GNUC_UNUSED) /* get process group from a pid */ -pid_t virProcessGroupGet(pid_t pid) +pid_t +virProcessGroupGet(pid_t pid) { if (pid <= 1) { errno = ESRCH; @@ -406,15 +404,17 @@ pid_t virProcessGroupGet(pid_t pid) * wait longer than the default. */ int -virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, bool group) +virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, + bool group) { size_t i; + /* This is in 1/5th seconds since polling is on a 0.2s interval */ - unsigned int polldelay = (force ? 200 : 75) + (extradelay*5); + unsigned int polldelay = (force ? 200 : 75) + (extradelay * 5); const char *signame = "TERM"; VIR_DEBUG("vpid=%lld force=%d extradelay=%u group=%d", - (long long)pid, force, extradelay, group); + (long long) pid, force, extradelay, group); /* This loop sends SIGTERM, then waits a few iterations (10 seconds) * to see if it dies. If the process still hasn't exited, and @@ -432,21 +432,21 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, boo int rc; if (i == 0) { - signum = SIGTERM; /* kindly suggest it should exit */ + signum = SIGTERM; /* kindly suggest it should exit */ } else if (i == 50 && force) { VIR_DEBUG("Timed out waiting after SIGTERM to process %lld, " - "sending SIGKILL", (long long)pid); + "sending SIGKILL", (long long) pid); /* No SIGKILL kill on Win32 ! Use SIGABRT instead which our * virProcessKill proc will handle more or less like SIGKILL */ #ifdef WIN32 - signum = SIGABRT; /* kill it after a grace period */ + signum = SIGABRT; /* kill it after a grace period */ signame = "ABRT"; #else - signum = SIGKILL; /* kill it after a grace period */ + signum = SIGKILL; /* kill it after a grace period */ signame = "KILL"; #endif } else { - signum = 0; /* Just check for existence */ + signum = 0; /* Just check for existence */ } if (group) @@ -457,8 +457,9 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, boo if (rc < 0) { if (errno != ESRCH) { virReportSystemError(errno, - _("Failed to terminate process %lld with SIG%s"), - (long long)pid, signame); + _ + ("Failed to terminate process %lld with SIG%s"), + (long long) pid, signame); return -1; } return signum == SIGTERM ? 0 : 1; @@ -469,20 +470,22 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, boo virReportSystemError(EBUSY, _("Failed to terminate process %lld with SIG%s"), - (long long)pid, signame); + (long long) pid, signame); return 0; } -int virProcessKillPainfully(pid_t pid, bool force) +int +virProcessKillPainfully(pid_t pid, bool force) { return virProcessKillPainfullyDelay(pid, force, 0, false); } #if WITH_DECL_CPU_SET_T -int virProcessSetAffinity(pid_t pid, virBitmap *map, bool quiet) +int +virProcessSetAffinity(pid_t pid, virBitmap * map, bool quiet) { size_t i; int numcpus = 1024; @@ -490,7 +493,7 @@ int virProcessSetAffinity(pid_t pid, virBitmap *map, bool quiet) cpu_set_t *mask; int rv = -1; - VIR_DEBUG("Set process affinity on %lld", (long long)pid); + VIR_DEBUG("Set process affinity on %lld", (long long) pid); /* Not only may the statically allocated cpu_set_t be too small, * but there is no way to ask the kernel what size is large enough. @@ -516,8 +519,7 @@ int virProcessSetAffinity(pid_t pid, virBitmap *map, bool quiet) CPU_FREE(mask); if (rv < 0) { - if (errno == EINVAL && - numcpus < (1024 << 8)) { /* 262144 cpus ought to be enough for anyone */ + if (errno == EINVAL && numcpus < (1024 << 8)) { /* 262144 cpus ought to be enough for anyone */ numcpus = numcpus << 2; goto realloc; } @@ -526,7 +528,8 @@ int virProcessSetAffinity(pid_t pid, virBitmap *map, bool quiet) pid, g_strerror(errno)); } else { virReportSystemError(errno, - _("cannot set CPU affinity on process %d"), pid); + _("cannot set CPU affinity on process %d"), + pid); return -1; } } @@ -574,9 +577,8 @@ virProcessGetAffinity(pid_t pid) #elif defined(WITH_BSD_CPU_AFFINITY) -int virProcessSetAffinity(pid_t pid, - virBitmap *map, - bool quiet) +int +virProcessSetAffinity(pid_t pid, virBitmap * map, bool quiet) { size_t i; cpuset_t mask; @@ -594,7 +596,8 @@ int virProcessSetAffinity(pid_t pid, pid, g_strerror(errno)); } else { virReportSystemError(errno, - _("cannot set CPU affinity on process %d"), pid); + _("cannot set CPU affinity on process %d"), + pid); return -1; } } @@ -628,14 +631,15 @@ virProcessGetAffinity(pid_t pid) #else /* WITH_DECL_CPU_SET_T */ -int virProcessSetAffinity(pid_t pid G_GNUC_UNUSED, - virBitmap *map G_GNUC_UNUSED, - bool quiet G_GNUC_UNUSED) +int +virProcessSetAffinity(pid_t pid G_GNUC_UNUSED, + virBitmap * map G_GNUC_UNUSED, bool quiet G_GNUC_UNUSED) { /* The @quiet parameter is ignored here, it is used only for silencing * actual failures. */ virReportSystemError(ENOSYS, "%s", - _("Process CPU affinity is not supported on this platform")); + _ + ("Process CPU affinity is not supported on this platform")); return -1; } @@ -643,15 +647,18 @@ virBitmap * virProcessGetAffinity(pid_t pid G_GNUC_UNUSED) { virReportSystemError(ENOSYS, "%s", - _("Process CPU affinity is not supported on this platform")); + _ + ("Process CPU affinity is not supported on this platform")); return NULL; } #endif /* WITH_DECL_CPU_SET_T */ -int virProcessGetPids(pid_t pid, size_t *npids, pid_t **pids) +int +virProcessGetPids(pid_t pid, size_t *npids, pid_t ** pids) { int ret = -1; + g_autoptr(DIR) dir = NULL; int value; struct dirent *ent; @@ -660,7 +667,7 @@ int virProcessGetPids(pid_t pid, size_t *npids, pid_t **pids) *npids = 0; *pids = NULL; - taskPath = g_strdup_printf("/proc/%llu/task", (long long)pid); + taskPath = g_strdup_printf("/proc/%llu/task", (long long) pid); if (virDirOpen(&dir, taskPath) < 0) goto cleanup; @@ -688,9 +695,8 @@ int virProcessGetPids(pid_t pid, size_t *npids, pid_t **pids) } -int virProcessGetNamespaces(pid_t pid, - size_t *nfdlist, - int **fdlist) +int +virProcessGetNamespaces(pid_t pid, size_t *nfdlist, int **fdlist) { size_t i = 0; const char *ns[] = { "user", "ipc", "uts", "net", "pid", "mnt" }; @@ -702,11 +708,11 @@ int virProcessGetNamespaces(pid_t pid, int fd; g_autofree char *nsfile = NULL; - nsfile = g_strdup_printf("/proc/%llu/ns/%s", (long long)pid, ns[i]); + nsfile = g_strdup_printf("/proc/%llu/ns/%s", (long long) pid, ns[i]); if ((fd = open(nsfile, O_RDONLY)) >= 0) { VIR_EXPAND_N(*fdlist, *nfdlist, 1); - (*fdlist)[(*nfdlist)-1] = fd; + (*fdlist)[(*nfdlist) - 1] = fd; } } @@ -714,8 +720,8 @@ int virProcessGetNamespaces(pid_t pid, } -int virProcessSetNamespaces(size_t nfdlist, - int *fdlist) +int +virProcessSetNamespaces(size_t nfdlist, int *fdlist) { size_t i; @@ -733,8 +739,7 @@ int virProcessSetNamespaces(size_t nfdlist, * type passed to setns()'s second param. Since we * pass 0, we know the EINVAL is harmless */ - if (setns(fdlist[i], 0) < 0 && - errno != EINVAL) { + if (setns(fdlist[i], 0) < 0 && errno != EINVAL) { virReportSystemError(errno, "%s", _("Unable to join domain namespace")); return -1; @@ -747,8 +752,7 @@ int virProcessSetNamespaces(size_t nfdlist, static int virProcessPrLimit(pid_t pid, int resource, - const struct rlimit *new_limit, - struct rlimit *old_limit) + const struct rlimit *new_limit, struct rlimit *old_limit) { return prlimit(pid, resource, new_limit, old_limit); } @@ -766,8 +770,7 @@ virProcessPrLimit(pid_t pid G_GNUC_UNUSED, #if WITH_GETRLIMIT static int -virProcessGetRLimit(int resource, - struct rlimit *old_limit) +virProcessGetRLimit(int resource, struct rlimit *old_limit) { return getrlimit(resource, old_limit); } @@ -775,51 +778,49 @@ virProcessGetRLimit(int resource, #if WITH_SETRLIMIT static int -virProcessSetRLimit(int resource, - const struct rlimit *new_limit) +virProcessSetRLimit(int resource, const struct rlimit *new_limit) { return setrlimit(resource, new_limit); } #endif /* WITH_SETRLIMIT */ #if WITH_GETRLIMIT -static const char* +static const char * virProcessLimitResourceToLabel(int resource) { switch (resource) { -# if defined(RLIMIT_MEMLOCK) +#if defined(RLIMIT_MEMLOCK) case RLIMIT_MEMLOCK: return "Max locked memory"; -# endif /* defined(RLIMIT_MEMLOCK) */ +#endif /* defined(RLIMIT_MEMLOCK) */ -# if defined(RLIMIT_NPROC) +#if defined(RLIMIT_NPROC) case RLIMIT_NPROC: return "Max processes"; -# endif /* defined(RLIMIT_NPROC) */ +#endif /* defined(RLIMIT_NPROC) */ -# if defined(RLIMIT_NOFILE) +#if defined(RLIMIT_NOFILE) case RLIMIT_NOFILE: return "Max open files"; -# endif /* defined(RLIMIT_NOFILE) */ +#endif /* defined(RLIMIT_NOFILE) */ -# if defined(RLIMIT_CORE) +#if defined(RLIMIT_CORE) case RLIMIT_CORE: return "Max core file size"; -# endif /* defined(RLIMIT_CORE) */ +#endif /* defined(RLIMIT_CORE) */ default: return NULL; } } -# if defined(__linux__) +#if defined(__linux__) static int -virProcessGetLimitFromProc(pid_t pid, - int resource, - struct rlimit *limit) +virProcessGetLimitFromProc(pid_t pid, int resource, struct rlimit *limit) { g_autofree char *procfile = NULL; g_autofree char *buf = NULL; + g_auto(GStrv) lines = NULL; const char *label; size_t i; @@ -829,7 +830,7 @@ virProcessGetLimitFromProc(pid_t pid, return -1; } - procfile = g_strdup_printf("/proc/%lld/limits", (long long)pid); + procfile = g_strdup_printf("/proc/%lld/limits", (long long) pid); if (virFileReadAllQuiet(procfile, 2048, &buf) < 0) { /* virFileReadAllQuiet() already sets errno, so don't overwrite @@ -873,7 +874,7 @@ virProcessGetLimitFromProc(pid_t pid, errno = EIO; return -1; } -# else /* !defined(__linux__) */ +#else /* !defined(__linux__) */ static int virProcessGetLimitFromProc(pid_t pid G_GNUC_UNUSED, int resource G_GNUC_UNUSED, @@ -882,12 +883,10 @@ virProcessGetLimitFromProc(pid_t pid G_GNUC_UNUSED, errno = ENOSYS; return -1; } -# endif /* !defined(__linux__) */ +#endif /* !defined(__linux__) */ static int -virProcessGetLimit(pid_t pid, - int resource, - struct rlimit *old_limit) +virProcessGetLimit(pid_t pid, int resource, struct rlimit *old_limit) { pid_t current_pid = getpid(); bool same_process = (pid == current_pid); @@ -913,9 +912,7 @@ virProcessGetLimit(pid_t pid, #if WITH_SETRLIMIT static int -virProcessSetLimit(pid_t pid, - int resource, - const struct rlimit *new_limit) +virProcessSetLimit(pid_t pid, int resource, const struct rlimit *new_limit) { pid_t current_pid = getpid(); bool same_process = (pid == current_pid); @@ -931,6 +928,7 @@ virProcessSetLimit(pid_t pid, #endif /* WITH_SETRLIMIT */ #if WITH_SETRLIMIT && defined(RLIMIT_MEMLOCK) + /** * virProcessSetMaxMemLock: * @pid: process to be changed @@ -958,7 +956,7 @@ virProcessSetMaxMemLock(pid_t pid, unsigned long long bytes) virReportSystemError(errno, _("cannot limit locked memory " "of process %lld to %llu"), - (long long int)pid, bytes); + (long long int) pid, bytes); } VIR_DEBUG("Locked memory for process %lld limited to %llu bytes", @@ -977,6 +975,7 @@ virProcessSetMaxMemLock(pid_t pid G_GNUC_UNUSED, #endif /* ! (WITH_SETRLIMIT && defined(RLIMIT_MEMLOCK)) */ #if WITH_GETRLIMIT && defined(RLIMIT_MEMLOCK) + /** * virProcessGetMaxMemLock: * @pid: process to be queried @@ -987,8 +986,7 @@ virProcessSetMaxMemLock(pid_t pid G_GNUC_UNUSED, * Returns: 0 on success, <0 on failure. */ int -virProcessGetMaxMemLock(pid_t pid, - unsigned long long *bytes) +virProcessGetMaxMemLock(pid_t pid, unsigned long long *bytes) { struct rlimit rlim; @@ -998,8 +996,7 @@ virProcessGetMaxMemLock(pid_t pid, if (virProcessGetLimit(pid, RLIMIT_MEMLOCK, &rlim) < 0) { virReportSystemError(errno, _("cannot get locked memory limit " - "of process %lld"), - (long long int) pid); + "of process %lld"), (long long int) pid); return -1; } @@ -1026,6 +1023,7 @@ virProcessGetMaxMemLock(pid_t pid G_GNUC_UNUSED, #endif /* ! (WITH_GETRLIMIT && defined(RLIMIT_MEMLOCK)) */ #if WITH_SETRLIMIT && defined(RLIMIT_NPROC) + /** * virProcessSetMaxProcesses: * @pid: process to be changed @@ -1045,9 +1043,9 @@ virProcessSetMaxProcesses(pid_t pid, unsigned int procs) if (virProcessSetLimit(pid, RLIMIT_NPROC, &rlim) < 0) { virReportSystemError(errno, - _("cannot limit number of subprocesses " - "of process %lld to %u"), - (long long int)pid, procs); + _("cannot limit number of subprocesses " + "of process %lld to %u"), + (long long int) pid, procs); return -1; } return 0; @@ -1063,6 +1061,7 @@ virProcessSetMaxProcesses(pid_t pid G_GNUC_UNUSED, #endif /* ! (WITH_SETRLIMIT && defined(RLIMIT_NPROC)) */ #if WITH_SETRLIMIT && defined(RLIMIT_NOFILE) + /** * virProcessSetMaxFiles: * @pid: process to be changed @@ -1077,21 +1076,21 @@ virProcessSetMaxFiles(pid_t pid, unsigned int files) { struct rlimit rlim; - /* Max number of opened files is one greater than actual limit. See - * man setrlimit. - * - * NB: That indicates to me that we would want the following code - * to say "files - 1", but the original of this code in - * qemu_process.c also had files + 1, so this preserves current - * behavior. - */ + /* Max number of opened files is one greater than actual limit. See + * man setrlimit. + * + * NB: That indicates to me that we would want the following code + * to say "files - 1", but the original of this code in + * qemu_process.c also had files + 1, so this preserves current + * behavior. + */ rlim.rlim_cur = rlim.rlim_max = files + 1; if (virProcessSetLimit(pid, RLIMIT_NOFILE, &rlim) < 0) { virReportSystemError(errno, _("cannot limit number of open files " "of process %lld to %u"), - (long long int)pid, files); + (long long int) pid, files); return -1; } @@ -1099,8 +1098,7 @@ virProcessSetMaxFiles(pid_t pid, unsigned int files) } #else /* ! (WITH_SETRLIMIT && defined(RLIMIT_NOFILE)) */ int -virProcessSetMaxFiles(pid_t pid G_GNUC_UNUSED, - unsigned int files G_GNUC_UNUSED) +virProcessSetMaxFiles(pid_t pid G_GNUC_UNUSED, unsigned int files G_GNUC_UNUSED) { virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); return -1; @@ -1108,6 +1106,7 @@ virProcessSetMaxFiles(pid_t pid G_GNUC_UNUSED, #endif /* ! (WITH_SETRLIMIT && defined(RLIMIT_NOFILE)) */ #if WITH_SETRLIMIT && defined(RLIMIT_CORE) + /** * virProcessSetMaxCoreSize: * @pid: process to be changed @@ -1126,9 +1125,9 @@ virProcessSetMaxCoreSize(pid_t pid, unsigned long long bytes) if (virProcessSetLimit(pid, RLIMIT_CORE, &rlim) < 0) { virReportSystemError(errno, - _("cannot limit core file size " - "of process %lld to %llu"), - (long long int)pid, bytes); + _("cannot limit core file size " + "of process %lld to %llu"), + (long long int) pid, bytes); return -1; } @@ -1146,19 +1145,20 @@ virProcessSetMaxCoreSize(pid_t pid G_GNUC_UNUSED, #ifdef __linux__ + /* * Port of code from polkitunixprocess.c under terms * of the LGPLv2+ */ -int virProcessGetStartTime(pid_t pid, - unsigned long long *timestamp) +int +virProcessGetStartTime(pid_t pid, unsigned long long *timestamp) { g_auto(GStrv) proc_stat = virProcessGetStat(pid, 0); const char *starttime_str = NULL; if (!proc_stat || g_strv_length(proc_stat) < 22) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("Cannot find start time for pid %d"), (int)pid); + _("Cannot find start time for pid %d"), (int) pid); return -1; } @@ -1166,14 +1166,14 @@ int virProcessGetStartTime(pid_t pid, if (virStrToLong_ull(starttime_str, NULL, 10, timestamp) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Cannot parse start time %s for pid %d"), - starttime_str, (int)pid); + starttime_str, (int) pid); return -1; } return 0; } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -int virProcessGetStartTime(pid_t pid, - unsigned long long *timestamp) +int +virProcessGetStartTime(pid_t pid, unsigned long long *timestamp) { struct kinfo_proc p; int mib[4]; @@ -1190,19 +1190,21 @@ int virProcessGetStartTime(pid_t pid, return -1; } - *timestamp = (unsigned long long)p.ki_start.tv_sec; + *timestamp = (unsigned long long) p.ki_start.tv_sec; return 0; } #else -int virProcessGetStartTime(pid_t pid, - unsigned long long *timestamp) +int +virProcessGetStartTime(pid_t pid, unsigned long long *timestamp) { static int warned; + if (g_atomic_int_add(&warned, 1) == 0) { - VIR_WARN("Process start time of pid %lld not available on this platform", - (long long) pid); + VIR_WARN + ("Process start time of pid %lld not available on this platform", + (long long) pid); } *timestamp = 0; return 0; @@ -1218,15 +1220,15 @@ struct _virProcessNamespaceHelperData { void *opaque; }; -static int virProcessNamespaceHelper(pid_t pid G_GNUC_UNUSED, - void *opaque) +static int +virProcessNamespaceHelper(pid_t pid G_GNUC_UNUSED, void *opaque) { virProcessNamespaceHelperData *data = opaque; int fd = -1; int ret = -1; g_autofree char *path = NULL; - path = g_strdup_printf("/proc/%lld/ns/mnt", (long long)data->pid); + path = g_strdup_printf("/proc/%lld/ns/mnt", (long long) data->pid); if ((fd = open(path, O_RDONLY)) < 0) { virReportSystemError(errno, "%s", @@ -1235,8 +1237,7 @@ static int virProcessNamespaceHelper(pid_t pid G_GNUC_UNUSED, } if (setns(fd, 0) < 0) { - virReportSystemError(errno, "%s", - _("Unable to enter mount namespace")); + virReportSystemError(errno, "%s", _("Unable to enter mount namespace")); goto cleanup; } @@ -1255,10 +1256,10 @@ static int virProcessNamespaceHelper(pid_t pid G_GNUC_UNUSED, */ int virProcessRunInMountNamespace(pid_t pid, - virProcessNamespaceCallback cb, - void *opaque) + virProcessNamespaceCallback cb, void *opaque) { - virProcessNamespaceHelperData data = {.pid = pid, .cb = cb, .opaque = opaque}; + virProcessNamespaceHelperData data = {.pid = pid, .cb = cb, + .opaque = opaque}; return virProcessRunInFork(virProcessNamespaceHelper, &data); } @@ -1279,8 +1280,9 @@ virProcessRunInMountNamespace(pid_t pid G_GNUC_UNUSED, #ifndef WIN32 + /* We assume that error messages will fit into 1024 chars */ -# define VIR_PROCESS_ERROR_MAX_LENGTH 1024 +#define VIR_PROCESS_ERROR_MAX_LENGTH 1024 typedef struct { int code; int domain; @@ -1296,13 +1298,12 @@ typedef struct { typedef union { errorData data; char bindata[sizeof(errorData)]; -} errorDataBin; +} +errorDataBin; static int virProcessRunInForkHelper(int errfd, - pid_t ppid, - virProcessForkCallback cb, - void *opaque) + pid_t ppid, virProcessForkCallback cb, void *opaque) { int ret = 0; @@ -1355,8 +1356,7 @@ virProcessRunInForkHelper(int errfd, * Otherwise the returned value is the retval of the callback. */ int -virProcessRunInFork(virProcessForkCallback cb, - void *opaque) +virProcessRunInFork(virProcessForkCallback cb, void *opaque) { int ret = -1; pid_t child = -1; @@ -1402,8 +1402,7 @@ virProcessRunInFork(virProcessForkCallback cb, bin->data.str2, bin->data.str3, bin->data.int1, - bin->data.int2, - "%s", bin->data.message); + bin->data.int2, "%s", bin->data.message); } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("child didn't write error (status=%d)"), @@ -1426,7 +1425,8 @@ virProcessRunInFork(virProcessForkCallback cb G_GNUC_UNUSED, void *opaque G_GNUC_UNUSED) { virReportSystemError(ENOSYS, "%s", - _("Process spawning is not supported on this platform")); + _ + ("Process spawning is not supported on this platform")); return -1; } @@ -1438,14 +1438,14 @@ int virProcessSetupPrivateMountNS(void) { if (unshare(CLONE_NEWNS) < 0) { - virReportSystemError(errno, "%s", - _("Cannot unshare mount namespace")); + virReportSystemError(errno, "%s", _("Cannot unshare mount namespace")); return -1; } - if (mount("", "/", "none", MS_SLAVE|MS_REC, NULL) < 0) { + if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL) < 0) { virReportSystemError(errno, "%s", - _("Failed disable mount propagation out of the root filesystem")); + _ + ("Failed disable mount propagation out of the root filesystem")); return -1; } @@ -1558,8 +1558,7 @@ virProcessExitWithStatus(int status) struct sigaction act; sigset_t sigs; - if (sigemptyset(&sigs) == 0 && - sigaddset(&sigs, WTERMSIG(status)) == 0) + if (sigemptyset(&sigs) == 0 && sigaddset(&sigs, WTERMSIG(status)) == 0) sigprocmask(SIG_UNBLOCK, &sigs, NULL); memset(&act, 0, sizeof(act)); act.sa_handler = SIG_DFL; @@ -1569,7 +1568,7 @@ virProcessExitWithStatus(int status) value = 128 + WTERMSIG(status); } #else /* WIN32 */ - (void)status; + (void) status; #endif /* WIN32 */ exit(value); } @@ -1580,43 +1579,41 @@ static int virProcessSchedTranslatePolicy(virProcessSchedPolicy policy) { switch (policy) { - case VIR_PROC_POLICY_NONE: - return SCHED_OTHER; + case VIR_PROC_POLICY_NONE: + return SCHED_OTHER; - case VIR_PROC_POLICY_BATCH: -# ifdef SCHED_BATCH - return SCHED_BATCH; -# else - return -1; -# endif + case VIR_PROC_POLICY_BATCH: +#ifdef SCHED_BATCH + return SCHED_BATCH; +#else + return -1; +#endif - case VIR_PROC_POLICY_IDLE: -# ifdef SCHED_IDLE - return SCHED_IDLE; -# else - return -1; -# endif + case VIR_PROC_POLICY_IDLE: +#ifdef SCHED_IDLE + return SCHED_IDLE; +#else + return -1; +#endif - case VIR_PROC_POLICY_FIFO: - return SCHED_FIFO; + case VIR_PROC_POLICY_FIFO: + return SCHED_FIFO; - case VIR_PROC_POLICY_RR: - return SCHED_RR; + case VIR_PROC_POLICY_RR: + return SCHED_RR; - case VIR_PROC_POLICY_LAST: - /* nada */ - break; + case VIR_PROC_POLICY_LAST: + /* nada */ + break; } return -1; } int -virProcessSetScheduler(pid_t pid, - virProcessSchedPolicy policy, - int priority) +virProcessSetScheduler(pid_t pid, virProcessSchedPolicy policy, int priority) { - struct sched_param param = {0}; + struct sched_param param = { 0 }; int pol = virProcessSchedTranslatePolicy(policy); VIR_DEBUG("pid=%lld, policy=%d, priority=%u", @@ -1674,8 +1671,7 @@ virProcessSetScheduler(pid_t pid, int virProcessSetScheduler(pid_t pid G_GNUC_UNUSED, - virProcessSchedPolicy policy, - int priority G_GNUC_UNUSED) + virProcessSchedPolicy policy, int priority G_GNUC_UNUSED) { if (!policy) return 0; @@ -1697,10 +1693,9 @@ virProcessSetScheduler(pid_t pid G_GNUC_UNUSED, * and return them as array of strings. */ GStrv -virProcessGetStat(pid_t pid, - pid_t tid) +virProcessGetStat(pid_t pid, pid_t tid) { - int len = 10 * 1024; /* 10kB ought to be enough for everyone */ + int len = 10 * 1024; /* 10kB ought to be enough for everyone */ g_autofree char *buf = NULL; g_autofree char *path = NULL; GStrv rest = NULL; @@ -1711,12 +1706,13 @@ virProcessGetStat(pid_t pid, if (pid) { if (tid) - path = g_strdup_printf("/proc/%d/task/%d/stat", (int)pid, (int)tid); + path = + g_strdup_printf("/proc/%d/task/%d/stat", (int) pid, (int) tid); else - path = g_strdup_printf("/proc/%d/stat", (int)pid); + path = g_strdup_printf("/proc/%d/stat", (int) pid); } else { if (tid) - path = g_strdup_printf("/proc/self/task/%d/stat", (int)tid); + path = g_strdup_printf("/proc/self/task/%d/stat", (int) tid); else path = g_strdup("/proc/self/stat"); } @@ -1727,7 +1723,7 @@ virProcessGetStat(pid_t pid, /* eliminate trailing spaces */ while (len > 0 && g_ascii_isspace(buf[--len])) - buf[len] = '\0'; + buf[len] = '\0'; /* Find end of the first field */ if (!(comm = strchr(buf, ' '))) @@ -1755,6 +1751,7 @@ virProcessGetStat(pid_t pid, rest = g_strsplit(rparen + 2, " ", 0); nrest = g_strv_length(rest); ret = g_new0(char *, nrest + 3); + ret[0] = g_strdup(buf); ret[1] = g_strdup(comm); memcpy(ret + 2, rest, nrest * sizeof(char *)); -- 2.27.0

On a Thursday in 2021, Praveen K Paladugu wrote:
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Most of these indentation fixes here are against our coding style: https://libvirt.org/coding-style.html
--- src/util/virprocess.c | 501 +++++++++++++++++++++--------------------- 1 file changed, 249 insertions(+), 252 deletions(-)
diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 7b0ad9c97b..8288e71f67 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -25,36 +25,36 @@ #include <fcntl.h> #include <signal.h> #ifndef WIN32 -# include <sys/wait.h> +#include <sys/wait.h> #endif #include <unistd.h>
This is intentional spacing to make it obvious which directives are conditional. It's enforced by cppi(1) which is run as a part of our tests, if installed.
-static inline int setns(int fd, int nstype) +static inline int +setns(int fd, int nstype) {
This is good and the style we try to use for new code.
@@ -115,15 +118,11 @@ static inline int setns(int fd G_GNUC_UNUSED, int nstype G_GNUC_UNUSED)
VIR_ENUM_IMPL(virProcessSchedPolicy, VIR_PROC_POLICY_LAST, - "none", - "batch", - "idle", - "fifo", - "rr", -); + "none", "batch", "idle", "fifo", "rr",);
One line per enum value makes for nicer diffs
#ifndef WIN32 + /** * virProcessTranslateStatus: * @status: child exit status to translate @@ -136,12 +135,11 @@ char * virProcessTranslateStatus(int status) { char *buf; + if (WIFEXITED(status)) { - buf = g_strdup_printf(_("exit status %d"), - WEXITSTATUS(status)); + buf = g_strdup_printf(_("exit status %d"), WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { - buf = g_strdup_printf(_("fatal signal %d"), - WTERMSIG(status)); + buf = g_strdup_printf(_("fatal signal %d"), WTERMSIG(status)); } else { buf = g_strdup_printf(_("invalid value %d"), status); } @@ -175,8 +173,7 @@ virProcessAbort(pid_t pid) */ saved_errno = errno; VIR_DEBUG("aborting child process %d", pid); - while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -185,8 +182,7 @@ virProcessAbort(pid_t pid) VIR_DEBUG("trying SIGTERM to child process %d", pid); kill(pid, SIGTERM); g_usleep(10 * 1000); - while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -194,8 +190,7 @@ virProcessAbort(pid_t pid) } else if (ret == 0) { VIR_DEBUG("trying SIGKILL to child process %d", pid); kill(pid, SIGKILL); - while ((ret = waitpid(pid, &status, 0)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, 0)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -246,8 +241,7 @@ virProcessWait(pid_t pid, int *exitstatus, bool raw) }
/* Wait for intermediate process to exit */ - while ((ret = waitpid(pid, &status, 0)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, 0)) == -1 && errno == EINTR);
if (ret == -1) { virReportSystemError(errno, _("unable to wait for process %lld"), @@ -289,7 +283,7 @@ void virProcessAbort(pid_t pid) { /* Not yet ported to mingw. Any volunteers? */ - VIR_DEBUG("failed to reap child %lld, abandoning it", (long long)pid); + VIR_DEBUG("failed to reap child %lld, abandoning it", (long long) pid); }
@@ -305,7 +299,8 @@ virProcessWait(pid_t pid, int *exitstatus G_GNUC_UNUSED, bool raw G_GNUC_UNUSED)
/* send signal to a single process */ -int virProcessKill(pid_t pid, int sig) +int +virProcessKill(pid_t pid, int sig) { if (pid <= 1) { errno = ESRCH; @@ -315,44 +310,45 @@ int virProcessKill(pid_t pid, int sig) #ifdef WIN32 /* Mingw / Windows don't have many signals (AFAIK) */ switch (sig) { - case SIGINT:
Aligning 'case's with the 'switch' keyword is intentional.
- /* This does a Ctrl+C equiv */ - if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)) { - errno = ESRCH; - return -1; - } - break; @@ -432,21 +432,21 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, boo int rc;
if (i == 0) { - signum = SIGTERM; /* kindly suggest it should exit */ + signum = SIGTERM; /* kindly suggest it should exit */
Indenting the comment by three spaces seems an odd choice.
} else if (i == 50 && force) { VIR_DEBUG("Timed out waiting after SIGTERM to process %lld, " - "sending SIGKILL", (long long)pid); + "sending SIGKILL", (long long) pid); /* No SIGKILL kill on Win32 ! Use SIGABRT instead which our * virProcessKill proc will handle more or less like SIGKILL */ #ifdef WIN32 - signum = SIGABRT; /* kill it after a grace period */ + signum = SIGABRT; /* kill it after a grace period */ signame = "ABRT"; #else - signum = SIGKILL; /* kill it after a grace period */ + signum = SIGKILL; /* kill it after a grace period */ signame = "KILL"; #endif } else { - signum = 0; /* Just check for existence */ + signum = 0; /* Just check for existence */ }
if (group) @@ -457,8 +457,9 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, boo if (rc < 0) { if (errno != ESRCH) { virReportSystemError(errno, - _("Failed to terminate process %lld with SIG%s"), - (long long)pid, signame); + _ + ("Failed to terminate process %lld with SIG%s"),
The macro invocation should be on the same line as its parameter.
+ (long long) pid, signame);
No need for the space after the cast.
return -1; } return signum == SIGTERM ? 0 : 1;
Jano

On 12/3/2021 11:25 AM, Ján Tomko wrote:
On a Thursday in 2021, Praveen K Paladugu wrote:
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
Most of these indentation fixes here are against our coding style: https://libvirt.org/coding-style.html
It is hard to follow all the formatting guidelines manually. So I primarily relied on running "indent" to handle all formatting as suggested at https://libvirt.org/coding-style.html#code-formatting-especially-for-new-cod.... Is there a different tool I can manage all formatting with?
--- src/util/virprocess.c | 501 +++++++++++++++++++++--------------------- 1 file changed, 249 insertions(+), 252 deletions(-)
diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 7b0ad9c97b..8288e71f67 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -25,36 +25,36 @@ #include <fcntl.h> #include <signal.h> #ifndef WIN32 -# include <sys/wait.h> +#include <sys/wait.h> #endif #include <unistd.h>
This is intentional spacing to make it obvious which directives are conditional. It's enforced by cppi(1) which is run as a part of our tests, if installed.
-static inline int setns(int fd, int nstype) +static inline int +setns(int fd, int nstype) {
This is good and the style we try to use for new code.
@@ -115,15 +118,11 @@ static inline int setns(int fd G_GNUC_UNUSED, int nstype G_GNUC_UNUSED)
VIR_ENUM_IMPL(virProcessSchedPolicy, VIR_PROC_POLICY_LAST, - "none", - "batch", - "idle", - "fifo", - "rr", -); + "none", "batch", "idle", "fifo", "rr",);
One line per enum value makes for nicer diffs
#ifndef WIN32 + /** * virProcessTranslateStatus: * @status: child exit status to translate @@ -136,12 +135,11 @@ char * virProcessTranslateStatus(int status) { char *buf; + if (WIFEXITED(status)) { - buf = g_strdup_printf(_("exit status %d"), - WEXITSTATUS(status)); + buf = g_strdup_printf(_("exit status %d"), WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { - buf = g_strdup_printf(_("fatal signal %d"), - WTERMSIG(status)); + buf = g_strdup_printf(_("fatal signal %d"), WTERMSIG(status)); } else { buf = g_strdup_printf(_("invalid value %d"), status); } @@ -175,8 +173,7 @@ virProcessAbort(pid_t pid) */ saved_errno = errno; VIR_DEBUG("aborting child process %d", pid); - while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -185,8 +182,7 @@ virProcessAbort(pid_t pid) VIR_DEBUG("trying SIGTERM to child process %d", pid); kill(pid, SIGTERM); g_usleep(10 * 1000); - while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -194,8 +190,7 @@ virProcessAbort(pid_t pid) } else if (ret == 0) { VIR_DEBUG("trying SIGKILL to child process %d", pid); kill(pid, SIGKILL); - while ((ret = waitpid(pid, &status, 0)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, 0)) == -1 && errno == EINTR); if (ret == pid) { tmp = virProcessTranslateStatus(status); VIR_DEBUG("process has ended: %s", tmp); @@ -246,8 +241,7 @@ virProcessWait(pid_t pid, int *exitstatus, bool raw) }
/* Wait for intermediate process to exit */ - while ((ret = waitpid(pid, &status, 0)) == -1 && - errno == EINTR); + while ((ret = waitpid(pid, &status, 0)) == -1 && errno == EINTR);
if (ret == -1) { virReportSystemError(errno, _("unable to wait for process %lld"), @@ -289,7 +283,7 @@ void virProcessAbort(pid_t pid) { /* Not yet ported to mingw. Any volunteers? */ - VIR_DEBUG("failed to reap child %lld, abandoning it", (long long)pid); + VIR_DEBUG("failed to reap child %lld, abandoning it", (long long) pid); }
@@ -305,7 +299,8 @@ virProcessWait(pid_t pid, int *exitstatus G_GNUC_UNUSED, bool raw G_GNUC_UNUSED)
/* send signal to a single process */ -int virProcessKill(pid_t pid, int sig) +int +virProcessKill(pid_t pid, int sig) { if (pid <= 1) { errno = ESRCH; @@ -315,44 +310,45 @@ int virProcessKill(pid_t pid, int sig) #ifdef WIN32 /* Mingw / Windows don't have many signals (AFAIK) */ switch (sig) { - case SIGINT:
Aligning 'case's with the 'switch' keyword is intentional.
- /* This does a Ctrl+C equiv */ - if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)) { - errno = ESRCH; - return -1; - } - break; @@ -432,21 +432,21 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, boo int rc;
if (i == 0) { - signum = SIGTERM; /* kindly suggest it should exit */ + signum = SIGTERM; /* kindly suggest it should exit */
Indenting the comment by three spaces seems an odd choice.
} else if (i == 50 && force) { VIR_DEBUG("Timed out waiting after SIGTERM to process %lld, " - "sending SIGKILL", (long long)pid); + "sending SIGKILL", (long long) pid); /* No SIGKILL kill on Win32 ! Use SIGABRT instead which our * virProcessKill proc will handle more or less like SIGKILL */ #ifdef WIN32 - signum = SIGABRT; /* kill it after a grace period */ + signum = SIGABRT; /* kill it after a grace period */ signame = "ABRT"; #else - signum = SIGKILL; /* kill it after a grace period */ + signum = SIGKILL; /* kill it after a grace period */ signame = "KILL"; #endif } else { - signum = 0; /* Just check for existence */ + signum = 0; /* Just check for existence */ }
if (group) @@ -457,8 +457,9 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, boo if (rc < 0) { if (errno != ESRCH) { virReportSystemError(errno, - _("Failed to terminate process %lld with SIG%s"), - (long long)pid, signame); + _ + ("Failed to terminate process %lld with SIG%s"),
The macro invocation should be on the same line as its parameter.
+ (long long) pid, signame);
No need for the space after the cast.
return -1; } return signum == SIGTERM ? 0 : 1;
Jano
-- Regards, Praveen K Paladugu

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 116 ++------------------------------------- src/util/virprocess.c | 108 ++++++++++++++++++++++++++++++++++++ src/util/virprocess.h | 5 ++ 4 files changed, 120 insertions(+), 111 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b98cb0f66d..e0c4fba522 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3099,8 +3099,10 @@ virProcessGetAffinity; virProcessGetMaxMemLock; virProcessGetNamespaces; virProcessGetPids; +virProcessGetSchedInfo; virProcessGetStartTime; virProcessGetStat; +virProcessGetStatInfo; virProcessGroupGet; virProcessGroupKill; virProcessKill; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4e680bc0a7..a7088d3a66 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1323,113 +1323,6 @@ qemuGetSchedstatDelay(unsigned long long *cpudelay, return 0; } - -static int -qemuGetSchedInfo(unsigned long long *cpuWait, - pid_t pid, pid_t tid) -{ - g_autofree char *proc = NULL; - g_autofree char *data = NULL; - g_auto(GStrv) lines = NULL; - size_t i; - double val; - - *cpuWait = 0; - - /* In general, we cannot assume pid_t fits in int; but /proc parsing - * is specific to Linux where int works fine. */ - if (tid) - proc = g_strdup_printf("/proc/%d/task/%d/sched", (int)pid, (int)tid); - else - proc = g_strdup_printf("/proc/%d/sched", (int)pid); - if (!proc) - return -1; - - /* The file is not guaranteed to exist (needs CONFIG_SCHED_DEBUG) */ - if (access(proc, R_OK) < 0) { - return 0; - } - - if (virFileReadAll(proc, (1<<16), &data) < 0) - return -1; - - lines = g_strsplit(data, "\n", 0); - if (!lines) - return -1; - - for (i = 0; lines[i] != NULL; i++) { - const char *line = lines[i]; - - /* Needs CONFIG_SCHEDSTATS. The second check - * is the old name the kernel used in past */ - if (STRPREFIX(line, "se.statistics.wait_sum") || - STRPREFIX(line, "se.wait_sum")) { - line = strchr(line, ':'); - if (!line) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Missing separator in sched info '%s'"), - lines[i]); - return -1; - } - line++; - while (*line == ' ') - line++; - - if (virStrToDouble(line, NULL, &val) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to parse sched info value '%s'"), - line); - return -1; - } - - *cpuWait = (unsigned long long)(val * 1000000); - break; - } - } - - return 0; -} - - -static int -qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss, - pid_t pid, pid_t tid) -{ - g_auto(GStrv) proc_stat = virProcessGetStat(pid, tid); - unsigned long long usertime = 0, systime = 0; - long rss = 0; - int cpu = 0; - - if (!proc_stat || - virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_UTIME], NULL, 10, &usertime) < 0 || - virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_STIME], NULL, 10, &systime) < 0 || - virStrToLong_l(proc_stat[VIR_PROCESS_STAT_RSS], NULL, 10, &rss) < 0 || - virStrToLong_i(proc_stat[VIR_PROCESS_STAT_PROCESSOR], NULL, 10, &cpu) < 0) { - VIR_WARN("cannot parse process status data"); - } - - /* We got jiffies - * We want nanoseconds - * _SC_CLK_TCK is jiffies per second - * So calculate thus.... - */ - if (cpuTime) - *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) - / (unsigned long long)sysconf(_SC_CLK_TCK); - if (lastCpu) - *lastCpu = cpu; - - if (vm_rss) - *vm_rss = rss * virGetSystemPageSizeKB(); - - - VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d rss=%ld", - (int)pid, tid, usertime, systime, cpu, rss); - - return 0; -} - - static int qemuDomainHelperGetVcpus(virDomainObj *vm, virVcpuInfoPtr info, @@ -1469,7 +1362,7 @@ qemuDomainHelperGetVcpus(virDomainObj *vm, vcpuinfo->number = i; vcpuinfo->state = VIR_VCPU_RUNNING; - if (qemuGetProcessInfo(&vcpuinfo->cpuTime, + if (virProcessGetStatInfo(&vcpuinfo->cpuTime, &vcpuinfo->cpu, NULL, vm->pid, vcpupid) < 0) { virReportSystemError(errno, "%s", @@ -1490,7 +1383,7 @@ qemuDomainHelperGetVcpus(virDomainObj *vm, } if (cpuwait) { - if (qemuGetSchedInfo(&(cpuwait[ncpuinfo]), vm->pid, vcpupid) < 0) + if (virProcessGetSchedInfo(&(cpuwait[ncpuinfo]), vm->pid, vcpupid) < 0) return -1; } @@ -2638,7 +2531,8 @@ qemuDomainGetInfo(virDomainPtr dom, } if (virDomainObjIsActive(vm)) { - if (qemuGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) { + if (virProcessGetStatInfo(&(info->cpuTime), NULL, NULL, + vm->pid, 0) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("cannot read cputime for domain")); goto cleanup; @@ -10650,7 +10544,7 @@ qemuDomainMemoryStatsInternal(virQEMUDriver *driver, ret = 0; } - if (qemuGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) { + if (virProcessGetStatInfo(NULL, NULL, &rss, vm->pid, 0) < 0) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("cannot get RSS for domain")); } else { diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 8288e71f67..efa96299fc 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -1761,3 +1761,111 @@ virProcessGetStat(pid_t pid, pid_t tid) return ret; } + + +int +virProcessGetStatInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss, + pid_t pid, pid_t tid) +{ + g_auto(GStrv) proc_stat = virProcessGetStat(pid, tid); + unsigned long long usertime = 0, systime = 0; + long rss = 0; + int cpu = 0; + + if (!proc_stat || + virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_UTIME], NULL, 10, + &usertime) < 0 + || virStrToLong_ullp(proc_stat[VIR_PROCESS_STAT_STIME], NULL, 10, + &systime) < 0 + || virStrToLong_l(proc_stat[VIR_PROCESS_STAT_RSS], NULL, 10, &rss) < 0 + || virStrToLong_i(proc_stat[VIR_PROCESS_STAT_PROCESSOR], NULL, 10, + &cpu) < 0) { + VIR_WARN("cannot parse process status data"); + } + + /* We got jiffies + * We want nanoseconds + * _SC_CLK_TCK is jiffies per second + * So calculate thus.... + */ + if (cpuTime) + *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) + / (unsigned long long) sysconf(_SC_CLK_TCK); + if (lastCpu) + *lastCpu = cpu; + + if (vm_rss) + *vm_rss = rss * virGetSystemPageSizeKB(); + + + VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d rss=%ld", + (int) pid, tid, usertime, systime, cpu, rss); + + return 0; +} + +int +virProcessGetSchedInfo(unsigned long long *cpuWait, pid_t pid, pid_t tid) +{ + g_autofree char *proc = NULL; + g_autofree char *data = NULL; + + g_auto(GStrv) lines = NULL; + size_t i; + double val; + + *cpuWait = 0; + + /* In general, we cannot assume pid_t fits in int; but /proc parsing + * is specific to Linux where int works fine. */ + if (tid) + proc = g_strdup_printf("/proc/%d/task/%d/sched", (int) pid, (int) tid); + else + proc = g_strdup_printf("/proc/%d/sched", (int) pid); + if (!proc) + return -1; + + /* The file is not guaranteed to exist (needs CONFIG_SCHED_DEBUG) */ + if (access(proc, R_OK) < 0) { + return 0; + } + + if (virFileReadAll(proc, (1 << 16), &data) < 0) + return -1; + + lines = g_strsplit(data, "\n", 0); + if (!lines) + return -1; + + for (i = 0; lines[i] != NULL; i++) { + const char *line = lines[i]; + + /* Needs CONFIG_SCHEDSTATS. The second check + * is the old name the kernel used in past */ + if (STRPREFIX(line, "se.statistics.wait_sum") || + STRPREFIX(line, "se.wait_sum")) { + line = strchr(line, ':'); + if (!line) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Missing separator in sched info '%s'"), + lines[i]); + return -1; + } + line++; + while (*line == ' ') + line++; + + if (virStrToDouble(line, NULL, &val) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse sched info value '%s'"), + line); + return -1; + } + + *cpuWait = (unsigned long long) (val * 1000000); + break; + } + } + + return 0; +} diff --git a/src/util/virprocess.h b/src/util/virprocess.h index 82b7403964..d9d27c29b8 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -193,3 +193,8 @@ typedef enum { } virProcessNamespaceFlags; int virProcessNamespaceAvailable(unsigned int ns); + +int virProcessGetStatInfo(unsigned long long *cpuTime, int *lastCpu, + long *vm_rss, pid_t pid, pid_t tid); +int virProcessGetSchedInfo(unsigned long long *cpuWait, pid_t pid, + pid_t tid); -- 2.27.0

On a Thursday in 2021, Praveen K Paladugu wrote:
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
It would be helpful to say in the commit message that the functions are being moved, not newly introduced. Jano
--- src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 116 ++------------------------------------- src/util/virprocess.c | 108 ++++++++++++++++++++++++++++++++++++ src/util/virprocess.h | 5 ++ 4 files changed, 120 insertions(+), 111 deletions(-)

On 12/3/2021 11:26 AM, Ján Tomko wrote:
On a Thursday in 2021, Praveen K Paladugu wrote:
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com>
It would be helpful to say in the commit message that the functions are being moved, not newly introduced.
Fixed in v3
Jano
--- src/libvirt_private.syms | 2 + src/qemu/qemu_driver.c | 116 ++------------------------------------- src/util/virprocess.c | 108 ++++++++++++++++++++++++++++++++++++ src/util/virprocess.h | 5 ++ 4 files changed, 120 insertions(+), 111 deletions(-)
-- Regards, Praveen K Paladugu

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 130 ++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 66 deletions(-) diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index dd4de9e1ea..44f7d26ca4 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -30,16 +30,12 @@ VIR_ENUM_IMPL(virCHDomainJob, CH_JOB_LAST, - "none", - "query", - "destroy", - "modify", -); + "none", "query", "destroy", "modify",); VIR_LOG_INIT("ch.ch_domain"); static int -virCHDomainObjInitJob(virCHDomainObjPrivate *priv) +virCHDomainObjInitJob(virCHDomainObjPrivate * priv) { memset(&priv->job, 0, sizeof(priv->job)); @@ -50,7 +46,7 @@ virCHDomainObjInitJob(virCHDomainObjPrivate *priv) } static void -virCHDomainObjResetJob(virCHDomainObjPrivate *priv) +virCHDomainObjResetJob(virCHDomainObjPrivate * priv) { struct virCHDomainJobObj *job = &priv->job; @@ -59,7 +55,7 @@ virCHDomainObjResetJob(virCHDomainObjPrivate *priv) } static void -virCHDomainObjFreeJob(virCHDomainObjPrivate *priv) +virCHDomainObjFreeJob(virCHDomainObjPrivate * priv) { ignore_value(virCondDestroy(&priv->job.cond)); } @@ -74,7 +70,7 @@ virCHDomainObjFreeJob(virCHDomainObjPrivate *priv) * Successful calls must be followed by EndJob eventually. */ int -virCHDomainObjBeginJob(virDomainObj *obj, enum virCHDomainJob job) +virCHDomainObjBeginJob(virDomainObj * obj, enum virCHDomainJob job) { virCHDomainObjPrivate *priv = obj->privateData; unsigned long long now; @@ -121,13 +117,12 @@ virCHDomainObjBeginJob(virDomainObj *obj, enum virCHDomainJob job) * earlier virCHDomainBeginJob() call */ void -virCHDomainObjEndJob(virDomainObj *obj) +virCHDomainObjEndJob(virDomainObj * obj) { virCHDomainObjPrivate *priv = obj->privateData; enum virCHDomainJob job = priv->job.active; - VIR_DEBUG("Stopping job: %s", - virCHDomainJobTypeToString(job)); + VIR_DEBUG("Stopping job: %s", virCHDomainJobTypeToString(job)); virCHDomainObjResetJob(priv); virCondSignal(&priv->job.cond); @@ -170,8 +165,7 @@ virDomainXMLPrivateDataCallbacks virCHDriverPrivateDataCallbacks = { }; static int -virCHDomainDefPostParseBasic(virDomainDef *def, - void *opaque G_GNUC_UNUSED) +virCHDomainDefPostParseBasic(virDomainDef * def, void *opaque G_GNUC_UNUSED) { /* check for emulator and create a default one if needed */ if (!def->emulator) { @@ -186,71 +180,70 @@ virCHDomainDefPostParseBasic(virDomainDef *def, } static int -virCHDomainDefPostParse(virDomainDef *def, +virCHDomainDefPostParse(virDomainDef * def, unsigned int parseFlags G_GNUC_UNUSED, - void *opaque, - void *parseOpaque G_GNUC_UNUSED) + void *opaque, void *parseOpaque G_GNUC_UNUSED) { virCHDriver *driver = opaque; + g_autoptr(virCaps) caps = virCHDriverGetCapabilities(driver, false); if (!caps) return -1; if (!virCapabilitiesDomainSupported(caps, def->os.type, - def->os.arch, - def->virtType)) + def->os.arch, def->virtType)) return -1; return 0; } static int -chValidateDomainDeviceDef(const virDomainDeviceDef *dev, - const virDomainDef *def G_GNUC_UNUSED, +chValidateDomainDeviceDef(const virDomainDeviceDef * dev, + const virDomainDef * def G_GNUC_UNUSED, void *opaque G_GNUC_UNUSED, void *parseOpaque G_GNUC_UNUSED) { - switch ((virDomainDeviceType)dev->type) { - case VIR_DOMAIN_DEVICE_DISK: - case VIR_DOMAIN_DEVICE_NET: - case VIR_DOMAIN_DEVICE_MEMORY: - case VIR_DOMAIN_DEVICE_VSOCK: - case VIR_DOMAIN_DEVICE_CONTROLLER: - case VIR_DOMAIN_DEVICE_CHR: - break; - - case VIR_DOMAIN_DEVICE_LEASE: - case VIR_DOMAIN_DEVICE_FS: - case VIR_DOMAIN_DEVICE_INPUT: - case VIR_DOMAIN_DEVICE_SOUND: - case VIR_DOMAIN_DEVICE_VIDEO: - case VIR_DOMAIN_DEVICE_HOSTDEV: - case VIR_DOMAIN_DEVICE_WATCHDOG: - case VIR_DOMAIN_DEVICE_GRAPHICS: - case VIR_DOMAIN_DEVICE_HUB: - case VIR_DOMAIN_DEVICE_REDIRDEV: - case VIR_DOMAIN_DEVICE_SMARTCARD: - case VIR_DOMAIN_DEVICE_MEMBALLOON: - case VIR_DOMAIN_DEVICE_NVRAM: - case VIR_DOMAIN_DEVICE_RNG: - case VIR_DOMAIN_DEVICE_SHMEM: - case VIR_DOMAIN_DEVICE_TPM: - case VIR_DOMAIN_DEVICE_PANIC: - case VIR_DOMAIN_DEVICE_IOMMU: - case VIR_DOMAIN_DEVICE_AUDIO: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Cloud-Hypervisor doesn't support '%s' device"), - virDomainDeviceTypeToString(dev->type)); - return -1; + switch ((virDomainDeviceType) dev->type) { + case VIR_DOMAIN_DEVICE_DISK: + case VIR_DOMAIN_DEVICE_NET: + case VIR_DOMAIN_DEVICE_MEMORY: + case VIR_DOMAIN_DEVICE_VSOCK: + case VIR_DOMAIN_DEVICE_CONTROLLER: + case VIR_DOMAIN_DEVICE_CHR: + break; + + case VIR_DOMAIN_DEVICE_LEASE: + case VIR_DOMAIN_DEVICE_FS: + case VIR_DOMAIN_DEVICE_INPUT: + case VIR_DOMAIN_DEVICE_SOUND: + case VIR_DOMAIN_DEVICE_VIDEO: + case VIR_DOMAIN_DEVICE_HOSTDEV: + case VIR_DOMAIN_DEVICE_WATCHDOG: + case VIR_DOMAIN_DEVICE_GRAPHICS: + case VIR_DOMAIN_DEVICE_HUB: + case VIR_DOMAIN_DEVICE_REDIRDEV: + case VIR_DOMAIN_DEVICE_SMARTCARD: + case VIR_DOMAIN_DEVICE_MEMBALLOON: + case VIR_DOMAIN_DEVICE_NVRAM: + case VIR_DOMAIN_DEVICE_RNG: + case VIR_DOMAIN_DEVICE_SHMEM: + case VIR_DOMAIN_DEVICE_TPM: + case VIR_DOMAIN_DEVICE_PANIC: + case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cloud-Hypervisor doesn't support '%s' device"), + virDomainDeviceTypeToString(dev->type)); + return -1; - case VIR_DOMAIN_DEVICE_NONE: - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("unexpected VIR_DOMAIN_DEVICE_NONE")); - return -1; + case VIR_DOMAIN_DEVICE_NONE: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("unexpected VIR_DOMAIN_DEVICE_NONE")); + return -1; - case VIR_DOMAIN_DEVICE_LAST: - default: - virReportEnumRangeError(virDomainDeviceType, dev->type); - return -1; + case VIR_DOMAIN_DEVICE_LAST: + default: + virReportEnumRangeError(virDomainDeviceType, dev->type); + return -1; } if ((def->nconsoles && @@ -258,25 +251,30 @@ chValidateDomainDeviceDef(const virDomainDeviceDef *dev, && (def->nserials && def->serials[0]->source->type == VIR_DOMAIN_CHR_TYPE_PTY)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Only a single console or serial can be configured for this domain")); + _ + ("Only a single console or serial can be configured for this domain")); return -1; } else if (def->nconsoles > 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Only a single console can be configured for this domain")); + _ + ("Only a single console can be configured for this domain")); return -1; } else if (def->nserials > 1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Only a single serial can be configured for this domain")); + _ + ("Only a single serial can be configured for this domain")); return -1; } - if (def->nconsoles && def->consoles[0]->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { + if (def->nconsoles + && def->consoles[0]->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Console can only be enabled for a PTY")); return -1; } - if (def->nserials && def->serials[0]->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { + if (def->nserials + && def->serials[0]->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Serial can only be enabled for a PTY")); return -1; -- 2.27.0

On a Thursday in 2021, Praveen K Paladugu wrote:
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 130 ++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 66 deletions(-)
diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index dd4de9e1ea..44f7d26ca4 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -30,16 +30,12 @@
static int -virCHDomainObjInitJob(virCHDomainObjPrivate *priv) +virCHDomainObjInitJob(virCHDomainObjPrivate * priv)
The prevailing style in libvirt codebase is no space after the '*'
{ memset(&priv->job, 0, sizeof(priv->job));
[...]
- if (def->nserials && def->serials[0]->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { + if (def->nserials + && def->serials[0]->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Serial can only be enabled for a PTY")); return -1;
80 columns is not a hard limit, there's no need to touch this. Jano
-- 2.27.0

On 12/3/2021 11:28 AM, Ján Tomko wrote:
On a Thursday in 2021, Praveen K Paladugu wrote:
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 130 ++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 66 deletions(-)
diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index dd4de9e1ea..44f7d26ca4 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -30,16 +30,12 @@
static int -virCHDomainObjInitJob(virCHDomainObjPrivate *priv) +virCHDomainObjInitJob(virCHDomainObjPrivate * priv)
The prevailing style in libvirt codebase is no space after the '*'
Fixed in v3
{ memset(&priv->job, 0, sizeof(priv->job));
[...]
- if (def->nserials && def->serials[0]->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { + if (def->nserials + && def->serials[0]->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Serial can only be enabled for a PTY")); return -1;
80 columns is not a hard limit, there's no need to touch this.
Addressed in v3
Jano
-- 2.27.0
-- Regards, Praveen K Paladugu

From: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 6 ++++++ src/ch/ch_domain.h | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index 44f7d26ca4..7bfe950822 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -288,3 +288,9 @@ virDomainDefParserConfig virCHDriverDomainDefParserConfig = { .domainPostParseCallback = virCHDomainDefPostParse, .deviceValidateCallback = chValidateDomainDeviceDef, }; + +virCHMonitor * +virCHDomainGetMonitor(virDomainObj * vm) +{ + return CH_DOMAIN_PRIVATE(vm)->monitor; +} diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h index 61b34b0467..04d19398b4 100644 --- a/src/ch/ch_domain.h +++ b/src/ch/ch_domain.h @@ -57,6 +57,11 @@ struct _virCHDomainObjPrivate { virChrdevs *chrdevs; }; +#define CH_DOMAIN_PRIVATE(vm) \ + ((virCHDomainObjPrivate *) (vm)->privateData) + +virCHMonitor *virCHDomainGetMonitor(virDomainObj *vm); + extern virDomainXMLPrivateDataCallbacks virCHDriverPrivateDataCallbacks; extern virDomainDefParserConfig virCHDriverDomainDefParserConfig; -- 2.27.0

From: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 50 +++++++++++++++++++++++++++++++++++++++++----- src/ch/ch_domain.h | 11 ++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index 7bfe950822..2769d758fe 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -159,11 +159,6 @@ virCHDomainObjPrivateFree(void *data) g_free(priv); } -virDomainXMLPrivateDataCallbacks virCHDriverPrivateDataCallbacks = { - .alloc = virCHDomainObjPrivateAlloc, - .free = virCHDomainObjPrivateFree, -}; - static int virCHDomainDefPostParseBasic(virDomainDef * def, void *opaque G_GNUC_UNUSED) { @@ -179,6 +174,45 @@ virCHDomainDefPostParseBasic(virDomainDef * def, void *opaque G_GNUC_UNUSED) return 0; } +static virClass *virCHDomainVcpuPrivateClass; +static void virCHDomainVcpuPrivateDispose(void *obj); + +static int +virCHDomainVcpuPrivateOnceInit(void) +{ + if (!VIR_CLASS_NEW(virCHDomainVcpuPrivate, virClassForObject())) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virCHDomainVcpuPrivate); + +static virObject * +virCHDomainVcpuPrivateNew(void) +{ + virCHDomainVcpuPrivate *priv; + + if (virCHDomainVcpuPrivateInitialize() < 0) + return NULL; + + if (!(priv = virObjectNew(virCHDomainVcpuPrivateClass))) + return NULL; + + return (virObject *) priv; +} + + +static void +virCHDomainVcpuPrivateDispose(void *obj) +{ + virCHDomainVcpuPrivate *priv = obj; + + priv->tid = 0; + + return; +} + static int virCHDomainDefPostParse(virDomainDef * def, unsigned int parseFlags G_GNUC_UNUSED, @@ -196,6 +230,12 @@ virCHDomainDefPostParse(virDomainDef * def, return 0; } +virDomainXMLPrivateDataCallbacks virCHDriverPrivateDataCallbacks = { + .alloc = virCHDomainObjPrivateAlloc, + .free = virCHDomainObjPrivateFree, + .vcpuNew = virCHDomainVcpuPrivateNew, +}; + static int chValidateDomainDeviceDef(const virDomainDeviceDef * dev, const virDomainDef * def G_GNUC_UNUSED, diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h index 04d19398b4..75b9933130 100644 --- a/src/ch/ch_domain.h +++ b/src/ch/ch_domain.h @@ -62,6 +62,17 @@ struct _virCHDomainObjPrivate { virCHMonitor *virCHDomainGetMonitor(virDomainObj *vm); +typedef struct _virCHDomainVcpuPrivate virCHDomainVcpuPrivate; +struct _virCHDomainVcpuPrivate { + virObject parent; + + pid_t tid; /* vcpu thread id */ + virTristateBool halted; +}; + +#define CH_DOMAIN_VCPU_PRIVATE(vcpu) \ + ((virCHDomainVcpuPrivate *) (vcpu)->privateData) + extern virDomainXMLPrivateDataCallbacks virCHDriverPrivateDataCallbacks; extern virDomainDefParserConfig virCHDriverDomainDefParserConfig; -- 2.27.0

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_driver.c | 241 +++++++++++++++++++++++---------------------- 1 file changed, 121 insertions(+), 120 deletions(-) diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 464bcef907..75c6a15dd6 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -50,7 +50,7 @@ VIR_LOG_INIT("ch.ch_driver"); virCHDriver *ch_driver = NULL; static virDomainObj * -chDomObjFromDomain(virDomain *domain) +chDomObjFromDomain(virDomain * domain) { virDomainObj *vm; virCHDriver *driver = domain->conn->privateData; @@ -79,10 +79,10 @@ chConnectURIProbe(char **uri) return 1; } -static virDrvOpenStatus chConnectOpen(virConnectPtr conn, - virConnectAuthPtr auth G_GNUC_UNUSED, - virConf *conf G_GNUC_UNUSED, - unsigned int flags) +static virDrvOpenStatus +chConnectOpen(virConnectPtr conn, + virConnectAuthPtr auth G_GNUC_UNUSED, + virConf * conf G_GNUC_UNUSED, unsigned int flags) { virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); @@ -101,13 +101,15 @@ static virDrvOpenStatus chConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_SUCCESS; } -static int chConnectClose(virConnectPtr conn) +static int +chConnectClose(virConnectPtr conn) { conn->privateData = NULL; return 0; } -static const char *chConnectGetType(virConnectPtr conn) +static const char * +chConnectGetType(virConnectPtr conn) { if (virConnectGetTypeEnsureACL(conn) < 0) return NULL; @@ -115,8 +117,8 @@ static const char *chConnectGetType(virConnectPtr conn) return "CH"; } -static int chConnectGetVersion(virConnectPtr conn, - unsigned long *version) +static int +chConnectGetVersion(virConnectPtr conn, unsigned long *version) { virCHDriver *driver = conn->privateData; @@ -129,7 +131,8 @@ static int chConnectGetVersion(virConnectPtr conn, return 0; } -static char *chConnectGetHostname(virConnectPtr conn) +static char * +chConnectGetHostname(virConnectPtr conn) { if (virConnectGetHostnameEnsureACL(conn) < 0) return NULL; @@ -137,7 +140,8 @@ static char *chConnectGetHostname(virConnectPtr conn) return virGetHostname(); } -static int chConnectNumOfDomains(virConnectPtr conn) +static int +chConnectNumOfDomains(virConnectPtr conn) { virCHDriver *driver = conn->privateData; @@ -148,7 +152,8 @@ static int chConnectNumOfDomains(virConnectPtr conn) virConnectNumOfDomainsCheckACL, conn); } -static int chConnectListDomains(virConnectPtr conn, int *ids, int nids) +static int +chConnectListDomains(virConnectPtr conn, int *ids, int nids) { virCHDriver *driver = conn->privateData; @@ -156,13 +161,12 @@ static int chConnectListDomains(virConnectPtr conn, int *ids, int nids) return -1; return virDomainObjListGetActiveIDs(driver->domains, ids, nids, - virConnectListDomainsCheckACL, conn); + virConnectListDomainsCheckACL, conn); } static int chConnectListAllDomains(virConnectPtr conn, - virDomainPtr **domains, - unsigned int flags) + virDomainPtr ** domains, unsigned int flags) { virCHDriver *driver = conn->privateData; @@ -172,11 +176,11 @@ chConnectListAllDomains(virConnectPtr conn, return -1; return virDomainObjListExport(driver->domains, conn, domains, - virConnectListAllDomainsCheckACL, flags); + virConnectListAllDomainsCheckACL, flags); } -static int chNodeGetInfo(virConnectPtr conn, - virNodeInfoPtr nodeinfo) +static int +chNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo) { if (virNodeGetInfoEnsureACL(conn) < 0) return -1; @@ -184,7 +188,8 @@ static int chNodeGetInfo(virConnectPtr conn, return virCapabilitiesGetNodeInfo(nodeinfo); } -static char *chConnectGetCapabilities(virConnectPtr conn) +static char * +chConnectGetCapabilities(virConnectPtr conn) { virCHDriver *driver = conn->privateData; virCaps *caps; @@ -213,9 +218,7 @@ static char *chConnectGetCapabilities(virConnectPtr conn) * Returns a new domain object or NULL in case of failure. */ static virDomainPtr -chDomainCreateXML(virConnectPtr conn, - const char *xml, - unsigned int flags) +chDomainCreateXML(virConnectPtr conn, const char *xml, unsigned int flags) { virCHDriver *driver = conn->privateData; virDomainDef *vmdef = NULL; @@ -240,8 +243,7 @@ chDomainCreateXML(virConnectPtr conn, &vmdef, driver->xmlopt, VIR_DOMAIN_OBJ_LIST_ADD_LIVE | - VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, - NULL))) + VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, NULL))) goto cleanup; if (virCHDomainObjBeginJob(vm, CH_JOB_MODIFY) < 0) @@ -343,8 +345,7 @@ chDomainDefineXML(virConnectPtr conn, const char *xml) } static int -chDomainUndefineFlags(virDomainPtr dom, - unsigned int flags) +chDomainUndefineFlags(virDomainPtr dom, unsigned int flags) { virCHDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -383,7 +384,8 @@ chDomainUndefine(virDomainPtr dom) return chDomainUndefineFlags(dom, 0); } -static int chDomainIsActive(virDomainPtr dom) +static int +chDomainIsActive(virDomainPtr dom) { virCHDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -405,8 +407,7 @@ static int chDomainIsActive(virDomainPtr dom) } static int -chDomainShutdownFlags(virDomainPtr dom, - unsigned int flags) +chDomainShutdownFlags(virDomainPtr dom, unsigned int flags) { virCHDomainObjPrivate *priv; virDomainObj *vm; @@ -437,7 +438,7 @@ chDomainShutdownFlags(virDomainPtr dom, } else { if (virCHMonitorShutdownVM(priv->monitor) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to shutdown guest VM")); + _("failed to shutdown guest VM")); goto endjob; } } @@ -501,7 +502,8 @@ chDomainReboot(virDomainPtr dom, unsigned int flags) if (state == VIR_DOMAIN_RUNNING) virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED); else - virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED); + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_UNPAUSED); ret = 0; @@ -541,7 +543,7 @@ chDomainSuspend(virDomainPtr dom) } else { if (virCHMonitorSuspendVM(priv->monitor) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to suspend domain")); + _("failed to suspend domain")); goto endjob; } } @@ -586,7 +588,7 @@ chDomainResume(virDomainPtr dom) } else { if (virCHMonitorResumeVM(priv->monitor) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to resume domain")); + _("failed to resume domain")); goto endjob; } } @@ -651,8 +653,8 @@ chDomainDestroy(virDomainPtr dom) return chDomainDestroyFlags(dom, 0); } -static virDomainPtr chDomainLookupByID(virConnectPtr conn, - int id) +static virDomainPtr +chDomainLookupByID(virConnectPtr conn, int id) { virCHDriver *driver = conn->privateData; virDomainObj *vm; @@ -678,8 +680,8 @@ static virDomainPtr chDomainLookupByID(virConnectPtr conn, return dom; } -static virDomainPtr chDomainLookupByName(virConnectPtr conn, - const char *name) +static virDomainPtr +chDomainLookupByName(virConnectPtr conn, const char *name) { virCHDriver *driver = conn->privateData; virDomainObj *vm; @@ -705,8 +707,8 @@ static virDomainPtr chDomainLookupByName(virConnectPtr conn, return dom; } -static virDomainPtr chDomainLookupByUUID(virConnectPtr conn, - const unsigned char *uuid) +static virDomainPtr +chDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { virCHDriver *driver = conn->privateData; virDomainObj *vm; @@ -718,6 +720,7 @@ static virDomainPtr chDomainLookupByUUID(virConnectPtr conn, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(uuid, uuidstr); virReportError(VIR_ERR_NO_DOMAIN, _("no domain with matching uuid '%s'"), uuidstr); @@ -735,10 +738,7 @@ static virDomainPtr chDomainLookupByUUID(virConnectPtr conn, } static int -chDomainGetState(virDomainPtr dom, - int *state, - int *reason, - unsigned int flags) +chDomainGetState(virDomainPtr dom, int *state, int *reason, unsigned int flags) { virDomainObj *vm; int ret = -1; @@ -759,8 +759,8 @@ chDomainGetState(virDomainPtr dom, return ret; } -static char *chDomainGetXMLDesc(virDomainPtr dom, - unsigned int flags) +static char * +chDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) { virCHDriver *driver = dom->conn->privateData; virDomainObj *vm; @@ -782,8 +782,8 @@ static char *chDomainGetXMLDesc(virDomainPtr dom, return ret; } -static int chDomainGetInfo(virDomainPtr dom, - virDomainInfoPtr info) +static int +chDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { virDomainObj *vm; int ret = -1; @@ -811,77 +811,76 @@ static int chDomainGetInfo(virDomainPtr dom, static int chDomainOpenConsole(virDomainPtr dom, - const char *dev_name, - virStreamPtr st, - unsigned int flags) -{ - virDomainObj *vm = NULL; - int ret = -1; - size_t i; - virDomainChrDef *chr = NULL; - virCHDomainObjPrivate *priv; - - virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE | VIR_DOMAIN_CONSOLE_FORCE, -1); - - if (!(vm = chDomObjFromDomain(dom))) - goto cleanup; - - if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0) - goto cleanup; - - if (virDomainObjCheckActive(vm) < 0) - goto cleanup; - - priv = vm->privateData; - - if (dev_name) { - for (i = 0; !chr && i < vm->def->nconsoles; i++) { - if (vm->def->consoles[i]->info.alias && - STREQ(dev_name, vm->def->consoles[i]->info.alias)) - chr = vm->def->consoles[i]; - } - for (i = 0; !chr && i < vm->def->nserials; i++) { - if (STREQ(dev_name, vm->def->serials[i]->info.alias)) - chr = vm->def->serials[i]; - } - } else { - if (vm->def->nconsoles && - vm->def->consoles[0]->source->type == VIR_DOMAIN_CHR_TYPE_PTY) - chr = vm->def->consoles[0]; - else if (vm->def->nserials && - vm->def->serials[0]->source->type == VIR_DOMAIN_CHR_TYPE_PTY) - chr = vm->def->serials[0]; - } - - if (!chr) { - virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot find character device %s"), - NULLSTR(dev_name)); - goto cleanup; - } - - if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("character device %s is not using a PTY"), - dev_name ? dev_name : NULLSTR(chr->info.alias)); - goto cleanup; - } - - /* handle mutually exclusive access to console devices */ - ret = virChrdevOpen(priv->chrdevs, chr->source, st, - (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0); - - if (ret == 1) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", - _("Active console session exists for this domain")); - ret = -1; - } + const char *dev_name, virStreamPtr st, unsigned int flags) +{ + virDomainObj *vm = NULL; + int ret = -1; + size_t i; + virDomainChrDef *chr = NULL; + virCHDomainObjPrivate *priv; + + virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE | VIR_DOMAIN_CONSOLE_FORCE, -1); + + if (!(vm = chDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (virDomainObjCheckActive(vm) < 0) + goto cleanup; + + priv = vm->privateData; + + if (dev_name) { + for (i = 0; !chr && i < vm->def->nconsoles; i++) { + if (vm->def->consoles[i]->info.alias && + STREQ(dev_name, vm->def->consoles[i]->info.alias)) + chr = vm->def->consoles[i]; + } + for (i = 0; !chr && i < vm->def->nserials; i++) { + if (STREQ(dev_name, vm->def->serials[i]->info.alias)) + chr = vm->def->serials[i]; + } + } else { + if (vm->def->nconsoles && + vm->def->consoles[0]->source->type == VIR_DOMAIN_CHR_TYPE_PTY) + chr = vm->def->consoles[0]; + else if (vm->def->nserials && + vm->def->serials[0]->source->type == VIR_DOMAIN_CHR_TYPE_PTY) + chr = vm->def->serials[0]; + } + + if (!chr) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find character device %s"), NULLSTR(dev_name)); + goto cleanup; + } + + if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("character device %s is not using a PTY"), + dev_name ? dev_name : NULLSTR(chr->info.alias)); + goto cleanup; + } + + /* handle mutually exclusive access to console devices */ + ret = virChrdevOpen(priv->chrdevs, chr->source, st, + (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0); + + if (ret == 1) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Active console session exists for this domain")); + ret = -1; + } cleanup: - virDomainObjEndAPI(&vm); - return ret; + virDomainObjEndAPI(&vm); + return ret; } -static int chStateCleanup(void) +static int +chStateCleanup(void) { if (ch_driver == NULL) return -1; @@ -897,10 +896,11 @@ static int chStateCleanup(void) return 0; } -static int chStateInitialize(bool privileged, - const char *root, - virStateInhibitCallback callback G_GNUC_UNUSED, - void *opaque G_GNUC_UNUSED) +static int +chStateInitialize(bool privileged, + const char *root, + virStateInhibitCallback callback G_GNUC_UNUSED, + void *opaque G_GNUC_UNUSED) { int ret = VIR_DRV_STATE_INIT_ERROR; int rv; @@ -984,7 +984,7 @@ static virHypervisorDriver chHypervisorDriver = { static virConnectDriver chConnectDriver = { .localOnly = true, - .uriSchemes = (const char *[]){"ch", NULL}, + .uriSchemes = (const char *[]) {"ch", NULL}, .hypervisorDriver = &chHypervisorDriver, }; @@ -994,7 +994,8 @@ static virStateDriver chStateDriver = { .stateCleanup = chStateCleanup, }; -int chRegister(void) +int +chRegister(void) { if (virRegisterConnectDriver(&chConnectDriver, true) < 0) return -1; -- 2.27.0

Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 25 +++++++++ src/ch/ch_domain.h | 4 ++ src/ch/ch_driver.c | 137 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index 2769d758fe..d81221679e 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -334,3 +334,28 @@ virCHDomainGetMonitor(virDomainObj * vm) { return CH_DOMAIN_PRIVATE(vm)->monitor; } + +pid_t +virCHDomainGetVcpuPid(virDomainObj * vm, unsigned int vcpuid) +{ + virDomainVcpuDef *vcpu = virDomainDefGetVcpu(vm->def, vcpuid); + + return CH_DOMAIN_VCPU_PRIVATE(vcpu)->tid; +} + +bool +virCHDomainHasVcpuPids(virDomainObj * vm) +{ + size_t i; + size_t maxvcpus = virDomainDefGetVcpusMax(vm->def); + virDomainVcpuDef *vcpu; + + for (i = 0; i < maxvcpus; i++) { + vcpu = virDomainDefGetVcpu(vm->def, i); + + if (CH_DOMAIN_VCPU_PRIVATE(vcpu)->tid > 0) + return true; + } + + return false; +} diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h index 75b9933130..d9c9d34a19 100644 --- a/src/ch/ch_domain.h +++ b/src/ch/ch_domain.h @@ -82,3 +82,7 @@ virCHDomainObjBeginJob(virDomainObj *obj, enum virCHDomainJob job) void virCHDomainObjEndJob(virDomainObj *obj); + +int virCHDomainRefreshVcpuInfo(virDomainObj *vm); +pid_t virCHDomainGetVcpuPid(virDomainObj *vm, unsigned int vcpuid); +bool virCHDomainHasVcpuPids(virDomainObj *vm); diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 75c6a15dd6..52c88571af 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -944,6 +944,140 @@ chStateInitialize(bool privileged, return ret; } +static int +chDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) +{ + virDomainObj *vm; + virDomainDef *def; + int ret = -1; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG | + VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_GUEST, -1); + + if (!(vm = chDomObjFromDomain(dom))) + return -1; + + if (virDomainGetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0) + goto cleanup; + + if (!(def = virDomainObjGetOneDef(vm, flags))) + goto cleanup; + + if (flags & VIR_DOMAIN_VCPU_MAXIMUM) + ret = virDomainDefGetVcpusMax(def); + else + ret = virDomainDefGetVcpus(def); + + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + +static int +chDomainGetMaxVcpus(virDomainPtr dom) +{ + return chDomainGetVcpusFlags(dom, + (VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_VCPU_MAXIMUM)); +} + +static int +chDomainHelperGetVcpus(virDomainObj * vm, + virVcpuInfoPtr info, + unsigned long long *cpuwait, + int maxinfo, unsigned char *cpumaps, int maplen) +{ + size_t ncpuinfo = 0; + size_t i; + + if (maxinfo == 0) + return 0; + + if (!virCHDomainHasVcpuPids(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cpu affinity is not supported")); + return -1; + } + + if (info) + memset(info, 0, sizeof(*info) * maxinfo); + + if (cpumaps) + memset(cpumaps, 0, sizeof(*cpumaps) * maxinfo); + + for (i = 0; i < virDomainDefGetVcpusMax(vm->def) && ncpuinfo < maxinfo; i++) { + virDomainVcpuDef *vcpu = virDomainDefGetVcpu(vm->def, i); + pid_t vcpupid = virCHDomainGetVcpuPid(vm, i); + virVcpuInfoPtr vcpuinfo = info + ncpuinfo; + + if (!vcpu->online) + continue; + + if (info) { + vcpuinfo->number = i; + vcpuinfo->state = VIR_VCPU_RUNNING; + if (virProcessGetStatInfo(&vcpuinfo->cpuTime, + &vcpuinfo->cpu, NULL, + vm->pid, vcpupid) < 0) { + virReportSystemError(errno, "%s", + _ + ("cannot get vCPU placement & pCPU time")); + return -1; + } + } + + if (cpumaps) { + unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, ncpuinfo); + g_autoptr(virBitmap) map = NULL; + + if (!(map = virProcessGetAffinity(vcpupid))) + return -1; + + virBitmapToDataBuf(map, cpumap, maplen); + } + + if (cpuwait) { + if (virProcessGetSchedInfo(&(cpuwait[ncpuinfo]), vm->pid, vcpupid) < + 0) + return -1; + } + + ncpuinfo++; + } + + return ncpuinfo; +} + +static int +chDomainGetVcpus(virDomainPtr dom, + virVcpuInfoPtr info, + int maxinfo, unsigned char *cpumaps, int maplen) +{ + virDomainObj *vm; + int ret = -1; + + if (!(vm = chDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainGetVcpusEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (virDomainObjCheckActive(vm) < 0) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _ + ("cannot retrieve vcpu information for inactive domain")); + goto cleanup; + } + + ret = chDomainHelperGetVcpus(vm, info, NULL, maxinfo, cpumaps, maplen); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + /* Function Tables */ static virHypervisorDriver chHypervisorDriver = { .name = "CH", @@ -980,6 +1114,9 @@ static virHypervisorDriver chHypervisorDriver = { .domainIsActive = chDomainIsActive, /* 7.5.0 */ .domainOpenConsole = chDomainOpenConsole, /* 7.8.0 */ .nodeGetInfo = chNodeGetInfo, /* 7.5.0 */ + .domainGetVcpus = chDomainGetVcpus, /* 7.11.0 */ + .domainGetVcpusFlags = chDomainGetVcpusFlags, /* 7.11.0 */ + .domainGetMaxVcpus = chDomainGetMaxVcpus, /* 7.11.0 */ }; static virConnectDriver chConnectDriver = { -- 2.27.0

On a Thursday in 2021, Praveen K Paladugu wrote:
Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 25 +++++++++ src/ch/ch_domain.h | 4 ++ src/ch/ch_driver.c | 137 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+)
/* Function Tables */ static virHypervisorDriver chHypervisorDriver = { .name = "CH", @@ -980,6 +1114,9 @@ static virHypervisorDriver chHypervisorDriver = { .domainIsActive = chDomainIsActive, /* 7.5.0 */ .domainOpenConsole = chDomainOpenConsole, /* 7.8.0 */ .nodeGetInfo = chNodeGetInfo, /* 7.5.0 */ + .domainGetVcpus = chDomainGetVcpus, /* 7.11.0 */ + .domainGetVcpusFlags = chDomainGetVcpusFlags, /* 7.11.0 */ + .domainGetMaxVcpus = chDomainGetMaxVcpus, /* 7.11.0 */
Next release (mid-January) will be 8.0.0. There's no such thing as 7.11.0 - the major is incremented every year and there are only 10 releases per year: https://libvirt.org/downloads.html#numbering Jano

From: Vineeth Pillai <viremana@linux.microsoft.com> Add domainGetVcpuPinInfo and nodeGetCPUMap callbacks to ch driver Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.h | 12 +++++++++-- src/ch/ch_driver.c | 54 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h index d9c9d34a19..e35777a9ec 100644 --- a/src/ch/ch_domain.h +++ b/src/ch/ch_domain.h @@ -23,6 +23,7 @@ #include "ch_conf.h" #include "ch_monitor.h" #include "virchrdev.h" +#include "vircgroup.h" /* Give up waiting for mutex after 30 seconds */ #define CH_JOB_WAIT_TIME (1000ull * 30) @@ -52,9 +53,16 @@ typedef struct _virCHDomainObjPrivate virCHDomainObjPrivate; struct _virCHDomainObjPrivate { struct virCHDomainJobObj job; - virCHMonitor *monitor; + virChrdevs *chrdevs; + + virCgroup *cgroup; - virChrdevs *chrdevs; + virCHDriver *driver; + virCHMonitor *monitor; + char *machineName; + virBitmap *autoNodeset; + virBitmap *autoCpuset; + virChrdevs *devs; }; #define CH_DOMAIN_PRIVATE(vm) \ diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 52c88571af..86d2776354 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -984,7 +984,56 @@ chDomainGetMaxVcpus(virDomainPtr dom) } static int -chDomainHelperGetVcpus(virDomainObj * vm, +chDomainGetVcpuPinInfo(virDomain * dom, + int ncpumaps, + unsigned char *cpumaps, int maplen, unsigned int flags) +{ + virDomainObj *vm = NULL; + virDomainDef *def; + bool live; + int ret = -1; + + g_autoptr(virBitmap) hostcpus = NULL; + virBitmap *autoCpuset = NULL; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1); + + if (!(vm = chDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainGetVcpuPinInfoEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (!(def = virDomainObjGetOneDefState(vm, flags, &live))) + goto cleanup; + + if (!(hostcpus = virHostCPUGetAvailableCPUsBitmap())) + goto cleanup; + + if (live) + autoCpuset = CH_DOMAIN_PRIVATE(vm)->autoCpuset; + + ret = virDomainDefGetVcpuPinInfoHelper(def, maplen, ncpumaps, cpumaps, + hostcpus, autoCpuset); + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + +static int +chNodeGetCPUMap(virConnectPtr conn, + unsigned char **cpumap, + unsigned int *online, unsigned int flags) +{ + if (virNodeGetCPUMapEnsureACL(conn) < 0) + return -1; + + return virHostCPUGetMap(cpumap, online, flags); +} + + +static int +chDomainHelperGetVcpus(virDomainObj *vm, virVcpuInfoPtr info, unsigned long long *cpuwait, int maxinfo, unsigned char *cpumaps, int maplen) @@ -1030,6 +1079,7 @@ chDomainHelperGetVcpus(virDomainObj * vm, if (cpumaps) { unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, ncpuinfo); + g_autoptr(virBitmap) map = NULL; if (!(map = virProcessGetAffinity(vcpupid))) @@ -1117,6 +1167,8 @@ static virHypervisorDriver chHypervisorDriver = { .domainGetVcpus = chDomainGetVcpus, /* 7.11.0 */ .domainGetVcpusFlags = chDomainGetVcpusFlags, /* 7.11.0 */ .domainGetMaxVcpus = chDomainGetMaxVcpus, /* 7.11.0 */ + .domainGetVcpuPinInfo = chDomainGetVcpuPinInfo, /* 7.11.0 */ + .nodeGetCPUMap = chNodeGetCPUMap, /* 7.11.0 */ }; static virConnectDriver chConnectDriver = { -- 2.27.0

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_monitor.c | 301 +++++++++++++++++++++++--------------------- 1 file changed, 161 insertions(+), 140 deletions(-) diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 12c10da874..68fa5b30aa 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -42,7 +42,8 @@ VIR_LOG_INIT("ch.ch_monitor"); static virClass *virCHMonitorClass; static void virCHMonitorDispose(void *obj); -static int virCHMonitorOnceInit(void) +static int +virCHMonitorOnceInit(void) { if (!VIR_CLASS_NEW(virCHMonitor, virClassForObjectLockable())) return -1; @@ -52,11 +53,11 @@ static int virCHMonitorOnceInit(void) VIR_ONCE_GLOBAL_INIT(virCHMonitor); -int virCHMonitorShutdownVMM(virCHMonitor *mon); -int virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint); +int virCHMonitorShutdownVMM(virCHMonitor * mon); +int virCHMonitorPutNoContent(virCHMonitor * mon, const char *endpoint); static int -virCHMonitorBuildCPUJson(virJSONValue *content, virDomainDef *vmdef) +virCHMonitorBuildCPUJson(virJSONValue * content, virDomainDef * vmdef) { g_autoptr(virJSONValue) cpus = NULL; unsigned int maxvcpus = 0; @@ -64,7 +65,7 @@ virCHMonitorBuildCPUJson(virJSONValue *content, virDomainDef *vmdef) virDomainVcpuDef *vcpu; size_t i; - /* count maximum allowed number vcpus and enabled vcpus when boot.*/ + /* count maximum allowed number vcpus and enabled vcpus when boot. */ maxvcpus = virDomainDefGetVcpusMax(vmdef); for (i = 0; i < maxvcpus; i++) { vcpu = virDomainDefGetVcpu(vmdef, i); @@ -76,7 +77,8 @@ virCHMonitorBuildCPUJson(virJSONValue *content, virDomainDef *vmdef) cpus = virJSONValueNewObject(); if (virJSONValueObjectAppendNumberInt(cpus, "boot_vcpus", nvcpus) < 0) return -1; - if (virJSONValueObjectAppendNumberInt(cpus, "max_vcpus", vmdef->maxvcpus) < 0) + if (virJSONValueObjectAppendNumberInt + (cpus, "max_vcpus", vmdef->maxvcpus) < 0) return -1; if (virJSONValueObjectAppend(content, "cpus", &cpus) < 0) return -1; @@ -86,7 +88,7 @@ virCHMonitorBuildCPUJson(virJSONValue *content, virDomainDef *vmdef) } static int -virCHMonitorBuildPTYJson(virJSONValue *content, virDomainDef *vmdef) +virCHMonitorBuildPTYJson(virJSONValue * content, virDomainDef * vmdef) { if (vmdef->nconsoles) { g_autoptr(virJSONValue) pty = virJSONValueNewObject(); @@ -108,7 +110,7 @@ virCHMonitorBuildPTYJson(virJSONValue *content, virDomainDef *vmdef) } static int -virCHMonitorBuildKernelRelatedJson(virJSONValue *content, virDomainDef *vmdef) +virCHMonitorBuildKernelRelatedJson(virJSONValue * content, virDomainDef * vmdef) { g_autoptr(virJSONValue) kernel = virJSONValueNewObject(); g_autoptr(virJSONValue) cmdline = virJSONValueNewObject(); @@ -119,21 +121,24 @@ virCHMonitorBuildKernelRelatedJson(virJSONValue *content, virDomainDef *vmdef) _("Kernel image path in this domain is not defined")); return -1; } else { - if (virJSONValueObjectAppendString(kernel, "path", vmdef->os.kernel) < 0) + if (virJSONValueObjectAppendString(kernel, "path", vmdef->os.kernel) < + 0) return -1; if (virJSONValueObjectAppend(content, "kernel", &kernel) < 0) return -1; } if (vmdef->os.cmdline) { - if (virJSONValueObjectAppendString(cmdline, "args", vmdef->os.cmdline) < 0) + if (virJSONValueObjectAppendString(cmdline, "args", vmdef->os.cmdline) < + 0) return -1; if (virJSONValueObjectAppend(content, "cmdline", &cmdline) < 0) return -1; } if (vmdef->os.initrd != NULL) { - if (virJSONValueObjectAppendString(initramfs, "path", vmdef->os.initrd) < 0) + if (virJSONValueObjectAppendString(initramfs, "path", vmdef->os.initrd) + < 0) return -1; if (virJSONValueObjectAppend(content, "initramfs", &initramfs) < 0) return -1; @@ -143,14 +148,16 @@ virCHMonitorBuildKernelRelatedJson(virJSONValue *content, virDomainDef *vmdef) } static int -virCHMonitorBuildMemoryJson(virJSONValue *content, virDomainDef *vmdef) +virCHMonitorBuildMemoryJson(virJSONValue * content, virDomainDef * vmdef) { - unsigned long long total_memory = virDomainDefGetMemoryInitial(vmdef) * 1024; + unsigned long long total_memory = + virDomainDefGetMemoryInitial(vmdef) * 1024; if (total_memory != 0) { g_autoptr(virJSONValue) memory = virJSONValueNewObject(); - if (virJSONValueObjectAppendNumberUlong(memory, "size", total_memory) < 0) + if (virJSONValueObjectAppendNumberUlong(memory, "size", total_memory) < + 0) return -1; if (virJSONValueObjectAppend(content, "memory", &memory) < 0) @@ -161,7 +168,7 @@ virCHMonitorBuildMemoryJson(virJSONValue *content, virDomainDef *vmdef) } static int -virCHMonitorBuildDiskJson(virJSONValue *disks, virDomainDiskDef *diskdef) +virCHMonitorBuildDiskJson(virJSONValue * disks, virDomainDiskDef * diskdef) { g_autoptr(virJSONValue) disk = virJSONValueNewObject(); @@ -169,44 +176,47 @@ virCHMonitorBuildDiskJson(virJSONValue *disks, virDomainDiskDef *diskdef) return -1; switch (diskdef->src->type) { - case VIR_STORAGE_TYPE_FILE: - if (!diskdef->src->path) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("Missing disk file path in domain")); - return -1; - } - if (diskdef->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) { - virReportError(VIR_ERR_INVALID_ARG, - _("Only virtio bus types are supported for '%s'"), diskdef->src->path); - return -1; - } - if (virJSONValueObjectAppendString(disk, "path", diskdef->src->path) < 0) - return -1; - if (diskdef->src->readonly) { - if (virJSONValueObjectAppendBoolean(disk, "readonly", true) < 0) + case VIR_STORAGE_TYPE_FILE: + if (!diskdef->src->path) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Missing disk file path in domain")); + return -1; + } + if (diskdef->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) { + virReportError(VIR_ERR_INVALID_ARG, + _ + ("Only virtio bus types are supported for '%s'"), + diskdef->src->path); + return -1; + } + if (virJSONValueObjectAppendString(disk, "path", diskdef->src->path) + < 0) + return -1; + if (diskdef->src->readonly) { + if (virJSONValueObjectAppendBoolean(disk, "readonly", true) < 0) + return -1; + } + if (virJSONValueArrayAppend(disks, &disk) < 0) return -1; - } - if (virJSONValueArrayAppend(disks, &disk) < 0) - return -1; - break; - case VIR_STORAGE_TYPE_NONE: - case VIR_STORAGE_TYPE_BLOCK: - case VIR_STORAGE_TYPE_DIR: - case VIR_STORAGE_TYPE_NETWORK: - case VIR_STORAGE_TYPE_VOLUME: - case VIR_STORAGE_TYPE_NVME: - case VIR_STORAGE_TYPE_VHOST_USER: - default: - virReportEnumRangeError(virStorageType, diskdef->src->type); - return -1; + break; + case VIR_STORAGE_TYPE_NONE: + case VIR_STORAGE_TYPE_BLOCK: + case VIR_STORAGE_TYPE_DIR: + case VIR_STORAGE_TYPE_NETWORK: + case VIR_STORAGE_TYPE_VOLUME: + case VIR_STORAGE_TYPE_NVME: + case VIR_STORAGE_TYPE_VHOST_USER: + default: + virReportEnumRangeError(virStorageType, diskdef->src->type); + return -1; } return 0; } static int -virCHMonitorBuildDisksJson(virJSONValue *content, virDomainDef *vmdef) +virCHMonitorBuildDisksJson(virJSONValue * content, virDomainDef * vmdef) { g_autoptr(virJSONValue) disks = NULL; size_t i; @@ -226,76 +236,86 @@ virCHMonitorBuildDisksJson(virJSONValue *content, virDomainDef *vmdef) } static int -virCHMonitorBuildNetJson(virJSONValue *nets, virDomainNetDef *netdef) +virCHMonitorBuildNetJson(virJSONValue * nets, virDomainNetDef * netdef) { virDomainNetType netType = virDomainNetGetActualType(netdef); char macaddr[VIR_MAC_STRING_BUFLEN]; + g_autoptr(virJSONValue) net = NULL; // check net type at first net = virJSONValueNewObject(); switch (netType) { - case VIR_DOMAIN_NET_TYPE_ETHERNET: - if (netdef->guestIP.nips == 1) { - const virNetDevIPAddr *ip = netdef->guestIP.ips[0]; - g_autofree char *addr = NULL; - virSocketAddr netmask; - g_autofree char *netmaskStr = NULL; - if (!(addr = virSocketAddrFormat(&ip->address))) - return -1; - if (virJSONValueObjectAppendString(net, "ip", addr) < 0) - return -1; - - if (virSocketAddrPrefixToNetmask(ip->prefix, &netmask, AF_INET) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to translate net prefix %d to netmask"), - ip->prefix); - return -1; + case VIR_DOMAIN_NET_TYPE_ETHERNET: + if (netdef->guestIP.nips == 1) { + const virNetDevIPAddr *ip = netdef->guestIP.ips[0]; + g_autofree char *addr = NULL; + virSocketAddr netmask; + g_autofree char *netmaskStr = NULL; + + if (!(addr = virSocketAddrFormat(&ip->address))) + return -1; + if (virJSONValueObjectAppendString(net, "ip", addr) < 0) + return -1; + + if (virSocketAddrPrefixToNetmask(ip->prefix, &netmask, AF_INET) + < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _ + ("Failed to translate net prefix %d to netmask"), + ip->prefix); + return -1; + } + if (!(netmaskStr = virSocketAddrFormat(&netmask))) + return -1; + if (virJSONValueObjectAppendString(net, "mask", netmaskStr) < 0) + return -1; + } else if (netdef->guestIP.nips > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("ethernet type supports a single guest ip")); } - if (!(netmaskStr = virSocketAddrFormat(&netmask))) - return -1; - if (virJSONValueObjectAppendString(net, "mask", netmaskStr) < 0) + break; + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + if ((virDomainChrType) netdef->data.vhostuser->type != + VIR_DOMAIN_CHR_TYPE_UNIX) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _ + ("vhost_user type support UNIX socket in this CH")); return -1; - } else if (netdef->guestIP.nips > 1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("ethernet type supports a single guest ip")); - } - break; - case VIR_DOMAIN_NET_TYPE_VHOSTUSER: - if ((virDomainChrType)netdef->data.vhostuser->type != VIR_DOMAIN_CHR_TYPE_UNIX) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vhost_user type support UNIX socket in this CH")); + } else { + if (virJSONValueObjectAppendString + (net, "vhost_socket", + netdef->data.vhostuser->data.nix.path) < 0) + return -1; + if (virJSONValueObjectAppendBoolean(net, "vhost_user", true) < + 0) + return -1; + } + break; + case VIR_DOMAIN_NET_TYPE_BRIDGE: + case VIR_DOMAIN_NET_TYPE_NETWORK: + case VIR_DOMAIN_NET_TYPE_DIRECT: + case VIR_DOMAIN_NET_TYPE_USER: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_CLIENT: + case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_INTERNAL: + case VIR_DOMAIN_NET_TYPE_HOSTDEV: + case VIR_DOMAIN_NET_TYPE_UDP: + case VIR_DOMAIN_NET_TYPE_VDPA: + case VIR_DOMAIN_NET_TYPE_LAST: + default: + virReportEnumRangeError(virDomainNetType, netType); return -1; - } else { - if (virJSONValueObjectAppendString(net, "vhost_socket", netdef->data.vhostuser->data.nix.path) < 0) - return -1; - if (virJSONValueObjectAppendBoolean(net, "vhost_user", true) < 0) - return -1; - } - break; - case VIR_DOMAIN_NET_TYPE_BRIDGE: - case VIR_DOMAIN_NET_TYPE_NETWORK: - case VIR_DOMAIN_NET_TYPE_DIRECT: - case VIR_DOMAIN_NET_TYPE_USER: - case VIR_DOMAIN_NET_TYPE_SERVER: - case VIR_DOMAIN_NET_TYPE_CLIENT: - case VIR_DOMAIN_NET_TYPE_MCAST: - case VIR_DOMAIN_NET_TYPE_INTERNAL: - case VIR_DOMAIN_NET_TYPE_HOSTDEV: - case VIR_DOMAIN_NET_TYPE_UDP: - case VIR_DOMAIN_NET_TYPE_VDPA: - case VIR_DOMAIN_NET_TYPE_LAST: - default: - virReportEnumRangeError(virDomainNetType, netType); - return -1; } if (netdef->ifname != NULL) { if (virJSONValueObjectAppendString(net, "tap", netdef->ifname) < 0) return -1; } - if (virJSONValueObjectAppendString(net, "mac", virMacAddrFormat(&netdef->mac, macaddr)) < 0) + if (virJSONValueObjectAppendString + (net, "mac", virMacAddrFormat(&netdef->mac, macaddr)) < 0) return -1; @@ -306,19 +326,24 @@ virCHMonitorBuildNetJson(virJSONValue *nets, virDomainNetDef *netdef) } } if (netdef->driver.virtio.queues) { - if (virJSONValueObjectAppendNumberInt(net, "num_queues", netdef->driver.virtio.queues) < 0) + if (virJSONValueObjectAppendNumberInt + (net, "num_queues", netdef->driver.virtio.queues) < 0) return -1; } - if (netdef->driver.virtio.rx_queue_size || netdef->driver.virtio.tx_queue_size) { - if (netdef->driver.virtio.rx_queue_size != netdef->driver.virtio.tx_queue_size) { + if (netdef->driver.virtio.rx_queue_size + || netdef->driver.virtio.tx_queue_size) { + if (netdef->driver.virtio.rx_queue_size != + netdef->driver.virtio.tx_queue_size) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("virtio rx_queue_size option %d is not same with tx_queue_size %d"), - netdef->driver.virtio.rx_queue_size, - netdef->driver.virtio.tx_queue_size); + _ + ("virtio rx_queue_size option %d is not same with tx_queue_size %d"), + netdef->driver.virtio.rx_queue_size, + netdef->driver.virtio.tx_queue_size); return -1; } - if (virJSONValueObjectAppendNumberInt(net, "queue_size", netdef->driver.virtio.rx_queue_size) < 0) + if (virJSONValueObjectAppendNumberInt + (net, "queue_size", netdef->driver.virtio.rx_queue_size) < 0) return -1; } @@ -329,7 +354,7 @@ virCHMonitorBuildNetJson(virJSONValue *nets, virDomainNetDef *netdef) } static int -virCHMonitorBuildNetsJson(virJSONValue *content, virDomainDef *vmdef) +virCHMonitorBuildNetsJson(virJSONValue * content, virDomainDef * vmdef) { g_autoptr(virJSONValue) nets = NULL; size_t i; @@ -349,13 +374,12 @@ virCHMonitorBuildNetsJson(virJSONValue *content, virDomainDef *vmdef) } static int -virCHMonitorBuildVMJson(virDomainDef *vmdef, char **jsonstr) +virCHMonitorBuildVMJson(virDomainDef * vmdef, char **jsonstr) { g_autoptr(virJSONValue) content = virJSONValueNewObject(); if (vmdef == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("VM is not defined")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("VM is not defined")); return -1; } @@ -391,8 +415,7 @@ chMonitorCreateSocket(const char *socket_path) int fd; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - virReportSystemError(errno, "%s", - _("Unable to create UNIX socket")); + virReportSystemError(errno, "%s", _("Unable to create UNIX socket")); goto error; } @@ -400,19 +423,16 @@ chMonitorCreateSocket(const char *socket_path) addr.sun_family = AF_UNIX; if (virStrcpyStatic(addr.sun_path, socket_path) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("UNIX socket path '%s' too long"), - socket_path); + _("UNIX socket path '%s' too long"), socket_path); goto error; } if (unlink(socket_path) < 0 && errno != ENOENT) { - virReportSystemError(errno, - _("Unable to unlink %s"), - socket_path); + virReportSystemError(errno, _("Unable to unlink %s"), socket_path); goto error; } - if (bind(fd, (struct sockaddr *)&addr, addrlen) < 0) { + if (bind(fd, (struct sockaddr *) &addr, addrlen) < 0) { virReportSystemError(errno, _("Unable to bind to UNIX socket path '%s'"), socket_path); @@ -440,7 +460,7 @@ chMonitorCreateSocket(const char *socket_path) } virCHMonitor * -virCHMonitorNew(virDomainObj *vm, const char *socketdir) +virCHMonitorNew(virDomainObj * vm, const char *socketdir) { g_autoptr(virCHMonitor) mon = NULL; g_autoptr(virCommand) cmd = NULL; @@ -453,8 +473,7 @@ virCHMonitorNew(virDomainObj *vm, const char *socketdir) return NULL; if (!vm->def) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("VM is not defined")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("VM is not defined")); return NULL; } @@ -472,8 +491,7 @@ virCHMonitorNew(virDomainObj *vm, const char *socketdir) socket_fd = chMonitorCreateSocket(mon->socketpath); if (socket_fd < 0) { virReportSystemError(errno, - _("Cannot create socket '%s'"), - mon->socketpath); + _("Cannot create socket '%s'"), mon->socketpath); return NULL; } @@ -494,7 +512,8 @@ virCHMonitorNew(virDomainObj *vm, const char *socketdir) return g_steal_pointer(&mon); } -static void virCHMonitorDispose(void *opaque) +static void +virCHMonitorDispose(void *opaque) { virCHMonitor *mon = opaque; @@ -502,7 +521,8 @@ static void virCHMonitorDispose(void *opaque) virObjectUnref(mon->vm); } -void virCHMonitorClose(virCHMonitor *mon) +void +virCHMonitorClose(virCHMonitor * mon) { if (!mon) return; @@ -518,8 +538,7 @@ void virCHMonitorClose(virCHMonitor *mon) if (mon->socketpath) { if (virFileRemove(mon->socketpath, -1, -1) < 0) { - VIR_WARN("Unable to remove CH socket file '%s'", - mon->socketpath); + VIR_WARN("Unable to remove CH socket file '%s'", mon->socketpath); } g_free(mon->socketpath); } @@ -528,7 +547,7 @@ void virCHMonitorClose(virCHMonitor *mon) } static int -virCHMonitorCurlPerform(CURL *handle) +virCHMonitorCurlPerform(CURL * handle) { CURLcode errorCode; long responseCode = 0; @@ -547,8 +566,9 @@ virCHMonitorCurlPerform(CURL *handle) if (errorCode != CURLE_OK) { virReportError(VIR_ERR_INTERNAL_ERROR, - _("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) returned an " - "error: %s (%d)"), curl_easy_strerror(errorCode), + _ + ("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) returned an " + "error: %s (%d)"), curl_easy_strerror(errorCode), errorCode); return -1; } @@ -564,7 +584,7 @@ virCHMonitorCurlPerform(CURL *handle) } int -virCHMonitorPutNoContent(virCHMonitor *mon, const char *endpoint) +virCHMonitorPutNoContent(virCHMonitor * mon, const char *endpoint) { g_autofree char *url = NULL; int responseCode = 0; @@ -615,13 +635,14 @@ curl_callback(void *contents, size_t size, size_t nmemb, void *userp) } static int -virCHMonitorGet(virCHMonitor *mon, const char *endpoint, virJSONValue **response) +virCHMonitorGet(virCHMonitor * mon, const char *endpoint, + virJSONValue ** response) { g_autofree char *url = NULL; int responseCode = 0; int ret = -1; struct curl_slist *headers = NULL; - struct curl_data data = {0}; + struct curl_data data = { 0 }; url = g_strdup_printf("%s/%s", URL_ROOT, endpoint); @@ -638,7 +659,7 @@ virCHMonitorGet(virCHMonitor *mon, const char *endpoint, virJSONValue **response headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(mon->handle, CURLOPT_WRITEFUNCTION, curl_callback); - curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *)&data); + curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *) &data); } responseCode = virCHMonitorCurlPerform(mon->handle); @@ -665,13 +686,13 @@ virCHMonitorGet(virCHMonitor *mon, const char *endpoint, virJSONValue **response } int -virCHMonitorShutdownVMM(virCHMonitor *mon) +virCHMonitorShutdownVMM(virCHMonitor * mon) { return virCHMonitorPutNoContent(mon, URL_VMM_SHUTDOWN); } int -virCHMonitorCreateVM(virCHMonitor *mon) +virCHMonitorCreateVM(virCHMonitor * mon) { g_autofree char *url = NULL; int responseCode = 0; @@ -709,31 +730,31 @@ virCHMonitorCreateVM(virCHMonitor *mon) } int -virCHMonitorBootVM(virCHMonitor *mon) +virCHMonitorBootVM(virCHMonitor * mon) { return virCHMonitorPutNoContent(mon, URL_VM_BOOT); } int -virCHMonitorShutdownVM(virCHMonitor *mon) +virCHMonitorShutdownVM(virCHMonitor * mon) { return virCHMonitorPutNoContent(mon, URL_VM_SHUTDOWN); } int -virCHMonitorRebootVM(virCHMonitor *mon) +virCHMonitorRebootVM(virCHMonitor * mon) { return virCHMonitorPutNoContent(mon, URL_VM_REBOOT); } int -virCHMonitorSuspendVM(virCHMonitor *mon) +virCHMonitorSuspendVM(virCHMonitor * mon) { return virCHMonitorPutNoContent(mon, URL_VM_Suspend); } int -virCHMonitorResumeVM(virCHMonitor *mon) +virCHMonitorResumeVM(virCHMonitor * mon) { return virCHMonitorPutNoContent(mon, URL_VM_RESUME); } @@ -748,7 +769,7 @@ virCHMonitorResumeVM(virCHMonitor *mon) * Returns 0 on success. */ int -virCHMonitorGetInfo(virCHMonitor *mon, virJSONValue **info) +virCHMonitorGetInfo(virCHMonitor * mon, virJSONValue ** info) { return virCHMonitorGet(mon, URL_VM_INFO, info); } -- 2.27.0

From: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_conf.h | 2 ++ src/ch/ch_domain.c | 27 +++++++++++++- src/ch/ch_domain.h | 4 +-- src/ch/ch_driver.c | 1 + src/ch/ch_monitor.c | 86 +++++++++++++++++++++++++++++++++++++++++---- src/ch/ch_monitor.h | 14 +++++++- src/ch/ch_process.c | 6 +++- src/ch/meson.build | 1 + 8 files changed, 129 insertions(+), 12 deletions(-) diff --git a/src/ch/ch_conf.h b/src/ch/ch_conf.h index 37c36d9a09..8fe69c8545 100644 --- a/src/ch/ch_conf.h +++ b/src/ch/ch_conf.h @@ -44,6 +44,8 @@ struct _virCHDriver { virMutex lock; + bool privileged; + /* Require lock to get a reference on the object, * lockless access thereafter */ virCaps *caps; diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index d81221679e..326c3802c3 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -21,10 +21,12 @@ #include <config.h> #include "ch_domain.h" +#include "domain_driver.h" #include "viralloc.h" #include "virchrdev.h" #include "virlog.h" #include "virtime.h" +#include "virsystemd.h" #define VIR_FROM_THIS VIR_FROM_CH @@ -129,7 +131,7 @@ virCHDomainObjEndJob(virDomainObj * obj) } static void * -virCHDomainObjPrivateAlloc(void *opaque G_GNUC_UNUSED) +virCHDomainObjPrivateAlloc(void *opaque) { virCHDomainObjPrivate *priv; @@ -145,6 +147,7 @@ virCHDomainObjPrivateAlloc(void *opaque G_GNUC_UNUSED) g_free(priv); return NULL; } + priv->driver = opaque; return priv; } @@ -359,3 +362,25 @@ virCHDomainHasVcpuPids(virDomainObj * vm) return false; } + +char * +virCHDomainGetMachineName(virDomainObj * vm) +{ + virCHDomainObjPrivate *priv = CH_DOMAIN_PRIVATE(vm); + virCHDriver *driver = priv->driver; + char *ret = NULL; + + if (vm->pid > 0) { + ret = virSystemdGetMachineNameByPID(vm->pid); + if (!ret) + virResetLastError(); + } + + if (!ret) + ret = virDomainDriverGenerateMachineName("ch", + NULL, + vm->def->id, vm->def->name, + driver->privileged); + + return ret; +} diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h index e35777a9ec..3ac3421015 100644 --- a/src/ch/ch_domain.h +++ b/src/ch/ch_domain.h @@ -54,9 +54,7 @@ struct _virCHDomainObjPrivate { struct virCHDomainJobObj job; virChrdevs *chrdevs; - virCgroup *cgroup; - virCHDriver *driver; virCHMonitor *monitor; char *machineName; @@ -94,3 +92,5 @@ virCHDomainObjEndJob(virDomainObj *obj); int virCHDomainRefreshVcpuInfo(virDomainObj *vm); pid_t virCHDomainGetVcpuPid(virDomainObj *vm, unsigned int vcpuid); bool virCHDomainHasVcpuPids(virDomainObj *vm); + +char *virCHDomainGetMachineName(virDomainObj *vm); diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 86d2776354..39e754d1ff 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -936,6 +936,7 @@ chStateInitialize(bool privileged, goto cleanup; } + ch_driver->privileged = privileged; ret = VIR_DRV_STATE_INIT_COMPLETE; cleanup: diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 68fa5b30aa..6bc7d035ad 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -236,7 +236,8 @@ virCHMonitorBuildDisksJson(virJSONValue * content, virDomainDef * vmdef) } static int -virCHMonitorBuildNetJson(virJSONValue * nets, virDomainNetDef * netdef) +virCHMonitorBuildNetJson(virJSONValue * nets, virDomainNetDef * netdef, + size_t *nnicindexes, int **nicindexes) { virDomainNetType netType = virDomainNetGetActualType(netdef); char macaddr[VIR_MAC_STRING_BUFLEN]; @@ -275,6 +276,18 @@ virCHMonitorBuildNetJson(virJSONValue * nets, virDomainNetDef * netdef) virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("ethernet type supports a single guest ip")); } + /* network and bridge use a tap device, and direct uses a + * macvtap device + */ + if (nicindexes && nnicindexes && netdef->ifname) { + int nicindex = 0; + + if (virNetDevGetIndex(netdef->ifname, &nicindex) < 0) + return -1; + + VIR_APPEND_ELEMENT(*nicindexes, *nnicindexes, nicindex); + } + break; case VIR_DOMAIN_NET_TYPE_VHOSTUSER: if ((virDomainChrType) netdef->data.vhostuser->type != @@ -354,7 +367,8 @@ virCHMonitorBuildNetJson(virJSONValue * nets, virDomainNetDef * netdef) } static int -virCHMonitorBuildNetsJson(virJSONValue * content, virDomainDef * vmdef) +virCHMonitorBuildNetsJson(virJSONValue * content, virDomainDef * vmdef, + size_t *nnicindexes, int **nicindexes) { g_autoptr(virJSONValue) nets = NULL; size_t i; @@ -363,7 +377,8 @@ virCHMonitorBuildNetsJson(virJSONValue * content, virDomainDef * vmdef) nets = virJSONValueNewArray(); for (i = 0; i < vmdef->nnets; i++) { - if (virCHMonitorBuildNetJson(nets, vmdef->nets[i]) < 0) + if (virCHMonitorBuildNetJson(nets, vmdef->nets[i], + nnicindexes, nicindexes) < 0) return -1; } if (virJSONValueObjectAppend(content, "net", &nets) < 0) @@ -374,7 +389,59 @@ virCHMonitorBuildNetsJson(virJSONValue * content, virDomainDef * vmdef) } static int -virCHMonitorBuildVMJson(virDomainDef * vmdef, char **jsonstr) +virCHMonitorBuildDeviceJson(virJSONValue * devices, + virDomainHostdevDef * hostdevdef) +{ + g_autoptr(virJSONValue) device = NULL; + + + if (hostdevdef->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdevdef->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { + g_autofree char *name = NULL; + g_autofree char *path = NULL; + virDomainHostdevSubsysPCI *pcisrc = &hostdevdef->source.subsys.u.pci; + + device = virJSONValueNewObject(); + name = virPCIDeviceAddressAsString(&pcisrc->addr); + path = g_strdup_printf("/sys/bus/pci/devices/%s/", name); + if (!virFileExists(path)) { + virReportError(VIR_ERR_DEVICE_MISSING, + _("host pci device %s not found"), path); + return -1; + } + if (virJSONValueObjectAppendString(device, "path", path) < 0) + return -1; + if (virJSONValueArrayAppend(devices, &device) < 0) + return -1; + } + + return 0; +} + +static int +virCHMonitorBuildDevicesJson(virJSONValue * content, virDomainDef * vmdef) +{ + size_t i; + + g_autoptr(virJSONValue) devices = NULL; + + if (vmdef->nhostdevs == 0) + return 0; + + devices = virJSONValueNewArray(); + for (i = 0; i < vmdef->nhostdevs; i++) { + if (virCHMonitorBuildDeviceJson(devices, vmdef->hostdevs[i]) < 0) + return -1; + } + if (virJSONValueObjectAppend(content, "devices", &devices) < 0) + return -1; + + return 0; +} + +static int +virCHMonitorBuildVMJson(virDomainDef * vmdef, char **jsonstr, + size_t *nnicindexes, int **nicindexes) { g_autoptr(virJSONValue) content = virJSONValueNewObject(); @@ -398,7 +465,11 @@ virCHMonitorBuildVMJson(virDomainDef * vmdef, char **jsonstr) if (virCHMonitorBuildDisksJson(content, vmdef) < 0) return -1; - if (virCHMonitorBuildNetsJson(content, vmdef) < 0) + + if (virCHMonitorBuildNetsJson(content, vmdef, nnicindexes, nicindexes) < 0) + return -1; + + if (virCHMonitorBuildDevicesJson(content, vmdef) < 0) return -1; if (!(*jsonstr = virJSONValueToString(content, false))) @@ -692,7 +763,7 @@ virCHMonitorShutdownVMM(virCHMonitor * mon) } int -virCHMonitorCreateVM(virCHMonitor * mon) +virCHMonitorCreateVM(virCHMonitor * mon, size_t *nnicindexes, int **nicindexes) { g_autofree char *url = NULL; int responseCode = 0; @@ -704,7 +775,8 @@ virCHMonitorCreateVM(virCHMonitor * mon) headers = curl_slist_append(headers, "Accept: application/json"); headers = curl_slist_append(headers, "Content-Type: application/json"); - if (virCHMonitorBuildVMJson(mon->vm->def, &payload) != 0) + if (virCHMonitorBuildVMJson(mon->vm->def, &payload, + nnicindexes, nicindexes) != 0) return -1; virObjectLock(mon); diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h index 0f684ca583..8ca9e17a9a 100644 --- a/src/ch/ch_monitor.h +++ b/src/ch/ch_monitor.h @@ -55,10 +55,22 @@ virCHMonitor *virCHMonitorNew(virDomainObj *vm, const char *socketdir); void virCHMonitorClose(virCHMonitor *mon); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCHMonitor, virCHMonitorClose); -int virCHMonitorCreateVM(virCHMonitor *mon); + +int virCHMonitorCreateVM(virCHMonitor *mon, + size_t *nnicindexes, int **nicindexes); int virCHMonitorBootVM(virCHMonitor *mon); int virCHMonitorShutdownVM(virCHMonitor *mon); int virCHMonitorRebootVM(virCHMonitor *mon); int virCHMonitorSuspendVM(virCHMonitor *mon); int virCHMonitorResumeVM(virCHMonitor *mon); int virCHMonitorGetInfo(virCHMonitor *mon, virJSONValue **info); + +typedef struct _virCHMonitorCPUInfo virCHMonitorCPUInfo; +struct _virCHMonitorCPUInfo { + pid_t tid; + bool online; +}; +void virCHMonitorCPUInfoFree(virCHMonitorCPUInfo *cpus); +int virCHMonitorGetCPUInfo(virCHMonitor *mon, + virCHMonitorCPUInfo **vcpus, + size_t maxvcpus); diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c index 1a01ca9384..3b7f6fcddf 100644 --- a/src/ch/ch_process.c +++ b/src/ch/ch_process.c @@ -149,6 +149,8 @@ int virCHProcessStart(virCHDriver *driver, { int ret = -1; virCHDomainObjPrivate *priv = vm->privateData; + g_autofree int *nicindexes = NULL; + size_t nnicindexes = 0; if (!priv->monitor) { /* And we can get the first monitor connection now too */ @@ -158,7 +160,8 @@ int virCHProcessStart(virCHDriver *driver, goto cleanup; } - if (virCHMonitorCreateVM(priv->monitor) < 0) { + if (virCHMonitorCreateVM(priv->monitor, + &nnicindexes, &nicindexes) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to create guest VM")); goto cleanup; @@ -171,6 +174,7 @@ int virCHProcessStart(virCHDriver *driver, goto cleanup; } + priv->machineName = virCHDomainGetMachineName(vm); vm->pid = priv->monitor->pid; vm->def->id = vm->pid; diff --git a/src/ch/meson.build b/src/ch/meson.build index e34974d56c..e0afdb390a 100644 --- a/src/ch/meson.build +++ b/src/ch/meson.build @@ -29,6 +29,7 @@ if conf.has('WITH_CH') ], include_directories: [ conf_inc_dir, + hypervisor_inc_dir, ], ) -- 2.27.0

Refactor some cgroup management methods from qemu into hypervisor. These methods will be shared by ch driver for cgroup management. Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/hypervisor/domain_cgroup.c | 426 ++++++++++++++++++++++++++++++++- src/hypervisor/domain_cgroup.h | 52 ++++ src/libvirt_private.syms | 10 + src/qemu/qemu_cgroup.c | 410 +------------------------------ src/qemu/qemu_cgroup.h | 11 - src/qemu/qemu_driver.c | 14 +- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 17 +- 8 files changed, 515 insertions(+), 429 deletions(-) diff --git a/src/hypervisor/domain_cgroup.c b/src/hypervisor/domain_cgroup.c index 61b54f071c..eda46e3421 100644 --- a/src/hypervisor/domain_cgroup.c +++ b/src/hypervisor/domain_cgroup.c @@ -22,11 +22,12 @@ #include "domain_cgroup.h" #include "domain_driver.h" - +#include "util/virnuma.h" +#include "virlog.h" #include "virutil.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN - +VIR_LOG_INIT("domain.cgroup"); int virDomainCgroupSetupBlkio(virCgroup *cgroup, virDomainBlkiotune blkio) @@ -269,3 +270,424 @@ virDomainCgroupSetMemoryLimitParameters(virCgroup *cgroup, return 0; } + + +int +virSetupBlkioCgroup(virDomainObj * vm, virCgroup * cgroup) +{ + + if (!virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) { + if (vm->def->blkio.weight || vm->def->blkio.ndevices) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Block I/O tuning is not available on this host")); + return -1; + } else { + return 0; + } + } + + return virDomainCgroupSetupBlkio(cgroup, vm->def->blkio); +} + + +int +virSetupMemoryCgroup(virDomainObj * vm, virCgroup * cgroup) +{ + + if (!virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) { + if (virMemoryLimitIsSet(vm->def->mem.hard_limit) || + virMemoryLimitIsSet(vm->def->mem.soft_limit) || + virMemoryLimitIsSet(vm->def->mem.swap_hard_limit)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Memory cgroup is not available on this host")); + return -1; + } else { + return 0; + } + } + + return virDomainCgroupSetupMemtune(cgroup, vm->def->mem); +} + + +int +virSetupCpusetCgroup(virCgroup * cgroup) +{ + + if (!virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) + return 0; + + if (virCgroupSetCpusetMemoryMigrate(cgroup, true) < 0) + return -1; + + return 0; +} + + +int +virSetupCpuCgroup(virDomainObj * vm, virCgroup * cgroup) +{ + + if (!virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPU)) { + if (vm->def->cputune.sharesSpecified) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("CPU tuning is not available on this host")); + return -1; + } else { + return 0; + } + } + + if (vm->def->cputune.sharesSpecified) { + + if (virCgroupSetCpuShares(cgroup, vm->def->cputune.shares) < 0) + return -1; + + } + + return 0; +} + + +int +virInitCgroup(const char *prefix, + virDomainObj * vm, + size_t nnicindexes, int *nicindexes, + virCgroup * cgroup, int cgroupControllers, + unsigned int maxThreadsPerProc, + bool privileged, char *machineName) +{ + if (!privileged) + return 0; + + if (!virCgroupAvailable()) + return 0; + + virCgroupFree(cgroup); + cgroup = NULL; + + if (!vm->def->resource) + vm->def->resource = g_new0(virDomainResourceDef, 1); + + if (!vm->def->resource->partition) + vm->def->resource->partition = g_strdup("/machine"); + + if (!g_path_is_absolute(vm->def->resource->partition)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Resource partition '%s' must start with '/'"), + vm->def->resource->partition); + return -1; + } + + if (virCgroupNewMachine(machineName, + prefix, + vm->def->uuid, + NULL, + vm->pid, + false, + nnicindexes, nicindexes, + vm->def->resource->partition, + cgroupControllers, + maxThreadsPerProc, &cgroup) < 0) { + if (virCgroupNewIgnoreError()) + return 0; + + return -1; + } + + return 0; +} + + +void +virRestoreCgroupState(virDomainObj * vm, virCgroup * cgroup) +{ + g_autofree char *mem_mask = NULL; + size_t i = 0; + + g_autoptr(virBitmap) all_nodes = NULL; + + if (!virNumaIsAvailable() || + !virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) + return; + + if (!(all_nodes = virNumaGetHostMemoryNodeset())) + goto error; + + if (!(mem_mask = virBitmapFormat(all_nodes))) + goto error; + + if (virCgroupHasEmptyTasks(cgroup, VIR_CGROUP_CONTROLLER_CPUSET) <= 0) + goto error; + + if (virCgroupSetCpusetMems(cgroup, mem_mask) < 0) + goto error; + + for (i = 0; i < virDomainDefGetVcpusMax(vm->def); i++) { + virDomainVcpuDef *vcpu = virDomainDefGetVcpu(vm->def, i); + + if (!vcpu->online) + continue; + + if (virRestoreCgroupThread(cgroup, VIR_CGROUP_THREAD_VCPU, i) < 0) + return; + } + + for (i = 0; i < vm->def->niothreadids; i++) { + if (virRestoreCgroupThread(cgroup, VIR_CGROUP_THREAD_IOTHREAD, + vm->def->iothreadids[i]->iothread_id) < 0) + return; + } + + if (virRestoreCgroupThread(cgroup, VIR_CGROUP_THREAD_EMULATOR, 0) < 0) + return; + + return; + + error: + virResetLastError(); + VIR_DEBUG("Couldn't restore cgroups to meaningful state"); + return; +} + + +int +virRestoreCgroupThread(virCgroup * cgroup, virCgroupThreadName thread, int id) +{ + g_autoptr(virCgroup) cgroup_temp = NULL; + g_autofree char *nodeset = NULL; + + if (virCgroupNewThread(cgroup, thread, id, false, &cgroup_temp) < 0) + return -1; + + if (virCgroupSetCpusetMemoryMigrate(cgroup_temp, true) < 0) + return -1; + + if (virCgroupGetCpusetMems(cgroup_temp, &nodeset) < 0) + return -1; + + if (virCgroupSetCpusetMems(cgroup_temp, nodeset) < 0) + return -1; + + return 0; +} + + +int +virConnectCgroup(const char *prefix, virDomainObj * vm, virCgroup * cgroup, + int cgroupControllers, bool privileged, char *machineName) +{ + if (privileged) + return 0; + + if (!virCgroupAvailable()) + return 0; + + virCgroupFree(cgroup); + + if (virCgroupNewDetectMachine(vm->def->name, + prefix, + vm->pid, + cgroupControllers, machineName, &cgroup) < 0) + return -1; + + virRestoreCgroupState(vm, cgroup); + return 0; +} + + +int +virSetupCgroup(const char *prefix, + virDomainObj * vm, + size_t nnicindexes, int *nicindexes, + virCgroup * cgroup, + int cgroupControllers, + unsigned int maxThreadsPerProc, + bool privileged, char *machineName) +{ + if (!vm->pid) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot setup cgroups until process is started")); + return -1; + } + + if (virInitCgroup(prefix, vm, nnicindexes, nicindexes, + cgroup, cgroupControllers, + maxThreadsPerProc, privileged, machineName) < 0) + return -1; + + if (!cgroup) + return 0; + + if (virSetupBlkioCgroup(vm, cgroup) < 0) + return -1; + + if (virSetupMemoryCgroup(vm, cgroup) < 0) + return -1; + + if (virSetupCpuCgroup(vm, cgroup) < 0) + return -1; + + if (virSetupCpusetCgroup(cgroup) < 0) + return -1; + + return 0; +} + + +int +virSetupCgroupVcpuBW(virCgroup * cgroup, + unsigned long long period, long long quota) +{ + return virCgroupSetupCpuPeriodQuota(cgroup, period, quota); +} + + +int +virSetupCgroupCpusetCpus(virCgroup * cgroup, virBitmap * cpumask) +{ + return virCgroupSetupCpusetCpus(cgroup, cpumask); +} + + +int +virSetupGlobalCpuCgroup(virDomainObj * vm, virCgroup * cgroup, + virBitmap * autoNodeset) +{ + unsigned long long period = vm->def->cputune.global_period; + long long quota = vm->def->cputune.global_quota; + g_autofree char *mem_mask = NULL; + virDomainNumatuneMemMode mem_mode; + + if ((period || quota) && + !virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPU)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cgroup cpu is required for scheduler tuning")); + return -1; + } + + /* + * If CPU cgroup controller is not initialized here, then we need + * neither period nor quota settings. And if CPUSET controller is + * not initialized either, then there's nothing to do anyway. + */ + if (!virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPU) && + !virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) + return 0; + + + if (virDomainNumatuneGetMode(vm->def->numa, -1, &mem_mode) == 0 && + mem_mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT && + virDomainNumatuneMaybeFormatNodeset(vm->def->numa, + autoNodeset, &mem_mask, -1) < 0) + return -1; + + if (period || quota) { + if (virSetupCgroupVcpuBW(cgroup, period, quota) < 0) + return -1; + } + + return 0; +} + + +int +virRemoveCgroup(virDomainObj * vm, virCgroup * cgroup, char *machineName) +{ + if (cgroup == NULL) + return 0; /* Not supported, so claim success */ + + if (virCgroupTerminateMachine(machineName) < 0) { + if (!virCgroupNewIgnoreError()) + VIR_DEBUG("Failed to terminate cgroup for %s", vm->def->name); + } + + return virCgroupRemove(cgroup); +} + + +void +virCgroupEmulatorAllNodesDataFree(virCgroupEmulatorAllNodesData * data) +{ + if (!data) + return; + + virCgroupFree(data->emulatorCgroup); + g_free(data->emulatorMemMask); + g_free(data); +} + + +/** + * virCgroupEmulatorAllNodesAllow: + * @cgroup: domain cgroup pointer + * @retData: filled with structure used to roll back the operation + * + * Allows all NUMA nodes for the cloud hypervisor thread temporarily. This is + * necessary when hotplugging cpus since it requires memory allocated in the + * DMA region. Afterwards the operation can be reverted by + * virCgroupEmulatorAllNodesRestore. + * + * Returns 0 on success -1 on error + */ +int +virCgroupEmulatorAllNodesAllow(virCgroup * cgroup, + virCgroupEmulatorAllNodesData ** retData) +{ + virCgroupEmulatorAllNodesData *data = NULL; + g_autofree char *all_nodes_str = NULL; + + g_autoptr(virBitmap) all_nodes = NULL; + int ret = -1; + + if (!virNumaIsAvailable() || + !virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) + return 0; + + if (!(all_nodes = virNumaGetHostMemoryNodeset())) + goto cleanup; + + if (!(all_nodes_str = virBitmapFormat(all_nodes))) + goto cleanup; + + data = g_new0(virCgroupEmulatorAllNodesData, 1); + + if (virCgroupNewThread(cgroup, VIR_CGROUP_THREAD_EMULATOR, 0, + false, &data->emulatorCgroup) < 0) + goto cleanup; + + if (virCgroupGetCpusetMems(data->emulatorCgroup, &data->emulatorMemMask) < 0 + || virCgroupSetCpusetMems(data->emulatorCgroup, all_nodes_str) < 0) + goto cleanup; + + *retData = g_steal_pointer(&data); + ret = 0; + + cleanup: + virCgroupEmulatorAllNodesDataFree(data); + + return ret; +} + + +/** + * virCgroupEmulatorAllNodesRestore: + * @data: data structure created by virCgroupEmulatorAllNodesAllow + * + * Rolls back the setting done by virCgroupEmulatorAllNodesAllow and frees the + * associated data. + */ +void +virCgroupEmulatorAllNodesRestore(virCgroupEmulatorAllNodesData * data) +{ + virError *err; + + if (!data) + return; + + virErrorPreserveLast(&err); + virCgroupSetCpusetMems(data->emulatorCgroup, data->emulatorMemMask); + virErrorRestore(&err); + + virCgroupEmulatorAllNodesDataFree(data); +} diff --git a/src/hypervisor/domain_cgroup.h b/src/hypervisor/domain_cgroup.h index f93e5f74fe..fd8b74a4ee 100644 --- a/src/hypervisor/domain_cgroup.h +++ b/src/hypervisor/domain_cgroup.h @@ -23,6 +23,11 @@ #include "vircgroup.h" #include "domain_conf.h" +typedef struct _virCgroupEmulatorAllNodesData virCgroupEmulatorAllNodesData; +struct _virCgroupEmulatorAllNodesData { + virCgroup *emulatorCgroup; + char *emulatorMemMask; +}; int virDomainCgroupSetupBlkio(virCgroup *cgroup, virDomainBlkiotune blkio); int virDomainCgroupSetupMemtune(virCgroup *cgroup, virDomainMemtune mem); @@ -36,3 +41,50 @@ int virDomainCgroupSetMemoryLimitParameters(virCgroup *cgroup, virDomainDef *persistentDef, virTypedParameterPtr params, int nparams); +int +virSetupBlkioCgroup(virDomainObj * vm, virCgroup *cgroup); +int +virSetupMemoryCgroup(virDomainObj * vm, virCgroup *cgroup); +int +virSetupCpusetCgroup(virCgroup *cgroup); +int +virSetupCpuCgroup(virDomainObj * vm, virCgroup *cgroup); +int +virInitCgroup(const char *prefix, virDomainObj * vm, + size_t nnicindexes, int *nicindexes, + virCgroup *cgroup, int cgroupControllers, + unsigned int maxThreadsPerProc, + bool privileged, + char *machineName); +void +virRestoreCgroupState(virDomainObj * vm, virCgroup *cgroup); +int +virConnectCgroup(const char *prefix, virDomainObj * vm, virCgroup *cgroup, + int cgroupControllers, bool privileged, char *machineName); +int +virSetupCgroup(const char *prefix, virDomainObj * vm, + size_t nnicindexes, int *nicindexes, + virCgroup *cgroup, int cgroupControllers, + unsigned int maxThreadsPerProc, + bool privileged, + char *machineName); +void +virCgroupEmulatorAllNodesDataFree(virCgroupEmulatorAllNodesData * data); +int +virCgroupEmulatorAllNodesAllow(virCgroup * cgroup, + virCgroupEmulatorAllNodesData ** retData); +void +virCgroupEmulatorAllNodesRestore(virCgroupEmulatorAllNodesData * data); +int +virSetupCgroupVcpuBW(virCgroup * cgroup, + unsigned long long period, long long quota); +int +virSetupCgroupCpusetCpus(virCgroup * cgroup, virBitmap * cpumask); +int +virSetupGlobalCpuCgroup(virDomainObj * vm, virCgroup * cgroup, + virBitmap *autoNodeset); +int +virRemoveCgroup(virDomainObj * vm, virCgroup * cgroup, char *machineName); +int +virRestoreCgroupThread(virCgroup *cgroup, virCgroupThreadName thread, + int id); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e0c4fba522..2e510f5b91 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1545,6 +1545,16 @@ virDomainCgroupSetMemoryLimitParameters; virDomainCgroupSetupBlkio; virDomainCgroupSetupDomainBlkioParameters; virDomainCgroupSetupMemtune; +virInitCgroup; +virRemoveCgroup; +virSetupBlkioCgroup; +virSetupCgroup; +virSetupCgroupCpusetCpus; +virSetupCgroupVcpuBW; +virSetupCpuCgroup; +virSetupCpusetCgroup; +virSetupGlobalCpuCgroup; +virSetupMemoryCgroup; # hypervisor/domain_driver.h diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 308be5b00f..b1d2875959 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -593,46 +593,6 @@ qemuSetupVideoCgroup(virDomainObj *vm, return ret; } - -static int -qemuSetupBlkioCgroup(virDomainObj *vm) -{ - qemuDomainObjPrivate *priv = vm->privateData; - - if (!virCgroupHasController(priv->cgroup, - VIR_CGROUP_CONTROLLER_BLKIO)) { - if (vm->def->blkio.weight || vm->def->blkio.ndevices) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Block I/O tuning is not available on this host")); - return -1; - } - return 0; - } - - return virDomainCgroupSetupBlkio(priv->cgroup, vm->def->blkio); -} - - -static int -qemuSetupMemoryCgroup(virDomainObj *vm) -{ - qemuDomainObjPrivate *priv = vm->privateData; - - if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) { - if (virMemoryLimitIsSet(vm->def->mem.hard_limit) || - virMemoryLimitIsSet(vm->def->mem.soft_limit) || - virMemoryLimitIsSet(vm->def->mem.swap_hard_limit)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Memory cgroup is not available on this host")); - return -1; - } - return 0; - } - - return virDomainCgroupSetupMemtune(priv->cgroup, vm->def->mem); -} - - static int qemuSetupFirmwareCgroup(virDomainObj *vm) { @@ -861,44 +821,6 @@ qemuSetupDevicesCgroup(virDomainObj *vm) } -static int -qemuSetupCpusetCgroup(virDomainObj *vm) -{ - qemuDomainObjPrivate *priv = vm->privateData; - - if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) - return 0; - - if (virCgroupSetCpusetMemoryMigrate(priv->cgroup, true) < 0) - return -1; - - return 0; -} - - -static int -qemuSetupCpuCgroup(virDomainObj *vm) -{ - qemuDomainObjPrivate *priv = vm->privateData; - - if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) { - if (vm->def->cputune.sharesSpecified) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("CPU tuning is not available on this host")); - return -1; - } - return 0; - } - - if (vm->def->cputune.sharesSpecified) { - if (virCgroupSetCpuShares(priv->cgroup, vm->def->cputune.shares) < 0) - return -1; - } - - return 0; -} - - static int qemuSetupCgroupAppid(virDomainObj *vm) { @@ -927,166 +849,13 @@ qemuSetupCgroupAppid(virDomainObj *vm) } -static int -qemuInitCgroup(virDomainObj *vm, - size_t nnicindexes, - int *nicindexes) -{ - qemuDomainObjPrivate *priv = vm->privateData; - g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(priv->driver); - - if (!priv->driver->privileged) - return 0; - - if (!virCgroupAvailable()) - return 0; - - virCgroupFree(priv->cgroup); - priv->cgroup = NULL; - - if (!vm->def->resource) - vm->def->resource = g_new0(virDomainResourceDef, 1); - - if (!vm->def->resource->partition) - vm->def->resource->partition = g_strdup("/machine"); - - if (!g_path_is_absolute(vm->def->resource->partition)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Resource partition '%s' must start with '/'"), - vm->def->resource->partition); - return -1; - } - - if (virCgroupNewMachine(priv->machineName, - "qemu", - vm->def->uuid, - NULL, - vm->pid, - false, - nnicindexes, nicindexes, - vm->def->resource->partition, - cfg->cgroupControllers, - cfg->maxThreadsPerProc, - &priv->cgroup) < 0) { - if (virCgroupNewIgnoreError()) - return 0; - - return -1; - } - - return 0; -} - -static int -qemuRestoreCgroupThread(virCgroup *cgroup, - virCgroupThreadName thread, - int id) -{ - g_autoptr(virCgroup) cgroup_temp = NULL; - g_autofree char *nodeset = NULL; - - if (virCgroupNewThread(cgroup, thread, id, false, &cgroup_temp) < 0) - return -1; - - if (virCgroupSetCpusetMemoryMigrate(cgroup_temp, true) < 0) - return -1; - - if (virCgroupGetCpusetMems(cgroup_temp, &nodeset) < 0) - return -1; - - if (virCgroupSetCpusetMems(cgroup_temp, nodeset) < 0) - return -1; - - return 0; -} - -static void -qemuRestoreCgroupState(virDomainObj *vm) -{ - g_autofree char *mem_mask = NULL; - qemuDomainObjPrivate *priv = vm->privateData; - size_t i = 0; - g_autoptr(virBitmap) all_nodes = NULL; - - if (!virNumaIsAvailable() || - !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) - return; - - if (!(all_nodes = virNumaGetHostMemoryNodeset())) - goto error; - - if (!(mem_mask = virBitmapFormat(all_nodes))) - goto error; - - if (virCgroupHasEmptyTasks(priv->cgroup, - VIR_CGROUP_CONTROLLER_CPUSET) <= 0) - goto error; - - if (virCgroupSetCpusetMems(priv->cgroup, mem_mask) < 0) - goto error; - - for (i = 0; i < virDomainDefGetVcpusMax(vm->def); i++) { - virDomainVcpuDef *vcpu = virDomainDefGetVcpu(vm->def, i); - - if (!vcpu->online) - continue; - - if (qemuRestoreCgroupThread(priv->cgroup, - VIR_CGROUP_THREAD_VCPU, i) < 0) - return; - } - - for (i = 0; i < vm->def->niothreadids; i++) { - if (qemuRestoreCgroupThread(priv->cgroup, VIR_CGROUP_THREAD_IOTHREAD, - vm->def->iothreadids[i]->iothread_id) < 0) - return; - } - - if (qemuRestoreCgroupThread(priv->cgroup, - VIR_CGROUP_THREAD_EMULATOR, 0) < 0) - return; - - return; - - error: - virResetLastError(); - VIR_DEBUG("Couldn't restore cgroups to meaningful state"); - return; -} - -int -qemuConnectCgroup(virDomainObj *vm) -{ - qemuDomainObjPrivate *priv = vm->privateData; - g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(priv->driver); - - if (!priv->driver->privileged) - return 0; - - if (!virCgroupAvailable()) - return 0; - - virCgroupFree(priv->cgroup); - priv->cgroup = NULL; - - if (virCgroupNewDetectMachine(vm->def->name, - "qemu", - vm->pid, - cfg->cgroupControllers, - priv->machineName, - &priv->cgroup) < 0) - return -1; - - qemuRestoreCgroupState(vm); - return 0; -} - int qemuSetupCgroup(virDomainObj *vm, size_t nnicindexes, int *nicindexes) { qemuDomainObjPrivate *priv = vm->privateData; + g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(priv->driver); if (!vm->pid) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -1094,7 +863,12 @@ qemuSetupCgroup(virDomainObj *vm, return -1; } - if (qemuInitCgroup(vm, nnicindexes, nicindexes) < 0) + if (virInitCgroup("qemu", vm, nnicindexes, nicindexes, + priv->cgroup, + cfg->cgroupControllers, + cfg->maxThreadsPerProc, + priv->driver->privileged, + priv->machineName) < 0) return -1; if (!priv->cgroup) @@ -1103,16 +877,16 @@ qemuSetupCgroup(virDomainObj *vm, if (qemuSetupDevicesCgroup(vm) < 0) return -1; - if (qemuSetupBlkioCgroup(vm) < 0) + if (virSetupBlkioCgroup(vm, priv->cgroup) < 0) return -1; - if (qemuSetupMemoryCgroup(vm) < 0) + if (virSetupMemoryCgroup(vm, priv->cgroup) < 0) return -1; - if (qemuSetupCpuCgroup(vm) < 0) + if (virSetupCpuCgroup(vm, priv->cgroup) < 0) return -1; - if (qemuSetupCpusetCgroup(vm) < 0) + if (virSetupCpusetCgroup(priv->cgroup) < 0) return -1; if (qemuSetupCgroupAppid(vm) < 0) @@ -1121,23 +895,6 @@ qemuSetupCgroup(virDomainObj *vm, return 0; } -int -qemuSetupCgroupVcpuBW(virCgroup *cgroup, - unsigned long long period, - long long quota) -{ - return virCgroupSetupCpuPeriodQuota(cgroup, period, quota); -} - - -int -qemuSetupCgroupCpusetCpus(virCgroup *cgroup, - virBitmap *cpumask) -{ - return virCgroupSetupCpusetCpus(cgroup, cpumask); -} - - int qemuSetupCgroupForExtDevices(virDomainObj *vm, virQEMUDriver *driver) @@ -1164,148 +921,3 @@ qemuSetupCgroupForExtDevices(virDomainObj *vm, return qemuExtDevicesSetupCgroup(driver, vm, cgroup_temp); } - - -int -qemuSetupGlobalCpuCgroup(virDomainObj *vm) -{ - qemuDomainObjPrivate *priv = vm->privateData; - unsigned long long period = vm->def->cputune.global_period; - long long quota = vm->def->cputune.global_quota; - g_autofree char *mem_mask = NULL; - virDomainNumatuneMemMode mem_mode; - - if ((period || quota) && - !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("cgroup cpu is required for scheduler tuning")); - return -1; - } - - /* - * If CPU cgroup controller is not initialized here, then we need - * neither period nor quota settings. And if CPUSET controller is - * not initialized either, then there's nothing to do anyway. - */ - if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU) && - !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) - return 0; - - - if (virDomainNumatuneGetMode(vm->def->numa, -1, &mem_mode) == 0 && - mem_mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT && - virDomainNumatuneMaybeFormatNodeset(vm->def->numa, - priv->autoNodeset, - &mem_mask, -1) < 0) - return -1; - - if (period || quota) { - if (qemuSetupCgroupVcpuBW(priv->cgroup, period, quota) < 0) - return -1; - } - - return 0; -} - - -int -qemuRemoveCgroup(virDomainObj *vm) -{ - qemuDomainObjPrivate *priv = vm->privateData; - - if (priv->cgroup == NULL) - return 0; /* Not supported, so claim success */ - - if (virCgroupTerminateMachine(priv->machineName) < 0) { - if (!virCgroupNewIgnoreError()) - VIR_DEBUG("Failed to terminate cgroup for %s", vm->def->name); - } - - return virCgroupRemove(priv->cgroup); -} - - -static void -qemuCgroupEmulatorAllNodesDataFree(qemuCgroupEmulatorAllNodesData *data) -{ - if (!data) - return; - - virCgroupFree(data->emulatorCgroup); - g_free(data->emulatorMemMask); - g_free(data); -} - - -/** - * qemuCgroupEmulatorAllNodesAllow: - * @cgroup: domain cgroup pointer - * @retData: filled with structure used to roll back the operation - * - * Allows all NUMA nodes for the qemu emulator thread temporarily. This is - * necessary when hotplugging cpus since it requires memory allocated in the - * DMA region. Afterwards the operation can be reverted by - * qemuCgroupEmulatorAllNodesRestore. - * - * Returns 0 on success -1 on error - */ -int -qemuCgroupEmulatorAllNodesAllow(virCgroup *cgroup, - qemuCgroupEmulatorAllNodesData **retData) -{ - qemuCgroupEmulatorAllNodesData *data = NULL; - g_autofree char *all_nodes_str = NULL; - g_autoptr(virBitmap) all_nodes = NULL; - int ret = -1; - - if (!virNumaIsAvailable() || - !virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) - return 0; - - if (!(all_nodes = virNumaGetHostMemoryNodeset())) - goto cleanup; - - if (!(all_nodes_str = virBitmapFormat(all_nodes))) - goto cleanup; - - data = g_new0(qemuCgroupEmulatorAllNodesData, 1); - - if (virCgroupNewThread(cgroup, VIR_CGROUP_THREAD_EMULATOR, 0, - false, &data->emulatorCgroup) < 0) - goto cleanup; - - if (virCgroupGetCpusetMems(data->emulatorCgroup, &data->emulatorMemMask) < 0 || - virCgroupSetCpusetMems(data->emulatorCgroup, all_nodes_str) < 0) - goto cleanup; - - *retData = g_steal_pointer(&data); - ret = 0; - - cleanup: - qemuCgroupEmulatorAllNodesDataFree(data); - - return ret; -} - - -/** - * qemuCgroupEmulatorAllNodesRestore: - * @data: data structure created by qemuCgroupEmulatorAllNodesAllow - * - * Rolls back the setting done by qemuCgroupEmulatorAllNodesAllow and frees the - * associated data. - */ -void -qemuCgroupEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesData *data) -{ - virErrorPtr err; - - if (!data) - return; - - virErrorPreserveLast(&err); - virCgroupSetCpusetMems(data->emulatorCgroup, data->emulatorMemMask); - virErrorRestore(&err); - - qemuCgroupEmulatorAllNodesDataFree(data); -} diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h index cd537ebd82..f09134947f 100644 --- a/src/qemu/qemu_cgroup.h +++ b/src/qemu/qemu_cgroup.h @@ -56,18 +56,11 @@ int qemuSetupChardevCgroup(virDomainObj *vm, virDomainChrDef *dev); int qemuTeardownChardevCgroup(virDomainObj *vm, virDomainChrDef *dev); -int qemuConnectCgroup(virDomainObj *vm); int qemuSetupCgroup(virDomainObj *vm, size_t nnicindexes, int *nicindexes); -int qemuSetupCgroupVcpuBW(virCgroup *cgroup, - unsigned long long period, - long long quota); -int qemuSetupCgroupCpusetCpus(virCgroup *cgroup, virBitmap *cpumask); -int qemuSetupGlobalCpuCgroup(virDomainObj *vm); int qemuSetupCgroupForExtDevices(virDomainObj *vm, virQEMUDriver *driver); -int qemuRemoveCgroup(virDomainObj *vm); typedef struct _qemuCgroupEmulatorAllNodesData qemuCgroupEmulatorAllNodesData; struct _qemuCgroupEmulatorAllNodesData { @@ -75,8 +68,4 @@ struct _qemuCgroupEmulatorAllNodesData { char *emulatorMemMask; }; -int qemuCgroupEmulatorAllNodesAllow(virCgroup *cgroup, - qemuCgroupEmulatorAllNodesData **data); -void qemuCgroupEmulatorAllNodesRestore(qemuCgroupEmulatorAllNodesData *data); - extern const char *const defaultDeviceACL[]; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a7088d3a66..316ea4642f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4438,7 +4438,7 @@ qemuDomainPinVcpuLive(virDomainObj *vm, if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, vcpu, false, &cgroup_vcpu) < 0) goto cleanup; - if (qemuSetupCgroupCpusetCpus(cgroup_vcpu, cpumap) < 0) + if (virSetupCgroupCpusetCpus(cgroup_vcpu, cpumap) < 0) goto cleanup; } @@ -4651,7 +4651,7 @@ qemuDomainPinEmulator(virDomainPtr dom, 0, false, &cgroup_emulator) < 0) goto endjob; - if (qemuSetupCgroupCpusetCpus(cgroup_emulator, pcpumap) < 0) { + if (virSetupCgroupCpusetCpus(cgroup_emulator, pcpumap) < 0) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("failed to set cpuset.cpus in cgroup" " for emulator threads")); @@ -5062,7 +5062,7 @@ qemuDomainPinIOThread(virDomainPtr dom, if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_IOTHREAD, iothread_id, false, &cgroup_iothread) < 0) goto endjob; - if (qemuSetupCgroupCpusetCpus(cgroup_iothread, pcpumap) < 0) { + if (virSetupCgroupCpusetCpus(cgroup_iothread, pcpumap) < 0) { virReportError(VIR_ERR_OPERATION_INVALID, _("failed to set cpuset.cpus in cgroup" " for iothread %d"), iothread_id); @@ -8948,7 +8948,7 @@ qemuSetGlobalBWLive(virCgroup *cgroup, unsigned long long period, if (period == 0 && quota == 0) return 0; - if (qemuSetupCgroupVcpuBW(cgroup, period, quota) < 0) + if (virSetupCgroupVcpuBW(cgroup, period, quota) < 0) return -1; return 0; @@ -9143,7 +9143,7 @@ qemuSetVcpusBWLive(virDomainObj *vm, virCgroup *cgroup, false, &cgroup_vcpu) < 0) return -1; - if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0) + if (virSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0) return -1; } @@ -9164,7 +9164,7 @@ qemuSetEmulatorBandwidthLive(virCgroup *cgroup, false, &cgroup_emulator) < 0) return -1; - if (qemuSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0) + if (virSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0) return -1; return 0; @@ -9191,7 +9191,7 @@ qemuSetIOThreadsBWLive(virDomainObj *vm, virCgroup *cgroup, false, &cgroup_iothread) < 0) return -1; - if (qemuSetupCgroupVcpuBW(cgroup_iothread, period, quota) < 0) + if (virSetupCgroupVcpuBW(cgroup_iothread, period, quota) < 0) return -1; } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 426710786b..f930a9eb7a 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -6634,7 +6634,7 @@ qemuDomainSetVcpusLive(virQEMUDriver *driver, ssize_t nextvcpu = -1; int ret = -1; - if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) + if (virCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) goto cleanup; if (enable) { @@ -6655,7 +6655,7 @@ qemuDomainSetVcpusLive(virQEMUDriver *driver, ret = 0; cleanup: - qemuCgroupEmulatorAllNodesRestore(emulatorCgroup); + virCgroupEmulatorAllNodesRestore(emulatorCgroup); return ret; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index c355a39e15..53662c3d52 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2756,7 +2756,7 @@ qemuProcessSetupPid(virDomainObj *vm, if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { if (use_cpumask && - qemuSetupCgroupCpusetCpus(cgroup, use_cpumask) < 0) + virSetupCgroupCpusetCpus(cgroup, use_cpumask) < 0) goto cleanup; if (mem_mask && virCgroupSetCpusetMems(cgroup, mem_mask) < 0) @@ -2765,7 +2765,7 @@ qemuProcessSetupPid(virDomainObj *vm, } if ((period || quota) && - qemuSetupCgroupVcpuBW(cgroup, period, quota) < 0) + virSetupCgroupVcpuBW(cgroup, period, quota) < 0) goto cleanup; /* Move the thread to the sub dir */ @@ -6100,7 +6100,7 @@ qemuProcessSetupHotpluggableVcpus(virQEMUDriver *driver, qsort(bootHotplug, nbootHotplug, sizeof(*bootHotplug), qemuProcessVcpusSortOrder); - if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) + if (virCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) goto cleanup; for (i = 0; i < nbootHotplug; i++) { @@ -6125,7 +6125,7 @@ qemuProcessSetupHotpluggableVcpus(virQEMUDriver *driver, ret = 0; cleanup: - qemuCgroupEmulatorAllNodesRestore(emulatorCgroup); + virCgroupEmulatorAllNodesRestore(emulatorCgroup); return ret; } @@ -6887,7 +6887,7 @@ qemuProcessPrepareHost(virQEMUDriver *driver, /* Ensure no historical cgroup for this VM is lying around bogus * settings */ VIR_DEBUG("Ensuring no historical cgroup is lying around"); - qemuRemoveCgroup(vm); + virRemoveCgroup(vm, priv->cgroup, priv->machineName); if (g_mkdir_with_parents(cfg->logDir, 0777) < 0) { virReportSystemError(errno, @@ -7505,7 +7505,7 @@ qemuProcessLaunch(virConnectPtr conn, goto cleanup; VIR_DEBUG("Setting global CPU cgroup (if required)"); - if (qemuSetupGlobalCpuCgroup(vm) < 0) + if (virSetupGlobalCpuCgroup(vm, priv->cgroup, priv->autoNodeset) < 0) goto cleanup; VIR_DEBUG("Setting vCPU tuning/settings"); @@ -8119,7 +8119,7 @@ void qemuProcessStop(virQEMUDriver *driver, } retry: - if ((ret = qemuRemoveCgroup(vm)) < 0) { + if ((ret = virRemoveCgroup(vm, priv->cgroup, priv->machineName)) < 0) { if (ret == -EBUSY && (retries++ < 5)) { g_usleep(200*1000); goto retry; @@ -8686,7 +8686,8 @@ qemuProcessReconnect(void *opaque) if (!priv->machineName) goto error; - if (qemuConnectCgroup(obj) < 0) + if (virConnectCgroup("qemu", obj, priv->cgroup, cfg->cgroupControllers, + priv->driver->privileged, priv->machineName) < 0) goto error; if (qemuDomainPerfRestart(obj) < 0) -- 2.27.0

On a Thursday in 2021, Praveen K Paladugu wrote:
Refactor some cgroup management methods from qemu into hypervisor. These methods will be shared by ch driver for cgroup management.
The QEMU driver fails to compile after this patch - it seems qemu_process.c needs to include the header with the functions. To get a build coverage for most of our supported platforms, you can push into your private fork of the libvirt repo on gitlab. The pipeline should run automatically. Jano
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/hypervisor/domain_cgroup.c | 426 ++++++++++++++++++++++++++++++++- src/hypervisor/domain_cgroup.h | 52 ++++ src/libvirt_private.syms | 10 + src/qemu/qemu_cgroup.c | 410 +------------------------------ src/qemu/qemu_cgroup.h | 11 - src/qemu/qemu_driver.c | 14 +- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 17 +- 8 files changed, 515 insertions(+), 429 deletions(-)

On 12/3/2021 11:38 AM, Ján Tomko wrote:
On a Thursday in 2021, Praveen K Paladugu wrote:
Refactor some cgroup management methods from qemu into hypervisor. These methods will be shared by ch driver for cgroup management.
The QEMU driver fails to compile after this patch - it seems qemu_process.c needs to include the header with the functions.
To get a build coverage for most of our supported platforms, you can push into your private fork of the libvirt repo on gitlab. The pipeline should run automatically.
Jano
Thanks for catching this. Just realized, I am only building ch driver in local checks. I will fix this immediately.
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/hypervisor/domain_cgroup.c | 426 ++++++++++++++++++++++++++++++++- src/hypervisor/domain_cgroup.h | 52 ++++ src/libvirt_private.syms | 10 + src/qemu/qemu_cgroup.c | 410 +------------------------------ src/qemu/qemu_cgroup.h | 11 - src/qemu/qemu_driver.c | 14 +- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 17 +- 8 files changed, 515 insertions(+), 429 deletions(-)
-- Regards, Praveen K Paladugu

On 12/3/2021 11:38 AM, Ján Tomko wrote:
On a Thursday in 2021, Praveen K Paladugu wrote:
Refactor some cgroup management methods from qemu into hypervisor. These methods will be shared by ch driver for cgroup management.
The QEMU driver fails to compile after this patch - it seems qemu_process.c needs to include the header with the functions.
To get a build coverage for most of our supported platforms, you can push into your private fork of the libvirt repo on gitlab. The pipeline should run automatically.
Thanks for the pointer Jano. I fixed the build issue and also confirmed majority of the builds pass in gitlab's CI.
Jano
Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/hypervisor/domain_cgroup.c | 426 ++++++++++++++++++++++++++++++++- src/hypervisor/domain_cgroup.h | 52 ++++ src/libvirt_private.syms | 10 + src/qemu/qemu_cgroup.c | 410 +------------------------------ src/qemu/qemu_cgroup.h | 11 - src/qemu/qemu_driver.c | 14 +- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 17 +- 8 files changed, 515 insertions(+), 429 deletions(-)
-- Regards, Praveen K Paladugu

From: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_conf.c | 2 + src/ch/ch_conf.h | 4 +- src/ch/ch_domain.c | 34 +++++ src/ch/ch_domain.h | 3 +- src/ch/ch_monitor.c | 96 ++++++++++++++ src/ch/ch_monitor.h | 54 +++++++- src/ch/ch_process.c | 306 ++++++++++++++++++++++++++++++++++++++++++-- src/ch/ch_process.h | 3 + 8 files changed, 484 insertions(+), 18 deletions(-) diff --git a/src/ch/ch_conf.c b/src/ch/ch_conf.c index ef6f4b5ba8..cfc1174354 100644 --- a/src/ch/ch_conf.c +++ b/src/ch/ch_conf.c @@ -129,6 +129,8 @@ virCHDriverConfigNew(bool privileged) if (!(cfg = virObjectNew(virCHDriverConfigClass))) return NULL; + cfg->cgroupControllers = -1; /* Auto detect */ + if (privileged) { if (virGetUserID(CH_USER, &cfg->user) < 0) return NULL; diff --git a/src/ch/ch_conf.h b/src/ch/ch_conf.h index 8fe69c8545..1790295ede 100644 --- a/src/ch/ch_conf.h +++ b/src/ch/ch_conf.h @@ -35,11 +35,13 @@ struct _virCHDriverConfig { char *stateDir; char *logDir; - + int cgroupControllers; uid_t user; gid_t group; }; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCHDriverConfig, virObjectUnref); + struct _virCHDriver { virMutex lock; diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index 326c3802c3..0a0b1206d6 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -322,6 +322,40 @@ chValidateDomainDeviceDef(const virDomainDeviceDef * dev, _("Serial can only be enabled for a PTY")); return -1; } + return 0; +} + +int +virCHDomainRefreshThreadInfo(virDomainObj * vm) +{ + size_t maxvcpus = virDomainDefGetVcpusMax(vm->def); + virCHMonitorThreadInfo *info = NULL; + size_t nthreads, ncpus = 0; + size_t i; + + nthreads = virCHMonitorGetThreadInfo(virCHDomainGetMonitor(vm), + true, &info); + + for (i = 0; i < nthreads; i++) { + virCHDomainVcpuPrivate *vcpupriv; + virDomainVcpuDef *vcpu; + virCHMonitorCPUInfo *vcpuInfo; + + if (info[i].type != virCHThreadTypeVcpu) + continue; + + // TODO: hotplug support + vcpuInfo = &info[i].vcpuInfo; + vcpu = virDomainDefGetVcpu(vm->def, vcpuInfo->cpuid); + vcpupriv = CH_DOMAIN_VCPU_PRIVATE(vcpu); + vcpupriv->tid = vcpuInfo->tid; + ncpus++; + } + + // TODO: Remove the warning when hotplug is implemented. + if (ncpus != maxvcpus) + VIR_WARN("Mismatch in the number of cpus, expected: %ld, actual: %ld", + maxvcpus, ncpus); return 0; } diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h index 3ac3421015..2ce3e2cef3 100644 --- a/src/ch/ch_domain.h +++ b/src/ch/ch_domain.h @@ -89,7 +89,8 @@ virCHDomainObjBeginJob(virDomainObj *obj, enum virCHDomainJob job) void virCHDomainObjEndJob(virDomainObj *obj); -int virCHDomainRefreshVcpuInfo(virDomainObj *vm); +int virCHDomainRefreshThreadInfo(virDomainObj *vm); + pid_t virCHDomainGetVcpuPid(virDomainObj *vm, unsigned int vcpuid); bool virCHDomainHasVcpuPids(virDomainObj *vm); diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index 6bc7d035ad..d7593d4aa6 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -41,6 +41,7 @@ VIR_LOG_INIT("ch.ch_monitor"); static virClass *virCHMonitorClass; static void virCHMonitorDispose(void *obj); +static void virCHMonitorThreadInfoFree(virCHMonitor * mon); static int virCHMonitorOnceInit(void) @@ -589,6 +590,7 @@ virCHMonitorDispose(void *opaque) virCHMonitor *mon = opaque; VIR_DEBUG("mon=%p", mon); + virCHMonitorThreadInfoFree(mon); virObjectUnref(mon->vm); } @@ -756,6 +758,100 @@ virCHMonitorGet(virCHMonitor * mon, const char *endpoint, return ret; } +static void +virCHMonitorThreadInfoFree(virCHMonitor * mon) +{ + mon->nthreads = 0; + if (mon->threads) + VIR_FREE(mon->threads); +} + +static size_t +virCHMonitorRefreshThreadInfo(virCHMonitor * mon) +{ + virCHMonitorThreadInfo *info = NULL; + g_autofree pid_t *tids = NULL; + virDomainObj *vm = mon->vm; + size_t ntids = 0; + size_t i; + + + virCHMonitorThreadInfoFree(mon); + if (virProcessGetPids(vm->pid, &ntids, &tids) < 0) { + mon->threads = NULL; + return 0; + } + + info = g_new0(virCHMonitorThreadInfo, ntids); + for (i = 0; i < ntids; i++) { + g_autofree char *proc = NULL; + g_autofree char *data = NULL; + + proc = g_strdup_printf("/proc/%d/task/%d/comm", + (int) vm->pid, (int) tids[i]); + + if (virFileReadAll(proc, (1 << 16), &data) < 0) { + continue; + } + + VIR_DEBUG("VM PID: %d, TID %d, COMM: %s", + (int) vm->pid, (int) tids[i], data); + if (STRPREFIX(data, "vcpu")) { + int cpuid; + char *tmp; + + if (virStrToLong_i(data + 4, &tmp, 0, &cpuid) < 0) { + VIR_WARN("Index is not specified correctly"); + continue; + } + info[i].type = virCHThreadTypeVcpu; + info[i].vcpuInfo.tid = tids[i]; + info[i].vcpuInfo.online = true; + info[i].vcpuInfo.cpuid = cpuid; + VIR_DEBUG("vcpu%d -> tid: %d", cpuid, tids[i]); + } else if (STRPREFIX(data, "_disk") || STRPREFIX(data, "_net") || + STRPREFIX(data, "_rng")) { + /* Prefixes used by cloud-hypervisor for IO Threads are captured at + * https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/vmm/src/devic... */ + info[i].type = virCHThreadTypeIO; + info[i].ioInfo.tid = tids[i]; + virStrcpy(info[i].ioInfo.thrName, data, VIRCH_THREAD_NAME_LEN - 1); + } else { + info[i].type = virCHThreadTypeEmulator; + info[i].emuInfo.tid = tids[i]; + virStrcpy(info[i].emuInfo.thrName, data, VIRCH_THREAD_NAME_LEN - 1); + } + mon->nthreads++; + + } + mon->threads = info; + + return mon->nthreads; +} + +/** + * virCHMonitorGetThreadInfo: + * @mon: Pointer to the monitor + * @refresh: Refresh thread info or not + * + * Retrive thread info and store to @threads + * + * Returns count of threads on success. + */ +size_t +virCHMonitorGetThreadInfo(virCHMonitor * mon, bool refresh, + virCHMonitorThreadInfo ** threads) +{ + int nthreads = 0; + + if (refresh) + nthreads = virCHMonitorRefreshThreadInfo(mon); + + *threads = mon->threads; + + return nthreads; +} + int virCHMonitorShutdownVMM(virCHMonitor * mon) { diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h index 8ca9e17a9a..f8c3fa75e8 100644 --- a/src/ch/ch_monitor.h +++ b/src/ch/ch_monitor.h @@ -37,6 +37,50 @@ #define URL_VM_RESUME "vm.resume" #define URL_VM_INFO "vm.info" +#define VIRCH_THREAD_NAME_LEN 16 + +typedef enum { + virCHThreadTypeEmulator, + virCHThreadTypeVcpu, + virCHThreadTypeIO, + virCHThreadTypeMax +} virCHThreadType; + +typedef struct _virCHMonitorCPUInfo virCHMonitorCPUInfo; + +struct _virCHMonitorCPUInfo { + int cpuid; + pid_t tid; + + bool online; +}; + +typedef struct _virCHMonitorEmuThreadInfo virCHMonitorEmuThreadInfo; + +struct _virCHMonitorEmuThreadInfo { + char thrName[VIRCH_THREAD_NAME_LEN]; + pid_t tid; +}; + +typedef struct _virCHMonitorIOThreadInfo virCHMonitorIOThreadInfo; + +struct _virCHMonitorIOThreadInfo { + char thrName[VIRCH_THREAD_NAME_LEN]; + pid_t tid; +}; + +typedef struct _virCHMonitorThreadInfo virCHMonitorThreadInfo; + +struct _virCHMonitorThreadInfo { + virCHThreadType type; + + union { + virCHMonitorCPUInfo vcpuInfo; + virCHMonitorEmuThreadInfo emuInfo; + virCHMonitorIOThreadInfo ioInfo; + }; +}; + typedef struct _virCHMonitor virCHMonitor; struct _virCHMonitor { @@ -49,6 +93,9 @@ struct _virCHMonitor { pid_t pid; virDomainObj *vm; + + size_t nthreads; + virCHMonitorThreadInfo *threads; }; virCHMonitor *virCHMonitorNew(virDomainObj *vm, const char *socketdir); @@ -65,12 +112,9 @@ int virCHMonitorSuspendVM(virCHMonitor *mon); int virCHMonitorResumeVM(virCHMonitor *mon); int virCHMonitorGetInfo(virCHMonitor *mon, virJSONValue **info); -typedef struct _virCHMonitorCPUInfo virCHMonitorCPUInfo; -struct _virCHMonitorCPUInfo { - pid_t tid; - bool online; -}; void virCHMonitorCPUInfoFree(virCHMonitorCPUInfo *cpus); int virCHMonitorGetCPUInfo(virCHMonitor *mon, virCHMonitorCPUInfo **vcpus, size_t maxvcpus); +size_t virCHMonitorGetThreadInfo(virCHMonitor *mon, bool refresh, + virCHMonitorThreadInfo **threads); diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c index 3b7f6fcddf..7a51531224 100644 --- a/src/ch/ch_process.c +++ b/src/ch/ch_process.c @@ -26,6 +26,8 @@ #include "ch_domain.h" #include "ch_monitor.h" #include "ch_process.h" +#include "domain_cgroup.h" +#include "virnuma.h" #include "viralloc.h" #include "virerror.h" #include "virjson.h" @@ -133,6 +135,254 @@ virCHProcessUpdateInfo(virDomainObj *vm) return 0; } +static int +virCHProcessGetAllCpuAffinity(virBitmap ** cpumapRet) +{ + *cpumapRet = NULL; + + if (!virHostCPUHasBitmap()) + return 0; + + if (!(*cpumapRet = virHostCPUGetOnlineBitmap())) + return -1; + + return 0; +} + +#if defined(WITH_SCHED_GETAFFINITY) || defined(WITH_BSD_CPU_AFFINITY) +static int +virCHProcessInitCpuAffinity(virDomainObj * vm) +{ + g_autoptr(virBitmap) cpumapToSet = NULL; + virDomainNumatuneMemMode mem_mode; + virCHDomainObjPrivate *priv = vm->privateData; + + if (!vm->pid) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot setup CPU affinity until process is started")); + return -1; + } + + if (virDomainNumaGetNodeCount(vm->def->numa) <= 1 && + virDomainNumatuneGetMode(vm->def->numa, -1, &mem_mode) == 0 && + mem_mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT) { + virBitmap *nodeset = NULL; + + if (virDomainNumatuneMaybeGetNodeset(vm->def->numa, + priv->autoNodeset, + &nodeset, -1) < 0) + return -1; + + if (virNumaNodesetToCPUset(nodeset, &cpumapToSet) < 0) + return -1; + } else if (vm->def->cputune.emulatorpin) { + if (!(cpumapToSet = virBitmapNewCopy(vm->def->cputune.emulatorpin))) + return -1; + } else { + if (virCHProcessGetAllCpuAffinity(&cpumapToSet) < 0) + return -1; + } + + if (cpumapToSet && virProcessSetAffinity(vm->pid, cpumapToSet, false) < 0) { + return -1; + } + + return 0; +} +#else /* !defined(WITH_SCHED_GETAFFINITY) && !defined(WITH_BSD_CPU_AFFINITY) */ +static int +virCHProcessInitCpuAffinity(virDomainObj * vm G_GNUC_UNUSED) +{ + return 0; +} +#endif /* !defined(WITH_SCHED_GETAFFINITY) && !defined(WITH_BSD_CPU_AFFINITY) */ + +/** + * virCHProcessSetupPid: + * + * This function sets resource properties (affinity, cgroups, + * scheduler) for any PID associated with a domain. It should be used + * to set up emulator PIDs as well as vCPU and I/O thread pids to + * ensure they are all handled the same way. + * + * Returns 0 on success, -1 on error. + */ +static int +virCHProcessSetupPid(virDomainObj *vm, + pid_t pid, + virCgroupThreadName nameval, + int id, + virBitmap *cpumask, + unsigned long long period, + long long quota, + virDomainThreadSchedParam *sched) +{ + virCHDomainObjPrivate *priv = vm->privateData; + virDomainNumatuneMemMode mem_mode; + virCgroup *cgroup = NULL; + virBitmap *use_cpumask = NULL; + virBitmap *affinity_cpumask = NULL; + g_autoptr(virBitmap) hostcpumap = NULL; + g_autofree char *mem_mask = NULL; + int ret = -1; + + if ((period || quota) && + !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cgroup cpu is required for scheduler tuning")); + goto cleanup; + } + + /* Infer which cpumask shall be used. */ + if (cpumask) { + use_cpumask = cpumask; + } else if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) { + use_cpumask = priv->autoCpuset; + } else if (vm->def->cpumask) { + use_cpumask = vm->def->cpumask; + } else { + /* we can't assume cloud-hypervisor itself is running on all pCPUs, + * so we need to explicitly set the spawned instance to all pCPUs. */ + if (virCHProcessGetAllCpuAffinity(&hostcpumap) < 0) + goto cleanup; + affinity_cpumask = hostcpumap; + } + + /* + * If CPU cgroup controller is not initialized here, then we need + * neither period nor quota settings. And if CPUSET controller is + * not initialized either, then there's nothing to do anyway. + */ + if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU) || + virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { + + if (virDomainNumatuneGetMode(vm->def->numa, -1, &mem_mode) == 0 && + mem_mode == VIR_DOMAIN_NUMATUNE_MEM_STRICT && + virDomainNumatuneMaybeFormatNodeset(vm->def->numa, + priv->autoNodeset, + &mem_mask, -1) < 0) + goto cleanup; + + if (virCgroupNewThread(priv->cgroup, nameval, id, true, &cgroup) < 0) + goto cleanup; + + if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { + if (use_cpumask && + virSetupCgroupCpusetCpus(cgroup, use_cpumask) < 0) + goto cleanup; + + if (mem_mask && virCgroupSetCpusetMems(cgroup, mem_mask) < 0) + goto cleanup; + + } + + if ((period || quota) && + virSetupCgroupVcpuBW(cgroup, period, quota) < 0) + goto cleanup; + + /* Move the thread to the sub dir */ + VIR_INFO("Adding pid %d to cgroup", pid); + if (virCgroupAddThread(cgroup, pid) < 0) + goto cleanup; + + } + + if (!affinity_cpumask) + affinity_cpumask = use_cpumask; + + /* Setup legacy affinity. */ + if (affinity_cpumask + && virProcessSetAffinity(pid, affinity_cpumask, false) < 0) + goto cleanup; + + /* Set scheduler type and priority, but not for the main thread. */ + if (sched && + nameval != VIR_CGROUP_THREAD_EMULATOR && + virProcessSetScheduler(pid, sched->policy, sched->priority) < 0) + goto cleanup; + + ret = 0; + cleanup: + if (cgroup) { + if (ret < 0) + virCgroupRemove(cgroup); + virCgroupFree(cgroup); + } + + return ret; +} + +/** + * virCHProcessSetupVcpu: + * @vm: domain object + * @vcpuid: id of VCPU to set defaults + * + * This function sets resource properties (cgroups, affinity, scheduler) for a + * vCPU. This function expects that the vCPU is online and the vCPU pids were + * correctly detected at the point when it's called. + * + * Returns 0 on success, -1 on error. + */ +int +virCHProcessSetupVcpu(virDomainObj * vm, unsigned int vcpuid) +{ + pid_t vcpupid = virCHDomainGetVcpuPid(vm, vcpuid); + virDomainVcpuDef *vcpu = virDomainDefGetVcpu(vm->def, vcpuid); + + return virCHProcessSetupPid(vm, vcpupid, VIR_CGROUP_THREAD_VCPU, + vcpuid, vcpu->cpumask, + vm->def->cputune.period, + vm->def->cputune.quota, &vcpu->sched); +} + +static int +virCHProcessSetupVcpus(virDomainObj * vm) +{ + virDomainVcpuDef *vcpu; + unsigned int maxvcpus = virDomainDefGetVcpusMax(vm->def); + size_t i; + + if ((vm->def->cputune.period || vm->def->cputune.quota) && + !virCgroupHasController(((virCHDomainObjPrivate *) vm->privateData)-> + cgroup, VIR_CGROUP_CONTROLLER_CPU)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("cgroup cpu is required for scheduler tuning")); + return -1; + } + + if (!virCHDomainHasVcpuPids(vm)) { + /* If any CPU has custom affinity that differs from the + * VM default affinity, we must reject it */ + for (i = 0; i < maxvcpus; i++) { + vcpu = virDomainDefGetVcpu(vm->def, i); + + if (!vcpu->online) + continue; + + if (vcpu->cpumask && + !virBitmapEqual(vm->def->cpumask, vcpu->cpumask)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cpu affinity is not supported")); + return -1; + } + } + + return 0; + } + + for (i = 0; i < maxvcpus; i++) { + vcpu = virDomainDefGetVcpu(vm->def, i); + + if (!vcpu->online) + continue; + + if (virCHProcessSetupVcpu(vm, i) < 0) + return -1; + } + + return 0; +} + /** * virCHProcessStart: * @driver: pointer to driver structure @@ -143,12 +393,13 @@ virCHProcessUpdateInfo(virDomainObj *vm) * * Returns 0 on success or -1 in case of error */ -int virCHProcessStart(virCHDriver *driver, - virDomainObj *vm, - virDomainRunningReason reason) +int +virCHProcessStart(virCHDriver * driver, + virDomainObj * vm, virDomainRunningReason reason) { int ret = -1; virCHDomainObjPrivate *priv = vm->privateData; + g_autoptr(virCHDriverConfig) cfg = virCHDriverGetConfig(priv->driver); g_autofree int *nicindexes = NULL; size_t nnicindexes = 0; @@ -168,18 +419,39 @@ int virCHProcessStart(virCHDriver *driver, } } + vm->pid = priv->monitor->pid; + vm->def->id = vm->pid; + priv->machineName = virCHDomainGetMachineName(vm); + + if (virSetupCgroup("ch", vm, + nnicindexes, nicindexes, + priv->cgroup, + cfg->cgroupControllers, + 0, /*maxThreadsPerProc*/ + priv->driver->privileged, + priv->machineName) < 0) + goto cleanup; + + if (virCHProcessInitCpuAffinity(vm) < 0) + goto cleanup; + if (virCHMonitorBootVM(priv->monitor) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("failed to boot guest VM")); goto cleanup; } - priv->machineName = virCHDomainGetMachineName(vm); - vm->pid = priv->monitor->pid; - vm->def->id = vm->pid; + virCHDomainRefreshThreadInfo(vm); - virCHProcessUpdateInfo(vm); + VIR_DEBUG("Setting global CPU cgroup (if required)"); + if (virSetupGlobalCpuCgroup(vm, priv->cgroup, priv->autoNodeset) < 0) + goto cleanup; + + VIR_DEBUG("Setting vCPU tuning/settings"); + if (virCHProcessSetupVcpus(vm) < 0) + goto cleanup; + virCHProcessUpdateInfo(vm); virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); return 0; @@ -191,20 +463,32 @@ int virCHProcessStart(virCHDriver *driver, return ret; } -int virCHProcessStop(virCHDriver *driver G_GNUC_UNUSED, - virDomainObj *vm, - virDomainShutoffReason reason) +int +virCHProcessStop(virCHDriver * driver G_GNUC_UNUSED, + virDomainObj * vm, virDomainShutoffReason reason) { + int ret; + int retries = 0; virCHDomainObjPrivate *priv = vm->privateData; VIR_DEBUG("Stopping VM name=%s pid=%d reason=%d", - vm->def->name, (int)vm->pid, (int)reason); + vm->def->name, (int) vm->pid, (int) reason); if (priv->monitor) { virCHMonitorClose(priv->monitor); priv->monitor = NULL; } + retry: + if ((ret = virRemoveCgroup(vm, priv->cgroup, priv->machineName)) < 0) { + if (ret == -EBUSY && (retries++ < 5)) { + g_usleep(200*1000); + goto retry; + } + VIR_WARN("Failed to remove cgroup for %s", + vm->def->name); + } + vm->pid = -1; vm->def->id = -1; diff --git a/src/ch/ch_process.h b/src/ch/ch_process.h index abc4915979..800e3f4e23 100644 --- a/src/ch/ch_process.h +++ b/src/ch/ch_process.h @@ -29,3 +29,6 @@ int virCHProcessStart(virCHDriver *driver, int virCHProcessStop(virCHDriver *driver, virDomainObj *vm, virDomainShutoffReason reason); + +int virCHProcessSetupVcpu(virDomainObj *vm, + unsigned int vcpuid); -- 2.27.0

From: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 30 +++++++++ src/ch/ch_domain.h | 1 + src/ch/ch_driver.c | 151 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c index 0a0b1206d6..de084ca15e 100644 --- a/src/ch/ch_domain.c +++ b/src/ch/ch_domain.c @@ -20,6 +20,7 @@ #include <config.h> +#include "datatypes.h" #include "ch_domain.h" #include "domain_driver.h" #include "viralloc.h" @@ -418,3 +419,32 @@ virCHDomainGetMachineName(virDomainObj * vm) return ret; } + +/** + * virCHDomainObjFromDomain: + * @domain: Domain pointer that has to be looked up + * + * This function looks up @domain and returns the appropriate virDomainObjPtr + * that has to be released by calling virDomainObjEndAPI(). + * + * Returns the domain object with incremented reference counter which is locked + * on success, NULL otherwise. + */ +virDomainObj * +virCHDomainObjFromDomain(virDomainPtr domain) +{ + virDomainObj *vm; + virCHDriver *driver = domain->conn->privateData; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + vm = virDomainObjListFindByUUID(driver->domains, domain->uuid); + if (!vm) { + virUUIDFormat(domain->uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s' (%s)"), + uuidstr, domain->name); + return NULL; + } + + return vm; +} diff --git a/src/ch/ch_domain.h b/src/ch/ch_domain.h index 2ce3e2cef3..db1451405b 100644 --- a/src/ch/ch_domain.h +++ b/src/ch/ch_domain.h @@ -95,3 +95,4 @@ pid_t virCHDomainGetVcpuPid(virDomainObj *vm, unsigned int vcpuid); bool virCHDomainHasVcpuPids(virDomainObj *vm); char *virCHDomainGetMachineName(virDomainObj *vm); +virDomainObj *virCHDomainObjFromDomain(virDomain *domain); diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 39e754d1ff..400dfee766 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -25,6 +25,7 @@ #include "ch_driver.h" #include "ch_monitor.h" #include "ch_process.h" +#include "domain_cgroup.h" #include "datatypes.h" #include "driver.h" #include "viraccessapicheck.h" @@ -1129,6 +1130,154 @@ chDomainGetVcpus(virDomainPtr dom, return ret; } +static int +chDomainPinVcpuLive(virDomainObj *vm, + virDomainDef *def, + int vcpu, + virCHDriver *driver, + virCHDriverConfig *cfg, + virBitmap *cpumap) +{ + virBitmap *tmpmap = NULL; + virDomainVcpuDef *vcpuinfo; + virCHDomainObjPrivate *priv = vm->privateData; + virCgroup *cgroup_vcpu = NULL; + g_autofree char *str = NULL; + int ret = -1; + + if (!virCHDomainHasVcpuPids(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cpu affinity is not supported")); + goto cleanup; + } + + if (!(vcpuinfo = virDomainDefGetVcpu(def, vcpu))) { + virReportError(VIR_ERR_INVALID_ARG, + _("vcpu %d is out of range of live cpu count %d"), + vcpu, virDomainDefGetVcpusMax(def)); + goto cleanup; + } + + if (!(tmpmap = virBitmapNewCopy(cpumap))) + goto cleanup; + + if (!(str = virBitmapFormat(cpumap))) + goto cleanup; + + if (vcpuinfo->online) { + /* Configure the corresponding cpuset cgroup before set affinity. */ + if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { + if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, vcpu, + false, &cgroup_vcpu) < 0) + goto cleanup; + if (virSetupCgroupCpusetCpus(cgroup_vcpu, cpumap) < 0) + goto cleanup; + } + + if (virProcessSetAffinity(virCHDomainGetVcpuPid(vm, vcpu), cpumap, false) < 0) + goto cleanup; + } + + virBitmapFree(vcpuinfo->cpumask); + vcpuinfo->cpumask = tmpmap; + tmpmap = NULL; + + if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virBitmapFree(tmpmap); + virCgroupFree(cgroup_vcpu); + return ret; +} + + +static int +chDomainPinVcpuFlags(virDomainPtr dom, + unsigned int vcpu, + unsigned char *cpumap, + int maplen, + unsigned int flags) +{ + virCHDriver *driver = dom->conn->privateData; + virDomainObj *vm; + virDomainDef *def; + virDomainDef *persistentDef; + int ret = -1; + virBitmap *pcpumap = NULL; + virDomainVcpuDef *vcpuinfo = NULL; + g_autoptr(virCHDriverConfig) cfg = NULL; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + cfg = virCHDriverGetConfig(driver); + + if (!(vm = virCHDomainObjFromDomain(dom))) + goto cleanup; + + if (virDomainPinVcpuFlagsEnsureACL(dom->conn, vm->def, flags) < 0) + goto cleanup; + + if (virCHDomainObjBeginJob(vm, CH_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0) + goto endjob; + + if (persistentDef && + !(vcpuinfo = virDomainDefGetVcpu(persistentDef, vcpu))) { + virReportError(VIR_ERR_INVALID_ARG, + _("vcpu %d is out of range of persistent cpu count %d"), + vcpu, virDomainDefGetVcpus(persistentDef)); + goto endjob; + } + + if (!(pcpumap = virBitmapNewData(cpumap, maplen))) + goto endjob; + + if (virBitmapIsAllClear(pcpumap)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Empty cpu list for pinning")); + goto endjob; + } + + if (def && + chDomainPinVcpuLive(vm, def, vcpu, driver, cfg, pcpumap) < 0) + goto endjob; + + if (persistentDef) { + virBitmapFree(vcpuinfo->cpumask); + vcpuinfo->cpumask = pcpumap; + pcpumap = NULL; + + // ret = virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir); + goto endjob; + } + + ret = 0; + + endjob: + virCHDomainObjEndJob(vm); + + cleanup: + virDomainObjEndAPI(&vm); + virBitmapFree(pcpumap); + return ret; +} + +static int +chDomainPinVcpu(virDomainPtr dom, + unsigned int vcpu, + unsigned char *cpumap, + int maplen) +{ + return chDomainPinVcpuFlags(dom, vcpu, cpumap, maplen, + VIR_DOMAIN_AFFECT_LIVE); +} + /* Function Tables */ static virHypervisorDriver chHypervisorDriver = { .name = "CH", @@ -1169,6 +1318,8 @@ static virHypervisorDriver chHypervisorDriver = { .domainGetVcpusFlags = chDomainGetVcpusFlags, /* 7.11.0 */ .domainGetMaxVcpus = chDomainGetMaxVcpus, /* 7.11.0 */ .domainGetVcpuPinInfo = chDomainGetVcpuPinInfo, /* 7.11.0 */ + .domainPinVcpu = chDomainPinVcpu, /* 7.11.0 */ + .domainPinVcpuFlags = chDomainPinVcpuFlags, /* 7.11.0 */ .nodeGetCPUMap = chNodeGetCPUMap, /* 7.11.0 */ }; -- 2.27.0

On a Thursday in 2021, Praveen K Paladugu wrote:
From: Vineeth Pillai <viremana@linux.microsoft.com>
Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_domain.c | 30 +++++++++ src/ch/ch_domain.h | 1 + src/ch/ch_driver.c | 151 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+)
@@ -1129,6 +1130,154 @@ chDomainGetVcpus(virDomainPtr dom, return ret; }
+static int +chDomainPinVcpuLive(virDomainObj *vm, + virDomainDef *def, + int vcpu, + virCHDriver *driver, + virCHDriverConfig *cfg, + virBitmap *cpumap) +{ + virBitmap *tmpmap = NULL;
You can use g_autoptr(virBitmap) tmpmap = NULL; to automatically free the memory when it goes out of scope instead of manually calling virBitmapFree
+ virDomainVcpuDef *vcpuinfo; + virCHDomainObjPrivate *priv = vm->privateData; + virCgroup *cgroup_vcpu = NULL; + g_autofree char *str = NULL; + int ret = -1; + + if (!virCHDomainHasVcpuPids(vm)) { +
+ if (persistentDef) { + virBitmapFree(vcpuinfo->cpumask); + vcpuinfo->cpumask = pcpumap; + pcpumap = NULL; + + // ret = virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir);
There's no need for this comment.
+ goto endjob;
Jano

From: Vineeth Pillai <viremana@linux.microsoft.com> Enable support of VIR_DRV_FEATURE_TYPED_PARAM_STRING to enable numatune Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_driver.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 400dfee766..c6dcc33f5e 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -946,6 +946,36 @@ chStateInitialize(bool privileged, return ret; } +/* Which features are supported by this driver? */ +static int +chConnectSupportsFeature(virConnectPtr conn, int feature) +{ + if (virConnectSupportsFeatureEnsureACL(conn) < 0) + return -1; + + switch ((virDrvFeature) feature) { + case VIR_DRV_FEATURE_TYPED_PARAM_STRING: + return 1; + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_V3: + case VIR_DRV_FEATURE_MIGRATION_P2P: + case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION: + case VIR_DRV_FEATURE_FD_PASSING: + case VIR_DRV_FEATURE_XML_MIGRATABLE: + case VIR_DRV_FEATURE_MIGRATION_OFFLINE: + case VIR_DRV_FEATURE_MIGRATION_PARAMS: + case VIR_DRV_FEATURE_MIGRATION_DIRECT: + case VIR_DRV_FEATURE_MIGRATION_V1: + case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE: + case VIR_DRV_FEATURE_REMOTE: + case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK: + case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK: + case VIR_DRV_FEATURE_NETWORK_UPDATE_HAS_CORRECT_ORDER: + default: + return 0; + } +} + static int chDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) { @@ -1291,6 +1321,7 @@ static virHypervisorDriver chHypervisorDriver = { .connectListAllDomains = chConnectListAllDomains, /* 7.5.0 */ .connectListDomains = chConnectListDomains, /* 7.5.0 */ .connectGetCapabilities = chConnectGetCapabilities, /* 7.5.0 */ + .connectSupportsFeature = chConnectSupportsFeature, /* 7.11.0 */ .domainCreateXML = chDomainCreateXML, /* 7.5.0 */ .domainCreate = chDomainCreate, /* 7.5.0 */ .domainCreateWithFlags = chDomainCreateWithFlags, /* 7.5.0 */ -- 2.27.0

From: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com> Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_driver.c | 316 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 297 insertions(+), 19 deletions(-) diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index c6dcc33f5e..8c14829d2a 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -43,6 +43,7 @@ #include "viruri.h" #include "virutil.h" #include "viruuid.h" +#include "virnuma.h" #define VIR_FROM_THIS VIR_FROM_CH @@ -954,25 +955,25 @@ chConnectSupportsFeature(virConnectPtr conn, int feature) return -1; switch ((virDrvFeature) feature) { - case VIR_DRV_FEATURE_TYPED_PARAM_STRING: - return 1; - case VIR_DRV_FEATURE_MIGRATION_V2: - case VIR_DRV_FEATURE_MIGRATION_V3: - case VIR_DRV_FEATURE_MIGRATION_P2P: - case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION: - case VIR_DRV_FEATURE_FD_PASSING: - case VIR_DRV_FEATURE_XML_MIGRATABLE: - case VIR_DRV_FEATURE_MIGRATION_OFFLINE: - case VIR_DRV_FEATURE_MIGRATION_PARAMS: - case VIR_DRV_FEATURE_MIGRATION_DIRECT: - case VIR_DRV_FEATURE_MIGRATION_V1: - case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE: - case VIR_DRV_FEATURE_REMOTE: - case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK: - case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK: - case VIR_DRV_FEATURE_NETWORK_UPDATE_HAS_CORRECT_ORDER: - default: - return 0; + case VIR_DRV_FEATURE_TYPED_PARAM_STRING: + return 1; + case VIR_DRV_FEATURE_MIGRATION_V2: + case VIR_DRV_FEATURE_MIGRATION_V3: + case VIR_DRV_FEATURE_MIGRATION_P2P: + case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION: + case VIR_DRV_FEATURE_FD_PASSING: + case VIR_DRV_FEATURE_XML_MIGRATABLE: + case VIR_DRV_FEATURE_MIGRATION_OFFLINE: + case VIR_DRV_FEATURE_MIGRATION_PARAMS: + case VIR_DRV_FEATURE_MIGRATION_DIRECT: + case VIR_DRV_FEATURE_MIGRATION_V1: + case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE: + case VIR_DRV_FEATURE_REMOTE: + case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK: + case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK: + case VIR_DRV_FEATURE_NETWORK_UPDATE_HAS_CORRECT_ORDER: + default: + return 0; } } @@ -1308,6 +1309,281 @@ chDomainPinVcpu(virDomainPtr dom, VIR_DOMAIN_AFFECT_LIVE); } +#define CH_NB_NUMA_PARAM 2 + +static int +chDomainGetNumaParameters(virDomainPtr dom, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + size_t i; + virDomainObj *vm = NULL; + virDomainNumatuneMemMode tmpmode = VIR_DOMAIN_NUMATUNE_MEM_STRICT; + virCHDomainObjPrivate *priv; + g_autofree char *nodeset = NULL; + int ret = -1; + virDomainDef *def = NULL; + bool live = false; + virBitmap *autoNodeset = NULL; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG | + VIR_TYPED_PARAM_STRING_OKAY, -1); + + if (!(vm = virCHDomainObjFromDomain(dom))) + return -1; + priv = vm->privateData; + + if (virDomainGetNumaParametersEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (!(def = virDomainObjGetOneDefState(vm, flags, &live))) + goto cleanup; + + if (live) + autoNodeset = priv->autoNodeset; + + if ((*nparams) == 0) { + *nparams = CH_NB_NUMA_PARAM; + ret = 0; + goto cleanup; + } + + for (i = 0; i < CH_NB_NUMA_PARAM && i < *nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + + switch (i) { + case 0: /* fill numa mode here */ + ignore_value(virDomainNumatuneGetMode(def->numa, -1, &tmpmode)); + + if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE, + VIR_TYPED_PARAM_INT, tmpmode) < 0) + goto cleanup; + + break; + + case 1: /* fill numa nodeset here */ + nodeset = virDomainNumatuneFormatNodeset(def->numa, autoNodeset, -1); + + if (!nodeset || + virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET, + VIR_TYPED_PARAM_STRING, nodeset) < 0) + goto cleanup; + + nodeset = NULL; + break; + + /* coverity[dead_error_begin] */ + default: + break; + /* should not hit here */ + } + } + + if (*nparams > CH_NB_NUMA_PARAM) + *nparams = CH_NB_NUMA_PARAM; + ret = 0; + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + +static int +chDomainSetNumaParamsLive(virDomainObj *vm, + virBitmap *nodeset) +{ + virCgroup *cgroup_temp = NULL; + virCHDomainObjPrivate *priv = vm->privateData; + g_autofree char *nodeset_str = NULL; + virDomainNumatuneMemMode mode; + size_t i = 0; + int ret = -1; + + if (virDomainNumatuneGetMode(vm->def->numa, -1, &mode) == 0 && + mode != VIR_DOMAIN_NUMATUNE_MEM_STRICT) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("change of nodeset for running domain " + "requires strict numa mode")); + goto cleanup; + } + + if (!virNumaNodesetIsAvailable(nodeset)) + goto cleanup; + + /* Ensure the cpuset string is formatted before passing to cgroup */ + if (!(nodeset_str = virBitmapFormat(nodeset))) + goto cleanup; + + if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_EMULATOR, 0, + false, &cgroup_temp) < 0 || + virCgroupSetCpusetMems(cgroup_temp, nodeset_str) < 0) + goto cleanup; + virCgroupFree(cgroup_temp); + + for (i = 0; i < virDomainDefGetVcpusMax(vm->def); i++) { + virDomainVcpuDef *vcpu = virDomainDefGetVcpu(vm->def, i); + + if (!vcpu->online) + continue; + + if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, i, + false, &cgroup_temp) < 0 || + virCgroupSetCpusetMems(cgroup_temp, nodeset_str) < 0) + goto cleanup; + virCgroupFree(cgroup_temp); + } + + for (i = 0; i < vm->def->niothreadids; i++) { + if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_IOTHREAD, + vm->def->iothreadids[i]->iothread_id, + false, &cgroup_temp) < 0 || + virCgroupSetCpusetMems(cgroup_temp, nodeset_str) < 0) + goto cleanup; + virCgroupFree(cgroup_temp); + } + + /* set nodeset for root cgroup */ + if (virCgroupSetCpusetMems(priv->cgroup, nodeset_str) < 0) + goto cleanup; + + ret = 0; + cleanup: + virCgroupFree(cgroup_temp); + + return ret; +} + +static int +chDomainSetNumaParameters(virDomainPtr dom, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virCHDriver *driver = dom->conn->privateData; + size_t i; + virDomainDef *def; + virDomainDef *persistentDef; + virDomainObj *vm = NULL; + int ret = -1; + g_autoptr(virCHDriverConfig) cfg = NULL; + virCHDomainObjPrivate *priv; + virBitmap *nodeset = NULL; + virDomainNumatuneMemMode config_mode; + int mode = -1; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + if (virTypedParamsValidate(params, nparams, + VIR_DOMAIN_NUMA_MODE, + VIR_TYPED_PARAM_INT, + VIR_DOMAIN_NUMA_NODESET, + VIR_TYPED_PARAM_STRING, + NULL) < 0) + return -1; + + if (!(vm = virCHDomainObjFromDomain(dom))) + return -1; + + priv = vm->privateData; + cfg = virCHDriverGetConfig(driver); + + if (virDomainSetNumaParametersEnsureACL(dom->conn, vm->def, flags) < 0) + goto cleanup; + + for (i = 0; i < nparams; i++) { + virTypedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, VIR_DOMAIN_NUMA_MODE)) { + mode = param->value.i; + + if (mode < 0 || mode >= VIR_DOMAIN_NUMATUNE_MEM_LAST) { + virReportError(VIR_ERR_INVALID_ARG, + _("unsupported numatune mode: '%d'"), mode); + goto cleanup; + } + + } else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) { + if (virBitmapParse(param->value.s, &nodeset, + VIR_DOMAIN_CPUMASK_LEN) < 0) + goto cleanup; + + if (virBitmapIsAllClear(nodeset)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("Invalid nodeset of 'numatune': %s"), + param->value.s); + goto cleanup; + } + } + } + + if (virCHDomainObjBeginJob(vm, CH_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0) + goto endjob; + + if (def) { + if (!driver->privileged) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("NUMA tuning is not available in session mode")); + goto endjob; + } + + if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cgroup cpuset controller is not mounted")); + goto endjob; + } + + if (mode != -1 && + virDomainNumatuneGetMode(def->numa, -1, &config_mode) == 0 && + config_mode != mode) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("can't change numatune mode for running domain")); + goto endjob; + } + + if (nodeset && + chDomainSetNumaParamsLive(vm, nodeset) < 0) + goto endjob; + + if (virDomainNumatuneSet(def->numa, + def->placement_mode == + VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC, + -1, mode, nodeset) < 0) + goto endjob; + + if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) + goto endjob; + } + + /* + if (persistentDef) { + if (virDomainNumatuneSet(persistentDef->numa, + persistentDef->placement_mode == + VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC, + -1, mode, nodeset) < 0) + goto endjob; + + if (virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0) + goto endjob; + } + */ + + ret = 0; + + endjob: + virCHDomainObjEndJob(vm); + + cleanup: + virBitmapFree(nodeset); + virDomainObjEndAPI(&vm); + return ret; +} + /* Function Tables */ static virHypervisorDriver chHypervisorDriver = { .name = "CH", @@ -1352,6 +1628,8 @@ static virHypervisorDriver chHypervisorDriver = { .domainPinVcpu = chDomainPinVcpu, /* 7.11.0 */ .domainPinVcpuFlags = chDomainPinVcpuFlags, /* 7.11.0 */ .nodeGetCPUMap = chNodeGetCPUMap, /* 7.11.0 */ + .domainSetNumaParameters = chDomainSetNumaParameters, /* 7.11.0 */ + .domainGetNumaParameters = chDomainGetNumaParameters, /* 7.11.0 */ }; static virConnectDriver chConnectDriver = { -- 2.27.0

using virCHProcessSetupPid Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_monitor.c | 60 ++++++++++++++++++++++++++++++++++ src/ch/ch_monitor.h | 2 ++ src/ch/ch_process.c | 78 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index d7593d4aa6..308487b4ff 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -941,3 +941,63 @@ virCHMonitorGetInfo(virCHMonitor * mon, virJSONValue ** info) { return virCHMonitorGet(mon, URL_VM_INFO, info); } + +/** + * virCHMonitorGetIOThreads: + * @mon: Pointer to the monitor + * @iothreads: Location to return array of IOThreadInfo data + * + * Retrieve the list of iothreads defined/running for the machine + * + * Returns count of IOThreadInfo structures on success + * -1 on error. + */ +int virCHMonitorGetIOThreads(virCHMonitor *mon, + virDomainIOThreadInfo ***iothreads) +{ + size_t nthreads = 0, niothreads = 0; + int thd_index; + virDomainIOThreadInfo **iothreadinfolist = NULL, *iothreadinfo = NULL; + + *iothreads = NULL; + nthreads = virCHMonitorRefreshThreadInfo(mon); + + iothreadinfolist = g_new0(virDomainIOThreadInfo*, nthreads); + + for (thd_index = 0; thd_index < nthreads; thd_index++) { + virBitmap *map = NULL; + if (mon->threads[thd_index].type == virCHThreadTypeIO) { + iothreadinfo = g_new0(virDomainIOThreadInfo, 1); + + iothreadinfo->iothread_id = mon->threads[thd_index].ioInfo.tid; + + if (!(map = virProcessGetAffinity(iothreadinfo->iothread_id))) + goto cleanup; + + if (virBitmapToData(map, &(iothreadinfo->cpumap), + &(iothreadinfo->cpumaplen)) < 0) { + virBitmapFree(map); + goto cleanup; + } + virBitmapFree(map); + //Append to iothreadinfolist + iothreadinfolist[niothreads] = iothreadinfo; + niothreads++; + } + } + VIR_DELETE_ELEMENT_INPLACE(iothreadinfolist, + niothreads, nthreads); + *iothreads = iothreadinfolist; + VIR_DEBUG("niothreads = %ld", niothreads); + return niothreads; + + cleanup: + if (iothreadinfolist) { + for (thd_index = 0; thd_index < niothreads; thd_index++) + VIR_FREE(iothreadinfolist[thd_index]); + VIR_FREE(iothreadinfolist); + } + if (iothreadinfo) + VIR_FREE(iothreadinfo); + return -1; +} diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h index f8c3fa75e8..98edb0faf9 100644 --- a/src/ch/ch_monitor.h +++ b/src/ch/ch_monitor.h @@ -118,3 +118,5 @@ int virCHMonitorGetCPUInfo(virCHMonitor *mon, size_t maxvcpus); size_t virCHMonitorGetThreadInfo(virCHMonitor *mon, bool refresh, virCHMonitorThreadInfo **threads); +int virCHMonitorGetIOThreads(virCHMonitor *mon, + virDomainIOThreadInfo ***iothreads); diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c index 7a51531224..1c0f5d0818 100644 --- a/src/ch/ch_process.c +++ b/src/ch/ch_process.c @@ -41,7 +41,6 @@ VIR_LOG_INIT("ch.ch_process"); #define START_VM_POSTFIX ": starting up vm\n" - static virCHMonitor * virCHProcessConnectMonitor(virCHDriver *driver, virDomainObj *vm) @@ -131,7 +130,6 @@ virCHProcessUpdateInfo(virDomainObj *vm) virCHProcessUpdateConsole(vm, info); virJSONValueFree(info); - return 0; } @@ -312,6 +310,74 @@ virCHProcessSetupPid(virDomainObj *vm, return ret; } +static int +virCHProcessSetupIOThread(virDomainObj *vm, + virDomainIOThreadInfo *iothread) +{ + virCHDomainObjPrivate *priv = vm->privateData; + return virCHProcessSetupPid(vm, iothread->iothread_id, + VIR_CGROUP_THREAD_IOTHREAD, + iothread->iothread_id, + priv->autoCpuset, // This should be updated when CLH supports accepting + // iothread settings from input domain definition + vm->def->cputune.iothread_period, + vm->def->cputune.iothread_quota, + NULL); // CLH doesn't allow choosing a scheduler for iothreads. +} + +static int +virCHProcessSetupIOThreads(virDomainObj *vm) +{ + virCHDomainObjPrivate *priv = vm->privateData; + virDomainIOThreadInfo **iothreads = NULL; + size_t i; + size_t niothreads; + + niothreads = virCHMonitorGetIOThreads(priv->monitor, &iothreads); + for (i = 0; i < niothreads; i++) { + VIR_DEBUG("IOThread index = %ld , tid = %d", i, iothreads[i]->iothread_id); + if (virCHProcessSetupIOThread(vm, iothreads[i]) < 0) + return -1; + } + return 0; +} + + +static int +virCHProcessSetupEmulatorThread(virDomainObj *vm, + virCHMonitorEmuThreadInfo emuthread) +{ + return virCHProcessSetupPid(vm, emuthread.tid, VIR_CGROUP_THREAD_EMULATOR, + 0, vm->def->cputune.emulatorpin, + vm->def->cputune.emulator_period, + vm->def->cputune.emulator_quota, + vm->def->cputune.emulatorsched); +} + +static int +virCHProcessSetupEmulatorThreads(virDomainObj *vm) +{ + int thd_index = 0; + virCHDomainObjPrivate *priv = vm->privateData; + /* + * Cloud-hypervisor start 4 Emulator threads by default: + * vmm + * cloud-hypervisor + * http-server + * signal_handler + */ + for (thd_index = 0; thd_index < priv->monitor->nthreads; thd_index++) { + if (priv->monitor->threads[thd_index].type == virCHThreadTypeEmulator) { + VIR_DEBUG("Setup tid = %d (%s) Emulator thread", priv->monitor->threads[thd_index].emuInfo.tid, + priv->monitor->threads[thd_index].emuInfo.thrName); + + if (virCHProcessSetupEmulatorThread(vm, priv->monitor->threads[thd_index].emuInfo) < 0) + return -1; + } + } + return 0; +} + /** * virCHProcessSetupVcpu: * @vm: domain object @@ -443,6 +509,14 @@ virCHProcessStart(virCHDriver * driver, virCHDomainRefreshThreadInfo(vm); + VIR_DEBUG("Setting emulator tuning/settings"); + if (virCHProcessSetupEmulatorThreads(vm) < 0) + goto cleanup; + + VIR_DEBUG("Setting iothread tuning/settings"); + if (virCHProcessSetupIOThreads(vm) < 0) + goto cleanup; + VIR_DEBUG("Setting global CPU cgroup (if required)"); if (virSetupGlobalCpuCgroup(vm, priv->cgroup, priv->autoNodeset) < 0) goto cleanup; -- 2.27.0

Signed-off-by: Praveen K Paladugu <prapal@linux.microsoft.com> --- src/ch/ch_driver.c | 154 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/src/ch/ch_driver.c b/src/ch/ch_driver.c index 8c14829d2a..100c54163e 100644 --- a/src/ch/ch_driver.c +++ b/src/ch/ch_driver.c @@ -1309,6 +1309,158 @@ chDomainPinVcpu(virDomainPtr dom, VIR_DOMAIN_AFFECT_LIVE); } + + +static int +chDomainGetEmulatorPinInfo(virDomainPtr dom, + unsigned char *cpumaps, + int maplen, + unsigned int flags) +{ + virDomainObj *vm = NULL; + virDomainDef *def; + virCHDomainObjPrivate *priv; + bool live; + int ret = -1; + virBitmap *cpumask = NULL; + g_autoptr(virBitmap) bitmap = NULL; + virBitmap *autoCpuset = NULL; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + if (!(vm = chDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainGetEmulatorPinInfoEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (!(def = virDomainObjGetOneDefState(vm, flags, &live))) + goto cleanup; + + if (live) { + priv = vm->privateData; + autoCpuset = priv->autoCpuset; + } + if (def->cputune.emulatorpin) { + cpumask = def->cputune.emulatorpin; + } else if (def->cpumask) { + cpumask = def->cpumask; + } else if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO && + autoCpuset) { + cpumask = autoCpuset; + } else { + if (!(bitmap = virHostCPUGetAvailableCPUsBitmap())) + goto cleanup; + cpumask = bitmap; + } + + virBitmapToDataBuf(cpumask, cpumaps, maplen); + + ret = 1; + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + +static int +chDomainPinEmulator(virDomainPtr dom, + unsigned char *cpumap, + int maplen, + unsigned int flags) +{ + virCHDriver *driver = dom->conn->privateData; + virDomainObj *vm; + virCgroup *cgroup_emulator = NULL; + virDomainDef *def; + virDomainDef *persistentDef; + int ret = -1; + virCHDomainObjPrivate *priv; + virBitmap *pcpumap = NULL; + g_autoptr(virCHDriverConfig) cfg = NULL; + g_autofree char *str = NULL; + virTypedParameterPtr eventParams = NULL; + int eventNparams = 0; + int eventMaxparams = 0; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + cfg = virCHDriverGetConfig(driver); + + if (!(vm = chDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainPinEmulatorEnsureACL(dom->conn, vm->def, flags) < 0) + goto cleanup; + + if (virCHDomainObjBeginJob(vm, CH_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0) + goto endjob; + + priv = vm->privateData; + + if (!(pcpumap = virBitmapNewData(cpumap, maplen))) + goto endjob; + + if (virBitmapIsAllClear(pcpumap)) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("Empty cpu list for pinning")); + goto endjob; + } + + if (def) { + if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) { + if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_EMULATOR, + 0, false, &cgroup_emulator) < 0) + goto endjob; + + if (virSetupCgroupCpusetCpus(cgroup_emulator, pcpumap) < 0) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("failed to set cpuset.cpus in cgroup" + " for emulator threads")); + goto endjob; + } + } + + if (virProcessSetAffinity(vm->pid, pcpumap, false) < 0) + goto endjob; + + virBitmapFree(def->cputune.emulatorpin); + def->cputune.emulatorpin = NULL; + + if (!(def->cputune.emulatorpin = virBitmapNewCopy(pcpumap))) + goto endjob; + + if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0) + goto endjob; + + str = virBitmapFormat(pcpumap); + if (virTypedParamsAddString(&eventParams, &eventNparams, + &eventMaxparams, + VIR_DOMAIN_TUNABLE_CPU_EMULATORPIN, + str) < 0) + goto endjob; + + } + + + ret = 0; + + endjob: + virCHDomainObjEndJob(vm); + + cleanup: + if (cgroup_emulator) + virCgroupFree(cgroup_emulator); + virBitmapFree(pcpumap); + virDomainObjEndAPI(&vm); + return ret; +} + #define CH_NB_NUMA_PARAM 2 static int @@ -1627,6 +1779,8 @@ static virHypervisorDriver chHypervisorDriver = { .domainGetVcpuPinInfo = chDomainGetVcpuPinInfo, /* 7.11.0 */ .domainPinVcpu = chDomainPinVcpu, /* 7.11.0 */ .domainPinVcpuFlags = chDomainPinVcpuFlags, /* 7.11.0 */ + .domainPinEmulator = chDomainPinEmulator, /* 7.11.0 */ + .domainGetEmulatorPinInfo = chDomainGetEmulatorPinInfo, /* 7.11.0 */ .nodeGetCPUMap = chNodeGetCPUMap, /* 7.11.0 */ .domainSetNumaParameters = chDomainSetNumaParameters, /* 7.11.0 */ .domainGetNumaParameters = chDomainGetNumaParameters, /* 7.11.0 */ -- 2.27.0
participants (2)
-
Ján Tomko
-
Praveen K Paladugu