On 02.02.26 14:26, Daniel P. Berrangé wrote:
On Sun, Feb 01, 2026 at 08:36:29PM +0300, Vladimir Sementsov-Ogievskiy wrote:
logfd is blocking, so we don't need to care about EAGAIN.
Let's simply use qemu_write_full().

Are you sure logfd is always blocking ?  It can be an FD passed in
from outside QEMU, and off-hand, I'm not sure where we force that to
be blocking. Though we could argue it is the client't fault if they
passed a non-blocking FD to QEMU.

NB, we can *not* assume logfd is a plain file as libvirt will pass
in a pipe to send logging via virtlogd.


I'm sorry I missed the email. And the commit is in master now.

And, I missed the fact that

   qemu_create(common->logfile, flags, 0666, errp);

Can actually chose fd from "fdset". All named fds in monitor are set blocking
explicitly except for the case when QIO_CHANNEL_READ_FLAG_FD_PRESERVE_BLOCKING 
flag
take place.. But fds coming through add-fd commandline options are not handled
this way, as I can see.


Looking through:

1. util/oslib-posix.c: qemu_write_pidfile()

Uses qemu_write_full(), *unprepared* to non-blocking.

2. ui/ui-qmp-cmds.c: qmp_screendump()

2.1. png_save() wraps the fd to fdopen(), which I assume should work well
with blocking and non-blocking fds

2.2. ppm_save() wraps it into qio_channel_file_new_fd()

qio_channel_write_all() -> qio_channel_writev_full_all() do handle 
QIO_CHANNEL_ERR_BLOCK

3. qio_channel_file_new_path()

In general qio-channels are prepared to work with non-blocking fds.

qio_channel_file_new_path() is used (except for 2.2 and tests) from migration 
code, which
I think should be prepared to non-blocking fds. At least, qemu_fill_buffer()
handles QIO_CHANNEL_ERR_BLOCK.

4. hw/usb/bus.c: usb_qdev_realize()

Wraps by fdopen()

5. hw/uefi/var-service-pcap.c: uefi_vars_pcap_init()

Wraps by fdopen()

6. hw/uefi/var-service-json.c: uefi_vars_json_init()

Use write() and don't handle EAGAIN: *unprepared* for non-blocking.

7. dump/dump.c: qmp_dump_guest_memory()

Use qemu_write_full() - *unprepared*

8. chardev/char.c: logfd - *unprepared* after my commit

9. block/file-posix.c: raw_co_create()

May use write() and not handle EAGAIN during raw_regular_truncate() - 
unprepared.


What to do with it? I see several possibilities:

1. simply support EAGAIN in qemu_write_full()? Like it was in 
qemu_chr_write_log()
- with g_usleep(100)?

2. switch to qio_channel_file_new_path() + qio_channel_write_all()

3. call qemu_set_blocking() on fd for *unprepared* cases



Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]>
---
  chardev/char.c | 22 +++++-----------------
  1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/chardev/char.c b/chardev/char.c
index 3e432195a5..64006a3119 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -82,29 +82,17 @@ void qemu_chr_be_event(Chardev *s, QEMUChrEvent event)
      CHARDEV_GET_CLASS(s)->chr_be_event(s, event);
  }
-/* Not reporting errors from writing to logfile, as logs are
- * defined to be "best effort" only */
  static void qemu_chr_write_log(Chardev *s, const uint8_t *buf, size_t len)
  {
-    size_t done = 0;
-    ssize_t ret;
-
      if (s->logfd < 0) {
          return;
      }
- while (done < len) {
-    retry:
-        ret = write(s->logfd, buf + done, len - done);
-        if (ret == -1 && errno == EAGAIN) {
-            g_usleep(100);
-            goto retry;
-        }
-
-        if (ret <= 0) {
-            return;
-        }
-        done += ret;
+    if (qemu_write_full(s->logfd, buf, len) < len) {
+        /*
+         * qemu_write_full() is defined with G_GNUC_WARN_UNUSED_RESULT,
+         * but logging is best‑effort, we do ignore errors.
+         */
      }
  }
--
2.52.0


With regards,
Daniel


--
Best regards,
Vladimir

Reply via email to