diff --git a/pkg/sentry/fsimpl/tmpfs/filesystem.go b/pkg/sentry/fsimpl/tmpfs/filesystem.go index 59b2efe4e..b4ad1b054 100644 --- a/pkg/sentry/fsimpl/tmpfs/filesystem.go +++ b/pkg/sentry/fsimpl/tmpfs/filesystem.go @@ -971,21 +971,22 @@ func (fs *filesystem) accountPagesPartial(pagesInc uint64) uint64 { return pagesInc } - // Need to acquire fs.pagesUsedMu for fs.pagesUsed. - fs.pagesUsedMu.Lock() - defer fs.pagesUsedMu.Unlock() - if fs.maxSizeInPages <= fs.pagesUsed { - return 0 - } + for { + pagesUsed := fs.pagesUsed.Load() + if fs.maxSizeInPages <= pagesUsed { + return 0 + } - pagesFree := fs.maxSizeInPages - fs.pagesUsed - if pagesFree < pagesInc { - fs.pagesUsed += pagesFree - return pagesFree - } + pagesFree := fs.maxSizeInPages - pagesUsed + toInc := pagesInc + if pagesFree < pagesInc { + toInc = pagesFree + } - fs.pagesUsed += pagesInc - return pagesInc + if fs.pagesUsed.CompareAndSwap(pagesUsed, pagesUsed+toInc) { + return toInc + } + } } // accountPages increases the pagesUsed in filesystem struct if tmpfs @@ -996,20 +997,21 @@ func (fs *filesystem) accountPages(pagesInc uint64) bool { return true // No accounting needed. } - // Need to acquire fs.pagesUsedMu for fs.pagesUsed. - fs.pagesUsedMu.Lock() - defer fs.pagesUsedMu.Unlock() - if fs.maxSizeInPages <= fs.pagesUsed { - return false - } + for { + pagesUsed := fs.pagesUsed.Load() + if fs.maxSizeInPages <= pagesUsed { + return false + } - pagesFree := fs.maxSizeInPages - fs.pagesUsed - if pagesFree < pagesInc { - return false - } + pagesFree := fs.maxSizeInPages - pagesUsed + if pagesFree < pagesInc { + return false + } - fs.pagesUsed += pagesInc - return true + if fs.pagesUsed.CompareAndSwap(pagesUsed, pagesUsed+pagesInc) { + return true + } + } } // unaccountPages decreases the pagesUsed in filesystem struct if tmpfs @@ -1018,11 +1020,14 @@ func (fs *filesystem) unaccountPages(pagesDec uint64) { if fs.maxSizeInPages == 0 || pagesDec == 0 { return } - // Need to acquire fs.pagesUsedMu for fs.pagesUsed. - fs.pagesUsedMu.Lock() - defer fs.pagesUsedMu.Unlock() - if fs.pagesUsed < pagesDec { - panic(fmt.Sprintf("Deallocating more pages than allocated: fs.pagesUsed = %d, pagesDec = %d", fs.pagesUsed, pagesDec)) + + for { + pagesUsed := fs.pagesUsed.Load() + if pagesUsed < pagesDec { + panic(fmt.Sprintf("Deallocating more pages than allocated: fs.pagesUsed = %d, pagesDec = %d", pagesUsed, pagesDec)) + } + if fs.pagesUsed.CompareAndSwap(pagesUsed, pagesUsed-pagesDec) { + break + } } - fs.pagesUsed -= pagesDec } diff --git a/pkg/sentry/fsimpl/tmpfs/tmpfs.go b/pkg/sentry/fsimpl/tmpfs/tmpfs.go index 7f45fa26a..c9be9136e 100644 --- a/pkg/sentry/fsimpl/tmpfs/tmpfs.go +++ b/pkg/sentry/fsimpl/tmpfs/tmpfs.go @@ -92,10 +92,8 @@ type filesystem struct { // This field is immutable. maxSizeInPages uint64 - // pagesUsed is the pages used out of the tmpfs size. - // pagesUsed is protected by pagesUsedMu. - pagesUsedMu pagesUsedMutex `state:"nosave"` - pagesUsed uint64 + // pagesUsed is the number of pages used by this filesystem. + pagesUsed atomicbitops.Uint64 } // Name implements vfs.FilesystemType.Name. @@ -321,10 +319,9 @@ func (fs *filesystem) statFS() linux.Statfs { if fs.maxSizeInPages > 0 { // If size is set for tmpfs return set values. st.Blocks = fs.maxSizeInPages - fs.pagesUsedMu.Lock() - defer fs.pagesUsedMu.Unlock() - st.BlocksFree = fs.maxSizeInPages - fs.pagesUsed - st.BlocksAvailable = fs.maxSizeInPages - fs.pagesUsed + pagesUsed := fs.pagesUsed.Load() + st.BlocksFree = fs.maxSizeInPages - pagesUsed + st.BlocksAvailable = fs.maxSizeInPages - pagesUsed return st } // In Linux, if tmpfs is mounted with no size option,