[PATCH 07/10] use qemu_set_blocking instead of g_unix_set_fd_nonblocking

Vladimir Sementsov-Ogievskiy posted 10 patches 5 months, 1 week ago
Maintainers: "Marc-André Lureau" <marcandre.lureau@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, "Michael S. Tsirkin" <mst@redhat.com>, Gerd Hoffmann <kraxel@redhat.com>, Gustavo Romero <gustavo.romero@linaro.org>, Elena Ufimtseva <elena.ufimtseva@oracle.com>, Jagannathan Raman <jag.raman@oracle.com>, John Levon <john.levon@nutanix.com>, Thanos Makatos <thanos.makatos@nutanix.com>, "Cédric Le Goater" <clg@redhat.com>, Stefano Garzarella <sgarzare@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Peter Xu <peterx@redhat.com>, Fabiano Rosas <farosas@suse.de>, Jason Wang <jasowang@redhat.com>, Michael Roth <michael.roth@amd.com>, Kostiantyn Kostiuk <kkostiuk@redhat.com>, Fam Zheng <fam@euphon.net>, Alexander Bulekov <alxndr@bu.edu>, Bandan Das <bsd@redhat.com>, Stefan Hajnoczi <stefanha@redhat.com>, Darren Kenny <darren.kenny@oracle.com>, Qiuhao Li <Qiuhao.Li@outlook.com>, Laurent Vivier <lvivier@redhat.com>, Stefan Berger <stefanb@linux.vnet.ibm.com>, Stefan Weil <sw@weilnetz.de>, Coiby Xu <Coiby.Xu@gmail.com>
There is a newer version of this series
[PATCH 07/10] use qemu_set_blocking instead of g_unix_set_fd_nonblocking
Posted by Vladimir Sementsov-Ogievskiy 5 months, 1 week ago
Instead of open-coded g_unix_set_fd_nonblocking() calls, use
QEMU wrapper qemu_socket_set_nonblock().

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 chardev/char-fd.c                  |  4 ++--
 chardev/char-pty.c                 |  3 +--
 chardev/char-serial.c              |  3 +--
 chardev/char-stdio.c               |  3 +--
 hw/input/virtio-input-host.c       |  3 +--
 hw/misc/ivshmem-flat.c             |  4 +++-
 hw/misc/ivshmem-pci.c              |  8 +++++++-
 hw/virtio/vhost-vsock.c            |  8 ++------
 io/channel-command.c               |  9 ++++++---
 io/channel-file.c                  |  3 +--
 net/tap-bsd.c                      | 12 ++++++++++--
 net/tap-linux.c                    |  8 +++++++-
 net/tap-solaris.c                  |  7 ++++++-
 net/tap.c                          | 21 ++++++---------------
 qga/commands-posix.c               |  3 +--
 tests/qtest/fuzz/virtio_net_fuzz.c |  2 +-
 tests/qtest/vhost-user-test.c      |  3 +--
 tests/unit/test-iov.c              |  5 +++--
 ui/input-linux.c                   |  3 +--
 util/event_notifier-posix.c        |  5 +++--
 util/main-loop.c                   |  6 +++++-
 21 files changed, 69 insertions(+), 54 deletions(-)

