[PATCH v2 12/15] virDomainGetMessages: Introduce VIR_DOMAIN_MESSAGE_IOERRORS

Peter Krempa posted 15 patches 7 months, 1 week ago
[PATCH v2 12/15] virDomainGetMessages: Introduce VIR_DOMAIN_MESSAGE_IOERRORS
Posted by Peter Krempa 7 months, 1 week ago
Report any stored I/O error messages reported by the hypervisor when
reporting messages of a domain. As the I/O error may be already stale we
report also the timestamp when it was recorded.

Example message:

 I/O error: disk='vda', index='1', path='/dev/mapper/errdev0', timestamp='2025-01-28 15:47:52.776+0000', message'Input/output error'

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
 include/libvirt/libvirt-domain.h |  3 ++
 src/conf/domain_conf.c           | 50 ++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h           |  5 ++++
 src/libvirt_private.syms         |  1 +
 src/libxl/libxl_driver.c         |  3 +-
 src/qemu/qemu_driver.c           | 15 +++++++++-
 src/test/test_driver.c           |  3 +-
 7 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 74016c6c46..9e9016cfe7 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -6520,6 +6520,9 @@ int virDomainAuthorizedSSHKeysSet(virDomainPtr domain,
 typedef enum {
     VIR_DOMAIN_MESSAGE_DEPRECATION = (1 << 0), /* (Since: 7.1.0) */
     VIR_DOMAIN_MESSAGE_TAINTING = (1 << 1), /* (Since: 7.1.0) */
+    VIR_DOMAIN_MESSAGE_IOERRORS = (1 << 2), /* Report available stored I/O
+                                               errors messages for disk images
+                                               (Since: 11.1.0) */
 } virDomainMessageType;

 int virDomainGetMessages(virDomainPtr domain,
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 00d486e774..548bc82308 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -31682,6 +31682,47 @@ virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev)
 }


