Retry direct unix package calls if observing EINTR

Retry Recvfrom, Sendmsg, Readmsg, and Read as they can return EINTR.

Signed-off-by: Evan Phoenix <evan@phx.io>
This commit is contained in:
Evan Phoenix
2025-02-20 12:52:55 -08:00
parent 91e6621205
commit 28475f12e3
3 changed files with 37 additions and 5 deletions

View File

@@ -2,6 +2,7 @@ package libcontainer
import ( import (
"fmt" "fmt"
"os"
"path/filepath" "path/filepath"
"unsafe" "unsafe"
@@ -40,7 +41,11 @@ func registerMemoryEventV2(cgDir, evName, cgEvName string) (<-chan struct{}, err
for { for {
n, err := unix.Read(fd, buffer[:]) n, err := unix.Read(fd, buffer[:])
if err == unix.EINTR { //nolint:errorlint // unix errors are bare
continue
}
if err != nil { if err != nil {
err = os.NewSyscallError("read", err)
logrus.Warnf("unable to read event data from inotify, got error: %v", err) logrus.Warnf("unable to read event data from inotify, got error: %v", err)
return return
} }

View File

@@ -42,9 +42,20 @@ func (s *syncSocket) WritePacket(b []byte) (int, error) {
} }
func (s *syncSocket) ReadPacket() ([]byte, error) { func (s *syncSocket) ReadPacket() ([]byte, error) {
size, _, err := unix.Recvfrom(int(s.f.Fd()), nil, unix.MSG_TRUNC|unix.MSG_PEEK) var (
size int
err error
)
for {
size, _, err = unix.Recvfrom(int(s.f.Fd()), nil, unix.MSG_TRUNC|unix.MSG_PEEK)
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
break
}
}
if err != nil { if err != nil {
return nil, fmt.Errorf("fetch packet length from socket: %w", err) return nil, fmt.Errorf("fetch packet length from socket: %w", os.NewSyscallError("recvfrom", err))
} }
// We will only get a zero size if the socket has been closed from the // We will only get a zero size if the socket has been closed from the
// other end (otherwise recvfrom(2) will block until a packet is ready). In // other end (otherwise recvfrom(2) will block until a packet is ready). In

View File

@@ -42,9 +42,20 @@ func RecvFile(socket *os.File) (_ *os.File, Err error) {
oob := make([]byte, oobSpace) oob := make([]byte, oobSpace)
sockfd := socket.Fd() sockfd := socket.Fd()
n, oobn, _, _, err := unix.Recvmsg(int(sockfd), name, oob, unix.MSG_CMSG_CLOEXEC) var (
n, oobn int
err error
)
for {
n, oobn, _, _, err = unix.Recvmsg(int(sockfd), name, oob, unix.MSG_CMSG_CLOEXEC)
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
break
}
}
if err != nil { if err != nil {
return nil, err return nil, os.NewSyscallError("recvmsg", err)
} }
if n >= MaxNameLen || oobn != oobSpace { if n >= MaxNameLen || oobn != oobSpace {
return nil, fmt.Errorf("recvfile: incorrect number of bytes read (n=%d oobn=%d)", n, oobn) return nil, fmt.Errorf("recvfile: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
@@ -115,5 +126,10 @@ func SendFile(socket *os.File, file *os.File) error {
// SendRawFd sends a specific file descriptor over the given AF_UNIX socket. // SendRawFd sends a specific file descriptor over the given AF_UNIX socket.
func SendRawFd(socket *os.File, msg string, fd uintptr) error { func SendRawFd(socket *os.File, msg string, fd uintptr) error {
oob := unix.UnixRights(int(fd)) oob := unix.UnixRights(int(fd))
return unix.Sendmsg(int(socket.Fd()), []byte(msg), oob, nil, 0) for {
err := unix.Sendmsg(int(socket.Fd()), []byte(msg), oob, nil, 0)
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
return os.NewSyscallError("sendmsg", err)
}
}
} }