[vfs2] Make gofer metadata atomics consistent

For accessing metadata fields:
- If metadataMu is locked, we can access without atomics
- If metadataMu is unlocked, we should use atomics

For mutating metadata fields:
- Always lock metadataMu and use atomics.

There were some instances of inconsistencies which have been fixed.

PiperOrigin-RevId: 321022895
This commit is contained in:
Ayush Ranjan
2020-07-13 13:35:32 -07:00
committed by gVisor bot
parent b8d3d09bd1
commit 6994f4d591
2 changed files with 18 additions and 10 deletions
+15 -9
View File
@@ -602,8 +602,14 @@ type dentry struct {
// returned by the server. dirents is protected by dirMu.
dirents []vfs.Dirent
// Cached metadata; protected by metadataMu and accessed using atomic
// memory operations unless otherwise specified.
// Cached metadata; protected by metadataMu.
// To access:
// - In situations where consistency is not required (like stat), these
// can be accessed using atomic operations only (without locking).
// - Lock metadataMu and can access without atomic operations.
// To mutate:
// - Lock metadataMu and use atomic operations to update because we might
// have atomic readers that don't hold the lock.
metadataMu sync.Mutex
ino inodeNumber // immutable
mode uint32 // type is immutable, perms are mutable
@@ -616,7 +622,7 @@ type dentry struct {
ctime int64
btime int64
// File size, protected by both metadataMu and dataMu (i.e. both must be
// locked to mutate it).
// locked to mutate it; locking either is sufficient to access it).
size uint64
// nlink counts the number of hard links to this dentry. It's updated and
@@ -904,14 +910,14 @@ func (d *dentry) setStat(ctx context.Context, creds *auth.Credentials, stat *lin
// Prepare for truncate.
if stat.Mask&linux.STATX_SIZE != 0 {
switch d.mode & linux.S_IFMT {
case linux.S_IFREG:
switch mode.FileType() {
case linux.ModeRegular:
if !setLocalMtime {
// Truncate updates mtime.
setLocalMtime = true
stat.Mtime.Nsec = linux.UTIME_NOW
}
case linux.S_IFDIR:
case linux.ModeDirectory:
return syserror.EISDIR
default:
return syserror.EINVAL
@@ -994,7 +1000,7 @@ func (d *dentry) setStat(ctx context.Context, creds *auth.Credentials, stat *lin
func (d *dentry) updateFileSizeLocked(newSize uint64) {
d.dataMu.Lock()
oldSize := d.size
d.size = newSize
atomic.StoreUint64(&d.size, newSize)
// d.dataMu must be unlocked to lock d.mapsMu and invalidate mappings
// below. This allows concurrent calls to Read/Translate/etc. These
// functions synchronize with truncation by refusing to use cache
@@ -1340,8 +1346,8 @@ func (d *dentry) removexattr(ctx context.Context, creds *auth.Credentials, name
// Extended attributes in the user.* namespace are only supported for regular
// files and directories.
func (d *dentry) userXattrSupported() bool {
filetype := linux.S_IFMT & atomic.LoadUint32(&d.mode)
return filetype == linux.S_IFREG || filetype == linux.S_IFDIR
filetype := linux.FileMode(atomic.LoadUint32(&d.mode)).FileType()
return filetype == linux.ModeRegular || filetype == linux.ModeDirectory
}
// Preconditions: !d.isSynthetic(). d.isRegularFile() || d.isDir().
+3 -1
View File
@@ -89,7 +89,9 @@ func (fd *regularFileFD) Allocate(ctx context.Context, mode, offset, length uint
if err != nil {
return err
}
d.size = size
d.dataMu.Lock()
atomic.StoreUint64(&d.size, size)
d.dataMu.Unlock()
if !d.cachedMetadataAuthoritative() {
d.touchCMtimeLocked()
}