[libvirt] [PATCH 0/6 v3] New APIs to get/set node memory tunables

v1: https://www.redhat.com/archives/libvir-list/2012-September/msg00517.html v1 - v2: * Rename virNode{Get,Set}SharedMemoryParameters to virNode{Get,Set}MemoryParameters, in case of we could add more node memory tunables in future. v2 - v3: * Add prefix "shm_" to the shared memory parameter field. * Change REMOTE_NODE_MEMORY_PARAMETERS_MAX from 16 to 64. * Helper fucntions for internal APIs (node{Get,Set}MemoryParameters) * Add "shm" prefix for the virsh options. As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}MemoryParameters) to get and set the host shared memory tunables (ksm under linux). Osier Yang (6): node_memory: Define the APIs to get/set memory parameters node_memory: Wire up the RPC protocol node_memory: Implement the internal APIs node_memory: Support get/set memory parameters for drivers node_memory: Expose the APIs to virsh node_memory: Expose the APIs to Python bindings daemon/remote.c | 59 +++++++++ include/libvirt/libvirt.h.in | 63 ++++++++++ python/generator.py | 2 + python/libvirt-override-api.xml | 13 ++ python/libvirt-override.c | 125 ++++++++++++++++++++ src/driver.h | 14 ++ src/libvirt.c | 121 +++++++++++++++++++ src/libvirt_private.syms | 2 + src/libvirt_public.syms | 2 + src/lxc/lxc_driver.c | 2 + src/nodeinfo.c | 249 +++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ src/qemu/qemu_driver.c | 2 + src/remote/remote_driver.c | 50 ++++++++ src/remote/remote_protocol.x | 24 ++++- src/remote_protocol-structs | 20 +++ src/rpc/gendispatch.pl | 3 + src/uml/uml_driver.c | 2 + src/xen/xen_driver.c | 3 + tools/virsh-host.c | 116 ++++++++++++++++++ tools/virsh.pod | 8 ++ 21 files changed, 889 insertions(+), 1 deletions(-) -- 1.7.7.3