diff --git a/chardev/char-fd.c b/chardev/char-fd.c
index 6f03adf872..739dc68c36 100644
--- a/chardev/char-fd.c
+++ b/chardev/char-fd.c
@@ -212,8 +212,8 @@ void qemu_chr_open_fd(Chardev *chr,
     FDChardev *s = FD_CHARDEV(chr);
     g_autofree char *name = NULL;
 
-    if (fd_out >= 0 && !g_unix_set_fd_nonblocking(fd_out, true, NULL)) {
-        assert(!"Failed to set FD nonblocking");
+    if (fd_out >= 0) {
+        qemu_set_blocking(fd_out, false, &error_abort);
     }
 
     if (fd_out == fd_in && fd_in >= 0) {
diff --git a/chardev/char-pty.c b/chardev/char-pty.c
index 674e9b3f14..fe6bfb043d 100644
--- a/chardev/char-pty.c
+++ b/chardev/char-pty.c
@@ -349,8 +349,7 @@ static void char_pty_open(Chardev *chr,
     }
 
     close(slave_fd);
-    if (!g_unix_set_fd_nonblocking(master_fd, true, NULL)) {
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+    if (!qemu_set_blocking(master_fd, false, errp)) {
         return;
     }
 
diff --git a/chardev/char-serial.c b/chardev/char-serial.c
index 0a68b4b4e0..1ff31dcde3 100644
--- a/chardev/char-serial.c
+++ b/chardev/char-serial.c
@@ -271,8 +271,7 @@ static void qmp_chardev_open_serial(Chardev *chr,
     if (fd < 0) {
         return;
     }
-    if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+    if (!qemu_set_blocking(fd, false, errp)) {
         return;
     }
     tty_serial_init(fd, 115200, 'N', 8, 1);
diff --git a/chardev/char-stdio.c b/chardev/char-stdio.c
index 48db8d2f30..193727e807 100644
--- a/chardev/char-stdio.c
+++ b/chardev/char-stdio.c
@@ -107,8 +107,7 @@ static void qemu_chr_open_stdio(Chardev *chr,
     old_fd0_flags = fcntl(0, F_GETFL);
     old_fd1_flags = fcntl(1, F_GETFL);
     tcgetattr(0, &oldtty);
-    if (!g_unix_set_fd_nonblocking(0, true, NULL)) {
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+    if (!qemu_set_blocking(0, false, errp)) {
         return;
     }
     atexit(term_exit);
diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c
index bbfee9d3b9..9f62532559 100644
--- a/hw/input/virtio-input-host.c
+++ b/hw/input/virtio-input-host.c
@@ -114,8 +114,7 @@ static void virtio_input_host_realize(DeviceState *dev, Error **errp)
         error_setg_file_open(errp, errno, vih->evdev);
         return;
     }
-    if (!g_unix_set_fd_nonblocking(vih->fd, true, NULL)) {
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+    if (!qemu_set_blocking(vih->fd, false, errp)) {
         goto err_close;
     }
 
diff --git a/hw/misc/ivshmem-flat.c b/hw/misc/ivshmem-flat.c
index fe4be6be17..29f298bbcb 100644
--- a/hw/misc/ivshmem-flat.c
+++ b/hw/misc/ivshmem-flat.c
@@ -12,6 +12,7 @@
 #include "qemu/units.h"
 #include "qemu/error-report.h"
 #include "qemu/module.h"
+#include "qemu/sockets.h"
 #include "qapi/error.h"
 #include "hw/irq.h"
 #include "hw/qdev-properties-system.h"
@@ -154,7 +155,8 @@ static void ivshmem_flat_add_vector(IvshmemFTState *s, IvshmemPeer *peer,
      * peer.
      */
     peer->vector[peer->vector_counter].id = peer->vector_counter;
-    g_unix_set_fd_nonblocking(vector_fd, true, NULL);
+    /* WARNING: qemu_socket_set_nonblock() return code ignored */
+    qemu_set_blocking(vector_fd, false, NULL);
     event_notifier_init_fd(&peer->vector[peer->vector_counter].event_notifier,
                            vector_fd);
 
diff --git a/hw/misc/ivshmem-pci.c b/hw/misc/ivshmem-pci.c
index d47ae739d6..b7da89fe3a 100644
--- a/hw/misc/ivshmem-pci.c
+++ b/hw/misc/ivshmem-pci.c
@@ -21,6 +21,7 @@
 #include "qemu/units.h"
 #include "qapi/error.h"
 #include "qemu/cutils.h"
+#include "qemu/sockets.h"
 #include "hw/pci/pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/qdev-properties-system.h"
@@ -540,7 +541,12 @@ static void process_msg_connect(IVShmemState *s, uint16_t posn, int fd,
 
     IVSHMEM_DPRINTF("eventfds[%d][%d] = %d\n", posn, vector, fd);
     event_notifier_init_fd(&peer->eventfds[vector], fd);
-    g_unix_set_fd_nonblocking(fd, true, NULL); /* msix/irqfd poll non block */
+
+    /* msix/irqfd poll non block */
+    if (!qemu_set_blocking(fd, false, errp)) {
+        close(fd);
+        return;
+    }
 
     if (posn == s->vm_id) {
         setup_interrupt(s, vector, errp);
diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c
index 6e4088831f..107d88babe 100644
--- a/hw/virtio/vhost-vsock.c
+++ b/hw/virtio/vhost-vsock.c
@@ -147,9 +147,7 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
             return;
         }
 
-        if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
-            error_setg_errno(errp, errno,
-                             "vhost-vsock: unable to set non-blocking mode");
+        if (!qemu_set_blocking(vhostfd, false, errp)) {
             return;
         }
     } else {
@@ -160,9 +158,7 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
             return;
         }
 
-        if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
-            error_setg_errno(errp, errno,
-                             "Failed to set FD nonblocking");
+        if (!qemu_set_blocking(vhostfd, false, errp)) {
             return;
         }
     }
diff --git a/io/channel-command.c b/io/channel-command.c
index 8966dd3a2b..8ae9a026b3 100644
--- a/io/channel-command.c
+++ b/io/channel-command.c
@@ -277,9 +277,12 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
     cioc->blocking = enabled;
 #else
 
-    if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
-        (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+    if (cioc->writefd >= 0 &&
+        !qemu_set_blocking(cioc->writefd, enabled, errp)) {
+        return -1;
+    }
+    if (cioc->readfd >= 0 &&
+        !qemu_set_blocking(cioc->readfd, enabled, errp)) {
         return -1;
     }
 #endif
diff --git a/io/channel-file.c b/io/channel-file.c
index ca3f180cc2..5cef75a67c 100644
--- a/io/channel-file.c
+++ b/io/channel-file.c
@@ -223,8 +223,7 @@ static int qio_channel_file_set_blocking(QIOChannel *ioc,
 #else
     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
 
-    if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+    if (!qemu_set_blocking(fioc->fd, enabled, errp)) {
         return -1;
     }
     return 0;
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index b4c84441ba..2e444e59b5 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -98,7 +98,12 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
             return -1;
         }
     }
-    g_unix_set_fd_nonblocking(fd, true, NULL);
+
+    if (!qemu_set_blocking(fd, false, errp) {
+        close(fd);
+        return -1;
+    }
+
     return fd;
 }
 
@@ -189,7 +194,10 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
         goto error;
     }
 
-    g_unix_set_fd_nonblocking(fd, true, NULL);
+    if (!qemu_set_blocking(fd, false, errp) {
+        goto error;
+    }
+
     return fd;
 
 error:
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 22ec2f45d2..786f339c13 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -34,6 +34,7 @@
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
+#include "qemu/sockets.h"
 
 #define PATH_NET_TUN "/dev/net/tun"
 
@@ -124,7 +125,12 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
         return -1;
     }
     pstrcpy(ifname, ifname_size, ifr.ifr_name);
-    g_unix_set_fd_nonblocking(fd, true, NULL);
+
+    if (!qemu_set_blocking(fd, false, NULL)) {
+        close(fd);
+        return -1;
+    }
+
     return fd;
 }
 
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
index 51b7830bef..02709590c1 100644
--- a/net/tap-solaris.c
+++ b/net/tap-solaris.c
@@ -198,7 +198,12 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
             return -1;
         }
     }
-    g_unix_set_fd_nonblocking(fd, true, NULL);
+
+    if (!qemu_set_blocking(fd, false NULL)) {
+        close(fd);
+        return -1;
+    }
+
     return fd;
 }
 
diff --git a/net/tap.c b/net/tap.c
index f7df702f97..f37133e301 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -627,8 +627,7 @@ int net_init_bridge(const Netdev *netdev, const char *name,
         return -1;
     }
 
-    if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+    if (!qemu_set_blocking(fd, false, errp)) {
         return -1;
     }
     vnet_hdr = tap_probe_vnet_hdr(fd, errp);
@@ -729,9 +728,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
                 error_propagate(errp, err);
                 goto failed;
             }
-            if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
-                error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
-                                 name, fd);
+            if (!qemu_set_blocking(vhostfd, false, errp)) {
                 goto failed;
             }
         } else {
@@ -741,8 +738,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
                                  "tap: open vhost char device failed");
                 goto failed;
             }
