internal/uevent: handle state divergence
Some checks failed
Test / Flake checks (push) Has been cancelled
Test / Sandbox (push) Has started running
Test / Sandbox (race detector) (push) Has started running
Test / Hakurei (push) Has been cancelled
Test / Hakurei (race detector) (push) Has been cancelled
Test / ShareFS (push) Has been cancelled
Test / Create distribution (push) Has been cancelled

This requires the caller to arrange for a coldboot to happen, some time after this error is encountered, and to resume event processing.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-03-30 01:48:20 +09:00
parent 648079f42c
commit 8658c50786

View File

@@ -18,6 +18,13 @@ type (
Recoverable interface{ recoverable() } Recoverable interface{ recoverable() }
// Nontrivial is satisfied by errors preferring a JSON encoding. // Nontrivial is satisfied by errors preferring a JSON encoding.
Nontrivial interface{ nontrivial() } Nontrivial interface{ nontrivial() }
// NeedsColdboot is satisfied by errors indicating divergence of local state
// from the kernel, usually from lost uevent data.
NeedsColdboot interface {
Recoverable
coldboot()
}
) )
// Conn represents a NETLINK_KOBJECT_UEVENT socket. // Conn represents a NETLINK_KOBJECT_UEVENT socket.
@@ -58,6 +65,18 @@ var (
ErrBadSocket = errors.New("unexpected socket address") ErrBadSocket = errors.New("unexpected socket address")
) )
// ReceiveBufferError indicates one or more [Message] being lost due to the
// socket receive buffer filling up. This is usually caused by epoll waking the
// receiving program up too late.
type ReceiveBufferError struct{ _ [0]*ReceiveBufferError }
var _ NeedsColdboot = ReceiveBufferError{}
func (ReceiveBufferError) recoverable() {}
func (ReceiveBufferError) coldboot() {}
func (ReceiveBufferError) Unwrap() error { return syscall.ENOBUFS }
func (e ReceiveBufferError) Error() string { return syscall.ENOBUFS.Error() }
// BadPortError is returned by [Conn.Consume] upon receiving a message that did // BadPortError is returned by [Conn.Consume] upon receiving a message that did
// not come from the kernel. // not come from the kernel.
type BadPortError syscall.SockaddrNetlink type BadPortError syscall.SockaddrNetlink
@@ -84,6 +103,9 @@ func (c *Conn) Consume(ctx context.Context, events chan<- *Message) error {
for { for {
data, _, from, err := c.conn.Recvmsg(ctx, 0) data, _, from, err := c.conn.Recvmsg(ctx, 0)
if err != nil { if err != nil {
if err == syscall.ENOBUFS {
return ReceiveBufferError{}
}
return err return err
} }