summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/kernel/fasync
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/kernel/fasync')
-rw-r--r--pkg/sentry/kernel/fasync/fasync.go45
-rwxr-xr-xpkg/sentry/kernel/fasync/fasync_state_autogen.go2
2 files changed, 37 insertions, 10 deletions
diff --git a/pkg/sentry/kernel/fasync/fasync.go b/pkg/sentry/kernel/fasync/fasync.go
index bcaca58f7..6b0bb0324 100644
--- a/pkg/sentry/kernel/fasync/fasync.go
+++ b/pkg/sentry/kernel/fasync/fasync.go
@@ -34,9 +34,23 @@ func New() fs.FileAsync {
//
// +stateify savable
type FileAsync struct {
- mu sync.Mutex `state:"nosave"`
- e waiter.Entry
- requester *auth.Credentials
+ // e is immutable after first use (which is protected by mu below).
+ e waiter.Entry
+
+ // regMu protects registeration and unregistration actions on e.
+ //
+ // regMu must be held while registration decisions are being made
+ // through the registration action itself.
+ //
+ // Lock ordering: regMu, mu.
+ regMu sync.Mutex `state:"nosave"`
+
+ // mu protects all following fields.
+ //
+ // Lock ordering: e.mu, mu.
+ mu sync.Mutex `state:"nosave"`
+ requester *auth.Credentials
+ registered bool
// Only one of the following is allowed to be non-nil.
recipientPG *kernel.ProcessGroup
@@ -47,7 +61,7 @@ type FileAsync struct {
// Callback sends a signal.
func (a *FileAsync) Callback(e *waiter.Entry) {
a.mu.Lock()
- if a.e.Callback == nil {
+ if !a.registered {
a.mu.Unlock()
return
}
@@ -80,14 +94,21 @@ func (a *FileAsync) Callback(e *waiter.Entry) {
//
// The file must not be currently registered.
func (a *FileAsync) Register(w waiter.Waitable) {
+ a.regMu.Lock()
+ defer a.regMu.Unlock()
a.mu.Lock()
- defer a.mu.Unlock()
- if a.e.Callback != nil {
+ if a.registered {
+ a.mu.Unlock()
panic("registering already registered file")
}
- a.e.Callback = a
+ if a.e.Callback == nil {
+ a.e.Callback = a
+ }
+ a.registered = true
+
+ a.mu.Unlock()
w.EventRegister(&a.e, waiter.EventIn|waiter.EventOut|waiter.EventErr|waiter.EventHUp)
}
@@ -95,15 +116,19 @@ func (a *FileAsync) Register(w waiter.Waitable) {
//
// The file must be currently registered.
func (a *FileAsync) Unregister(w waiter.Waitable) {
+ a.regMu.Lock()
+ defer a.regMu.Unlock()
a.mu.Lock()
- defer a.mu.Unlock()
- if a.e.Callback == nil {
+ if !a.registered {
+ a.mu.Unlock()
panic("unregistering unregistered file")
}
+ a.registered = false
+
+ a.mu.Unlock()
w.EventUnregister(&a.e)
- a.e.Callback = nil
}
// Owner returns who is currently getting signals. All return values will be
diff --git a/pkg/sentry/kernel/fasync/fasync_state_autogen.go b/pkg/sentry/kernel/fasync/fasync_state_autogen.go
index 0ffb3f7ad..c17daa8a1 100755
--- a/pkg/sentry/kernel/fasync/fasync_state_autogen.go
+++ b/pkg/sentry/kernel/fasync/fasync_state_autogen.go
@@ -11,6 +11,7 @@ func (x *FileAsync) save(m state.Map) {
x.beforeSave()
m.Save("e", &x.e)
m.Save("requester", &x.requester)
+ m.Save("registered", &x.registered)
m.Save("recipientPG", &x.recipientPG)
m.Save("recipientTG", &x.recipientTG)
m.Save("recipientT", &x.recipientT)
@@ -20,6 +21,7 @@ func (x *FileAsync) afterLoad() {}
func (x *FileAsync) load(m state.Map) {
m.Load("e", &x.e)
m.Load("requester", &x.requester)
+ m.Load("registered", &x.registered)
m.Load("recipientPG", &x.recipientPG)
m.Load("recipientTG", &x.recipientTG)
m.Load("recipientT", &x.recipientT)