summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs
diff options
context:
space:
mode:
authorNicolas Lacasse <nlacasse@google.com>2018-06-20 13:05:00 -0700
committerShentubot <shentubot@google.com>2018-06-20 13:05:54 -0700
commitd93f55e863c598de9126a0316a813f872b11e29f (patch)
treed80a363f2003108ddd858297a3bd02e4883c0f1b /pkg/sentry/fs
parentaf6f9f56f80027a89ee517b79502ca6183094a39 (diff)
Remove some defers in hot paths in the filesystem code.
PiperOrigin-RevId: 201401727 Change-Id: Ia5589882ba58a00efb522ab372e206b7e8e62aee
Diffstat (limited to 'pkg/sentry/fs')
-rw-r--r--pkg/sentry/fs/fsutil/inode_cached.go89
-rw-r--r--pkg/sentry/fs/inode_overlay.go105
-rw-r--r--pkg/sentry/fs/ramfs/ramfs.go52
3 files changed, 160 insertions, 86 deletions
diff --git a/pkg/sentry/fs/fsutil/inode_cached.go b/pkg/sentry/fs/fsutil/inode_cached.go
index 484668735..7c0f96ac2 100644
--- a/pkg/sentry/fs/fsutil/inode_cached.go
+++ b/pkg/sentry/fs/fsutil/inode_cached.go
@@ -179,8 +179,9 @@ func (c *CachingInodeOperations) Release() {
// UnstableAttr implements fs.InodeOperations.UnstableAttr.
func (c *CachingInodeOperations) UnstableAttr(ctx context.Context, inode *fs.Inode) (fs.UnstableAttr, error) {
c.attrMu.Lock()
- defer c.attrMu.Unlock()
- return c.attr, nil
+ attr := c.attr
+ c.attrMu.Unlock()
+ return attr, nil
}
// SetPermissions implements fs.InodeOperations.SetPermissions.
@@ -463,15 +464,17 @@ func (c *CachingInodeOperations) Read(ctx context.Context, file *fs.File, dst us
//
// If Write partially fills src, a non-nil error is returned.
func (c *CachingInodeOperations) Write(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) {
+ // Hot path. Avoid defers.
if src.NumBytes() == 0 {
return 0, nil
}
c.attrMu.Lock()
- defer c.attrMu.Unlock()
// Compare Linux's mm/filemap.c:__generic_file_write_iter() => file_update_time().
c.touchModificationTimeLocked(ctx)
- return src.CopyInTo(ctx, &inodeReadWriter{ctx, c, offset})
+ n, err := src.CopyInTo(ctx, &inodeReadWriter{ctx, c, offset})
+ c.attrMu.Unlock()
+ return n, err
}
type inodeReadWriter struct {
@@ -482,15 +485,17 @@ type inodeReadWriter struct {
// ReadToBlocks implements safemem.Reader.ReadToBlocks.
func (rw *inodeReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
+ // Hot path. Avoid defers.
rw.c.dataMu.RLock()
- defer rw.c.dataMu.RUnlock()
// Compute the range to read.
if rw.offset >= rw.c.attr.Size {
+ rw.c.dataMu.RUnlock()
return 0, io.EOF
}
end := fs.ReadEndOffset(rw.offset, int64(dsts.NumBytes()), rw.c.attr.Size)
if end == rw.offset { // dsts.NumBytes() == 0?
+ rw.c.dataMu.RUnlock()
return 0, nil
}
@@ -504,6 +509,7 @@ func (rw *inodeReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
// Get internal mappings from the cache.
ims, err := mem.MapInternal(seg.FileRangeOf(seg.Range().Intersect(mr)), usermem.Read)
if err != nil {
+ rw.c.dataMu.RUnlock()
return done, err
}
@@ -513,6 +519,7 @@ func (rw *inodeReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
rw.offset += int64(n)
dsts = dsts.DropFirst64(n)
if err != nil {
+ rw.c.dataMu.RUnlock()
return done, err
}
@@ -529,6 +536,7 @@ func (rw *inodeReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
dsts = dsts.DropFirst64(n)
// Partial reads are fine. But we must stop reading.
if n != dst.NumBytes() || err != nil {
+ rw.c.dataMu.RUnlock()
return done, err
}
@@ -539,38 +547,44 @@ func (rw *inodeReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
break
}
}
+ rw.c.dataMu.RUnlock()
return done, nil
}
+// maybeGrowFile grows the file's size if data has been written past the old
+// size.
+//
+// Preconditions: rw.c.attrMu and rw.c.dataMu bust be locked.
+func (rw *inodeReadWriter) maybeGrowFile() {
+ // If the write ends beyond the file's previous size, it causes the
+ // file to grow.
+ if rw.offset > rw.c.attr.Size {
+ rw.c.attr.Size = rw.offset
+ rw.c.dirtyAttr.Size = true
+ }
+ if rw.offset > rw.c.attr.Usage {
+ // This is incorrect if CachingInodeOperations is caching a sparse
+ // file. (In Linux, keeping inode::i_blocks up to date is the
+ // filesystem's responsibility.)
+ rw.c.attr.Usage = rw.offset
+ rw.c.dirtyAttr.Usage = true
+ }
+}
+
// WriteFromBlocks implements safemem.Writer.WriteFromBlocks.
//
// Preconditions: rw.c.attrMu must be locked.
func (rw *inodeReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) {
+ // Hot path. Avoid defers.
rw.c.dataMu.Lock()
- defer rw.c.dataMu.Unlock()
// Compute the range to write.
end := fs.WriteEndOffset(rw.offset, int64(srcs.NumBytes()))
if end == rw.offset { // srcs.NumBytes() == 0?
+ rw.c.dataMu.Unlock()
return 0, nil
}
- defer func() {
- // If the write ends beyond the file's previous size, it causes the
- // file to grow.
- if rw.offset > rw.c.attr.Size {
- rw.c.attr.Size = rw.offset
- rw.c.dirtyAttr.Size = true
- }
- if rw.offset > rw.c.attr.Usage {
- // This is incorrect if CachingInodeOperations is caching a sparse
- // file. (In Linux, keeping inode::i_blocks up to date is the
- // filesystem's responsibility.)
- rw.c.attr.Usage = rw.offset
- rw.c.dirtyAttr.Usage = true
- }
- }()
-
mem := rw.c.platform.Memory()
var done uint64
seg, gap := rw.c.cache.Find(uint64(rw.offset))
@@ -582,6 +596,8 @@ func (rw *inodeReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error
segMR := seg.Range().Intersect(mr)
ims, err := mem.MapInternal(seg.FileRangeOf(segMR), usermem.Write)
if err != nil {
+ rw.maybeGrowFile()
+ rw.c.dataMu.Unlock()
return done, err
}
@@ -592,6 +608,8 @@ func (rw *inodeReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error
srcs = srcs.DropFirst64(n)
rw.c.dirty.MarkDirty(segMR)
if err != nil {
+ rw.maybeGrowFile()
+ rw.c.dataMu.Unlock()
return done, err
}
@@ -608,6 +626,8 @@ func (rw *inodeReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error
srcs = srcs.DropFirst64(n)
// Partial writes are fine. But we must stop writing.
if n != src.NumBytes() || err != nil {
+ rw.maybeGrowFile()
+ rw.c.dataMu.Unlock()
return done, err
}
@@ -618,13 +638,15 @@ func (rw *inodeReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error
break
}
}
+ rw.maybeGrowFile()
+ rw.c.dataMu.Unlock()
return done, nil
}
// AddMapping implements memmap.Mappable.AddMapping.
func (c *CachingInodeOperations) AddMapping(ctx context.Context, ms memmap.MappingSpace, ar usermem.AddrRange, offset uint64) error {
+ // Hot path. Avoid defers.
c.mapsMu.Lock()
- defer c.mapsMu.Unlock()
mapped := c.mappings.AddMapping(ms, ar, offset)
// Do this unconditionally since whether we have c.backingFile.FD() >= 0
// can change across save/restore.
@@ -636,13 +658,14 @@ func (c *CachingInodeOperations) AddMapping(ctx context.Context, ms memmap.Mappi
usage.MemoryAccounting.Inc(r.Length(), usage.Mapped)
}
}
+ c.mapsMu.Unlock()
return nil
}
// RemoveMapping implements memmap.Mappable.RemoveMapping.
func (c *CachingInodeOperations) RemoveMapping(ctx context.Context, ms memmap.MappingSpace, ar usermem.AddrRange, offset uint64) {
+ // Hot path. Avoid defers.
c.mapsMu.Lock()
- defer c.mapsMu.Unlock()
unmapped := c.mappings.RemoveMapping(ms, ar, offset)
for _, r := range unmapped {
c.hostFileMapper.DecRefOn(r)
@@ -653,6 +676,7 @@ func (c *CachingInodeOperations) RemoveMapping(ctx context.Context, ms memmap.Ma
usage.MemoryAccounting.Dec(r.Length(), usage.Mapped)
}
}
+ c.mapsMu.Unlock()
return
}
@@ -661,7 +685,6 @@ func (c *CachingInodeOperations) RemoveMapping(ctx context.Context, ms memmap.Ma
// strategy.
mem := c.platform.Memory()
c.dataMu.Lock()
- defer c.dataMu.Unlock()
for _, r := range unmapped {
if err := SyncDirty(ctx, r, &c.cache, &c.dirty, uint64(c.attr.Size), c.platform.Memory(), c.backingFile.WriteFromBlocksAt); err != nil {
log.Warningf("Failed to writeback cached data %v: %v", r, err)
@@ -669,6 +692,8 @@ func (c *CachingInodeOperations) RemoveMapping(ctx context.Context, ms memmap.Ma
c.cache.Drop(r, mem)
c.dirty.KeepClean(r)
}
+ c.dataMu.Unlock()
+ c.mapsMu.Unlock()
}
// CopyMapping implements memmap.Mappable.CopyMapping.
@@ -678,6 +703,7 @@ func (c *CachingInodeOperations) CopyMapping(ctx context.Context, ms memmap.Mapp
// Translate implements memmap.Mappable.Translate.
func (c *CachingInodeOperations) Translate(ctx context.Context, required, optional memmap.MappableRange, at usermem.AccessType) ([]memmap.Translation, error) {
+ // Hot path. Avoid defer.
if !c.forcePageCache && c.backingFile.FD() >= 0 {
return []memmap.Translation{
{
@@ -689,7 +715,6 @@ func (c *CachingInodeOperations) Translate(ctx context.Context, required, option
}
c.dataMu.Lock()
- defer c.dataMu.Unlock()
// Constrain translations to c.attr.Size (rounded up) to prevent
// translation to pages that may be concurrently truncated.
@@ -697,6 +722,7 @@ func (c *CachingInodeOperations) Translate(ctx context.Context, required, option
var beyondEOF bool
if required.End > pgend {
if required.Start >= pgend {
+ c.dataMu.Unlock()
return nil, &memmap.BusError{io.EOF}
}
beyondEOF = true
@@ -726,6 +752,8 @@ func (c *CachingInodeOperations) Translate(ctx context.Context, required, option
translatedEnd = segMR.End
}
+ c.dataMu.Unlock()
+
// Don't return the error returned by c.cache.Fill if it occurred outside
// of required.
if translatedEnd < required.End && cerr != nil {
@@ -797,9 +825,8 @@ func (c *CachingInodeOperations) MapInternal(fr platform.FileRange, at usermem.A
// underlying host fd and CachingInodeOperations is used as the platform.File
// during translation.
func (c *CachingInodeOperations) IncRef(fr platform.FileRange) {
+ // Hot path. Avoid defers.
c.dataMu.Lock()
- defer c.dataMu.Unlock()
-
seg, gap := c.refs.Find(fr.Start)
for {
switch {
@@ -815,6 +842,7 @@ func (c *CachingInodeOperations) IncRef(fr platform.FileRange) {
seg, gap = c.refs.InsertWithoutMerging(gap, newRange, 1).NextNonEmpty()
default:
c.refs.MergeAdjacent(fr)
+ c.dataMu.Unlock()
return
}
}
@@ -824,9 +852,8 @@ func (c *CachingInodeOperations) IncRef(fr platform.FileRange) {
// underlying host fd and CachingInodeOperations is used as the platform.File
// during translation.
func (c *CachingInodeOperations) DecRef(fr platform.FileRange) {
+ // Hot path. Avoid defers.
c.dataMu.Lock()
- defer c.dataMu.Unlock()
-
seg := c.refs.FindSegment(fr.Start)
for seg.Ok() && seg.Start() < fr.End {
@@ -842,4 +869,6 @@ func (c *CachingInodeOperations) DecRef(fr platform.FileRange) {
}
}
c.refs.MergeAdjacent(fr)
+ c.dataMu.Unlock()
+
}
diff --git a/pkg/sentry/fs/inode_overlay.go b/pkg/sentry/fs/inode_overlay.go
index 343150bb8..53fbd1481 100644
--- a/pkg/sentry/fs/inode_overlay.go
+++ b/pkg/sentry/fs/inode_overlay.go
@@ -34,20 +34,23 @@ func overlayCreateWhiteout(parent *Inode, name string) error {
}
func overlayWriteOut(ctx context.Context, o *overlayEntry) error {
+ // Hot path. Avoid defers.
+ var err error
o.copyMu.RLock()
- defer o.copyMu.RUnlock()
- if o.upper == nil {
- return nil
+ if o.upper != nil {
+ err = o.upper.InodeOperations.WriteOut(ctx, o.upper)
}
- return o.upper.InodeOperations.WriteOut(ctx, o.upper)
+ o.copyMu.RUnlock()
+ return err
}
func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name string) (*Dirent, error) {
+ // Hot path. Avoid defers.
parent.copyMu.RLock()
- defer parent.copyMu.RUnlock()
// Assert that there is at least one upper or lower entry.
if parent.upper == nil && parent.lower == nil {
+ parent.copyMu.RUnlock()
panic("invalid overlayEntry, needs at least one Inode")
}
@@ -63,30 +66,33 @@ func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name
if err != nil && err != syserror.ENOENT {
// We encountered an error that an overlay cannot handle,
// we must propagate it to the caller.
+ parent.copyMu.RUnlock()
return nil, err
}
if child != nil {
- defer child.DecRef()
-
- // Is the child non-negative?
if !child.IsNegative() {
upperInode = child.Inode
upperInode.IncRef()
}
+ child.DecRef()
}
// Are we done?
if overlayHasWhiteout(parent.upper, name) {
if upperInode == nil {
+ parent.copyMu.RUnlock()
return NewNegativeDirent(name), nil
}
entry, err := newOverlayEntry(ctx, upperInode, nil, false)
if err != nil {
// Don't leak resources.
upperInode.DecRef()
+ parent.copyMu.RUnlock()
return nil, err
}
- return NewDirent(newOverlayInode(ctx, entry, inode.MountSource), name), nil
+ d, err := NewDirent(newOverlayInode(ctx, entry, inode.MountSource), name), nil
+ parent.copyMu.RUnlock()
+ return d, err
}
}
@@ -103,12 +109,10 @@ func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name
if upperInode != nil {
upperInode.DecRef()
}
+ parent.copyMu.RUnlock()
return nil, err
}
if child != nil {
- defer child.DecRef()
-
- // Is the child negative?
if !child.IsNegative() {
// Did we find something in the upper filesystem? We can
// only use it if the types match.
@@ -117,12 +121,14 @@ func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name
lowerInode.IncRef()
}
}
+ child.DecRef()
}
}
// Was all of this for naught?
if upperInode == nil && lowerInode == nil {
// Return a negative Dirent indicating that nothing was found.
+ parent.copyMu.RUnlock()
return NewNegativeDirent(name), nil
}
@@ -157,9 +163,12 @@ func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name
if lowerInode != nil {
lowerInode.DecRef()
}
+ parent.copyMu.RUnlock()
return nil, err
}
- return NewDirent(newOverlayInode(ctx, entry, inode.MountSource), name), nil
+ d, err := NewDirent(newOverlayInode(ctx, entry, inode.MountSource), name), nil
+ parent.copyMu.RUnlock()
+ return d, err
}
func overlayCreate(ctx context.Context, o *overlayEntry, parent *Dirent, name string, flags FileFlags, perm FilePermissions) (*File, error) {
@@ -349,6 +358,7 @@ func overlayBoundEndpoint(o *overlayEntry, path string) unix.BoundEndpoint {
}
func overlayGetFile(ctx context.Context, o *overlayEntry, d *Dirent, flags FileFlags) (*File, error) {
+ // Hot path. Avoid defers.
if flags.Write {
if err := copyUp(ctx, d); err != nil {
return nil, err
@@ -356,48 +366,69 @@ func overlayGetFile(ctx context.Context, o *overlayEntry, d *Dirent, flags FileF
}
o.copyMu.RLock()
- defer o.copyMu.RUnlock()
if o.upper != nil {
upper, err := overlayFile(ctx, o.upper, flags)
if err != nil {
+ o.copyMu.RUnlock()
return nil, err
}
flags.Pread = upper.Flags().Pread
flags.Pwrite = upper.Flags().Pwrite
- return NewFile(ctx, d, flags, &overlayFileOperations{upper: upper}), nil
+ f, err := NewFile(ctx, d, flags, &overlayFileOperations{upper: upper}), nil
+ o.copyMu.RUnlock()
+ return f, err
}
lower, err := overlayFile(ctx, o.lower, flags)
if err != nil {
+ o.copyMu.RUnlock()
return nil, err
}
flags.Pread = lower.Flags().Pread
flags.Pwrite = lower.Flags().Pwrite
+ o.copyMu.RUnlock()
return NewFile(ctx, d, flags, &overlayFileOperations{lower: lower}), nil
}
func overlayUnstableAttr(ctx context.Context, o *overlayEntry) (UnstableAttr, error) {
+ // Hot path. Avoid defers.
+ var (
+ attr UnstableAttr
+ err error
+ )
o.copyMu.RLock()
- defer o.copyMu.RUnlock()
if o.upper != nil {
- return o.upper.UnstableAttr(ctx)
+ attr, err = o.upper.UnstableAttr(ctx)
+ } else {
+ attr, err = o.lower.UnstableAttr(ctx)
}
- return o.lower.UnstableAttr(ctx)
+ o.copyMu.RUnlock()
+ return attr, err
}
func overlayGetxattr(o *overlayEntry, name string) ([]byte, error) {
+ // Hot path. This is how the overlay checks for whiteout files.
+ // Avoid defers.
+ var (
+ b []byte
+ err error
+ )
+
// Don't forward the value of the extended attribute if it would
// unexpectedly change the behavior of a wrapping overlay layer.
if strings.HasPrefix(XattrOverlayPrefix, name) {
return nil, syserror.ENODATA
}
+
o.copyMu.RLock()
- defer o.copyMu.RUnlock()
if o.upper != nil {
- return o.upper.Getxattr(name)
+ b, err = o.upper.Getxattr(name)
+ } else {
+ b, err = o.lower.Getxattr(name)
}
- return o.lower.Getxattr(name)
+ o.copyMu.RUnlock()
+ return b, err
}
func overlayListxattr(o *overlayEntry) (map[string]struct{}, error) {
@@ -422,17 +453,21 @@ func overlayListxattr(o *overlayEntry) (map[string]struct{}, error) {
func overlayCheck(ctx context.Context, o *overlayEntry, p PermMask) error {
o.copyMu.RLock()
- defer o.copyMu.RUnlock()
+ // Hot path. Avoid defers.
+ var err error
if o.upper != nil {
- return o.upper.check(ctx, p)
- }
- if p.Write {
- // Since writes will be redirected to the upper filesystem, the lower
- // filesystem need not be writable, but must be readable for copy-up.
- p.Write = false
- p.Read = true
+ err = o.upper.check(ctx, p)
+ } else {
+ if p.Write {
+ // Since writes will be redirected to the upper filesystem, the lower
+ // filesystem need not be writable, but must be readable for copy-up.
+ p.Write = false
+ p.Read = true
+ }
+ err = o.lower.check(ctx, p)
}
- return o.lower.check(ctx, p)
+ o.copyMu.RUnlock()
+ return err
}
func overlaySetPermissions(ctx context.Context, o *overlayEntry, d *Dirent, f FilePermissions) bool {
@@ -520,12 +555,16 @@ func overlayStatFS(ctx context.Context, o *overlayEntry) (Info, error) {
}
func overlayHandleOps(o *overlayEntry) HandleOperations {
+ // Hot path. Avoid defers.
+ var hops HandleOperations
o.copyMu.RLock()
- defer o.copyMu.RUnlock()
if o.upper != nil {
- return o.upper.HandleOps()
+ hops = o.upper.HandleOps()
+ } else {
+ hops = o.lower.HandleOps()
}
- return o.lower.HandleOps()
+ o.copyMu.RUnlock()
+ return hops
}
// NewTestOverlayDir returns an overlay Inode for tests.
diff --git a/pkg/sentry/fs/ramfs/ramfs.go b/pkg/sentry/fs/ramfs/ramfs.go
index 04f2d38de..90b6c9a4f 100644
--- a/pkg/sentry/fs/ramfs/ramfs.go
+++ b/pkg/sentry/fs/ramfs/ramfs.go
@@ -95,8 +95,9 @@ func (e *Entry) InitEntryWithAttr(ctx context.Context, uattr fs.UnstableAttr) {
// UnstableAttr implements fs.InodeOperations.UnstableAttr.
func (e *Entry) UnstableAttr(ctx context.Context, inode *fs.Inode) (fs.UnstableAttr, error) {
e.mu.Lock()
- defer e.mu.Unlock()
- return e.unstable, nil
+ attr := e.unstable
+ e.mu.Unlock()
+ return attr, nil
}
// Check implements fs.InodeOperations.Check.
@@ -106,9 +107,11 @@ func (*Entry) Check(ctx context.Context, inode *fs.Inode, p fs.PermMask) bool {
// Getxattr implements fs.InodeOperations.Getxattr.
func (e *Entry) Getxattr(inode *fs.Inode, name string) ([]byte, error) {
+ // Hot path. Avoid defers.
e.mu.Lock()
- defer e.mu.Unlock()
- if value, ok := e.xattrs[name]; ok {
+ value, ok := e.xattrs[name]
+ e.mu.Unlock()
+ if ok {
return value, nil
}
return nil, syserror.ENOATTR
@@ -117,19 +120,19 @@ func (e *Entry) Getxattr(inode *fs.Inode, name string) ([]byte, error) {
// Setxattr implements fs.InodeOperations.Setxattr.
func (e *Entry) Setxattr(inode *fs.Inode, name string, value []byte) error {
e.mu.Lock()
- defer e.mu.Unlock()
e.xattrs[name] = value
+ e.mu.Unlock()
return nil
}
// Listxattr implements fs.InodeOperations.Listxattr.
func (e *Entry) Listxattr(inode *fs.Inode) (map[string]struct{}, error) {
e.mu.Lock()
- defer e.mu.Unlock()
names := make(map[string]struct{}, len(e.xattrs))
for name := range e.xattrs {
names[name] = struct{}{}
}
+ e.mu.Unlock()
return names, nil
}
@@ -141,22 +144,22 @@ func (*Entry) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*f
// SetPermissions always sets the permissions.
func (e *Entry) SetPermissions(ctx context.Context, inode *fs.Inode, p fs.FilePermissions) bool {
e.mu.Lock()
- defer e.mu.Unlock()
e.unstable.Perms = p
e.unstable.StatusChangeTime = ktime.NowFromContext(ctx)
+ e.mu.Unlock()
return true
}
// SetOwner always sets ownership.
func (e *Entry) SetOwner(ctx context.Context, inode *fs.Inode, owner fs.FileOwner) error {
e.mu.Lock()
- defer e.mu.Unlock()
if owner.UID.Ok() {
e.unstable.Owner.UID = owner.UID
}
if owner.GID.Ok() {
e.unstable.Owner.GID = owner.GID
}
+ e.mu.Unlock()
return nil
}
@@ -167,8 +170,6 @@ func (e *Entry) SetTimestamps(ctx context.Context, inode *fs.Inode, ts fs.TimeSp
}
e.mu.Lock()
- defer e.mu.Unlock()
-
now := ktime.NowFromContext(ctx)
if !ts.ATimeOmit {
if ts.ATimeSetSystemTime {
@@ -185,59 +186,64 @@ func (e *Entry) SetTimestamps(ctx context.Context, inode *fs.Inode, ts fs.TimeSp
}
}
e.unstable.StatusChangeTime = now
+ e.mu.Unlock()
return nil
}
// NotifyStatusChange updates the status change time (ctime).
func (e *Entry) NotifyStatusChange(ctx context.Context) {
e.mu.Lock()
- defer e.mu.Unlock()
e.unstable.StatusChangeTime = ktime.NowFromContext(ctx)
+ e.mu.Unlock()
}
// StatusChangeTime returns the last status change time for this node.
func (e *Entry) StatusChangeTime() ktime.Time {
e.mu.Lock()
- defer e.mu.Unlock()
- return e.unstable.StatusChangeTime
+ t := e.unstable.StatusChangeTime
+ e.mu.Unlock()
+ return t
}
// NotifyModification updates the modification time and the status change time.
func (e *Entry) NotifyModification(ctx context.Context) {
e.mu.Lock()
- defer e.mu.Unlock()
now := ktime.NowFromContext(ctx)
e.unstable.ModificationTime = now
e.unstable.StatusChangeTime = now
+ e.mu.Unlock()
}
// ModificationTime returns the last modification time for this node.
func (e *Entry) ModificationTime() ktime.Time {
e.mu.Lock()
- defer e.mu.Unlock()
- return e.unstable.ModificationTime
+ t := e.unstable.ModificationTime
+ e.mu.Unlock()
+ return t
}
// NotifyAccess updates the access time.
func (e *Entry) NotifyAccess(ctx context.Context) {
e.mu.Lock()
- defer e.mu.Unlock()
now := ktime.NowFromContext(ctx)
e.unstable.AccessTime = now
+ e.mu.Unlock()
}
// AccessTime returns the last access time for this node.
func (e *Entry) AccessTime() ktime.Time {
e.mu.Lock()
- defer e.mu.Unlock()
- return e.unstable.AccessTime
+ t := e.unstable.AccessTime
+ e.mu.Unlock()
+ return t
}
// Permissions returns permissions on this entry.
func (e *Entry) Permissions() fs.FilePermissions {
e.mu.Lock()
- defer e.mu.Unlock()
- return e.unstable.Perms
+ p := e.unstable.Perms
+ e.mu.Unlock()
+ return p
}
// Lookup is not supported by default.
@@ -379,15 +385,15 @@ func (e *Entry) Release(context.Context) {}
// AddLink implements InodeOperationss.AddLink.
func (e *Entry) AddLink() {
e.mu.Lock()
- defer e.mu.Unlock()
e.unstable.Links++
+ e.mu.Unlock()
}
// DropLink implements InodeOperationss.DropLink.
func (e *Entry) DropLink() {
e.mu.Lock()
- defer e.mu.Unlock()
e.unstable.Links--
+ e.mu.Unlock()
}
// DeprecatedReaddir is not supported by default.