summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/dirent_cache.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fs/dirent_cache.go')
-rw-r--r--pkg/sentry/fs/dirent_cache.go43
1 files changed, 37 insertions, 6 deletions
diff --git a/pkg/sentry/fs/dirent_cache.go b/pkg/sentry/fs/dirent_cache.go
index 502b0a09b..d26a06971 100644
--- a/pkg/sentry/fs/dirent_cache.go
+++ b/pkg/sentry/fs/dirent_cache.go
@@ -32,6 +32,10 @@ type DirentCache struct {
// when cache is nil.
maxSize uint64
+ // limit restricts the number of entries in the cache amoung multiple caches.
+ // It may be nil if there are no global limit for this cache.
+ limit *DirentCacheLimiter
+
// mu protects currentSize and direntList.
mu sync.Mutex `state:"nosave"`
@@ -45,8 +49,7 @@ type DirentCache struct {
list direntList `state:"zerovalue"`
}
-// NewDirentCache returns a new DirentCache with the given maxSize. If maxSize
-// is 0, nil is returned.
+// NewDirentCache returns a new DirentCache with the given maxSize.
func NewDirentCache(maxSize uint64) *DirentCache {
return &DirentCache{
maxSize: maxSize,
@@ -71,15 +74,24 @@ func (c *DirentCache) Add(d *Dirent) {
return
}
+ // First check against the global limit.
+ for c.limit != nil && !c.limit.tryInc() {
+ if c.currentSize == 0 {
+ // If the global limit is reached, but there is nothing more to drop from
+ // this cache, there is not much else to do.
+ c.mu.Unlock()
+ return
+ }
+ c.remove(c.list.Back())
+ }
+
// d is not in cache. Add it and take a reference.
c.list.PushFront(d)
d.IncRef()
c.currentSize++
- // Remove the oldest until we are under the size limit.
- for c.maxSize > 0 && c.currentSize > c.maxSize {
- c.remove(c.list.Back())
- }
+ c.maybeShrink()
+
c.mu.Unlock()
}
@@ -92,6 +104,9 @@ func (c *DirentCache) remove(d *Dirent) {
d.SetNext(nil)
d.DecRef()
c.currentSize--
+ if c.limit != nil {
+ c.limit.dec()
+ }
}
// Remove removes the element from the cache and decrements its refCount. It
@@ -142,3 +157,19 @@ func (c *DirentCache) Invalidate() {
}
c.mu.Unlock()
}
+
+// setMaxSize sets cache max size. If current size is larger than max size, the
+// cache shrinks to acommodate the new max.
+func (c *DirentCache) setMaxSize(max uint64) {
+ c.mu.Lock()
+ c.maxSize = max
+ c.maybeShrink()
+ c.mu.Unlock()
+}
+
+// shrink removes the oldest element until the list is under the size limit.
+func (c *DirentCache) maybeShrink() {
+ for c.maxSize > 0 && c.currentSize > c.maxSize {
+ c.remove(c.list.Back())
+ }
+}