Added integration tests for mounting tmpfs with size option enabled.

PiperOrigin-RevId: 444705540
This commit is contained in:
Shambhavi Srivastava 2022-04-26 16:58:33 -07:00 committed by gVisor bot
parent bf251f1838
commit ce91143bdc
4 changed files with 106 additions and 2 deletions

View File

@ -202,7 +202,7 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
var maxSizeInPages uint64
if ok {
delete(mopts, "size")
maxSizeInBytes, err := strconv.ParseUint(maxSizeStr, 10, 64)
maxSizeInBytes, err := parseSize(maxSizeStr)
if err != nil {
ctx.Warningf("tmpfs.FilesystemType.GetFilesystem: invalid size: %q", maxSizeStr)
return nil, nil, linuxerr.EINVAL
@ -944,3 +944,33 @@ func (fd *fileDescription) RemoveXattr(ctx context.Context, name string) error {
func (*fileDescription) Sync(context.Context) error {
return nil
}
// parseSize converts size in string to an integer bytes.
// Supported suffixes in string are:K, M, G, T, P, E.
func parseSize(s string) (uint64, error) {
suffix := s[len(s)-1]
count := 1
switch suffix {
case 'e', 'E':
count = count << 10
fallthrough
case 'p', 'P':
count = count << 10
fallthrough
case 't', 'T':
count = count << 10
fallthrough
case 'g', 'G':
count = count << 10
fallthrough
case 'm', 'M':
count = count << 10
fallthrough
case 'k', 'K':
count = count << 10
s = s[:len(s)-1]
}
bytes, err := strconv.ParseUint(s, 10, 64)
bytes = bytes * uint64(count)
return bytes, err
}

View File

@ -16,6 +16,7 @@ package tmpfs
import (
"fmt"
"testing"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/atomicbitops"
@ -155,3 +156,37 @@ func newPipeFD(ctx context.Context, mode linux.FileMode) (*vfs.FileDescription,
return fd, cleanup, nil
}
func TestParseSize(t *testing.T) {
var tests = []struct {
s string
want uint64
wantError bool
}{
{"500", 500, false},
{"5k", (5 * 1024), false},
{"5m", (5 * 1024 * 1024), false},
{"5G", (5 * 1024 * 1024 * 1024), false},
{"5t", (5 * 1024 * 1024 * 1024 * 1024), false},
{"5P", (5 * 1024 * 1024 * 1024 * 1024 * 1024), false},
{"5e", (5 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024), false},
{"5e3", 0, true},
}
for _, tt := range tests {
testname := fmt.Sprintf("%s", tt.s)
t.Run(testname, func(t *testing.T) {
size, err := parseSize(tt.s)
if tt.wantError && err == nil {
t.Errorf("Invalid input: %v parsed", tt.s)
}
if !tt.wantError {
if err != nil {
t.Errorf("Couldn't parse size, Error: %v", err)
}
if size != tt.want {
t.Errorf("got: %v, want %v", size, tt.want)
}
}
})
}
}

View File

@ -67,7 +67,7 @@ const (
)
// tmpfs has some extra supported options that we must pass through.
var tmpfsAllowedData = []string{"mode", "uid", "gid"}
var tmpfsAllowedData = []string{"mode", "size", "uid", "gid"}
func addOverlay(ctx context.Context, lower *fs.Inode, name string, lowerFlags fs.MountSourceFlags) (*fs.Inode, error) {
// Upper layer uses the same flags as lower, but it must be read-write.

View File

@ -911,3 +911,42 @@ func TestRevalidateSymlinkChain(t *testing.T) {
t.Fatalf("Read wrong file, want: %q, got: %q", want, got)
}
}
// TestTmpMountWithSize checks when 'tmpfs' is mounted
// with size option the limit is not exceeded.
func TestTmpMountWithSize(t *testing.T) {
ctx := context.Background()
d := dockerutil.MakeContainer(ctx, t)
defer d.CleanUp(ctx)
opts := dockerutil.RunOpts{
Image: "basic/alpine",
Mounts: []mount.Mount{
{
Type: mount.TypeTmpfs,
Target: "/tmp/foo",
TmpfsOptions: &mount.TmpfsOptions{
SizeBytes: 4096,
},
},
},
}
if err := d.Create(ctx, opts, "sleep", "1000"); err != nil {
t.Fatalf("docker create failed: %v", err)
}
if err := d.Start(ctx); err != nil {
t.Fatalf("docker start failed: %v", err)
}
if _, err := d.Exec(ctx, dockerutil.ExecOpts{}, "/bin/sh", "-c", "echo hello > /tmp/foo/test1.txt"); err != nil {
t.Fatalf("docker exec failed: %v", err)
}
echoOutput, err := d.Exec(ctx, dockerutil.ExecOpts{}, "/bin/sh", "-c", "echo world > /tmp/foo/test2.txt")
if err == nil {
t.Fatalf("docker exec size check failed: %v", err)
}
wantErr := "No space left on device"
if !strings.Contains(echoOutput, wantErr) {
t.Errorf("unexpected echo error:Expected: %v, Got: %v", wantErr, echoOutput)
}
}