-            if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
-                error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+            if (!qemu_set_blocking(vhostfd, false, errp)) {
                 goto failed;
             }
         }
@@ -839,9 +835,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
             return -1;
         }
 
-        if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
-            error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
-                             name, fd);
+        if (!qemu_set_blocking(fd, false, errp)) {
             close(fd);
             return -1;
         }
@@ -895,10 +889,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
                 goto free_fail;
             }
 
-            if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
+            if (!qemu_set_blocking(fd, false, errp)) {
                 ret = -1;
-                error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
-                                 name, fd);
                 goto free_fail;
             }
 
@@ -951,8 +943,7 @@ free_fail:
             return -1;
         }
 
-        if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
-            error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+        if (!qemu_set_blocking(fd, false, errp)) {
             return -1;
         }
         vnet_hdr = tap_probe_vnet_hdr(fd, errp);
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 12bc086d79..5070f27d75 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -503,9 +503,8 @@ int64_t qmp_guest_file_open(const char *path, const char *mode,
     /* set fd non-blocking to avoid common use cases (like reading from a
      * named pipe) from hanging the agent
      */
-    if (!g_unix_set_fd_nonblocking(fileno(fh), true, NULL)) {
+    if (!qemu_set_blocking(fileno(fh), false, errp)) {
         fclose(fh);
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
         return -1;
     }
 
diff --git a/tests/qtest/fuzz/virtio_net_fuzz.c b/tests/qtest/fuzz/virtio_net_fuzz.c
index e239875e3b..e9b13d3e4f 100644
--- a/tests/qtest/fuzz/virtio_net_fuzz.c
+++ b/tests/qtest/fuzz/virtio_net_fuzz.c
@@ -132,7 +132,7 @@ static void *virtio_net_test_setup_socket(GString *cmd_line, void *arg)
 {
     int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sockfds);
     g_assert_cmpint(ret, !=, -1);
-    g_unix_set_fd_nonblocking(sockfds[0], true, NULL);
+    qemu_set_blocking(sockfds[0], false, &error_abort);
     sockfds_initialized = true;
     g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
                            sockfds[1]);
diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c
index 75cb3e44b2..ba70bf997c 100644
--- a/tests/qtest/vhost-user-test.c
+++ b/tests/qtest/vhost-user-test.c
@@ -472,8 +472,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
          * The receive function forces it to be blocking,
          * so revert it back to non-blocking.
          */
-        g_unix_set_fd_nonblocking(fd, true, &err);
-        g_assert_no_error(err);
+        qemu_set_blocking(fd, false, &error_abort);
         break;
 
     case VHOST_USER_SET_LOG_BASE:
diff --git a/tests/unit/test-iov.c b/tests/unit/test-iov.c
index 75bc3be005..63e2b1583c 100644
--- a/tests/unit/test-iov.c
+++ b/tests/unit/test-iov.c
@@ -1,4 +1,5 @@
 #include "qemu/osdep.h"
+#include "qapi/error.h"
 #include "qemu/iov.h"
 #include "qemu/sockets.h"
 
@@ -186,7 +187,7 @@ static void test_io(void)
 
        close(sv[0]);
        FD_SET(sv[1], &fds);
-       g_unix_set_fd_nonblocking(sv[1], true, NULL);
+       qemu_set_blocking(sv[1], false, &error_abort);
        r = g_test_rand_int_range(sz / 2, sz);
        setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
 
@@ -222,7 +223,7 @@ static void test_io(void)
 
        close(sv[1]);
        FD_SET(sv[0], &fds);
-       g_unix_set_fd_nonblocking(sv[0], true, NULL);
+       qemu_set_blocking(sv[0], false, &error_abort);
        r = g_test_rand_int_range(sz / 2, sz);
        setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r));
        usleep(500000);