+static void
+virDomainObjGetMessagesIOErrorsSrc(virStorageSource *src,
+                                   const char *diskdst,
+                                   GPtrArray *m)
+{
+    if (!src ||
+        !src->ioerror_message)
+        return;
+
+    g_ptr_array_add(m, g_strdup_printf(_("I/O error: disk='%1$s', index='%2$d', path='%3$s', timestamp='%4$s', message'%5$s'"),
+                                       NULLSTR_MINUS(diskdst),
+                                       src->id,
+                                       NULLSTR_MINUS(src->path),
+                                       src->ioerror_timestamp,
+                                       src->ioerror_message));
+}
+
+
+void
+virDomainObjGetMessagesIOErrorsChain(virStorageSource *src,
+                                     const char *diskdst,
+                                     GPtrArray *m)
+{
+    virStorageSource *n;
+
+    for (n = src; n; n = n->backingStore) {
+        virDomainObjGetMessagesIOErrorsSrc(n, diskdst, m);
+        virDomainObjGetMessagesIOErrorsSrc(n->dataFileStore, diskdst, m);
+    }
+}
+
+
+static void
+virDomainObjGetMessagesIOErrorsDisk(virDomainDiskDef *disk,
+                                    GPtrArray *m)
+{
+    virDomainObjGetMessagesIOErrorsChain(disk->src, disk->dst, m);
+    virDomainObjGetMessagesIOErrorsChain(disk->mirror, disk->dst, m);
+}
+
+
 /**
  * virDomainObjGetMessages:
  * @vm: domain object
@@ -31710,6 +31751,15 @@ virDomainObjGetMessages(virDomainObj *vm,
                                                vm->deprecations[i]));
         }
     }
+
+    if (!flags || (flags & VIR_DOMAIN_MESSAGE_IOERRORS)) {
+        if (vm->def->os.loader)
+            virDomainObjGetMessagesIOErrorsChain(vm->def->os.loader->nvram, NULL, m);
+
+        for (i = 0; i < vm->def->ndisks; i++)
+            virDomainObjGetMessagesIOErrorsDisk(vm->def->disks[i], m);
+    }
+
 }

 bool
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index e996d3c0de..e51c74b6d1 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -4588,6 +4588,11 @@ bool
 virHostdevIsPCIDevice(const virDomainHostdevDef *hostdev)
     ATTRIBUTE_NONNULL(1);

+void
+virDomainObjGetMessagesIOErrorsChain(virStorageSource *src,
+                                     const char *diskdst,
+                                     GPtrArray *m);
+
 void
 virDomainObjGetMessages(virDomainObj *vm,
                         GPtrArray *m,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 2fe0a07944..406e6583a3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -592,6 +592,7 @@ virDomainObjEndAPI;
 virDomainObjFormat;
 virDomainObjGetDefs;
 virDomainObjGetMessages;
+virDomainObjGetMessagesIOErrorsChain;
 virDomainObjGetMetadata;
 virDomainObjGetOneDef;
 virDomainObjGetOneDefState;
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 426c2b4278..a76545c9ff 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -6580,7 +6580,8 @@ libxlDomainGetMessages(virDomainPtr dom,
     int ret = -1;

     virCheckFlags(VIR_DOMAIN_MESSAGE_DEPRECATION |
-                  VIR_DOMAIN_MESSAGE_TAINTING, -1);
+                  VIR_DOMAIN_MESSAGE_TAINTING |
+                  VIR_DOMAIN_MESSAGE_IOERRORS, -1);

     if (!(vm = libxlDomObjFromDomain(dom)))
         return -1;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 8327e7079c..50733a5b3a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -19821,9 +19821,11 @@ qemuDomainGetMessages(virDomainPtr dom,
     g_autoptr(GPtrArray) m = g_ptr_array_new_with_free_func(g_free);
     virDomainObj *vm = NULL;
     int rv = -1;
+    qemuDomainObjPrivate *priv;

     virCheckFlags(VIR_DOMAIN_MESSAGE_DEPRECATION |
-                  VIR_DOMAIN_MESSAGE_TAINTING, -1);
+                  VIR_DOMAIN_MESSAGE_TAINTING |
+                  VIR_DOMAIN_MESSAGE_IOERRORS, -1);

     if (!(vm = qemuDomainObjFromDomain(dom)))
         return -1;
@@ -19831,8 +19833,19 @@ qemuDomainGetMessages(virDomainPtr dom,
     if (virDomainGetMessagesEnsureACL(dom->conn, vm->def) < 0)
         goto cleanup;

+    priv = vm->privateData;
+
     virDomainObjGetMessages(vm, m, flags);

+    if (priv->backup) {
+        size_t i;
+
+        for (i = 0; i < priv->backup->ndisks; i++)
+            virDomainObjGetMessagesIOErrorsChain(priv->backup->disks[i].store,
+                                                 priv->backup->disks[i].name,
+                                                 m);
+    }
+
     rv = m->len;
     if (m->len > 0) {
         g_ptr_array_add(m, NULL);
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index a10ec3bc41..6f18b2b2c8 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -9527,7 +9527,8 @@ testDomainGetMessages(virDomainPtr dom,
     int rv = -1;

     virCheckFlags(VIR_DOMAIN_MESSAGE_DEPRECATION |
-                  VIR_DOMAIN_MESSAGE_TAINTING, -1);
+                  VIR_DOMAIN_MESSAGE_TAINTING |
+                  VIR_DOMAIN_MESSAGE_IOERRORS, -1);

     if (!(vm = testDomObjFromDomain(dom)))
         return -1;
-- 
2.48.1
Re: [PATCH v2 12/15] virDomainGetMessages: Introduce VIR_DOMAIN_MESSAGE_IOERRORS
Posted by Daniel P. Berrangé 7 months, 1 week ago
On Tue, Jan 28, 2025 at 05:28:16PM +0100, Peter Krempa wrote:
> Report any stored I/O error messages reported by the hypervisor when
> reporting messages of a domain. As the I/O error may be already stale we
> report also the timestamp when it was recorded.
> 
> Example message:
> 
>  I/O error: disk='vda', index='1', path='/dev/mapper/errdev0', timestamp='2025-01-28 15:47:52.776+0000', message'Input/output error'
> 
> Signed-off-by: Peter Krempa <pkrempa@redhat.com>
> ---
>  include/libvirt/libvirt-domain.h |  3 ++
>  src/conf/domain_conf.c           | 50 ++++++++++++++++++++++++++++++++
>  src/conf/domain_conf.h           |  5 ++++
>  src/libvirt_private.syms         |  1 +
>  src/libxl/libxl_driver.c         |  3 +-
>  src/qemu/qemu_driver.c           | 15 +++++++++-
>  src/test/test_driver.c           |  3 +-
>  7 files changed, 77 insertions(+), 3 deletions(-)
> 

> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 8327e7079c..50733a5b3a 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -19821,9 +19821,11 @@ qemuDomainGetMessages(virDomainPtr dom,
>      g_autoptr(GPtrArray) m = g_ptr_array_new_with_free_func(g_free);
>      virDomainObj *vm = NULL;
>      int rv = -1;
> +    qemuDomainObjPrivate *priv;
> 
>      virCheckFlags(VIR_DOMAIN_MESSAGE_DEPRECATION |
> -                  VIR_DOMAIN_MESSAGE_TAINTING, -1);
> +                  VIR_DOMAIN_MESSAGE_TAINTING |
> +                  VIR_DOMAIN_MESSAGE_IOERRORS, -1);
> 
>      if (!(vm = qemuDomainObjFromDomain(dom)))
>          return -1;
> @@ -19831,8 +19833,19 @@ qemuDomainGetMessages(virDomainPtr dom,
>      if (virDomainGetMessagesEnsureACL(dom->conn, vm->def) < 0)
>          goto cleanup;
> 
> +    priv = vm->privateData;
> +
>      virDomainObjGetMessages(vm, m, flags);
> 
> +    if (priv->backup) {

 &&  (!flags || (flags & VIR_DOMAIN_MESSAGE_IOERRORS))

with that

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>


> +        size_t i;
> +
> +        for (i = 0; i < priv->backup->ndisks; i++)
> +            virDomainObjGetMessagesIOErrorsChain(priv->backup->disks[i].store,
> +                                                 priv->backup->disks[i].name,
> +                                                 m);
> +    }


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [PATCH v2 12/15] virDomainGetMessages: Introduce VIR_DOMAIN_MESSAGE_IOERRORS
Posted by Peter Krempa 7 months, 1 week ago
On Tue, Jan 28, 2025 at 17:28:16 +0100, Peter Krempa wrote:
> Report any stored I/O error messages reported by the hypervisor when
> reporting messages of a domain. As the I/O error may be already stale we
> report also the timestamp when it was recorded.
> 
> Example message:
> 
>  I/O error: disk='vda', index='1', path='/dev/mapper/errdev0', timestamp='2025-01-28 15:47:52.776+0000', message'Input/output error'

Missing = after 'message'

> 
> Signed-off-by: Peter Krempa <pkrempa@redhat.com>
> ---



> +static void
> +virDomainObjGetMessagesIOErrorsSrc(virStorageSource *src,
> +                                   const char *diskdst,
> +                                   GPtrArray *m)
> +{
> +    if (!src ||
> +        !src->ioerror_message)
> +        return;
> +
> +    g_ptr_array_add(m, g_strdup_printf(_("I/O error: disk='%1$s', index='%2$d', path='%3$s', timestamp='%4$s', message'%5$s'"),

here.

> +                                       NULLSTR_MINUS(diskdst),
> +                                       src->id,
> +                                       NULLSTR_MINUS(src->path),
> +                                       src->ioerror_timestamp,
> +                                       src->ioerror_message));
> +}