summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/proc/seqfile
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fs/proc/seqfile')
-rw-r--r--pkg/sentry/fs/proc/seqfile/BUILD35
-rwxr-xr-xpkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go58
-rw-r--r--pkg/sentry/fs/proc/seqfile/seqfile_test.go279
3 files changed, 58 insertions, 314 deletions
diff --git a/pkg/sentry/fs/proc/seqfile/BUILD b/pkg/sentry/fs/proc/seqfile/BUILD
deleted file mode 100644
index 21338d912..000000000
--- a/pkg/sentry/fs/proc/seqfile/BUILD
+++ /dev/null
@@ -1,35 +0,0 @@
-load("//tools:defs.bzl", "go_library", "go_test")
-
-package(licenses = ["notice"])
-
-go_library(
- name = "seqfile",
- srcs = ["seqfile.go"],
- visibility = ["//pkg/sentry:internal"],
- deps = [
- "//pkg/abi/linux",
- "//pkg/context",
- "//pkg/sentry/fs",
- "//pkg/sentry/fs/fsutil",
- "//pkg/sentry/fs/proc/device",
- "//pkg/sentry/kernel/time",
- "//pkg/sync",
- "//pkg/syserror",
- "//pkg/usermem",
- "//pkg/waiter",
- ],
-)
-
-go_test(
- name = "seqfile_test",
- size = "small",
- srcs = ["seqfile_test.go"],
- library = ":seqfile",
- deps = [
- "//pkg/context",
- "//pkg/sentry/contexttest",
- "//pkg/sentry/fs",
- "//pkg/sentry/fs/ramfs",
- "//pkg/usermem",
- ],
-)
diff --git a/pkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go b/pkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go
new file mode 100755
index 000000000..cfd3a40b4
--- /dev/null
+++ b/pkg/sentry/fs/proc/seqfile/seqfile_state_autogen.go
@@ -0,0 +1,58 @@
+// automatically generated by stateify.
+
+package seqfile
+
+import (
+ "gvisor.dev/gvisor/pkg/state"
+)
+
+func (x *SeqData) beforeSave() {}
+func (x *SeqData) save(m state.Map) {
+ x.beforeSave()
+ m.Save("Buf", &x.Buf)
+ m.Save("Handle", &x.Handle)
+}
+
+func (x *SeqData) afterLoad() {}
+func (x *SeqData) load(m state.Map) {
+ m.Load("Buf", &x.Buf)
+ m.Load("Handle", &x.Handle)
+}
+
+func (x *SeqFile) beforeSave() {}
+func (x *SeqFile) save(m state.Map) {
+ x.beforeSave()
+ m.Save("InodeSimpleExtendedAttributes", &x.InodeSimpleExtendedAttributes)
+ m.Save("InodeSimpleAttributes", &x.InodeSimpleAttributes)
+ m.Save("SeqSource", &x.SeqSource)
+ m.Save("source", &x.source)
+ m.Save("generation", &x.generation)
+ m.Save("lastRead", &x.lastRead)
+}
+
+func (x *SeqFile) afterLoad() {}
+func (x *SeqFile) load(m state.Map) {
+ m.Load("InodeSimpleExtendedAttributes", &x.InodeSimpleExtendedAttributes)
+ m.Load("InodeSimpleAttributes", &x.InodeSimpleAttributes)
+ m.Load("SeqSource", &x.SeqSource)
+ m.Load("source", &x.source)
+ m.Load("generation", &x.generation)
+ m.Load("lastRead", &x.lastRead)
+}
+
+func (x *seqFileOperations) beforeSave() {}
+func (x *seqFileOperations) save(m state.Map) {
+ x.beforeSave()
+ m.Save("seqFile", &x.seqFile)
+}
+
+func (x *seqFileOperations) afterLoad() {}
+func (x *seqFileOperations) load(m state.Map) {
+ m.Load("seqFile", &x.seqFile)
+}
+
+func init() {
+ state.Register("pkg/sentry/fs/proc/seqfile.SeqData", (*SeqData)(nil), state.Fns{Save: (*SeqData).save, Load: (*SeqData).load})
+ state.Register("pkg/sentry/fs/proc/seqfile.SeqFile", (*SeqFile)(nil), state.Fns{Save: (*SeqFile).save, Load: (*SeqFile).load})
+ state.Register("pkg/sentry/fs/proc/seqfile.seqFileOperations", (*seqFileOperations)(nil), state.Fns{Save: (*seqFileOperations).save, Load: (*seqFileOperations).load})
+}
diff --git a/pkg/sentry/fs/proc/seqfile/seqfile_test.go b/pkg/sentry/fs/proc/seqfile/seqfile_test.go
deleted file mode 100644
index 98e394569..000000000
--- a/pkg/sentry/fs/proc/seqfile/seqfile_test.go
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright 2018 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package seqfile
-
-import (
- "bytes"
- "fmt"
- "io"
- "testing"
-
- "gvisor.dev/gvisor/pkg/context"
- "gvisor.dev/gvisor/pkg/sentry/contexttest"
- "gvisor.dev/gvisor/pkg/sentry/fs"
- "gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
- "gvisor.dev/gvisor/pkg/usermem"
-)
-
-type seqTest struct {
- actual []SeqData
- update bool
-}
-
-func (s *seqTest) Init() {
- var sq []SeqData
- // Create some SeqData.
- for i := 0; i < 10; i++ {
- var b []byte
- for j := 0; j < 10; j++ {
- b = append(b, byte(i))
- }
- sq = append(sq, SeqData{
- Buf: b,
- Handle: &testHandle{i: i},
- })
- }
- s.actual = sq
-}
-
-// NeedsUpdate reports whether we need to update the data we've previously read.
-func (s *seqTest) NeedsUpdate(int64) bool {
- return s.update
-}
-
-// ReadSeqFiledata returns a slice of SeqData which contains elements
-// greater than the handle.
-func (s *seqTest) ReadSeqFileData(ctx context.Context, handle SeqHandle) ([]SeqData, int64) {
- if handle == nil {
- return s.actual, 0
- }
- h := *handle.(*testHandle)
- var ret []SeqData
- for _, b := range s.actual {
- // We want the next one.
- h2 := *b.Handle.(*testHandle)
- if h2.i > h.i {
- ret = append(ret, b)
- }
- }
- return ret, 0
-}
-
-// Flatten a slice of slices into one slice.
-func flatten(buf ...[]byte) []byte {
- var flat []byte
- for _, b := range buf {
- flat = append(flat, b...)
- }
- return flat
-}
-
-type testHandle struct {
- i int
-}
-
-type testTable struct {
- offset int64
- readBufferSize int
- expectedData []byte
- expectedError error
-}
-
-func runTableTests(ctx context.Context, table []testTable, dirent *fs.Dirent) error {
- for _, tt := range table {
- file, err := dirent.Inode.InodeOperations.GetFile(ctx, dirent, fs.FileFlags{Read: true})
- if err != nil {
- return fmt.Errorf("GetFile returned error: %v", err)
- }
-
- data := make([]byte, tt.readBufferSize)
- resultLen, err := file.Preadv(ctx, usermem.BytesIOSequence(data), tt.offset)
- if err != tt.expectedError {
- return fmt.Errorf("t.Preadv(len: %v, offset: %v) (error) => %v expected %v", tt.readBufferSize, tt.offset, err, tt.expectedError)
- }
- expectedLen := int64(len(tt.expectedData))
- if resultLen != expectedLen {
- // We make this just an error so we wall through and print the data below.
- return fmt.Errorf("t.Preadv(len: %v, offset: %v) (size) => %v expected %v", tt.readBufferSize, tt.offset, resultLen, expectedLen)
- }
- if !bytes.Equal(data[:expectedLen], tt.expectedData) {
- return fmt.Errorf("t.Preadv(len: %v, offset: %v) (data) => %v expected %v", tt.readBufferSize, tt.offset, data[:expectedLen], tt.expectedData)
- }
- }
- return nil
-}
-
-func TestSeqFile(t *testing.T) {
- testSource := &seqTest{}
- testSource.Init()
-
- // Create a file that can be R/W.
- ctx := contexttest.Context(t)
- m := fs.NewPseudoMountSource(ctx)
- contents := map[string]*fs.Inode{
- "foo": NewSeqFileInode(ctx, testSource, m),
- }
- root := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0777))
-
- // How about opening it?
- inode := fs.NewInode(ctx, root, m, fs.StableAttr{Type: fs.Directory})
- dirent2, err := root.Lookup(ctx, inode, "foo")
- if err != nil {
- t.Fatalf("failed to walk to foo for n2: %v", err)
- }
- n2 := dirent2.Inode.InodeOperations
- file2, err := n2.GetFile(ctx, dirent2, fs.FileFlags{Read: true, Write: true})
- if err != nil {
- t.Fatalf("GetFile returned error: %v", err)
- }
-
- // Writing?
- if _, err := file2.Writev(ctx, usermem.BytesIOSequence([]byte("test"))); err == nil {
- t.Fatalf("managed to write to n2: %v", err)
- }
-
- // How about reading?
- dirent3, err := root.Lookup(ctx, inode, "foo")
- if err != nil {
- t.Fatalf("failed to walk to foo: %v", err)
- }
- n3 := dirent3.Inode.InodeOperations
- if n2 != n3 {
- t.Error("got n2 != n3, want same")
- }
-
- testSource.update = true
-
- table := []testTable{
- // Read past the end.
- {100, 4, []byte{}, io.EOF},
- {110, 4, []byte{}, io.EOF},
- {200, 4, []byte{}, io.EOF},
- // Read a truncated first line.
- {0, 4, testSource.actual[0].Buf[:4], nil},
- // Read the whole first line.
- {0, 10, testSource.actual[0].Buf, nil},
- // Read the whole first line + 5 bytes of second line.
- {0, 15, flatten(testSource.actual[0].Buf, testSource.actual[1].Buf[:5]), nil},
- // First 4 bytes of the second line.
- {10, 4, testSource.actual[1].Buf[:4], nil},
- // Read the two first lines.
- {0, 20, flatten(testSource.actual[0].Buf, testSource.actual[1].Buf), nil},
- // Read three lines.
- {0, 30, flatten(testSource.actual[0].Buf, testSource.actual[1].Buf, testSource.actual[2].Buf), nil},
- // Read everything, but use a bigger buffer than necessary.
- {0, 150, flatten(testSource.actual[0].Buf, testSource.actual[1].Buf, testSource.actual[2].Buf, testSource.actual[3].Buf, testSource.actual[4].Buf, testSource.actual[5].Buf, testSource.actual[6].Buf, testSource.actual[7].Buf, testSource.actual[8].Buf, testSource.actual[9].Buf), nil},
- // Read the last 3 bytes.
- {97, 10, testSource.actual[9].Buf[7:], nil},
- }
- if err := runTableTests(ctx, table, dirent2); err != nil {
- t.Errorf("runTableTest failed with testSource.update = %v : %v", testSource.update, err)
- }
-
- // Disable updates and do it again.
- testSource.update = false
- if err := runTableTests(ctx, table, dirent2); err != nil {
- t.Errorf("runTableTest failed with testSource.update = %v: %v", testSource.update, err)
- }
-}
-
-// Test that we behave correctly when the file is updated.
-func TestSeqFileFileUpdated(t *testing.T) {
- testSource := &seqTest{}
- testSource.Init()
- testSource.update = true
-
- // Create a file that can be R/W.
- ctx := contexttest.Context(t)
- m := fs.NewPseudoMountSource(ctx)
- contents := map[string]*fs.Inode{
- "foo": NewSeqFileInode(ctx, testSource, m),
- }
- root := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0777))
-
- // How about opening it?
- inode := fs.NewInode(ctx, root, m, fs.StableAttr{Type: fs.Directory})
- dirent2, err := root.Lookup(ctx, inode, "foo")
- if err != nil {
- t.Fatalf("failed to walk to foo for dirent2: %v", err)
- }
-
- table := []testTable{
- {0, 16, flatten(testSource.actual[0].Buf, testSource.actual[1].Buf[:6]), nil},
- }
- if err := runTableTests(ctx, table, dirent2); err != nil {
- t.Errorf("runTableTest failed: %v", err)
- }
- // Delete the first entry.
- cut := testSource.actual[0].Buf
- testSource.actual = testSource.actual[1:]
-
- table = []testTable{
- // Try reading buffer 0 with an offset. This will not delete the old data.
- {1, 5, cut[1:6], nil},
- // Reset our file by reading at offset 0.
- {0, 10, testSource.actual[0].Buf, nil},
- {16, 14, flatten(testSource.actual[1].Buf[6:], testSource.actual[2].Buf), nil},
- // Read the same data a second time.
- {16, 14, flatten(testSource.actual[1].Buf[6:], testSource.actual[2].Buf), nil},
- // Read the following two lines.
- {30, 20, flatten(testSource.actual[3].Buf, testSource.actual[4].Buf), nil},
- }
- if err := runTableTests(ctx, table, dirent2); err != nil {
- t.Errorf("runTableTest failed after removing first entry: %v", err)
- }
-
- // Add a new duplicate line in the middle (6666...)
- after := testSource.actual[5:]
- testSource.actual = testSource.actual[:4]
- // Note the list must be sorted.
- testSource.actual = append(testSource.actual, after[0])
- testSource.actual = append(testSource.actual, after...)
-
- table = []testTable{
- {50, 20, flatten(testSource.actual[4].Buf, testSource.actual[5].Buf), nil},
- }
- if err := runTableTests(ctx, table, dirent2); err != nil {
- t.Errorf("runTableTest failed after adding middle entry: %v", err)
- }
- // This will be used in a later test.
- oldTestData := testSource.actual
-
- // Delete everything.
- testSource.actual = testSource.actual[:0]
- table = []testTable{
- {20, 20, []byte{}, io.EOF},
- }
- if err := runTableTests(ctx, table, dirent2); err != nil {
- t.Errorf("runTableTest failed after removing all entries: %v", err)
- }
- // Restore some of the data.
- testSource.actual = oldTestData[:1]
- table = []testTable{
- {6, 20, testSource.actual[0].Buf[6:], nil},
- }
- if err := runTableTests(ctx, table, dirent2); err != nil {
- t.Errorf("runTableTest failed after adding first entry back: %v", err)
- }
-
- // Re-extend the data
- testSource.actual = oldTestData
- table = []testTable{
- {30, 20, flatten(testSource.actual[3].Buf, testSource.actual[4].Buf), nil},
- }
- if err := runTableTests(ctx, table, dirent2); err != nil {
- t.Errorf("runTableTest failed after extending testSource: %v", err)
- }
-}