diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index d9b9b95f161f4c193f939c4c6daece11f01fb41e..cf53cf260d3d8b6b843724f63b002fdbd9e21ff1 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 6f813ae0dba740f79fe9b05330e26df70e7c6a88..b514af5bc2ec7333f475fd3b47782b6613975145 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 2e2042e3b7218f3509eebeeb14fa1571c11f1ea1..9ff5edf18fc076b962bec61fb94d5e9118f1df4f 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 f412a823cd5a2255c99450c5fa04c73a8e355299..fc41a3fad2ac103acfbae9066d54db0ef09b6f29 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 1c4e0a3aa7812bb9b04957f17c2a1b7ec1dcbc43..ced9fb3969ffac7e302522e39a94a3fd3b70c361 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;