Introduce and use internal/linux

This package is to provide unix.* wrappers to ensure that:
 - they retry on EINTR;
 - a "rich" error is returned on failure.

 A first such wrapper, Sendmsg, is introduced.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2025-03-25 14:24:20 -07:00
parent e5895f1100
commit 8cc1eb379b
4 changed files with 39 additions and 9 deletions

18
internal/linux/eintr.go Normal file
View File

@@ -0,0 +1,18 @@
package linux
import (
"errors"
"golang.org/x/sys/unix"
)
// retryOnEINTR takes a function that returns an error and calls it
// until the error returned is not EINTR.
func retryOnEINTR(fn func() error) error {
for {
err := fn()
if !errors.Is(err, unix.EINTR) {
return err
}
}
}

15
internal/linux/linux.go Normal file
View File

@@ -0,0 +1,15 @@
package linux
import (
"os"
"golang.org/x/sys/unix"
)
// Sendmsg wraps [unix.Sendmsg].
func Sendmsg(fd int, p, oob []byte, to unix.Sockaddr, flags int) error {
err := retryOnEINTR(func() error {
return unix.Sendmsg(fd, p, oob, to, flags)
})
return os.NewSyscallError("sendmsg", err)
}

View File

@@ -21,6 +21,7 @@ import (
"os" "os"
"runtime" "runtime"
"github.com/opencontainers/runc/internal/linux"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@@ -126,10 +127,5 @@ 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))
for { return linux.Sendmsg(int(socket.Fd()), []byte(msg), oob, nil, 0)
err := unix.Sendmsg(int(socket.Fd()), []byte(msg), oob, nil, 0)
if err != unix.EINTR {
return os.NewSyscallError("sendmsg", err)
}
}
} }

View File

@@ -11,6 +11,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/opencontainers/runc/internal/linux"
"github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@@ -181,7 +182,7 @@ func sdNotifyBarrier(client *net.UnixConn) error {
return err return err
} }
// Get the FD for the unix socket file to be able to do perform syscall.Sendmsg. // Get the FD for the unix socket file to be able to use sendmsg.
clientFd, err := client.File() clientFd, err := client.File()
if err != nil { if err != nil {
return err return err
@@ -189,9 +190,9 @@ func sdNotifyBarrier(client *net.UnixConn) error {
// Send the write end of the pipe along with a BARRIER=1 message. // Send the write end of the pipe along with a BARRIER=1 message.
fdRights := unix.UnixRights(int(pipeW.Fd())) fdRights := unix.UnixRights(int(pipeW.Fd()))
err = unix.Sendmsg(int(clientFd.Fd()), []byte("BARRIER=1"), fdRights, nil, 0) err = linux.Sendmsg(int(clientFd.Fd()), []byte("BARRIER=1"), fdRights, nil, 0)
if err != nil { if err != nil {
return &os.SyscallError{Syscall: "sendmsg", Err: err} return err
} }
// Close our copy of pipeW. // Close our copy of pipeW.