diff options
author | Ian Gudger <igudger@google.com> | 2018-06-21 10:52:33 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-06-21 10:53:21 -0700 |
commit | d571a4359cebbcf8a9b201bb125f1cdc9fb126e4 (patch) | |
tree | 53d993db5ab045897c4ad50bb73670e3f018ffea /pkg/sentry/fs | |
parent | f2a687001ded18a4343c1aa3bfba18b08c6a816a (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')
-rw-r--r-- | pkg/sentry/fs/file.go | 62 | ||||
-rw-r--r-- | pkg/sentry/fs/file_state.go | 10 | ||||
-rw-r--r-- | pkg/sentry/fs/flags.go | 7 |
3 files changed, 61 insertions, 18 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. diff --git a/pkg/sentry/fs/file_state.go b/pkg/sentry/fs/file_state.go index 341cbda0b..3384737ab 100644 --- a/pkg/sentry/fs/file_state.go +++ b/pkg/sentry/fs/file_state.go @@ -18,13 +18,3 @@ package fs func (f *File) afterLoad() { f.mu.Init() } - -// saveFlags is invoked by stateify. -func (f *File) saveFlags() FileFlags { - return f.flags.Load().(FileFlags) -} - -// loadFlags is invoked by stateify. -func (f *File) loadFlags(flags FileFlags) { - f.flags.Store(flags) -} diff --git a/pkg/sentry/fs/flags.go b/pkg/sentry/fs/flags.go index dfa6a3d62..7a8eefd02 100644 --- a/pkg/sentry/fs/flags.go +++ b/pkg/sentry/fs/flags.go @@ -42,6 +42,9 @@ type FileFlags struct { // Directory indicates that this file must be a directory. Directory bool + + // Async indicates that this file sends signals on IO events. + Async bool } // SettableFileFlags is a subset of FileFlags above that can be changed @@ -55,6 +58,9 @@ type SettableFileFlags struct { // Append indicates this file is append only. Append bool + + // Async indicates that this file sends signals on IO events. + Async bool } // Settable returns the subset of f that are settable. @@ -63,5 +69,6 @@ func (f FileFlags) Settable() SettableFileFlags { Direct: f.Direct, NonBlocking: f.NonBlocking, Append: f.Append, + Async: f.Async, } } |