[vfs2][gofer] Fix update attributes race condition.

We were getting the file attributes before locking the metadataMu which was
causing stale updates to the file attributes.

Fixes OpenTest_AppendConcurrentWrite.

Updates #2923

PiperOrigin-RevId: 322804438
This commit is contained in:
Ayush Ranjan
2020-07-23 09:45:26 -07:00
committed by gVisor bot
parent 36257e6b7b
commit 4fbd0728ac
2 changed files with 20 additions and 8 deletions
+13 -4
View File
@@ -150,11 +150,9 @@ afterSymlink:
return nil, err
}
if d != d.parent && !d.cachedMetadataAuthoritative() {
_, attrMask, attr, err := d.parent.file.getAttr(ctx, dentryAttrMask())
if err != nil {
if err := d.parent.updateFromGetattr(ctx); err != nil {
return nil, err
}
d.parent.updateFromP9Attrs(attrMask, &attr)
}
rp.Advance()
return d.parent, nil
@@ -209,17 +207,28 @@ func (fs *filesystem) getChildLocked(ctx context.Context, vfsObj *vfs.VirtualFil
// Preconditions: As for getChildLocked. !parent.isSynthetic().
func (fs *filesystem) revalidateChildLocked(ctx context.Context, vfsObj *vfs.VirtualFilesystem, parent *dentry, name string, child *dentry, ds **[]*dentry) (*dentry, error) {
if child != nil {
// Need to lock child.metadataMu because we might be updating child
// metadata. We need to hold the lock *before* getting metadata from the
// server and release it after updating local metadata.
child.metadataMu.Lock()
}
qid, file, attrMask, attr, err := parent.file.walkGetAttrOne(ctx, name)
if err != nil && err != syserror.ENOENT {
if child != nil {
child.metadataMu.Unlock()
}
return nil, err
}
if child != nil {
if !file.isNil() && inoFromPath(qid.Path) == child.ino {
// The file at this path hasn't changed. Just update cached metadata.
file.close(ctx)
child.updateFromP9Attrs(attrMask, &attr)
child.updateFromP9AttrsLocked(attrMask, &attr)
child.metadataMu.Unlock()
return child, nil
}
child.metadataMu.Unlock()
if file.isNil() && child.isSynthetic() {
// We have a synthetic file, and no remote file has arisen to
// replace it.
+7 -4
View File
@@ -785,8 +785,8 @@ func (d *dentry) cachedMetadataAuthoritative() bool {
// updateFromP9Attrs is called to update d's metadata after an update from the
// remote filesystem.
func (d *dentry) updateFromP9Attrs(mask p9.AttrMask, attr *p9.Attr) {
d.metadataMu.Lock()
// Precondition: d.metadataMu must be locked.
func (d *dentry) updateFromP9AttrsLocked(mask p9.AttrMask, attr *p9.Attr) {
if mask.Mode {
if got, want := uint32(attr.Mode.FileType()), d.fileType(); got != want {
d.metadataMu.Unlock()
@@ -822,7 +822,6 @@ func (d *dentry) updateFromP9Attrs(mask p9.AttrMask, attr *p9.Attr) {
if mask.Size {
d.updateFileSizeLocked(attr.Size)
}
d.metadataMu.Unlock()
}
// Preconditions: !d.isSynthetic()
@@ -834,6 +833,10 @@ func (d *dentry) updateFromGetattr(ctx context.Context) error {
file p9file
handleMuRLocked bool
)
// d.metadataMu must be locked *before* we getAttr so that we do not end up
// updating stale attributes in d.updateFromP9AttrsLocked().
d.metadataMu.Lock()
defer d.metadataMu.Unlock()
d.handleMu.RLock()
if !d.handle.file.isNil() {
file = d.handle.file
@@ -849,7 +852,7 @@ func (d *dentry) updateFromGetattr(ctx context.Context) error {
if err != nil {
return err
}
d.updateFromP9Attrs(attrMask, &attr)
d.updateFromP9AttrsLocked(attrMask, &attr)
return nil
}