We already provide ways to detect when a domain has been paused as a
result of I/O error, but there was no way of getting the exact error or
even the device that experienced it. This new API may be used for both.
---
include/libvirt/libvirt.h.in | 32 ++++++++++++++++++++
python/generator.py | 3 +-
src/driver.h | 7 ++++
src/libvirt.c | 65 ++++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 1 +
5 files changed, 107 insertions(+), 1 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index d9b9b95..cf53cf2 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1967,6 +1967,38 @@ virDomainGetBlockIoTune(virDomainPtr dom,
int *nparams,
unsigned int flags);
+/**
+ * virDomainDiskErrorCode:
+ *
+ * Disk I/O error.
+ */
+typedef enum {
+ VIR_DOMAIN_DISK_ERROR_NONE = 0, /* no error */
+ VIR_DOMAIN_DISK_ERROR_UNSPEC = 1, /* unspecified I/O error */
+ VIR_DOMAIN_DISK_ERROR_NO_SPACE = 2, /* no space left on the device */
+
+#ifdef VIR_ENUM_SENTINELS
+ VIR_DOMAIN_DISK_ERROR_LAST
+#endif
+} virDomainDiskErrorCode;
+
+/**
+ * virDomainDiskError:
+ *
+ */
+typedef struct _virDomainDiskError virDomainDiskError;
+typedef virDomainDiskError *virDomainDiskErrorPtr;
+
+struct _virDomainDiskError {
+ char *disk; /* disk target */
+ int error; /* virDomainDiskErrorCode */
+};
+
+int virDomainGetDiskErrors(virDomainPtr dom,
+ virDomainDiskErrorPtr errors,
+ unsigned int maxerrors,
+ unsigned int flags);
+
/*
* NUMA support
diff --git a/python/generator.py b/python/generator.py
index 6f813ae..b514af5 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -423,7 +423,8 @@ skip_impl = (
'virDomainGetBlockIoTune',
'virDomainSetInterfaceParameters',
'virDomainGetInterfaceParameters',
- 'virDomainGetCPUStats' # not implemented now.
+ 'virDomainGetCPUStats', # not implemented now.
+ 'virDomainGetDiskErrors',
)
qemu_skip_impl = (
diff --git a/src/driver.h b/src/driver.h
index 2e2042e..9ff5edf 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -810,6 +810,12 @@ typedef int
unsigned int ncpus,
unsigned int flags);
+typedef int
+ (*virDrvDomainGetDiskErrors)(virDomainPtr dom,
+ virDomainDiskErrorPtr errors,
+ unsigned int maxerrors,
+ unsigned int flags);
+
/**
* _virDriver:
*
@@ -981,6 +987,7 @@ struct _virDriver {
virDrvDomainSetBlockIoTune domainSetBlockIoTune;
virDrvDomainGetBlockIoTune domainGetBlockIoTune;
virDrvDomainGetCPUStats domainGetCPUStats;
+ virDrvDomainGetDiskErrors domainGetDiskErrors;
};
typedef int
diff --git a/src/libvirt.c b/src/libvirt.c
index c609202..e84447e 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -18282,3 +18282,68 @@ error:
virDispatchError(domain->conn);
return -1;
}
+
+/**
+ * virDomainGetDiskErrors:
+ * @dom: a domain object
+ * @errors: array to populate on output
+ * @maxerrors: size of @errors array
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * The function populates @errors array with all disks that encountered an
+ * I/O error. Disks with no error will not be returned in the @errors array.
+ * Each disk is identified by its target (the dev attribute of target
+ * subelement in domain XML), such as "vda", and accompanied with the error
+ * that was seen on it. The caller is also responsible for calling free()
+ * on each disk name returned.
+ *
+ * In a special case when @errors is NULL and @maxerrors is 0, the function
+ * returns preferred size of @errors that the caller should use to get all
+ * disk errors.
+ *
+ * Since calling virDomainGetDiskErrors(dom, NULL, 0, 0) to get preferred size
+ * of @errors array and getting the errors are two separate operations, new
+ * disks may be hotplugged to the domain and new errors may be encountered
+ * between the two calls. Thus, this function may not return all disk errors
+ * because the supplied array is not large enough. Such errors may, however,
+ * be detected by listening to domain events.
+ *
+ * Returns number of disks with errors filled in the @errors array or -1 on
+ * error.
+ */
+int
+virDomainGetDiskErrors(virDomainPtr dom,
+ virDomainDiskErrorPtr errors,
+ unsigned int maxerrors,
+ unsigned int flags)
+{
+ VIR_DOMAIN_DEBUG(dom, "errors=%p, maxerrors=%u, flags=%x",
+ errors, maxerrors, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_DOMAIN(dom)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ if ((!errors && maxerrors) || (errors && !maxerrors)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ goto error;
+ }
+
+ if (dom->conn->driver->domainGetDiskErrors) {
+ int ret = dom->conn->driver->domainGetDiskErrors(dom, errors,
+ maxerrors, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(dom->conn);
+ return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 1c4e0a3..ced9fb3 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -519,6 +519,7 @@ LIBVIRT_0.9.9 {
LIBVIRT_0.9.10 {
global:
virDomainGetCPUStats;
+ virDomainGetDiskErrors;
virDomainPMSuspendForDuration;
virDomainShutdownFlags;
virStorageVolResize;
--
1.7.8.4