diff --git a/ui/input-linux.c b/ui/input-linux.c
index 92e1a1aa64..44d0c15a9b 100644
--- a/ui/input-linux.c
+++ b/ui/input-linux.c
@@ -316,8 +316,7 @@ static void input_linux_complete(UserCreatable *uc, Error **errp)
         error_setg_file_open(errp, errno, il->evdev);
         return;
     }
-    if (!g_unix_set_fd_nonblocking(il->fd, true, NULL)) {
-        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+    if (!qemu_set_blocking(il->fd, false, errp)) {
         return;
     }
 
diff --git a/util/event_notifier-posix.c b/util/event_notifier-posix.c
index 76420c5b56..8c05e0d528 100644
--- a/util/event_notifier-posix.c
+++ b/util/event_notifier-posix.c
@@ -14,6 +14,7 @@
 #include "qemu/cutils.h"
 #include "qemu/event_notifier.h"
 #include "qemu/main-loop.h"
+#include "qemu/sockets.h"
 
 #ifdef CONFIG_EVENTFD
 #include <sys/eventfd.h>
@@ -52,11 +53,11 @@ int event_notifier_init(EventNotifier *e, int active)
         if (!g_unix_open_pipe(fds, FD_CLOEXEC, NULL)) {
             return -errno;
         }
-        if (!g_unix_set_fd_nonblocking(fds[0], true, NULL)) {
+        if (!qemu_set_blocking(fds[0], false, NULL)) {
             ret = -errno;
             goto fail;
         }
-        if (!g_unix_set_fd_nonblocking(fds[1], true, NULL)) {
+        if (!qemu_set_blocking(fds[1], false, NULL)) {
             ret = -errno;
             goto fail;
         }
diff --git a/util/main-loop.c b/util/main-loop.c
index 51aeb2432e..6885be688c 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -34,6 +34,7 @@
 #include "block/thread-pool.h"
 #include "qemu/error-report.h"
 #include "qemu/queue.h"
+#include "qemu/sockets.h"
 #include "qom/object.h"
 
 #ifndef _WIN32
@@ -114,7 +115,10 @@ static int qemu_signal_init(Error **errp)
         return -errno;
     }
 
-    g_unix_set_fd_nonblocking(sigfd, true, NULL);
+    if (!qemu_set_blocking(sigfd, false, errp)) {
+        close(sigfd);
+        return -EINVAL;
+    }
 
     qemu_set_fd_handler(sigfd, sigfd_handler, NULL, (void *)(intptr_t)sigfd);
 
-- 
2.48.1
Re: [PATCH 07/10] use qemu_set_blocking instead of g_unix_set_fd_nonblocking
Posted by Stefan Hajnoczi 5 months ago
On Wed, Sep 03, 2025 at 12:44:07PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> Instead of open-coded g_unix_set_fd_nonblocking() calls, use
> QEMU wrapper qemu_socket_set_nonblock().

The commit description is outdated: the patch actually uses
qemu_set_blocking().
Re: [PATCH 07/10] use qemu_set_blocking instead of g_unix_set_fd_nonblocking
Posted by Daniel P. Berrangé 5 months ago
On Wed, Sep 03, 2025 at 12:44:07PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> Instead of open-coded g_unix_set_fd_nonblocking() calls, use
> QEMU wrapper qemu_socket_set_nonblock().
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> ---
>  chardev/char-fd.c                  |  4 ++--
>  chardev/char-pty.c                 |  3 +--
>  chardev/char-serial.c              |  3 +--
>  chardev/char-stdio.c               |  3 +--
>  hw/input/virtio-input-host.c       |  3 +--
>  hw/misc/ivshmem-flat.c             |  4 +++-
>  hw/misc/ivshmem-pci.c              |  8 +++++++-
>  hw/virtio/vhost-vsock.c            |  8 ++------
>  io/channel-command.c               |  9 ++++++---
>  io/channel-file.c                  |  3 +--
>  net/tap-bsd.c                      | 12 ++++++++++--
>  net/tap-linux.c                    |  8 +++++++-
>  net/tap-solaris.c                  |  7 ++++++-
>  net/tap.c                          | 21 ++++++---------------
>  qga/commands-posix.c               |  3 +--
>  tests/qtest/fuzz/virtio_net_fuzz.c |  2 +-
>  tests/qtest/vhost-user-test.c      |  3 +--
>  tests/unit/test-iov.c              |  5 +++--
>  ui/input-linux.c                   |  3 +--
>  util/event_notifier-posix.c        |  5 +++--
>  util/main-loop.c                   |  6 +++++-
>  21 files changed, 69 insertions(+), 54 deletions(-)

> diff --git a/io/channel-command.c b/io/channel-command.c
> index 8966dd3a2b..8ae9a026b3 100644
> --- a/io/channel-command.c
> +++ b/io/channel-command.c
> @@ -277,9 +277,12 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
>      cioc->blocking = enabled;
>  #else
>  
> -    if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
> -        (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
> -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
> +    if (cioc->writefd >= 0 &&
> +        !qemu_set_blocking(cioc->writefd, enabled, errp)) {
> +        return -1;
> +    }
> +    if (cioc->readfd >= 0 &&
> +        !qemu_set_blocking(cioc->readfd, enabled, errp)) {
>          return -1;
>      }
>  #endif
> diff --git a/io/channel-file.c b/io/channel-file.c
> index ca3f180cc2..5cef75a67c 100644
> --- a/io/channel-file.c
> +++ b/io/channel-file.c
> @@ -223,8 +223,7 @@ static int qio_channel_file_set_blocking(QIOChannel *ioc,
>  #else
>      QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
>  
> -    if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
> -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
> +    if (!qemu_set_blocking(fioc->fd, enabled, errp)) {
>          return -1;
>      }
>      return 0;

This is wrong for Windows. fioc->fd is not a socket, but this is passing
it to an API whose impl assume it is receiving a socket.


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 07/10] use qemu_set_blocking instead of g_unix_set_fd_nonblocking
Posted by Vladimir Sementsov-Ogievskiy 5 months ago
On 09.09.25 12:00, Daniel P. Berrangé wrote:
> On Wed, Sep 03, 2025 at 12:44:07PM +0300, Vladimir Sementsov-Ogievskiy wrote:
>> Instead of open-coded g_unix_set_fd_nonblocking() calls, use
>> QEMU wrapper qemu_socket_set_nonblock().
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
>> ---
>>   chardev/char-fd.c                  |  4 ++--
>>   chardev/char-pty.c                 |  3 +--
>>   chardev/char-serial.c              |  3 +--
>>   chardev/char-stdio.c               |  3 +--
>>   hw/input/virtio-input-host.c       |  3 +--
>>   hw/misc/ivshmem-flat.c             |  4 +++-
>>   hw/misc/ivshmem-pci.c              |  8 +++++++-
>>   hw/virtio/vhost-vsock.c            |  8 ++------
>>   io/channel-command.c               |  9 ++++++---
>>   io/channel-file.c                  |  3 +--
>>   net/tap-bsd.c                      | 12 ++++++++++--
>>   net/tap-linux.c                    |  8 +++++++-
>>   net/tap-solaris.c                  |  7 ++++++-
>>   net/tap.c                          | 21 ++++++---------------
>>   qga/commands-posix.c               |  3 +--
>>   tests/qtest/fuzz/virtio_net_fuzz.c |  2 +-
>>   tests/qtest/vhost-user-test.c      |  3 +--
>>   tests/unit/test-iov.c              |  5 +++--
>>   ui/input-linux.c                   |  3 +--
>>   util/event_notifier-posix.c        |  5 +++--
>>   util/main-loop.c                   |  6 +++++-
>>   21 files changed, 69 insertions(+), 54 deletions(-)
> 
>> diff --git a/io/channel-command.c b/io/channel-command.c
>> index 8966dd3a2b..8ae9a026b3 100644
>> --- a/io/channel-command.c
>> +++ b/io/channel-command.c
>> @@ -277,9 +277,12 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
>>       cioc->blocking = enabled;
>>   #else
>>   
>> -    if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
>> -        (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
>> -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
>> +    if (cioc->writefd >= 0 &&
>> +        !qemu_set_blocking(cioc->writefd, enabled, errp)) {
>> +        return -1;
>> +    }
>> +    if (cioc->readfd >= 0 &&
>> +        !qemu_set_blocking(cioc->readfd, enabled, errp)) {
>>           return -1;
>>       }
>>   #endif
>> diff --git a/io/channel-file.c b/io/channel-file.c
>> index ca3f180cc2..5cef75a67c 100644
>> --- a/io/channel-file.c
>> +++ b/io/channel-file.c
>> @@ -223,8 +223,7 @@ static int qio_channel_file_set_blocking(QIOChannel *ioc,
>>   #else
>>       QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
>>   
>> -    if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
>> -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
>> +    if (!qemu_set_blocking(fioc->fd, enabled, errp)) {
>>           return -1;
>>       }
>>       return 0;
> 
> This is wrong for Windows. fioc->fd is not a socket, but this is passing
> it to an API whose impl assume it is receiving a socket.
> 

But what is changed with the patch? g_unix_set_fd_nonblocking(fioc->fd, ..) is wrong for Windows as well.

And making separate qemu_set_blocking() and qemu_socket_set_blocking(), which do the same
thing, doesn't make sense..

Hmm. But we can define qemu_set_blocking() only for Linux, keeping qemu_socket_set_blocking() the generic
function. Still, nothing prevents using qemu_socket_set_blocking() on non-sockets..

I don't know. For me it seems better to have one qemu_set_blocking, and rely on Windows realization to
correctly error-out for non-socket fds.

Do you have and idea, how final API should look, covering sockets and non-socket fds?

I also found ff5927baa7ffb9c978 commit about it, see my last answer to the cover-letter.

-- 
Best regards,
Vladimir

Re: [PATCH 07/10] use qemu_set_blocking instead of g_unix_set_fd_nonblocking
Posted by Daniel P. Berrangé 5 months ago
On Tue, Sep 09, 2025 at 12:11:19PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> On 09.09.25 12:00, Daniel P. Berrangé wrote:
> > On Wed, Sep 03, 2025 at 12:44:07PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> > > Instead of open-coded g_unix_set_fd_nonblocking() calls, use
> > > QEMU wrapper qemu_socket_set_nonblock().
> > > 
> > > Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> > > ---
> > >   chardev/char-fd.c                  |  4 ++--
> > >   chardev/char-pty.c                 |  3 +--
> > >   chardev/char-serial.c              |  3 +--
> > >   chardev/char-stdio.c               |  3 +--
> > >   hw/input/virtio-input-host.c       |  3 +--
> > >   hw/misc/ivshmem-flat.c             |  4 +++-
> > >   hw/misc/ivshmem-pci.c              |  8 +++++++-
> > >   hw/virtio/vhost-vsock.c            |  8 ++------
> > >   io/channel-command.c               |  9 ++++++---
> > >   io/channel-file.c                  |  3 +--
> > >   net/tap-bsd.c                      | 12 ++++++++++--
> > >   net/tap-linux.c                    |  8 +++++++-
> > >   net/tap-solaris.c                  |  7 ++++++-
> > >   net/tap.c                          | 21 ++++++---------------
> > >   qga/commands-posix.c               |  3 +--
> > >   tests/qtest/fuzz/virtio_net_fuzz.c |  2 +-
> > >   tests/qtest/vhost-user-test.c      |  3 +--
> > >   tests/unit/test-iov.c              |  5 +++--
> > >   ui/input-linux.c                   |  3 +--
> > >   util/event_notifier-posix.c        |  5 +++--
> > >   util/main-loop.c                   |  6 +++++-
> > >   21 files changed, 69 insertions(+), 54 deletions(-)
> > 
> > > diff --git a/io/channel-command.c b/io/channel-command.c
> > > index 8966dd3a2b..8ae9a026b3 100644
> > > --- a/io/channel-command.c
> > > +++ b/io/channel-command.c
> > > @@ -277,9 +277,12 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
> > >       cioc->blocking = enabled;
> > >   #else
> > > -    if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
> > > -        (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
> > > -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
> > > +    if (cioc->writefd >= 0 &&
> > > +        !qemu_set_blocking(cioc->writefd, enabled, errp)) {
> > > +        return -1;
> > > +    }
> > > +    if (cioc->readfd >= 0 &&
> > > +        !qemu_set_blocking(cioc->readfd, enabled, errp)) {
> > >           return -1;
> > >       }
> > >   #endif
> > > diff --git a/io/channel-file.c b/io/channel-file.c
> > > index ca3f180cc2..5cef75a67c 100644
> > > --- a/io/channel-file.c
> > > +++ b/io/channel-file.c
> > > @@ -223,8 +223,7 @@ static int qio_channel_file_set_blocking(QIOChannel *ioc,
> > >   #else
> > >       QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
> > > -    if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
> > > -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
> > > +    if (!qemu_set_blocking(fioc->fd, enabled, errp)) {
> > >           return -1;
> > >       }
> > >       return 0;
> > 
> > This is wrong for Windows. fioc->fd is not a socket, but this is passing
> > it to an API whose impl assume it is receiving a socket.
> > 
> 
> But what is changed with the patch? g_unix_set_fd_nonblocking(fioc->fd, ..) is wrong for Windows as well.

Actually I missed the #ifdef. This code is in an #else branch that excludes
compilation on Wnidows - the Windows brach just raise an error.

> And making separate qemu_set_blocking() and qemu_socket_set_blocking(), which do the same
> thing, doesn't make sense..
> 
> Hmm. But we can define qemu_set_blocking() only for Linux, keeping qemu_socket_set_blocking() the generic
> function. Still, nothing prevents using qemu_socket_set_blocking() on non-sockets..

We just relying on the name of the function alerting the developer / reviewer.
If you're dealing with a FIFO pipe FD you are (hopefully) going to realize
that qemu_socket_XXX is not a function to be used.

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 07/10] use qemu_set_blocking instead of g_unix_set_fd_nonblocking
Posted by Vladimir Sementsov-Ogievskiy 5 months ago
On 09.09.25 12:15, Daniel P. Berrangé wrote:
> On Tue, Sep 09, 2025 at 12:11:19PM +0300, Vladimir Sementsov-Ogievskiy wrote:
>> On 09.09.25 12:00, Daniel P. Berrangé wrote:
>>> On Wed, Sep 03, 2025 at 12:44:07PM +0300, Vladimir Sementsov-Ogievskiy wrote:
>>>> Instead of open-coded g_unix_set_fd_nonblocking() calls, use
>>>> QEMU wrapper qemu_socket_set_nonblock().
>>>>
>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
>>>> ---
>>>>    chardev/char-fd.c                  |  4 ++--
>>>>    chardev/char-pty.c                 |  3 +--
>>>>    chardev/char-serial.c              |  3 +--
>>>>    chardev/char-stdio.c               |  3 +--
>>>>    hw/input/virtio-input-host.c       |  3 +--
>>>>    hw/misc/ivshmem-flat.c             |  4 +++-
>>>>    hw/misc/ivshmem-pci.c              |  8 +++++++-
>>>>    hw/virtio/vhost-vsock.c            |  8 ++------
>>>>    io/channel-command.c               |  9 ++++++---
>>>>    io/channel-file.c                  |  3 +--
>>>>    net/tap-bsd.c                      | 12 ++++++++++--
>>>>    net/tap-linux.c                    |  8 +++++++-
>>>>    net/tap-solaris.c                  |  7 ++++++-
>>>>    net/tap.c                          | 21 ++++++---------------
>>>>    qga/commands-posix.c               |  3 +--
>>>>    tests/qtest/fuzz/virtio_net_fuzz.c |  2 +-
>>>>    tests/qtest/vhost-user-test.c      |  3 +--
>>>>    tests/unit/test-iov.c              |  5 +++--
>>>>    ui/input-linux.c                   |  3 +--
>>>>    util/event_notifier-posix.c        |  5 +++--
>>>>    util/main-loop.c                   |  6 +++++-
>>>>    21 files changed, 69 insertions(+), 54 deletions(-)
>>>
>>>> diff --git a/io/channel-command.c b/io/channel-command.c
>>>> index 8966dd3a2b..8ae9a026b3 100644
>>>> --- a/io/channel-command.c
>>>> +++ b/io/channel-command.c
>>>> @@ -277,9 +277,12 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
>>>>        cioc->blocking = enabled;
>>>>    #else
>>>> -    if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
>>>> -        (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
>>>> -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
>>>> +    if (cioc->writefd >= 0 &&
>>>> +        !qemu_set_blocking(cioc->writefd, enabled, errp)) {
>>>> +        return -1;
>>>> +    }
>>>> +    if (cioc->readfd >= 0 &&
>>>> +        !qemu_set_blocking(cioc->readfd, enabled, errp)) {
>>>>            return -1;
>>>>        }
>>>>    #endif
>>>> diff --git a/io/channel-file.c b/io/channel-file.c
>>>> index ca3f180cc2..5cef75a67c 100644
>>>> --- a/io/channel-file.c
>>>> +++ b/io/channel-file.c
>>>> @@ -223,8 +223,7 @@ static int qio_channel_file_set_blocking(QIOChannel *ioc,
>>>>    #else
>>>>        QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
>>>> -    if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
>>>> -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
>>>> +    if (!qemu_set_blocking(fioc->fd, enabled, errp)) {
>>>>            return -1;
>>>>        }
>>>>        return 0;
>>>
>>> This is wrong for Windows. fioc->fd is not a socket, but this is passing
>>> it to an API whose impl assume it is receiving a socket.
>>>
>>
>> But what is changed with the patch? g_unix_set_fd_nonblocking(fioc->fd, ..) is wrong for Windows as well.
> 
> Actually I missed the #ifdef. This code is in an #else branch that excludes
> compilation on Wnidows - the Windows brach just raise an error.
> 
>> And making separate qemu_set_blocking() and qemu_socket_set_blocking(), which do the same
>> thing, doesn't make sense..
>>
>> Hmm. But we can define qemu_set_blocking() only for Linux, keeping qemu_socket_set_blocking() the generic
>> function. Still, nothing prevents using qemu_socket_set_blocking() on non-sockets..
> 
> We just relying on the name of the function alerting the developer / reviewer.
> If you're dealing with a FIFO pipe FD you are (hopefully) going to realize
> that qemu_socket_XXX is not a function to be used.
> 

Understand. But having both qemu_XXX() and qemu_socket_XXX(), I'd be confused, why not just use qemu_XXX() everywhere.

So, for final API, either we have one function qemu_set_blocking() (as the series propose), and lose this alert,

or, we should have something like:

qemu_socket_set_blocking() - generic, for calling on sockets, Windows or Linux

qemu_unix_set_blocking() - defined only for Linux

What I dislike with the latter:

1. For Linux functions are duplicates actually. So, we have a defined only for Linux duplicate of generic function

2. Nothing prevents using qemu_socket_set_blocking() on any fds in Linux except name (and it will succeed!!)


-- 
Best regards,
Vladimir

Re: [PATCH 07/10] use qemu_set_blocking instead of g_unix_set_fd_nonblocking
Posted by Daniel P. Berrangé 5 months ago
On Tue, Sep 09, 2025 at 12:50:00PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> On 09.09.25 12:15, Daniel P. Berrangé wrote:
> > On Tue, Sep 09, 2025 at 12:11:19PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> > > On 09.09.25 12:00, Daniel P. Berrangé wrote:
> > > > On Wed, Sep 03, 2025 at 12:44:07PM +0300, Vladimir Sementsov-Ogievskiy wrote:
> > > > > Instead of open-coded g_unix_set_fd_nonblocking() calls, use
> > > > > QEMU wrapper qemu_socket_set_nonblock().
> > > > > 
> > > > > Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
> > > > > ---
> > > > >    chardev/char-fd.c                  |  4 ++--
> > > > >    chardev/char-pty.c                 |  3 +--
> > > > >    chardev/char-serial.c              |  3 +--
> > > > >    chardev/char-stdio.c               |  3 +--
> > > > >    hw/input/virtio-input-host.c       |  3 +--
> > > > >    hw/misc/ivshmem-flat.c             |  4 +++-
> > > > >    hw/misc/ivshmem-pci.c              |  8 +++++++-
> > > > >    hw/virtio/vhost-vsock.c            |  8 ++------
> > > > >    io/channel-command.c               |  9 ++++++---
> > > > >    io/channel-file.c                  |  3 +--
> > > > >    net/tap-bsd.c                      | 12 ++++++++++--
> > > > >    net/tap-linux.c                    |  8 +++++++-
> > > > >    net/tap-solaris.c                  |  7 ++++++-
> > > > >    net/tap.c                          | 21 ++++++---------------
> > > > >    qga/commands-posix.c               |  3 +--
> > > > >    tests/qtest/fuzz/virtio_net_fuzz.c |  2 +-
> > > > >    tests/qtest/vhost-user-test.c      |  3 +--
> > > > >    tests/unit/test-iov.c              |  5 +++--
> > > > >    ui/input-linux.c                   |  3 +--
> > > > >    util/event_notifier-posix.c        |  5 +++--
> > > > >    util/main-loop.c                   |  6 +++++-
> > > > >    21 files changed, 69 insertions(+), 54 deletions(-)
> > > > 
> > > > > diff --git a/io/channel-command.c b/io/channel-command.c
> > > > > index 8966dd3a2b..8ae9a026b3 100644
> > > > > --- a/io/channel-command.c
> > > > > +++ b/io/channel-command.c
> > > > > @@ -277,9 +277,12 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
> > > > >        cioc->blocking = enabled;
> > > > >    #else
> > > > > -    if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
> > > > > -        (cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
> > > > > -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
> > > > > +    if (cioc->writefd >= 0 &&
> > > > > +        !qemu_set_blocking(cioc->writefd, enabled, errp)) {
> > > > > +        return -1;
> > > > > +    }
> > > > > +    if (cioc->readfd >= 0 &&
> > > > > +        !qemu_set_blocking(cioc->readfd, enabled, errp)) {
> > > > >            return -1;
> > > > >        }
> > > > >    #endif
> > > > > diff --git a/io/channel-file.c b/io/channel-file.c
> > > > > index ca3f180cc2..5cef75a67c 100644
> > > > > --- a/io/channel-file.c
> > > > > +++ b/io/channel-file.c
> > > > > @@ -223,8 +223,7 @@ static int qio_channel_file_set_blocking(QIOChannel *ioc,
> > > > >    #else
> > > > >        QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
> > > > > -    if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
> > > > > -        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
> > > > > +    if (!qemu_set_blocking(fioc->fd, enabled, errp)) {
> > > > >            return -1;
> > > > >        }
> > > > >        return 0;
> > > > 
> > > > This is wrong for Windows. fioc->fd is not a socket, but this is passing
> > > > it to an API whose impl assume it is receiving a socket.
> > > > 
> > > 
> > > But what is changed with the patch? g_unix_set_fd_nonblocking(fioc->fd, ..) is wrong for Windows as well.
> > 
> > Actually I missed the #ifdef. This code is in an #else branch that excludes
> > compilation on Wnidows - the Windows brach just raise an error.
> > 
> > > And making separate qemu_set_blocking() and qemu_socket_set_blocking(), which do the same
> > > thing, doesn't make sense..
> > > 
> > > Hmm. But we can define qemu_set_blocking() only for Linux, keeping qemu_socket_set_blocking() the generic
> > > function. Still, nothing prevents using qemu_socket_set_blocking() on non-sockets..
> > 
> > We just relying on the name of the function alerting the developer / reviewer.
> > If you're dealing with a FIFO pipe FD you are (hopefully) going to realize
> > that qemu_socket_XXX is not a function to be used.
> > 
> 
> Understand. But having both qemu_XXX() and qemu_socket_XXX(), I'd be confused, why not just use qemu_XXX() everywhere.
> 
> So, for final API, either we have one function qemu_set_blocking() (as the series propose), and lose this alert,
> 
> or, we should have something like:
> 
> qemu_socket_set_blocking() - generic, for calling on sockets, Windows or Linux
> 
> qemu_unix_set_blocking() - defined only for Linux
> 
> What I dislike with the latter:
> 
> 1. For Linux functions are duplicates actually. So, we have a defined only for Linux duplicate of generic function
> 
> 2. Nothing prevents using qemu_socket_set_blocking() on any fds in Linux except name (and it will succeed!!)

I looked at what we do in libvirt, and there we just have a single
function virSetBlocking() that simply does ioctrlsocket() on Windows.
I can't say we've had any significant trouble with that, though our
Windows scope & usage is much less than QEMU's.

A key difference though is that callers are expected to check the
return value for failure.


With the current QEMU design where we do NOT expect callers to check
for failure, I think it is important that the function naming make
clear the intended use case, as we won't get runtime diagnosis of
incorrect calls.

So with this in mind, I'm actually OK with your proposed design for
a general  qemu_set_blocking, as that has an Error **errp parameter
encouraging failure checking by callers.

The ioctlsocket method will also return a clear error if passed
something that is not a SOCKET, but a generic file backed HANDLE.

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 :|