Make tmpfs size accounting lock-free by using atomics.

This is likely to be a speed-up in the common case when contention between
threads is low. In such situations, generally atomic operations are faster.

PiperOrigin-RevId: 493731992
This commit is contained in:
Ayush Ranjan
2022-12-07 15:58:10 -08:00
committed by gVisor bot
parent d984f7e8d8
commit c6faaea7dc
2 changed files with 41 additions and 39 deletions
+36 -31
View File
@@ -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
}
+5 -8
View File
@@ -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,