* include/libvirt/libvirt.h.in: (Add macros for the param fields, declare the APIs). * src/driver.h: (New methods for the driver struct) * src/libvirt.c: (Implement the public APIs) * src/libvirt_public.syms: (Export the public symbols) --- include/libvirt/libvirt.h.in | 63 ++++++++++++++++++++++ python/generator.py | 2 + src/driver.h | 14 +++++ src/libvirt.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 2 + 5 files changed, 202 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index ca04f6c..db61820 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4305,6 +4305,69 @@ typedef struct _virTypedParameter virMemoryParameter; */ typedef virMemoryParameter *virMemoryParameterPtr; +/* + * VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN: + * + * Macro for typed parameter that represents how many present pages + * to scan before the shared memory service goes to sleep. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN "shm_pages_to_scan" + +/* + * VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS: + * + * Macro for typed parameter that represents how many milliseconds + * the shared memory service should sleep before next scan. + */ +# define VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS "shm_sleep_millisecs" + +/* + * VIR_NODE_MEMORY_SHARED_PAGES_SHARED: + * + * Macro for typed parameter that represents how many the shared + * mmeory pages are being used. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_SHARED "shm_pages_shared" + +/* + * VIR_NODE_MEMORY_SHARED_PAGES_SHARING: + * + * Macro for typed parameter that represents how many sites are + * sharing the pages i.e. how much saved. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_SHARING "shm_pages_sharing" + +/* VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED: + * + * Macro for typed parameter that represents how many pages unique + * but repeatedly checked for merging. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED "shm_pages_unshared" + +/* VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE: + * + * Macro for typed parameter that represents how many pages changing + * too fast to be placed in a tree. + */ +# define VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE "shm_pages_volatile" + +/* VIR_NODE_MEMORY_SHARED_FULL_SCAN: + * + * Macro for typed parameter that represents how many times all + * mergeable areas have been scanned. + */ +# define VIR_NODE_MEMORY_SHARED_FULL_SCANS "shm_full_scans" + +int virNodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int virNodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index 8f6e455..8a73a9f 100755 --- a/python/generator.py +++ b/python/generator.py @@ -427,6 +427,8 @@ skip_impl = ( 'virDomainGetDiskErrors', 'virConnectUnregisterCloseCallback', 'virConnectRegisterCloseCallback', + 'virNodeGetMemoryParameters', + 'virNodeSetMemoryParameters', ) qemu_skip_impl = ( diff --git a/src/driver.h b/src/driver.h index 518e9d4..0eae601 100644 --- a/src/driver.h +++ b/src/driver.h @@ -882,6 +882,18 @@ typedef char * const char *uri, unsigned int flags); +typedef int + (*virDrvNodeGetMemoryParameters)(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +typedef int + (*virDrvNodeSetMemoryParameters)(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + /** * _virDriver: * @@ -1068,6 +1080,8 @@ struct _virDriver { virDrvDomainGetDiskErrors domainGetDiskErrors; virDrvDomainSetMetadata domainSetMetadata; virDrvDomainGetMetadata domainGetMetadata; + virDrvNodeGetMemoryParameters nodeGetMemoryParameters; + virDrvNodeSetMemoryParameters nodeSetMemoryParameters; }; typedef int diff --git a/src/libvirt.c b/src/libvirt.c index 6e25baf..d451ec8 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -6720,6 +6720,127 @@ error: return -1; } +/* + * virNodeGetMemoryParameters: + * @conn: pointer to the hypervisor connection + * @params: pointer to memory parameter object + * (return value, allocated by the caller) + * @nparams: pointer to number of memory parameters; input and output + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Get all node memory parameters. On input, @nparams gives the size + * of the @params array; on output, @nparams gives how many slots were + * filled with parameter information, which might be less but will + * not exceed the input value. + * + * As a special case, calling with @params as NULL and @nparams as 0 on + * input will cause @nparams on output to contain the number of parameters + * supported by the hypervisor. The caller should then allocate @params + * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API + * again. See virDomainGetMemoryParameters() for an equivalent usage + * example. + * + * Returns 0 in case of success, and -1 in case of failure. + */ +int +virNodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, params=%p, nparams=%p, flags=%x", + conn, params, nparams, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + virCheckNonNullArgGoto(nparams, error); + virCheckNonNegativeArgGoto(*nparams, error); + if (*nparams != 0) + virCheckNonNullArgGoto(params, error); + + if (VIR_DRV_SUPPORTS_FEATURE(conn->driver, conn, + VIR_DRV_FEATURE_TYPED_PARAM_STRING)) + flags |= VIR_TYPED_PARAM_STRING_OKAY; + + if (conn->driver->nodeGetMemoryParameters) { + int ret; + ret = conn->driver->nodeGetMemoryParameters(conn, params, + nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/* + * virNodeSetMemoryParameters: + * @conn: pointer to the hypervisor connection + * @params: pointer to scheduler parameter objects + * @nparams: number of scheduler parameter objects + * (this value can be the same or less than the returned + * value nparams of virDomainGetSchedulerType) + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Change all or a subset of the node memory tunables. + * This function may require privileged access to the hypervisor. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, params=%p, nparams=%d, flags=%x", + conn, params, nparams, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + virCheckNonNullArgGoto(params, error); + virCheckNonNegativeArgGoto(nparams, error); + + if (virTypedParameterValidateSet(conn, params, nparams) < 0) + goto error; + + if (conn->driver->nodeSetMemoryParameters) { + int ret; + ret = conn->driver->nodeSetMemoryParameters(conn, params, + nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} /** * virDomainGetSchedulerType: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 8dda48b..7ec1177 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -559,6 +559,8 @@ LIBVIRT_0.10.2 { virConnectListAllInterfaces; virConnectListAllNetworks; virConnectListAllStoragePools; + virNodeGetMemoryParameters; + virNodeSetMemoryParameters; virStoragePoolListAllVolumes; } LIBVIRT_0.10.0; -- 1.7.7.3

