lib/utils: introduce xwritel() as a more robust and convenient write()
commit4a7f07addf8b5dffae1aefe81e380b9ad7142bed
authorLaszlo Ersek <lersek@redhat.com>
Wed, 15 Mar 2023 11:01:55 +0000 (15 12:01 +0100)
committerLaszlo Ersek <lersek@redhat.com>
Thu, 16 Mar 2023 10:20:10 +0000 (16 11:20 +0100)
tree652a24defd8c38e22feb74423b9533a0ad28be6a
parent48eca6a254685b2d741e9e29ef77dee340de4640
lib/utils: introduce xwritel() as a more robust and convenient write()

While nbd_internal_fork_safe_perror() must indeed call write(), and
arguably justifiedly ignores the return value of write(), we can still
make the write operations slightly more robust and convenient. Let's do
that by introducing xwritel():

- Let the caller pass a list of NUL-terminated strings, via stdarg /
  ellipsis notation in the parameter list.

- Handle partial writes.

- Cope with EINTR and EAGAIN errors. (A busy loop around EAGAIN on a
  non-blocking file is not great in the general case, but it's good enough
  for writing out diagnostics before giving up.)

- In the common case, handle an nbd_internal_fork_safe_perror() call with
  a single xwritel() -> writev() call chain, rather than with four
  separate write() calls. In practice, this tends to make the error
  message written to a regular file contiguous, even if other threads are
  writing to the same file. Multiple separate write() calls tend to
  interleave chunks of data from different threads.

As a side bonus, remove the path in nbd_internal_fork_safe_perror() where
at least one of the first two write() syscalls fails, and overwrites
"errno", before we get to formatting the error string from "errno".

Thanks to Eric Blake for helping me understand the scope of Austin Group
bug reports.

Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20230315110157.357958-2-lersek@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[lersek@redhat.com: add __attribute__ ((sentinel)), suggested by Eric]
lib/utils.c