aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Berg <[email protected]>2023-10-18 14:36:42 +0200
committerJohannes Berg <[email protected]>2024-07-03 12:18:02 +0200
commit4cfb44df8d12a5fc2b801d18dc41b03bf7e6cd7b (patch)
treebed231d30bf3ee20d2ef5de473b087ecd649b35f
parentc6c4cbaa01b61eff2232d8cf4d441565535aa53a (diff)
um: chan_user: retry partial writes
In the next commit, we are going to set the output FD to be blocking. Once that is done, the write() may be short if an interrupt happens while it is writing out data. As such, to properly catch an EINTR error, we need to retry the write. Signed-off-by: Benjamin Berg <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Johannes Berg <[email protected]>
-rw-r--r--arch/um/drivers/chan_user.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 60fcb181835d..a66e556012c4 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -37,11 +37,23 @@ int generic_read(int fd, __u8 *c_out, void *unused)
int generic_write(int fd, const __u8 *buf, size_t n, void *unused)
{
+ int written = 0;
int err;
- CATCH_EINTR(err = write(fd, buf, n));
- if (err > 0)
- return err;
+ /* The FD may be in blocking mode, as such, need to retry short writes,
+ * they may have been interrupted by a signal.
+ */
+ do {
+ errno = 0;
+ err = write(fd, buf + written, n - written);
+ if (err > 0) {
+ written += err;
+ continue;
+ }
+ } while (err < 0 && errno == EINTR);
+
+ if (written > 0)
+ return written;
else if (errno == EAGAIN)
return 0;
else if (err == 0)