git: d2b3a0ed31ef - main - sendto: don't clear transient errors for atomic protocols

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Wed, 23 Feb 2022 18:27:17 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=d2b3a0ed31ef6270c712d0779a95bb222df88909

commit d2b3a0ed31ef6270c712d0779a95bb222df88909
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2022-02-17 17:07:31 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2022-02-23 18:24:14 +0000

    sendto: don't clear transient errors for atomic protocols
    
    The changeset 65572cade35 uncovered the fact that top layer of sendto(2)
    would clear a transient error code if some data was copied out of uio.
    The clearing of the error makes sense for non-atomic protocols, since
    they have sent some data.  The atomic protocols send all or nothing.
    
    The current implementation of unix/dgram uses sosend_generic(), which
    would always copyout and only then it may fail to deliver a message.
    The sosend_dgram(), currently used by UDP only, also has same behavior.
    
    Reported by:            pho
    Reviewed by:            pho, markj
    Differential revision:  https://reviews.freebsd.org/D34309
---
 sys/kern/uipc_syscalls.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 766c68b35cfe..72336d31071c 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -785,8 +785,10 @@ kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
 	len = auio.uio_resid;
 	error = sosend(so, mp->msg_name, &auio, 0, control, flags, td);
 	if (error != 0) {
-		if (auio.uio_resid != len && (error == ERESTART ||
-		    error == EINTR || error == EWOULDBLOCK))
+		if (auio.uio_resid != len &&
+		    (so->so_proto->pr_flags & PR_ATOMIC) == 0 &&
+		    (error == ERESTART || error == EINTR ||
+		    error == EWOULDBLOCK))
 			error = 0;
 		/* Generation of SIGPIPE can be controlled per socket */
 		if (error == EPIPE && !(so->so_options & SO_NOSIGPIPE) &&