summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/file_overlay_test.go
diff options
context:
space:
mode:
authorNicolas Lacasse <nlacasse@google.com>2018-08-10 17:15:27 -0700
committerShentubot <shentubot@google.com>2018-08-10 17:16:38 -0700
commita2ec391dfbc5a03077b73078777a9347c372dece (patch)
tree037d59bfbb29c2bb4bee25678060be65139e8bb7 /pkg/sentry/fs/file_overlay_test.go
parentae6f092fe117a738df34e072ef5ba01a41c89222 (diff)
fs: Allow overlays to revalidate files from the upper fs.
Previously, an overlay would panic if either the upper or lower fs required revalidation for a given Dirent. Now, we allow revalidation from the upper file, but not the lower. If a cached overlay inode does need revalidation (because the upper needs revalidation), then the entire overlay Inode will be discarded and a new overlay Inode will be built with a fresh copy of the upper file. As a side effect of this change, Revalidate must take an Inode instead of a Dirent, since an overlay needs to revalidate individual Inodes. PiperOrigin-RevId: 208293638 Change-Id: Ic8f8d1ffdc09114721745661a09522b54420c5f1
Diffstat (limited to 'pkg/sentry/fs/file_overlay_test.go')
-rw-r--r--pkg/sentry/fs/file_overlay_test.go70
1 files changed, 62 insertions, 8 deletions
diff --git a/pkg/sentry/fs/file_overlay_test.go b/pkg/sentry/fs/file_overlay_test.go
index 407ba8562..38762d8a1 100644
--- a/pkg/sentry/fs/file_overlay_test.go
+++ b/pkg/sentry/fs/file_overlay_test.go
@@ -21,6 +21,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/context/contexttest"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
+ ramfstest "gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs/test"
)
func TestReaddir(t *testing.T) {
@@ -48,7 +49,7 @@ func TestReaddir(t *testing.T) {
{name: "a"},
{name: "b"},
}, nil), /* lower */
- ),
+ false /* revalidate */),
names: []string{".", "..", "a", "b"},
},
{
@@ -59,7 +60,7 @@ func TestReaddir(t *testing.T) {
{name: "b"},
}, nil), /* upper */
nil, /* lower */
- ),
+ false /* revalidate */),
names: []string{".", "..", "a", "b"},
},
{
@@ -67,11 +68,11 @@ func TestReaddir(t *testing.T) {
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, []dirContent{
{name: "a"},
- }, nil), /* lower */
+ }, nil), /* upper */
newTestRamfsDir(ctx, []dirContent{
{name: "b"},
}, nil), /* lower */
- ),
+ false /* revalidate */),
names: []string{".", "..", "a", "b"},
},
{
@@ -79,11 +80,11 @@ func TestReaddir(t *testing.T) {
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, []dirContent{
{name: "a"},
- }, []string{"b"}), /* lower */
+ }, []string{"b"}), /* upper */
newTestRamfsDir(ctx, []dirContent{
{name: "c"},
}, nil), /* lower */
- ),
+ false /* revalidate */),
names: []string{".", "..", "a", "c"},
},
{
@@ -91,12 +92,12 @@ func TestReaddir(t *testing.T) {
dir: fs.NewTestOverlayDir(ctx,
newTestRamfsDir(ctx, []dirContent{
{name: "a"},
- }, []string{"b"}), /* lower */
+ }, []string{"b"}), /* upper */
newTestRamfsDir(ctx, []dirContent{
{name: "b"}, /* will be masked */
{name: "c"},
}, nil), /* lower */
- ),
+ false /* revalidate */),
names: []string{".", "..", "a", "c"},
},
} {
@@ -120,6 +121,59 @@ func TestReaddir(t *testing.T) {
}
}
+func TestReaddirRevalidation(t *testing.T) {
+ ctx := contexttest.Context(t)
+ ctx = &rootContext{
+ Context: ctx,
+ root: fs.NewDirent(newTestRamfsDir(ctx, nil, nil), "root"),
+ }
+
+ // Create an overlay with two directories, each with one file.
+ upper := newTestRamfsDir(ctx, []dirContent{{name: "a"}}, nil)
+ lower := newTestRamfsDir(ctx, []dirContent{{name: "b"}}, nil)
+ overlay := fs.NewTestOverlayDir(ctx, upper, lower, true /* revalidate */)
+
+ // Get a handle to the dirent in the upper filesystem so that we can
+ // modify it without going through the dirent.
+ upperDir := upper.InodeOperations.(*dir).InodeOperations.(*ramfstest.Dir)
+
+ // Check that overlay returns the files from both upper and lower.
+ openDir, err := overlay.GetFile(ctx, fs.NewDirent(overlay, "stub"), fs.FileFlags{Read: true})
+ if err != nil {
+ t.Fatalf("GetFile got error %v, want nil", err)
+ }
+ ser := &fs.CollectEntriesSerializer{}
+ if err := openDir.Readdir(ctx, ser); err != nil {
+ t.Fatalf("Readdir got error %v, want nil", err)
+ }
+ got, want := ser.Order, []string{".", "..", "a", "b"}
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("Readdir got names %v, want %v", got, want)
+ }
+
+ // Remove "a" from the upper and add "c".
+ if err := upperDir.Remove(ctx, upper, "a"); err != nil {
+ t.Fatalf("error removing child: %v", err)
+ }
+ upperDir.AddChild(ctx, "c", fs.NewInode(ramfstest.NewFile(ctx, fs.FilePermissions{}),
+ upper.MountSource, fs.StableAttr{Type: fs.RegularFile}))
+
+ // Seek to beginning of the directory and do the readdir again.
+ if _, err := openDir.Seek(ctx, fs.SeekSet, 0); err != nil {
+ t.Fatalf("error seeking to beginning of dir: %v", err)
+ }
+ ser = &fs.CollectEntriesSerializer{}
+ if err := openDir.Readdir(ctx, ser); err != nil {
+ t.Fatalf("Readdir got error %v, want nil", err)
+ }
+
+ // Readdir should return the updated children.
+ got, want = ser.Order, []string{".", "..", "b", "c"}
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("Readdir got names %v, want %v", got, want)
+ }
+}
+
type rootContext struct {
context.Context
root *fs.Dirent