[libvirt] [PATCH] virsh: Fix name of domain suspend command
by Michal Privoznik
It's dompmsuspend, not suspend-duration.
---
Pushed under trivial rule.
tools/virsh.pod | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tools/virsh.pod b/tools/virsh.pod
index bd79b4c..877533b 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1280,7 +1280,7 @@ Moves a domain out of the suspended state. This will allow a previously
suspended domain to now be eligible for scheduling by the underlying
hypervisor.
-=item B<suspend-duration> I<domain-id> I<target>
+=item B<dompmsuspend> I<domain-id> I<target>
Suspend a running domain into one of these states (possible I<target>
values):
--
1.7.3.4
12 years, 9 months
[libvirt] [PATCH] virpidfile: Allow whitespace character on the end of pidfile
by Michal Privoznik
Some programs, notably dnsmasq, which are writing pidfiles on their
own do append a whitespace character after pid, e.g. '\n'.
---
src/util/virpidfile.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/util/virpidfile.c b/src/util/virpidfile.c
index 34d1250..9c29967 100644
--- a/src/util/virpidfile.c
+++ b/src/util/virpidfile.c
@@ -34,7 +34,7 @@
#include "intprops.h"
#include "logging.h"
#include "virterror_internal.h"
-
+#include "c-ctype.h"
#define VIR_FROM_THIS VIR_FROM_NONE
@@ -119,6 +119,7 @@ int virPidFileReadPath(const char *path,
ssize_t bytes;
long long pid_value = 0;
char pidstr[INT_BUFSIZE_BOUND(pid_value)];
+ char *endptr = NULL;
*pid = 0;
@@ -135,7 +136,8 @@ int virPidFileReadPath(const char *path,
}
pidstr[bytes] = '\0';
- if (virStrToLong_ll(pidstr, NULL, 10, &pid_value) < 0 ||
+ if (virStrToLong_ll(pidstr, &endptr, 10, &pid_value) < 0 ||
+ !(*endptr == '\0' || c_isspace(*endptr)) ||
(pid_t) pid_value != pid_value) {
rc = -1;
goto cleanup;
--
1.7.3.4
12 years, 9 months
[libvirt] [test-API][PATCH] Add 3 APIs in snapshotAPI
by Wayne Sun
* new APIs
get_parent(self, domname, snapname, flag = 0)
children_num(self, domname, snapname, flag)
children_names_list(self, domname, snapname, flag)
the flag in children_num and children_names_list could be in 0-7,
which is the OR operation result of
(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
VIR_DOMAIN_SNAPSHOT_LIST_LEAVES)
* deleted redundancy spaces and fixed a typo in function domain()
* getConnect(), getDomain() and getName() API are not added in,
current snapshotAPI requires user to offer connection obj, domain
name and snapshot name.
---
lib/snapshotAPI.py | 59 ++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 46 insertions(+), 13 deletions(-)
diff --git a/lib/snapshotAPI.py b/lib/snapshotAPI.py
index 43ccb89..d866b60 100644
--- a/lib/snapshotAPI.py
+++ b/lib/snapshotAPI.py
@@ -24,14 +24,14 @@ import libvirt
import re
import os
-def append_path(path):
+def append_path(path):
"""Append root path of package"""
if path in sys.path:
pass
else:
sys.path.append(path)
-
-pwd = os.getcwd()
+
+pwd = os.getcwd()
result = re.search('(.*)libvirt-test-API', pwd)
append_path(result.group(0))
@@ -39,7 +39,7 @@ import exception
class SnapshotAPI(object):
def __init__(self, connection):
- self.conn = connection
+ self.conn = connection
def create(self, domname, xml_desc, flag = 0):
try:
@@ -57,7 +57,7 @@ class SnapshotAPI(object):
except libvirt.libvirtError, e:
message = e.get_error_message()
code = e.get_error_code()
- raise exception.LibvirtAPI(message, code)
+ raise exception.LibvirtAPI(message, code)
def snapshot_name_list(self, domname, flag = 0):
try:
@@ -66,7 +66,7 @@ class SnapshotAPI(object):
except libvirt.libvirtError, e:
message = e.get_error_message()
code = e.get_error_code()
- raise exception.LibvirtAPI(message, code)
+ raise exception.LibvirtAPI(message, code)
def snapshot_nums(self, domname, flag = 0):
try:
@@ -95,31 +95,64 @@ class SnapshotAPI(object):
message = e.get_error_message()
code = e.get_error_code()
raise exception.LibvirtAPI(message, code)
-
+
def delete(self, domname, snapname, flag = 0):
try:
- snap = self.snapshot_lookup_by_name(domname, snapname, flag = 0)
+ snap = self.snapshot_lookup_by_name(domname, snapname)
return snap.delete(flag)
except libvirt.libvirtError, e:
message = e.get_error_message()
code = e.get_error_code()
- raise exception.LibvirtAPI(message, code)
+ raise exception.LibvirtAPI(message, code)
def get_xml_desc(self, domname, snapname, flag = 0):
try:
- snap = self.snapshot_lookup_by_name(domname, snapname, flag = 0)
+ snap = self.snapshot_lookup_by_name(domname, snapname)
return snap.getXMLDesc(flag)
except libvirt.libvirtError, e:
message = e.get_error_message()
code = e.get_error_code()
raise exception.LibvirtAPI(message, code)
- def domain(self, domname):
+ def domain(self, domname, snapname):
try:
- snap = self.snapshot_lookup_by_name(domname, snapname, flag = 0)
+ snap = self.snapshot_lookup_by_name(domname, snapname)
return snap.domain()
except libvirt.libvirtError, e:
message = e.get_error_message()
code = e.get_error_code()
raise exception.LibvirtAPI(message, code)
-
+
+ def get_parent(self, domname, snapname, flag = 0):
+ try:
+ snap = self.snapshot_lookup_by_name(domname, snapname)
+ return snap.getParent(flag)
+ except libvirt.libvirtError, e:
+ message = e.get_error_message()
+ code = e.get_error_code()
+ raise exception.LibvirtAPI(message, code)
+
+ def children_num(self, domname, snapname, flag):
+ try:
+ snap = self.snapshot_lookup_by_name(domname, snapname)
+ return snap.numChildren(flag)
+ except libvirt.libvirtError, e:
+ message = e.get_error_message()
+ code = e.get_error_code()
+ raise exception.LibvirtAPI(message, code)
+
+ def children_names_list(self, domname, snapname, flag):
+ try:
+ snap = self.snapshot_lookup_by_name(domname, snapname)
+ return snap.listChildrenNames(flag)
+ except libvirt.libvirtError, e:
+ message = e.get_error_message()
+ code = e.get_error_code()
+ raise exception.LibvirtAPI(message, code)
+
+# virDomainSnapshotListFlags
+VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS = 1
+VIR_DOMAIN_SNAPSHOT_LIST_ROOTS = 1
+VIR_DOMAIN_SNAPSHOT_LIST_METADATA = 2
+VIR_DOMAIN_SNAPSHOT_LIST_LEAVES = 4
+
--
1.7.1
12 years, 9 months
[libvirt] [PATCH] python: make other APIs share common {get, set}PyVirTypedParameter
by Guannan Ren
*libvirt_virDomainBlockStatsFlags
*libvirt_virDomainGetSchedulerParameters
*libvirt_virDomainGetSchedulerParametersFlags
*libvirt_virDomainSetSchedulerParameters
*libvirt_virDomainSetSchedulerParametersFlags
*libvirt_virDomainSetBlkioParameters
*libvirt_virDomainGetBlkioParameters
*libvirt_virDomainSetMemoryParameters
*libvirt_virDomainGetMemoryParameters
*libvirt_virDomainSetBlockIoTune
*libvirt_virDomainGetBlockIoTune
---
python/libvirt-override-api.xml | 12 +-
python/libvirt-override.c | 885 +++++++++++++--------------------------
2 files changed, 295 insertions(+), 602 deletions(-)
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
index 8eed0bb..563dd46 100644
--- a/python/libvirt-override-api.xml
+++ b/python/libvirt-override-api.xml
@@ -144,7 +144,7 @@
</function>
<function name='virDomainBlockStatsFlags' file='python'>
<info>Extracts block device statistics parameters of a running domain</info>
- <return type='virTypedParameterPtr' info='None in case of error, returns a dictionary of params'/>
+ <return type='str *' info='None in case of error, returns a dictionary of params'/>
<arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
<arg name='path' type='char *' info='the path for the block device'/>
<arg name='flags' type='int' info='flags (unused; pass 0)'/>
@@ -169,12 +169,12 @@
</function>
<function name='virDomainGetSchedulerParameters' file='python'>
<info>Get the scheduler parameters, the @params array will be filled with the values.</info>
- <return type='int' info='-1 in case of error, 0 in case of success.'/>
+ <return type='str *' info='None in case of error, returns a dictionary of params.'/>
<arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
</function>
<function name='virDomainGetSchedulerParametersFlags' file='python'>
<info>Get the scheduler parameters</info>
- <return type='virSchedParameterPtr' info='None in case of error, returns a dictionary of params'/>
+ <return type='str *' info='None in case of error, returns a dictionary of params'/>
<arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
<arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/>
</function>
@@ -231,7 +231,7 @@
</function>
<function name='virDomainGetBlkioParameters' file='python'>
<info>Get the blkio parameters</info>
- <return type='virSchedParameterPtr' info='None in case of error, returns a dictionary of params'/>
+ <return type='str *' info='None in case of error, returns a dictionary of params'/>
<arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
<arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/>
</function>
@@ -244,7 +244,7 @@
</function>
<function name='virDomainGetMemoryParameters' file='python'>
<info>Get the memory parameters</info>
- <return type='virSchedParameterPtr' info='None in case of error, returns a dictionary of params'/>
+ <return type='str *' info='None in case of error, returns a dictionary of params'/>
<arg name='domain' type='virDomainPtr' info='pointer to domain object'/>
<arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/>
</function>
@@ -415,7 +415,7 @@
<arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
<arg name='disk' type='const char *' info='disk name'/>
<arg name='flags' type='unsigned int' info='an OR'ed set of virDomainModificationImpact'/>
- <return type='virTypedParameterPtr' info='the I/O tunables value or None in case of error'/>
+ <return type='str *' info='the I/O tunables value or None in case of error'/>
</function>
<function name='virDomainBlockPeek' file='python'>
<info>Read the contents of domain's disk device</info>
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index e7c2bd5..3ffdb62 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -330,18 +330,20 @@ libvirt_virDomainBlockStats(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
static PyObject *
libvirt_virDomainBlockStatsFlags(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
- PyObject *pyobj_domain, *info;
+ PyObject *pyobj_domain;
+ PyObject *ret = NULL;
int i_retval;
- int nparams = 0, i;
+ int nparams = 0;
unsigned int flags;
virTypedParameterPtr params;
const char *path;
if (!PyArg_ParseTuple(args, (char *)"Ozi:virDomainBlockStatsFlags",
&pyobj_domain, &path, &flags))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
LIBVIRT_BEGIN_ALLOW_THREADS;
@@ -351,67 +353,29 @@ libvirt_virDomainBlockStatsFlags(PyObject *self ATTRIBUTE_UNUSED,
if (i_retval < 0)
return VIR_PY_NONE;
+ if (!nparams)
+ return PyDict_New();
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_NONE;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainBlockStatsFlags(domain, path, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_NONE;
- }
-
- /* convert to a Python tuple of long objects */
- if ((info = PyDict_New()) == NULL) {
- VIR_FREE(params);
- return VIR_PY_NONE;
+ ret = VIR_PY_NONE;
+ goto cleanup;
}
- for (i = 0 ; i < nparams ; i++) {
- PyObject *key, *val;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- val = PyInt_FromLong((long)params[i].value.i);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- val = PyInt_FromLong((long)params[i].value.ui);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- val = PyLong_FromLongLong((long long)params[i].value.l);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- val = PyLong_FromLongLong((long long)params[i].value.ul);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- val = PyFloat_FromDouble((double)params[i].value.d);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- val = PyBool_FromLong((long)params[i].value.b);
- break;
-
- default:
- VIR_FREE(params);
- Py_DECREF(info);
- return VIR_PY_NONE;
- }
-
- key = libvirt_constcharPtrWrap(params[i].field);
- PyDict_SetItem(info, key, val);
- }
+ ret = getPyVirTypedParameter(params, nparams);
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return(info);
+ return ret;
}
-
static PyObject *
libvirt_virDomainInterfaceStats(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
virDomainPtr domain;
@@ -530,17 +494,19 @@ libvirt_virDomainGetSchedulerType(PyObject *self ATTRIBUTE_UNUSED,
static PyObject *
libvirt_virDomainGetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
- PyObject *pyobj_domain, *info;
+ PyObject *pyobj_domain;
+ PyObject *ret = NULL;
char *c_retval;
int i_retval;
- int nparams, i;
+ int nparams = 0;
virTypedParameterPtr params;
if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetScedulerParameters",
&pyobj_domain))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
LIBVIRT_BEGIN_ALLOW_THREADS;
@@ -551,78 +517,45 @@ libvirt_virDomainGetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED,
return VIR_PY_NONE;
VIR_FREE(c_retval);
+ if (!nparams)
+ return PyDict_New();
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_NONE;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetSchedulerParameters(domain, params, &nparams);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_NONE;
+ ret = VIR_PY_NONE;
+ goto cleanup;
}
- /* convert to a Python tuple of long objects */
- if ((info = PyDict_New()) == NULL) {
- VIR_FREE(params);
- return VIR_PY_NONE;
- }
- for (i = 0 ; i < nparams ; i++) {
- PyObject *key, *val;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- val = PyInt_FromLong((long)params[i].value.i);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- val = PyInt_FromLong((long)params[i].value.ui);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- val = PyLong_FromLongLong((long long)params[i].value.l);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- val = PyLong_FromLongLong((long long)params[i].value.ul);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- val = PyFloat_FromDouble((double)params[i].value.d);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- val = PyBool_FromLong((long)params[i].value.b);
- break;
-
- default:
- VIR_FREE(params);
- Py_DECREF(info);
- return VIR_PY_NONE;
- }
+ ret = getPyVirTypedParameter(params, nparams);
- key = libvirt_constcharPtrWrap(params[i].field);
- PyDict_SetItem(info, key, val);
- }
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return(info);
+ return ret;
}
static PyObject *
libvirt_virDomainGetSchedulerParametersFlags(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
- PyObject *pyobj_domain, *info;
+ PyObject *pyobj_domain;
+ PyObject *ret = NULL;
char *c_retval;
int i_retval;
- int nparams, i;
+ int nparams = 0;
unsigned int flags;
virTypedParameterPtr params;
if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetScedulerParametersFlags",
&pyobj_domain, &flags))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
LIBVIRT_BEGIN_ALLOW_THREADS;
@@ -633,79 +566,55 @@ libvirt_virDomainGetSchedulerParametersFlags(PyObject *self ATTRIBUTE_UNUSED,
return VIR_PY_NONE;
VIR_FREE(c_retval);
+ if (!nparams)
+ return PyDict_New();
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_NONE;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetSchedulerParametersFlags(domain, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_NONE;
- }
-
- /* convert to a Python tuple of long objects */
- if ((info = PyDict_New()) == NULL) {
- VIR_FREE(params);
- return VIR_PY_NONE;
+ ret = VIR_PY_NONE;
+ goto cleanup;
}
- for (i = 0 ; i < nparams ; i++) {
- PyObject *key, *val;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- val = PyInt_FromLong((long)params[i].value.i);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- val = PyInt_FromLong((long)params[i].value.ui);
- break;
- case VIR_TYPED_PARAM_LLONG:
- val = PyLong_FromLongLong((long long)params[i].value.l);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- val = PyLong_FromLongLong((long long)params[i].value.ul);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- val = PyFloat_FromDouble((double)params[i].value.d);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- val = PyBool_FromLong((long)params[i].value.b);
- break;
-
- default:
- VIR_FREE(params);
- Py_DECREF(info);
- return VIR_PY_NONE;
- }
+ ret = getPyVirTypedParameter(params, nparams);
- key = libvirt_constcharPtrWrap(params[i].field);
- PyDict_SetItem(info, key, val);
- }
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return(info);
+ return ret;
}
static PyObject *
libvirt_virDomainSetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
PyObject *pyobj_domain, *info;
+ PyObject *ret = NULL;
char *c_retval;
int i_retval;
- int nparams, i;
- virTypedParameterPtr params;
+ int nparams = 0, size = 0;
+ virTypedParameterPtr params, new_params;
if (!PyArg_ParseTuple(args, (char *)"OO:virDomainSetScedulerParameters",
&pyobj_domain, &info))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+ 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;
c_retval = virDomainGetSchedulerType(domain, &nparams);
LIBVIRT_END_ALLOW_THREADS;
@@ -714,95 +623,74 @@ libvirt_virDomainSetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED,
return VIR_PY_INT_FAIL;
VIR_FREE(c_retval);
+ if (nparams == 0) {
+ PyErr_Format(PyExc_LookupError,
+ "Domain has no settable attributes");
+ return NULL;
+ }
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_INT_FAIL;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetSchedulerParameters(domain, params, &nparams);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
- /* convert to a Python tuple of long objects */
- for (i = 0 ; i < nparams ; i++) {
- PyObject *key, *val;
- key = libvirt_constcharPtrWrap(params[i].field);
- val = PyDict_GetItem(info, key);
- Py_DECREF(key);
-
- if (val == NULL)
- continue;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- params[i].value.i = (int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- params[i].value.l = (long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- params[i].value.d = (double)PyFloat_AsDouble(val);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- {
- /* Hack - Python's definition of Py_True breaks strict
- * aliasing rules, so can't directly compare :-(
- */
- PyObject *hacktrue = PyBool_FromLong(1);
- params[i].value.b = hacktrue == val ? 1 : 0;
- Py_DECREF(hacktrue);
- }
- break;
-
- default:
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
- }
- }
+ new_params = setPyVirTypedParameter(info, params, nparams);
+ if (!new_params)
+ goto cleanup;
LIBVIRT_BEGIN_ALLOW_THREADS;
- i_retval = virDomainSetSchedulerParameters(domain, params, nparams);
+ i_retval = virDomainSetSchedulerParameters(domain, new_params, size);
LIBVIRT_END_ALLOW_THREADS;
+
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
+ ret = VIR_PY_INT_SUCCESS;
+
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return VIR_PY_INT_SUCCESS;
+ VIR_FREE(new_params);
+ return ret;
}
static PyObject *
libvirt_virDomainSetSchedulerParametersFlags(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
PyObject *pyobj_domain, *info;
+ PyObject *ret = NULL;
char *c_retval;
int i_retval;
- int nparams, i;
+ int nparams = 0, size = 0;
unsigned int flags;
- virTypedParameterPtr params;
+ virTypedParameterPtr params, new_params;
if (!PyArg_ParseTuple(args,
(char *)"OOi:virDomainSetScedulerParametersFlags",
&pyobj_domain, &info, &flags))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+ 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;
c_retval = virDomainGetSchedulerType(domain, &nparams);
LIBVIRT_END_ALLOW_THREADS;
@@ -811,95 +699,73 @@ libvirt_virDomainSetSchedulerParametersFlags(PyObject *self ATTRIBUTE_UNUSED,
return VIR_PY_INT_FAIL;
VIR_FREE(c_retval);
+ if (nparams == 0) {
+ PyErr_Format(PyExc_LookupError,
+ "Domain has no settable attributes");
+ return NULL;
+ }
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_INT_FAIL;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetSchedulerParametersFlags(domain, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
- /* convert to a Python tuple of long objects */
- for (i = 0; i < nparams; i++) {
- PyObject *key, *val;
- key = libvirt_constcharPtrWrap(params[i].field);
- val = PyDict_GetItem(info, key);
- Py_DECREF(key);
-
- if (val == NULL)
- continue;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- params[i].value.i = (int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- params[i].value.l = (long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- params[i].value.d = (double)PyFloat_AsDouble(val);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- {
- /* Hack - Python's definition of Py_True breaks strict
- * aliasing rules, so can't directly compare :-(
- */
- PyObject *hacktrue = PyBool_FromLong(1);
- params[i].value.b = hacktrue == val ? 1: 0;
- Py_DECREF(hacktrue);
- }
- break;
-
- default:
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
- }
- }
+ new_params = setPyVirTypedParameter(info, params, nparams);
+ if (!new_params)
+ goto cleanup;
LIBVIRT_BEGIN_ALLOW_THREADS;
- i_retval = virDomainSetSchedulerParametersFlags(domain, params, nparams, flags);
+ i_retval = virDomainSetSchedulerParametersFlags(domain, new_params, size, flags);
LIBVIRT_END_ALLOW_THREADS;
+
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
+ ret = VIR_PY_INT_SUCCESS;
+
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return VIR_PY_INT_SUCCESS;
+ VIR_FREE(new_params);
+ return ret;
}
-
static PyObject *
libvirt_virDomainSetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
PyObject *pyobj_domain, *info;
+ PyObject *ret = NULL;
int i_retval;
- int nparams = 0, i;
+ int nparams = 0, size = 0;
unsigned int flags;
- virTypedParameterPtr params;
+ virTypedParameterPtr params, new_params;
if (!PyArg_ParseTuple(args,
(char *)"OOi:virDomainSetBlkioParameters",
&pyobj_domain, &info, &flags))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+ 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 = virDomainGetBlkioParameters(domain, NULL, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
@@ -907,91 +773,61 @@ libvirt_virDomainSetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
if (i_retval < 0)
return VIR_PY_INT_FAIL;
+ if (nparams == 0) {
+ PyErr_Format(PyExc_LookupError,
+ "Domain has no settable attributes");
+ return NULL;
+ }
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_INT_FAIL;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetBlkioParameters(domain, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
- /* convert to a Python tuple of long objects */
- for (i = 0; i < nparams; i++) {
- PyObject *key, *val;
- key = libvirt_constcharPtrWrap(params[i].field);
- val = PyDict_GetItem(info, key);
- Py_DECREF(key);
-
- if (val == NULL)
- continue;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- params[i].value.i = (int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- params[i].value.l = (long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- params[i].value.d = (double)PyFloat_AsDouble(val);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- {
- /* Hack - Python's definition of Py_True breaks strict
- * aliasing rules, so can't directly compare :-(
- */
- PyObject *hacktrue = PyBool_FromLong(1);
- params[i].value.b = hacktrue == val ? 1: 0;
- Py_DECREF(hacktrue);
- }
- break;
-
- default:
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
- }
- }
+ new_params = setPyVirTypedParameter(info, params, nparams);
+ if (!new_params)
+ goto cleanup;
LIBVIRT_BEGIN_ALLOW_THREADS;
- i_retval = virDomainSetBlkioParameters(domain, params, nparams, flags);
+ i_retval = virDomainSetBlkioParameters(domain, new_params, size, flags);
LIBVIRT_END_ALLOW_THREADS;
+
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
+ ret = VIR_PY_INT_SUCCESS;
+
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return VIR_PY_INT_SUCCESS;
+ VIR_FREE(new_params);
+ return ret;
}
static PyObject *
libvirt_virDomainGetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
- PyObject *pyobj_domain, *info;
+ PyObject *pyobj_domain;
+ PyObject *ret = NULL;
int i_retval;
- int nparams = 0, i;
+ int nparams = 0;
unsigned int flags;
virTypedParameterPtr params;
if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetBlkioParameters",
&pyobj_domain, &flags))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
LIBVIRT_BEGIN_ALLOW_THREADS;
@@ -1001,80 +837,56 @@ libvirt_virDomainGetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
if (i_retval < 0)
return VIR_PY_NONE;
+ if (!nparams)
+ return PyDict_New();
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_NONE;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetBlkioParameters(domain, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_NONE;
- }
-
- /* convert to a Python tuple of long objects */
- if ((info = PyDict_New()) == NULL) {
- VIR_FREE(params);
- return VIR_PY_NONE;
+ ret = VIR_PY_NONE;
+ goto cleanup;
}
- for (i = 0 ; i < nparams ; i++) {
- PyObject *key, *val;
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- val = PyInt_FromLong((long)params[i].value.i);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- val = PyInt_FromLong((long)params[i].value.ui);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- val = PyLong_FromLongLong((long long)params[i].value.l);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- val = PyLong_FromLongLong((long long)params[i].value.ul);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- val = PyFloat_FromDouble((double)params[i].value.d);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- val = PyBool_FromLong((long)params[i].value.b);
- break;
-
- default:
- VIR_FREE(params);
- Py_DECREF(info);
- return VIR_PY_NONE;
- }
+ ret = getPyVirTypedParameter(params, nparams);
- key = libvirt_constcharPtrWrap(params[i].field);
- PyDict_SetItem(info, key, val);
- }
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return(info);
+ return ret;
}
static PyObject *
libvirt_virDomainSetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
PyObject *pyobj_domain, *info;
+ PyObject *ret = NULL;
int i_retval;
- int nparams = 0, i;
+ int nparams = 0, size = 0;
unsigned int flags;
- virTypedParameterPtr params;
+ virTypedParameterPtr params, new_params;
if (!PyArg_ParseTuple(args,
(char *)"OOi:virDomainSetMemoryParameters",
&pyobj_domain, &info, &flags))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+ 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 = virDomainGetMemoryParameters(domain, NULL, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
@@ -1082,91 +894,61 @@ libvirt_virDomainSetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED,
if (i_retval < 0)
return VIR_PY_INT_FAIL;
+ if (nparams == 0) {
+ PyErr_Format(PyExc_LookupError,
+ "Domain has no settable attributes");
+ return NULL;
+ }
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_INT_FAIL;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetMemoryParameters(domain, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
- /* convert to a Python tuple of long objects */
- for (i = 0; i < nparams; i++) {
- PyObject *key, *val;
- key = libvirt_constcharPtrWrap(params[i].field);
- val = PyDict_GetItem(info, key);
- Py_DECREF(key);
-
- if (val == NULL)
- continue;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- params[i].value.i = (int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- params[i].value.l = (long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- params[i].value.d = (double)PyFloat_AsDouble(val);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- {
- /* Hack - Python's definition of Py_True breaks strict
- * aliasing rules, so can't directly compare :-(
- */
- PyObject *hacktrue = PyBool_FromLong(1);
- params[i].value.b = hacktrue == val ? 1: 0;
- Py_DECREF(hacktrue);
- }
- break;
-
- default:
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
- }
- }
+ new_params = setPyVirTypedParameter(info, params, nparams);
+ if (!new_params)
+ goto cleanup;
LIBVIRT_BEGIN_ALLOW_THREADS;
- i_retval = virDomainSetMemoryParameters(domain, params, nparams, flags);
+ i_retval = virDomainSetMemoryParameters(domain, new_params, size, flags);
LIBVIRT_END_ALLOW_THREADS;
+
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
+ ret = VIR_PY_INT_SUCCESS;
+
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return VIR_PY_INT_SUCCESS;
+ VIR_FREE(new_params);
+ return ret;
}
static PyObject *
libvirt_virDomainGetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED,
- PyObject *args) {
+ PyObject *args)
+{
virDomainPtr domain;
- PyObject *pyobj_domain, *info;
+ PyObject *pyobj_domain;
+ PyObject *ret = NULL;
int i_retval;
- int nparams = 0, i;
+ int nparams = 0;
unsigned int flags;
virTypedParameterPtr params;
if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetMemoryParameters",
&pyobj_domain, &flags))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
LIBVIRT_BEGIN_ALLOW_THREADS;
@@ -1176,62 +958,27 @@ libvirt_virDomainGetMemoryParameters(PyObject *self ATTRIBUTE_UNUSED,
if (i_retval < 0)
return VIR_PY_NONE;
+ if (!nparams)
+ return PyDict_New();
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_NONE;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetMemoryParameters(domain, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_NONE;
- }
-
- /* convert to a Python tuple of long objects */
- if ((info = PyDict_New()) == NULL) {
- VIR_FREE(params);
- return VIR_PY_NONE;
+ ret = VIR_PY_NONE;
+ goto cleanup;
}
- for (i = 0 ; i < nparams ; i++) {
- PyObject *key, *val;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- val = PyInt_FromLong((long)params[i].value.i);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- val = PyInt_FromLong((long)params[i].value.ui);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- val = PyLong_FromLongLong((long long)params[i].value.l);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- val = PyLong_FromLongLong((long long)params[i].value.ul);
- break;
- case VIR_TYPED_PARAM_DOUBLE:
- val = PyFloat_FromDouble((double)params[i].value.d);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- val = PyBool_FromLong((long)params[i].value.b);
- break;
-
- default:
- VIR_FREE(params);
- Py_DECREF(info);
- return VIR_PY_NONE;
- }
+ ret = getPyVirTypedParameter(params, nparams);
- key = libvirt_constcharPtrWrap(params[i].field);
- PyDict_SetItem(info, key, val);
- }
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return(info);
+ return ret;
}
static PyObject *
@@ -3650,93 +3397,73 @@ libvirt_virDomainSetBlockIoTune(PyObject *self ATTRIBUTE_UNUSED,
PyObject *args)
{
virDomainPtr domain;
- PyObject *pyobj_domain, *pyinfo;
+ PyObject *pyobj_domain, *info;
+ PyObject *ret = NULL;
+ int i_retval;
+ int nparams = 0, size = 0;
const char *disk;
unsigned int flags;
- virTypedParameterPtr params;
- int nparams = 0, i;
- int c_ret;
+ virTypedParameterPtr params, new_params;
if (!PyArg_ParseTuple(args, (char *)"OzOi:virDomainSetBlockIoTune",
- &pyobj_domain, &disk, &pyinfo, &flags))
- return(NULL);
+ &pyobj_domain, &disk, &info, &flags))
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+ 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;
- c_ret = virDomainGetBlockIoTune(domain, disk, NULL, &nparams, flags);
+ i_retval = virDomainGetBlockIoTune(domain, disk, NULL, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
- if (c_ret < 0)
+ if (i_retval < 0)
return VIR_PY_INT_FAIL;
+ if (nparams == 0) {
+ PyErr_Format(PyExc_LookupError,
+ "Domain has no settable attributes");
+ return NULL;
+ }
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_INT_FAIL;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
- c_ret = virDomainGetBlockIoTune(domain, disk, params, &nparams, flags);
+ i_retval = virDomainGetBlockIoTune(domain, disk, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
- if (c_ret < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ if (i_retval < 0) {
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
- /* convert to a Python tuple of long objects */
- for (i = 0; i < nparams; i++) {
- PyObject *key, *val;
- key = libvirt_constcharPtrWrap(params[i].field);
- val = PyDict_GetItem(pyinfo, key);
- Py_DECREF(key);
-
- if (val == NULL)
- continue;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- params[i].value.i = (int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- params[i].value.l = (long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- params[i].value.d = (double)PyFloat_AsDouble(val);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- {
- PyObject *hacktrue = PyBool_FromLong(1);
- params[i].value.b = hacktrue == val ? 1: 0;
- Py_DECREF(hacktrue);
- }
- break;
-
- default:
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
- }
- }
+ new_params = setPyVirTypedParameter(info, params, nparams);
+ if (!new_params)
+ goto cleanup;
LIBVIRT_BEGIN_ALLOW_THREADS;
- c_ret = virDomainSetBlockIoTune(domain, disk, params, nparams, flags);
+ i_retval = virDomainSetBlockIoTune(domain, disk, new_params, size, flags);
LIBVIRT_END_ALLOW_THREADS;
- if (c_ret < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ if (i_retval < 0) {
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
+ ret = VIR_PY_INT_SUCCESS;
+
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return VIR_PY_INT_SUCCESS;
+ VIR_FREE(new_params);
+ return ret;
}
static PyObject *
@@ -3744,81 +3471,47 @@ libvirt_virDomainGetBlockIoTune(PyObject *self ATTRIBUTE_UNUSED,
PyObject *args)
{
virDomainPtr domain;
- PyObject *pyobj_domain, *pyreply;
+ PyObject *pyobj_domain;
+ PyObject *ret = NULL;
+ int i_retval;
+ int nparams = 0;
const char *disk;
- int nparams = 0, i;
unsigned int flags;
virTypedParameterPtr params;
- int c_ret;
if (!PyArg_ParseTuple(args, (char *)"Ozi:virDomainGetBlockIoTune",
&pyobj_domain, &disk, &flags))
- return(NULL);
+ return NULL;
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
LIBVIRT_BEGIN_ALLOW_THREADS;
- c_ret = virDomainGetBlockIoTune(domain, disk, NULL, &nparams, flags);
+ i_retval = virDomainGetBlockIoTune(domain, disk, NULL, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
- if (c_ret < 0)
+ if (i_retval < 0)
return VIR_PY_NONE;
+ if (!nparams)
+ return PyDict_New();
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_NONE;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
- c_ret = virDomainGetBlockIoTune(domain, disk, params, &nparams, flags);
+ i_retval = virDomainGetBlockIoTune(domain, disk, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
- if (c_ret < 0) {
- VIR_FREE(params);
- return VIR_PY_NONE;
- }
-
- /* convert to a Python tuple of long objects */
- if ((pyreply = PyDict_New()) == NULL) {
- VIR_FREE(params);
- return VIR_PY_NONE;
+ if (i_retval < 0) {
+ ret = VIR_PY_NONE;
+ goto cleanup;
}
- for (i = 0 ; i < nparams ; i++) {
- PyObject *key, *val;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- val = PyInt_FromLong((long)params[i].value.i);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- val = PyInt_FromLong((long)params[i].value.ui);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- val = PyLong_FromLongLong((long long)params[i].value.l);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- val = PyLong_FromLongLong((unsigned long long)params[i].value.ul);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- val = PyFloat_FromDouble((double)params[i].value.d);
- break;
- case VIR_TYPED_PARAM_BOOLEAN:
- val = PyBool_FromLong((long)params[i].value.b);
- break;
-
- default:
- VIR_FREE(params);
- Py_DECREF(pyreply);
- return VIR_PY_NONE;
- }
+ ret = getPyVirTypedParameter(params, nparams);
- key = libvirt_constcharPtrWrap(params[i].field);
- PyDict_SetItem(pyreply, key, val);
- }
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return(pyreply);
+ return ret;
}
static PyObject *
--
1.7.7.5
12 years, 9 months
[libvirt] [PATCHv3] python: Fix problems of virDomain{Set, Get}BlkioParameters bindings
by ajia@redhat.com
From: Alex Jia <ajia(a)redhat.com>
The parameter 'device_weight' is a string, however, the 'VIR_TYPED_PARAM_STRING'
type condition is missed by libvirt_virDomain{Set, Get}BlkioParameters bindings,
the result is we can't get or change 'device_weight' value.
The latest python binding codes are refactored and added related 'VIR_TYPED_PARAM_STRING'
type argument process, the v3 patch follows latest codes change to resolve the above issue.
The v2 patch added missed 'VIR_TYPED_PARAM_STRING' condition into
libvirt_virDomain{Set, Get}BlkioParameters bindings and free allocated memory.
https://www.redhat.com/archives/libvir-list/2011-December/msg01122.html
RHBZ:https://bugzilla.redhat.com/show_bug.cgi?id=770795
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
python/libvirt-override.c | 142 +++++++++++++--------------------------------
1 files changed, 40 insertions(+), 102 deletions(-)
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index e7c2bd5..203ffa1 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -889,10 +889,11 @@ libvirt_virDomainSetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
PyObject *args) {
virDomainPtr domain;
PyObject *pyobj_domain, *info;
+ PyObject *ret = NULL;
int i_retval;
- int nparams = 0, i;
+ int nparams = 0, size = 0;
unsigned int flags;
- virTypedParameterPtr params;
+ virTypedParameterPtr params, new_params;
if (!PyArg_ParseTuple(args,
(char *)"OOi:virDomainSetBlkioParameters",
@@ -900,6 +901,9 @@ libvirt_virDomainSetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
return(NULL);
domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+ if ((size = PyDict_Size(info)) < 0)
+ return NULL;
+
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetBlkioParameters(domain, NULL, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
@@ -907,85 +911,54 @@ libvirt_virDomainSetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
if (i_retval < 0)
return VIR_PY_INT_FAIL;
+ if (size == 0) {
+ PyErr_Format(PyExc_LookupError,
+ "Domain has no settable attributes");
+ return NULL;
+ }
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_INT_FAIL;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetBlkioParameters(domain, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
- /* convert to a Python tuple of long objects */
- for (i = 0; i < nparams; i++) {
- PyObject *key, *val;
- key = libvirt_constcharPtrWrap(params[i].field);
- val = PyDict_GetItem(info, key);
- Py_DECREF(key);
-
- if (val == NULL)
- continue;
-
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- params[i].value.i = (int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- params[i].value.l = (long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- params[i].value.d = (double)PyFloat_AsDouble(val);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- {
- /* Hack - Python's definition of Py_True breaks strict
- * aliasing rules, so can't directly compare :-(
- */
- PyObject *hacktrue = PyBool_FromLong(1);
- params[i].value.b = hacktrue == val ? 1: 0;
- Py_DECREF(hacktrue);
- }
- break;
-
- default:
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
- }
- }
+ new_params = setPyVirTypedParameter(info, params, nparams);
+ if (!new_params)
+ goto cleanup;
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainSetBlkioParameters(domain, params, nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
+
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_INT_FAIL;
+ ret = VIR_PY_INT_FAIL;
+ goto cleanup;
}
+ ret = VIR_PY_INT_SUCCESS;
+
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return VIR_PY_INT_SUCCESS;
+ VIR_FREE(new_params);
+ return ret;
}
static PyObject *
libvirt_virDomainGetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
PyObject *args) {
virDomainPtr domain;
- PyObject *pyobj_domain, *info;
+ PyObject *pyobj_domain;
+ PyObject *ret = NULL;
int i_retval;
- int nparams = 0, i;
+ int nparams = 0;
unsigned int flags;
virTypedParameterPtr params;
@@ -1001,62 +974,27 @@ libvirt_virDomainGetBlkioParameters(PyObject *self ATTRIBUTE_UNUSED,
if (i_retval < 0)
return VIR_PY_NONE;
+ if (!nparams)
+ return PyDict_New();
+
if (VIR_ALLOC_N(params, nparams) < 0)
- return VIR_PY_NONE;
+ return PyErr_NoMemory();
LIBVIRT_BEGIN_ALLOW_THREADS;
i_retval = virDomainGetBlkioParameters(domain, params, &nparams, flags);
LIBVIRT_END_ALLOW_THREADS;
if (i_retval < 0) {
- VIR_FREE(params);
- return VIR_PY_NONE;
- }
-
- /* convert to a Python tuple of long objects */
- if ((info = PyDict_New()) == NULL) {
- VIR_FREE(params);
- return VIR_PY_NONE;
+ ret = VIR_PY_NONE;
+ goto cleanup;
}
- for (i = 0 ; i < nparams ; i++) {
- PyObject *key, *val;
- switch (params[i].type) {
- case VIR_TYPED_PARAM_INT:
- val = PyInt_FromLong((long)params[i].value.i);
- break;
-
- case VIR_TYPED_PARAM_UINT:
- val = PyInt_FromLong((long)params[i].value.ui);
- break;
-
- case VIR_TYPED_PARAM_LLONG:
- val = PyLong_FromLongLong((long long)params[i].value.l);
- break;
-
- case VIR_TYPED_PARAM_ULLONG:
- val = PyLong_FromLongLong((long long)params[i].value.ul);
- break;
-
- case VIR_TYPED_PARAM_DOUBLE:
- val = PyFloat_FromDouble((double)params[i].value.d);
- break;
-
- case VIR_TYPED_PARAM_BOOLEAN:
- val = PyBool_FromLong((long)params[i].value.b);
- break;
-
- default:
- VIR_FREE(params);
- Py_DECREF(info);
- return VIR_PY_NONE;
- }
+ ret = getPyVirTypedParameter(params, nparams);
- key = libvirt_constcharPtrWrap(params[i].field);
- PyDict_SetItem(info, key, val);
- }
+cleanup:
+ virTypedParameterArrayClear(params, nparams);
VIR_FREE(params);
- return(info);
+ return ret;
}
static PyObject *
--
1.7.1
12 years, 9 months
[libvirt] [PATCH libvirt 1/6] errcode is typedef by mingw, rename an argument name
by Marc-André Lureau
Fixes the following warning:
util/virterror.c:1242:31: warning: declaration of 'errcode' shadows a global declaration [-Wshadow]
---
src/util/virterror.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/util/virterror.c b/src/util/virterror.c
index ff44a57..85eec8d 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -1228,7 +1228,7 @@ virErrorMsg(virErrorNumber error, const char *info)
* virReportErrorHelper:
*
* @domcode: the virErrorDomain indicating where it's coming from
- * @errcode: the virErrorNumber code for the error
+ * @errorcode: the virErrorNumber code for the error
* @filename: Source file error is dispatched from
* @funcname: Function error is dispatched from
* @linenr: Line number error is dispatched from
@@ -1239,7 +1239,7 @@ virErrorMsg(virErrorNumber error, const char *info)
* ReportError
*/
void virReportErrorHelper(int domcode,
- int errcode,
+ int errorcode,
const char *filename,
const char *funcname,
size_t linenr,
@@ -1258,9 +1258,9 @@ void virReportErrorHelper(int domcode,
errorMessage[0] = '\0';
}
- virerr = virErrorMsg(errcode, (errorMessage[0] ? errorMessage : NULL));
+ virerr = virErrorMsg(errorcode, (errorMessage[0] ? errorMessage : NULL));
virRaiseErrorFull(filename, funcname, linenr,
- domcode, errcode, VIR_ERR_ERROR,
+ domcode, errorcode, VIR_ERR_ERROR,
virerr, errorMessage, NULL,
-1, -1, virerr, errorMessage);
errno = save_errno;
--
1.7.7.5
12 years, 9 months
[libvirt] RFC: PCI-Passthrough of SRIOV VF's new forward mode
by Shradha Shah
RFC: New network forward type pci-passthrough-hybrid
I saw a couple of posts regarding PCI-Passthrough usage of SRIOV VF's a couple
of weeks ago (20th Jan 2012). Initially I was going to post this RFC along with
a set of patches. I would require a few more days to clean my patches for
submission and hence I would start with an RFC on a new method to
manage PCI-Passthrough of SRIOV VF's.
I work for Solarflare Communications who make 10G network adapters. We
currently have SRIOV capable adapters available and in production and we would
like to work with upstream libvirt to develop the required support for our
hardware.
This RFC introduces a new network forward mode to libvirt called
pci-passthrough-hybrid and provides a solution for migration with
PCI-Passthrough as well as providing significant increase in the networking
performance.
The Solarflare SRIOV driver architecture for KVM is explained in the Release
notes which can be found here:
https://support.solarflare.com/index.php?view=categories&id=1813&option=c...
This is a working model and currently available to Solarflare Customers for
evaluation. The hybrid model of the SRIOV driver provided by Solarflare
currently achieves the highest SPECvirt performance in the market.
Solarflare Ethernet card supports 127 VF's on each port. The MAC address of
each unused VF is 00:00:00:00:00:00 by default. Hence the MAC address of the VF
does not change on every reboot. There is no VF driver on the host. Each VF
does not correspond to an Ethernet device. Instead, VF's are managed using the
PCI sysfs files.
With the pci-passthrough-hybrid model when the VF is passed into the guest,
it appears in the guest as a PCI device and not as a network device. A virtual
network device in the form of a virtio interface is also present
in the guest. The virtio device in the guest comes from either bridging the
physical network device or by creating a macvtap interface of type (vepa,
private, bridge) on the physical network device. The virtio device
and the VF bind together in the guest to create an accelerated and a
non-accelerated path.
The new method I wish to propose, uses implicit pci-passthrough and there is no
need to provide an explicit <hostdev> element in the domain xml. The hostdev
would be added to the live xml as non-persistent as suggested by Laine Stump in
a previous post, link to which can be found at:
https://www.redhat.com/archives/libvir-list/2011-August/msg00937.html
1) In order to support the above mentioned hybrid model, the requirement is
that the VF needs to be assigned the same MAC address as the virtio device in
the guest. This enables the VF and the virtio device to bind successfully using
the Solarflare driver called XNAP.
Effectively we do not need to extend the <hostdev> schema. This can be taken care
of by the <interface> element. Along with the MAC address the VLAN tags can also
be taken care of by the <interface>/<network> elements.
2) The VF appears in the guest as a PCI device hence the MAC address of the VF
is stored in the sysfs files. Assigning the MAC address to the VF before or
after pci passthough is not an issue.
Proposed steps to support the hybrid model of pci-passthrough in libvirt:
1) <network> will have a new forward type='pci-passthroug-hybrid'. When forward
type='pci-passthrough-hybrid' instead of a pool of Ethernet interfaces a <pf>
element will need to be specified for implicit VF allocation as shown in the
example below:
<network>
<name>direct-network</name>
<forward mode="pci-passthrough-hybrid">
<pf dev="eth2"/>
</forward>
</network>
2) In the domain's <interface> definition, when type='network' and if network
has forward type='pci-passthrough-hybrid', the domain code will request an
unused VF from the physical device. Example:
<interface type='network'>
<source network='direct-network'/>
<mac address='00:50:56:0f:86:3b'/>
<model type='virtio'/>
<actual type='direct'>
<source mode='pci-passthrough-hybrid'/>
</actual>
</interface>
3) The code will then use the NodeDevice API to learn all the necessary PCI
domain/slot/bus/function information.
4) Before starting the guest the VF's PCI device name (0000:04:00.2) will be
saved in interface/actual so that it can be easily retrieved if libvirtd is
restarted.
5) While building the qemu command line, if a network device has forward
mode='pci-passthrough-hybrid', the code will add a (non-persisting) <hostdev>
element to the qemu command line. This <hostdev> will be marked as ephemeral
before passing it to the guest. Ephemeral=transient.
6) During the process of network connection the MAC address of the VF will be
set according to the domain <interface> config. This step can also involve
setting the VLAN tag, port profiles, etc.
7) Follwoing the above steps the guest will then start with implicit
PCI-Passthough of a SRIOV VF.
8) When the guest is eventually destroyed, the Ethernet device will be free'd
back to the network pool for use by another guest. Since the MAC address needs
to be reset to 00:00:00:00:00:00 we do not need any reference to the higher
level device definition.
Since the VF is transient, it will be removed when the guest is shutdown and
hotplugged again, by the libvirt API, when the guest is started. Hence, in
order to get a list of hostdevs attached to a guest we only ever have to look
at the <hostdev> element.
One of the objections that had been raised following Mr Stump's post was that a
transient hostdev will not ensure that the guest PCI address does not get
changed each time the guest is run, but since the VF is a pci device in the
guest and does not bind to specific driver, we can work with this proposed
solution.
Migration is possible using the above method without any explicit effort from
the user in the following way:
1) Begin stage: All the ephemeral devices do not make their way into the xml
that is passed to the destination.
2) Prepare stage: Replacement VF's on the destination, if present, will be
automatically reserved and plugged in the guest by the networking code.
3) Perform stage: Any ephemeral device are removed from the guest by libvirt.
4) Confirm stage: If migration fails the VF's will be restored else the VF's
will be free's back to the networking pool by the networking code.
I have been working on the patches for the above mentioned method and would
like to know your take on the hybrid model.
12 years, 9 months
[libvirt] [PATCH 0/3] Introduce virDomainPMWakeup API
by Michal Privoznik
This is counterpart for virDomainPMSuspendForDuration API which
we have already in. It allows user to wake up guest from S3 state.
Michal Privoznik (3):
Introduce virDomainPMWakeup API
virsh: Expose virDomainPMWakeup
qemu: Implement virDomainPMWakeup API
include/libvirt/libvirt.h.in | 2 +
src/driver.h | 4 +++
src/libvirt.c | 50 ++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 1 +
src/qemu/qemu_driver.c | 54 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor.c | 20 +++++++++++++++
src/qemu/qemu_monitor.h | 2 +
src/qemu/qemu_monitor_json.c | 21 ++++++++++++++++
src/qemu/qemu_monitor_json.h | 2 +
src/qemu/qemu_monitor_text.c | 26 ++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 2 +
src/remote/remote_driver.c | 1 +
src/remote/remote_protocol.x | 8 +++++-
src/remote_protocol-structs | 5 ++++
tools/virsh.c | 46 +++++++++++++++++++++++++++++++++++
15 files changed, 243 insertions(+), 1 deletions(-)
--
1.7.3.4
12 years, 9 months
[libvirt] [PATCH v5] npiv: Auto-generate WWN if it's not specified
by Osier Yang
The auto-generated WWN comply with the new addressing schema of WWN:
<quote>
the first nibble is either hex 5 or 6 followed by a 3-byte vendor
identifier and 36 bits for a vendor-specified serial number.
</quote>
We choose hex 5 for the first nibble. And use Qumranet's OUI
(00:1A:4A) as the 3-byte vendor indentifier. The last 36 bits
are auto-generated.
---
src/conf/node_device_conf.c | 36 +++++++++++++++++++-----------------
src/libvirt_private.syms | 1 +
src/util/virrandom.c | 18 ++++++++++++++++++
src/util/virrandom.h | 1 +
4 files changed, 39 insertions(+), 17 deletions(-)
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index d9dc9ac..127a4ae 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -37,6 +37,7 @@
#include "buf.h"
#include "uuid.h"
#include "pci.h"
+#include "virrandom.h"
#define VIR_FROM_THIS VIR_FROM_NODEDEV
@@ -63,19 +64,12 @@ VIR_ENUM_IMPL(virNodeDevHBACap, VIR_NODE_DEV_CAP_HBA_LAST,
static int
virNodeDevCapsDefParseString(const char *xpath,
xmlXPathContextPtr ctxt,
- char **string,
- virNodeDeviceDefPtr def,
- const char *missing_error_fmt)
+ char **string)
{
char *s;
- s = virXPathString(xpath, ctxt);
- if (s == NULL) {
- virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR,
- missing_error_fmt,
- def->name);
+ if (!(s = virXPathString(xpath, ctxt)))
return -1;
- }
*string = s;
return 0;
@@ -763,18 +757,26 @@ virNodeDevCapScsiHostParseXML(xmlXPathContextPtr ctxt,
if (virNodeDevCapsDefParseString("string(./wwnn[1])",
ctxt,
- &data->scsi_host.wwnn,
- def,
- _("no WWNN supplied for '%s'")) < 0) {
- goto out;
+ &data->scsi_host.wwnn) < 0) {
+ if (virRandomGenerateWWN(&data->scsi_host.wwnn) < 0) {
+ virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no WWNN supplied for '%s', and "
+ "auto-generation failed"),
+ def->name);
+ goto out;
+ }
}
if (virNodeDevCapsDefParseString("string(./wwpn[1])",
ctxt,
- &data->scsi_host.wwpn,
- def,
- _("no WWPN supplied for '%s'")) < 0) {
- goto out;
+ &data->scsi_host.wwpn) < 0) {
+ if (virRandomGenerateWWN(&data->scsi_host.wwpn) < 0) {
+ virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no WWPN supplied for '%s', and "
+ "auto-generation failed"),
+ def->name);
+ goto out;
+ }
}
ctxt->node = orignode2;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d6ad36c..421986b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1373,6 +1373,7 @@ virPidFileDeletePath;
# virrandom.h
virRandomBits;
+virRandomGenerateWWN;
virRandomInitialize;
diff --git a/src/util/virrandom.c b/src/util/virrandom.c
index ec0cf03..3116275 100644
--- a/src/util/virrandom.c
+++ b/src/util/virrandom.c
@@ -22,10 +22,15 @@
#include <config.h>
#include <stdlib.h>
+#include <inttypes.h>
#include "virrandom.h"
#include "threads.h"
#include "count-one-bits.h"
+#include "util.h"
+#include "virterror_internal.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
static char randomState[128];
static struct random_data randomData;
@@ -79,3 +84,16 @@ uint64_t virRandomBits(int nbits)
virMutexUnlock(&randomLock);
return ret;
}
+
+#define QUMRANET_OUI "001a4a"
+
+int
+virRandomGenerateWWN(char **wwn) {
+ if (virAsprintf(wwn, "5" QUMRANET_OUI "%09" PRIx64,
+ virRandomBits(36)) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/util/virrandom.h b/src/util/virrandom.h
index e180a2f..443451e 100644
--- a/src/util/virrandom.h
+++ b/src/util/virrandom.h
@@ -27,5 +27,6 @@
int virRandomInitialize(uint32_t seed) ATTRIBUTE_RETURN_CHECK;
uint64_t virRandomBits(int nbits);
+int virRandomGenerateWWN(char **wwn);
#endif /* __VIR_RANDOM_H__ */
--
1.7.7.3
12 years, 9 months