summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/file_overlay_test.go
diff options
context:
space:
mode:
authorNicolas Lacasse <nlacasse@google.com>2018-09-18 15:41:13 -0700
committerShentubot <shentubot@google.com>2018-09-18 15:42:22 -0700
commitfd222d62eda8b447fa0e11260f64fdb94e5e7084 (patch)
tree9d5522fd1ef87dfbe974c04cc18977f5619dbdd6 /pkg/sentry/fs/file_overlay_test.go
parent7967d8ecd57383f406d202f7e2f65e275bb36fc8 (diff)
Short-circuit Readdir calls on overlay files when the dirent is frozen.
If we have an overlay file whose corresponding Dirent is frozen, then we should not bother calling Readdir on the upper or lower files, since DirentReaddir will calculate children based on the frozen Dirent tree. A test was added that fails without this change. PiperOrigin-RevId: 213531215 Change-Id: I4d6c98f1416541a476a34418f664ba58f936a81d
Diffstat (limited to 'pkg/sentry/fs/file_overlay_test.go')
-rw-r--r--pkg/sentry/fs/file_overlay_test.go83
1 files changed, 83 insertions, 0 deletions
diff --git a/pkg/sentry/fs/file_overlay_test.go b/pkg/sentry/fs/file_overlay_test.go
index 38762d8a1..830458ff9 100644
--- a/pkg/sentry/fs/file_overlay_test.go
+++ b/pkg/sentry/fs/file_overlay_test.go
@@ -174,6 +174,89 @@ func TestReaddirRevalidation(t *testing.T) {
}
}
+// TestReaddirOverlayFrozen tests that calling Readdir on an overlay file with
+// a frozen dirent tree does not make Readdir calls to the underlying files.
+func TestReaddirOverlayFrozen(t *testing.T) {
+ ctx := contexttest.Context(t)
+
+ // Create an overlay with two directories, each with two files.
+ upper := newTestRamfsDir(ctx, []dirContent{{name: "upper-file1"}, {name: "upper-file2"}}, nil)
+ lower := newTestRamfsDir(ctx, []dirContent{{name: "lower-file1"}, {name: "lower-file2"}}, nil)
+ overlayInode := fs.NewTestOverlayDir(ctx, upper, lower, false)
+
+ // Set that overlay as the root.
+ root := fs.NewDirent(overlayInode, "root")
+ ctx = &rootContext{
+ Context: ctx,
+ root: root,
+ }
+
+ // Check that calling Readdir on the root now returns all 4 files (2
+ // from each layer in the overlay).
+ rootFile, err := root.Inode.GetFile(ctx, root, fs.FileFlags{Read: true})
+ if err != nil {
+ t.Fatalf("root.Inode.GetFile failed: %v", err)
+ }
+ defer rootFile.DecRef()
+ ser := &fs.CollectEntriesSerializer{}
+ if err := rootFile.Readdir(ctx, ser); err != nil {
+ t.Fatalf("rootFile.Readdir failed: %v", err)
+ }
+ if got, want := ser.Order, []string{".", "..", "lower-file1", "lower-file2", "upper-file1", "upper-file2"}; !reflect.DeepEqual(got, want) {
+ t.Errorf("Readdir got names %v, want %v", got, want)
+ }
+
+ // Readdir should have been called on upper and lower.
+ upperDir := upper.InodeOperations.(*dir)
+ lowerDir := lower.InodeOperations.(*dir)
+ if !upperDir.ReaddirCalled {
+ t.Errorf("upperDir.ReaddirCalled got %v, want true", upperDir.ReaddirCalled)
+ }
+ if !lowerDir.ReaddirCalled {
+ t.Errorf("lowerDir.ReaddirCalled got %v, want true", lowerDir.ReaddirCalled)
+ }
+
+ // Reset.
+ upperDir.ReaddirCalled = false
+ lowerDir.ReaddirCalled = false
+
+ // Take references on "upper-file1" and "lower-file1", pinning them in
+ // the dirent tree.
+ for _, name := range []string{"upper-file1", "lower-file1"} {
+ if _, err := root.Walk(ctx, root, name); err != nil {
+ t.Fatalf("root.Walk(%q) failed: %v", name, err)
+ }
+ // Don't drop a reference on the returned dirent so that it
+ // will stay in the tree.
+ }
+
+ // Freeze the dirent tree.
+ root.Freeze()
+
+ // Seek back to the beginning of the file.
+ if _, err := rootFile.Seek(ctx, fs.SeekSet, 0); err != nil {
+ t.Fatalf("error seeking to beginning of directory: %v", err)
+ }
+
+ // Calling Readdir on the root now will return only the pinned
+ // children.
+ ser = &fs.CollectEntriesSerializer{}
+ if err := rootFile.Readdir(ctx, ser); err != nil {
+ t.Fatalf("rootFile.Readdir failed: %v", err)
+ }
+ if got, want := ser.Order, []string{".", "..", "lower-file1", "upper-file1"}; !reflect.DeepEqual(got, want) {
+ t.Errorf("Readdir got names %v, want %v", got, want)
+ }
+
+ // Readdir should NOT have been called on upper or lower.
+ if upperDir.ReaddirCalled {
+ t.Errorf("upperDir.ReaddirCalled got %v, want false", upperDir.ReaddirCalled)
+ }
+ if lowerDir.ReaddirCalled {
+ t.Errorf("lowerDir.ReaddirCalled got %v, want false", lowerDir.ReaddirCalled)
+ }
+}
+
type rootContext struct {
context.Context
root *fs.Dirent