aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-03-30 01:48:20 +0900
committerOphestra <cat@gensokyo.uk>2026-03-30 01:50:09 +0900
commit141958656f8a83a4f5703bd4890389dd1f180e0a (patch)
tree7999403cc9754284f724ef16bfc52818d199a6eb
parent648079f42cd872f16110e571ce34fdbd90f7c476 (diff)
internal/uevent: handle state divergence
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>
-rw-r--r--internal/uevent/uevent.go22
1 files changed, 22 insertions, 0 deletions
diff --git a/internal/uevent/uevent.go b/internal/uevent/uevent.go
index e0779866..47091f59 100644
--- a/internal/uevent/uevent.go
+++ b/internal/uevent/uevent.go
@@ -18,6 +18,13 @@ type (
Recoverable interface{ recoverable() }
// Nontrivial is satisfied by errors preferring a JSON encoding.
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.
@@ -58,6 +65,18 @@ var (
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
// not come from the kernel.
type BadPortError syscall.SockaddrNetlink
@@ -84,6 +103,9 @@ func (c *Conn) Consume(ctx context.Context, events chan<- *Message) error {
for {
data, _, from, err := c.conn.Recvmsg(ctx, 0)
if err != nil {
+ if errors.Is(err, syscall.ENOBUFS) {
+ return ReceiveBufferError{}
+ }
return err
}