summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/file.go
diff options
context:
space:
mode:
authorIan Gudger <igudger@google.com>2018-06-21 10:52:33 -0700
committerShentubot <shentubot@google.com>2018-06-21 10:53:21 -0700
commitd571a4359cebbcf8a9b201bb125f1cdc9fb126e4 (patch)
tree53d993db5ab045897c4ad50bb73670e3f018ffea /pkg/sentry/fs/file.go
parentf2a687001ded18a4343c1aa3bfba18b08c6a816a (diff)
Implement ioctl(FIOASYNC)
FIOASYNC and friends are used to send signals when a file is ready for IO. This may or may not be needed by Nginx. While Nginx does use it, it is unclear if the code that uses it has any effect. PiperOrigin-RevId: 201550828 Change-Id: I7ba05a7db4eb2dfffde11e9bd9a35b65b98d7f50
Diffstat (limited to 'pkg/sentry/fs/file.go')
-rw-r--r--pkg/sentry/fs/file.go62
1 files changed, 54 insertions, 8 deletions
diff --git a/pkg/sentry/fs/file.go b/pkg/sentry/fs/file.go
index f2683bbd2..6d93ef760 100644
--- a/pkg/sentry/fs/file.go
+++ b/pkg/sentry/fs/file.go
@@ -16,6 +16,7 @@ package fs
import (
"math"
+ "sync"
"sync/atomic"
"gvisor.googlesource.com/gvisor/pkg/amutex"
@@ -72,9 +73,15 @@ type File struct {
// other files via the Dirent cache.
Dirent *Dirent
+ // flagsMu protects flags and async below.
+ flagsMu sync.Mutex `state:"nosave"`
+
// flags are the File's flags. Setting or getting flags is fully atomic
// and is not protected by mu (below).
- flags atomic.Value `state:".(FileFlags)"`
+ flags FileFlags
+
+ // async handles O_ASYNC notifications.
+ async FileAsync
// mu is dual-purpose: first, to make read(2) and write(2) thread-safe
// in conformity with POSIX, and second, to cancel operations before they
@@ -99,8 +106,8 @@ func NewFile(ctx context.Context, dirent *Dirent, flags FileFlags, fops FileOper
UniqueID: uniqueid.GlobalFromContext(ctx),
Dirent: dirent,
FileOperations: fops,
+ flags: flags,
}
- f.flags.Store(flags)
f.mu.Init()
return f
}
@@ -117,22 +124,40 @@ func (f *File) DecRef() {
// Release a reference on the Dirent.
f.Dirent.DecRef()
+
+ f.flagsMu.Lock()
+ if f.flags.Async && f.async != nil {
+ f.async.Unregister(f)
+ }
+ f.flagsMu.Unlock()
})
}
// Flags atomically loads the File's flags.
func (f *File) Flags() FileFlags {
- return f.flags.Load().(FileFlags)
+ f.flagsMu.Lock()
+ flags := f.flags
+ f.flagsMu.Unlock()
+ return flags
}
// SetFlags atomically changes the File's flags to the values contained
// in newFlags. See SettableFileFlags for values that can be set.
func (f *File) SetFlags(newFlags SettableFileFlags) {
- flags := f.flags.Load().(FileFlags)
- flags.Direct = newFlags.Direct
- flags.NonBlocking = newFlags.NonBlocking
- flags.Append = newFlags.Append
- f.flags.Store(flags)
+ f.flagsMu.Lock()
+ f.flags.Direct = newFlags.Direct
+ f.flags.NonBlocking = newFlags.NonBlocking
+ f.flags.Append = newFlags.Append
+ if f.async != nil {
+ if newFlags.Async && !f.flags.Async {
+ f.async.Register(f)
+ }
+ if !newFlags.Async && f.flags.Async {
+ f.async.Unregister(f)
+ }
+ }
+ f.flags.Async = newFlags.Async
+ f.flagsMu.Unlock()
}
// Offset atomically loads the File's offset.
@@ -361,6 +386,27 @@ func (f *File) Msync(ctx context.Context, mr memmap.MappableRange) error {
return f.Fsync(ctx, int64(mr.Start), int64(mr.End-1), SyncData)
}
+// A FileAsync sends signals to its owner when w is ready for IO.
+type FileAsync interface {
+ Register(w waiter.Waitable)
+ Unregister(w waiter.Waitable)
+}
+
+// Async gets the stored FileAsync or creates a new one with the supplied
+// function. If the supplied function is nil, no FileAsync is created and the
+// current value is returned.
+func (f *File) Async(newAsync func() FileAsync) FileAsync {
+ f.flagsMu.Lock()
+ defer f.flagsMu.Unlock()
+ if f.async == nil && newAsync != nil {
+ f.async = newAsync()
+ if f.flags.Async {
+ f.async.Register(f)
+ }
+ }
+ return f.async
+}
+
// FileReader implements io.Reader and io.ReaderAt.
type FileReader struct {
// Ctx is the context for the file reader.