* src/rpc/gendispatch.pl: (virNodeSetMemoryParameters is the the special one which needs a connection object as the first argument, improve the generator to support it). * daemon/remote.c: (Implement the server side handler for virDomainGetMemoryParameters) * src/remote/remote_driver.c: (Implement the client side handler for virDomainGetMemoryParameters) * src/remote/remote_protocol.x: (New RPC procedures for the two new APIs and structs to represent the args and ret for it) * src/remote_protocol-structs: Likewise --- daemon/remote.c | 59 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 50 +++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 24 ++++++++++++++++- src/remote_protocol-structs | 20 ++++++++++++++ src/rpc/gendispatch.pl | 3 ++ 5 files changed, 155 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 12cd25c..337acd8 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4321,6 +4321,65 @@ cleanup: return rv; } +static int +remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_node_get_memory_parameters_args *args, + remote_node_get_memory_parameters_ret *ret) +{ + virTypedParameterPtr params = NULL; + int nparams = args->nparams; + unsigned int flags; + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + flags = args->flags; + + if (nparams > REMOTE_NODE_MEMORY_PARAMETERS_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large")); + goto cleanup; + } + if (nparams && VIR_ALLOC_N(params, nparams) < 0) { + virReportOOMError(); + goto cleanup; + } + + + if (virNodeGetMemoryParameters(priv->conn, params, &nparams, flags) < 0) + goto cleanup; + + /* In this case, we need to send back the number of parameters + * supported + */ + if (args->nparams == 0) { + ret->nparams = nparams; + goto success; + } + + if (remoteSerializeTypedParameters(params, nparams, + &ret->params.params_val, + &ret->params.params_len, + args->flags) < 0) + goto cleanup; + +success: + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); + return rv; +} /*----- Helpers. -----*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index f47b06c..c16fc4a 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -5510,6 +5510,54 @@ done: return rv; } +static int +remoteNodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + int rv = -1; + remote_node_get_memory_parameters_args args; + remote_node_get_memory_parameters_ret ret; + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + args.nparams = *nparams; + args.flags = flags; + + memset (&ret, 0, sizeof(ret)); + if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS, + (xdrproc_t) xdr_remote_node_get_memory_parameters_args, (char *) &args, + (xdrproc_t) xdr_remote_node_get_memory_parameters_ret, (char *) &ret) == -1) + goto done; + + /* Handle the case when the caller does not know the number of parameters + * and is asking for the number of parameters supported + */ + if (*nparams == 0) { + *nparams = ret.nparams; + rv = 0; + goto cleanup; + } + + if (remoteDeserializeTypedParameters(ret.params.params_val, + ret.params.params_len, + REMOTE_NODE_MEMORY_PARAMETERS_MAX, + params, + nparams) < 0) + goto cleanup; + + rv = 0; + +cleanup: + xdr_free ((xdrproc_t) xdr_remote_node_get_memory_parameters_ret, + (char *) &ret); +done: + remoteDriverUnlock(priv); + return rv; +} + static void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) { @@ -5821,6 +5869,8 @@ static virDriver remote_driver = { .domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */ .domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */ .domainGetHostname = remoteDomainGetHostname, /* 0.10.0 */ + .nodeSetMemoryParameters = remoteNodeSetMemoryParameters, /* 0.10.2 */ + .nodeGetMemoryParameters = remoteNodeGetMemoryParameters, /* 0.10.2 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 54054af..a7aaf58 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -229,6 +229,11 @@ const REMOTE_DOMAIN_GET_CPU_STATS_MAX = 2048; */ const REMOTE_DOMAIN_DISK_ERRORS_MAX = 256; +/* + * Upper limit on number of memory parameters + */ +const REMOTE_NODE_MEMORY_PARAMETERS_MAX = 64; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -2599,6 +2604,21 @@ struct remote_connect_list_all_interfaces_ret { unsigned int ret; }; +struct remote_node_set_memory_parameters_args { + remote_typed_param params<REMOTE_NODE_MEMORY_PARAMETERS_MAX>; + unsigned int flags; +}; + +struct remote_node_get_memory_parameters_args { + int nparams; + unsigned int flags; +}; + +struct remote_node_get_memory_parameters_ret { + remote_typed_param params<REMOTE_NODE_MEMORY_PARAMETERS_MAX>; + int nparams; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -2933,7 +2953,9 @@ enum remote_procedure { REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 281, /* skipgen skipgen priority:high */ REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 282, /* skipgen skipgen priority:high */ REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 283, /* skipgen skipgen priority:high */ - REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284 /* skipgen skipgen priority:high */ + REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284, /* skipgen skipgen priority:high */ + REMOTE_PROC_NODE_SET_MEMORY_PARAMETERS = 285, /* autogen autogen */ + REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 286 /* skipgen skipgen */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 2a33039..7fc3e25 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2056,6 +2056,24 @@ struct remote_connect_list_all_interfaces_ret { } ifaces; u_int ret; }; +struct remote_node_set_memory_parameters_args { + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + u_int flags; +}; +struct remote_node_get_memory_parameters_args { + int nparams; + u_int flags; +}; +struct remote_node_get_memory_parameters_ret { + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + int nparams; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2341,4 +2359,6 @@ enum remote_procedure { REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 282, REMOTE_PROC_CONNECT_LIST_ALL_NETWORKS = 283, REMOTE_PROC_CONNECT_LIST_ALL_INTERFACES = 284, + REMOTE_PROC_NODE_SET_MEMORY_PARAMETERS = 285, + REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 286, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 12023e9..774977d 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -478,6 +478,9 @@ elsif ($opt_b) { } elsif ($args_member =~ m/^remote_typed_param (\S+)<(\S+)>;/) { push(@vars_list, "virTypedParameterPtr $1 = NULL"); push(@vars_list, "int n$1"); + if ($call->{ProcName} eq "NodeSetMemoryParameters") { + push(@args_list, "priv->conn"); + } push(@args_list, "$1"); push(@args_list, "n$1"); push(@getters_list, " if (($1 = remoteDeserializeTypedParameters(args->$1.$1_val,\n" . -- 1.7.7.3

Only implemented for linux platform. * src/nodeinfo.h: (Declare node{Get,Set}MemoryParameters) * src/nodeinfo.c: (Implement node{Get,Set}MemoryParameters) * src/libvirt_private.syms: (Export those two new internal APIs to private symbols) --- src/libvirt_private.syms | 2 + src/nodeinfo.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ 3 files changed, 261 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 064e2a6..1fcaa25 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -881,7 +881,9 @@ nodeGetCPUStats; nodeGetCellsFreeMemory; nodeGetFreeMemory; nodeGetInfo; +nodeGetMemoryParameters; nodeGetMemoryStats; +nodeSetMemoryParameters; # nwfilter_conf.h diff --git a/src/nodeinfo.c b/src/nodeinfo.c index e3d4a24..7af6512 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -48,6 +48,7 @@ #include "count-one-bits.h" #include "intprops.h" #include "virfile.h" +#include "virtypedparam.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -57,6 +58,7 @@ # define SYSFS_SYSTEM_PATH "/sys/devices/system" # define PROCSTAT_PATH "/proc/stat" # define MEMINFO_PATH "/proc/meminfo" +# define SYSFS_MEMORY_SHARED_PATH "/sys/kernel/mm/ksm" # define LINUX_NB_CPU_STATS 4 # define LINUX_NB_MEMORY_STATS_ALL 4 @@ -933,6 +935,253 @@ nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED, #endif } +static int +nodeSetMemoryParameterValue(const char *field, + virTypedParameterPtr param) +{ + char *path = NULL; + char *strval = NULL; + int ret = -1; + int rc = -1; + + if (virAsprintf(&path, "%s/%s", + SYSFS_MEMORY_SHARED_PATH, field) < 0) { + virReportOOMError(); + ret = -2; + goto cleanup; + } + + if (virAsprintf(&strval, "%u", param->value.ui) == -1) { + virReportOOMError(); + ret = -2; + goto cleanup; + } + + if ((rc = virFileWriteStr(path, strval, 0)) < 0) { + virReportSystemError(-rc, _("failed to set %s"), field); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(path); + VIR_FREE(strval); + return ret; +} + +int +nodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virCheckFlags(0, -1); + +#ifdef __linux__ + int ret = 0; + int i; + + if (virTypedParameterArrayValidate(params, nparams, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + NULL) < 0) + return -1; + + for (i = 0; i < nparams; i++) { + virTypedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN)) { + ret = nodeSetMemoryParameterValue("pages_to_scan", param); + + /* Out of memory */ + if (ret == -2) + return -1; + } else if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS)) { + ret = nodeSetMemoryParameterValue("sleep_millisecs", param); + + /* Out of memory */ + if (ret == -2) + return -1; + } + } + + return ret; +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node set memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + +static int +nodeGetMemoryParameterValue(const char *field, + void *value) +{ + char *path = NULL; + char *buf = NULL; + char *tmp = NULL; + int ret = -1; + int rc = -1; + + if (virAsprintf(&path, "%s/%s", + SYSFS_MEMORY_SHARED_PATH, field) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (STREQ(field, "pages_to_scan") || + STREQ(field, "sleep_millisecs")) + rc = virStrToLong_ui(buf, NULL, 10, (unsigned int *)value); + else if (STREQ(field, "pages_shared") || + STREQ(field, "pages_sharing") || + STREQ(field, "pages_unshared") || + STREQ(field, "pages_volatile") || + STREQ(field, "full_scans")) + rc = virStrToLong_ull(buf, NULL, 10, (unsigned long long *)value); + + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse %s"), field); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(path); + VIR_FREE(buf); + return ret; +} + +#define NODE_MEMORY_PARAMETERS_NUM 7 +int +nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + +#ifdef __linux__ + unsigned int pages_to_scan; + unsigned int sleep_millisecs; + unsigned long long pages_shared; + unsigned long long pages_sharing; + unsigned long long pages_unshared; + unsigned long long pages_volatile; + unsigned long long full_scans = 0; + int i; + + if ((*nparams) == 0) { + *nparams = NODE_MEMORY_PARAMETERS_NUM; + return 0; + } + + for (i = 0; i < *nparams && i < NODE_MEMORY_PARAMETERS_NUM; i++) { + virTypedParameterPtr param = ¶ms[i]; + + switch(i) { + case 0: + if (nodeGetMemoryParameterValue("pages_to_scan", + &pages_to_scan) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, pages_to_scan) < 0) + return -1; + + break; + + case 1: + if (nodeGetMemoryParameterValue("sleep_millisecs", + &sleep_millisecs) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, sleep_millisecs) < 0) + return -1; + + break; + + case 2: + if (nodeGetMemoryParameterValue("pages_shared", + &pages_shared) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARED, + VIR_TYPED_PARAM_ULLONG, pages_shared) < 0) + return -1; + + break; + + case 3: + if (nodeGetMemoryParameterValue("pages_sharing", + &pages_sharing) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARING, + VIR_TYPED_PARAM_ULLONG, pages_sharing) < 0) + return -1; + + break; + + case 4: + if (nodeGetMemoryParameterValue("pages_unshared", + &pages_unshared) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED, + VIR_TYPED_PARAM_ULLONG, pages_unshared) < 0) + return -1; + + break; + + case 5: + if (nodeGetMemoryParameterValue("pages_volatile", + &pages_volatile) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE, + VIR_TYPED_PARAM_ULLONG, pages_volatile) < 0) + return -1; + + break; + + case 6: + if (nodeGetMemoryParameterValue("full_scans", + &full_scans) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_FULL_SCANS, + VIR_TYPED_PARAM_ULLONG, full_scans) < 0) + return -1; + + break; + + default: + break; + } + } + + return 0; +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node get memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + #if HAVE_NUMACTL # if LIBNUMA_API_VERSION <= 1 # define NUMA_MAX_N_CPUS 4096 diff --git a/src/nodeinfo.h b/src/nodeinfo.h index 12090e2..25ad0dd 100644 --- a/src/nodeinfo.h +++ b/src/nodeinfo.h @@ -49,4 +49,14 @@ unsigned long long nodeGetFreeMemory(virConnectPtr conn); char *nodeGetCPUmap(virConnectPtr conn, int *max_id, const char *mapname); + +int nodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int nodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); #endif /* __VIR_NODEINFO_H__*/ -- 1.7.7.3

Including QEMU, LXC, UML, XEN drivers. --- src/lxc/lxc_driver.c | 2 ++ src/qemu/qemu_driver.c | 2 ++ src/uml/uml_driver.c | 2 ++ src/xen/xen_driver.c | 3 +++ 4 files changed, 9 insertions(+), 0 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index ff11c2c..62c36e6 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2748,6 +2748,8 @@ static virDriver lxcDriver = { .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */ .isAlive = lxcIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ }; static virStateDriver lxcStateDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 23a7a75..981e6d4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -14112,6 +14112,8 @@ static virDriver qemuDriver = { .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */ .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */ .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ }; diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 26877eb..72d1b0e 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -2623,6 +2623,8 @@ static virDriver umlDriver = { .domainOpenConsole = umlDomainOpenConsole, /* 0.8.6 */ .isAlive = umlIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ }; static virStateDriver umlStateDriver = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index d33737e..3a14d12 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -64,6 +64,7 @@ #include "viruri.h" #include "command.h" #include "virnodesuspend.h" +#include "nodeinfo.h" #define VIR_FROM_THIS VIR_FROM_XEN @@ -2269,6 +2270,8 @@ static virDriver xenUnifiedDriver = { .domainOpenConsole = xenUnifiedDomainOpenConsole, /* 0.8.6 */ .isAlive = xenUnifiedIsAlive, /* 0.9.8 */ .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */ + .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ + .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ }; /** -- 1.7.7.3

New command node-memory-tune to get/set the node memory parameters, only two parameters are allowed to set (pages_to_scan, and sleep_millisecs, see documents in this patch for more details). Example of node-memory-tune's output: Shared memory: pages_to_scan 100 sleep_millisecs 20 pages_shared 0 pages_sharing 0 pages_unshared 0 pages_volatile 0 full_scans 0 --- tools/virsh-host.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 8 ++++ 2 files changed, 124 insertions(+), 0 deletions(-) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index c46288b..713c003 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -37,6 +37,7 @@ #include "util.h" #include "virsh-domain.h" #include "xml.h" +#include "virtypedparam.h" /* * "capabilities" command @@ -884,12 +885,127 @@ cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } +static const vshCmdInfo info_node_memory_tune[] = { + {"help", N_("Get or set node memory parameters")}, + {"desc", N_("Get or set node memory parameters" + " To get the memory parameters, use following command: \n\n" + " virsh # node-memory-tune")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_memory_tune[] = { + {"shm-pages-to-scan", VSH_OT_INT, VSH_OFLAG_NONE, + N_("number of pages to scan before the shared memory service " + "goes to sleep")}, + {"shm-sleep-millisecs", VSH_OT_INT, VSH_OFLAG_NONE, + N_("number of millisecs the shared memory service should " + "sleep before next scan")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeMemoryTune(vshControl *ctl, const vshCmd *cmd) +{ + virTypedParameterPtr params = NULL; + int nparams = 0; + unsigned int flags = 0; + unsigned int shm_pages_to_scan = 0; + unsigned int shm_sleep_millisecs = 0; + bool ret = false; + int i = 0; + + if (vshCommandOptUInt(cmd, "shm-pages-to-scan", + &shm_pages_to_scan) < 0) { + vshError(ctl, "%s", _("invalid shm-pages-to-scan number")); + return false; + } + + if (vshCommandOptUInt(cmd, "shm-sleep-millisecs", + &shm_sleep_millisecs) < 0) { + vshError(ctl, "%s", _("invalid shm-sleep-millisecs number")); + return false; + } + + if (shm_pages_to_scan) + nparams++; + + if (shm_sleep_millisecs) + nparams++; + + if (nparams == 0) { + /* Get the number of memory parameters */ + if (virNodeGetMemoryParameters(ctl->conn, NULL, &nparams, flags) != 0) { + vshError(ctl, "%s", + _("Unable to get number of memory parameters")); + goto cleanup; + } + + if (nparams == 0) { + ret = true; + goto cleanup; + } + + /* Now go get all the memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + if (virNodeGetMemoryParameters(ctl->conn, params, &nparams, flags) != 0) { + vshError(ctl, "%s", _("Unable to get memory parameters")); + goto cleanup; + } + + /* XXX: Need to sort the returned params once new parameter + * fields not of shared memory are added. + */ + vshPrint(ctl, _("Shared memory:\n")); + for (i = 0; i < nparams; i++) { + char *str = vshGetTypedParamValue(ctl, ¶ms[i]); + vshPrint(ctl, "\t%-15s %s\n", params[i].field, str); + VIR_FREE(str); + } + + ret = true; + } else { + /* Set the memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + + if (i < nparams && shm_pages_to_scan) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + shm_pages_to_scan) < 0) + goto error; + } + + if (i < nparams && shm_sleep_millisecs) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + shm_sleep_millisecs) < 0) + goto error; + } + + if (virNodeSetMemoryParameters(ctl->conn, params, nparams, flags) != 0) + goto error; + else + ret = true; + } + +cleanup: + VIR_FREE(params); + return ret; + +error: + vshError(ctl, "%s", _("Unable to change memory parameters")); + goto cleanup; +} + const vshCmdDef hostAndHypervisorCmds[] = { {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, {"connect", cmdConnect, opts_connect, info_connect, VSH_CMD_FLAG_NOCONNECT}, {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, {"hostname", cmdHostname, NULL, info_hostname, 0}, + {"node-memory-tune", cmdNodeMemoryTune, + opts_node_memory_tune, info_node_memory_tune, 0}, {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 559e64d..d1f7068 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -293,6 +293,14 @@ Real-Time-Clock interrupt to fire (to wake up the node) after a time delay specified by the 'duration' parameter. The duration time should be at least 60 seconds. +=item B<node-memory-tune> [I<shm-pages-to-scan>] [I<shm-sleep-millisecs>] + +Allows you to display or set the node memory parameters. +I<shm-pages-to-scan> can be used to set the number of pages to scan +before the shared memory service goes to sleep; I<shm-sleep-millisecs> +can be used to set the number of millisecs the shared memory service should +sleep before next scan. + =item B<capabilities> Print an XML document describing the capabilities of the hypervisor -- 1.7.7.3

* python/libvirt-override-api.xml: (Add document to describe the APIs). * python/libvirt-override.c: (Implement the API wrappers manually) --- python/libvirt-override-api.xml | 13 ++++ python/libvirt-override.c | 125 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 0 deletions(-) diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index ab6f407..abc0b81 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -511,5 +511,18 @@ <arg name='domain' type='virDomainPtr' info='a domain object'/> <arg name='flags' type='unsigned int' info='unused, always pass 0'/> </function> + <function name='virNodeSetMemoryParameters' file='python'> + <info>Change the node memory tunables</info> + <return type='int' info='-1 in case of error, 0 in case of success.'/> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='params' type='virTypedParameterPtr' info='pointer to the memory tunable objects'/> + <arg name='flags' type='int' info='unused, always pass 0'/> + </function> + <function name='virNodeGetMemoryParameters' file='python'> + <info>Get the node memory parameters</info> + <return type='str *' info='None in case of error, returns a dictionary of params'/> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + <arg name='flags' type='int' info='unused, always pass 0'/> + </function> </symbols> </api> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index d07e7cb..ca32f80 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -6005,6 +6005,129 @@ cleanup: return py_retval; } +static PyObject * +libvirt_virNodeSetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + virConnectPtr conn; + PyObject *pyobj_conn, *info; + PyObject *ret = NULL; + int i_retval; + int nparams = 0; + Py_ssize_t size = 0; + unsigned int flags; + virTypedParameterPtr params, new_params; + + if (!PyArg_ParseTuple(args, + (char *)"OOi:virNodeSetMemoryParameters", + &pyobj_conn, &info, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + if ((size = PyDict_Size(info)) < 0) + return NULL; + + if (size == 0) { + PyErr_Format(PyExc_LookupError, + "Need non-empty dictionary to set attributes"); + return NULL; + } + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, NULL, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) + return VIR_PY_INT_FAIL; + + if (nparams == 0) { + PyErr_Format(PyExc_LookupError, + "no settable attributes"); + return NULL; + } + + if (VIR_ALLOC_N(params, nparams) < 0) + return PyErr_NoMemory(); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, params, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_INT_FAIL; + goto cleanup; + } + + new_params = setPyVirTypedParameter(info, params, nparams); + if (!new_params) + goto cleanup; + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeSetMemoryParameters(conn, new_params, size, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_INT_FAIL; + goto cleanup; + } + + ret = VIR_PY_INT_SUCCESS; + +cleanup: + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); + VIR_FREE(new_params); + return ret; +} + +static PyObject * +libvirt_virNodeGetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + virConnectPtr conn; + PyObject *pyobj_conn; + PyObject *ret = NULL; + int i_retval; + int nparams = 0; + unsigned int flags; + virTypedParameterPtr params; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virNodeGetMemoryParameters", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, NULL, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) + return VIR_PY_NONE; + + if (!nparams) + return PyDict_New(); + + if (VIR_ALLOC_N(params, nparams) < 0) + return PyErr_NoMemory(); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetMemoryParameters(conn, params, &nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (i_retval < 0) { + ret = VIR_PY_NONE; + goto cleanup; + } + + ret = getPyVirTypedParameter(params, nparams); + +cleanup: + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); + return ret; +} + + /************************************************************************ * * * The registration stuff * @@ -6116,6 +6239,8 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virDomainBlockPeek", libvirt_virDomainBlockPeek, METH_VARARGS, NULL}, {(char *) "virDomainMemoryPeek", libvirt_virDomainMemoryPeek, METH_VARARGS, NULL}, {(char *) "virDomainGetDiskErrors", libvirt_virDomainGetDiskErrors, METH_VARARGS, NULL}, + {(char *) "virNodeGetMemoryParameters", libvirt_virNodeGetMemoryParameters, METH_VARARGS, NULL}, + {(char *) "virNodeSetMemoryParameters", libvirt_virNodeSetMemoryParameters, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; -- 1.7.7.3

On Fri, Sep 14, 2012 at 10:42:13PM +0800, Osier Yang wrote:
v1:
https://www.redhat.com/archives/libvir-list/2012-September/msg00517.html
v1 - v2: * Rename virNode{Get,Set}SharedMemoryParameters to virNode{Get,Set}MemoryParameters, in case of we could add more node memory tunables in future.
v2 - v3: * Add prefix "shm_" to the shared memory parameter field. * Change REMOTE_NODE_MEMORY_PARAMETERS_MAX from 16 to 64. * Helper fucntions for internal APIs (node{Get,Set}MemoryParameters) * Add "shm" prefix for the virsh options.
As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}MemoryParameters) to get and set the host shared memory tunables (ksm under linux).
Osier Yang (6): node_memory: Define the APIs to get/set memory parameters node_memory: Wire up the RPC protocol node_memory: Implement the internal APIs node_memory: Support get/set memory parameters for drivers node_memory: Expose the APIs to virsh node_memory: Expose the APIs to Python bindings
daemon/remote.c | 59 +++++++++ include/libvirt/libvirt.h.in | 63 ++++++++++ python/generator.py | 2 + python/libvirt-override-api.xml | 13 ++ python/libvirt-override.c | 125 ++++++++++++++++++++ src/driver.h | 14 ++ src/libvirt.c | 121 +++++++++++++++++++ src/libvirt_private.syms | 2 + src/libvirt_public.syms | 2 + src/lxc/lxc_driver.c | 2 + src/nodeinfo.c | 249 +++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ src/qemu/qemu_driver.c | 2 + src/remote/remote_driver.c | 50 ++++++++ src/remote/remote_protocol.x | 24 ++++- src/remote_protocol-structs | 20 +++ src/rpc/gendispatch.pl | 3 + src/uml/uml_driver.c | 2 + src/xen/xen_driver.c | 3 + tools/virsh-host.c | 116 ++++++++++++++++++ tools/virsh.pod | 8 ++ 21 files changed, 889 insertions(+), 1 deletions(-)
ACK to the patch set, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On 2012年09月15日 14:57, Daniel Veillard wrote:
On Fri, Sep 14, 2012 at 10:42:13PM +0800, Osier Yang wrote:
v1:
https://www.redhat.com/archives/libvir-list/2012-September/msg00517.html
v1 - v2: * Rename virNode{Get,Set}SharedMemoryParameters to virNode{Get,Set}MemoryParameters, in case of we could add more node memory tunables in future.
v2 - v3: * Add prefix "shm_" to the shared memory parameter field. * Change REMOTE_NODE_MEMORY_PARAMETERS_MAX from 16 to 64. * Helper fucntions for internal APIs (node{Get,Set}MemoryParameters) * Add "shm" prefix for the virsh options.
As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}MemoryParameters) to get and set the host shared memory tunables (ksm under linux).
Osier Yang (6): node_memory: Define the APIs to get/set memory parameters node_memory: Wire up the RPC protocol node_memory: Implement the internal APIs node_memory: Support get/set memory parameters for drivers node_memory: Expose the APIs to virsh node_memory: Expose the APIs to Python bindings
daemon/remote.c | 59 +++++++++ include/libvirt/libvirt.h.in | 63 ++++++++++ python/generator.py | 2 + python/libvirt-override-api.xml | 13 ++ python/libvirt-override.c | 125 ++++++++++++++++++++ src/driver.h | 14 ++ src/libvirt.c | 121 +++++++++++++++++++ src/libvirt_private.syms | 2 + src/libvirt_public.syms | 2 + src/lxc/lxc_driver.c | 2 + src/nodeinfo.c | 249 +++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ src/qemu/qemu_driver.c | 2 + src/remote/remote_driver.c | 50 ++++++++ src/remote/remote_protocol.x | 24 ++++- src/remote_protocol-structs | 20 +++ src/rpc/gendispatch.pl | 3 + src/uml/uml_driver.c | 2 + src/xen/xen_driver.c | 3 + tools/virsh-host.c | 116 ++++++++++++++++++ tools/virsh.pod | 8 ++ 21 files changed, 889 insertions(+), 1 deletions(-)
ACK to the patch set,
Daniel
Rebased on the top, and pushed. Thanks. Osier
participants (2)
-
Daniel Veillard
-
Osier Yang