[libvirt] [PATCH 0/7] New APIs to get/set node shared memory parameters

As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}SharedMemoryParameters) to get and set the host shared memory tunables (ksm under linux). Osier Yang (7): Improve virTypedParameterValidateSet shared_memory: Define the APIs to get/set shared memory parameters shared_memory: Wire up the RPC protocol shared_memory: Implement the internal APIs shared_memory: Support get/set shared memory parameters for drivers shared_memory: Expose the APIs to virsh shared_memory: Expose the APIs to Python bindings daemon/remote.c | 61 +++++++ 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 | 141 +++++++++++++++- src/libvirt_private.syms | 2 + src/libvirt_public.syms | 2 + src/lxc/lxc_driver.c | 2 + src/nodeinfo.c | 344 +++++++++++++++++++++++++++++++++++++++ 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 | 110 +++++++++++++ tools/virsh.pod | 8 + 21 files changed, 990 insertions(+), 11 deletions(-) -- 1.7.7.3

Assume not only domain object will use it. --- src/libvirt.c | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index 700dbef..3de6b13 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3739,15 +3739,15 @@ error: /* Helper function called to validate incoming client array on any * interface that sets typed parameters in the hypervisor. */ static int -virTypedParameterValidateSet(virDomainPtr domain, +virTypedParameterValidateSet(virConnectPtr conn, virTypedParameterPtr params, int nparams) { bool string_okay; int i; - string_okay = VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, - domain->conn, + string_okay = VIR_DRV_SUPPORTS_FEATURE(conn->driver, + conn, VIR_DRV_FEATURE_TYPED_PARAM_STRING); for (i = 0; i < nparams; i++) { if (strnlen(params[i].field, VIR_TYPED_PARAM_FIELD_LENGTH) == @@ -3814,7 +3814,7 @@ virDomainSetMemoryParameters(virDomainPtr domain, virCheckNonNullArgGoto(params, error); virCheckPositiveArgGoto(nparams, error); - if (virTypedParameterValidateSet(domain, params, nparams) < 0) + if (virTypedParameterValidateSet(domain->conn, params, nparams) < 0) goto error; conn = domain->conn; @@ -3955,7 +3955,7 @@ virDomainSetNumaParameters(virDomainPtr domain, } virCheckNonNullArgGoto(params, error); virCheckPositiveArgGoto(nparams, error); - if (virTypedParameterValidateSet(domain, params, nparams) < 0) + if (virTypedParameterValidateSet(domain->conn, params, nparams) < 0) goto error; conn = domain->conn; @@ -4083,7 +4083,7 @@ virDomainSetBlkioParameters(virDomainPtr domain, virCheckNonNullArgGoto(params, error); virCheckNonNegativeArgGoto(nparams, error); - if (virTypedParameterValidateSet(domain, params, nparams) < 0) + if (virTypedParameterValidateSet(domain->conn, params, nparams) < 0) goto error; conn = domain->conn; @@ -6938,7 +6938,7 @@ virDomainSetSchedulerParameters(virDomainPtr domain, virCheckNonNullArgGoto(params, error); virCheckNonNegativeArgGoto(nparams, error); - if (virTypedParameterValidateSet(domain, params, nparams) < 0) + if (virTypedParameterValidateSet(domain->conn, params, nparams) < 0) goto error; conn = domain->conn; @@ -7002,7 +7002,7 @@ virDomainSetSchedulerParametersFlags(virDomainPtr domain, virCheckNonNullArgGoto(params, error); virCheckNonNegativeArgGoto(nparams, error); - if (virTypedParameterValidateSet(domain, params, nparams) < 0) + if (virTypedParameterValidateSet(domain->conn, params, nparams) < 0) goto error; conn = domain->conn; @@ -7283,7 +7283,7 @@ virDomainSetInterfaceParameters(virDomainPtr domain, virCheckNonNullArgGoto(params, error); virCheckPositiveArgGoto(nparams, error); - if (virTypedParameterValidateSet(domain, params, nparams) < 0) + if (virTypedParameterValidateSet(domain->conn, params, nparams) < 0) goto error; conn = domain->conn; @@ -19088,7 +19088,7 @@ int virDomainSetBlockIoTune(virDomainPtr dom, virCheckPositiveArgGoto(nparams, error); virCheckNonNullArgGoto(params, error); - if (virTypedParameterValidateSet(dom, params, nparams) < 0) + if (virTypedParameterValidateSet(dom->conn, params, nparams) < 0) goto error; conn = dom->conn; -- 1.7.7.3

On 09/10/2012 06:08 AM, Osier Yang wrote:
Assume not only domain object will use it. --- src/libvirt.c | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-)
ACK. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 2012年09月14日 05:05, Eric Blake wrote:
On 09/10/2012 06:08 AM, Osier Yang wrote:
Assume not only domain object will use it. --- src/libvirt.c | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-)
ACK.
Thanks, I pushed this first. Regards, Osier

* 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 f63178c..5d8e6f4 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4272,6 +4272,69 @@ typedef struct _virTypedParameter virMemoryParameter; */ typedef virMemoryParameter *virMemoryParameterPtr; +/* + * VIR_NODE_KSM_PAGES_TO_SCAN: + * + * Macro for typed parameter that represents how many present pages + * to scan before ksmd goes to sleep. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_TO_SCAN "pages_to_scan" + +/* + * VIR_NODE_KSM_SLEEP_MILLISECS: + * + * Macro for typed parameter that represents how many milliseconds + * ksmd should sleep before next scan. + */ +# define VIR_NODE_SHARED_MEMORY_SLEEP_MILLISECS "sleep_millisecs" + +/* + * VIR_NODE_KSM_PAGES_SHARED: + * + * Macro for typed parameter that represents how many ksm shared pages + * are being used. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_SHARED "pages_shared" + +/* + * VIR_NODE_KSM_PAGES_SHARING: + * + * Macro for typed parameter that represents how many sites are + * sharing the pages i.e. how much saved. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_SHARING "pages_sharing" + +/* VIR_NODE_KSM_PAGES_UNSHARED: + * + * Macro for typed parameter that represents how many pages unique + * but repeatedly checked for merging. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_UNSHARED "pages_unshared" + +/* VIR_NODE_KSM_PAGES_VOLATILE: + * + * Macro for typed parameter that represents how many pages changing + * too fast to be placed in a tree. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_VOLATILE "pages_volatile" + +/* VIR_NODE_KSM_FULL_SCAN: + * + * Macro for typed parameter that represents how many times all + * mergeable areas have been scanned. + */ +# define VIR_NODE_SHARED_MEMORY_FULL_SCANS "full_scans" + +int virNodeGetSharedMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int virNodeSetSharedMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index 276b4ff..e963a6b 100755 --- a/python/generator.py +++ b/python/generator.py @@ -427,6 +427,8 @@ skip_impl = ( 'virDomainGetDiskErrors', 'virConnectUnregisterCloseCallback', 'virConnectRegisterCloseCallback', + 'virNodeGetSharedMemoryParameters', + 'virNodeSetSharedMemoryParameters', ) qemu_skip_impl = ( diff --git a/src/driver.h b/src/driver.h index 1bdfd29..d758f2e 100644 --- a/src/driver.h +++ b/src/driver.h @@ -882,6 +882,18 @@ typedef char * const char *uri, unsigned int flags); +typedef int + (*virDrvNodeGetSharedMemoryParameters)(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +typedef int + (*virDrvNodeSetSharedMemoryParameters)(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); + /** * _virDriver: * @@ -1068,6 +1080,8 @@ struct _virDriver { virDrvDomainGetDiskErrors domainGetDiskErrors; virDrvDomainSetMetadata domainSetMetadata; virDrvDomainGetMetadata domainGetMetadata; + virDrvNodeGetSharedMemoryParameters nodeGetSharedMemoryParameters; + virDrvNodeSetSharedMemoryParameters nodeSetSharedMemoryParameters; }; typedef int diff --git a/src/libvirt.c b/src/libvirt.c index 3de6b13..0f60de3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -6717,6 +6717,127 @@ error: return -1; } +/* + * virNodeGetSharedMemoryParameters: + * @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 shared 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 +virNodeGetSharedMemoryParameters(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->nodeGetSharedMemoryParameters) { + int ret; + ret = conn->driver->nodeGetSharedMemoryParameters(conn, params, + nparams, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/* + * virNodeSetSharedMemoryParameters: + * @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 shared memory tunables. + * This function may require privileged access to the hypervisor. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +virNodeSetSharedMemoryParameters(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->nodeSetSharedMemoryParameters) { + int ret; + ret = conn->driver->nodeSetSharedMemoryParameters(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 53db37f..655d3fc 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -557,6 +557,8 @@ LIBVIRT_0.10.0 { LIBVIRT_0.10.2 { global: virConnectListAllStoragePools; + virNodeGetSharedMemoryParameters; + virNodeSetSharedMemoryParameters; virStoragePoolListAllVolumes; } LIBVIRT_0.10.0; -- 1.7.7.3

On 2012年09月10日 20:08, Osier Yang wrote:
* 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 f63178c..5d8e6f4 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4272,6 +4272,69 @@ typedef struct _virTypedParameter virMemoryParameter; */ typedef virMemoryParameter *virMemoryParameterPtr;
+/* + * VIR_NODE_KSM_PAGES_TO_SCAN: + * + * Macro for typed parameter that represents how many present pages + * to scan before ksmd goes to sleep. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_TO_SCAN "pages_to_scan" + +/* + * VIR_NODE_KSM_SLEEP_MILLISECS: + * + * Macro for typed parameter that represents how many milliseconds + * ksmd should sleep before next scan. + */ +# define VIR_NODE_SHARED_MEMORY_SLEEP_MILLISECS "sleep_millisecs" + +/* + * VIR_NODE_KSM_PAGES_SHARED: + * + * Macro for typed parameter that represents how many ksm shared pages + * are being used. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_SHARED "pages_shared" + +/* + * VIR_NODE_KSM_PAGES_SHARING: + * + * Macro for typed parameter that represents how many sites are + * sharing the pages i.e. how much saved. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_SHARING "pages_sharing" + +/* VIR_NODE_KSM_PAGES_UNSHARED: + * + * Macro for typed parameter that represents how many pages unique + * but repeatedly checked for merging. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_UNSHARED "pages_unshared" + +/* VIR_NODE_KSM_PAGES_VOLATILE: + * + * Macro for typed parameter that represents how many pages changing + * too fast to be placed in a tree. + */ +# define VIR_NODE_SHARED_MEMORY_PAGES_VOLATILE "pages_volatile" + +/* VIR_NODE_KSM_FULL_SCAN: + * + * Macro for typed parameter that represents how many times all + * mergeable areas have been scanned. + */ +# define VIR_NODE_SHARED_MEMORY_FULL_SCANS "full_scans" +
Oh, I forgot to change the comments, squashed with following diff on my local repo:

On 09/10/2012 06:08 AM, Osier Yang wrote:
* 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(-)
Looks good in general, once you squash in the renames mentioned in your followup patch, and once we settle the bikeshed question of whether to drop 'Shared' from the API names. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 2012年09月14日 11:26, Eric Blake wrote:
On 09/10/2012 06:08 AM, Osier Yang wrote:
* 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(-)
Looks good in general, once you squash in the renames mentioned in your followup patch, and once we settle the bikeshed question of whether to drop 'Shared' from the API names.
For the names, got a 3rd opinion from Daniel internally, he voted for term "MemoryParameters" (I lost :-)) Updated patch posted following. Regards, Osier

* 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..5a26474 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 "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 "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 "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 "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 "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 "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 "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: (virNodeSetSharedMemoryParameters 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 virDomainGetSharedMemoryParameters) * src/remote/remote_driver.c: (Implement the client side handler for virDomainGetSharedMemoryParameters) * 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 | 61 ++++++++++++++++++++++++++++++++++++++++++ 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, 157 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index f86f7ec..c746c0b 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4213,6 +4213,67 @@ cleanup: return rv; } +static int +remoteDispatchNodeGetSharedMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_node_get_shared_memory_parameters_args *args, + remote_node_get_shared_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_SHARED_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 (virNodeGetSharedMemoryParameters(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. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 130d8e2..c7ccaee 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2718,6 +2718,54 @@ done: return rv; } +static int +remoteNodeGetSharedMemoryParameters (virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + int rv = -1; + remote_node_get_shared_memory_parameters_args args; + remote_node_get_shared_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_SHARED_MEMORY_PARAMETERS, + (xdrproc_t) xdr_remote_node_get_shared_memory_parameters_args, (char *) &args, + (xdrproc_t) xdr_remote_node_get_shared_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_SHARED_MEMORY_PARAMETERS_MAX, + params, + nparams) < 0) + goto cleanup; + + rv = 0; + +cleanup: + xdr_free ((xdrproc_t) xdr_remote_node_get_shared_memory_parameters_ret, + (char *) &ret); +done: + remoteDriverUnlock(priv); + return rv; +} + /*----------------------------------------------------------------------*/ @@ -5686,6 +5734,8 @@ static virDriver remote_driver = { .domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */ .domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */ .domainGetHostname = remoteDomainGetHostname, /* 0.10.0 */ + .nodeSetSharedMemoryParameters = remoteNodeSetSharedMemoryParameters, /* 0.10.2 */ + .nodeGetSharedMemoryParameters = remoteNodeGetSharedMemoryParameters, /* 0.10.2 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index e540167..214931c 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 shared memory parameters + */ +const REMOTE_NODE_SHARED_MEMORY_PARAMETERS_MAX = 16; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -2579,6 +2584,21 @@ struct remote_storage_pool_list_all_volumes_ret { unsigned int ret; }; +struct remote_node_set_shared_memory_parameters_args { + remote_typed_param params<REMOTE_NODE_SHARED_MEMORY_PARAMETERS_MAX>; + unsigned int flags; +}; + +struct remote_node_get_shared_memory_parameters_args { + int nparams; + unsigned int flags; +}; + +struct remote_node_get_shared_memory_parameters_ret { + remote_typed_param params<REMOTE_NODE_SHARED_MEMORY_PARAMETERS_MAX>; + int nparams; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -2911,7 +2931,9 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_EMULATOR_PIN_INFO = 280, /* skipgen skipgen */ 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_STORAGE_POOL_LIST_ALL_VOLUMES = 282, /* skipgen skipgen priority:high */ + REMOTE_PROC_NODE_SET_SHARED_MEMORY_PARAMETERS = 283, /* autogen autogen */ + REMOTE_PROC_NODE_GET_SHARED_MEMORY_PARAMETERS = 284 /* 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 cef62e8..88eeeee 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2034,6 +2034,24 @@ struct remote_storage_pool_list_all_volumes_ret { } vols; u_int ret; }; +struct remote_node_set_shared_memory_parameters_args { + struct { + u_int params_len; + remote_typed_param * params_val; + } params; + u_int flags; +}; +struct remote_node_get_shared_memory_parameters_args { + int nparams; + u_int flags; +}; +struct remote_node_get_shared_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, @@ -2317,4 +2335,6 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_GET_EMULATOR_PIN_INFO = 280, REMOTE_PROC_CONNECT_LIST_ALL_STORAGE_POOLS = 281, REMOTE_PROC_STORAGE_POOL_LIST_ALL_VOLUMES = 282, + REMOTE_PROC_NODE_SET_SHARED_MEMORY_PARAMETERS = 283, + REMOTE_PROC_NODE_GET_SHARED_MEMORY_PARAMETERS = 284, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 12023e9..8122de1 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 "NodeSetSharedMemoryParameters") { + 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}SharedMemoryParameters) * src/nodeinfo.c: (Implement node{Get,Set}SharedMemoryParameters) * src/libvirt_private.syms: (Export those two new internal APIs to private symbols) --- src/libvirt_private.syms | 2 + src/nodeinfo.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 10 ++ 3 files changed, 356 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 10af063..b6f3d84 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -878,6 +878,8 @@ nodeGetCellsFreeMemory; nodeGetFreeMemory; nodeGetInfo; nodeGetMemoryStats; +nodeGetSharedMemoryParameters; +nodeSetSharedMemoryParameters; # nwfilter_conf.h diff --git a/src/nodeinfo.c b/src/nodeinfo.c index e3d4a24..b7560b0 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_SHARED_MEMORY_PATH "/sys/kernel/mm/ksm" # define LINUX_NB_CPU_STATS 4 # define LINUX_NB_MEMORY_STATS_ALL 4 @@ -933,6 +935,348 @@ nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED, #endif } +int +nodeSetSharedMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virCheckFlags(0, -1); + +#ifdef __linux__ + { + int ret = 0; + int rc; + int i; + + if (virTypedParameterArrayValidate(params, nparams, + VIR_NODE_SHARED_MEMORY_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + VIR_NODE_SHARED_MEMORY_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + NULL) < 0) + return -1; + + if (!virFileExists(SYSFS_SHARED_MEMORY_PATH)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("shared memory is not enabled on this host")); + return -1; + } + + for (i = 0; i < nparams; i++) { + virTypedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, + VIR_NODE_SHARED_MEMORY_PAGES_TO_SCAN)) { + char *pages_to_scan = NULL; + char *strval = NULL; + + if (virAsprintf(&pages_to_scan, "%s/%s", + SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_PAGES_TO_SCAN) < 0) { + virReportOOMError(); + return -1; + } + + if (virAsprintf(&strval, "%u", param->value.ui) == -1) { + virReportOOMError(); + VIR_FREE(pages_to_scan); + return -1; + } + + if ((rc = virFileWriteStr(pages_to_scan, strval, 0)) < 0) { + virReportSystemError(-rc, "%s", + _("failed to set pages_to_scan")); + ret = -1; + } + VIR_FREE(pages_to_scan); + VIR_FREE(strval); + } else if (STREQ(param->field, + VIR_NODE_SHARED_MEMORY_SLEEP_MILLISECS)) { + char *sleep_millisecs = NULL; + char *strval = NULL; + + if (virAsprintf(&sleep_millisecs, "%s/%s", + SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_SLEEP_MILLISECS) < 0) { + virReportOOMError(); + return -1; + } + + if (virAsprintf(&strval, "%u", param->value.ui) == -1) { + virReportOOMError(); + VIR_FREE(sleep_millisecs); + return -1; + } + + if ((rc = virFileWriteStr(sleep_millisecs, strval, 0)) < 0) { + virReportSystemError(-rc, "%s", + _("failed to set pages_to_scan")); + ret = -1; + } + VIR_FREE(sleep_millisecs); + VIR_FREE(strval); + } + } + + return ret; + } +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node set shared memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + +#define NODE_SHARED_MEMORY_PARAMETERS_NUM 7 +int +nodeGetSharedMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + +#ifdef __linux__ + { + char *path = NULL; + char *buf = NULL; + 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 ret = -1; + int i; + + if (!virFileExists(SYSFS_SHARED_MEMORY_PATH)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("shared memory is not enabled on this host")); + return -1; + } + + if ((*nparams) == 0) { + *nparams = NODE_SHARED_MEMORY_PARAMETERS_NUM; + return 0; + } + + for (i = 0; i < *nparams && i < NODE_SHARED_MEMORY_PARAMETERS_NUM; i++) { + virTypedParameterPtr param = ¶ms[i]; + char *tmp = NULL; + + switch(i) { + case 0: + if (virAsprintf(&path, "%s/%s", SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_PAGES_TO_SCAN) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &pages_to_scan) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_to_scan")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_SHARED_MEMORY_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, pages_to_scan) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 1: + if (virAsprintf(&path, "%s/%s", SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_SLEEP_MILLISECS) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &sleep_millisecs) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse sleep_millisecs")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_SHARED_MEMORY_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, sleep_millisecs) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 2: + if (virAsprintf(&path, "%s/%s", SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_PAGES_SHARED) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_shared) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_shared")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_SHARED_MEMORY_PAGES_SHARED, + VIR_TYPED_PARAM_ULLONG, pages_shared) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 3: + if (virAsprintf(&path, "%s/%s", SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_PAGES_SHARING) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_sharing) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_sharing")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_SHARED_MEMORY_PAGES_SHARING, + VIR_TYPED_PARAM_ULLONG, pages_sharing) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 4: + if (virAsprintf(&path, "%s/%s", SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_PAGES_UNSHARED) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_unshared) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_unshared")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_SHARED_MEMORY_PAGES_UNSHARED, + VIR_TYPED_PARAM_ULLONG, pages_unshared) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 5: + if (virAsprintf(&path, "%s/%s", SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_PAGES_VOLATILE) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &pages_volatile) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse pages_volatile")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_SHARED_MEMORY_PAGES_VOLATILE, + VIR_TYPED_PARAM_ULLONG, pages_volatile) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + case 6: + if (virAsprintf(&path, "%s/%s", SYSFS_SHARED_MEMORY_PATH, + VIR_NODE_SHARED_MEMORY_FULL_SCANS) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (virStrToLong_ull(buf, NULL, 10, &full_scans) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse full_scans")); + goto cleanup; + } + + if (virTypedParameterAssign(param, VIR_NODE_SHARED_MEMORY_FULL_SCANS, + VIR_TYPED_PARAM_ULLONG, full_scans) < 0) + goto cleanup; + + VIR_FREE(path); + VIR_FREE(buf); + break; + + default: + break; + } + } + + ret = 0; + + cleanup: + VIR_FREE(path); + VIR_FREE(buf); + return ret; + } +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node get shared 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..fa9e49f 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 nodeGetSharedMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int nodeSetSharedMemoryParameters(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..c96f324 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 */ + .nodeGetSharedMemoryParameters = nodeGetSharedMemoryParameters, /* 0.10.2 */ + .nodeSetSharedMemoryParameters = nodeSetSharedMemoryParameters, /* 0.10.2 */ }; static virStateDriver lxcStateDriver = { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8e8e00c..d77e8fc 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 */ + .nodeGetSharedMemoryParameters = nodeGetSharedMemoryParameters, /* 0.10.2 */ + .nodeSetSharedMemoryParameters = nodeSetSharedMemoryParameters, /* 0.10.2 */ }; diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 26877eb..65ac13a 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 */ + .nodeGetSharedMemoryParameters = nodeGetSharedMemoryParameters, /* 0.10.2 */ + .nodeSetSharedMemoryParameters = nodeSetSharedMemoryParameters, /* 0.10.2 */ }; static virStateDriver umlStateDriver = { diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index d33737e..8019513 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 */ + .nodeGetSharedMemoryParameters = nodeGetSharedMemoryParameters, /* 0.10.2 */ + .nodeSetSharedMemoryParameters = nodeSetSharedMemoryParameters, /* 0.10.2 */ }; /** -- 1.7.7.3

New command node-shared-memory-tune to get/set the node shared memory parameters, only two parameters are allowed to set (pages_to_scan, and sleep_millisecs, see documents in this patch for more details). --- tools/virsh-host.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 8 ++++ 2 files changed, 118 insertions(+), 0 deletions(-) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index c46288b..a33cdd7 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,121 @@ cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } +static const vshCmdInfo info_node_shared_memory_tune[] = { + {"help", N_("Get or set node shared memory parameters")}, + {"desc", N_("Get or set node shared memory parameters" + " To get the shared memory parameters, use following command: \n\n" + " virsh # node-shared-memory-tune")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_shared_memory_tune[] = { + {"pages-to-scan", VSH_OT_INT, VSH_OFLAG_NONE, + N_("number of pages to scan before shared memory service " + "goes to sleep")}, + {"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 +cmdNodeSharedMemoryTune(vshControl *ctl, const vshCmd *cmd) +{ + virTypedParameterPtr params = NULL; + int nparams = 0; + unsigned int flags = 0; + unsigned int pages_to_scan = 0; + unsigned int sleep_millisecs = 0; + bool ret = false; + int i = 0; + + if (vshCommandOptUInt(cmd, "pages-to-scan", &pages_to_scan) < 0) { + vshError(ctl, "%s", _("invalid pages-to-scan number")); + return false; + } + + if (vshCommandOptUInt(cmd, "sleep-millisecs", &sleep_millisecs) < 0) { + vshError(ctl, "%s", _("invalid sleep-millisecs number")); + return false; + } + + if (pages_to_scan) + nparams++; + + if (sleep_millisecs) + nparams++; + + if (nparams == 0) { + /* Get the number of shared memory parameters */ + if (virNodeGetSharedMemoryParameters(ctl->conn, NULL, &nparams, flags) != 0) { + vshError(ctl, "%s", + _("Unable to get number of shared memory parameters")); + goto cleanup; + } + + if (nparams == 0) { + ret = true; + goto cleanup; + } + + /* Now go get all the shared memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + if (virNodeGetSharedMemoryParameters(ctl->conn, params, &nparams, flags) != 0) { + vshError(ctl, "%s", _("Unable to get shared memory parameters")); + goto cleanup; + } + + for (i = 0; i < nparams; i++) { + char *str = vshGetTypedParamValue(ctl, ¶ms[i]); + vshPrint(ctl, "%-15s: %s\n", params[i].field, str); + VIR_FREE(str); + } + + ret = true; + } else { + /* Set the shared memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + + if (i < nparams && pages_to_scan) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_SHARED_MEMORY_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + pages_to_scan) < 0) + goto error; + } + + if (i < nparams && sleep_millisecs) { + if (virTypedParameterAssign(¶ms[i++], + VIR_NODE_SHARED_MEMORY_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + sleep_millisecs) < 0) + goto error; + } + + if (virNodeSetSharedMemoryParameters(ctl->conn, params, nparams, flags) != 0) + goto error; + else + ret = true; + } + +cleanup: + VIR_FREE(params); + return ret; + +error: + vshError(ctl, "%s", _("Unable to change shared 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-shared-memory-tune", cmdNodeSharedMemoryTune, + opts_node_shared_memory_tune, info_node_shared_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 68138e5..6c9e14e 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-shared-memory-tune> [I<pages-to-scan>] [I<sleep-millisecs>] + +Allows you to display or set the node shared memory parameters. +I<pages-to-scan> can be used to set the number of pages to scan +before the shared memory service goes to sleep; I<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 8a228fb..ccccefc 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -499,5 +499,18 @@ <arg name='domain' type='virDomainPtr' info='a domain object'/> <arg name='flags' type='unsigned int' info='unused, always pass 0'/> </function> + <function name='virNodeSetSharedMemoryParameters' file='python'> + <info>Change the node shared 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 shared memory tunable objects'/> + <arg name='flags' type='int' info='unused, always pass 0'/> + </function> + <function name='virNodeGetSharedMemoryParameters' file='python'> + <info>Get the node shared 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 c1f8938..ea4fbea 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -5907,6 +5907,129 @@ cleanup: return py_retval; } +static PyObject * +libvirt_virNodeSetSharedMemoryParameters(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:virNodeSetSharedMemoryParameters", + &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 = virNodeGetSharedMemoryParameters(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 = virNodeGetSharedMemoryParameters(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 = virNodeSetSharedMemoryParameters(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_virNodeGetSharedMemoryParameters(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:virNodeGetSharedMemoryParameters", + &pyobj_conn, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virNodeGetSharedMemoryParameters(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 = virNodeGetSharedMemoryParameters(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 * @@ -6016,6 +6139,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 *) "virNodeGetSharedMemoryParameters", libvirt_virNodeGetSharedMemoryParameters, METH_VARARGS, NULL}, + {(char *) "virNodeSetSharedMemoryParameters", libvirt_virNodeSetSharedMemoryParameters, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; -- 1.7.7.3

Ping. On 2012年09月10日 20:08, Osier Yang wrote:
As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}SharedMemoryParameters) to get and set the host shared memory tunables (ksm under linux).
Osier Yang (7): Improve virTypedParameterValidateSet shared_memory: Define the APIs to get/set shared memory parameters shared_memory: Wire up the RPC protocol shared_memory: Implement the internal APIs shared_memory: Support get/set shared memory parameters for drivers shared_memory: Expose the APIs to virsh shared_memory: Expose the APIs to Python bindings
daemon/remote.c | 61 +++++++ 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 | 141 +++++++++++++++- src/libvirt_private.syms | 2 + src/libvirt_public.syms | 2 + src/lxc/lxc_driver.c | 2 + src/nodeinfo.c | 344 +++++++++++++++++++++++++++++++++++++++ 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 | 110 +++++++++++++ tools/virsh.pod | 8 + 21 files changed, 990 insertions(+), 11 deletions(-)

On 09/10/2012 06:08 AM, Osier Yang wrote:
As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}SharedMemoryParameters) to get
I still think this name is too long; virNode{Get,Set}MemoryParameters seems just fine, and is more extensible if we come up with a future node memory turning not related to just how shared memory behaves. Anyone else have an opinion on naming, since I'd like to see the API itself in 0.10.2? -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 2012年09月14日 05:04, Eric Blake wrote:
On 09/10/2012 06:08 AM, Osier Yang wrote:
As a result of RFC: https://www.redhat.com/archives/libvir-list/2012-August/msg01998.html, this adds two new APIs (virNode{Get,Set}SharedMemoryParameters) to get
I still think this name is too long; virNode{Get,Set}MemoryParameters seems just fine, and is more extensible if we come up with a future node memory turning not related to just how shared memory behaves. Anyone else have an opinion on naming, since I'd like to see the API itself in 0.10.2?
Hi, Eric, It's trivial to change the name, and it doesn't affect review the left patches, so if you are free, can you review the left ones too? I'm afraid the window between posts could past the freezing date. Regards, Osier
participants (2)
-
Eric Blake
-
Osier Yang