mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Force timestamps to update when set via InodeOperations.SetTimestamps.
The gofer's CachingInodeOperations implementation contains an optimization for the common open-read-close pattern when we have a host FD. In this case, the host kernel will update the timestamp for us to a reasonably close time, so we don't need an extra RPC to the gofer. However, when the app explicitly sets the timestamps (via futimes or similar) then we actually DO need to update the timestamps, because the host kernel won't do it for us. To fix this, a new boolean `forceSetTimestamps` was added to CachineInodeOperations.SetMaskedAttributes. It is only set by gofer.InodeOperations.SetTimestamps. PiperOrigin-RevId: 272048146
This commit is contained in:
committed by
gVisor bot
parent
981fc188f0
commit
3ad17ff597
@@ -144,7 +144,7 @@ func (h *HostMappable) Truncate(ctx context.Context, newSize int64) error {
|
||||
|
||||
mask := fs.AttrMask{Size: true}
|
||||
attr := fs.UnstableAttr{Size: newSize}
|
||||
if err := h.backingFile.SetMaskedAttributes(ctx, mask, attr); err != nil {
|
||||
if err := h.backingFile.SetMaskedAttributes(ctx, mask, attr, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -140,12 +140,16 @@ type CachedFileObject interface {
|
||||
// WriteFromBlocksAt may return a partial write without an error.
|
||||
WriteFromBlocksAt(ctx context.Context, srcs safemem.BlockSeq, offset uint64) (uint64, error)
|
||||
|
||||
// SetMaskedAttributes sets the attributes in attr that are true in mask
|
||||
// on the backing file.
|
||||
// SetMaskedAttributes sets the attributes in attr that are true in
|
||||
// mask on the backing file. If the mask contains only ATime or MTime
|
||||
// and the CachedFileObject has an FD to the file, then this operation
|
||||
// is a noop unless forceSetTimestamps is true. This avoids an extra
|
||||
// RPC to the gofer in the open-read/write-close case, when the
|
||||
// timestamps on the file will be updated by the host kernel for us.
|
||||
//
|
||||
// SetMaskedAttributes may be called at any point, regardless of whether
|
||||
// the file was opened.
|
||||
SetMaskedAttributes(ctx context.Context, mask fs.AttrMask, attr fs.UnstableAttr) error
|
||||
SetMaskedAttributes(ctx context.Context, mask fs.AttrMask, attr fs.UnstableAttr, forceSetTimestamps bool) error
|
||||
|
||||
// Allocate allows the caller to reserve disk space for the inode.
|
||||
// It's equivalent to fallocate(2) with 'mode=0'.
|
||||
@@ -224,7 +228,7 @@ func (c *CachingInodeOperations) SetPermissions(ctx context.Context, inode *fs.I
|
||||
|
||||
now := ktime.NowFromContext(ctx)
|
||||
masked := fs.AttrMask{Perms: true}
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, masked, fs.UnstableAttr{Perms: perms}); err != nil {
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, masked, fs.UnstableAttr{Perms: perms}, false); err != nil {
|
||||
return false
|
||||
}
|
||||
c.attr.Perms = perms
|
||||
@@ -246,7 +250,7 @@ func (c *CachingInodeOperations) SetOwner(ctx context.Context, inode *fs.Inode,
|
||||
UID: owner.UID.Ok(),
|
||||
GID: owner.GID.Ok(),
|
||||
}
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, masked, fs.UnstableAttr{Owner: owner}); err != nil {
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, masked, fs.UnstableAttr{Owner: owner}, false); err != nil {
|
||||
return err
|
||||
}
|
||||
if owner.UID.Ok() {
|
||||
@@ -282,7 +286,9 @@ func (c *CachingInodeOperations) SetTimestamps(ctx context.Context, inode *fs.In
|
||||
AccessTime: !ts.ATimeOmit,
|
||||
ModificationTime: !ts.MTimeOmit,
|
||||
}
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, masked, fs.UnstableAttr{AccessTime: ts.ATime, ModificationTime: ts.MTime}); err != nil {
|
||||
// Call SetMaskedAttributes with forceSetTimestamps = true to make sure
|
||||
// the timestamp is updated.
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, masked, fs.UnstableAttr{AccessTime: ts.ATime, ModificationTime: ts.MTime}, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if !ts.ATimeOmit {
|
||||
@@ -305,7 +311,7 @@ func (c *CachingInodeOperations) Truncate(ctx context.Context, inode *fs.Inode,
|
||||
now := ktime.NowFromContext(ctx)
|
||||
masked := fs.AttrMask{Size: true}
|
||||
attr := fs.UnstableAttr{Size: size}
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, masked, attr); err != nil {
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, masked, attr, false); err != nil {
|
||||
c.dataMu.Unlock()
|
||||
return err
|
||||
}
|
||||
@@ -394,7 +400,7 @@ func (c *CachingInodeOperations) WriteOut(ctx context.Context, inode *fs.Inode)
|
||||
c.dirtyAttr.Size = false
|
||||
|
||||
// Write out cached attributes.
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, c.dirtyAttr, c.attr); err != nil {
|
||||
if err := c.backingFile.SetMaskedAttributes(ctx, c.dirtyAttr, c.attr, false); err != nil {
|
||||
c.attrMu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (noopBackingFile) WriteFromBlocksAt(ctx context.Context, srcs safemem.Block
|
||||
return srcs.NumBytes(), nil
|
||||
}
|
||||
|
||||
func (noopBackingFile) SetMaskedAttributes(context.Context, fs.AttrMask, fs.UnstableAttr) error {
|
||||
func (noopBackingFile) SetMaskedAttributes(context.Context, fs.AttrMask, fs.UnstableAttr, bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ func (f *sliceBackingFile) WriteFromBlocksAt(ctx context.Context, srcs safemem.B
|
||||
return w.WriteFromBlocks(srcs)
|
||||
}
|
||||
|
||||
func (*sliceBackingFile) SetMaskedAttributes(context.Context, fs.AttrMask, fs.UnstableAttr) error {
|
||||
func (*sliceBackingFile) SetMaskedAttributes(context.Context, fs.AttrMask, fs.UnstableAttr, bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -215,8 +215,8 @@ func (i *inodeFileState) WriteFromBlocksAt(ctx context.Context, srcs safemem.Blo
|
||||
}
|
||||
|
||||
// SetMaskedAttributes implements fsutil.CachedFileObject.SetMaskedAttributes.
|
||||
func (i *inodeFileState) SetMaskedAttributes(ctx context.Context, mask fs.AttrMask, attr fs.UnstableAttr) error {
|
||||
if i.skipSetAttr(mask) {
|
||||
func (i *inodeFileState) SetMaskedAttributes(ctx context.Context, mask fs.AttrMask, attr fs.UnstableAttr, forceSetTimestamps bool) error {
|
||||
if i.skipSetAttr(mask, forceSetTimestamps) {
|
||||
return nil
|
||||
}
|
||||
as, ans := attr.AccessTime.Unix()
|
||||
@@ -251,13 +251,14 @@ func (i *inodeFileState) SetMaskedAttributes(ctx context.Context, mask fs.AttrMa
|
||||
// when:
|
||||
// - Mask is empty
|
||||
// - Mask contains only attributes that cannot be set in the gofer
|
||||
// - Mask contains only atime and/or mtime, and host FD exists
|
||||
// - forceSetTimestamps is false and mask contains only atime and/or mtime
|
||||
// and host FD exists
|
||||
//
|
||||
// Updates to atime and mtime can be skipped because cached value will be
|
||||
// "close enough" to host value, given that operation went directly to host FD.
|
||||
// Skipping atime updates is particularly important to reduce the number of
|
||||
// operations sent to the Gofer for readonly files.
|
||||
func (i *inodeFileState) skipSetAttr(mask fs.AttrMask) bool {
|
||||
func (i *inodeFileState) skipSetAttr(mask fs.AttrMask, forceSetTimestamps bool) bool {
|
||||
// First remove attributes that cannot be updated.
|
||||
cpy := mask
|
||||
cpy.Type = false
|
||||
@@ -277,6 +278,12 @@ func (i *inodeFileState) skipSetAttr(mask fs.AttrMask) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// If forceSetTimestamps was passed, then we cannot skip.
|
||||
if forceSetTimestamps {
|
||||
return false
|
||||
}
|
||||
|
||||
// Skip if we have a host FD.
|
||||
i.handlesMu.RLock()
|
||||
defer i.handlesMu.RUnlock()
|
||||
return (i.readHandles != nil && i.readHandles.Host != nil) ||
|
||||
|
||||
@@ -114,7 +114,7 @@ func (i *inodeFileState) WriteFromBlocksAt(ctx context.Context, srcs safemem.Blo
|
||||
}
|
||||
|
||||
// SetMaskedAttributes implements fsutil.CachedFileObject.SetMaskedAttributes.
|
||||
func (i *inodeFileState) SetMaskedAttributes(ctx context.Context, mask fs.AttrMask, attr fs.UnstableAttr) error {
|
||||
func (i *inodeFileState) SetMaskedAttributes(ctx context.Context, mask fs.AttrMask, attr fs.UnstableAttr, _ bool) error {
|
||||
if mask.Empty() {
|
||||
return nil
|
||||
}
|
||||
@@ -163,7 +163,7 @@ func (i *inodeFileState) unstableAttr(ctx context.Context) (fs.UnstableAttr, err
|
||||
return unstableAttr(i.mops, &s), nil
|
||||
}
|
||||
|
||||
// SetMaskedAttributes implements fsutil.CachedFileObject.SetMaskedAttributes.
|
||||
// Allocate implements fsutil.CachedFileObject.Allocate.
|
||||
func (i *inodeFileState) Allocate(_ context.Context, offset, length int64) error {
|
||||
return syscall.Fallocate(i.FD(), 0, offset, length)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user